diff --git a/src/app/appmarket/admin/configuration/configuration.routes.ts b/src/app/appmarket/admin/configuration/configuration.routes.ts index adde5168ce4badc1f068931ff7978c8122ecdbbf..c69d5a34517777869646484e7c22b62c5ecfa1fb 100644 --- a/src/app/appmarket/admin/configuration/configuration.routes.ts +++ b/src/app/appmarket/admin/configuration/configuration.routes.ts @@ -2,8 +2,14 @@ import {Route} from "@angular/router"; import {AuthGuard} from "../../../auth/auth.guard"; import {RoleGuard} from "../../../auth/role.guard"; import {ConfigurationDetailsComponent} from "./index"; +import { WebhookListComponent } from "../webhook/webhook-list/webhook-list.component"; +import { WebhookDetailsComponent } from "../webhook/webhook-details/webhook-details.component"; export const ConfigurationRoutes: Route[] = [ {path: 'configuration', component: ConfigurationDetailsComponent, canActivate: [AuthGuard, RoleGuard], + data:{roles: ['ROLE_SYSTEM_ADMIN']} }, + {path: 'webhooks', component: WebhookListComponent, canActivate: [AuthGuard, RoleGuard], + data:{roles: ['ROLE_SYSTEM_ADMIN']} }, + {path: 'webhooks/:id', component: WebhookDetailsComponent, canActivate: [AuthGuard, RoleGuard], data:{roles: ['ROLE_SYSTEM_ADMIN']} } ]; diff --git a/src/app/appmarket/admin/webhook/webhook-details/webhook-details.component.css b/src/app/appmarket/admin/webhook/webhook-details/webhook-details.component.css new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/src/app/appmarket/admin/webhook/webhook-details/webhook-details.component.html b/src/app/appmarket/admin/webhook/webhook-details/webhook-details.component.html new file mode 100644 index 0000000000000000000000000000000000000000..f2fb671831fa7abf2a18ef727bde77e0c878e631 --- /dev/null +++ b/src/app/appmarket/admin/webhook/webhook-details/webhook-details.component.html @@ -0,0 +1,81 @@ +<div class=""> + <div class="background-section"> + <h4 style="font-size:15px; font-weight: bold">{{ 'WEBHOOKS.TITLE' | translate }}</h4> + + <div class="panel-body"> + <form *ngIf="webhook" (submit)="submit()" class="form-horizontal" #webhookForm="ngForm"> + <div class="panel-default panel-heading">{{ 'CLUSTERS.GENERAL' | translate }} </div> + <div class="panel-body"> + + <div class="form-group"> + <label for="clusterId" class="col-sm-2 control-label">{{ 'WEBHOOKS.ID' | translate }}</label> + <div class="col-sm-10"> + <div class="col-sm-10"> + <input type="text" class="form-control" id="clusterId" name="clusterId" + [(ngModel)]="webhook.id" [disabled]="true"> + </div> + </div> + </div> + + <div class="form-group"> + <label for="clusterName" class="col-sm-2 control-label">{{ 'WEBHOOKS.NAME' | translate }}</label> + <div class="col-sm-10"> + <div class="col-sm-10"> + <input type="text" class="form-control" id="clusterName" name="clusterName" + [(ngModel)]="webhook.name" [disabled]="false"> + </div> + </div> + </div> + + <div class="form-group"> + <label for="targetUrl" class="col-sm-2 control-label">{{ 'WEBHOOKS.TARGEt_URL' | translate }}</label> + <div class="col-sm-10"> + <div class="col-sm-10"> + <input type="text" class="form-control" id="targetUrl" name="targetUrl" + [(ngModel)]="webhook.targetUrl" [disabled]="false"> + </div> + </div> + </div> + + <div class="form-group"> + <label for="clusterDescription" class="col-sm-2 control-label">{{ 'WEBHOOKS.TYPE' | translate }}</label> + <div class="col-sm-10"> + <div class="col-sm-10"> + <input type="text" class="form-control" id="clusterDescription" name="clusterDescription" + placeholder="{{webhook.eventType | translate}}" [disabled]="true"> + </div> + </div> + </div> + + <div class="form-group"> + <label for="token" class="col-sm-2 control-label">{{ 'WEBHOOKS.TOKEN' | translate }}</label> + <div class="col-sm-10"> + <div class="col-sm-10"> + <input type="text" class="form-control" id="token" name="token" + [(ngModel)]="webhook.tokenValue" [disabled]="false"> + </div> + </div> + </div> + + + <div class="form-group"> + <label for="auth" class="col-sm-2 control-label">{{ 'WEBHOOKS.AUTH' | translate }}</label> + <div class="col-sm-10"> + <div class="col-sm-10"> + <input type="text" class="form-control" id="auth" name="auth" + [(ngModel)]="webhook.authorizationHeader" [disabled]="false"> + </div> + </div> + </div> + + <div class="flex justify-content-end"> + <button [disabled]="!webhookForm.form.valid" type="submit" class="btn btn-primary" + type="submit">{{ 'PORTAL_CONFIGURATION.SUBMIT_BUTTON' | translate }}</button> + </div> + + + </div> + </form> + </div> +</div> +</div> \ No newline at end of file diff --git a/src/app/appmarket/admin/webhook/webhook-details/webhook-details.component.spec.ts b/src/app/appmarket/admin/webhook/webhook-details/webhook-details.component.spec.ts new file mode 100644 index 0000000000000000000000000000000000000000..89d35d84e215e651f40edf8859f8cc4d81aa6df6 --- /dev/null +++ b/src/app/appmarket/admin/webhook/webhook-details/webhook-details.component.spec.ts @@ -0,0 +1,23 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { WebhookDetailsComponent } from './webhook-details.component'; + +describe('WebhookDetailsComponent', () => { + let component: WebhookDetailsComponent; + let fixture: ComponentFixture<WebhookDetailsComponent>; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + declarations: [WebhookDetailsComponent] + }) + .compileComponents(); + + fixture = TestBed.createComponent(WebhookDetailsComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/src/app/appmarket/admin/webhook/webhook-details/webhook-details.component.ts b/src/app/appmarket/admin/webhook/webhook-details/webhook-details.component.ts new file mode 100644 index 0000000000000000000000000000000000000000..ef3ae89e81d00a607683d2c4178c02861fd2ba6f --- /dev/null +++ b/src/app/appmarket/admin/webhook/webhook-details/webhook-details.component.ts @@ -0,0 +1,43 @@ +import { Component, OnInit } from '@angular/core'; +import { WebhookService } from '../../../../service/webhook.service'; +import { ActivatedRoute, Router } from '@angular/router'; +import { Webhook } from '../../../../model/webhook'; +import { BaseComponent } from '../../../../shared/common/basecomponent/base.component'; + +@Component({ + selector: 'app-webhook-details', + templateUrl: './webhook-details.component.html', + styleUrl: './webhook-details.component.css' +}) +export class WebhookDetailsComponent extends BaseComponent implements OnInit { + + public webhooksId: number; + public webhook: Webhook; + + constructor(private service: WebhookService, + public router: Router, + private route: ActivatedRoute) { + super(); + } + + + ngOnInit(): void { + this.route.params.subscribe(params => { + this.webhooksId = +params['id']; + + this.service.getOne(this.webhooksId).subscribe(result => { + console.log(result); + this.webhook = result; + } ) + }) + } + + + public submit(): void { + console.log(this.webhook); + this.service.update(this.webhook).subscribe(result => { + console.log(result); + this.webhook = result; + }); + } +} diff --git a/src/app/appmarket/admin/webhook/webhook-list/webhook-list.component.css b/src/app/appmarket/admin/webhook/webhook-list/webhook-list.component.css new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/src/app/appmarket/admin/webhook/webhook-list/webhook-list.component.html b/src/app/appmarket/admin/webhook/webhook-list/webhook-list.component.html new file mode 100644 index 0000000000000000000000000000000000000000..8158c52a0252fe096e268b2f7036dfda7f05a424 --- /dev/null +++ b/src/app/appmarket/admin/webhook/webhook-list/webhook-list.component.html @@ -0,0 +1,112 @@ +<div style="display: flex; align-items: center; margin-top:20px"> + <div style="margin-right:20px"> + <div > + <button class="btn btn-primary" (click)="openModal()">{{'WEBHOOKS.NEW' | translate}}</button> + </div> + </div> + <div class="flex" style="margin-right:20px"> + + </div> +</div> + + <h4 class="header">{{ 'WEBHOOKS.TITLE' | translate }}</h4> + +<div class="background-section"> + <p-table + [value]="webkooks" + [paginator]="true" + [rows]="maxItemsOnPage" + [rowsPerPageOptions]="[15, 20, 25, 30, 50]" + [responsiveLayout]="'scroll'"> + <ng-template pTemplate="header"> + <tr> + <th pSortableColumn="id" id="id"> {{ 'WEBHOOKS.ID' | translate }} + <p-sortIcon field="id"></p-sortIcon> + </th> + <th pSortableColumn="name" id="name"> {{ 'WEBHOOKS.NAME' | translate }} + <p-sortIcon field="name"></p-sortIcon> + </th> + <th pSortableColumn="url" id="url"> {{ 'WEBHOOKS.TARGET_URL' | translate }} + <p-sortIcon field="url"></p-sortIcon> + </th> + <th pSortableColumn="type" id="type"> {{ 'WEBHOOKS.TYPE' | translate }} + <p-sortIcon field="type"></p-sortIcon> + </th> + <th></th> + </tr> + </ng-template> + <ng-template pTemplate="body" let-webhook> + <tr> + <td [routerLink]="[webhook.id]">{{webhook.id}}</td> + <td>{{webhook.name}}</td> + <td>{{('WEBHOOKS.' + webhook.eventType.toString().toUpperCase() ) | translate}}</td> + <td>{{webhook.targetUrl}}</td> + + <td class="text-right"> + <span class="dropdown"> + <a style="display: inline-block" class="dropdown-toggle" aria-expanded="false" aria-haspopup="true" data-toggle="dropdown" href="#" role="button"> + <em class="pi pi-cog" style="font-size: 1.8rem; color: var(--l-text-color)"></em> + </a> + <ul class="dropdown-menu pull-right-drop" > + <li><a [routerLink]="[ webhook.id]" class=""> + {{ 'WEBHOOKS.DETAILS' | translate }}</a> + </li> + </ul> + </span> + </td> + </tr> + </ng-template> + </p-table> + +</div> + + +<nmaas-modal > + <div class="nmaas-modal-header">{{'WEBHOOKS.TITLE_SHORT' | translate}}</div> + <div class="nmaas-modal-body"> + <div class="flex flex-column"> + <div class="mt-4"> + <label for="name">{{'WEBHOOKS.NAME' | translate}}</label> + <input id="name" type="text" class="form-control" [(ngModel)]="addedWebhook.name" [ngModelOptions]="{standalone: true}"> + </div> + + <div class="mt-4"> + <label for="desc">{{'WEBHOOKS.TARGET_URL' | translate}}</label> + <input id="desc" type="text" class="form-control" [(ngModel)]="addedWebhook.targetUrl" [ngModelOptions]="{standalone: true}"> + </div> + <div class="mt-4"> + <label for="contactEmail">{{'WEBHOOKS.TYPE' | translate}}</label> + <select id="domain" #typeSelect class="form-control" (change)="onTypeSelect(typeSelect.value)" > + <option *ngFor="let t of type" [value]="t.name" + >{{t.name | translate}} + </option> + </select> + </div> + + + <div class="mt-4"> + <label for="assignDomain">Auth required</label> + <input class="ml-2" type="checkbox" [(ngModel)]="authRequired" id="authRequired"/> + </div> + + <div *ngIf="authRequired" class="mt-4"> + <label for="desc">{{'WEBHOOKS.TOKEN' | translate}}</label> + <input id="desc" type="text" class="form-control" [(ngModel)]="addedWebhook.tokenValue" [ngModelOptions]="{standalone: true}"> + </div> + + <div *ngIf="authRequired" class="mt-4"> + <label for="desc">{{'WEBHOOKS.AUTH' | translate}}</label> + <input id="desc" type="text" class="form-control" [(ngModel)]="addedWebhook.authorizationHeader" [ngModelOptions]="{standalone: true}"> + </div> + + + </div> + </div> + <div class="nmaas-modal-footer"> + <button type="button" class="btn btn-primary" [disabled]=" addedWebhook?.name === null "(click)="closeModalAndSaveWebhook()" + pTooltip="Upload file is required before save" showDelay="2000" >{{'CLUSTERS.SAVE' | translate}}</button> + <button type="button" class="btn btn-secondary" + (click)="this.modal.hide()">{{'UNDEPLOY_MODAL.CANCEL_BUTTON' | translate}}</button> + + </div> + </nmaas-modal> diff --git a/src/app/appmarket/admin/webhook/webhook-list/webhook-list.component.spec.ts b/src/app/appmarket/admin/webhook/webhook-list/webhook-list.component.spec.ts new file mode 100644 index 0000000000000000000000000000000000000000..66dcfb7ebff2aea79a92d579c4e6e0be8592921f --- /dev/null +++ b/src/app/appmarket/admin/webhook/webhook-list/webhook-list.component.spec.ts @@ -0,0 +1,23 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { WebhookListComponent } from './webhook-list.component'; + +describe('WebhookListComponent', () => { + let component: WebhookListComponent; + let fixture: ComponentFixture<WebhookListComponent>; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + declarations: [WebhookListComponent] + }) + .compileComponents(); + + fixture = TestBed.createComponent(WebhookListComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/src/app/appmarket/admin/webhook/webhook-list/webhook-list.component.ts b/src/app/appmarket/admin/webhook/webhook-list/webhook-list.component.ts new file mode 100644 index 0000000000000000000000000000000000000000..63500136dd4095e6f6474f4bb86338b56d05322c --- /dev/null +++ b/src/app/appmarket/admin/webhook/webhook-list/webhook-list.component.ts @@ -0,0 +1,62 @@ +import { Component, OnInit, ViewChild } from '@angular/core'; +import { Webhook, WebhookType } from '../../../../model/webhook'; +import { ModalComponent } from '../../../../shared'; +import { WebhookService } from '../../../../service/webhook.service'; + +@Component({ + selector: 'app-webhook-list', + templateUrl: './webhook-list.component.html', + styleUrl: './webhook-list.component.css' +}) +export class WebhookListComponent implements OnInit { + + public webkooks: Webhook[] = []; + + public addedWebhook: Webhook = new Webhook(); + public maxItemsOnPage = 15; + + public authRequired: boolean = false; + + public type =[ + { name: "DOMAIN_CREATION", value: "DOMAIN_CREATION" }, + { name: "APPLICATION_DEPLOYMENT", value: "APPLICATION_DEPLOYMENT" }, + { name: "USER_ASSIGNMENT", value: "USER_ASSIGNMENT" }, + { name: "DOMAIN_GROUP_CHANGE", value: "DOMAIN_GROUP_CHANGE" } + ] + + @ViewChild(ModalComponent, { static: true }) + public modal: ModalComponent; + + + constructor(private service: WebhookService) { + } + + ngOnInit() { + this.refreshList(); + } + + public refreshList() { + this.service.getAll().subscribe(result => { + this.webkooks = result; + }) + } + + onTypeSelect(event: any) { + console.log(event); + this.addedWebhook.eventType = event; + } + + public openModal() { + this.addedWebhook.eventType = WebhookType.DOMAIN_CREATION + this.modal.show(); + } + + public closeModalAndSaveWebhook() { + this.service.create(this.addedWebhook).subscribe(result => { + this.modal.hide(); + this.refreshList(); + }); + + } + +} diff --git a/src/app/appmarket/appmarket.module.ts b/src/app/appmarket/appmarket.module.ts index 1539264532ea45f31fb58cb059887338c5cecf57..ac973b85d8a36ae4f9d123d28f24a4473091244b 100644 --- a/src/app/appmarket/appmarket.module.ts +++ b/src/app/appmarket/appmarket.module.ts @@ -51,6 +51,9 @@ import { InputSwitchModule } from 'primeng/inputswitch'; import { OverlayPanelModule } from 'primeng/overlaypanel'; import { SidebarModule } from 'primeng/sidebar'; import { ProgressBarModule } from 'primeng/progressbar'; +import { WebhookDetailsComponent } from './admin/webhook/webhook-details/webhook-details.component'; +import { WebhookListComponent } from './admin/webhook/webhook-list/webhook-list.component'; +import { WebhookService } from '../service/webhook.service'; @@ -67,7 +70,9 @@ import { ProgressBarModule } from 'primeng/progressbar'; BulkViewComponent, BulkAppListComponent, BulkListComponent, - BulkSearchPipe + BulkSearchPipe, + WebhookDetailsComponent, + WebhookListComponent ], imports: [ FormsModule, @@ -101,7 +106,7 @@ import { ProgressBarModule } from 'primeng/progressbar'; InputSwitchModule, OverlayPanelModule, SidebarModule, - ProgressBarModule + ProgressBarModule, ], exports: [ AppMarketComponent, @@ -116,6 +121,7 @@ import { ProgressBarModule } from 'primeng/progressbar'; ClusterService, SortService, SessionService, + WebhookService ], schemas: [ NO_ERRORS_SCHEMA, diff --git a/src/app/model/webhook.ts b/src/app/model/webhook.ts new file mode 100644 index 0000000000000000000000000000000000000000..3fd1c0a0bf4622c404a62fd69d9d27f18950fd2b --- /dev/null +++ b/src/app/model/webhook.ts @@ -0,0 +1,16 @@ +export class Webhook { + + public id: number = undefined; + public name: string = undefined; + public targetUrl: string = undefined; + public tokenValue: string = undefined; + public authorizationHeader: string = undefined; + public eventType: WebhookType = undefined; +} + +export enum WebhookType { + DOMAIN_CREATION = "DOMAIN_CREATION", + APPLICATION_DEPLOYMENT = "APPLICATION_DEPLOYMENT", + USER_ASSIGNMENT = "USER_ASSIGNMENT", + DOMAIN_GROUP_CHANGE = "DOMAIN_GROUP_CHANGE", +} \ No newline at end of file diff --git a/src/app/service/webhook.service.ts b/src/app/service/webhook.service.ts new file mode 100644 index 0000000000000000000000000000000000000000..6dc30fc662bcf28a658225cc108bdf627f8a9d71 --- /dev/null +++ b/src/app/service/webhook.service.ts @@ -0,0 +1,38 @@ +import { HttpClient } from '@angular/common/http'; +import {Injectable} from '@angular/core'; +import {BehaviorSubject, Observable} from 'rxjs'; +import { AppConfigService } from './appconfig.service'; +import { GenericDataService } from './genericdata.service'; +import { Webhook } from '../model/webhook'; +import { Id } from '../model'; + +@Injectable() +export class WebhookService extends GenericDataService { + + + protected url: string; + + constructor(http: HttpClient, appConfig: AppConfigService) { + super(http, appConfig); + this.url = this.appConfig.getApiUrl() + '/webhooks'; + } + + + public getAll() : Observable<Webhook[]> { + return this.get<Webhook[]>(this.url); + } + + public create(webhook: Webhook) { + return this.post<Webhook, Id>(this.url, webhook); + } + + public getOne(id: number) { + return this.get<Webhook>(this.url + '/' + id); + } + + + public update(webhook: Webhook) { + return this.put<Webhook, Webhook>(this.url + '/' + webhook.id, webhook); + } + +} diff --git a/src/app/shared/admin/clusters/manager/manager.component.html b/src/app/shared/admin/clusters/manager/manager.component.html index cf693202ea648e7e341fc231b6df0e9becbdfcce..d96ff9d9d7c82616ba82f4b5f2f1ac05b7344b91 100644 --- a/src/app/shared/admin/clusters/manager/manager.component.html +++ b/src/app/shared/admin/clusters/manager/manager.component.html @@ -88,12 +88,20 @@ <div class="mt-4"> + + <div> + <label for="assignDomain">Assign to domain? </label> + <input type="checkbox" [(ngModel)]="assignedDomain" (change)="onDomainChange($event)" id="assignDomain" /> + </div> + <div class="mt-4" *ngIf="assignedDomain"> <label for="name">{{'CLUSTERS.DOMAIN' | translate}}</label> - <select id="domain" #domainSelect class="form-control" (change)="onDomainSelection(domainSelect.value)"> + <select id="domain" #domainSelect class="form-control" (change)="onDomainSelection(domainSelect.value)" plaaceholder="testtesttest" > <option *ngFor="let domain of domains" [value]="domain.name" >{{domain.name}} </option> </select> + </div> + </div> diff --git a/src/app/shared/admin/clusters/manager/manager.component.ts b/src/app/shared/admin/clusters/manager/manager.component.ts index 2e9df32629c98c7ed0181231b3fe064f3da72753..3a38ba79f26ad9226bb0ef04f0e9df0ead0bc59e 100644 --- a/src/app/shared/admin/clusters/manager/manager.component.ts +++ b/src/app/shared/admin/clusters/manager/manager.component.ts @@ -16,6 +16,7 @@ export class ClusterManagerComponent { public addedCluster: ClusterManager = new ClusterManager(); public updatedFile : File = null; public maxItemsOnPage = 15; + public assignedDomain: boolean = false; public domains = []; @@ -72,6 +73,8 @@ public openModal() { this.modal.show(); } - +public onDomainChange(event: any) { +console.log(event); +} } diff --git a/src/app/shared/left-menu/left-menu.component.html b/src/app/shared/left-menu/left-menu.component.html index 35fb1012e9652c3a94fea38b6afcbb7f6cc3945b..dfbe2909c0903e63a3db35d464e4650663a79281 100644 --- a/src/app/shared/left-menu/left-menu.component.html +++ b/src/app/shared/left-menu/left-menu.component.html @@ -119,6 +119,14 @@ </span> </a> </li> + <li *roles="['ROLE_SYSTEM_ADMIN']" [routerLinkActiveOptions]="{exact:true}" [routerLinkActive]="['active']" [ngClass]="{'collapsed': isCollapsed}"> + <a style="display: flex; align-items: center;" [routerLink]="['/admin/webhooks']"> + <i class="pi pi-cog" style="margin-right:10px; font-size: 18px" title="Settings"></i> + <span *ngIf="!isCollapsed"> + {{ 'WEBHOOKS.TITLE_SHORT' | translate }} + </span> + </a> + </li> <li *roles="['ROLE_SYSTEM_ADMIN']" [routerLinkActiveOptions]="{exact:true}" [routerLinkActive]="['active']" [ngClass]="{'collapsed': isCollapsed}"> <a style="display: flex; align-items: center;" [routerLink]="['/admin/manage/clusters']"> <i class="pi pi-cog" style="margin-right:10px; font-size: 18px"></i>