From bc4e3f0d16f79167b24464f1ab4d2f350d3ae57e Mon Sep 17 00:00:00 2001 From: David Flor <493294@mail.muni.cz> Date: Tue, 8 Aug 2023 14:20:06 +0200 Subject: [PATCH 1/9] fix: do not redirect to proxy logout page when not required * even when proxy_logout was false, oauth-service redirected to logout page specified in openid-configuration. This no longer happens --- libs/perun/services/src/lib/auth.service.ts | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/libs/perun/services/src/lib/auth.service.ts b/libs/perun/services/src/lib/auth.service.ts index 5f69cd29a..1a08af3d2 100644 --- a/libs/perun/services/src/lib/auth.service.ts +++ b/libs/perun/services/src/lib/auth.service.ts @@ -49,13 +49,14 @@ export class AuthService { void this.router.navigate(['/service-access'], { queryParamsHandling: 'preserve' }); } else { this.logoutProcess = true; - this.oauthService.logOut(); + const proxyLogout = this.store.getProperty('proxy_logout'); + this.oauthService.logOut(!proxyLogout); const postLogoutUrl = this.store.getProperty('oidc_client').oauth_post_logout_redirect_uri; if (!postLogoutUrl) { // redirect to the login page if there is no postLogoutUrl void this.router.navigate(['/login'], { queryParamsHandling: 'preserve' }); - } else if (this.store.getProperty('proxy_logout')) { + } else if (proxyLogout) { // redirect to the logout loading page if postLogoutUrl exist and logout should be handled by proxy void this.router.navigate(['/logout'], { queryParamsHandling: 'preserve' }); } else { From a742e804a59872ea10f7b4b41e0e510ef55d3d15 Mon Sep 17 00:00:00 2001 From: Adam Bodnar Date: Thu, 10 Aug 2023 11:38:34 +0200 Subject: [PATCH 2/9] fix(admin): side menu async items ordering * ordering of side menu items is correct even for async added items --- .../app/shared/side-menu/side-menu-item.service.ts | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) 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 05f8128e0..dc605223b 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 @@ -994,20 +994,20 @@ export class SideMenuItemService { this.apiRequest.dontHandleErrorForNext(); this.attributesManager .getGroupAttributeByName(group.id, Urns.GROUP_DEF_EXPIRATION_RULES) - .subscribe( - () => { - settingsChildrenLinks.push({ + .subscribe({ + next: () => { + settingsChildrenLinks.unshift({ label: 'MENU_ITEMS.GROUP.EXPIRATION', url: [`/organizations/${group.voId}/groups/${group.id}/settings/expiration`], activatedRegex: '/organizations/\\d+/groups/\\d+/settings/expiration$', }); }, - (error: RPCError) => { + error: (error: RPCError) => { if (error.name !== 'PrivilegeException') { this.notificator.showRPCError(error); } - } - ); + }, + }); //SettingsManagers if (this.routePolicyService.canNavigate('groups-settings-managers', group)) { From 5823d9b0a1dcec19ac5ede02c0fd5c948ae1d57c Mon Sep 17 00:00:00 2001 From: HejdaJakub Date: Thu, 10 Aug 2023 12:40:56 +0200 Subject: [PATCH 3/9] fix(lib): display just one alert on login page * When the user is logged out from service-access, he/she can see the info alter about successfull log out. Then if the user try to log in again with incorrect credentials, another alert will be displayed, but the old one used to be still presented on login page. --- .../login-screen-service-access.component.html | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/libs/perun/login/src/lib/login-screen-service-access/login-screen-service-access.component.html b/libs/perun/login/src/lib/login-screen-service-access/login-screen-service-access.component.html index 6f8dc74a0..6f9b3f54d 100644 --- a/libs/perun/login/src/lib/login-screen-service-access/login-screen-service-access.component.html +++ b/libs/perun/login/src/lib/login-screen-service-access/login-screen-service-access.component.html @@ -5,7 +5,10 @@

{{'SHARED_LIB.PERUN.LOGIN_SERVICE_ACCESS.LABEL' | translate}}

{{'SHARED_LIB.PERUN.LOGIN_SERVICE_ACCESS.WRONG_LOGIN_OR_PASSWORD' | translate}} - + {{'SHARED_LIB.PERUN.LOGIN.LOGOUT_INFO' | translate}} From 1deaa0265626366fa15d8f83647fe77711a70fba Mon Sep 17 00:00:00 2001 From: Michal Berky Date: Wed, 9 Aug 2023 11:56:05 +0200 Subject: [PATCH 4/9] feat(lib): password reset on profile opens modal window Password reset, when clicked on in profile, now opens a modal window instead of redirecting to separate application. * Created a new password reset dialog * Modified password-reset component to use this new dialog. --- apps/admin-gui/src/assets/i18n/en.json | 9 ++ apps/user-profile/src/assets/i18n/cs.json | 9 ++ apps/user-profile/src/assets/i18n/en.json | 9 ++ .../password-reset.component.html | 2 +- .../password-reset.component.ts | 24 ++--- libs/perun/dialogs/src/index.ts | 1 + .../password-reset-dialog.component.html | 43 +++++++++ .../password-reset-dialog.component.scss | 0 .../password-reset-dialog.component.ts | 94 +++++++++++++++++++ .../dialogs/src/lib/perun-dialogs.module.ts | 3 + 10 files changed, 181 insertions(+), 13 deletions(-) create mode 100644 libs/perun/dialogs/src/lib/password-reset-dialog/password-reset-dialog.component.html create mode 100644 libs/perun/dialogs/src/lib/password-reset-dialog/password-reset-dialog.component.scss create mode 100644 libs/perun/dialogs/src/lib/password-reset-dialog/password-reset-dialog.component.ts diff --git a/apps/admin-gui/src/assets/i18n/en.json b/apps/admin-gui/src/assets/i18n/en.json index 285bddb65..d3ed4f981 100644 --- a/apps/admin-gui/src/assets/i18n/en.json +++ b/apps/admin-gui/src/assets/i18n/en.json @@ -3161,6 +3161,15 @@ "FIELD_EMPTY": "This field cannot be empty", "SUCCESS": "Password has been changed successfully," }, + "RESET_PASSWORD_DIALOG": { + "LOGIN": "Login", + "NAMESPACE": "Namespace", + "TITLE": "Reset password", + "CANCEL": "Cancel", + "CHANGE": "Confirm", + "FIELD_EMPTY": "This field cannot be empty", + "SUCCESS": "Password has been reset successfully," + }, "PASSWORD_FORM_FIELD": { "PASSWORD": "Password", "PASSWORD_AGAIN": "Confirm password", diff --git a/apps/user-profile/src/assets/i18n/cs.json b/apps/user-profile/src/assets/i18n/cs.json index 44b2c8c99..9942b12f3 100644 --- a/apps/user-profile/src/assets/i18n/cs.json +++ b/apps/user-profile/src/assets/i18n/cs.json @@ -412,6 +412,15 @@ "FIELD_EMPTY": "Tohle políčko musí být vyplněné.", "SUCCESS": "Heslo bylo úspěšně změněno" }, + "RESET_PASSWORD_DIALOG": { + "LOGIN": "Jméno", + "NAMESPACE": "Namespace", + "TITLE": "Resetovat heslo", + "CANCEL": "Zrušit", + "CHANGE": "Potvrdit", + "FIELD_EMPTY": "Tohle políčko musí být vyplněné.", + "SUCCESS": "Heslo bylo úspěšně resetováno" + }, "PASSWORD_FORM_FIELD": { "PASSWORD": "Nové heslo", "PASSWORD_AGAIN": "Znovu zadejte nové heslo", diff --git a/apps/user-profile/src/assets/i18n/en.json b/apps/user-profile/src/assets/i18n/en.json index ecd7677ec..f3064b846 100644 --- a/apps/user-profile/src/assets/i18n/en.json +++ b/apps/user-profile/src/assets/i18n/en.json @@ -480,6 +480,15 @@ "FIELD_EMPTY": "This field cannot be empty", "SUCCESS": "Password has been changed successfully," }, + "RESET_PASSWORD_DIALOG": { + "LOGIN": "Login", + "NAMESPACE": "Namespace", + "TITLE": "Reset password", + "CANCEL": "Cancel", + "CHANGE": "Confirm", + "FIELD_EMPTY": "This field cannot be empty", + "SUCCESS": "Password has been reset successfully," + }, "PASSWORD_FORM_FIELD": { "PASSWORD": "New password", "PASSWORD_AGAIN": "New password again", diff --git a/libs/perun/components/src/lib/password-reset/password-reset.component.html b/libs/perun/components/src/lib/password-reset/password-reset.component.html index 701b5d34a..2f3a0852d 100644 --- a/libs/perun/components/src/lib/password-reset/password-reset.component.html +++ b/libs/perun/components/src/lib/password-reset/password-reset.component.html @@ -32,7 +32,7 @@

+ + + + + diff --git a/libs/perun/dialogs/src/lib/password-reset-dialog/password-reset-dialog.component.scss b/libs/perun/dialogs/src/lib/password-reset-dialog/password-reset-dialog.component.scss new file mode 100644 index 000000000..e69de29bb diff --git a/libs/perun/dialogs/src/lib/password-reset-dialog/password-reset-dialog.component.ts b/libs/perun/dialogs/src/lib/password-reset-dialog/password-reset-dialog.component.ts new file mode 100644 index 000000000..803880b1e --- /dev/null +++ b/libs/perun/dialogs/src/lib/password-reset-dialog/password-reset-dialog.component.ts @@ -0,0 +1,94 @@ +import { Component, Inject, OnInit } from '@angular/core'; +import { TranslateService } from '@ngx-translate/core'; +import { + ApiRequestConfigurationService, + NotificatorService, + StoreService, +} from '@perun-web-apps/perun/services'; +import { UsersManagerService } from '@perun-web-apps/perun/openapi'; +import { loginAsyncValidator } from '@perun-web-apps/perun/namespace-password-form'; +import { FormBuilder, FormControl, FormGroup, ValidatorFn, Validators } from '@angular/forms'; +import { CustomValidators } from '@perun-web-apps/perun/utils'; +import { PasswordLabels } from '@perun-web-apps/perun/models'; +import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog'; + +export interface ResetPasswordDialogData { + namespace: string; + login: string; +} + +@Component({ + selector: 'perun-web-apps-password-reset-dialog', + templateUrl: './password-reset-dialog.component.html', + styleUrls: ['./password-reset-dialog.component.scss'], +}) +export class PasswordResetDialogComponent implements OnInit { + loading = false; + language = 'en'; + newPasswdForm: FormGroup<{ + passwordCtrl: FormControl; + passwordAgainCtrl: FormControl; + }>; + labels: PasswordLabels; + + constructor( + @Inject(MAT_DIALOG_DATA) public data: ResetPasswordDialogData, + private dialogRef: MatDialogRef, + private storeService: StoreService, + private translate: TranslateService, + private apiRequestConfiguration: ApiRequestConfigurationService, + private usersService: UsersManagerService, + private formBuilder: FormBuilder, + private notificator: NotificatorService + ) {} + + ngOnInit(): void { + this.newPasswdForm = this.formBuilder.group( + { + passwordCtrl: [ + '', + Validators.required, + [ + loginAsyncValidator( + this.data.namespace, + this.usersService, + this.apiRequestConfiguration + ), + ], + ], + passwordAgainCtrl: ['', Validators.required], + }, + { + validators: CustomValidators.passwordMatchValidator as ValidatorFn, + } + ); + this.setLabels(this.translate.currentLang); + } + + onSubmit(): void { + this.loading = true; + this.usersService + .changePasswordForLogin({ + login: this.data.login, + namespace: this.data.namespace, + newPassword: this.newPasswdForm.value.passwordCtrl, + }) + .subscribe(() => { + this.notificator.showInstantSuccess( + 'SHARED_LIB.PERUN.COMPONENTS.RESET_PASSWORD_DIALOG.SUCCESS' + ); + this.loading = false; + this.dialogRef.close(true); + }); + } + + close(): void { + this.dialogRef.close(false); + } + + private setLabels(lang: string): void { + this.labels = this.storeService.getProperty( + lang === 'en' ? 'password_labels' : 'password_labels_cs' + ); + } +} diff --git a/libs/perun/dialogs/src/lib/perun-dialogs.module.ts b/libs/perun/dialogs/src/lib/perun-dialogs.module.ts index 61d112d6b..7e928fad7 100644 --- a/libs/perun/dialogs/src/lib/perun-dialogs.module.ts +++ b/libs/perun/dialogs/src/lib/perun-dialogs.module.ts @@ -48,6 +48,7 @@ import { ExportDataDialogComponent } from './exporting-data-dialog/export-data-d import { RequestChangeDataQuotaDialogComponent } from './request-change-data-quota-dialog/request-change-data-quota-dialog.component'; import { ExpirationSelectComponent } from './expiration-select/expiration-select.component'; import { DeleteUserDialogComponent } from './delete-user-dialog/delete-user-dialog.component'; +import { PasswordResetDialogComponent } from './password-reset-dialog/password-reset-dialog.component'; @NgModule({ imports: [ @@ -103,6 +104,7 @@ import { DeleteUserDialogComponent } from './delete-user-dialog/delete-user-dial RequestChangeDataQuotaDialogComponent, ExpirationSelectComponent, DeleteUserDialogComponent, + PasswordResetDialogComponent, ], exports: [ ChangeExpirationDialogComponent, @@ -128,6 +130,7 @@ import { DeleteUserDialogComponent } from './delete-user-dialog/delete-user-dial RequestChangeDataQuotaDialogComponent, ExpirationSelectComponent, DeleteUserDialogComponent, + PasswordResetDialogComponent, ], }) export class PerunDialogsModule {} From d29bb9386b04678031a9dc4679d37e200bae4685 Mon Sep 17 00:00:00 2001 From: mattjoke Date: Mon, 7 Aug 2023 14:06:50 +0200 Subject: [PATCH 5/9] feat: remove access for service-accounts * service accounts are now not able to log in * a new dialog has been added, that can redirect users to /login or /service-access * the dialog logic is evaluated when principal is loading --- apps/admin-gui/src/assets/i18n/en.json | 5 +++++ apps/consolidator/src/assets/i18n/en.json | 5 +++++ apps/linker/src/assets/i18n/en.json | 5 +++++ apps/password-reset/src/assets/i18n/cs.json | 5 +++++ apps/password-reset/src/assets/i18n/en.json | 5 +++++ apps/publications/src/assets/i18n/en.json | 5 +++++ apps/user-profile/src/assets/i18n/cs.json | 5 +++++ apps/user-profile/src/assets/i18n/en.json | 5 +++++ libs/general/src/index.ts | 1 + libs/general/src/lib/general.module.ts | 3 +++ .../user-not-allowed-access.component.html | 11 +++++++++++ .../user-not-allowed-access.component.scss | 0 .../user-not-allowed-access.component.ts | 15 +++++++++++++++ libs/perun/services/src/lib/init-auth.service.ts | 9 +++++++++ 14 files changed, 79 insertions(+) create mode 100644 libs/general/src/lib/user-not-allowed-access/user-not-allowed-access.component.html create mode 100644 libs/general/src/lib/user-not-allowed-access/user-not-allowed-access.component.scss create mode 100644 libs/general/src/lib/user-not-allowed-access/user-not-allowed-access.component.ts diff --git a/apps/admin-gui/src/assets/i18n/en.json b/apps/admin-gui/src/assets/i18n/en.json index d3ed4f981..b089f8fc6 100644 --- a/apps/admin-gui/src/assets/i18n/en.json +++ b/apps/admin-gui/src/assets/i18n/en.json @@ -3104,6 +3104,11 @@ "USER_DONT_EXIST": { "TITLE": "The requested user (by Id or external identity) doesn't exist." }, + "USER_NOT_ALLOWED": { + "TITLE": "Access not allowed", + "MESSAGE": "Service accounts are not allowed to access this application.", + "REDIRECT": "Redirect to login page" + }, "TABLE_OPTIONS": { "EXPORT_TO_FILE": "Export to file", "ALL_DATA": "All data", diff --git a/apps/consolidator/src/assets/i18n/en.json b/apps/consolidator/src/assets/i18n/en.json index 1a37fdea8..4d8635380 100644 --- a/apps/consolidator/src/assets/i18n/en.json +++ b/apps/consolidator/src/assets/i18n/en.json @@ -76,6 +76,11 @@ "REMOVE": "Remove", "SUCCESS": "User account successfully removed" } + }, + "USER_NOT_ALLOWED": { + "TITLE": "Access not allowed", + "MESSAGE": "Service accounts are not allowed to access this application.", + "REDIRECT": "Redirect to login page" } }, "CONSOLIDATOR": { diff --git a/apps/linker/src/assets/i18n/en.json b/apps/linker/src/assets/i18n/en.json index 9082b16b0..91b0c3cde 100644 --- a/apps/linker/src/assets/i18n/en.json +++ b/apps/linker/src/assets/i18n/en.json @@ -35,6 +35,11 @@ "FOCUS_ON_MFA_DIALOG": { "MODAL": "Modal window is opened.", "MODAL_WARNING": "Please check your browser settings if no modal window is open." + }, + "USER_NOT_ALLOWED": { + "TITLE": "Access not allowed", + "MESSAGE": "Service accounts are not allowed to access this application.", + "REDIRECT": "Redirect to login page" } } }, diff --git a/apps/password-reset/src/assets/i18n/cs.json b/apps/password-reset/src/assets/i18n/cs.json index 4f3048afc..a43115e1b 100644 --- a/apps/password-reset/src/assets/i18n/cs.json +++ b/apps/password-reset/src/assets/i18n/cs.json @@ -38,6 +38,11 @@ "USER_DONT_EXIST": { "TITLE": "Požadovaný uživatel (dle ID nebo externí identity) neexistuje." }, + "USER_NOT_ALLOWED": { + "TITLE": "Přístup není povolen", + "MESSAGE": "Servisní účty (Service account) nemají povolen přístup k této aplikaci.", + "REDIRECT": "Přesměrovaní na přihlášení" + }, "SESSION_EXPIRATION": { "TITLE": "Platnost přihlášení vypršela", "DESCRIPTION": "Byli jste automaticky odhlášeni. Pro pokračování se znovu přihlaste.", diff --git a/apps/password-reset/src/assets/i18n/en.json b/apps/password-reset/src/assets/i18n/en.json index 888489b12..12f2169d0 100644 --- a/apps/password-reset/src/assets/i18n/en.json +++ b/apps/password-reset/src/assets/i18n/en.json @@ -38,6 +38,11 @@ "USER_DONT_EXIST": { "TITLE": "Requested user (by ID or external identity) doesn't exist." }, + "USER_NOT_ALLOWED": { + "TITLE": "Access not allowed", + "MESSAGE": "Service accounts are not allowed to access this application.", + "REDIRECT": "Redirect to login page" + }, "SESSION_EXPIRATION": { "TITLE": "Session expiration", "DESCRIPTION": "Your session has expired. Please sign in to continue.", diff --git a/apps/publications/src/assets/i18n/en.json b/apps/publications/src/assets/i18n/en.json index a36fa025f..229ad9403 100644 --- a/apps/publications/src/assets/i18n/en.json +++ b/apps/publications/src/assets/i18n/en.json @@ -356,6 +356,11 @@ "USER_DONT_EXIST": { "TITLE": "Requested user (by ID or external identity) doesn't exist." }, + "USER_NOT_ALLOWED": { + "TITLE": "Access not allowed", + "MESSAGE": "Service accounts are not allowed to access this application.", + "REDIRECT": "Redirect to login page" + }, "TABLE_OPTIONS": { "EXPORT_TO_FILE": "Export to file", "ALL_DATA": "All data", diff --git a/apps/user-profile/src/assets/i18n/cs.json b/apps/user-profile/src/assets/i18n/cs.json index 9942b12f3..08122ba12 100644 --- a/apps/user-profile/src/assets/i18n/cs.json +++ b/apps/user-profile/src/assets/i18n/cs.json @@ -309,6 +309,11 @@ "USER_DONT_EXIST": { "TITLE": "Požadovaný uživatel (dle ID nebo externí identity) neexistuje." }, + "USER_NOT_ALLOWED": { + "TITLE": "Přístup není povolen", + "MESSAGE": "Servisní účty (Service account) nemají povolen přístup k této aplikaci.", + "REDIRECT": "Přesměrovaní na přihlášení" + }, "TABLE_OPTIONS": { "EXPORT_TO_FILE": "Exportovat do souboru", "ALL_DATA": "Všechna data", diff --git a/apps/user-profile/src/assets/i18n/en.json b/apps/user-profile/src/assets/i18n/en.json index f3064b846..7dcbdc48e 100644 --- a/apps/user-profile/src/assets/i18n/en.json +++ b/apps/user-profile/src/assets/i18n/en.json @@ -353,6 +353,11 @@ "USER_DONT_EXIST": { "TITLE": "Requested user (by ID or external identity) doesn't exist." }, + "USER_NOT_ALLOWED": { + "TITLE": "Access not allowed", + "MESSAGE": "Service accounts are not allowed to access this application.", + "REDIRECT": "Redirect to login page" + }, "TABLE_OPTIONS": { "EXPORT_TO_FILE": "Export to file", "ALL_DATA": "All data", diff --git a/libs/general/src/index.ts b/libs/general/src/index.ts index 621b08a8e..cefb9ef80 100644 --- a/libs/general/src/index.ts +++ b/libs/general/src/index.ts @@ -2,3 +2,4 @@ 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'; export * from './lib/prevent-proxy-overload-dialog/prevent-proxy-overload-dialog.component'; +export * from './lib/user-not-allowed-access/user-not-allowed-access.component'; diff --git a/libs/general/src/lib/general.module.ts b/libs/general/src/lib/general.module.ts index bde6a12a7..22ae0f7cf 100644 --- a/libs/general/src/lib/general.module.ts +++ b/libs/general/src/lib/general.module.ts @@ -6,17 +6,20 @@ import { MatButtonModule } from '@angular/material/button'; import { UserDontExistDialogComponent } from './user-dont-exist-dialog/user-dont-exist-dialog.component'; import { TranslateModule } from '@ngx-translate/core'; import { PreventProxyOverloadDialogComponent } from './prevent-proxy-overload-dialog/prevent-proxy-overload-dialog.component'; +import { UserNotAllowedAccessComponent } from './user-not-allowed-access/user-not-allowed-access.component'; @NgModule({ imports: [CommonModule, MatDialogModule, MatButtonModule, TranslateModule], exports: [ ServerDownDialogComponent, UserDontExistDialogComponent, + UserNotAllowedAccessComponent, PreventProxyOverloadDialogComponent, ], declarations: [ ServerDownDialogComponent, UserDontExistDialogComponent, + UserNotAllowedAccessComponent, PreventProxyOverloadDialogComponent, ], }) diff --git a/libs/general/src/lib/user-not-allowed-access/user-not-allowed-access.component.html b/libs/general/src/lib/user-not-allowed-access/user-not-allowed-access.component.html new file mode 100644 index 000000000..35fdd34cb --- /dev/null +++ b/libs/general/src/lib/user-not-allowed-access/user-not-allowed-access.component.html @@ -0,0 +1,11 @@ +

+ {{'SHARED_LIB.PERUN.COMPONENTS.USER_NOT_ALLOWED.TITLE' | translate}} +

+
+ {{'SHARED_LIB.PERUN.COMPONENTS.USER_NOT_ALLOWED.MESSAGE' | translate}} +
+
+ +
diff --git a/libs/general/src/lib/user-not-allowed-access/user-not-allowed-access.component.scss b/libs/general/src/lib/user-not-allowed-access/user-not-allowed-access.component.scss new file mode 100644 index 000000000..e69de29bb diff --git a/libs/general/src/lib/user-not-allowed-access/user-not-allowed-access.component.ts b/libs/general/src/lib/user-not-allowed-access/user-not-allowed-access.component.ts new file mode 100644 index 000000000..92a2989eb --- /dev/null +++ b/libs/general/src/lib/user-not-allowed-access/user-not-allowed-access.component.ts @@ -0,0 +1,15 @@ +import { Component } from '@angular/core'; +import { MatDialogRef } from '@angular/material/dialog'; + +@Component({ + selector: 'perun-web-apps-user-dont-exist-dialog', + templateUrl: './user-not-allowed-access.component.html', + styleUrls: ['./user-not-allowed-access.component.scss'], +}) +export class UserNotAllowedAccessComponent { + constructor(public dialogRef: MatDialogRef) {} + + redirect(): void { + this.dialogRef.close(); + } +} diff --git a/libs/perun/services/src/lib/init-auth.service.ts b/libs/perun/services/src/lib/init-auth.service.ts index aca838ddd..4a3dad150 100644 --- a/libs/perun/services/src/lib/init-auth.service.ts +++ b/libs/perun/services/src/lib/init-auth.service.ts @@ -12,6 +12,7 @@ import { OAuthInfoEvent, OAuthService } from 'angular-oauth2-oidc'; import { filter } from 'rxjs/operators'; import { firstValueFrom, timer } from 'rxjs'; import { MfaHandlerService } from './mfa-handler.service'; +import { UserNotAllowedAccessComponent } from '@perun-web-apps/general'; @Injectable({ providedIn: 'root', @@ -109,6 +110,14 @@ export class InitAuthService { if (perunPrincipal.user === null) { const config = getDefaultDialogConfig(); this.dialog.open(UserDontExistDialogComponent, config); + } else if (perunPrincipal.user.serviceUser) { + const config = getDefaultDialogConfig(); + this.dialog + .open(UserNotAllowedAccessComponent, config) + .afterClosed() + .subscribe(() => { + this.authService.logout(); + }); } else { this.storeService.setPerunPrincipal(perunPrincipal); this.authResolver.init(perunPrincipal); From 193a50893a90bf0fe93ce88c79c1ec5dedc170f6 Mon Sep 17 00:00:00 2001 From: HejdaJakub Date: Wed, 9 Aug 2023 16:34:12 +0200 Subject: [PATCH 6/9] feat(admin): added tree view also to member-groups page * Member groups page was extended by tree view (previously there was just list view). * Groups-tree component was extended by group status icon and expiration functionality (expiration can be edited also from tree view). --- .../group-subgroups.component.html | 1 + .../member-groups.component.html | 49 ++++++++++++++----- .../member-groups.component.scss | 4 ++ .../member-groups/member-groups.component.ts | 37 ++++++++++++-- .../vo-groups/vo-groups.component.html | 1 + apps/admin-gui/src/assets/i18n/en.json | 4 +- .../groups-list/groups-list.component.html | 22 +++++---- .../lib/groups-list/groups-list.component.ts | 11 ++--- .../groups-tree/groups-tree.component.html | 34 +++++++++++-- .../lib/groups-tree/groups-tree.component.ts | 5 +- 10 files changed, 128 insertions(+), 40 deletions(-) diff --git a/apps/admin-gui/src/app/vos/pages/group-detail-page/group-subgroups/group-subgroups.component.html b/apps/admin-gui/src/app/vos/pages/group-detail-page/group-subgroups/group-subgroups.component.html index ddc902c37..d940753df 100644 --- a/apps/admin-gui/src/app/vos/pages/group-detail-page/group-subgroups/group-subgroups.component.html +++ b/apps/admin-gui/src/app/vos/pages/group-detail-page/group-subgroups/group-subgroups.component.html @@ -53,6 +53,7 @@

{{'GROUP_DETAIL.SUBGROUPS.TITLE' | translate}}

[groups]="groups" (moveGroup)="onMoveGroup($event)" (refreshTable)="refreshTable()" + [displayedColumns]="['nameWithId', 'description', 'menu']" [hideCheckbox]="!deleteAuth" [filterValue]="filterValue" [selection]="selected"> diff --git a/apps/admin-gui/src/app/vos/pages/member-detail-page/member-groups/member-groups.component.html b/apps/admin-gui/src/app/vos/pages/member-detail-page/member-groups/member-groups.component.html index af586c620..48665d6a1 100644 --- a/apps/admin-gui/src/app/vos/pages/member-detail-page/member-groups/member-groups.component.html +++ b/apps/admin-gui/src/app/vos/pages/member-detail-page/member-groups/member-groups.component.html @@ -25,20 +25,45 @@

{{'MEMBER_DETAIL.GROUPS.TITLE' | translate}}

(filter)="applyFilter($event)" [placeholder]="'SHARED_LIB.PERUN.COMPONENTS.RESOURCES_LIST.TABLE_SEARCH'"> + + + +
- - +
+ + +
+
+ + +
diff --git a/apps/admin-gui/src/app/vos/pages/member-detail-page/member-groups/member-groups.component.scss b/apps/admin-gui/src/app/vos/pages/member-detail-page/member-groups/member-groups.component.scss index e69de29bb..f83aab731 100644 --- a/apps/admin-gui/src/app/vos/pages/member-detail-page/member-groups/member-groups.component.scss +++ b/apps/admin-gui/src/app/vos/pages/member-detail-page/member-groups/member-groups.component.scss @@ -0,0 +1,4 @@ +.slide-label { + display: inline; + cursor: pointer; +} diff --git a/apps/admin-gui/src/app/vos/pages/member-detail-page/member-groups/member-groups.component.ts b/apps/admin-gui/src/app/vos/pages/member-detail-page/member-groups/member-groups.component.ts index ef197f728..2476273d1 100644 --- a/apps/admin-gui/src/app/vos/pages/member-detail-page/member-groups/member-groups.component.ts +++ b/apps/admin-gui/src/app/vos/pages/member-detail-page/member-groups/member-groups.component.ts @@ -1,4 +1,4 @@ -import { Component, HostBinding, OnInit } from '@angular/core'; +import { Component, HostBinding, OnInit, ViewChild } from '@angular/core'; import { ActivatedRoute } from '@angular/router'; import { Group, @@ -17,6 +17,9 @@ import { GuiAuthResolver } from '@perun-web-apps/perun/services'; import { Urns } from '@perun-web-apps/perun/urns'; import { Observable } from 'rxjs'; import { map, startWith } from 'rxjs/operators'; +import { MatSlideToggle } from '@angular/material/slide-toggle'; +import { GroupsListComponent } from '@perun-web-apps/perun/components'; +import { GroupWithStatus } from '@perun-web-apps/perun/models'; @Component({ selector: 'app-member-groups', @@ -28,6 +31,8 @@ export class MemberGroupsComponent implements OnInit { // used for router animation @HostBinding('class.router-component') true; + @ViewChild('toggle', { static: true }) toggle: MatSlideToggle; + @ViewChild('list') private list: GroupsListComponent; groups: Group[] = []; memberId: number; @@ -35,7 +40,9 @@ export class MemberGroupsComponent implements OnInit { allGroups: Group[]; loading: boolean; filterValue = ''; + filtering = false; tableId = TABLE_MEMBER_DETAIL_GROUPS; + showGroupList = false; selection = new SelectionModel(true, []); addAuth: boolean; routeAuth: boolean; @@ -67,6 +74,16 @@ export class MemberGroupsComponent implements OnInit { this.groupsService.getAllGroups(this.member.voId).subscribe((allGroups) => { this.allGroups = allGroups; this.refreshTable(); + if (localStorage.getItem('preferedValue') === 'list') { + this.toggle.toggle(); + this.showGroupList = true; + } + + this.toggle.change.subscribe(() => { + const value = this.toggle.checked ? 'list' : 'tree'; + localStorage.setItem('preferedValue', value); + this.refreshTable(); + }); }); }); }); @@ -80,15 +97,19 @@ export class MemberGroupsComponent implements OnInit { Urns.MEMBER_GROUP_STATUS, Urns.MEMBER_GROUP_STATUS_INDIRECT, ]) - .subscribe( - (groups) => { + .subscribe({ + next: (groups) => { this.selection.clear(); this.groups = groups; this.setAuthRights(); this.loading = false; }, - () => (this.loading = false) - ); + error: () => (this.loading = false), + }); + } + + changeExpiration(group: GroupWithStatus): void { + this.list.changeExpiration(group); } setAuthRights(): void { @@ -148,5 +169,11 @@ export class MemberGroupsComponent implements OnInit { applyFilter(filterValue: string): void { this.filterValue = filterValue; + this.filtering = filterValue !== ''; + } + + labelToggle(): void { + this.showGroupList = !this.showGroupList; + this.refreshTable(); } } diff --git a/apps/admin-gui/src/app/vos/pages/vo-detail-page/vo-groups/vo-groups.component.html b/apps/admin-gui/src/app/vos/pages/vo-detail-page/vo-groups/vo-groups.component.html index aab0a4055..08ea4381c 100644 --- a/apps/admin-gui/src/app/vos/pages/vo-detail-page/vo-groups/vo-groups.component.html +++ b/apps/admin-gui/src/app/vos/pages/vo-detail-page/vo-groups/vo-groups.component.html @@ -42,6 +42,7 @@

{{'VO_DETAIL.GROUPS.TITLE' | translate}}

*perunWebAppsLoader="loading$ | async; indicator: spinner" (moveGroup)="onMoveGroup($event)" (refreshTable)="refresh()" + [displayedColumns]="['nameWithId', 'description', 'menu']" [expandAll]="filtering" [disableRouting]="!routeAuth" [groups]="groups" diff --git a/apps/admin-gui/src/assets/i18n/en.json b/apps/admin-gui/src/assets/i18n/en.json index b089f8fc6..d0297769c 100644 --- a/apps/admin-gui/src/assets/i18n/en.json +++ b/apps/admin-gui/src/assets/i18n/en.json @@ -832,7 +832,9 @@ "TITLE": "Member groups", "ADD": "Add", "REMOVE": "Remove", - "REMOVE_PERMISSION_HINT": "You don't have permission to remove some of the selected groups." + "REMOVE_PERMISSION_HINT": "You don't have permission to remove some of the selected groups.", + "LIST_VIEW": "List view", + "TREE_VIEW": "Tree view" }, "APPLICATIONS": { "TITLE": "Application", diff --git a/libs/perun/components/src/lib/groups-list/groups-list.component.html b/libs/perun/components/src/lib/groups-list/groups-list.component.html index de02896f8..f32ee5a35 100644 --- a/libs/perun/components/src/lib/groups-list/groups-list.component.html +++ b/libs/perun/components/src/lib/groups-list/groups-list.component.html @@ -160,16 +160,18 @@ {{'SHARED_LIB.PERUN.COMPONENTS.GROUPS_LIST.TABLE_GROUP_EXPIRATION' | translate}} - {{group | groupExpiration | parseDate}} - + + {{group | groupExpiration | parseDate}} + + diff --git a/libs/perun/components/src/lib/groups-list/groups-list.component.ts b/libs/perun/components/src/lib/groups-list/groups-list.component.ts index 02566afa0..b4528fb91 100644 --- a/libs/perun/components/src/lib/groups-list/groups-list.component.ts +++ b/libs/perun/components/src/lib/groups-list/groups-list.component.ts @@ -5,12 +5,7 @@ import { EditFacilityResourceGroupVoDialogOptions, GroupSyncDetailDialogComponent, } from '@perun-web-apps/perun/dialogs'; -import { - Group, - Member, - PaginatedRichGroups, - VosManagerService, -} from '@perun-web-apps/perun/openapi'; +import { Group, PaginatedRichGroups, VosManagerService } from '@perun-web-apps/perun/openapi'; import { GuiAuthResolver, TableCheckbox } from '@perun-web-apps/perun/services'; import { customDataSourceFilterPredicate, @@ -259,8 +254,8 @@ export class GroupsListComponent { }; const dialogRef = this.dialog.open(ChangeGroupExpirationDialogComponent, config); - dialogRef.afterClosed().subscribe((success: { success: boolean; member: Member }) => { - if (success.success) { + dialogRef.afterClosed().subscribe((success) => { + if (success) { this.refreshTable.emit(); } }); diff --git a/libs/perun/components/src/lib/groups-tree/groups-tree.component.html b/libs/perun/components/src/lib/groups-tree/groups-tree.component.html index 8179fba3d..c9c6597fb 100644 --- a/libs/perun/components/src/lib/groups-tree/groups-tree.component.html +++ b/libs/perun/components/src/lib/groups-tree/groups-tree.component.html @@ -37,7 +37,7 @@ {{treeControl.isExpanded(group) ? 'expand_more' : 'chevron_right'}} -
+
{{group.name}} @@ -45,13 +45,41 @@ #{{group.id}}
-
+
{{group.description}}
-
+
+ {{group | groupExpiration | parseDate}} + +
+
+ + + {{groupStatus.status | memberStatusIcon}} + + +
+
(); @Output() refreshTable = new EventEmitter(); + @Output() changeExpiration = new EventEmitter(); @Input() groups: RichGroup[]; @Input() filterValue: string; @Input() expandAll = false; @@ -44,8 +45,10 @@ export class GroupsTreeComponent implements OnChanges { @Input() selection = new SelectionModel(true, []); @Input() hideCheckbox = false; @Input() vo: Vo; + @Input() displayedColumns = ['nameWithId', 'description', 'menu', 'expiration', 'status']; @ViewChild('scrollViewport', { static: false }) scrollViewport: CdkVirtualScrollViewport; + disabledRouting = false; displayButtons = window.innerWidth > 600; removeAuth: boolean; From 8d98a04e404706849239cf5b2ab0b186ce6d6a33 Mon Sep 17 00:00:00 2001 From: HejdaJakub Date: Thu, 10 Aug 2023 14:16:10 +0200 Subject: [PATCH 7/9] fix(profile): add CS translation to the Authentication section * There were missing texts in Czech language for the new Authenticatoin section. --- apps/user-profile/src/assets/i18n/cs.json | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/apps/user-profile/src/assets/i18n/cs.json b/apps/user-profile/src/assets/i18n/cs.json index 08122ba12..3871b37fb 100644 --- a/apps/user-profile/src/assets/i18n/cs.json +++ b/apps/user-profile/src/assets/i18n/cs.json @@ -12,17 +12,14 @@ "PRIVACY": "Soukromí", "CONSENTS": "Souhlasy", "CONSENT_REQUEST": "Žádost o souhlas", + "AUTHENTICATION": "Autentizace", "SETTINGS": "Nastavení" }, "SETTINGS": { - "ALTERNATIVE_PASSWORDS": "Alternativní hesla", "DATA_QUOTAS": "Kvóty dat", "MAILING_LISTS": "Vyřazení ze seznamu adresátů", "PREFERRED_SHELLS": "Preferované shelly", "PREFERRED_UNIX_GROUP_NAMES": "Preferovaná jména Unixových skupin", - "SAMBA_PASSWORD": "Heslo pro službu SAMBA", - "SSH_KEYS": "SSH klíče", - "PASSWORD_RESET": "Změna hesla", "AUTHENTICATION": "Autentizace", "LOCAL_ACCOUNT": "Lokální účet" }, @@ -154,7 +151,14 @@ "SAVE_IMG_SUCCESS": "Bezpečnostní obrázek byl změněn.", "REMOVE_IMG_SUCCESS": "Bezpečnostní obrázek byl odebrán.", "SAVE_TEXT_SUCCESS": "Bezpečnostní text byl změněn.", - "REMOVE_TEXT_SUCCESS": "Bezpečnostní text byl odebrán." + "REMOVE_TEXT_SUCCESS": "Bezpečnostní text byl odebrán.", + "SAMBA_PASSWORD": "Heslo pro službu SAMBA", + "LOCAL_ACCOUNT": "Lokální účet", + "ANTI_PHISHING": "Anti-phishingová ochrana", + "ACCOUNT_ACTIVATION": "Aktivace účtu", + "SSH_KEYS": "SSH klíče", + "PASSWORD_RESET": "Změna hesla", + "ALTERNATIVE_PASSWORDS": "Alternativní hesla" }, "LOCAL_ACCOUNT": { "TITLE": "Lokální účet", From 2d03c6c196bc8d0d6858f57706bad9dcc97975e9 Mon Sep 17 00:00:00 2001 From: Rastislav Krutak <492918@mail.muni.cz> Date: Mon, 14 Aug 2023 09:52:28 +0200 Subject: [PATCH 8/9] fix(admin): align application type column in notifications --- .../notification-list/notification-list.component.html | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/apps/admin-gui/src/app/vos/components/notification-list/notification-list.component.html b/apps/admin-gui/src/app/vos/components/notification-list/notification-list.component.html index 20a69266f..020f70e4a 100644 --- a/apps/admin-gui/src/app/vos/components/notification-list/notification-list.component.html +++ b/apps/admin-gui/src/app/vos/components/notification-list/notification-list.component.html @@ -52,13 +52,17 @@ {{'VO_DETAIL.SETTINGS.NOTIFICATIONS.TABLE_APPLICATION_TYPE' | translate}} -
+
arrow_right_alt {{'VO_DETAIL.SETTINGS.NOTIFICATIONS.TABLE_APPLICATION_TYPE_INITIAL' | translate}}
- cached - {{'VO_DETAIL.SETTINGS.NOTIFICATIONS.TABLE_APPLICATION_TYPE_EXTENSION' | translate}} +
+ cached + {{'VO_DETAIL.SETTINGS.NOTIFICATIONS.TABLE_APPLICATION_TYPE_EXTENSION' | translate}} +
From 70ca49d4a7773f7ca4b0ce7fa7e9c01fc58d6187 Mon Sep 17 00:00:00 2001 From: mattjoke Date: Thu, 10 Aug 2023 15:21:32 +0200 Subject: [PATCH 9/9] feat(admin): replaced old table export * replaced mat-menu with a dialog * functionally it works the same --- apps/admin-gui/src/assets/i18n/en.json | 9 +++- apps/publications/src/assets/i18n/en.json | 12 ++++- apps/user-profile/src/assets/i18n/cs.json | 12 ++++- apps/user-profile/src/assets/i18n/en.json | 12 ++++- libs/perun/utils/src/index.ts | 1 + .../export-table-dialog.component.html | 45 +++++++++++++++++++ .../export-table-dialog.component.scss | 0 .../export-table-dialog.component.ts | 34 ++++++++++++++ .../perun/utils/src/lib/perun-utils.module.ts | 23 +++------- .../table-options.component.html | 15 +------ .../table-options/table-options.component.ts | 29 ++++++++++++ 11 files changed, 155 insertions(+), 37 deletions(-) create mode 100644 libs/perun/utils/src/lib/export-table-dialog/export-table-dialog.component.html create mode 100644 libs/perun/utils/src/lib/export-table-dialog/export-table-dialog.component.scss create mode 100644 libs/perun/utils/src/lib/export-table-dialog/export-table-dialog.component.ts diff --git a/apps/admin-gui/src/assets/i18n/en.json b/apps/admin-gui/src/assets/i18n/en.json index d0297769c..68e2c39b9 100644 --- a/apps/admin-gui/src/assets/i18n/en.json +++ b/apps/admin-gui/src/assets/i18n/en.json @@ -3113,8 +3113,15 @@ }, "TABLE_OPTIONS": { "EXPORT_TO_FILE": "Export to file", - "ALL_DATA": "All data", + "EXPORT_TITLE": "Export table", + "BUTTON_EXPORT": "Export", + "BUTTON_CLOSE": "Close", + "SELECT_FORMAT": "Select format", + "EXPORT_OPTIONS": "Export options", "DISPLAYED_DATA": "Displayed data", + "ALL_DATA": "All data", + "ERROR_FORMAT":"Export format is not selected", + "ERROR_OPTION": "Export option is not selected", "EXPORT_LOADING": "Exporting data...", "MORE": "More" }, diff --git a/apps/publications/src/assets/i18n/en.json b/apps/publications/src/assets/i18n/en.json index 229ad9403..2387ea2e6 100644 --- a/apps/publications/src/assets/i18n/en.json +++ b/apps/publications/src/assets/i18n/en.json @@ -363,9 +363,17 @@ }, "TABLE_OPTIONS": { "EXPORT_TO_FILE": "Export to file", - "ALL_DATA": "All data", + "EXPORT_TITLE": "Export table", + "BUTTON_EXPORT": "Export", + "BUTTON_CLOSE": "Close", + "SELECT_FORMAT": "Select format", + "EXPORT_OPTIONS": "Export options", "DISPLAYED_DATA": "Displayed data", - "EXPORT_LOADING": "Exporting data..." + "ALL_DATA": "All data", + "ERROR_FORMAT":"Export format is not selected", + "ERROR_OPTION": "Export option is not selected", + "EXPORT_LOADING": "Exporting data...", + "MORE": "More" }, "NOTIFICATOR": { "NOTIFICATION": { diff --git a/apps/user-profile/src/assets/i18n/cs.json b/apps/user-profile/src/assets/i18n/cs.json index 3871b37fb..7fbd0a81c 100644 --- a/apps/user-profile/src/assets/i18n/cs.json +++ b/apps/user-profile/src/assets/i18n/cs.json @@ -320,9 +320,17 @@ }, "TABLE_OPTIONS": { "EXPORT_TO_FILE": "Exportovat do souboru", - "ALL_DATA": "Všechna data", + "EXPORT_TITLE": "Exportovat tabulku", + "BUTTON_EXPORT": "Export", + "BUTTON_CLOSE": "Zrušit", + "SELECT_FORMAT": "Zvolte formát výstupu", + "EXPORT_OPTIONS": "Možnosti exportu", "DISPLAYED_DATA": "Zobrazená data", - "EXPORT_LOADING": "Probíhá exportování dat..." + "ALL_DATA": "Všechna data", + "ERROR_FORMAT":"Formát exportu není zvolen", + "ERROR_OPTION": "Není vybrána možnost exportu", + "EXPORT_LOADING": "Probíhá exportování dat...", + "MORE": "Více" }, "NOTIFICATOR": { "NOTIFICATION": { diff --git a/apps/user-profile/src/assets/i18n/en.json b/apps/user-profile/src/assets/i18n/en.json index 7dcbdc48e..b3d6541a3 100644 --- a/apps/user-profile/src/assets/i18n/en.json +++ b/apps/user-profile/src/assets/i18n/en.json @@ -360,9 +360,17 @@ }, "TABLE_OPTIONS": { "EXPORT_TO_FILE": "Export to file", - "ALL_DATA": "All data", + "EXPORT_TITLE": "Export table", + "BUTTON_EXPORT": "Export", + "BUTTON_CLOSE": "Close", + "SELECT_FORMAT": "Select format", + "EXPORT_OPTIONS": "Export options", "DISPLAYED_DATA": "Displayed data", - "EXPORT_LOADING": "Exporting data..." + "ALL_DATA": "All data", + "ERROR_FORMAT":"Export format is not selected", + "ERROR_OPTION": "Export option is not selected", + "EXPORT_LOADING": "Exporting data...", + "MORE": "More" }, "NOTIFICATOR": { "NOTIFICATION": { diff --git a/libs/perun/utils/src/index.ts b/libs/perun/utils/src/index.ts index d3dba9427..dd1667590 100644 --- a/libs/perun/utils/src/index.ts +++ b/libs/perun/utils/src/index.ts @@ -2,3 +2,4 @@ export * from './lib/perun-utils.module'; export * from './lib/perun-utils'; export * from './lib/table-wrapper/table-wrapper.component'; export * from './lib/custom-validators'; +export * from './lib/export-table-dialog/export-table-dialog.component'; diff --git a/libs/perun/utils/src/lib/export-table-dialog/export-table-dialog.component.html b/libs/perun/utils/src/lib/export-table-dialog/export-table-dialog.component.html new file mode 100644 index 000000000..9a9d63acc --- /dev/null +++ b/libs/perun/utils/src/lib/export-table-dialog/export-table-dialog.component.html @@ -0,0 +1,45 @@ +

+ {{'SHARED_LIB.PERUN.COMPONENTS.TABLE_OPTIONS.EXPORT_TITLE'| translate}} +

+
+ + {{'SHARED_LIB.PERUN.COMPONENTS.TABLE_OPTIONS.SELECT_FORMAT'| translate}} + + + {{format.viewValue}} + + + + +

{{'SHARED_LIB.PERUN.COMPONENTS.TABLE_OPTIONS.EXPORT_OPTIONS'| translate}}

+ + + + {{'SHARED_LIB.PERUN.COMPONENTS.TABLE_OPTIONS.DISPLAYED_DATA'| translate}} + + + {{'SHARED_LIB.PERUN.COMPONENTS.TABLE_OPTIONS.ALL_DATA'| translate}} + + +
+
+ +
+
+ +
+
+
diff --git a/libs/perun/utils/src/lib/export-table-dialog/export-table-dialog.component.scss b/libs/perun/utils/src/lib/export-table-dialog/export-table-dialog.component.scss new file mode 100644 index 000000000..e69de29bb diff --git a/libs/perun/utils/src/lib/export-table-dialog/export-table-dialog.component.ts b/libs/perun/utils/src/lib/export-table-dialog/export-table-dialog.component.ts new file mode 100644 index 000000000..8f82ee624 --- /dev/null +++ b/libs/perun/utils/src/lib/export-table-dialog/export-table-dialog.component.ts @@ -0,0 +1,34 @@ +import { Component, Inject } from '@angular/core'; +import { FormControl, Validators } from '@angular/forms'; +import { MAT_DIALOG_DATA } from '@angular/material/dialog'; + +interface Format { + value: string; + viewValue: string; +} + +interface InputData { + allowExportAll: boolean; +} + +@Component({ + selector: 'perun-web-apps-export-table-dialog', + templateUrl: './export-table-dialog.component.html', + styleUrls: ['./export-table-dialog.component.scss'], +}) +export class ExportTableDialogComponent { + formats: Format[] = [{ value: 'csv', viewValue: 'CSV' }]; + selectedFormat = new FormControl('csv', Validators.required); + selectedExportType = new FormControl('current', Validators.required); + constructor(@Inject(MAT_DIALOG_DATA) public inputData: InputData) {} + isValidSelection(): boolean { + return this.selectedFormat.value !== null && this.selectedExportType.value !== null; + } + + export(): { exportType: string; format: string } { + return { + exportType: this.selectedExportType.value, + format: this.selectedFormat.value, + }; + } +} diff --git a/libs/perun/utils/src/lib/perun-utils.module.ts b/libs/perun/utils/src/lib/perun-utils.module.ts index 3ffc03042..32899b2aa 100644 --- a/libs/perun/utils/src/lib/perun-utils.module.ts +++ b/libs/perun/utils/src/lib/perun-utils.module.ts @@ -1,26 +1,17 @@ import { NgModule } from '@angular/core'; import { TableWrapperComponent } from './table-wrapper/table-wrapper.component'; -import { MatPaginatorModule } from '@angular/material/paginator'; import { TableOptionsComponent } from './table-options/table-options.component'; -import { MatMenuModule } from '@angular/material/menu'; -import { MatIconModule } from '@angular/material/icon'; -import { MatButtonModule } from '@angular/material/button'; import { TranslateModule } from '@ngx-translate/core'; import { CommonModule } from '@angular/common'; -import { MatTooltipModule } from '@angular/material/tooltip'; +import { ExportTableDialogComponent } from './export-table-dialog/export-table-dialog.component'; +import { UiMaterialModule } from '@perun-web-apps/ui/material'; +import { MatRadioModule } from '@angular/material/radio'; +import { ReactiveFormsModule } from '@angular/forms'; @NgModule({ - imports: [ - MatPaginatorModule, - MatMenuModule, - MatIconModule, - MatButtonModule, - TranslateModule, - CommonModule, - MatTooltipModule, - ], - declarations: [TableWrapperComponent, TableOptionsComponent], - exports: [TableWrapperComponent, TableOptionsComponent], + imports: [TranslateModule, CommonModule, ReactiveFormsModule, UiMaterialModule, MatRadioModule], + declarations: [TableWrapperComponent, TableOptionsComponent, ExportTableDialogComponent], + exports: [TableWrapperComponent, TableOptionsComponent, ExportTableDialogComponent], providers: [], }) export class PerunUtilsModule {} diff --git a/libs/perun/utils/src/lib/table-options/table-options.component.html b/libs/perun/utils/src/lib/table-options/table-options.component.html index 39d7e01dd..d56a44cfb 100644 --- a/libs/perun/utils/src/lib/table-options/table-options.component.html +++ b/libs/perun/utils/src/lib/table-options/table-options.component.html @@ -7,21 +7,8 @@ - - - - - - - - - -
diff --git a/libs/perun/utils/src/lib/table-options/table-options.component.ts b/libs/perun/utils/src/lib/table-options/table-options.component.ts index 41aca1559..801ecd869 100644 --- a/libs/perun/utils/src/lib/table-options/table-options.component.ts +++ b/libs/perun/utils/src/lib/table-options/table-options.component.ts @@ -1,4 +1,12 @@ import { Component, EventEmitter, Input, Output } from '@angular/core'; +import { MatDialog } from '@angular/material/dialog'; +import { ExportTableDialogComponent } from '../export-table-dialog/export-table-dialog.component'; +import { getDefaultDialogConfig } from '../perun-utils'; + +interface DialogData { + exportType: string; + format: string; +} @Component({ selector: 'perun-web-apps-table-options', @@ -9,4 +17,25 @@ export class TableOptionsComponent { @Input() allowExportAll: boolean; @Output() exportDisplayedData = new EventEmitter(); @Output() exportAllData = new EventEmitter(); + + constructor(private dialog: MatDialog) {} + openDialog(): void { + const config = getDefaultDialogConfig(); + config.width = '500px'; + config.data = { + allowExportAll: this.allowExportAll, + }; + this.dialog + .open(ExportTableDialogComponent, config) + .afterClosed() + .subscribe((result: DialogData) => { + if (result) { + if (result.exportType === 'all') { + this.exportAllData.emit(result.format); + } else { + this.exportDisplayedData.emit(result.format); + } + } + }); + } }