diff --git a/src/app/appmarket/admin/configuration/details/configurationdetails.component.spec.ts b/src/app/appmarket/admin/configuration/details/configurationdetails.component.spec.ts index a4a16f4886c54bbf0f2a56c8f438975c435b1454..4fc9b0a1f0676ad4f0ca86e79fbc3b8d570668dc 100644 --- a/src/app/appmarket/admin/configuration/details/configurationdetails.component.spec.ts +++ b/src/app/appmarket/admin/configuration/details/configurationdetails.component.spec.ts @@ -9,10 +9,13 @@ import {TranslateFakeLoader, TranslateLoader, TranslateModule} from '@ngx-transl import {InternationalizationService} from '../../../../service/internationalization.service'; import createSpyObj = jasmine.createSpyObj; import { CUSTOM_ELEMENTS_SCHEMA } from '@angular/core'; +import {ToastContainerComponent} from '../../../../shared/toast-container/toast-container.component'; + describe('ConfigurationDetailsComponent', () => { let component: ConfigurationDetailsComponent; let fixture: ComponentFixture<ConfigurationDetailsComponent>; + let mockToast: jasmine.SpyObj<ToastContainerComponent>; beforeEach(waitForAsync(() => { const internationalizationSpy = createSpyObj('InternationalizationService', ['getEnabledLanguages', 'getAllSupportedLanguages']) @@ -22,6 +25,7 @@ describe('ConfigurationDetailsComponent', () => { const configurationServiceSpy = createSpyObj('ConfigurationService', ['getConfiguration', 'updateConfiguration']) configurationServiceSpy.getConfiguration.and.returnValue(of()) configurationServiceSpy.updateConfiguration.and.returnValue(of()) + mockToast = jasmine.createSpyObj('ToastContainerComponent', ['show']); TestBed.configureTestingModule({ declarations: [ConfigurationDetailsComponent], @@ -37,7 +41,8 @@ describe('ConfigurationDetailsComponent', () => { ], providers: [ {provide: ConfigurationService, useValue: configurationServiceSpy}, - {provide: InternationalizationService, useValue: internationalizationSpy} + {provide: InternationalizationService, useValue: internationalizationSpy}, + { provide: ToastContainerComponent, useValue: mockToast } ], schemas: [CUSTOM_ELEMENTS_SCHEMA], }) diff --git a/src/app/appmarket/admin/configuration/details/configurationdetails.component.ts b/src/app/appmarket/admin/configuration/details/configurationdetails.component.ts index d43fcfd51f299193fc3908bbdabeddea06779774..62519d173d66eb7ce9c15b14c640400ef4de5f55 100644 --- a/src/app/appmarket/admin/configuration/details/configurationdetails.component.ts +++ b/src/app/appmarket/admin/configuration/details/configurationdetails.component.ts @@ -5,6 +5,7 @@ import {ConfigurationService} from '../../../../service'; import {Configuration} from '../../../../model/configuration'; import {InternationalizationService} from '../../../../service/internationalization.service'; import {Language} from '../../../../model/language'; +import {ToastContainerComponent, ToastMode} from '../../../../shared/toast-container/toast-container.component'; @@ -21,7 +22,8 @@ export class ConfigurationDetailsComponent extends BaseComponent implements OnIn constructor(private router: Router, private configurationService: ConfigurationService, - private languageService: InternationalizationService) { + private languageService: InternationalizationService, + private toast: ToastContainerComponent) { super(); } @@ -35,9 +37,16 @@ export class ConfigurationDetailsComponent extends BaseComponent implements OnIn } public save(): void { + this.configurationService.updateConfiguration(this.configuration).subscribe( - () => this.update(), - err => this.errorMsg = err.message + () => { + this.update() + this.toast.show('Success', ToastMode.SUCCESS, 'HEADER') + }, + err => { + this.errorMsg = err.message + this.toast.show('Danger', ToastMode.DANGER, 'HEADER') + } ); } diff --git a/src/app/shared/admin-dashboard/admin-dashboard.component.css b/src/app/shared/admin-dashboard/admin-dashboard.component.css index fdab80cb4c0d886552fe88c52387d4e9616f0493..8abeaa8ecf4ac107b08b128912ae1b74d088958b 100644 --- a/src/app/shared/admin-dashboard/admin-dashboard.component.css +++ b/src/app/shared/admin-dashboard/admin-dashboard.component.css @@ -66,4 +66,6 @@ th{ width:100% } } - +:host ::ng-deep .p-datatable>.p-datatable-wrapper { + overflow: auto; +} diff --git a/src/app/shared/admin-dashboard/admin-dashboard.component.html b/src/app/shared/admin-dashboard/admin-dashboard.component.html index 7e01f82968e8ac8e082a90d767a6e52c5fb10274..7e72a08092d2236988714df76ba94730eb7dc72d 100644 --- a/src/app/shared/admin-dashboard/admin-dashboard.component.html +++ b/src/app/shared/admin-dashboard/admin-dashboard.component.html @@ -26,7 +26,7 @@ selectionMode="range" [readonlyInput]="true" (ngModelChange)="onDateChange($event)" - placeholder="Select date range" + showClear="true" dateFormat="dd.mm.yy" /> @@ -42,8 +42,9 @@ </tr> </ng-template> <ng-template pTemplate="body" let-instance> - <tr> - <td><img style="height: 40px" [src]="(appImagesService.getAppLogoUrl(instance.appId) | secure) || '../../../assets/images/app-logo-example.png'"/></td> + <tr [ngClass]="{'clickable': !userHasGuestRoleInCurrentDomain()}" + [routerLink]="userHasGuestRoleInCurrentDomain() ? [] : [instance.id]"> + <td><img style="width: 40px" [src]="(appImagesService.getAppLogoUrl(instance.appId) | secure) || '../../../assets/images/app-logo-example.png'"/></td> <td>{{instance.applicationName}}</td> <td>{{instance.applicationVersion}}</td> <td>{{instance.domainName}}</td> @@ -113,7 +114,7 @@ </ng-template> <ng-template pTemplate="body" let-app> <tr> - <td><img style="height: 40px" [src]="(appImagesService.getAppLogoUrl(app.appId) | secure) || '../../../assets/images/app-logo-example.png'"/></td> + <td><img style="width: 40px" [src]="(appImagesService.getAppLogoUrl(app.appId) | secure) || '../../../assets/images/app-logo-example.png'"/></td> <td>{{app.appName}}</td> <td>{{app.appId}}</td> <td>{{app.instanceName}}</td> diff --git a/src/app/shared/admin-dashboard/admin-dashboard.component.spec.ts b/src/app/shared/admin-dashboard/admin-dashboard.component.spec.ts index 860578e237ff398405ccb76b4281b4d303439d19..65e8f7587d236a753d78e8d0600e1ed1187d5a55 100644 --- a/src/app/shared/admin-dashboard/admin-dashboard.component.spec.ts +++ b/src/app/shared/admin-dashboard/admin-dashboard.component.spec.ts @@ -6,6 +6,7 @@ import { UserDataService } from '../../service/userdata.service'; import { CUSTOM_ELEMENTS_SCHEMA, NO_ERRORS_SCHEMA } from '@angular/core'; import {AppImagesService, AppsService} from '../../service'; import {ActivatedRoute} from '@angular/router'; +import {AuthService} from '../../auth/auth.service'; describe('AdminDashboardComponent', () => { let component: AdminDashboardComponent; @@ -19,6 +20,8 @@ describe('AdminDashboardComponent', () => { ]; beforeEach(async () => { + const authServiceSpy = jasmine.createSpyObj('AuthService', ['hasDomainRole']); + authServiceSpy.hasDomainRole.and.returnValue(true) mockDashboardService = jasmine.createSpyObj('DashboardService', ['getAdmin', 'getDomainAdmin']); mockUserDataService = jasmine.createSpyObj('UserDataService', ['selectedDomainId']); const appImagesServiceSpy = jasmine.createSpyObj('AppImagesService', ['getAppLogoUrl']); @@ -40,7 +43,8 @@ describe('AdminDashboardComponent', () => { {provide: AppImagesService, useValue: appImagesServiceSpy}, { provide: UserDataService, useValue: mockUserDataService }, {provide: ActivatedRoute, useValue: {params: of({id: 1})}}, - { provide: AppsService, useValue: appsServiceSpy } + { provide: AppsService, useValue: appsServiceSpy }, + {provide: AuthService, useValue: authServiceSpy} ], schemas: [NO_ERRORS_SCHEMA, CUSTOM_ELEMENTS_SCHEMA] // Add this to allow unknown properties }).compileComponents(); diff --git a/src/app/shared/admin-dashboard/admin-dashboard.component.ts b/src/app/shared/admin-dashboard/admin-dashboard.component.ts index 66918dda6626f8d58a51b5cb7a07c5c47a65ec0d..d3828df6b76bfd20f4212ca3c21533cd46a8856f 100644 --- a/src/app/shared/admin-dashboard/admin-dashboard.component.ts +++ b/src/app/shared/admin-dashboard/admin-dashboard.component.ts @@ -3,6 +3,7 @@ import {DashboardService} from '../../service/dashboard.service'; import {UserDataService} from '../../service/userdata.service'; import {AppImagesService, AppsService} from '../../service'; import {ActivatedRoute} from '@angular/router'; +import {AuthService} from '../../auth/auth.service'; @Component({ selector: 'app-admin-dashboard', @@ -29,7 +30,8 @@ export class AdminDashboardComponent { private userDataService: UserDataService, public appImagesService: AppImagesService, private route: ActivatedRoute, - private appsService: AppsService) { + private appsService: AppsService, + public authService: AuthService) { } @@ -145,5 +147,9 @@ export class AdminDashboardComponent { start.setDate(start.getDate() - 7); this.startDate = start.toISOString(); this.endDate = end.toISOString(); + this.rangeDates = [new Date(start.setDate(start.getDate() - 7)), end] + } + public userHasGuestRoleInCurrentDomain(): boolean { + return this.authService.hasDomainRole(this.domainId, 'ROLE_GUEST'); } } diff --git a/src/app/shared/admin/clusters/manager/manager.component.html b/src/app/shared/admin/clusters/manager/manager.component.html index 785c7ebb96573cfb100f3b889556f554dca83c16..8a2e06fa97790ad74bb6eb0831b3adde7c7dc838 100644 --- a/src/app/shared/admin/clusters/manager/manager.component.html +++ b/src/app/shared/admin/clusters/manager/manager.component.html @@ -23,9 +23,6 @@ [responsiveLayout]="'scroll'"> <ng-template pTemplate="header"> <tr> - <th pSortableColumn="id" id="id"> {{ 'CLUSTERS.ID' | translate }} - <p-sortIcon field="id"></p-sortIcon> - </th> <th pSortableColumn="name" id="name"> {{ 'CLUSTERS.NAME' | translate }} <p-sortIcon field="name"></p-sortIcon> </th> @@ -35,23 +32,14 @@ <th pSortableColumn="state" id="state"> {{ 'CLUSTERS.STATE' | translate }} <p-sortIcon field="state"></p-sortIcon> </th> - <th pSortableColumn="creationDate" id="creationDate"> {{ 'CLUSTERS.CREATION_DATE' | translate }} - <p-sortIcon field="creationDate"></p-sortIcon> - </th> - <th pSortableColumn="modificationDate" id="modificationDate"> {{ 'CLUSTERS.MODIFICATION_DATE' | translate }} - <p-sortIcon field="modificationDate"></p-sortIcon> - </th> <th></th> </tr> </ng-template> <ng-template pTemplate="body" let-cluster> <tr> - <td [routerLink]="[cluster.id]">{{cluster.id}}</td> <td [routerLink]="[cluster.id]">{{cluster.name}}</td> <td [routerLink]="[cluster.id]">{{cluster.codename}}</td> <td [routerLink]="[cluster.id]">{{('CLUSTERS.'+cluster.state.toString().toUpperCase() ) | translate}}</td> - <td [routerLink]="[cluster.id]">{{cluster.creationDate | date: 'dd-MM-yyyy HH:mm'}}</td> - <td [routerLink]="[cluster.id]">{{cluster.modificationDate | date: 'dd-MM-yyyy HH:mm'}}</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"> diff --git a/src/app/shared/common/domainfilter/domainfilter.component.ts b/src/app/shared/common/domainfilter/domainfilter.component.ts index 57723deda8e95bddd8f115b8ca89e7f32fdeb62a..78d7a2150cafd823e9c502ffab4c0cb7caf5c863 100644 --- a/src/app/shared/common/domainfilter/domainfilter.component.ts +++ b/src/app/shared/common/domainfilter/domainfilter.component.ts @@ -56,9 +56,17 @@ export class DomainFilterComponent implements OnInit { this.updateDomains(); this.domains.subscribe(domain => { - this.selectedDomain = domain[0]; - this.domainName = domain[0].name; - this.userData.selectDomainId(domain[0].id) + const savedDomainId = sessionStorage.getItem('selectedDomainId'); + const savedDomain = domain.find(d => d.id === Number(savedDomainId)); + if (savedDomain) { + this.selectedDomain = savedDomain; + this.domainName = savedDomain.name; + this.userData.selectDomainId(savedDomain.id); + } else { + this.selectedDomain = domain[0]; + this.domainName = domain[0].name; + this.userData.selectDomainId(domain[0].id) + } this.filteredDomainsSub.next(domain); }); } @@ -141,6 +149,9 @@ export class DomainFilterComponent implements OnInit { this.domainId = domainId; this.domainName = domainName; this.userData.selectDomainId(Number(domainId)); + + sessionStorage.setItem('selectedDomainId', domainId.toString()); + sessionStorage.setItem('selectedDomainName', domainName); } public getCurrent() { diff --git a/src/app/shared/users/list/userslist.component.html b/src/app/shared/users/list/userslist.component.html index 4f27e95daa33c87868ada58f862ead350493eb0b..716ca13ff16aa03d293bd5d5ceecd0d59006b35f 100644 --- a/src/app/shared/users/list/userslist.component.html +++ b/src/app/shared/users/list/userslist.component.html @@ -69,14 +69,14 @@ <div class="background-section"> <p-table #dt [value]="displayUsers" [paginator]="true" [rows]="maxItemsOnPage" - [rowsPerPageOptions]="[15, 20, 25, 30, 50]" > + [rowsPerPageOptions]="[15, 20, 25, 30, 50]" (sortFunction)="customSort($event)" [customSort]="true"> <ng-template pTemplate="header"> <tr> - <th scope="col" class="column-sortable" pSortableColumn="username"> + <th scope="col" class="column-sortable" pSortableColumn="username"> {{ 'USERS.USER_NAME' | translate }} <p-sortIcon field="username"></p-sortIcon> </th> - <th scope="col" class="column-sortable" pSortableColumn="lastname"> + <th scope="col" class="column-sortable" pSortableColumn="lastname"> {{'USERS.NAME' | translate}} <p-sortIcon field="lastname"></p-sortIcon> </th> @@ -84,11 +84,10 @@ {{'USERS.EMAIL' | translate}} <p-sortIcon field="email"></p-sortIcon> </th> - <th scope="col" class="column-sortable" pSortableColumn="domains" *ngIf="domainId === domainService.getGlobalDomainId()"> + <th scope="col" class="column-sortable" *ngIf="domainId === domainService.getGlobalDomainId()"> {{ 'USERS.DOMAINS' | translate }} - <p-sortIcon field="domains"></p-sortIcon> </th> - <th scope="col" class="column-sortable" pSortableColumn="globalRole" *ngIf="domainId === domainService.getGlobalDomainId()"> + <th scope="col" class="column-sortable" pSortableColumn="globalRole" *ngIf="domainId === domainService.getGlobalDomainId() "> {{ 'USERS.GLOBAL_ROLE' | translate }} <p-sortIcon field="globalRole"></p-sortIcon> </th> @@ -104,7 +103,7 @@ {{ 'USERS.LAST_SUCCESSFUL_LOGIN' | translate }} <p-sortIcon field="lastSuccessfulLoginDate"></p-sortIcon> </th> - <th scope="col" class="column-sortable" pSortableColumn="enabled"> + <th scope="col" class="column-sortable" pSortableColumn="enabled"> {{ 'USERS.ENABLED' | translate }} <p-sortIcon field="enabled"></p-sortIcon> </th> diff --git a/src/app/shared/users/list/userslist.component.ts b/src/app/shared/users/list/userslist.component.ts index 1ae3116b57b2d986b67eaaef9d6ca6a47f96d777..a51a28234e3b9798919e98d37c479b416ffc784f 100644 --- a/src/app/shared/users/list/userslist.component.ts +++ b/src/app/shared/users/list/userslist.component.ts @@ -11,6 +11,7 @@ import {AuthService} from '../../../auth/auth.service'; import {UntypedFormControl} from '@angular/forms'; import {ComponentMode} from '../../common/componentmode'; import {Router} from '@angular/router'; +import {TranslateService} from '@ngx-translate/core'; function userMatches(u: User, term: string): boolean { const t = term || '' @@ -75,7 +76,8 @@ export class UsersListComponent extends BaseComponent implements OnInit, OnChang public domainService: DomainService, private userDataService: UserDataService, public authService: AuthService, - private router: Router) { + private router: Router, + private translate: TranslateService) { super(); userDataService.selectedDomainId.subscribe(domain => this.domainId = domain); } @@ -114,7 +116,6 @@ export class UsersListComponent extends BaseComponent implements OnInit, OnChang }) }) } - } public getDomainName(domainId: number): Observable<string> { @@ -330,6 +331,27 @@ export class UsersListComponent extends BaseComponent implements OnInit, OnChang public checkUserIfIsCurrentUser(userName: string) { return this.authService.getUsername() === userName } + customSort(event: any) { + const { order } = event; + + const roleKeys = this.displayUsers.map(user => + this.getGlobalRole(user).toUpperCase() + ); + const uniqueKeys = [...new Set(roleKeys)]; + const translationKeys = uniqueKeys.map(key => `ENUM.USER_ROLES.${key}`); + + this.translate.get(translationKeys).subscribe(translations => { + this.displayUsers.sort((a, b) => { + const keyA = `ENUM.USER_ROLES.${this.getGlobalRole(a).toUpperCase()}`; + const keyB = `ENUM.USER_ROLES.${this.getGlobalRole(b).toUpperCase()}`; + + const translatedA = translations[keyA] || ''; + const translatedB = translations[keyB] || ''; + + return translatedA.localeCompare(translatedB) * order; + }); + }); + } } function roleConvert(role: string | Role): Role {