From 3080eebc1397c4cfe81ff08d0f6fd632963185c2 Mon Sep 17 00:00:00 2001 From: Lucie Kureckova <lkureckova@seznam.cz> Date: Sun, 10 May 2020 17:36:47 +0200 Subject: [PATCH 1/4] Facilities - services destinations page * added services destinations page * added feature remove destinations * added feature add destination to service and facility --- .../facilities/facilities-routing.module.ts | 5 + .../src/app/facilities/facilities.module.ts | 4 +- .../facility-overview.component.ts | 14 +- .../facility-resources.component.ts | 5 +- ...ility-services-destinations.component.html | 23 +++ ...ility-services-destinations.component.scss | 0 ...acility-services-destinations.component.ts | 129 ++++++++++++++++ .../destination-list.component.html | 76 ++++++++++ .../destination-list.component.scss | 0 .../destination-list.component.ts | 98 ++++++++++++ ...services-destination-dialog.component.html | 96 ++++++++++++ ...services-destination-dialog.component.scss | 0 ...d-services-destination-dialog.component.ts | 142 ++++++++++++++++++ .../remove-destination-dialog.component.html | 39 +++++ .../remove-destination-dialog.component.scss | 0 .../remove-destination-dialog.component.ts | 44 ++++++ .../admin-gui/src/app/shared/shared.module.ts | 12 +- .../side-menu/side-menu-item.service.ts | 5 + apps/admin-gui/src/assets/i18n/en.json | 43 +++++- .../src/lib/table-config.service.ts | 1 + .../services/src/lib/custom-icon.service.ts | 6 + 21 files changed, 729 insertions(+), 13 deletions(-) create mode 100644 apps/admin-gui/src/app/facilities/pages/facility-detail-page/facility-services-destinations/facility-services-destinations.component.html create mode 100644 apps/admin-gui/src/app/facilities/pages/facility-detail-page/facility-services-destinations/facility-services-destinations.component.scss create mode 100644 apps/admin-gui/src/app/facilities/pages/facility-detail-page/facility-services-destinations/facility-services-destinations.component.ts create mode 100644 apps/admin-gui/src/app/shared/components/destination-list/destination-list.component.html create mode 100644 apps/admin-gui/src/app/shared/components/destination-list/destination-list.component.scss create mode 100644 apps/admin-gui/src/app/shared/components/destination-list/destination-list.component.ts create mode 100644 apps/admin-gui/src/app/shared/components/dialogs/add-services-destination-dialog/add-services-destination-dialog.component.html create mode 100644 apps/admin-gui/src/app/shared/components/dialogs/add-services-destination-dialog/add-services-destination-dialog.component.scss create mode 100644 apps/admin-gui/src/app/shared/components/dialogs/add-services-destination-dialog/add-services-destination-dialog.component.ts create mode 100644 apps/admin-gui/src/app/shared/components/dialogs/remove-destination-dialog/remove-destination-dialog.component.html create mode 100644 apps/admin-gui/src/app/shared/components/dialogs/remove-destination-dialog/remove-destination-dialog.component.scss create mode 100644 apps/admin-gui/src/app/shared/components/dialogs/remove-destination-dialog/remove-destination-dialog.component.ts diff --git a/apps/admin-gui/src/app/facilities/facilities-routing.module.ts b/apps/admin-gui/src/app/facilities/facilities-routing.module.ts index c58d0a40f..6e74802d9 100644 --- a/apps/admin-gui/src/app/facilities/facilities-routing.module.ts +++ b/apps/admin-gui/src/app/facilities/facilities-routing.module.ts @@ -24,6 +24,7 @@ import { import { ResourceGroupsComponent } from './pages/resource-detail-page/resource-groups/resource-groups.component'; import { FacilityServiceConfigComponent } from './pages/facility-detail-page/facility-service-config/facility-service-config.component'; import { FacilitySettingsManagersComponent } from './pages/facility-detail-page/facility-settings/facility-settings-managers/facility-settings-managers.component'; +import { FacilityServicesDestinationsComponent } from './pages/facility-detail-page/facility-services-destinations/facility-services-destinations.component'; const routes: Routes = [ { @@ -53,6 +54,10 @@ const routes: Routes = [ path: 'service-config', component: FacilityServiceConfigComponent, data: {animation: 'FacilityServiceConfigPage'} + },{ + path: 'services-destinations', + component: FacilityServicesDestinationsComponent, + data: {animation: 'FacilityServicesDestinationsPage'} }, { path: 'settings', diff --git a/apps/admin-gui/src/app/facilities/facilities.module.ts b/apps/admin-gui/src/app/facilities/facilities.module.ts index 58ce23038..26f9678a6 100644 --- a/apps/admin-gui/src/app/facilities/facilities.module.ts +++ b/apps/admin-gui/src/app/facilities/facilities.module.ts @@ -32,6 +32,7 @@ import { PerunSharedComponentsModule } from '@perun-web-apps/perun/components'; import { FacilityServiceConfigComponent } from './pages/facility-detail-page/facility-service-config/facility-service-config.component'; import { PerunFacilityServicesConfigModule } from '@perun-web-apps/perun/facility-services-config'; import { FacilitySettingsManagersComponent } from './pages/facility-detail-page/facility-settings/facility-settings-managers/facility-settings-managers.component'; +import { FacilityServicesDestinationsComponent } from './pages/facility-detail-page/facility-services-destinations/facility-services-destinations.component'; @NgModule({ declarations: [ @@ -51,7 +52,8 @@ import { FacilitySettingsManagersComponent } from './pages/facility-detail-page/ ResourceSettingsAttributesComponent, ResourceGroupsComponent, FacilityServiceConfigComponent, - FacilitySettingsManagersComponent + FacilitySettingsManagersComponent, + FacilityServicesDestinationsComponent ], imports: [ CommonModule, diff --git a/apps/admin-gui/src/app/facilities/pages/facility-detail-page/facility-overview/facility-overview.component.ts b/apps/admin-gui/src/app/facilities/pages/facility-detail-page/facility-overview/facility-overview.component.ts index 4e7159b75..3b8df9a4d 100644 --- a/apps/admin-gui/src/app/facilities/pages/facility-detail-page/facility-overview/facility-overview.component.ts +++ b/apps/admin-gui/src/app/facilities/pages/facility-detail-page/facility-overview/facility-overview.component.ts @@ -48,14 +48,20 @@ export class FacilityOverviewComponent implements OnInit { }, { cssIcon: 'perun-settings2', - url: `/facilities/${this.facility.id}/settings`, - label: 'MENU_ITEMS.FACILITY.SETTINGS', + url: `/facilities/${this.facility.id}/service-config`, + label: 'MENU_ITEMS.FACILITY.SERVICE_CONFIG', + style: 'facility-btn' + }, + { + cssIcon: 'perun-service_destination', + url: `/facilities/${this.facility.id}/services-destinations`, + label: 'MENU_ITEMS.FACILITY.SERVICES_DESTINATIONS', style: 'facility-btn' }, { cssIcon: 'perun-settings2', - url: `/facilities/${this.facility.id}/service-config`, - label: 'MENU_ITEMS.FACILITY.SERVICE_CONFIG', + url: `/facilities/${this.facility.id}/settings`, + label: 'MENU_ITEMS.FACILITY.SETTINGS', style: 'facility-btn' } ]; diff --git a/apps/admin-gui/src/app/facilities/pages/facility-detail-page/facility-resources/facility-resources.component.ts b/apps/admin-gui/src/app/facilities/pages/facility-detail-page/facility-resources/facility-resources.component.ts index 60ba4998c..118d11641 100644 --- a/apps/admin-gui/src/app/facilities/pages/facility-detail-page/facility-resources/facility-resources.component.ts +++ b/apps/admin-gui/src/app/facilities/pages/facility-detail-page/facility-resources/facility-resources.component.ts @@ -1,5 +1,4 @@ import { Component, HostBinding, Input, OnInit } from '@angular/core'; -import { SideMenuService } from '../../../../core/services/common/side-menu.service'; import { ActivatedRoute } from '@angular/router'; import { SelectionModel } from '@angular/cdk/collections'; import { MatDialog } from '@angular/material/dialog'; @@ -26,9 +25,7 @@ export class FacilityResourcesComponent implements OnInit { constructor(private dialog: MatDialog, private facilitiesManager: FacilitiesManagerService, - private sideMenuService: SideMenuService, private tableConfigService: TableConfigService, - private facilityManager: FacilitiesManagerService, private route: ActivatedRoute) { } @@ -49,7 +46,7 @@ export class FacilityResourcesComponent implements OnInit { this.route.parent.params.subscribe(parentParams => { const facilityId = parentParams['facilityId']; - this.facilityManager.getFacilityById(facilityId).subscribe(facility => { + this.facilitiesManager.getFacilityById(facilityId).subscribe(facility => { this.facility = facility; this.refreshTable(); diff --git a/apps/admin-gui/src/app/facilities/pages/facility-detail-page/facility-services-destinations/facility-services-destinations.component.html b/apps/admin-gui/src/app/facilities/pages/facility-detail-page/facility-services-destinations/facility-services-destinations.component.html new file mode 100644 index 000000000..cd54430a5 --- /dev/null +++ b/apps/admin-gui/src/app/facilities/pages/facility-detail-page/facility-services-destinations/facility-services-destinations.component.html @@ -0,0 +1,23 @@ +<div> + <h1 class="page-subtitle">{{'FACILITY_DETAIL.SERVICES_DESTINATIONS.TITLE' | translate}}</h1> + <perun-web-apps-refresh-button (refresh)="refreshTable()"></perun-web-apps-refresh-button> + <button mat-flat-button color="accent" (click)="addDestination()"> + {{'FACILITY_DETAIL.SERVICES_DESTINATIONS.ADD' | translate}} + </button> + <button mat-flat-button color="warn" class="ml-2" [disabled]="selected.selected.length === 0" (click)="removeDestination()"> + {{'FACILITY_DETAIL.SERVICES_DESTINATIONS.REMOVE' | translate}} + </button> + <perun-web-apps-immediate-filter + [placeholder]="'FACILITY_DETAIL.SERVICES_DESTINATIONS.FILTER'" + (filter)="applyFilter($event)"></perun-web-apps-immediate-filter> + <mat-spinner class="ml-auto mr-auto" *ngIf="loading"></mat-spinner> + <app-perun-web-apps-destination-list + [pageSize]="pageSize" + (page)="pageChanged($event)" + *ngIf="!loading" + [filterValue]="filterValue" + [destinations]="destinations" + [selection]="selected" + [displayedColumns]="displayedColumns"> + </app-perun-web-apps-destination-list> +</div> diff --git a/apps/admin-gui/src/app/facilities/pages/facility-detail-page/facility-services-destinations/facility-services-destinations.component.scss b/apps/admin-gui/src/app/facilities/pages/facility-detail-page/facility-services-destinations/facility-services-destinations.component.scss new file mode 100644 index 000000000..e69de29bb diff --git a/apps/admin-gui/src/app/facilities/pages/facility-detail-page/facility-services-destinations/facility-services-destinations.component.ts b/apps/admin-gui/src/app/facilities/pages/facility-detail-page/facility-services-destinations/facility-services-destinations.component.ts new file mode 100644 index 000000000..1f83d1e49 --- /dev/null +++ b/apps/admin-gui/src/app/facilities/pages/facility-detail-page/facility-services-destinations/facility-services-destinations.component.ts @@ -0,0 +1,129 @@ +import { Component, HostBinding, OnInit } from '@angular/core'; +import { MatDialog } from '@angular/material/dialog'; +import { + FacilitiesManagerService, + Facility, RichDestination, + RichResource, + ServicesManagerService +} from '@perun-web-apps/perun/openapi'; +import { + TABLE_FACILITY_SERVICES_DESTINATION_LIST, + TableConfigService +} from '@perun-web-apps/config/table-config'; +import { ActivatedRoute } from '@angular/router'; +import { SelectionModel } from '@angular/cdk/collections'; +import { PageEvent } from '@angular/material/paginator'; +import { RemoveDestinationDialogComponent } from '../../../../shared/components/dialogs/remove-destination-dialog/remove-destination-dialog.component'; +import { TranslateService } from '@ngx-translate/core'; +import { NotificatorService } from '../../../../core/services/common/notificator.service'; +import { AddServicesDestinationDialogComponent } from '../../../../shared/components/dialogs/add-services-destination-dialog/add-services-destination-dialog.component'; + +@Component({ + selector: 'app-perun-web-apps-facility-services-destinations', + templateUrl: './facility-services-destinations.component.html', + styleUrls: ['./facility-services-destinations.component.scss'] +}) +export class FacilityServicesDestinationsComponent implements OnInit { + + static id = 'FacilityServicesDestinationsComponent'; + + // class used for animation + @HostBinding('class.router-component') true; + + constructor(private dialog: MatDialog, + private facilitiesManager: FacilitiesManagerService, + private servicesManager: ServicesManagerService, + private tableConfigService: TableConfigService, + private translate: TranslateService, + private notificator: NotificatorService, + private route: ActivatedRoute) { } + + facility: Facility; + destinations: RichDestination[]; + selected = new SelectionModel<RichResource>(true, []); + displayedColumns: string[] = ['select', 'destinationId', 'service', 'destination', 'type', 'propagationType']; + + filterValue = ''; + + loading: boolean; + pageSize: number; + tableId = TABLE_FACILITY_SERVICES_DESTINATION_LIST; + + ngOnInit() { + this.loading = true; + this.pageSize = this.tableConfigService.getTablePageSize(this.tableId); + + this.route.parent.params.subscribe(parentParams => { + const facilityId = parentParams['facilityId']; + + this.facilitiesManager.getFacilityById(facilityId).subscribe(facility => { + this.facility = facility; + + this.refreshTable(); + }); + }); + } + + refreshTable() { + this.loading = true; + this.servicesManager.getAllRichDestinationsForFacility(this.facility.id).subscribe( destinations => { + this.destinations = destinations; + this.selected.clear(); + this.loading = false; + }); + } + + addDestination() { + const dialogRef = this.dialog.open(AddServicesDestinationDialogComponent, { + width: '600px', + data: {facility: this.facility, theme: 'facility-theme'} + }); + + dialogRef.afterClosed().subscribe(result => { + if (result) { + this.refreshTable(); + } + }); + } + + removeDestination() { + const dialogRef = this.dialog.open(RemoveDestinationDialogComponent, { + width: '600px', + data: {destinations: this.selected.selected, theme: 'facility-theme'} + }); + + dialogRef.afterClosed().subscribe(result => { + if (result) { + this.loading = true; + this.deleteDestinations(this.selected.selected); + } + }); + } + + applyFilter(filterValue: string) { + this.filterValue = filterValue; + } + + pageChanged(event: PageEvent) { + this.pageSize = event.pageSize; + this.tableConfigService.setTablePageSize(this.tableId, event.pageSize); + } + + deleteDestinations(destinationsForDelete: RichDestination[]) { + if (destinationsForDelete.length === 0) { + this.translate.get('FACILITY_DETAIL.SERVICES_DESTINATIONS.REMOVE_SUCCESS').subscribe(successMessage => { + this.refreshTable(); + this.notificator.showSuccess(successMessage); + }); + } else { + const destination = destinationsForDelete[0]; + this.servicesManager.removeDestination(destination.service.id, + destination.facility.id, + destination.destination, + destination.type).subscribe( () => { + destinationsForDelete.shift(); + this.deleteDestinations(destinationsForDelete); + }); + } + } +} diff --git a/apps/admin-gui/src/app/shared/components/destination-list/destination-list.component.html b/apps/admin-gui/src/app/shared/components/destination-list/destination-list.component.html new file mode 100644 index 000000000..e33b6c2bc --- /dev/null +++ b/apps/admin-gui/src/app/shared/components/destination-list/destination-list.component.html @@ -0,0 +1,76 @@ +<div class="card mt-3" [class.hide-table]="exporting" [hidden]="dataSource.filteredData.length === 0 || destinations.length === 0"> + <div class="card-body"> + <perun-web-apps-table-options (end)="exporting = false" (start)="exporting = true" [exporter]="exporter" class="ml-auto"></perun-web-apps-table-options> + <table mat-table matTableExporter [dataSource]="dataSource" #exporter="matTableExporter" matSort matSortActive="id" matSortDirection="asc" matSortDisableClear + class="w-100"> + + <ng-container matColumnDef="select"> + <th mat-header-cell *matHeaderCellDef> + <mat-checkbox color="primary" + (change)="$event ? masterToggle() : null" + [checked]="selection.hasValue() && isAllSelected()" + [indeterminate]="selection.hasValue() && !isAllSelected()" + [aria-label]="checkboxLabel()"> + </mat-checkbox> + </th> + <td mat-cell *matCellDef="let resource" class="static-column-size"> + <mat-checkbox color="primary" + (click)="$event.stopPropagation()" + (change)="$event ? selection.toggle(resource) : null" + [checked]="selection.isSelected(resource)" + [aria-label]="checkboxLabel(resource)"> + </mat-checkbox> + </td> + </ng-container> + + <ng-container matColumnDef="destinationId"> + <th mat-header-cell *matHeaderCellDef + mat-sort-header>{{'FACILITY_DETAIL.SERVICES_DESTINATIONS.TABLE_DESTINATION_ID' | translate}}</th> + <td mat-cell class="static-column-size" *matCellDef="let destination">{{destination.id}}</td> + </ng-container> + <ng-container matColumnDef="service"> + <th mat-header-cell *matHeaderCellDef + mat-sort-header>{{'FACILITY_DETAIL.SERVICES_DESTINATIONS.TABLE_SERVICE' | translate}}</th> + <td mat-cell *matCellDef="let destination">{{destination.service.name}}</td> + </ng-container> + <ng-container matColumnDef="destination"> + <th mat-header-cell *matHeaderCellDef + mat-sort-header>{{'FACILITY_DETAIL.SERVICES_DESTINATIONS.TABLE_DESTINATION' | translate}}</th> + <td mat-cell *matCellDef="let destination">{{destination.destination}}</td> + </ng-container> + <ng-container matColumnDef="type"> + <th mat-header-cell *matHeaderCellDef + mat-sort-header>{{'FACILITY_DETAIL.SERVICES_DESTINATIONS.TABLE_TYPE' | translate}}</th> + <td mat-cell *matCellDef="let destination">{{destination.type}}</td> + </ng-container> + <ng-container matColumnDef="propagationType"> + <th mat-header-cell *matHeaderCellDef + mat-sort-header>{{'FACILITY_DETAIL.SERVICES_DESTINATIONS.TABLE_PROPAGATION_TYPE' | translate}}</th> + <td mat-cell *matCellDef="let destination">{{destination.propagationType}}</td> + </ng-container> + + <tr mat-header-row *matHeaderRowDef="displayedColumns"></tr> + <tr + mat-row + *matRowDef="let destination; columns: displayedColumns;" + class="dark-hover-list-item"> + </tr> + </table> + <mat-paginator + [length]="destinations.length" + [pageSize]="pageSize" + (page)="page.emit($event)" + [pageSizeOptions]="pageSizeOptions"> + </mat-paginator> + </div> +</div> + +<mat-spinner *ngIf="exporting" class="ml-auto mr-auto"></mat-spinner> + +<app-alert *ngIf="dataSource.filteredData.length === 0 && destinations.length !== 0" color="warn"> + {{'SHARED_LIB.UI.ALERTS.NO_FILTER_RESULTS_ALERT' | translate}} +</app-alert> + +<app-alert *ngIf="destinations.length === 0" color="warn"> + {{'FACILITY_DETAIL.SERVICES_DESTINATIONS.NO_DESTINATION' | translate}} +</app-alert> diff --git a/apps/admin-gui/src/app/shared/components/destination-list/destination-list.component.scss b/apps/admin-gui/src/app/shared/components/destination-list/destination-list.component.scss new file mode 100644 index 000000000..e69de29bb diff --git a/apps/admin-gui/src/app/shared/components/destination-list/destination-list.component.ts b/apps/admin-gui/src/app/shared/components/destination-list/destination-list.component.ts new file mode 100644 index 000000000..44e8af0a6 --- /dev/null +++ b/apps/admin-gui/src/app/shared/components/destination-list/destination-list.component.ts @@ -0,0 +1,98 @@ +import { Component, EventEmitter, Input, OnChanges, Output, SimpleChanges, ViewChild } from '@angular/core'; +import { MatSort } from '@angular/material/sort'; +import { RichDestination, RichResource } from '@perun-web-apps/perun/openapi'; +import { SelectionModel } from '@angular/cdk/collections'; +import { MatPaginator, PageEvent } from '@angular/material/paginator'; +import { MatTableDataSource } from '@angular/material/table'; +import { TABLE_ITEMS_COUNT_OPTIONS } from '@perun-web-apps/perun/utils'; + +@Component({ + selector: 'app-perun-web-apps-destination-list', + templateUrl: './destination-list.component.html', + styleUrls: ['./destination-list.component.scss'] +}) +export class DestinationListComponent implements OnChanges { + + constructor() { } + + @Input() + destinations: RichDestination[] = []; + @Input() + selection = new SelectionModel<RichResource>(true, []); + @Input() + filterValue: string; + @Input() + pageSize = 10; + @Input() + displayedColumns: string[]; + + @Output() + page: EventEmitter<PageEvent> = new EventEmitter<PageEvent>(); + + @ViewChild(MatSort, { static: true }) set matSort(ms: MatSort) { + this.sort = ms; + this.setDataSource(); + } + + private sort: MatSort; + + dataSource: MatTableDataSource<RichDestination>; + + exporting = false; + + + @ViewChild(MatPaginator) paginator: MatPaginator; + pageSizeOptions = TABLE_ITEMS_COUNT_OPTIONS; + + ngOnChanges(changes: SimpleChanges) { + this.dataSource = new MatTableDataSource<RichDestination>(this.destinations); + this.setDataSource(); + this.dataSource.filter = this.filterValue.toLowerCase(); + } + + setDataSource() { + if (!!this.dataSource) { + this.dataSource.sort = this.sort; + this.dataSource.paginator = this.paginator; + this.dataSource.sortingDataAccessor = (item, property) => { + switch (property) { + case 'service': { + return item.service.name; + } + default: return item[property]; + } + }; + this.dataSource.filterPredicate = (data, filter) => { + const dataStr = data.service.name + data.id + data.destination + data.type + data.propagationType; + return dataStr.indexOf(filter) !== -1; + } + } + } + + /** Whether the number of selected elements matches the total number of rows. */ + isAllSelected() { + const numSelected = this.selection.selected.length; + const numRows = this.dataSource.data.length; + return numSelected === numRows; + } + + /** Selects all rows if they are not all selected; otherwise clear selection. */ + masterToggle() { + this.isAllSelected() ? + this.selection.clear() : + this.dataSource.data.forEach(row => this.selection.select(row)); + } + + /** The label for the checkbox on the passed row */ + checkboxLabel(row?: RichResource): string { + if (!row) { + return `${this.isAllSelected() ? 'select' : 'deselect'} all`; + } + return `${this.selection.isSelected(row) ? 'deselect' : 'select'} row ${row.id + 1}`; + } + + pageChanged(event: PageEvent) { + this.page.emit(event); + } + +} diff --git a/apps/admin-gui/src/app/shared/components/dialogs/add-services-destination-dialog/add-services-destination-dialog.component.html b/apps/admin-gui/src/app/shared/components/dialogs/add-services-destination-dialog/add-services-destination-dialog.component.html new file mode 100644 index 000000000..e16372886 --- /dev/null +++ b/apps/admin-gui/src/app/shared/components/dialogs/add-services-destination-dialog/add-services-destination-dialog.component.html @@ -0,0 +1,96 @@ +<div class="{{data.theme}}"> + + <h1 mat-dialog-title>{{'DIALOGS.ADD_SERVICE_DESTINATION.TITLE' | translate}}</h1> + <div mat-dialog-content> + <div [@openClose]="isInvalid() ? 'open' : 'closed'"> + <app-alert color="error">{{'DIALOGS.ADD_SERVICE_DESTINATION.' + invalidNotification | translate}}</app-alert> + </div> + <div class="font-italic">{{'DIALOGS.ADD_SERVICE_DESTINATION.DESCRIPTION' | translate}}</div> + <div class="d-flex"> + <span class="w-25 m-auto font-weight-bold">{{'DIALOGS.ADD_SERVICE_DESTINATION.SERVICE' | translate}}:</span> + <div class="w-75"> + <mat-form-field class="w-100"> + <mat-select [(ngModel)]="selectedService" required> + <mat-option *ngIf="services.length !== 0" value="all">{{'DIALOGS.ADD_SERVICE_DESTINATION.SELECTION_ALL' | translate}}</mat-option> + <mat-option *ngIf="services.length === 0" value="noService">{{'DIALOGS.ADD_SERVICE_DESTINATION.NO_SERVICE' | translate}}</mat-option> + <mat-option *ngFor="let service of services" [value]="service"> + {{service.name}} + </mat-option> + </mat-select> + <mat-error *ngIf="selectedService == undefined"> + {{'DIALOGS.ADD_SERVICE_DESTINATION.CHOOSE_SERVICE' | translate}} + </mat-error> + </mat-form-field> + </div> + </div> + <div class="d-flex"> + <span class="w-25 m-auto font-weight-bold"></span> + <div class="w-75"> + <mat-checkbox (change)="getServices()" [(ngModel)]="servicesOnFacility">{{'DIALOGS.ADD_SERVICE_DESTINATION.IS_SERVICES_ONLY_ON_FACILITY' | translate}}</mat-checkbox> + </div> + </div> + <div class="d-flex"> + <span class="w-25 m-auto font-weight-bold">{{'DIALOGS.ADD_SERVICE_DESTINATION.TYPE' | translate}}:</span> + <div class="w-75"> + <mat-form-field class="w-100"> + <mat-select [(ngModel)]="selectedType"> + <mat-option *ngFor="let type of types" [value]="type"> + {{getTypeForView(type)}} + </mat-option> + </mat-select> + </mat-form-field> + </div> + </div> + <div class="d-flex"> + <span class="w-25 m-auto font-weight-bold">{{getTypeForView(selectedType)}}:</span> + <div class="w-75"> + <mat-form-field class="w-100"> + <input + matInput + required + [disabled]="useFacilityHost && selectedType === 'host'" + [(ngModel)]="destination"> + <mat-error *ngIf="!(useFacilityHost && selectedType === 'host')"> + {{'DIALOGS.ADD_SERVICE_DESTINATION.REQUIRED_FIELD' | translate}} + </mat-error> + </mat-form-field> + </div> + </div> + <div class="d-flex" *ngIf="selectedType == 'host'"> + <span class="w-25 m-auto font-weight-bold"></span> + <div class="w-75"> + <mat-checkbox [(ngModel)]="useFacilityHost">{{'DIALOGS.ADD_SERVICE_DESTINATION.USE_FACILITY_HOST' | translate}}</mat-checkbox> + </div> + </div> + <div class="d-flex"> + <span class="w-25 m-auto font-weight-bold">{{'DIALOGS.ADD_SERVICE_DESTINATION.PROPAGATION' | translate}}:</span> + <div class="w-75"> + <mat-form-field class="w-100"> + <mat-select [(ngModel)]="selectedPropagation"> + <mat-option *ngFor="let propagation of propagations" [value]="propagation"> + {{propagation}} + </mat-option> + </mat-select> + </mat-form-field> + </div> + </div> + <div class="font-italic">{{'DIALOGS.ADD_SERVICE_DESTINATION.PROPAGATION_TYPE_' + selectedPropagation | translate}}</div> + </div> + <div mat-dialog-actions> + <button + mat-flat-button + class="ml-auto" + (click)="onCancel()"> + {{'DIALOGS.ADD_SERVICE_DESTINATION.CANCEL' | translate}} + </button> + <button + mat-flat-button + class="ml-2" + color="accent" + [disabled]="isInvalid()" + (click)="onSubmit()"> + {{'DIALOGS.ADD_SERVICE_DESTINATION.ADD' | translate}} + </button> + </div> +</div> + diff --git a/apps/admin-gui/src/app/shared/components/dialogs/add-services-destination-dialog/add-services-destination-dialog.component.scss b/apps/admin-gui/src/app/shared/components/dialogs/add-services-destination-dialog/add-services-destination-dialog.component.scss new file mode 100644 index 000000000..e69de29bb diff --git a/apps/admin-gui/src/app/shared/components/dialogs/add-services-destination-dialog/add-services-destination-dialog.component.ts b/apps/admin-gui/src/app/shared/components/dialogs/add-services-destination-dialog/add-services-destination-dialog.component.ts new file mode 100644 index 000000000..c9bbcc700 --- /dev/null +++ b/apps/admin-gui/src/app/shared/components/dialogs/add-services-destination-dialog/add-services-destination-dialog.component.ts @@ -0,0 +1,142 @@ +import { Component, Inject, OnInit } from '@angular/core'; +import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog'; +import { openClose } from '../../../animations/Animations'; +import { + DestinationPropagationType, + DestinationType, + FacilitiesManagerService, + Facility, + Host, + Service, + ServicesManagerService +} from '@perun-web-apps/perun/openapi'; + +export interface AddServicesDestinationDialogData { + facility: Facility; + theme: string; +} + +@Component({ + selector: 'app-perun-web-apps-add-services-destination-dialog', + templateUrl: './add-services-destination-dialog.component.html', + styleUrls: ['./add-services-destination-dialog.component.scss'], + animations: [ + openClose + ] +}) +export class AddServicesDestinationDialogComponent implements OnInit { + + constructor(public dialogRef: MatDialogRef<AddServicesDestinationDialogComponent>, + @Inject(MAT_DIALOG_DATA) public data: AddServicesDestinationDialogData, + public facilitiesManager: FacilitiesManagerService, + public servicesManager: ServicesManagerService) { } + + + hosts: Host[]; + servicesOnFacility: boolean; + services: Service[] = []; + selectedService: Service; + types: string[] = ['host', 'user@host', 'user@host:port','user@host-windows', 'host-windows-proxy', + 'url', 'mail', 'semail', 'service-specific']; + selectedType = 'host'; + propagations: string[] = ['PARALLEL', 'DUMMY']; + selectedPropagation = 'PARALLEL'; + destination = ''; + useFacilityHost = false; + invalidNotification = ''; + + ngOnInit() { + this.facilitiesManager.getHosts(this.data.facility.id).subscribe( hosts => { + this.hosts = hosts; + this.servicesOnFacility = true; + this.getServices(); + }); + } + + onCancel() { + this.dialogRef.close(); + } + + onSubmit() { + // @ts-ignore + if (this.selectedService === 'all') { + if (this.useFacilityHost) { + this.servicesManager.addDestinationsDefinedByHostsOnFacilityWithListOfServiceAndFacility( + {services: this.services, facility: this.data.facility.id}).subscribe( destination => { + this.dialogRef.close(true); + }); + } + else { + this.servicesManager.addDestinationToMultipleServices({services: this.services, facility: this.data.facility.id, + destination: this.destination, type: this.selectedType as DestinationType, + propagationType: this.selectedPropagation as DestinationPropagationType}).subscribe( destination => { + this.dialogRef.close(true); + }); + } + } else { + if (this.useFacilityHost) { + this.servicesManager.addDestinationsDefinedByHostsOnFacilityWithServiceAndFacility( + this.selectedService.id, this.data.facility.id + ).subscribe( destination => { + this.dialogRef.close(true); + }); + } + else { + this.servicesManager.addDestination(this.selectedService.id, this.data.facility.id, + this.destination, this.selectedType as DestinationType, + this.selectedPropagation as DestinationPropagationType).subscribe( destination => { + this.dialogRef.close(true); + }); + } + } + } + + getServices() { + if (this.servicesOnFacility) { + this.servicesManager.getAssignedServices(this.data.facility.id).subscribe( services => { + this.services = services; + + }); + } else { + this.servicesManager.getServices().subscribe( services => { + this.services = services; + }) + } + this.selectedService = undefined; + } + + getTypeForView(type: string) { + if (type === 'semail') { + return 'Send Mail'; + } + if (type === 'service-specific') { + return 'Service Specific'; + } + return type; + } + + isInvalid():boolean { + // @ts-ignore + if (this.selectedService === 'noService') { + this.invalidNotification = 'NO_SERVICE'; + return true; + } + // @ts-ignore + if (this.selectedService === undefined) { + this.invalidNotification = 'CHOOSE_SERVICE'; + return true; + } + if (this.destination === '' && !this.useFacilityHost) { + this.invalidNotification = 'REQUIRED_FIELD'; + return true; + } + if (this.selectedType === 'mail'|| this.selectedType === 'semail') { + const regexp = new RegExp(/^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/); + if (!regexp.test(this.destination)) { + this.invalidNotification = 'TYPE_EMAIL'; + return true; + } + } + return false; + } +} diff --git a/apps/admin-gui/src/app/shared/components/dialogs/remove-destination-dialog/remove-destination-dialog.component.html b/apps/admin-gui/src/app/shared/components/dialogs/remove-destination-dialog/remove-destination-dialog.component.html new file mode 100644 index 000000000..027db15a3 --- /dev/null +++ b/apps/admin-gui/src/app/shared/components/dialogs/remove-destination-dialog/remove-destination-dialog.component.html @@ -0,0 +1,39 @@ +<div class="{{data.theme}}"> + + <h1 mat-dialog-title>{{'DIALOGS.REMOVE_DESTINATIONS.TITLE' | translate}}</h1> + <div mat-dialog-content> + <app-alert + [color]="'warn'">{{'DIALOGS.REMOVE_DESTINATIONS.WARNING' | translate}}</app-alert> + <p> + {{'DIALOGS.REMOVE_DESTINATIONS.DESCRIPTION' | translate}} + </p> + + <div class="font-weight-bold"> + {{'DIALOGS.REMOVE_DESTINATIONS.ASK' | translate}} + </div> + + <app-perun-web-apps-destination-list + [pageSize]="pageSize" + (page)="pageChanged($event)" + [destinations]="this.data.destinations" + [filterValue]="''" + [displayedColumns]="displayedColumns"> + </app-perun-web-apps-destination-list> + + </div> + <div mat-dialog-actions> + <button + mat-flat-button + class="ml-auto" + (click)="onCancel()"> + {{'DIALOGS.REMOVE_DESTINATIONS.CANCEL' | translate}} + </button> + <button + mat-flat-button + class="ml-2" + color="warn" + (click)="onSubmit()"> + {{'DIALOGS.REMOVE_DESTINATIONS.DELETE' | translate}} + </button> + </div> +</div> diff --git a/apps/admin-gui/src/app/shared/components/dialogs/remove-destination-dialog/remove-destination-dialog.component.scss b/apps/admin-gui/src/app/shared/components/dialogs/remove-destination-dialog/remove-destination-dialog.component.scss new file mode 100644 index 000000000..e69de29bb diff --git a/apps/admin-gui/src/app/shared/components/dialogs/remove-destination-dialog/remove-destination-dialog.component.ts b/apps/admin-gui/src/app/shared/components/dialogs/remove-destination-dialog/remove-destination-dialog.component.ts new file mode 100644 index 000000000..274ede261 --- /dev/null +++ b/apps/admin-gui/src/app/shared/components/dialogs/remove-destination-dialog/remove-destination-dialog.component.ts @@ -0,0 +1,44 @@ +import { Component, Inject, OnInit } from '@angular/core'; +import { RichDestination } from '@perun-web-apps/perun/openapi'; +import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog'; +import { PageEvent } from '@angular/material/paginator'; +import { TABLE_FACILITY_SERVICES_DESTINATION_LIST, TableConfigService } from '@perun-web-apps/config/table-config'; + +export interface RemoveDestinationDialogData { + destinations: RichDestination[]; + theme: string; +} + +@Component({ + selector: 'app-perun-web-apps-remove-destination-dialog', + templateUrl: './remove-destination-dialog.component.html', + styleUrls: ['./remove-destination-dialog.component.scss'] +}) +export class RemoveDestinationDialogComponent implements OnInit { + + constructor(public dialogRef: MatDialogRef<RemoveDestinationDialogComponent>, + @Inject(MAT_DIALOG_DATA) public data: RemoveDestinationDialogData, + private tableConfigService: TableConfigService) { } + + displayedColumns: string[] = ['destinationId', 'service', 'destination', 'type', 'propagationType']; + + pageSize: number; + tableId = TABLE_FACILITY_SERVICES_DESTINATION_LIST; + + ngOnInit() { + this.pageSize = this.tableConfigService.getTablePageSize(this.tableId); + } + + onCancel() { + this.dialogRef.close(false); + } + + onSubmit() { + this.dialogRef.close(true); + } + + pageChanged(event: PageEvent) { + this.pageSize = event.pageSize; + this.tableConfigService.setTablePageSize(this.tableId, event.pageSize); + } +} diff --git a/apps/admin-gui/src/app/shared/shared.module.ts b/apps/admin-gui/src/app/shared/shared.module.ts index 247c4ffb3..684cf3db2 100644 --- a/apps/admin-gui/src/app/shared/shared.module.ts +++ b/apps/admin-gui/src/app/shared/shared.module.ts @@ -153,7 +153,9 @@ import { EditAttributeDialogComponent } from './components/dialogs/edit-attribut import { UserSettingsAppConfigurationComponent } from './components/user-detail-page/user-settings/user-settings-app-configuration/user-settings-app-configuration.component'; import { ConfigTableConfigModule } from '@perun-web-apps/config/table-config'; import { PerunPipesModule } from '@perun-web-apps/perun/pipes'; - +import { RemoveDestinationDialogComponent } from './components/dialogs/remove-destination-dialog/remove-destination-dialog.component'; +import { DestinationListComponent } from './components/destination-list/destination-list.component'; +import { AddServicesDestinationDialogComponent } from './components/dialogs/add-services-destination-dialog/add-services-destination-dialog.component'; @NgModule({ imports: [ CommonModule, @@ -280,7 +282,8 @@ import { PerunPipesModule } from '@perun-web-apps/perun/pipes'; ExtSourcesListComponent, ExtSourceTypePipe, ConfigTableConfigModule, - SideMenuRootItemComponent + SideMenuRootItemComponent, + DestinationListComponent ], declarations: [ PerunNavComponent, @@ -384,7 +387,10 @@ import { PerunPipesModule } from '@perun-web-apps/perun/pipes'; ExtSourceTypePipe, UserRolesComponent, EditAttributeDialogComponent, - UserSettingsAppConfigurationComponent + UserSettingsAppConfigurationComponent, + RemoveDestinationDialogComponent, + DestinationListComponent, + AddServicesDestinationDialogComponent ], providers: [ AnyToStringPipe, diff --git a/apps/admin-gui/src/app/shared/side-menu/side-menu-item.service.ts b/apps/admin-gui/src/app/shared/side-menu/side-menu-item.service.ts index 550722a36..f6cd17ce9 100644 --- a/apps/admin-gui/src/app/shared/side-menu/side-menu-item.service.ts +++ b/apps/admin-gui/src/app/shared/side-menu/side-menu-item.service.ts @@ -206,6 +206,11 @@ export class SideMenuItemService { url: [`/facilities/${facility.id}/service-config`], activatedRegex: 'facilities/\\d+/service-config' }, + { + label: 'MENU_ITEMS.FACILITY.SERVICES_DESTINATIONS', + url: [`/facilities/${facility.id}/services-destinations`], + activatedRegex: 'facilities/\\d+/services-destinations' + }, { label: 'MENU_ITEMS.FACILITY.SETTINGS', url: ['/facilities', facility.id, 'settings'], diff --git a/apps/admin-gui/src/assets/i18n/en.json b/apps/admin-gui/src/assets/i18n/en.json index 41dbd113b..630da4484 100644 --- a/apps/admin-gui/src/assets/i18n/en.json +++ b/apps/admin-gui/src/assets/i18n/en.json @@ -101,6 +101,19 @@ "ALL": "All", "NO_GROUPS_ALERT": "No groups found." }, + "SERVICES_DESTINATIONS": { + "TITLE": "Services Destinations", + "ADD": "Add", + "REMOVE": "Remove", + "FILTER": "Filter", + "TABLE_DESTINATION_ID": "Destination ID", + "TABLE_SERVICE": "Service", + "TABLE_DESTINATION": "Destination", + "TABLE_TYPE": "Type", + "TABLE_PROPAGATION_TYPE": "Propagation Type", + "NO_DESTINATION": "Facility has no services destinations. Service configuration can't be propagated.", + "REMOVE_SUCCESS": "Facilities were successfully removed" + }, "SETTINGS": { "ATTRIBUTES": { "TITLE": "Attributes", @@ -512,7 +525,8 @@ "SETTINGS": "Settings", "ATTRIBUTES": "Attributes", "SERVICE_CONFIG": "Services configuration", - "MANAGERS": "Managers" + "MANAGERS": "Managers", + "SERVICES_DESTINATIONS": "Services destinations" }, "RESOURCE": { "OVERVIEW": "Overview", @@ -1085,6 +1099,33 @@ "TOOLTIP_CONFIRM": "Fill every required field", "SHOW_KEYS": "Show keys", "SERVICES": "Dependent services:" + }, + "REMOVE_DESTINATIONS": { + "TITLE": "Confirm delete action", + "WARNING": "Removing destination will stop propagation of service's configuration for this destination/service.", + "DESCRIPTION": "Following destinations will be removed.", + "ASK": "Do you want to proceed?", + "CANCEL": "Cancel", + "DELETE": "Delete" + }, + "ADD_SERVICE_DESTINATION": { + "TITLE": "Add destination", + "DESCRIPTION": "Please add destinations for service configuration delivery. New service configuration can be performed directly on facility (dest. type HOST) or sent to URL or by an email.", + "SERVICE": "Service", + "SELECTION_ALL": "All", + "NO_SERVICE": "No service available", + "CHOOSE_SERVICE": "You must choose service", + "TYPE_EMAIL": "Please type valid email", + "IS_SERVICES_ONLY_ON_FACILITY": "Show only services on facility", + "TYPE": "Type", + "HOST": "Host", + "REQUIRED_FIELD": "Destination value can't be empty.", + "USE_FACILITY_HOST": "Use names of all facility's hosts", + "PROPAGATION": "Propagation", + "PROPAGATION_TYPE_PARALLEL": "PARALLEL - Data for all destinations and one service are pushed in parallel.", + "PROPAGATION_TYPE_DUMMY": "DUMMY - Service provisioning data is generated by Perun, but not pushed to destination. Destinations can pull data by themselves.", + "CANCEL": "Cancel", + "ADD": "Add" } }, "MEMBERS_LIST": { diff --git a/libs/config/table-config/src/lib/table-config.service.ts b/libs/config/table-config/src/lib/table-config.service.ts index 5ea4af309..cd817f55b 100644 --- a/libs/config/table-config/src/lib/table-config.service.ts +++ b/libs/config/table-config/src/lib/table-config.service.ts @@ -67,3 +67,4 @@ export const TABLE_USER_DETAIL_ADMIN_GROUPS = '33'; export const TABLE_GROUP_SETTINGS_RELATIONS = '34'; export const TABLE_GROUP_SUBGROUPS = '35'; export const TABLE_VO_GROUPS = '36'; +export const TABLE_FACILITY_SERVICES_DESTINATION_LIST = '37'; diff --git a/libs/perun/services/src/lib/custom-icon.service.ts b/libs/perun/services/src/lib/custom-icon.service.ts index c445f9902..0257e5a28 100644 --- a/libs/perun/services/src/lib/custom-icon.service.ts +++ b/libs/perun/services/src/lib/custom-icon.service.ts @@ -111,10 +111,16 @@ export class CustomIconService { url: 'assets/img/PerunWebImages/external_sources-white.svg', name: 'perun-external-sources' }, +<<<<<<< HEAD // TESTING PURPOSES { url: 'assets/img/settings1-blue.svg', name: 'settings-blue' +======= + { + url: 'assets/img/PerunWebImages/service_destination-blue.svg', + name: 'perun-service_destination' +>>>>>>> f232c60... Facilities - services destinations page }, ]; -- GitLab From ba7ebb72c37f16dadf7c047c94f5653ffbf1cf76 Mon Sep 17 00:00:00 2001 From: Lucie Kureckova <lkureckova@seznam.cz> Date: Sun, 10 May 2020 17:49:10 +0200 Subject: [PATCH 2/4] Facilities - services destinations page * resolve conflicts --- libs/perun/services/src/lib/custom-icon.service.ts | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/libs/perun/services/src/lib/custom-icon.service.ts b/libs/perun/services/src/lib/custom-icon.service.ts index 0257e5a28..95a418b1e 100644 --- a/libs/perun/services/src/lib/custom-icon.service.ts +++ b/libs/perun/services/src/lib/custom-icon.service.ts @@ -111,16 +111,14 @@ export class CustomIconService { url: 'assets/img/PerunWebImages/external_sources-white.svg', name: 'perun-external-sources' }, -<<<<<<< HEAD // TESTING PURPOSES { url: 'assets/img/settings1-blue.svg', name: 'settings-blue' -======= + }, { url: 'assets/img/PerunWebImages/service_destination-blue.svg', name: 'perun-service_destination' ->>>>>>> f232c60... Facilities - services destinations page }, ]; -- GitLab From 5a14e6bce307eb1830e3fac8162a76e359d9fb21 Mon Sep 17 00:00:00 2001 From: Daniel Fecko <38562381+DanoFecko@users.noreply.github.com> Date: Thu, 14 May 2020 09:41:38 +0200 Subject: [PATCH 3/4] Handling error when perunPrincipal.user is null (#219) * Error message for case when user doesn't exist * Error message for case when perunPrincipal.user is null --- .../services/common/admin-gui-config.service.ts | 1 - apps/admin-gui/src/assets/i18n/en.json | 3 +++ libs/general/src/index.ts | 1 + libs/general/src/lib/general.module.ts | 8 +++++--- .../user-dont-exist-dialog.component.html | 1 + .../user-dont-exist-dialog.component.scss | 0 .../user-dont-exist-dialog.component.ts | 13 +++++++++++++ .../components/src/lib/perun-components.module.ts | 5 ++++- libs/perun/services/src/lib/init-auth.service.ts | 13 ++++++++++--- 9 files changed, 37 insertions(+), 8 deletions(-) create mode 100644 libs/general/src/lib/user-dont-exist-dialog/user-dont-exist-dialog.component.html create mode 100644 libs/general/src/lib/user-dont-exist-dialog/user-dont-exist-dialog.component.scss create mode 100644 libs/general/src/lib/user-dont-exist-dialog/user-dont-exist-dialog.component.ts diff --git a/apps/admin-gui/src/app/core/services/common/admin-gui-config.service.ts b/apps/admin-gui/src/app/core/services/common/admin-gui-config.service.ts index ad8f6aec0..067c978bd 100644 --- a/apps/admin-gui/src/app/core/services/common/admin-gui-config.service.ts +++ b/apps/admin-gui/src/app/core/services/common/admin-gui-config.service.ts @@ -107,7 +107,6 @@ export class AdminGuiConfigService { } private handlePrincipalErr(err: any) { - console.log("sdfsdf"); this.translate.get('GENERAL.PRINCIPAL.ERROR.TITLE').subscribe(sdf => console.log(sdf)); this.dialog.open(ServerDownDialogComponent, { data: { diff --git a/apps/admin-gui/src/assets/i18n/en.json b/apps/admin-gui/src/assets/i18n/en.json index 41dbd113b..a9dc34538 100644 --- a/apps/admin-gui/src/assets/i18n/en.json +++ b/apps/admin-gui/src/assets/i18n/en.json @@ -1336,6 +1336,9 @@ "NAME": "Name", "VALUE": "Value", "DESCRIPTION": "Description" + }, + "USER_DONT_EXIST": { + "TITLE": "Requested user (by ID or external identity) doesn't exist." } }, "ORGANIZATIONS": { diff --git a/libs/general/src/index.ts b/libs/general/src/index.ts index 193737685..bff3eee99 100644 --- a/libs/general/src/index.ts +++ b/libs/general/src/index.ts @@ -1,2 +1,3 @@ export * from './lib/general.module'; export * from './lib/server-down-dialog/server-down-dialog.component'; +export * from './lib/user-dont-exist-dialog/user-dont-exist-dialog.component' diff --git a/libs/general/src/lib/general.module.ts b/libs/general/src/lib/general.module.ts index 74933ea85..08a7825a8 100644 --- a/libs/general/src/lib/general.module.ts +++ b/libs/general/src/lib/general.module.ts @@ -3,10 +3,12 @@ import { CommonModule } from '@angular/common'; import { ServerDownDialogComponent } from './server-down-dialog/server-down-dialog.component'; import { MatDialogModule } from '@angular/material/dialog'; import { MatButtonModule } from '@angular/material/button'; +import { UserDontExistDialogComponent } from './user-dont-exist-dialog/user-dont-exist-dialog.component'; +import { TranslateModule } from '@ngx-translate/core'; @NgModule({ - imports: [CommonModule, MatDialogModule, MatButtonModule], - exports: [ServerDownDialogComponent], - declarations: [ServerDownDialogComponent] + imports: [CommonModule, MatDialogModule, MatButtonModule, TranslateModule], + exports: [ServerDownDialogComponent, UserDontExistDialogComponent], + declarations: [ServerDownDialogComponent, UserDontExistDialogComponent] }) export class GeneralModule {} diff --git a/libs/general/src/lib/user-dont-exist-dialog/user-dont-exist-dialog.component.html b/libs/general/src/lib/user-dont-exist-dialog/user-dont-exist-dialog.component.html new file mode 100644 index 000000000..3d31c3db6 --- /dev/null +++ b/libs/general/src/lib/user-dont-exist-dialog/user-dont-exist-dialog.component.html @@ -0,0 +1 @@ +<h2 mat-dialog-content class="mt-2 mb-2">{{'SHARED_LIB.PERUN.COMPONENTS.USER_DONT_EXIST.TITLE' | translate}}</h2> diff --git a/libs/general/src/lib/user-dont-exist-dialog/user-dont-exist-dialog.component.scss b/libs/general/src/lib/user-dont-exist-dialog/user-dont-exist-dialog.component.scss new file mode 100644 index 000000000..e69de29bb diff --git a/libs/general/src/lib/user-dont-exist-dialog/user-dont-exist-dialog.component.ts b/libs/general/src/lib/user-dont-exist-dialog/user-dont-exist-dialog.component.ts new file mode 100644 index 000000000..d1ac4c104 --- /dev/null +++ b/libs/general/src/lib/user-dont-exist-dialog/user-dont-exist-dialog.component.ts @@ -0,0 +1,13 @@ +import { Component} from '@angular/core'; +import { MatDialogRef } from '@angular/material/dialog'; + +@Component({ + selector: 'perun-web-apps-user-dont-exist-dialog', + templateUrl: './user-dont-exist-dialog.component.html', + styleUrls: ['./user-dont-exist-dialog.component.scss'] +}) +export class UserDontExistDialogComponent { + + constructor(public dialogRef: MatDialogRef<UserDontExistDialogComponent>) { + } +} diff --git a/libs/perun/components/src/lib/perun-components.module.ts b/libs/perun/components/src/lib/perun-components.module.ts index 8c992982f..a929b0da5 100644 --- a/libs/perun/components/src/lib/perun-components.module.ts +++ b/libs/perun/components/src/lib/perun-components.module.ts @@ -37,6 +37,8 @@ import { MatRippleModule } from '@angular/material/core'; import { AttributeValueListEditDialogComponent } from './attributes-list/attribute-value/attribute-value-list/attribute-value-list-edit-dialog/attribute-value-list-edit-dialog.component'; import { AttributeValueListDeleteDialogComponent } from './attributes-list/attribute-value/attribute-value-list/attribute-value-list-delete-dialog/attribute-value-list-delete-dialog.component'; import { PerunPipesModule } from '@perun-web-apps/perun/pipes'; +import { MatDialogModule } from '@angular/material/dialog'; + @NgModule({ imports: [ @@ -61,7 +63,8 @@ import { PerunPipesModule } from '@perun-web-apps/perun/pipes'; ReactiveFormsModule, MatInputModule, MatRippleModule, - PerunPipesModule + PerunPipesModule, + MatDialogModule ], declarations: [ VoSelectTableComponent, diff --git a/libs/perun/services/src/lib/init-auth.service.ts b/libs/perun/services/src/lib/init-auth.service.ts index ee886e2d4..2d755dcbc 100644 --- a/libs/perun/services/src/lib/init-auth.service.ts +++ b/libs/perun/services/src/lib/init-auth.service.ts @@ -4,6 +4,8 @@ import { AuthService } from './auth.service'; import { StoreService } from './store.service'; import { GuiAuthResolver } from './gui-auth-resolver.service'; import { AuthzResolverService } from '@perun-web-apps/perun/openapi'; +import { MatDialog } from '@angular/material/dialog'; +import { UserDontExistDialogComponent } from '@perun-web-apps/general'; @Injectable({ providedIn: 'root' @@ -14,7 +16,8 @@ export class InitAuthService { private authService: AuthService, private storeService: StoreService, private authResolver: GuiAuthResolver, - private authzService: AuthzResolverService + private authzService: AuthzResolverService, + private dialog: MatDialog ) { } @@ -40,8 +43,12 @@ export class InitAuthService { return this.authzService.getPerunPrincipal() .toPromise() .then(perunPrincipal => { - this.storeService.setPerunPrincipal(perunPrincipal); - this.authResolver.init(perunPrincipal); + if (perunPrincipal.user === null) { + this.dialog.open(UserDontExistDialogComponent, { disableClose: true }); + } else { + this.storeService.setPerunPrincipal(perunPrincipal); + this.authResolver.init(perunPrincipal); + } }); } } -- GitLab From 59fa84977fe333145b3a4bc7b1de4b2ca377869a Mon Sep 17 00:00:00 2001 From: xkureck <445264@mail.muni.cz> Date: Fri, 15 May 2020 18:36:48 +0200 Subject: [PATCH 4/4] Facilities - services destinations page * fixed mat paginator * add successful notification when adding destinations * long lines were divided --- ...acility-services-destinations.component.ts | 10 ++++++--- .../destination-list.component.html | 19 ++++++++++++++--- .../destination-list.component.ts | 21 +++++++++++++++---- apps/admin-gui/src/assets/i18n/en.json | 3 ++- 4 files changed, 42 insertions(+), 11 deletions(-) diff --git a/apps/admin-gui/src/app/facilities/pages/facility-detail-page/facility-services-destinations/facility-services-destinations.component.ts b/apps/admin-gui/src/app/facilities/pages/facility-detail-page/facility-services-destinations/facility-services-destinations.component.ts index 1f83d1e49..0926f4ab0 100644 --- a/apps/admin-gui/src/app/facilities/pages/facility-detail-page/facility-services-destinations/facility-services-destinations.component.ts +++ b/apps/admin-gui/src/app/facilities/pages/facility-detail-page/facility-services-destinations/facility-services-destinations.component.ts @@ -50,9 +50,9 @@ export class FacilityServicesDestinationsComponent implements OnInit { tableId = TABLE_FACILITY_SERVICES_DESTINATION_LIST; ngOnInit() { - this.loading = true; - this.pageSize = this.tableConfigService.getTablePageSize(this.tableId); + this.pageSize = this.tableConfigService.getTablePageSize(this.tableId); + this.loading = true; this.route.parent.params.subscribe(parentParams => { const facilityId = parentParams['facilityId']; @@ -81,7 +81,10 @@ export class FacilityServicesDestinationsComponent implements OnInit { dialogRef.afterClosed().subscribe(result => { if (result) { - this.refreshTable(); + this.translate.get('FACILITY_DETAIL.SERVICES_DESTINATIONS.ADD_SUCCESS').subscribe(successMessage => { + this.refreshTable(); + this.notificator.showSuccess(successMessage); + }); } }); } @@ -105,6 +108,7 @@ export class FacilityServicesDestinationsComponent implements OnInit { } pageChanged(event: PageEvent) { + console.log(event.pageSize); this.pageSize = event.pageSize; this.tableConfigService.setTablePageSize(this.tableId, event.pageSize); } diff --git a/apps/admin-gui/src/app/shared/components/destination-list/destination-list.component.html b/apps/admin-gui/src/app/shared/components/destination-list/destination-list.component.html index e33b6c2bc..7fa53ade9 100644 --- a/apps/admin-gui/src/app/shared/components/destination-list/destination-list.component.html +++ b/apps/admin-gui/src/app/shared/components/destination-list/destination-list.component.html @@ -1,7 +1,20 @@ -<div class="card mt-3" [class.hide-table]="exporting" [hidden]="dataSource.filteredData.length === 0 || destinations.length === 0"> +<div class="card mt-3" + [class.hide-table]="exporting" + [hidden]="dataSource.filteredData.length === 0 || destinations.length === 0"> <div class="card-body"> - <perun-web-apps-table-options (end)="exporting = false" (start)="exporting = true" [exporter]="exporter" class="ml-auto"></perun-web-apps-table-options> - <table mat-table matTableExporter [dataSource]="dataSource" #exporter="matTableExporter" matSort matSortActive="id" matSortDirection="asc" matSortDisableClear + <perun-web-apps-table-options + (end)="exporting = false" + (start)="exporting = true" + [exporter]="exporter" + class="ml-auto"> + </perun-web-apps-table-options> + <table mat-table matTableExporter + [dataSource]="dataSource" + #exporter="matTableExporter" + matSort + matSortActive="id" + matSortDirection="asc" + matSortDisableClear class="w-100"> <ng-container matColumnDef="select"> diff --git a/apps/admin-gui/src/app/shared/components/destination-list/destination-list.component.ts b/apps/admin-gui/src/app/shared/components/destination-list/destination-list.component.ts index 44e8af0a6..c4136ae3c 100644 --- a/apps/admin-gui/src/app/shared/components/destination-list/destination-list.component.ts +++ b/apps/admin-gui/src/app/shared/components/destination-list/destination-list.component.ts @@ -1,4 +1,13 @@ -import { Component, EventEmitter, Input, OnChanges, Output, SimpleChanges, ViewChild } from '@angular/core'; +import { + AfterViewInit, + Component, + EventEmitter, + Input, + OnChanges, + Output, + SimpleChanges, + ViewChild +} from '@angular/core'; import { MatSort } from '@angular/material/sort'; import { RichDestination, RichResource } from '@perun-web-apps/perun/openapi'; import { SelectionModel } from '@angular/cdk/collections'; @@ -11,7 +20,7 @@ import { TABLE_ITEMS_COUNT_OPTIONS } from '@perun-web-apps/perun/utils'; templateUrl: './destination-list.component.html', styleUrls: ['./destination-list.component.scss'] }) -export class DestinationListComponent implements OnChanges { +export class DestinationListComponent implements AfterViewInit, OnChanges { constructor() { } @@ -53,7 +62,6 @@ export class DestinationListComponent implements OnChanges { setDataSource() { if (!!this.dataSource) { this.dataSource.sort = this.sort; - this.dataSource.paginator = this.paginator; this.dataSource.sortingDataAccessor = (item, property) => { switch (property) { case 'service': { @@ -65,7 +73,8 @@ export class DestinationListComponent implements OnChanges { this.dataSource.filterPredicate = (data, filter) => { const dataStr = data.service.name + data.id + data.destination + data.type + data.propagationType; return dataStr.indexOf(filter) !== -1; - } + }; + this.dataSource.paginator = this.paginator; } } @@ -95,4 +104,8 @@ export class DestinationListComponent implements OnChanges { this.page.emit(event); } + ngAfterViewInit(): void { + this.dataSource.paginator = this.paginator; + } + } diff --git a/apps/admin-gui/src/assets/i18n/en.json b/apps/admin-gui/src/assets/i18n/en.json index 5779f05bf..02412a1ce 100644 --- a/apps/admin-gui/src/assets/i18n/en.json +++ b/apps/admin-gui/src/assets/i18n/en.json @@ -112,7 +112,8 @@ "TABLE_TYPE": "Type", "TABLE_PROPAGATION_TYPE": "Propagation Type", "NO_DESTINATION": "Facility has no services destinations. Service configuration can't be propagated.", - "REMOVE_SUCCESS": "Facilities were successfully removed" + "REMOVE_SUCCESS": "Destinations were successfully removed", + "ADD_SUCCESS": "Destinations were successfully added" }, "SETTINGS": { "ATTRIBUTES": { -- GitLab