From 0df39c2d5e7e269bc801587a058470d4c2360131 Mon Sep 17 00:00:00 2001 From: Rastislav Krutak <492918@mail.muni.cz> Date: Thu, 31 Aug 2023 10:25:43 +0200 Subject: [PATCH 1/5] feat(profile): consolidator config uses full url * Changed the consolidator_base_url property to consolidator_url, which now includes the full url, thus no fed/cert rerouting is done in code. BREAKING CHANGE: The consolidator_base_url config property needs to be changed to consolidator_url and include the complete url. --- .../app/pages/identities-page/identities-page.component.ts | 7 ++----- apps/user-profile/src/assets/config/defaultConfig.json | 2 +- libs/perun/models/src/lib/ConfigProperties.ts | 2 +- 3 files changed, 4 insertions(+), 7 deletions(-) diff --git a/apps/user-profile/src/app/pages/identities-page/identities-page.component.ts b/apps/user-profile/src/app/pages/identities-page/identities-page.component.ts index ccf530361..67c609015 100644 --- a/apps/user-profile/src/app/pages/identities-page/identities-page.component.ts +++ b/apps/user-profile/src/app/pages/identities-page/identities-page.component.ts @@ -143,11 +143,8 @@ export class IdentitiesPageComponent implements OnInit { }); } else { this.registrarManagerService.getConsolidatorToken().subscribe((token) => { - const type = this.storage.getPerunPrincipal().extSourceType; - const consolidatorBaseUrl = this.storage.getProperty('consolidator_base_url'); - window.location.href = `${consolidatorBaseUrl}${ - type?.endsWith('X509') ? 'cert' : 'fed' - }-ic/ic/?target_url=${window.location.href}&token=${token}`; + const consolidatorUrl = this.storage.getProperty('consolidator_url'); + window.location.href = `${consolidatorUrl}?target_url=${window.location.href}&token=${token}`; }); } } diff --git a/apps/user-profile/src/assets/config/defaultConfig.json b/apps/user-profile/src/assets/config/defaultConfig.json index 9867a2f6d..133152909 100644 --- a/apps/user-profile/src/assets/config/defaultConfig.json +++ b/apps/user-profile/src/assets/config/defaultConfig.json @@ -28,7 +28,7 @@ "urn:perun:user:attribute-def:def:login-namespace:egi-ui", "urn:perun:user:attribute-def:def:login-namespace:sitola" ], - "consolidator_base_url": "https://perun-dev.cesnet.cz/", + "consolidator_url": "https://perun-dev.cesnet.cz/cert-ic/ic/", "registrar_base_url": "https://perun-dev.cesnet.cz/fed/registrar/", "use_localhost_linker_url": false, "password_help": { diff --git a/libs/perun/models/src/lib/ConfigProperties.ts b/libs/perun/models/src/lib/ConfigProperties.ts index 47613ce71..f344d1917 100644 --- a/libs/perun/models/src/lib/ConfigProperties.ts +++ b/libs/perun/models/src/lib/ConfigProperties.ts @@ -186,7 +186,7 @@ export interface PerunConfig { // User profile specific // Required displayed_tabs: string[]; - consolidator_base_url: string; + consolidator_url: string; registrar_base_url: string; mfa: ProfileMFA; preferred_unix_group_names: string[]; From 21ef02165455bfef3e84331648d9dc5bc9f15a88 Mon Sep 17 00:00:00 2001 From: Adam Bodnar Date: Mon, 21 Aug 2023 08:28:33 +0200 Subject: [PATCH 2/5] fix: initialize colors from instance config * all color variables are now initialized by the script * removed creation of css variables during runtime * removed unused classes in styles.scss for all apps * formated styles.scss for all apps --- apps/admin-gui/src/_styles.scss | 1478 +++++------------ apps/admin-gui/src/app/app.component.html | 13 +- apps/admin-gui/src/app/app.component.ts | 5 - .../common/admin-gui-config.service.ts | 83 +- .../side-menu-item.component.scss | 40 - .../src/assets/config/defaultConfig.json | 3 +- apps/consolidator/src/_styles.scss | 154 +- apps/linker/src/_styles.scss | 106 +- apps/password-reset/src/_styles.scss | 114 +- apps/publications/src/_styles.scss | 314 ++-- .../services/publications-config.service.ts | 36 +- apps/user-profile/src/_styles.scss | 280 ++-- .../services/user-profile-config.service.ts | 36 +- color-migration.js | 232 ++- libs/config/src/index.ts | 2 - libs/config/src/lib/app-config.service.ts | 97 -- package-lock.json | 11 +- package.json | 4 +- 18 files changed, 1044 insertions(+), 1964 deletions(-) diff --git a/apps/admin-gui/src/_styles.scss b/apps/admin-gui/src/_styles.scss index 508f6a2a5..6849c9fd8 100644 --- a/apps/admin-gui/src/_styles.scss +++ b/apps/admin-gui/src/_styles.scss @@ -8,29 +8,6 @@ // Changes to the styles.scss would result in the styles being overwritten // during the build process and the changes would be lost. -@function mat-color-from-palette($palette, $hue: default, $opacity: null) { - @if type-of($hue) == number and $hue >= 0 and $hue <= 1 { - @return mat-color-from-palette($palette, default, $hue); - } - - $color: map-get($palette, $hue); - - @if (type-of($color) != color) { - @if ($opacity == null) { - @return $color; - } - - // Here is the change from the original function: - // If the $color resolved to something different from a color, we assume it is a CSS variable - // in the form of rgba(var(--rgba-css-var),a) and replace the 'a' value. - @return #{str-slice($color, 0, str-index($color, ',')) + $opacity + ')'}; - } - - @return rgba($color, if($opacity == null, opacity($color), $opacity)); -} - -// Plus imports for other components in your app. - // Include the common styles for Angular Material. @include mat.all-component-typographies(); @include mat.core(); @@ -63,63 +40,11 @@ $perun-theme: mat.define-light-theme( mat.$theme-ignore-duplication-warnings: true; @include mat.all-component-themes($perun-theme); -:root { - //--vo-color: #ff0000; - //--vo-theme-primary-50: 0,158,224; - //--vo-theme-primary-100: 0,158,224; - //--vo-theme-primary-200: 0,158,224; - //--vo-theme-primary-300: 0,158,224; - //--vo-theme-primary-400: 0,158,224; - //--vo-theme-primary-500: 0,158,224; - //--vo-theme-primary-600: 0,158,224; - //--vo-theme-primary-700: 0,158,224; - //--vo-theme-primary-800: 0,158,224; - //--vo-theme-primary-900: 0,158,224; - //--vo-theme-primary-A100: 0,158,224; - //--vo-theme-primary-A200: 0,158,224; - //--vo-theme-primary-A400: 0,158,224; - //--vo-theme-primary-A700: 0,158,224; - //--vo-theme-primary-contrast-50: 0,158,224; - //--vo-theme-primary-contrast-100: 0,158,224; - //--vo-theme-primary-contrast-200: 0,158,224; - //--vo-theme-primary-contrast-300: 0,158,224; - //--vo-theme-primary-contrast-400: 0,158,224; - //--vo-theme-primary-contrast-500: 0,158,224; - //--vo-theme-primary-contrast-600: 0,158,224; - //--vo-theme-primary-contrast-700: 0,158,224; - //--vo-theme-primary-contrast-800: 0,158,224; - //--vo-theme-primary-contrast-900: 0,158,224; - //--vo-theme-primary-contrast-A100: 0,158,224; - //--vo-theme-primary-contrast-A200: 0,158,224; - //--vo-theme-primary-contrast-A400: 0,158,224; - //--vo-theme-primary-contrast-A700: 0,158,224; -} - -@function mixw($variable, $opacity) { - @return unquote( - 'linear-gradient(to top, rgba(255, 255, 255,' + $opacity + '),rgba(255, 255, 255,' + $opacity + - ')) ' + $variable - ); -} - -@function mixb($variable, $opacity) { - @return unquote( - 'linear-gradient(to top, rgba(0, 0, 0,' + $opacity + '),rgba(0, 0, 0,' + $opacity + '))' + - $variable - ); -} - -// Perun entities colors -//$vo-color: #283593; -//var(--facility-color): #d84315; -//$resource-color: #6a1b9a; -//$group-color: #33691e; -//var(--member-color): #ad1457; -//var(--admin-color): #c62828; -//var(--user-color): #00796b; - +/************************************* +************** Vo theme ************** +*************************************/ .vo-theme { - $vo-dynamic-colors: ( + $vo-palette: ( 50: rgba(var(--vo-theme-primary-50), 1), 100: rgba(var(--vo-theme-primary-100), 1), 200: rgba(var(--vo-theme-primary-200), 1), @@ -152,7 +77,7 @@ mat.$theme-ignore-duplication-warnings: true; ), ); - $vo-primary: mat.define-palette($vo-dynamic-colors, 500); + $vo-primary: mat.define-palette($vo-palette, 500); $vo-accent: mat.define-palette(mat.$green-palette, 600); $vo-theme: mat.define-light-theme( @@ -167,16 +92,29 @@ mat.$theme-ignore-duplication-warnings: true; @include mat.all-component-colors($vo-theme); } -//.facility-theme { -// $vo-primary: mat.define-palette(mat.$deep-orange-palette, 800); -// $vo-accent: mat.define-palette(mat.$green-palette, 600); -// $vo-theme: mat.define-light-theme($vo-primary, $vo-accent); -// -// @include mat.all-component-themes($vo-theme); -//} +.vo-btn { + background: var(--vo-color); + color: rgba(var(--vo-theme-primary-contrast-500), 1); + + &:hover { + color: rgba(var(--vo-theme-primary-contrast-500), 1); + } +} + +.vo-link { + color: var(--vo-color); + text-decoration: underline; + + &:hover { + color: rgba(var(--vo-theme-primary-contrast-500), 1); + } +} +/************************************* +*********** Facility theme *********** +*************************************/ .facility-theme { - $facility-dynamic-colors: ( + $facility-palette: ( 50: rgba(var(--facility-theme-primary-50), 1), 100: rgba(var(--facility-theme-primary-100), 1), 200: rgba(var(--facility-theme-primary-200), 1), @@ -209,7 +147,7 @@ mat.$theme-ignore-duplication-warnings: true; ), ); - $facility-primary: mat.define-palette($facility-dynamic-colors, 500); + $facility-primary: mat.define-palette($facility-palette, 500); $facility-accent: mat.define-palette(mat.$green-palette, 600); $facility-theme: mat.define-light-theme( ( @@ -223,16 +161,29 @@ mat.$theme-ignore-duplication-warnings: true; @include mat.all-component-colors($facility-theme); } -//.resource-theme { -// $vo-primary: mat.define-palette(mat.$purple-palette, 800); -// $vo-accent: mat.define-palette(mat.$green-palette, 600); -// $vo-theme: mat.define-light-theme($vo-primary, $vo-accent); -// -// @include mat.all-component-themes($vo-theme); -//} +.facility-btn { + background-color: var(--facility-color); + color: rgba(var(--facility-theme-primary-contrast-500), 1); + + &:hover { + color: rgba(var(--facility-theme-primary-contrast-500), 1); + } +} + +.facility-link { + color: var(--facility-color); + text-decoration: underline; + + &:hover { + color: rgba(var(--facility-theme-primary-contrast-500), 1); + } +} +/************************************* +********** Resource theme ************ +*************************************/ .resource-theme { - $resource-dynamic-colors: ( + $resource-palette: ( 50: rgba(var(--resource-theme-primary-50), 1), 100: rgba(var(--resource-theme-primary-100), 1), 200: rgba(var(--resource-theme-primary-200), 1), @@ -265,7 +216,7 @@ mat.$theme-ignore-duplication-warnings: true; ), ); - $resource-primary: mat.define-palette($resource-dynamic-colors, 500); + $resource-primary: mat.define-palette($resource-palette, 500); $resource-accent: mat.define-palette(mat.$green-palette, 600); $resource-theme: mat.define-light-theme( ( @@ -279,16 +230,29 @@ mat.$theme-ignore-duplication-warnings: true; @include mat.all-component-colors($resource-theme); } -//.group-theme { -// $group-primary: mat.define-palette(mat.$light-green-palette, 900); -// $group-accent: mat.define-palette(mat.$green-palette, 600); -// $group-theme: mat.define-light-theme($group-primary, $group-accent); -// -// @include mat.all-component-themes($group-theme); -//} +.resource-btn { + background-color: var(--resource-color); + color: rgba(var(--resource-theme-primary-contrast-500), 1); + + &:hover { + color: rgba(var(--resource-theme-primary-contrast-500), 1); + } +} + +.resource-link { + color: var(--resource-color); + text-decoration: underline; + + &:hover { + color: rgba(var(--resource-theme-primary-contrast-500), 1); + } +} +/************************************* +************ Group theme ************* +*************************************/ .group-theme { - $group-dynamic-colors: ( + $group-palette: ( 50: rgba(var(--group-theme-primary-50), 1), 100: rgba(var(--group-theme-primary-100), 1), 200: rgba(var(--group-theme-primary-200), 1), @@ -321,7 +285,7 @@ mat.$theme-ignore-duplication-warnings: true; ), ); - $group-primary: mat.define-palette($group-dynamic-colors, 500); + $group-primary: mat.define-palette($group-palette, 500); $group-accent: mat.define-palette(mat.$green-palette, 600); $group-theme: mat.define-light-theme( ( @@ -335,16 +299,29 @@ mat.$theme-ignore-duplication-warnings: true; @include mat.all-component-colors($group-theme); } -//.member-theme { -// $member-primary: mat.define-palette(mat.$pink-palette, 800); -// $member-accent: mat.define-palette(mat.$green-palette, 600); -// $member-theme: mat.define-light-theme($member-primary, $member-accent); -// -// @include mat.all-component-themes($member-theme); -//} +.group-btn { + background: var(--group-color); + color: rgba(var(--group-theme-primary-contrast-500), 1); + + &:hover { + color: rgba(var(--group-theme-primary-contrast-500), 1); + } +} + +.group-link { + color: var(--group-color); + text-decoration: underline; + + &:hover { + color: rgba(var(--group-theme-primary-contrast-500), 1); + } +} +/************************************* +************ Member theme ************ +*************************************/ .member-theme { - $member-dynamic-colors: ( + $member-palette: ( 50: rgba(var(--member-theme-primary-50), 1), 100: rgba(var(--member-theme-primary-100), 1), 200: rgba(var(--member-theme-primary-200), 1), @@ -377,7 +354,7 @@ mat.$theme-ignore-duplication-warnings: true; ), ); - $member-primary: mat.define-palette($member-dynamic-colors, 500); + $member-primary: mat.define-palette($member-palette, 500); $member-accent: mat.define-palette(mat.$green-palette, 600); $member-theme: mat.define-light-theme( ( @@ -391,16 +368,29 @@ mat.$theme-ignore-duplication-warnings: true; @include mat.all-component-colors($member-theme); } -//.admin-theme { -// $admin-primary: mat.define-palette(mat.$red-palette, 800); -// $admin-accent: mat.define-palette(mat.$green-palette, 600); -// $admin-theme: mat.define-light-theme($admin-primary, $admin-accent); -// -// @include mat.all-component-themes($admin-theme); -//} +.member-btn { + background-color: var(--member-color); + color: rgba(var(--member-theme-primary-contrast-500), 1); + + &:hover { + color: rgba(var(--member-theme-primary-contrast-500), 1); + } +} + +.member-link { + color: var(--member-color); + text-decoration: underline; + + &:hover { + color: rgba(var(--member-theme-primary-contrast-500), 1); + } +} +/************************************* +************ Admin theme ************* +*************************************/ .admin-theme { - $admin-dynamic-colors: ( + $admin-palette: ( 50: rgba(var(--admin-theme-primary-50), 1), 100: rgba(var(--admin-theme-primary-100), 1), 200: rgba(var(--admin-theme-primary-200), 1), @@ -433,7 +423,7 @@ mat.$theme-ignore-duplication-warnings: true; ), ); - $admin-primary: mat.define-palette($admin-dynamic-colors, 500); + $admin-primary: mat.define-palette($admin-palette, 500); $admin-accent: mat.define-palette(mat.$green-palette, 600); $admin-theme: mat.define-light-theme( ( @@ -447,16 +437,20 @@ mat.$theme-ignore-duplication-warnings: true; @include mat.all-component-colors($admin-theme); } -//.user-theme { -// $user-primary: mat.define-palette(mat.$teal-palette, 700); -// $user-accent: mat.define-palette(mat.$green-palette, 600); -// $user-theme: mat.define-light-theme($user-primary, $user-accent); -// -// @include mat.all-component-themes($user-theme); -//} +.admin-btn { + background-color: var(--admin-color); + color: rgba(var(--admin-theme-primary-contrast-500), 1); + + &:hover { + color: rgba(var(--admin-theme-primary-contrast-500), 1); + } +} +/************************************* +************* User theme ************* +*************************************/ .user-theme { - $user-dynamic-colors: ( + $user-palette: ( 50: rgba(var(--user-theme-primary-50), 1), 100: rgba(var(--user-theme-primary-100), 1), 200: rgba(var(--user-theme-primary-200), 1), @@ -489,7 +483,7 @@ mat.$theme-ignore-duplication-warnings: true; ), ); - $user-primary: mat.define-palette($user-dynamic-colors, 500); + $user-primary: mat.define-palette($user-palette, 500); $user-accent: mat.define-palette(mat.$green-palette, 600); $user-theme: mat.define-light-theme( ( @@ -503,8 +497,29 @@ mat.$theme-ignore-duplication-warnings: true; @include mat.all-component-colors($user-theme); } +.user-btn { + background-color: var(--user-color); + color: rgba(var(--user-theme-primary-contrast-500), 1); + + &:hover { + color: rgba(var(--user-theme-primary-contrast-500), 1); + } +} + +.user-link { + color: var(--user-color); + text-decoration: underline; + + &:hover { + color: rgba(var(--user-theme-primary-contrast-500), 1); + } +} + +/************************************* +*********** Service theme ************ +*************************************/ .service-theme { - $service-dynamic-colors: ( + $service-palette: ( 50: rgba(var(--service-theme-primary-50), 1), 100: rgba(var(--service-theme-primary-100), 1), 200: rgba(var(--service-theme-primary-200), 1), @@ -537,7 +552,7 @@ mat.$theme-ignore-duplication-warnings: true; ), ); - $service-primary: mat.define-palette($service-dynamic-colors, 500); + $service-primary: mat.define-palette($service-palette, 500); $service-accent: mat.define-palette(mat.$green-palette, 600); $service-theme: mat.define-light-theme( ( @@ -551,248 +566,188 @@ mat.$theme-ignore-duplication-warnings: true; @include mat.all-component-colors($service-theme); } -body { - background-color: #fafafa; -} +.service-btn { + background-color: var(--service-color); + color: rgba(var(--service-theme-primary-contrast-500), 1); -button { - border-radius: var(--bs-border-radius) !important; + &:hover { + color: rgba(var(--service-theme-primary-contrast-500), 1); + } } -button:focus { - outline: none !important; -} +.service-link { + color: var(--service-color); + text-decoration: underline; -.vo-item { - background-color: var(--vo-color); + &:hover { + color: rgba(var(--service-theme-primary-contrast-500), 1); + } } -.facility-item { - background-color: var(--facility-color); +/************************************* +************** General *************** +*************************************/ +body { + background-color: #fafafa; } -.resource-item { - background-color: var(--resource-color); +.mb-25 { + margin-bottom: 0.75rem; } -.group-item { - background-color: var(--group-color); +.clickable { + cursor: pointer; + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; } -.member-item { - background-color: var(--member-color); +.word-break-all { + word-break: break-all; } -.service-item { - background-color: var(--service-color); +.overflow-ellipsis { + text-overflow: ellipsis; } -.dark-item-activated { - //border-left: 5px solid #ffffff; - //font-weight: 600; - background: var(--side-link-active) !important; - color: var(--side-link-text-active) !important; +.status-change { + position: relative; + display: inline-block; + margin-left: 5px; - &:hover { - //background-color: rgba(255, 255, 255, 0.15) !important; + // Using ::before to create a pseudo-element serving as circular background + &:before { + content: ''; + position: absolute; + top: 50%; + left: 50%; + transform: translate(-50%, -50%); + width: 150%; + padding-bottom: 150%; + border-radius: 50%; + background-color: rgba(0, 0, 0, 0.05); + opacity: 0; } -} - -.vo-item-activated { - border-right: 5px solid var(--vo-color); - color: var(--vo-color) !important; - font-weight: 500; - background-color: rgba(63, 76, 255, 0.1) !important; - &:hover { - background-color: rgba(63, 76, 255, 0.15) !important; + &:hover::before { + opacity: 1; } } -.admin-item-activated { - border-right: 5px solid var(--admin-color); - color: var(--admin-color) !important; - font-weight: 500; - background-color: rgba(255, 50, 50, 0.1); - - &:hover { - background-color: rgba(255, 50, 50, 0.15) !important; - } +.input-width-250 { + width: 250px; } -.facility-item-activated { - border-right: 5px solid var(--facility-color); - color: var(--facility-color) !important; +.setting-item { + font-size: 1.15rem; font-weight: 500; - background-color: rgba(255, 80, 23, 0.1); - - &:hover { - background-color: rgba(255, 80, 23, 0.15) !important; - } - - //background-color: #eaeaea !important; } -.resource-item-activated { - border-right: 5px solid var(--resource-color); - color: var(--resource-color) !important; - font-weight: 500; - background-color: rgba(176, 44, 255, 0.1); - - &:hover { - background-color: rgba(176, 44, 255, 0.15) !important; - } - - //background-color: #eaeaea !important; +// hack to make the content of the virtual scroll be limited by its width +.cdk-virtual-scroll-content-wrapper { + contain: size !important; } -.group-item-activated { - border-right: 5px solid var(--group-color); - color: var(--group-color) !important; - font-weight: 500; - background-color: rgba(123, 255, 71, 0.1); - - &:hover { - background-color: rgba(123, 255, 71, 0.15) !important; - } +.align-checkbox { + text-align: center !important; + vertical-align: middle !important; } -.member-item-activated { - border-right: 5px solid var(--member-color); - color: var(--member-color) !important; - font-weight: 500; - background-color: rgba(255, 28, 133, 0.1); +.align-elements { + display: flex; + align-items: center; + flex-wrap: wrap; +} - &:hover { - background-color: rgba(255, 28, 133, 0.15) !important; - } +/************************************* +************** Buttons *************** +*************************************/ +button { + border-radius: var(--bs-border-radius) !important; +} - //background-color: #eaeaea !important; +.mat-mdc-outlined-button { + border-radius: var(--bs-border-radius) !important; } -.user-item-activated { - border-right: 5px solid var(--member-color); - color: var(--member-color) !important; - font-weight: 500; - background-color: rgba(0, 121, 107, 0.1); +.mat-mdc-unelevated-button { + border-radius: var(--bs-border-radius) !important; +} - &:hover { - background-color: rgba(0, 121, 107, 0.15) !important; - } +.mat-mdc-button { + border-radius: var(--bs-border-radius) !important; } -.service-item-activated { - border-right: 5px solid var(--service-color); - color: var(--service-color) !important; - font-weight: 500; - background-color: rgba(86, 19, 53, 0.1); - - &:hover { - background-color: rgba(86, 19, 53, 0.15) !important; - } -} - -.dark-item-links a:hover { - //background-color: rgba(255, 255, 255, 0.15) !important; -} - -.vo-item-links a:hover { - color: var(--vo-color) !important; - background-color: rgba(63, 76, 255, 0.15) !important; -} - -.group-item-links a:hover { - color: var(--group-color) !important; - background-color: rgba(123, 255, 71, 0.15) !important; -} - -.admin-item-links a:hover { - color: var(--admin-color) !important; - background-color: rgba(255, 50, 50, 0.15) !important; -} - -.facility-item-links a:hover { - color: var(--facility-color) !important; - background-color: rgba(255, 82, 28, 0.15) !important; -} - -.resource-item-links a:hover { - color: var(--resource-color) !important; - background-color: rgba(176, 44, 255, 0.15) !important; -} - -.member-item-links a:hover { - color: var(--member-color) !important; - background-color: rgba(255, 28, 133, 0.15) !important; -} - -.user-item-links a:hover { - color: var(--user-color) !important; - background-color: rgba(0, 121, 107, 0.15) !important; -} - -.service-item-links a:hover { - color: var(--service-color) !important; - background-color: rgba(86, 19, 53, 0.15) !important; -} - -.vo-text { - color: var(--vo-color) !important; -} - -.facility-text { - color: var(--facility-color) !important; +.mdc-button { + border-radius: var(--bs-border-radius) !important; + white-space: nowrap !important; + letter-spacing: normal; } -.resource-text { - color: var(--resource-color) !important; +.action-button { + display: inline-block !important; } -.group-text { - color: var(--group-color) !important; +.action-button::after { + content: '\2026'; + margin-left: -4px; } -.member-text { - color: var(--member-color) !important; +/************************************* +************** Sidemenu ************** +*************************************/ +.side-menu-item { + a { + padding: 0.5rem 0.5rem 0.5rem 1rem; + cursor: pointer; + text-decoration: none; + + &:hover { + background: var(--sidemenu-hover-color) !important; + color: var(--sidemenu-hover-text-color) !important; + } + } } -.user-text { - color: var(--user-color) !important; +.side-menu-item-label { + display: flex; + flex-direction: row; + align-items: center; + word-break: break-word; + text-decoration: none; } -.service-text { - color: var(--service-color) !important; -} +.side-menu-link { + a { + padding: 0.25rem 0.25rem 0.25rem 2rem; + text-decoration: none; + color: #ffffff; + font-size: 1rem; + display: block; -.router-component { - padding-bottom: 5rem; - min-height: calc(100vh - 314px); - @media (min-width: 769px) and (max-width: 1199px) { - width: calc(100vw - 330px); - } - @media (max-width: 768px) { - width: calc(100vw - 30px); + &:hover { + background: var(--sidemenu-submenu-hover-color) !important; + color: var(--sidemenu-submenu-hover-text-color) !important; + } } } -.main-input { - font-size: 1.2rem !important; - line-height: 1.2 !important; -} - -.error-text { - color: #d32f2f; +.header-activated { + background: var(--sidemenu-active-color) !important; + color: var(--sidemenu-active-text-color) !important; } -.tab-padding-top { - /* TODO(mdc-migration): The following rule targets internal classes of tabs that may no longer apply for the MDC version.*/ - .mat-tab-body-content { - padding-top: 2rem; - } +.dark-item-activated { + background: var(--sidemenu-submenu-active-color) !important; + color: var(--sidemenu-submenu-active-text-color) !important; } -#nav-menu { - background: #102027; +/************************************* +*************** Nav ***************** +*************************************/ +.nav-menu { + background: var(--nav-bg-color); position: fixed; width: 100%; z-index: 999; @@ -800,21 +755,21 @@ button:focus { justify-content: space-between; height: 64px; max-height: 64px; - //display: table; -} - -textarea.cdk-textarea-autosize-measuring { - padding: 4px 0 !important; } -.base-item-color { - background-color: mat.get-color-from-palette(mat.$blue-grey-palette, 900); +.side-nav { + background: var(--sidemenu-bg-color); + border-color: var(--sidemenu-border-color); } -.base-item-color-activated { - background-color: #62727b; +.side-nav-content { + position: relative; + background: var(--content-bg-color); } +/************************************* +*************** Dialogs ************** +*************************************/ .dialog-container { display: flex; flex-direction: column; @@ -824,6 +779,14 @@ textarea.cdk-textarea-autosize-measuring { width: 100%; } +//specific style for dialog without any border +.noBorderDialog .mat-mdc-dialog-container { + padding: 0 !important; +} + +/************************************* +*************** Titles *************** +*************************************/ .page-title { margin-top: 1rem; margin-bottom: 2rem; @@ -843,7 +806,6 @@ textarea.cdk-textarea-autosize-measuring { flex-direction: column; margin-left: 2rem; margin-bottom: 2rem; - //d-flex flex-column ms-5 pb-4 } .page-subtitle { @@ -851,582 +813,232 @@ textarea.cdk-textarea-autosize-measuring { font-size: 1.5rem; } -.page-subtitle-2 { - margin-bottom: 0.75rem; - font-size: 1.1rem; -} - -.input-width-250 { - width: 250px; +.entity-info { + font-size: 1rem; } -.space-right { - margin-right: 20px; +/************************************* +*************** Icons **************** +*************************************/ +mat-icon { + overflow: inherit !important; } -.box-button-large { - text-align: center; - font-size: 1.25em; - color: #ffffff; - -webkit-box-shadow: 0 2px 8px 0 rgba(0, 0, 0, 0.35); - -moz-box-shadow: 0 2px 8px 0 rgba(0, 0, 0, 0.35); - box-shadow: 0 2px 8px 0 rgba(0, 0, 0, 0.35); +// Proper mat icon inside button +.mat-mdc-outlined-button > .mat-icon, +.mat-mdc-unelevated-button > .mat-icon { + margin-left: 0 !important; + margin-right: 0 !important; + height: 1.5rem !important; + width: 1.5rem !important; + font-size: 1.5rem !important; } -.box-button-small { - color: #ffffff; - -webkit-box-shadow: 0 2px 8px 0 rgba(0, 0, 0, 0.35); - -moz-box-shadow: 0 2px 8px 0 rgba(0, 0, 0, 0.35); - box-shadow: 0 2px 8px 0 rgba(0, 0, 0, 0.35); +.perun-icon-detail { + transform: scale(2.7); + margin-left: 1.4rem; + margin-top: 1.4rem; } -.box-button-medium { - color: #ffffff; - -webkit-box-shadow: 0 2px 8px 0 rgba(0, 0, 0, 0.35); - -moz-box-shadow: 0 2px 8px 0 rgba(0, 0, 0, 0.35); - box-shadow: 0 2px 8px 0 rgba(0, 0, 0, 0.35); +.icon-beak { + vertical-align: bottom; } -.button-shadow { - -webkit-box-shadow: 0 2px 8px 0 rgba(0, 0, 0, 0.35) !important; - -moz-box-shadow: 0 2px 8px 0 rgba(0, 0, 0, 0.35) !important; - box-shadow: 0 2px 8px 0 rgba(0, 0, 0, 0.35) !important; +.icon-scale { + transform: scale(1.7); + margin-left: 0.5rem; + margin-top: -0.4rem; + margin-right: 0.9rem; } -.menu-items { - display: flex; - flex-wrap: wrap; - margin-top: 2rem; +.material-icons.orange { + color: #fb8c00; + vertical-align: bottom; } -.menu-item-large { - img { - width: 100%; - flex-grow: 1; - padding-left: 0.5rem; - padding-right: 0.5rem; - } - - @media (min-width: 768px) and (max-width: 991px) { - img { - padding-left: 0.75rem; - padding-right: 0.75rem; - } - } - - @media (min-width: 992px) and (max-width: 1199px) { - img { - padding-left: 0.75rem; - padding-right: 0.75rem; - } - } - - @media (min-width: 1200px) { - img { - padding-left: 1rem; - padding-right: 1rem; - } - } - display: flex; - flex-direction: column; - text-align: center; - font-size: 1.25em; - padding: 0.5rem 0.5rem 1.5rem 0.5rem; - width: 100%; - margin: 1rem; - - &:first-child { - margin-left: 0; - } - - &:last-child { - margin-right: 0; - } - - &:hover { - color: white; - text-decoration: none !important; - } +.material-icons.red { + color: #ff0000; + vertical-align: bottom; } -.menu-item-small { - img { - width: 100%; - flex-grow: 1; - padding-left: 0.5rem; - padding-right: 0.5rem; - } - - @media (min-width: 768px) and (max-width: 991px) { - img { - padding-left: 0.75rem; - padding-right: 0.75rem; - } - } - - @media (min-width: 992px) and (max-width: 1199px) { - img { - padding-left: 1rem; - padding-right: 1rem; - } - } - - @media (min-width: 1200px) { - img { - padding-left: 1.25rem; - padding-right: 1.25rem; - } - } - - @media (min-width: 1600px) { - img { - padding-left: 1.5rem; - padding-right: 1.5rem; - } - } - display: flex; - flex-direction: column; - text-align: center; - font-size: 1.25em; - padding: 0.5rem; - width: 100%; - margin: 1rem; - - &:first-child { - margin-left: 0; - } - - &:last-child { - margin-right: 0; - } - - &:hover { - color: white; - text-decoration: none !important; - } +.material-icons.green { + color: #28a745; + vertical-align: bottom; } -.dark-hover-list-item { - &:hover { - background-color: rgba(0, 0, 0, 0.05); - } +.material-icons.blue { + color: #1a87ff; + vertical-align: bottom; } -.info-table { - td:first-child { - width: 40%; - white-space: nowrap; - } +.material-icons.black { + color: #000000; + vertical-align: bottom; } -.menu-items-row { - margin-left: -15px !important; - margin-right: -15px !important; +.material-icons.grey { + color: #808080; + vertical-align: bottom; } -.menu-item-medium { - align-items: center; - display: flex; - flex-direction: row; - text-align: center; - padding: 0.75rem; - width: 100%; - margin: 1rem; - font-size: 1.25rem; - - &:first-child { - margin-left: 0; - } - - &:last-child { - margin-right: 0; - } - - &:hover { - color: white; - text-decoration: none !important; - } - - img { - width: 4rem; - height: 4rem; - flex-grow: 1; - padding-left: 0.5rem; - padding-right: 0.5rem; - } - - div { - flex-grow: 5; +// this allows custom colors for perun icons used in material icons +.perun-icon { + path { + fill: currentColor !important; } - /*@media (min-width: 992px) and (max-width: 1199px) { - img { - padding-left: .75rem; - padding-right: .75rem; - } + rect { + fill: currentColor; } - @media (min-width: 768px) and (max-width: 991px) { - img { - padding-left: .75rem; - padding-right: .75rem; - } + polygon { + fill: currentColor; } - @media (min-width: 1200px) { - img { - padding-left: 1rem; - padding-right: 1rem; - } - }*/ + min-width: 24px; + min-height: 24px; } -// Color styles for entities -.vo-bg-color { - background-color: var(--vo-color); +/************************************* +*************** Tables *************** +*************************************/ +.static-column-size { + width: 80px; } -.facility-bg-color { - background-color: var(--facility-color); +.hide-table { + height: 0 !important; + overflow: hidden !important; + border: none !important; } -.group-bg-color { - background-color: var(--group-color); +th, +td.mat-mdc-cell { + padding: 0.25rem !important; } -.member-bg-color { - background-color: var(--member-color); +.mdc-data-table__cell { + border-bottom: 1px solid rgba(0, 0, 0, 0.12) !important; } -.admin-bg-color { - background-color: var(--admin-color); +// sticky table headers +.mat-mdc-header-cell { + position: sticky !important; + top: 0; + z-index: 100; + font-weight: bold !important; } -.user-bg-color { - background-color: var(--user-color); - - .cdk-text-field-autofilled { - background-color: black !important; - } +/************************************* +************* Tooltip **************** +*************************************/ +.mat-mdc-tooltip { + font-size: 14px !important; + word-wrap: break-word !important; } -.service-bg-color { - background-color: var(--service-color); +/************************************* +**************** Tab ***************** +*************************************/ +.mdc-tab__text-label { + font-size: 16px !important; + color: black !important; + opacity: 1 !important; + border-radius: var(--bs-border-radius) !important; } -.setting-item { - font-size: 1.15rem; - font-weight: 500; +.mdc-tab__icon { + font-size: 16px !important; } -.clickable { - cursor: pointer; - -webkit-user-select: none; - -moz-user-select: none; - -ms-user-select: none; - user-select: none; +.mat-mdc-tab-header { + border-bottom: 1px solid rgba(0, 0, 0, 0.12) !important; + border-radius: var(--bs-border-radius) var(--bs-border-radius) 0 0 !important; } -.unselected-setting { - color: #888888; +.mat-mdc-tab.mdc-tab--active { + background-color: #e8e4e4; + border-radius: var(--bs-border-radius) var(--bs-border-radius) 0 0 !important; } -.app-btn { - display: inline-block; - font-weight: 400; - color: #212529; - text-align: center; - vertical-align: middle; - -webkit-user-select: none; - -moz-user-select: none; - -ms-user-select: none; - user-select: none; - background-color: transparent; - border: 1px solid transparent; - padding: 0.375rem 0.75rem; - font-size: 1rem; - line-height: 1.5; +// Dont show horizontal scroll at menu items +.mat-mdc-tab-body-content { + overflow: hidden !important; } -.app-btn.disabled, -.app-btn:disabled { - opacity: 0.65; +/************************************* +************* Form field ************* +*************************************/ +.mdc-text-field { + background-color: transparent !important; + margin-top: 5px !important; } - -.app-btn:focus { - outline: none; -} - -.vo-btn { - background: var(--vo-color); - color: rgba(var(--vo-theme-primary-contrast-500), 1); - border-radius: 0; - - &:hover { - color: rgba(var(--vo-theme-primary-contrast-500), 1); - } -} - -.facility-btn { - background-color: var(--facility-color); - color: rgba(var(--facility-theme-primary-contrast-500), 1); - border-radius: 0; - - &:hover { - color: rgba(var(--facility-theme-primary-contrast-500), 1); - } -} - -.resource-btn { - background-color: var(--resource-color); - color: rgba(var(--resource-theme-primary-contrast-500), 1); - border-radius: 0; - - &:hover { - color: rgba(var(--resource-theme-primary-contrast-500), 1); - } -} - -.group-btn { - background: var(--group-color); - color: rgba(var(--group-theme-primary-contrast-500), 1); - border-radius: 0; - - &:hover { - color: rgba(var(--group-theme-primary-contrast-500), 1); - } -} - -.member-btn { - background-color: var(--member-color); - color: rgba(var(--member-theme-primary-contrast-500), 1); - border-radius: 0; - - &:hover { - color: rgba(var(--member-theme-primary-contrast-500), 1); - } -} - -.admin-btn { - background-color: var(--admin-color); - color: rgba(var(--admin-theme-primary-contrast-500), 1); - border-radius: 0; - - &:hover { - color: rgba(var(--admin-theme-primary-contrast-500), 1); - } -} - -.user-btn { - background-color: var(--user-color); - color: rgba(var(--user-theme-primary-contrast-500), 1); - border-radius: 0; - - &:hover { - color: rgba(var(--user-theme-primary-contrast-500), 1); - } -} - -.service-btn { - background-color: var(--service-color); - color: rgba(var(--service-theme-primary-contrast-500), 1); - border-radius: 0; - - &:hover { - color: rgba(var(--service-theme-primary-contrast-500), 1); - } -} - -.title-link { - color: #000000; - text-decoration: underline; - - &:hover { - color: #404040; - } -} - -.vo-link { - color: var(--vo-color); - text-decoration: underline; - - &:hover { - //color: lighten(var(--vo-color), 10%); - color: mixw(var(--vo-color), 0.1); - } -} - -.facility-link { - color: var(--facility-color); - text-decoration: underline; - - &:hover { - color: mixw(var(--facility-color), 0.1); - } -} - -.resource-link { - color: var(--resource-color); - text-decoration: underline; - - &:hover { - color: mixw(var(--resource-color), 0.1); - } -} - -.member-link { - color: var(--member-color); - text-decoration: underline; - - &:hover { - color: mixw(var(--member-color), 0.1); - } -} - -.group-link { - color: var(--group-color); - text-decoration: underline; - - &:hover { - color: mixw(var(--group-color), 0.1); - } -} - -.user-link { - color: var(--user-color); - text-decoration: underline; - - &:hover { - color: mixw(var(--user-color), 0.1); - } -} - -.service-link { - color: var(--service-color); - text-decoration: underline; - - &:hover { - color: mixw(var(--service-color), 0.1); - } -} - -// HACKS - -// Dont show horizontal scroll at menu items -.mat-mdc-tab-body-content { - overflow: hidden !important; +label:not(.mdc-floating-label--float-above) { + padding-top: 16px !important; + width: 100%; } - -.no-label-margin-bottom { - label { - margin-bottom: 0 !important; +.mat-form-field-appearance-outline { + label:not(.mdc-floating-label--float-above) { + padding-top: 0 !important; } } - -// sharp design -.mat-mdc-outlined-button { - border-radius: var(--bs-border-radius) !important; -} - -.mat-mdc-unelevated-button { - border-radius: var(--bs-border-radius) !important; -} - -.mat-mdc-button { - border-radius: var(--bs-border-radius) !important; -} - -//colors for material icons -.material-icons.orange { - color: #fb8c00; - vertical-align: bottom; -} - -.material-icons.red { - color: #ff0000; - vertical-align: bottom; -} - -.material-icons.green { - color: #28a745; - vertical-align: bottom; -} - -.material-icons.blue { - color: #1a87ff; - vertical-align: bottom; -} - -.material-icons.black { - color: #000000; - vertical-align: bottom; -} - -.material-icons.grey { - color: #808080; - vertical-align: bottom; +.mdc-floating-label--float-above { + width: 133.33% !important; } - -//specific style for dialog without any border -.noBorderDialog .mat-mdc-dialog-container { +mat-form-field mat-icon { padding: 0 !important; } -.mat-drawer-inner-container { - //background-color: mat.get-color-from-palette(mat.$blue-grey-palette, 900); -} - -.align-inline { - display: flex; - line-height: 75px; - align-items: flex-end; +// Custom MDC form field in table - for attributes +table .mdc-text-field { + margin-top: 0 !important; } - -.static-column-size { - width: 80px; +table .mat-mdc-form-field-infix { + min-height: 35px !important; + padding-top: 7px !important; + padding-bottom: 0 !important; } -.hide-table { - height: 0 !important; - overflow: hidden !important; - border: none !important; +// Custom MDC outlined form field in table - for attributes +table .mdc-notched-outline__leading, +table .mdc-notched-outline__trailing { + border: 0 !important; } - -// this allows custom colors for perun icons used in material icons -.perun-icon { - path { - fill: currentColor !important; - } - - rect { - fill: currentColor; - } - - polygon { - fill: currentColor; - } - - min-width: 24px; - min-height: 24px; +table .mdc-text-field--outlined { + padding-left: 0 !important; } -.word-break-all { - word-break: break-all; +/************************************* +************** Checkbox ************** +*************************************/ +.mat-mdc-checkbox label { + padding-top: 0 !important; } -th, -td.mat-mdc-cell { - padding: 0.25rem !important; +/************************************* +************** Radio ***************** +*************************************/ +.mat-mdc-radio-button label { + padding-top: 0 !important; } -.overflow-ellipsis { - text-overflow: ellipsis; +/************************************* +************** Toggle ***************** +*************************************/ +.mat-mdc-slide-toggle label { + padding-top: 0 !important; } -.entity-info { - font-size: 1rem; +/************************************* +************** Cards ***************** +*************************************/ +.card { + border-radius: var(--bs-border-radius) !important; } +/************************************* +************** Loading *************** +*************************************/ .spinner-container { position: absolute; top: 0; @@ -1440,30 +1052,6 @@ td.mat-mdc-cell { justify-content: center; } -.status-change { - position: relative; - display: inline-block; - margin-left: 5px; - - // Using ::before to create a pseudo-element serving as circular background - &:before { - content: ''; - position: absolute; - top: 50%; - left: 50%; - transform: translate(-50%, -50%); - width: 150%; - padding-bottom: 150%; - border-radius: 50%; - background-color: rgba(0, 0, 0, 0.05); - opacity: 0; - } - - &:hover::before { - opacity: 1; - } -} - #preloader { position: fixed; top: 0; @@ -1551,181 +1139,3 @@ td.mat-mdc-cell { right: 0; width: 180px; } - -@keyframes load { - 100% { - opacity: 0; - transform: scale(1); - } -} - -@keyframes load { - 100% { - opacity: 0; - transform: scale(1); - } -} - -.perun-icon-detail { - transform: scale(2.7); - margin-left: 1.4rem; - margin-top: 1.4rem; -} - -.icon-beak { - vertical-align: bottom; -} - -.icon-scale { - transform: scale(1.7); - margin-left: 0.5rem; - margin-top: -0.4rem; - margin-right: 0.9rem; -} - -//font size of tooltip -.mat-mdc-tooltip { - font-size: 14px !important; - word-wrap: break-word !important; -} - -.mdc-tab__text-label { - font-size: 16px !important; - color: black !important; - opacity: 1 !important; - border-radius: var(--bs-border-radius) !important; -} - -.mdc-tab__icon { - font-size: 16px !important; -} - -// hack to make the content of the virtual scroll be limited by its width -.cdk-virtual-scroll-content-wrapper { - contain: size !important; -} - -.action-button { - display: inline-block !important; -} - -.action-button::after { - content: '\2026'; - margin-left: -4px; -} - -.align-checkbox { - text-align: center !important; - vertical-align: middle !important; -} - -//.align-checkbox mat-checkbox { -// margin-top: 7px !important; -//} - -mat-icon { - overflow: inherit !important; -} - -/************************************* -******** Customization of MDC ******** -*************************************/ - -// Custom MDC form field -.mdc-text-field { - background-color: transparent !important; - margin-top: 5px !important; -} -label:not(.mdc-floating-label--float-above) { - padding-top: 16px !important; - width: 100%; -} -.mat-form-field-appearance-outline { - label:not(.mdc-floating-label--float-above) { - padding-top: 0 !important; - } -} -.mdc-floating-label--float-above { - width: 133.33% !important; -} -mat-form-field mat-icon { - padding: 0 !important; -} - -// Custom MDC form field in table - for attributes -table .mdc-text-field { - margin-top: 0 !important; -} -table .mat-mdc-form-field-infix { - min-height: 35px !important; - padding-top: 7px !important; - padding-bottom: 0 !important; -} - -// Custom MDC outlined form field in table - for attributes -table .mdc-notched-outline__leading, -table .mdc-notched-outline__trailing { - border: 0 !important; -} -table .mdc-text-field--outlined { - padding-left: 0 !important; -} - -// Proper mat icon inside button -.mat-mdc-outlined-button > .mat-icon, -.mat-mdc-unelevated-button > .mat-icon { - margin-left: 0 !important; - margin-right: 0 !important; - height: 1.5rem !important; - width: 1.5rem !important; - font-size: 1.5rem !important; -} - -// angular 15 button fixes - -.mdc-button { - border-radius: var(--bs-border-radius) !important; - white-space: nowrap !important; - letter-spacing: normal; -} - -.align-elements { - display: flex; - align-items: center; - flex-wrap: wrap; -} - -.mat-mdc-checkbox label, -.mat-mdc-radio-button label, -.mat-mdc-slide-toggle label { - padding-top: 0 !important; -} - -.mat-mdc-tab-header { - border-bottom: 1px solid rgba(0, 0, 0, 0.12) !important; - border-radius: var(--bs-border-radius) var(--bs-border-radius) 0 0 !important; -} - -.mat-mdc-tab.mdc-tab--active { - background-color: #e8e4e4; - border-radius: var(--bs-border-radius) var(--bs-border-radius) 0 0 !important; -} -.mdc-data-table__cell { - border-bottom: 1px solid rgba(0, 0, 0, 0.12) !important; -} - -// sticky table headers -.mat-mdc-header-cell { - position: sticky !important; - top: 0; - z-index: 100; - font-weight: bold !important; -} - -.mb-25 { - margin-bottom: 0.75rem; -} - -.card { - border-radius: var(--bs-border-radius) !important; -} diff --git a/apps/admin-gui/src/app/app.component.html b/apps/admin-gui/src/app/app.component.html index edd620c99..1e9c91ca1 100644 --- a/apps/admin-gui/src/app/app.component.html +++ b/apps/admin-gui/src/app/app.component.html @@ -6,11 +6,10 @@ + class="nav-menu mat-elevation-z3"> @@ -19,16 +18,14 @@ [fixedInViewport]="true" [mode]="sidebarMode" [fixedTopGap]="getTopGap()" - [ngStyle]="{'border-color': sideBarBorderColor, 'background': sideMenubackgroundColor}" - [opened]="!isMobile()"> + [opened]="!isMobile()" + class="side-nav"> - +
diff --git a/apps/admin-gui/src/app/app.component.ts b/apps/admin-gui/src/app/app.component.ts index 10bee41fc..32f371989 100644 --- a/apps/admin-gui/src/app/app.component.ts +++ b/apps/admin-gui/src/app/app.component.ts @@ -41,11 +41,6 @@ export class AppComponent implements OnInit, AfterViewInit { isServiceAccess: boolean; principal: PerunPrincipal; - theme = this.store.getProperty('theme'); - navBackgroundColor = this.theme.nav_bg_color; - sideBarBorderColor = this.theme.sidemenu_border_color; - contentBackgroundColor = this.theme.content_bg_color; - sideMenubackgroundColor = this.theme.sidemenu_bg_color; displayWarning: boolean = this.store.getProperty('display_warning'); warningMessage: string = this.store.getProperty('warning_message'); 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 1835abc32..8823d385c 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 @@ -4,7 +4,7 @@ import { InitAuthService, MfaHandlerService, } from '@perun-web-apps/perun/services'; -import { AppConfigService, ColorConfig, EntityColorConfig } from '@perun-web-apps/config'; +import { AppConfigService } from '@perun-web-apps/config'; import { AuthzResolverService } from '@perun-web-apps/perun/openapi'; import { MatDialog } from '@angular/material/dialog'; import { Location } from '@angular/common'; @@ -20,84 +20,6 @@ import { firstValueFrom } from 'rxjs'; providedIn: 'root', }) export class AdminGuiConfigService { - entityColorConfigs: EntityColorConfig[] = [ - { - entity: 'vo', - configValue: 'vo_color', - cssVariable: '--vo-color', - }, - { - entity: 'group', - configValue: 'group_color', - cssVariable: '--group-color', - }, - { - entity: 'user', - configValue: 'user_color', - cssVariable: '--user-color', - }, - { - entity: 'member', - configValue: 'member_color', - cssVariable: '--member-color', - }, - { - entity: 'facility', - configValue: 'facility_color', - cssVariable: '--facility-color', - }, - { - entity: 'resource', - configValue: 'resource_color', - cssVariable: '--resource-color', - }, - { - entity: 'admin', - configValue: 'admin_color', - cssVariable: '--admin-color', - }, - { - entity: 'service', - configValue: 'service_color', - cssVariable: '--service-color', - }, - ]; - - colorConfigs: ColorConfig[] = [ - { - configValue: 'sidemenu_hover_color', - cssVariable: '--side-root-item-hover', - }, - { - configValue: 'sidemenu_active_color', - cssVariable: '--side-root-item-active', - }, - { - configValue: 'sidemenu_submenu_active_color', - cssVariable: '--side-link-active', - }, - { - configValue: 'sidemenu_submenu_hover_color', - cssVariable: '--side-link-hover', - }, - { - configValue: 'sidemenu_hover_text_color', - cssVariable: '--side-root-item-text-hover', - }, - { - configValue: 'sidemenu_active_text_color', - cssVariable: '--side-root-item-text-active', - }, - { - configValue: 'sidemenu_submenu_active_text_color', - cssVariable: '--side-link-text-active', - }, - { - configValue: 'sidemenu_submenu_hover_text_color', - cssVariable: '--side-link-text-hover', - }, - ]; - constructor( private initAuthService: InitAuthService, private appConfigService: AppConfigService, @@ -113,9 +35,6 @@ export class AdminGuiConfigService { .loadAppDefaultConfig() .then(() => this.appConfigService.loadAppInstanceConfig()) .then(() => this.appConfigService.setApiUrl()) - .then(() => - this.appConfigService.initializeColors(this.entityColorConfigs, this.colorConfigs) - ) .then(() => this.appConfigService.setInstanceFavicon()) .then(() => this.initAuthService.verifyAuth()) .catch((err) => { diff --git a/apps/admin-gui/src/app/shared/side-menu/side-menu-item/side-menu-item.component.scss b/apps/admin-gui/src/app/shared/side-menu/side-menu-item/side-menu-item.component.scss index 65163f4d8..e69de29bb 100644 --- a/apps/admin-gui/src/app/shared/side-menu/side-menu-item/side-menu-item.component.scss +++ b/apps/admin-gui/src/app/shared/side-menu/side-menu-item/side-menu-item.component.scss @@ -1,40 +0,0 @@ -.side-menu-item { - a { - padding: 0.5rem 0.5rem 0.5rem 1rem; - cursor: pointer; - text-decoration: none; - - &:hover { - background: var(--side-root-item-hover) !important; - color: var(--side-root-item-text-hover) !important; - } - } -} - -.side-menu-item-label { - display: flex; - flex-direction: row; - align-items: center; - word-break: break-word; - text-decoration: none; -} - -.side-menu-link { - a { - padding: 0.25rem 0.25rem 0.25rem 2rem; - text-decoration: none; - color: #ffffff; - font-size: 1rem; - display: block; - - &:hover { - background: var(--side-link-hover) !important; - color: var(--side-link-text-hover) !important; - } - } -} - -.header-activated { - background: var(--side-root-item-active) !important; - color: var(--side-root-item-text-active) !important; -} diff --git a/apps/admin-gui/src/assets/config/defaultConfig.json b/apps/admin-gui/src/assets/config/defaultConfig.json index 371209b4e..8aa945a60 100644 --- a/apps/admin-gui/src/assets/config/defaultConfig.json +++ b/apps/admin-gui/src/assets/config/defaultConfig.json @@ -123,7 +123,7 @@ "profile_label_en": "Profile", "logo": "image/svg+xml\n\n\t.st0{fill:#FFFFFF;}\n\n\n\n\t\n\t\n\n", "theme": { - "content_bg_color": "", + "content_bg_color": "#f2f2f2", "back_button_color": "#000000", "nav_bg_color": "#102027", "nav_text_color": "#ffffff", @@ -140,6 +140,7 @@ "sidemenu_active_color": "#465258", "sidemenu_active_text_color": "#ffffff", "sidemenu_text_color": "#ffffff", + "sidemenu_item_icon_color": "#ffffff", "sidemenu_submenu_bg_color": "#1b2428", "sidemenu_submenu_hover_color": "#566268", "sidemenu_submenu_hover_text_color": "#ffffff", diff --git a/apps/consolidator/src/_styles.scss b/apps/consolidator/src/_styles.scss index a108719aa..ae6fe97ad 100644 --- a/apps/consolidator/src/_styles.scss +++ b/apps/consolidator/src/_styles.scss @@ -7,29 +7,6 @@ // Changes to the styles.scss would result in the styles being overwritten // during the build process and the changes would be lost. -@function mat-color-from-palette($palette, $hue: default, $opacity: null) { - @if type-of($hue) == number and $hue >= 0 and $hue <= 1 { - @return mat-color-from-palette($palette, default, $hue); - } - - $color: map-get($palette, $hue); - - @if (type-of($color) != color) { - @if ($opacity == null) { - @return $color; - } - - // Here is the change from the original function: - // If the $color resolved to something different from a color, we assume it is a CSS variable - // in the form of rgba(var(--rgba-css-var),a) and replace the 'a' value. - @return #{str-slice($color, 0, str-index($color, ',')) + $opacity + ')'}; - } - - @return rgba($color, if($opacity == null, opacity($color), $opacity)); -} - -// Plus imports for other components in your app. - // Include the common styles for Angular Material. @include mat.all-component-typographies(); @include mat.core(); @@ -61,6 +38,9 @@ $perun-theme: mat.define-light-theme( // that you are using. @include mat.all-component-themes($perun-theme); +/************************************* +************** User theme ************ +*************************************/ .user-theme { $user-dynamic-colors: ( 50: rgba(var(--user-theme-primary-50), 1), @@ -110,25 +90,30 @@ $perun-theme: mat.define-light-theme( @include mat.all-component-colors($user-theme); } +/************************************* +************** Buttons *************** +*************************************/ button { border-radius: var(--bs-border-radius) !important; } -button:focus { - outline: none !important; +.mdc-button { + border-radius: var(--bs-border-radius) !important; + white-space: nowrap !important; + letter-spacing: normal; } +/************************************* +*************** Titles *************** +*************************************/ .page-subtitle { margin-bottom: 1rem; font-size: 1.5rem; } -.dark-hover-list-item { - &:hover { - background-color: rgba(0, 0, 0, 0.05); - } -} - +/************************************* +*************** Dialogs ************** +*************************************/ .dialog-container { display: flex; flex-direction: column; @@ -138,6 +123,61 @@ button:focus { width: 100%; } +.noBorderDialog .mat-mdc-dialog-container { + background-color: black; + border-radius: var(--bs-border-radius); +} + +.noBorderDialog .mat-mdc-dialog-container .mdc-dialog__surface { + background-color: black !important; + border-radius: var(--bs-border-radius); +} + +/************************************* +*************** Icons **************** +*************************************/ +mat-icon { + overflow: inherit !important; +} + +.perun-icon { + path { + fill: currentColor !important; + } + rect { + fill: currentColor; + } + polygon { + fill: currentColor; + } +} + +.perun-icon-detail { + transform: scale(2.7); + margin-left: 1.4rem; + margin-top: 1.4rem; +} + +/************************************* +*************** Tables *************** +*************************************/ +.mat-mdc-header-cell { + position: sticky !important; + top: 0; + z-index: 100; + font-weight: bold !important; +} + +/************************************* +*************** Chip *************** +*************************************/ +mat-mdc-chip-grid { + pointer-events: none; +} + +/************************************* +************** Loading *************** +*************************************/ .spinner-container { position: absolute; top: 0; @@ -223,55 +263,3 @@ button:focus { transform: rotate(360deg); } } - -.perun-icon { - path { - fill: currentColor !important; - } - rect { - fill: currentColor; - } - polygon { - fill: currentColor; - } -} - -.perun-icon-detail { - transform: scale(2.7); - margin-left: 1.4rem; - margin-top: 1.4rem; -} - -.noBorderDialog .mat-mdc-dialog-container { - background-color: black; - border-radius: var(--bs-border-radius); -} - -.noBorderDialog .mat-mdc-dialog-container .mdc-dialog__surface { - background-color: black !important; - border-radius: var(--bs-border-radius); -} - -mat-mdc-chip-grid { - pointer-events: none; -} - -mat-icon { - overflow: inherit !important; -} - -// angular 15 button fixes - -.mdc-button { - border-radius: var(--bs-border-radius) !important; - white-space: nowrap !important; - letter-spacing: normal; -} - -// sticky table headers -.mat-mdc-header-cell { - position: sticky !important; - top: 0; - z-index: 100; - font-weight: bold !important; -} diff --git a/apps/linker/src/_styles.scss b/apps/linker/src/_styles.scss index ed7555c24..3a9d4aa95 100644 --- a/apps/linker/src/_styles.scss +++ b/apps/linker/src/_styles.scss @@ -7,29 +7,6 @@ // Changes to the styles.scss would result in the styles being overwritten // during the build process and the changes would be lost. -@function mat-color-from-palette($palette, $hue: default, $opacity: null) { - @if type-of($hue) == number and $hue >= 0 and $hue <= 1 { - @return mat-color-from-palette($palette, default, $hue); - } - - $color: map-get($palette, $hue); - - @if (type-of($color) != color) { - @if ($opacity == null) { - @return $color; - } - - // Here is the change from the original function: - // If the $color resolved to something different from a color, we assume it is a CSS variable - // in the form of rgba(var(--rgba-css-var),a) and replace the 'a' value. - @return #{str-slice($color, 0, str-index($color, ',')) + $opacity + ')'}; - } - - @return rgba($color, if($opacity == null, opacity($color), $opacity)); -} - -// Plus imports for other components in your app. - // Include the common styles for Angular Material. @include mat.all-component-typographies(); @include mat.core(); @@ -61,6 +38,9 @@ $perun-theme: mat.define-light-theme( // that you are using. @include mat.all-component-themes($perun-theme); +/************************************* +************** User theme ************ +*************************************/ .user-theme { $user-dynamic-colors: ( 50: rgba(var(--user-theme-primary-50), 1), @@ -110,6 +90,49 @@ $perun-theme: mat.define-light-theme( @include mat.all-component-colors($user-theme); } +/************************************* +*************** Icons **************** +*************************************/ +mat-icon { + overflow: inherit !important; +} + +.perun-icon { + path { + fill: currentColor !important; + } + rect { + fill: currentColor; + } + polygon { + fill: currentColor; + } +} + +/************************************* +************** Buttons *************** +*************************************/ +button { + border-radius: var(--bs-border-radius) !important; +} + +.mdc-button { + border-radius: var(--bs-border-radius) !important; + white-space: nowrap !important; + letter-spacing: normal; +} + +/************************************* +*************** Titles *************** +*************************************/ +.page-subtitle { + margin-bottom: 1rem; + font-size: 1.5rem; +} + +/************************************* +************** Loading *************** +*************************************/ .spinner-container { position: absolute; top: 0; @@ -195,40 +218,3 @@ $perun-theme: mat.define-light-theme( transform: rotate(360deg); } } - -.perun-icon { - path { - fill: currentColor !important; - } - rect { - fill: currentColor; - } - polygon { - fill: currentColor; - } -} - -button { - border-radius: var(--bs-border-radius) !important; -} - -button:focus { - outline: none !important; -} - -mat-icon { - overflow: inherit !important; -} - -.page-subtitle { - margin-bottom: 1rem; - font-size: 1.5rem; -} - -// angular 15 button fixes - -.mdc-button { - border-radius: var(--bs-border-radius) !important; - white-space: nowrap !important; - letter-spacing: normal; -} diff --git a/apps/password-reset/src/_styles.scss b/apps/password-reset/src/_styles.scss index 87aca6935..bf0225382 100644 --- a/apps/password-reset/src/_styles.scss +++ b/apps/password-reset/src/_styles.scss @@ -39,8 +39,9 @@ $password-reset-theme: mat.define-light-theme( // that you are using. @include mat.all-component-themes($password-reset-theme); -/* You can add global styles to this file, and also import other style files */ - +/************************************* +************** User theme ************ +*************************************/ .user-theme { $user-dynamic-colors: ( 50: rgba(var(--user-theme-primary-50), 1), @@ -90,10 +91,26 @@ $password-reset-theme: mat.define-light-theme( @include mat.all-component-colors($user-theme); } +/************************************* +************** Buttons *************** +*************************************/ +button { + border-radius: var(--bs-border-radius) !important; +} + .mat-mdc-unelevated-button { border-radius: var(--bs-border-radius) !important; } +.mdc-button { + border-radius: var(--bs-border-radius) !important; + white-space: nowrap !important; + letter-spacing: normal; +} + +/************************************* +*************** Dialogs ************** +*************************************/ .dialog-container { display: flex; flex-direction: column; @@ -103,32 +120,51 @@ $password-reset-theme: mat.define-light-theme( width: 100%; } +/************************************* +*************** Icons **************** +*************************************/ +mat-icon { + overflow: inherit !important; +} + +// Proper mat icon inside button +.mat-mdc-outlined-button > .mat-icon, +.mat-mdc-unelevated-button > .mat-icon { + margin-left: 0 !important; + margin-right: 0 !important; + height: 1.5rem !important; + width: 1.5rem !important; + font-size: 1.5rem !important; +} + +/************************************* +*************** Tables *************** +*************************************/ +.mdc-data-table__cell { + border-bottom: 1px solid rgba(0, 0, 0, 0.12) !important; +} + +/************************************* +************* Tooltip **************** +*************************************/ .mat-mdc-tooltip { font-size: 13px !important; } -mat-icon { - overflow: inherit !important; +/************************************* +**************** Tab ***************** +*************************************/ +.mat-mdc-tab-header { + border-bottom: 1px solid rgba(0, 0, 0, 0.12) !important; } -.spinner-container { - position: absolute; - top: 0; - left: 0; - bottom: 0; - right: 0; - background: rgba(0, 0, 0, 0.15); - z-index: 999; - display: flex; - align-items: center; - justify-content: center; +.mat-mdc-tab.mdc-tab--active { + background-color: #e8e4e4; } /************************************* -******** Customization of MDC ******** +************* Form field ************* *************************************/ - -// Custom MDC form field .mdc-text-field { background-color: transparent !important; margin-top: 5px !important; @@ -149,32 +185,18 @@ mat-form-field mat-icon { padding: 0 !important; } -// angular 15 button fixes - -.mdc-button { - border-radius: var(--bs-border-radius) !important; - white-space: nowrap !important; - letter-spacing: normal; -} - -// Proper mat icon inside button -.mat-mdc-outlined-button > .mat-icon, -.mat-mdc-unelevated-button > .mat-icon { - margin-left: 0 !important; - margin-right: 0 !important; - height: 1.5rem !important; - width: 1.5rem !important; - font-size: 1.5rem !important; -} - -.mat-mdc-tab-header { - border-bottom: 1px solid rgba(0, 0, 0, 0.12) !important; -} - -.mat-mdc-tab.mdc-tab--active { - background-color: #e8e4e4; -} - -.mdc-data-table__cell { - border-bottom: 1px solid rgba(0, 0, 0, 0.12) !important; +/************************************* +************** Loading *************** +*************************************/ +.spinner-container { + position: absolute; + top: 0; + left: 0; + bottom: 0; + right: 0; + background: rgba(0, 0, 0, 0.15); + z-index: 999; + display: flex; + align-items: center; + justify-content: center; } diff --git a/apps/publications/src/_styles.scss b/apps/publications/src/_styles.scss index 454937fee..af1d2d671 100644 --- a/apps/publications/src/_styles.scss +++ b/apps/publications/src/_styles.scss @@ -7,29 +7,6 @@ // Changes to the styles.scss would result in the styles being overwritten // during the build process and the changes would be lost. -@function mat-color-from-palette($palette, $hue: default, $opacity: null) { - @if type-of($hue) == number and $hue >= 0 and $hue <= 1 { - @return mat-color-from-palette($palette, default, $hue); - } - - $color: map-get($palette, $hue); - - @if (type-of($color) != color) { - @if ($opacity == null) { - @return $color; - } - - // Here is the change from the original function: - // If the $color resolved to something different from a color, we assume it is a CSS variable - // in the form of rgba(var(--rgba-css-var),a) and replace the 'a' value. - @return #{str-slice($color, 0, str-index($color, ',')) + $opacity + ')'}; - } - - @return rgba($color, if($opacity == null, opacity($color), $opacity)); -} - -// Plus imports for other components in your app. - // Include the common styles for Angular Material. @include mat.all-component-typographies(); @include mat.core(); @@ -61,6 +38,9 @@ $perun-theme: mat.define-light-theme( // that you are using. @include mat.all-component-themes($perun-theme); +/************************************* +************* User theme ************* +*************************************/ .user-theme { $user-dynamic-colors: ( 50: rgba(var(--user-theme-primary-50), 1), @@ -110,27 +90,68 @@ $perun-theme: mat.define-light-theme( @include mat.all-component-colors($user-theme); } +/************************************* +************** Buttons *************** +*************************************/ button { border-radius: var(--bs-border-radius) !important; } -button:focus { - outline: none !important; +.mdc-button { + border-radius: var(--bs-border-radius) !important; + white-space: nowrap !important; + letter-spacing: normal; } -th, -td.mat-mdc-cell { - padding: 0.25rem !important; +.action-button::after { + content: '\2026'; } +/************************************* +*************** Dialogs ************** +*************************************/ +.dialog-container { + display: flex; + flex-direction: column; +} + +.dialog-container > * { + width: 100%; +} + +/************************************* +*************** Titles *************** +*************************************/ .page-subtitle { margin-bottom: 1rem; font-size: 1.5rem; } -.dark-hover-list-item { - &:hover { - background-color: rgba(0, 0, 0, 0.05); +/************************************* +*************** Icons **************** +*************************************/ +mat-icon { + overflow: inherit !important; +} + +.mat-mdc-outlined-button > .mat-icon, +.mat-mdc-unelevated-button > .mat-icon { + margin-left: 0 !important; + margin-right: 0 !important; + height: 1.5rem !important; + width: 1.5rem !important; + font-size: 1.5rem !important; +} + +.perun-icon { + path { + fill: currentColor !important; + } + rect { + fill: currentColor; + } + polygon { + fill: currentColor; } } @@ -138,14 +159,117 @@ td.mat-mdc-cell { font-size: 32px; } -.dialog-container { - display: flex; - flex-direction: column; +/************************************* +*************** Tables *************** +*************************************/ +th, +td.mat-mdc-cell { + padding: 0.25rem !important; } -.dialog-container > * { +.static-column-size { + width: 80px; +} + +.mdc-data-table__cell { + border-bottom: 1px solid rgba(0, 0, 0, 0.12) !important; +} + +// sticky table headers +.mat-mdc-header-cell { + position: sticky !important; + top: 0; + z-index: 100; + font-weight: bold !important; +} + +/************************************* +************* Tooltip **************** +*************************************/ +.mat-mdc-tooltip { + font-size: 14px !important; + word-wrap: break-word !important; +} + +/************************************* +**************** Tab ***************** +*************************************/ +.mat-mdc-tab-header { + border-bottom: 1px solid rgba(0, 0, 0, 0.12) !important; +} + +.mat-mdc-tab.mdc-tab--active { + background-color: #e8e4e4; +} + +/************************************* +************* Form field ************* +*************************************/ +.mdc-text-field { + background-color: transparent !important; + margin-top: 5px !important; +} +label:not(.mdc-floating-label--float-above) { + padding-top: 16px !important; width: 100%; } +.mat-form-field-appearance-outline { + label:not(.mdc-floating-label--float-above) { + padding-top: 0 !important; + } +} +.mdc-floating-label--float-above { + width: 133.33% !important; +} +mat-form-field mat-icon { + padding: 0 !important; +} + +/************************************* +************** Checkbox ************** +*************************************/ +.align-checkbox { + text-align: center !important; + vertical-align: middle !important; +} + +.align-checkbox mat-checkbox { + margin-top: 7px !important; +} + +.mat-mdc-checkbox label { + padding-top: 0 !important; +} + +/************************************* +************** Radio ***************** +*************************************/ +.mat-mdc-radio-button label { + padding-top: 0 !important; +} + +/************************************* +************** Toggle ***************** +*************************************/ +.mat-mdc-slide-toggle label { + padding-top: 0 !important; +} + +/************************************* +************** Loading *************** +*************************************/ +.spinner-container { + position: absolute; + top: 0; + left: 0; + bottom: 0; + right: 0; + background: rgba(0, 0, 0, 0.15); + z-index: 999; + display: flex; + align-items: center; + justify-content: center; +} .loading { min-height: 100vh; @@ -325,123 +449,3 @@ $i: 0; transform: rotateZ(-90deg); } } - -.action-button::after { - content: '\2026'; -} - -.perun-icon { - path { - fill: currentColor !important; - } - rect { - fill: currentColor; - } - polygon { - fill: currentColor; - } -} - -mat-icon { - overflow: inherit !important; -} - -.static-column-size { - width: 80px; -} - -.align-checkbox { - text-align: center !important; - vertical-align: middle !important; -} - -.align-checkbox mat-checkbox { - margin-top: 7px !important; -} - -.mat-mdc-tooltip { - font-size: 14px !important; - word-wrap: break-word !important; -} - -.spinner-container { - position: absolute; - top: 0; - left: 0; - bottom: 0; - right: 0; - background: rgba(0, 0, 0, 0.15); - z-index: 999; - display: flex; - align-items: center; - justify-content: center; -} - -/************************************* -******** Customization of MDC ******** -*************************************/ - -// Custom MDC form field -.mdc-text-field { - background-color: transparent !important; - margin-top: 5px !important; -} -label:not(.mdc-floating-label--float-above) { - padding-top: 16px !important; - width: 100%; -} -.mat-form-field-appearance-outline { - label:not(.mdc-floating-label--float-above) { - padding-top: 0 !important; - } -} -.mdc-floating-label--float-above { - width: 133.33% !important; -} -mat-form-field mat-icon { - padding: 0 !important; -} - -// Proper mat icon inside button -.mat-mdc-outlined-button > .mat-icon, -.mat-mdc-unelevated-button > .mat-icon { - margin-left: 0 !important; - margin-right: 0 !important; - height: 1.5rem !important; - width: 1.5rem !important; - font-size: 1.5rem !important; -} - -// angular 15 button fixes - -.mdc-button { - border-radius: var(--bs-border-radius) !important; - white-space: nowrap !important; - letter-spacing: normal; -} - -.mat-mdc-checkbox label, -.mat-mdc-radio-button label, -.mat-mdc-slide-toggle label { - padding-top: 0 !important; -} - -.mat-mdc-tab-header { - border-bottom: 1px solid rgba(0, 0, 0, 0.12) !important; -} - -.mat-mdc-tab.mdc-tab--active { - background-color: #e8e4e4; -} - -.mdc-data-table__cell { - border-bottom: 1px solid rgba(0, 0, 0, 0.12) !important; -} - -// sticky table headers -.mat-mdc-header-cell { - position: sticky !important; - top: 0; - z-index: 100; - font-weight: bold !important; -} diff --git a/apps/publications/src/app/services/publications-config.service.ts b/apps/publications/src/app/services/publications-config.service.ts index 26974811d..5ffc6f68f 100644 --- a/apps/publications/src/app/services/publications-config.service.ts +++ b/apps/publications/src/app/services/publications-config.service.ts @@ -4,7 +4,7 @@ import { InitAuthService, MfaHandlerService, } from '@perun-web-apps/perun/services'; -import { AppConfigService, ColorConfig, EntityColorConfig } from '@perun-web-apps/config'; +import { AppConfigService } from '@perun-web-apps/config'; import { Location } from '@angular/common'; import { AuthzResolverService } from '@perun-web-apps/perun/openapi'; import { firstValueFrom } from 'rxjs'; @@ -13,37 +13,6 @@ import { firstValueFrom } from 'rxjs'; providedIn: 'root', }) export class PublicationsConfigService { - private entityColorConfigs: EntityColorConfig[] = [ - { - entity: 'user', - configValue: 'user_color', - cssVariable: '--user-color', - }, - ]; - - private colorConfigs: ColorConfig[] = [ - { - configValue: 'sidemenu_bg_color', - cssVariable: '--side-bg', - }, - { - configValue: 'sidemenu_hover_color', - cssVariable: '--side-hover', - }, - { - configValue: 'sidemenu_hover_text_color', - cssVariable: '--side-text-hover', - }, - { - configValue: 'sidemenu_active_color', - cssVariable: '--side-active', - }, - { - configValue: 'sidemenu_active_text_color', - cssVariable: '--side-text-active', - }, - ]; - constructor( private initAuthService: InitAuthService, private appConfigService: AppConfigService, @@ -58,9 +27,6 @@ export class PublicationsConfigService { .loadAppDefaultConfig() .then(() => this.appConfigService.loadAppInstanceConfig()) .then(() => this.appConfigService.setApiUrl()) - .then(() => - this.appConfigService.initializeColors(this.entityColorConfigs, this.colorConfigs) - ) .then(() => this.initAuthService.verifyAuth()) .catch((err) => { // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-unsafe-argument diff --git a/apps/user-profile/src/_styles.scss b/apps/user-profile/src/_styles.scss index 6be0821dd..a12630071 100644 --- a/apps/user-profile/src/_styles.scss +++ b/apps/user-profile/src/_styles.scss @@ -7,29 +7,6 @@ // Changes to the styles.scss would result in the styles being overwritten // during the build process and the changes would be lost. -@function mat-color-from-palette($palette, $hue: default, $opacity: null) { - @if type-of($hue) == number and $hue >= 0 and $hue <= 1 { - @return mat-color-from-palette($palette, default, $hue); - } - - $color: map-get($palette, $hue); - - @if (type-of($color) != color) { - @if ($opacity == null) { - @return $color; - } - - // Here is the change from the original function: - // If the $color resolved to something different from a color, we assume it is a CSS variable - // in the form of rgba(var(--rgba-css-var),a) and replace the 'a' value. - @return #{str-slice($color, 0, str-index($color, ',')) + $opacity + ')'}; - } - - @return rgba($color, if($opacity == null, opacity($color), $opacity)); -} - -// Plus imports for other components in your app. - // Include the common styles for Angular Material. @include mat.all-component-typographies(); @include mat.core(); @@ -61,6 +38,9 @@ $perun-theme: mat.define-light-theme( // that you are using. @include mat.all-component-themes($perun-theme); +/************************************* +************* User theme ************* +*************************************/ .user-theme { $user-dynamic-colors: ( 50: rgba(var(--user-theme-primary-50), 1), @@ -68,9 +48,7 @@ $perun-theme: mat.define-light-theme( 200: rgba(var(--user-theme-primary-200), 1), 300: rgba(var(--user-theme-primary-300), 1), 400: rgba(var(--user-theme-primary-400), 1), - //FIXME(theme-error): we want ot load color from the config - // 500: rgba(var(--user-theme-primary-500), 1), - 500: rgba(#00796b, 1), + 500: rgba(var(--user-theme-primary-500), 1), 600: rgba(var(--user-theme-primary-600), 1), 700: rgba(var(--user-theme-primary-700), 1), 800: rgba(var(--user-theme-primary-800), 1), @@ -112,19 +90,45 @@ $perun-theme: mat.define-light-theme( @include mat.all-component-colors($user-theme); } +/************************************* +************** General *************** +*************************************/ +.app-min-width { + min-width: 400px; +} + +.align-elements { + display: flex; + align-items: center; + flex-wrap: wrap; +} + +/************************************* +************** Buttons *************** +*************************************/ button { border-radius: var(--bs-border-radius) !important; } -button:focus { - outline: none !important; +.mdc-button { + border-radius: var(--bs-border-radius) !important; + white-space: nowrap !important; + letter-spacing: normal; } -.page-subtitle { - margin-bottom: 1.5rem; - font-size: 1.25rem; +.action-button::after { + content: '\2026'; +} +/************************************* +*************** Dialogs ************** +*************************************/ +.noBorderDialog .mat-mdc-dialog-container { + background-color: black; } +/************************************* +*************** Titles *************** +*************************************/ .page-title { margin-top: 1rem; margin-bottom: 2rem; @@ -135,27 +139,125 @@ button:focus { margin-bottom: 0.5rem; font-size: 1.2rem; } +/************************************* +*************** Icons **************** +*************************************/ +mat-icon { + overflow: inherit !important; +} -.dark-hover-list-item { - &:hover { - background-color: rgba(0, 0, 0, 0.05); - } +.mat-mdc-outlined-button > .mat-icon, +.mat-mdc-unelevated-button > .mat-icon { + margin-left: 0 !important; + margin-right: 0 !important; + height: 1.5rem !important; + width: 1.5rem !important; + font-size: 1.5rem !important; } +/************************************* +*************** Tables *************** +*************************************/ th, td.mat-mdc-cell { padding: 0.25rem !important; } -.app-min-width { - min-width: 400px; +.mdc-data-table__cell { + border-bottom: 1px solid rgba(0, 0, 0, 0.12) !important; } +// sticky table headers +.mat-mdc-header-cell { + position: sticky !important; + top: 0; + z-index: 100; + font-weight: bold !important; +} + +/************************************* +************* Tooltip **************** +*************************************/ .mat-mdc-tooltip { font-size: 14px !important; word-wrap: break-word !important; } +/************************************* +**************** Tab ***************** +*************************************/ +.mat-mdc-tab-header { + border-bottom: 1px solid rgba(0, 0, 0, 0.12) !important; +} + +.mat-mdc-tab.mdc-tab--active { + background-color: #e8e4e4; +} + +/************************************* +************* Form field ************* +*************************************/ +.mdc-text-field { + background-color: transparent !important; + margin-top: 5px !important; +} +label:not(.mdc-floating-label--float-above) { + padding-top: 16px !important; + width: 100%; +} +.mat-form-field-appearance-outline { + label:not(.mdc-floating-label--float-above) { + padding-top: 0 !important; + } +} +.mdc-floating-label--float-above { + width: 133.33% !important; +} +mat-form-field mat-icon { + padding: 0 !important; +} + +// Custom MDC outlined form field in table - for attributes +table .mdc-notched-outline__leading, +table .mdc-notched-outline__trailing { + border: 0 !important; +} +table .mdc-text-field--outlined { + padding-left: 0 !important; +} + +// Custom MDC form filed in mat-list +mat-list-item .mat-mdc-text-field-wrapper { + height: 40px !important; +} +mat-list-item .mat-mdc-form-field-subscript-wrapper { + height: 0 !important; +} + +/************************************* +************** Checkbox ************** +*************************************/ +.mat-mdc-checkbox label { + padding-top: 0 !important; +} + +/************************************* +************** Radio ***************** +*************************************/ +.mat-mdc-radio-button label { + padding-top: 0 !important; +} + +/************************************* +************** Toggle ***************** +*************************************/ +.mat-mdc-slide-toggle label { + padding-top: 0 !important; +} + +/************************************* +************** Loading *************** +*************************************/ .spinner-container { position: absolute; top: 0; @@ -241,107 +343,3 @@ td.mat-mdc-cell { transform: rotate(360deg); } } - -.action-button::after { - content: '\2026'; -} - -.noBorderDialog .mat-mdc-dialog-container { - background-color: black; -} - -mat-icon { - overflow: inherit !important; -} - -/************************************* -******** Customization of MDC ******** -*************************************/ - -// Custom MDC form field -.mdc-text-field { - background-color: transparent !important; - margin-top: 5px !important; -} -label:not(.mdc-floating-label--float-above) { - padding-top: 16px !important; - width: 100%; -} -.mat-form-field-appearance-outline { - label:not(.mdc-floating-label--float-above) { - padding-top: 0 !important; - } -} -.mdc-floating-label--float-above { - width: 133.33% !important; -} -mat-form-field mat-icon { - padding: 0 !important; -} - -// Custom MDC outlined form field in table - for attributes -table .mdc-notched-outline__leading, -table .mdc-notched-outline__trailing { - border: 0 !important; -} -table .mdc-text-field--outlined { - padding-left: 0 !important; -} - -// Custom MDC form filed in mat-list -mat-list-item .mat-mdc-text-field-wrapper { - height: 40px !important; -} -mat-list-item .mat-mdc-form-field-subscript-wrapper { - height: 0 !important; -} - -// angular 15 button fixes - -.mdc-button { - border-radius: var(--bs-border-radius) !important; - white-space: nowrap !important; - letter-spacing: normal; -} - -.align-elements { - display: flex; - align-items: center; - flex-wrap: wrap; -} - -.mat-mdc-checkbox label, -.mat-mdc-radio-button label, -.mat-mdc-slide-toggle label { - padding-top: 0 !important; -} - -// Proper mat icon inside button -.mat-mdc-outlined-button > .mat-icon, -.mat-mdc-unelevated-button > .mat-icon { - margin-left: 0 !important; - margin-right: 0 !important; - height: 1.5rem !important; - width: 1.5rem !important; - font-size: 1.5rem !important; -} - -.mat-mdc-tab-header { - border-bottom: 1px solid rgba(0, 0, 0, 0.12) !important; -} - -.mat-mdc-tab.mdc-tab--active { - background-color: #e8e4e4; -} - -.mdc-data-table__cell { - border-bottom: 1px solid rgba(0, 0, 0, 0.12) !important; -} - -// sticky table headers -.mat-mdc-header-cell { - position: sticky !important; - top: 0; - z-index: 100; - font-weight: bold !important; -} diff --git a/apps/user-profile/src/app/services/user-profile-config.service.ts b/apps/user-profile/src/app/services/user-profile-config.service.ts index 353ab5a72..6674986e9 100644 --- a/apps/user-profile/src/app/services/user-profile-config.service.ts +++ b/apps/user-profile/src/app/services/user-profile-config.service.ts @@ -1,43 +1,12 @@ import { Injectable } from '@angular/core'; import { InitAuthService, MfaHandlerService } from '@perun-web-apps/perun/services'; -import { AppConfigService, ColorConfig, EntityColorConfig } from '@perun-web-apps/config'; +import { AppConfigService } from '@perun-web-apps/config'; import { Location } from '@angular/common'; @Injectable({ providedIn: 'root', }) export class UserProfileConfigService { - entityColorConfigs: EntityColorConfig[] = [ - { - entity: 'user', - configValue: 'user_color', - cssVariable: '--user-color', - }, - ]; - - colorConfigs: ColorConfig[] = [ - { - configValue: 'sidemenu_bg_color', - cssVariable: '--side-bg', - }, - { - configValue: 'sidemenu_hover_color', - cssVariable: '--side-hover', - }, - { - configValue: 'sidemenu_hover_text_color', - cssVariable: '--side-text-hover', - }, - { - configValue: 'sidemenu_active_color', - cssVariable: '--side-active', - }, - { - configValue: 'sidemenu_active_text_color', - cssVariable: '--side-text-active', - }, - ]; - constructor( private initAuthService: InitAuthService, private appConfigService: AppConfigService, @@ -50,9 +19,6 @@ export class UserProfileConfigService { .loadAppDefaultConfig() .then(() => this.appConfigService.loadAppInstanceConfig()) .then(() => this.appConfigService.setApiUrl()) - .then(() => - this.appConfigService.initializeColors(this.entityColorConfigs, this.colorConfigs) - ) .then(() => this.appConfigService.setInstanceFavicon()) .then(() => this.initAuthService.verifyAuth()) .catch((err) => { diff --git a/color-migration.js b/color-migration.js index 846f8c599..bc8a0ae45 100644 --- a/color-migration.js +++ b/color-migration.js @@ -8,18 +8,21 @@ const fs = require('fs/promises'); const tinycolor = require('tinycolor2'); -// Crawls apps directory -const getConfigs = async () => { +/** + * Crawl apps directory and load themes by merging default and instance config + * @returns {Promise<*[]>} Array of themes for each app + */ +const getThemes = async (local) => { // Open apps directory let dir = null; try { dir = await fs.opendir('./apps'); } catch (error) { - console.log("Error opening apps directory"); + console.log('Error opening apps directory'); return; } - const configs = []; + const themes = []; // Read directory let dirent = null; while ((dirent = await dir.read()) !== null) { @@ -27,152 +30,119 @@ const getConfigs = async () => { if (dirent.name === '.gitkeep') continue; if (dirent.name.includes('e2e')) continue; - const config = { - name: dirent.name, - path: `./apps/${dirent.name}`, - colors: {} - } + const theme = { + pathToUpdatedStyles: `./apps/${dirent.name}/src/styles.scss`, + pathToStyles: `./apps/${dirent.name}/src/_styles.scss`, + colors: {}, + }; try { - const file = await fs.readFile(`./apps/${dirent.name}/src/assets/config/defaultConfig.json`, 'utf-8'); - const obj = JSON.parse(file); - config.colors = obj["theme"]; - // Update configs with instanceConfig.json - const file2 = await fs.readFile(`./apps/${dirent.name}/src/assets/config/instanceConfig.json`, 'utf-8'); - const obj2 = JSON.parse(file2); - // Update missing colors - for (let color in obj2["theme"]) { - // Update colors with colors from instanceConfig - if (config.colors[color] != null) { - config.colors[color] = obj2["theme"][color]; - } + // Load default config and set default theme + const dc_file = await fs.readFile( + `./apps/${dirent.name}/src/assets/config/defaultConfig.json`, + 'utf-8' + ); + const dc = JSON.parse(dc_file); + theme.colors = dc['theme']; + + // Load instance config and override theme + let pathToIC = `/var/www/perun-web-apps/${dirent.name}/assets/config/instanceConfig.json`; + if (local) { + pathToIC = `./apps/${dirent.name}/src/assets/config/instanceConfig.json` + } + const ic_file = await fs.readFile( + pathToIC, + 'utf-8' + ); + const ic = JSON.parse(ic_file); + // Override colors + for (let color in ic['theme']) { + theme.colors[color] = ic['theme'][color]; } } catch (error) { - //console.log("Error reading a config file", error); + // console.log("Error reading a config file", error); } finally { - for (let color in config.colors) { - if (color.includes('_')) { - // Update keys to have - instead of _ - let newColor = color.replaceAll('_', '-'); - // Remove '-color' from each color name - newColor = newColor.substring(0, newColor.indexOf('-color')); - config.colors[newColor] = config.colors[color]; - delete config.colors[color]; - } + for (let color in theme.colors) { + // Update keys to represent css variable names (e.g. --vo-color) + let newColor = '--' + color.replaceAll('_', '-'); + theme.colors[newColor] = theme.colors[color]; + delete theme.colors[color]; } - configs.push(config); + themes.push(theme); } } - dir.close(); - return configs; -} + void dir.close(); + return themes; +}; -// https://www.w3.org/TR/2008/REC-WCAG20-20081211/#relativeluminancedef -const computeLuminance = (color) => { - const rgb = tinycolor(color).toRgb(); - let r = rgb.r / 255; - let g = rgb.g / 255; - let b = rgb.b / 255; - if (r <= 0.03928) { - r = r / 12.92; - } else { - r = Math.pow((r + 0.055) / 1.055, 2.4); - } - if (g <= 0.03928) { - g = g / 12.92; - } - else { - g = Math.pow((g + 0.055) / 1.055, 2.4); - } - if (b <= 0.03928) { - b = b / 12.92; - } - else { - b = Math.pow((b + 0.055) / 1.055, 2.4); - } - return 0.2126 * r + 0.7152 * g + 0.0722 * b; -} - -// Via: https://www.w3.org/TR/2008/REC-WCAG20-20081211/#contrast-ratiodef -const computeContrast = (color1, color2) => { - const l1 = computeLuminance(color1); - const l2 = computeLuminance(color2); - if (l1 > l2) { - return (l1 + 0.05) / (l2 + 0.05); - } else { - return (l2 + 0.05) / (l1 + 0.05); - } -} - -const generatePallette = (color) => { +const generatePalette = (color) => { + // FIXME this simple way of palette creation is not very robust + // for lighter colors it goes to white on the lower end (for dark to black on higher end) const colors = { - "50": tinycolor(color).lighten(52).toHexString(), // light - "100": tinycolor(color).lighten(37).toHexString(), // light - "200": tinycolor(color).lighten(26).toHexString(), - "300": tinycolor(color).lighten(12).toHexString(), - "400": tinycolor(color).lighten(6).toHexString(), - "500": tinycolor(color).toHexString(), - "600": tinycolor(color).darken(6).toHexString(), - "700": tinycolor(color).darken(12).toHexString(), - "800": tinycolor(color).darken(18).toHexString(), - "900": tinycolor(color).darken(24).toHexString(), - "A100": tinycolor(color).lighten(50).saturate(30).toHexString(), // light - "A200": tinycolor(color).lighten(30).saturate(30).toHexString(), - "A400": tinycolor(color).lighten(10).saturate(15).toHexString(), - "A700": tinycolor(color).lighten(5).saturate(5).toHexString(), - } - const contrast = {}; - for (let key in colors) { - // Compute contrast ratio w.r.t. white - const ratioWhite = computeContrast(colors[key], "#ffffff"); - // Compute contrast ratio w.r.t. 1e1e1e - const ratioBlack = computeContrast(colors[key], "#1e1e1e"); - // Pick the higher ratio - contrast[key] = ratioWhite > ratioBlack ? "#ffffff" : "#1e1e1e"; + '50': tinycolor(color).lighten(52).toHexString(), + '100': tinycolor(color).lighten(37).toHexString(), + '200': tinycolor(color).lighten(26).toHexString(), + '300': tinycolor(color).lighten(12).toHexString(), + '400': tinycolor(color).lighten(6).toHexString(), + '500': tinycolor(color).toHexString(), + '600': tinycolor(color).darken(6).toHexString(), + '700': tinycolor(color).darken(12).toHexString(), + '800': tinycolor(color).darken(18).toHexString(), + '900': tinycolor(color).darken(24).toHexString(), + 'A100': tinycolor(color).lighten(50).saturate(30).toHexString(), + 'A200': tinycolor(color).lighten(30).saturate(30).toHexString(), + 'A400': tinycolor(color).lighten(10).saturate(15).toHexString(), + 'A700': tinycolor(color).lighten(5).saturate(5).toHexString(), + }; + for (let hue in colors) { + colors[`contrast-${hue}`] = tinycolor.mostReadable(colors[hue], ['#ffffff', '#000000']).toHexString(); } - return { colors, contrast }; -} + return colors; +}; -const updateTemplates = async (configs) => { - // Open styles file and replace colors from config - for (let config of configs) { - let _style = await fs.readFile(`${config.path}/src/_styles.scss`, 'utf-8'); - - const regex = new RegExp(/.(.*)-theme \{\n ((.|\n)*)-theme\);\n\}/g); - const matches = _style.match(regex); - if (matches == null) { - continue; +const getEntity = (colorVar) => { + const entities = ['vo', 'facility', 'resource', 'group', 'member', 'admin', 'user', 'service']; + for (let entity of entities) { + if (colorVar.includes(entity)) { + return entity; } - let string = matches[0]; - for (let color in config.colors) { - // Regex to match all instances of color-theme - // var(--{entity}-theme-primary-50) - const regex = new RegExp(`var\\(--${color}-theme-primary-(.*\\d{2,3}\\))`, 'g'); - const m = _style.match(regex); - const pallette = generatePallette(config.colors[color]); + } + return null; +} - // Special case for entities - if (m != null) { - for (const match of m) { - const key = match.substring(match.lastIndexOf('-') + 1, match.indexOf(')')); +/** + * Replaces all variable colors defined in theme with real hex values. + * Creates new file 'styles.scss' with colors replaced. + * + * @param themes Array of themes for each application + * @returns {Promise} + */ +const updateStyles = async (themes) => { + for (let theme of themes) { + let styles = await fs.readFile(theme.pathToStyles, 'utf-8'); - if (match.includes('contrast')) { - string = string.replaceAll(match, pallette.contrast[key]); - continue; - } - // Replace colors in pallette - string = string.replaceAll(match, pallette.colors[key]); + for (let color in theme.colors) { + // Replace all variable colors + styles = styles.replaceAll(`var(${color})`, theme.colors[color]); + // Create palette for entity theme + const entity = getEntity(color); + if (entity) { + const palette = generatePalette(theme.colors[color]) + for (let hue in palette) { + styles = styles.replaceAll(`var(--${entity}-theme-primary-${hue})`, palette[hue]); } } } - // Save cahnges to styles.scss - _style = _style.replaceAll(regex, string); - await fs.writeFile(`${config.path}/src/styles.scss`, _style); + await fs.writeFile(theme.pathToUpdatedStyles, styles); } -} +}; // Async closure (async () => { - const configs = await getConfigs(); - await updateTemplates(configs); - console.log("Style files are loaded from themes!") + let local = false; + if (process.argv.length > 2) { + local = Boolean(process.argv[2]); + } + const themes = await getThemes(local); + await updateStyles(themes); + console.log('Style files are loaded from themes!'); })(); diff --git a/libs/config/src/index.ts b/libs/config/src/index.ts index c47497813..1102164ce 100644 --- a/libs/config/src/index.ts +++ b/libs/config/src/index.ts @@ -1,3 +1 @@ export { AppConfigService } from './lib/app-config.service'; -export { ColorConfig } from './lib/app-config.service'; -export { EntityColorConfig } from './lib/app-config.service'; diff --git a/libs/config/src/lib/app-config.service.ts b/libs/config/src/lib/app-config.service.ts index 37d7d401e..8e113bd1d 100644 --- a/libs/config/src/lib/app-config.service.ts +++ b/libs/config/src/lib/app-config.service.ts @@ -11,41 +11,12 @@ import { Title } from '@angular/platform-browser'; import { UtilsService } from '@perun-web-apps/perun/openapi'; import { PerunConfig } from '@perun-web-apps/perun/models'; -declare const tinycolor: any; - -export interface RGBColor { - r: number; - g: number; - b: number; - a: number; -} - export interface Link extends Element { rel: string; type: string; href: string; } -export interface Color { - name: string; - hex: string; - darkContrast: boolean; - red: number; - green: number; - blue: number; -} - -export interface EntityColorConfig { - entity: string; - configValue: string; - cssVariable: string; -} - -export interface ColorConfig { - configValue: string; - cssVariable: string; -} - @Injectable({ providedIn: 'root', }) @@ -58,42 +29,6 @@ export class AppConfigService { private utilsService: UtilsService ) {} - initializeColors( - entityColorConfigs: EntityColorConfig[], - colorConfigs: ColorConfig[] - ): Promise { - return new Promise((resolve) => { - colorConfigs.forEach((cc) => { - //configuration for single items - const color: string = this.storeService.getProperty('theme')[cc.configValue]; - document.documentElement.style.setProperty(cc.cssVariable, color); - }); - - entityColorConfigs.forEach((ecc) => { - //configuration for whole entities - const color: string = this.storeService.getProperty('theme')[ecc.configValue]; - // set CSS variable for given entity - document.documentElement.style.setProperty(ecc.cssVariable, color); - // update theme for given entity - this.setEntityTheme(ecc.entity, color); - }); - resolve(); - }); - } - - setEntityTheme(entity: string, color: string): void { - const primaryColorPalette = computeColors(color); - - for (const paletteColor of primaryColorPalette) { - const key1 = `--${entity}-theme-primary-${paletteColor.name}`; - const value1 = `${paletteColor.red},${paletteColor.green},${paletteColor.blue}`; - const key2 = `--${entity}-theme-primary-contrast-${paletteColor.name}`; - const value2 = paletteColor.darkContrast ? '30,30,30' : '255,255,255'; - document.documentElement.style.setProperty(key1, value1); - document.documentElement.style.setProperty(key2, value2); - } - } - /** * Load default configuration. * If instance is not in production mode, the configuration is also @@ -196,35 +131,3 @@ export class AppConfigService { }); } } - -function computeColors(hex: string): Color[] { - return [ - getColorObject(tinycolor(hex).lighten(52), '50'), - getColorObject(tinycolor(hex).lighten(37), '100'), - getColorObject(tinycolor(hex).lighten(26), '200'), - getColorObject(tinycolor(hex).lighten(12), '300'), - getColorObject(tinycolor(hex).lighten(6), '400'), - getColorObject(tinycolor(hex), '500'), - getColorObject(tinycolor(hex).darken(6), '600'), - getColorObject(tinycolor(hex).darken(12), '700'), - getColorObject(tinycolor(hex).darken(18), '800'), - getColorObject(tinycolor(hex).darken(24), '900'), - getColorObject(tinycolor(hex).lighten(50).saturate(30), 'A100'), - getColorObject(tinycolor(hex).lighten(30).saturate(30), 'A200'), - getColorObject(tinycolor(hex).lighten(10).saturate(15), 'A400'), - getColorObject(tinycolor(hex).lighten(5).saturate(5), 'A700'), - ]; -} - -function getColorObject(value, name): Color { - const c = tinycolor(value); - const rgb: RGBColor = c.toRgb() as RGBColor; - return { - name: name, - hex: c.toHexString(), - darkContrast: c.isLight(), - red: rgb.r, - green: rgb.g, - blue: rgb.b, - }; -} diff --git a/package-lock.json b/package-lock.json index 177b44ef5..de7371298 100644 --- a/package-lock.json +++ b/package-lock.json @@ -43,7 +43,7 @@ "pdfmake": "^0.2.7", "rxjs": "7.8.1", "save": "^2.4.0", - "tinycolor2": "^1.4.2", + "tinycolor2": "1.6.0", "tslib": "^2.3.1", "y18n": "^5.0.8", "zone.js": "0.13.1" @@ -29854,12 +29854,9 @@ "integrity": "sha512-pkY1fj1cKHb2seWDy0B16HeWyczlJA9/WW3u3c4z/NiWDsO3DOU5D7nhTLE9CF0yXv/QZFY7sEJmj24dK+Rrqw==" }, "node_modules/tinycolor2": { - "version": "1.4.2", - "resolved": "https://registry.npmjs.org/tinycolor2/-/tinycolor2-1.4.2.tgz", - "integrity": "sha512-vJhccZPs965sV/L2sU4oRQVAos0pQXwsvTLkWYdqJ+a8Q5kPFzJTuOFwy7UniPli44NKQGAglksjvOcpo95aZA==", - "engines": { - "node": "*" - } + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/tinycolor2/-/tinycolor2-1.6.0.tgz", + "integrity": "sha512-XPaBkWQJdsf3pLKJV9p4qN/S+fm2Oj8AIPo1BTUhg5oxkvm9+SVEGFdhyOz7tTdUTfvxMiAs4sp6/eZO2Ew+pw==" }, "node_modules/tmp": { "version": "0.2.1", diff --git a/package.json b/package.json index 88240dec7..3360115c5 100644 --- a/package.json +++ b/package.json @@ -36,7 +36,7 @@ "start-publications": "ng serve publications --public-host=http://localhost:4200 --disable-host-check", "start-password-reset": "ng serve password-reset --public-host=http://localhost:4200 --disable-host-check", "start-dev-admin-gui-with-external-database": "sudo ng serve admin-gui --port=80 --public-host=http://localhost:80 --disable-host-check", - "postinstall": "node ./decorate-angular-cli.js && node ./color-migration.js", + "postinstall": "node ./decorate-angular-cli.js && node color-migration.js", "workspace-generator": "nx workspace-generator", "semantic-release": "semantic-release" }, @@ -74,7 +74,7 @@ "pdfmake": "^0.2.7", "rxjs": "7.8.1", "save": "^2.4.0", - "tinycolor2": "^1.4.2", + "tinycolor2": "1.6.0", "tslib": "^2.3.1", "y18n": "^5.0.8", "zone.js": "0.13.1", From ecd57a69738ffe1e7b28cae4b0e130644a2d7f81 Mon Sep 17 00:00:00 2001 From: HejdaJakub Date: Fri, 1 Sep 2023 03:48:16 +0200 Subject: [PATCH 3/5] test(admin): fixing the failing E2E tests * New path to advanced settings (and related logic) broke some tests, so it it fixed now. * Removed skip from tests which were failing due to the bug with privileges because this bug has been already fixed IMHO (I think it was related to the refreshing roles on BE where we have done some changes to avoid PrivilegeException). * Fixed some 'hidden' items covered by another item (like header). --- .../src/e2e/admin/perun-admin.cy.js | 2 +- .../src/e2e/facilities/facility-admin.cy.js | 113 +++++++++--------- .../e2e/facilities/facility-observer.cy.js | 43 +++---- .../src/e2e/groups/group-admin.cy.js | 13 +- .../src/e2e/groups/group-observer.cy.js | 57 ++++----- .../src/e2e/resources/resource-admin.cy.js | 89 +++++++------- .../src/e2e/resources/resource-observer.cy.js | 8 +- .../e2e/resources/resource-self-service.cy.js | 2 - .../resources/trusted-facility-admin.cy.js | 4 +- .../src/e2e/vos/perun-admin.cy.js | 2 +- apps/admin-gui-e2e/src/e2e/vos/vo-admin.cy.js | 8 +- .../src/e2e/vos/vo-observer.cy.js | 4 - apps/admin-gui-e2e/src/support/e2e.ts | 4 + 13 files changed, 157 insertions(+), 192 deletions(-) diff --git a/apps/admin-gui-e2e/src/e2e/admin/perun-admin.cy.js b/apps/admin-gui-e2e/src/e2e/admin/perun-admin.cy.js index 41f39ed37..316b20852 100644 --- a/apps/admin-gui-e2e/src/e2e/admin/perun-admin.cy.js +++ b/apps/admin-gui-e2e/src/e2e/admin/perun-admin.cy.js @@ -188,7 +188,7 @@ describe('Perun admin management with role Perun admin', () => { .get(`[data-cy=${dbServiceName2.toLowerCase()}-name-td]`) .click() .get('[data-cy=service-edit-button]') - .click() + .click({force: true}) .get('[data-cy=service-name-input]') .clear() .type(dbServiceName2 + 'edit', {force: true}) diff --git a/apps/admin-gui-e2e/src/e2e/facilities/facility-admin.cy.js b/apps/admin-gui-e2e/src/e2e/facilities/facility-admin.cy.js index bc5fca40f..3cf0ff25e 100644 --- a/apps/admin-gui-e2e/src/e2e/facilities/facility-admin.cy.js +++ b/apps/admin-gui-e2e/src/e2e/facilities/facility-admin.cy.js @@ -176,63 +176,62 @@ describe('Facility management with role Facility admin', () => { .should('not.exist'); }); - it('test add facility manager', () => { - cy.intercept('**/facilitiesManager/getEnrichedFacilities') - .as('getEnrichedFacilities') - .intercept('**/usersManager/findRichUsersWithAttributes?**') - .as('findRichUsers') - // .wait('@getEnrichedFacilities') - .get('[data-cy=filter-input]') - .type(dbFacilityName2, {force: true}) - .get(`[data-cy=${dbFacilityName2}]`) - .click() - .get('[data-cy=advanced-settings]') - .click() - .get('[data-cy=managers]') - .click() - .get('[data-cy=add-manager-button]') - .click() - .get('[data-cy=search-manager-input]') - .type(addManagerUser, {force: true}) - .get('[data-cy=search-manager-button]') - .click() - .wait('@findRichUsers') - .get(`[data-cy=${addManagerUser}-checkbox]`) - .click() - .get('[data-cy=add-manager-button-dialog]') - .click() - .intercept('**/authzResolver/getRichAdmins?**') - .as('getRichAdmins') - .wait('@getRichAdmins') - // assert that manager was added - .get(`[data-cy=${addManagerUser}-checkbox]`) - .should('exist'); - }); + context('Advanced settings', () => { - it('test remove facility manager', () => { - cy.intercept('**/facilitiesManager/getEnrichedFacilities') - .as('getEnrichedFacilities') - // .wait('@getEnrichedFacilities') - .get('[data-cy=filter-input]') - .type(dbFacilityName2, {force: true}) - .get(`[data-cy=${dbFacilityName2}]`) - .click() - .get('[data-cy=advanced-settings]') - .click() - .get('[data-cy=managers]') - .click() - .get(`[data-cy=${removeManagerUser}-checkbox]`) - .click() - .get('[data-cy=remove-manager-button]') - .should('have.attr', 'color', 'warn') // check if the button is enabled (due to the force click below) - .click({ force: true }) - .get('[data-cy=remove-manager-button-dialog]') - .click() - .intercept('**/authzResolver/getRichAdmins?**') - .as('getRichAdmins') - .wait('@getRichAdmins') - // assert that manager doesn't exist - .get(`[data-cy=${removeManagerUser}-checkbox]`) - .should('not.exist'); + it('test add facility manager', () => { + cy.intercept('**/facilitiesManager/getEnrichedFacilities') + .as('getEnrichedFacilities') + .intercept('**/usersManager/findRichUsersWithAttributes?**') + .as('findRichUsers') + // .wait('@getEnrichedFacilities') + .get('[data-cy=filter-input]') + .type(dbFacilityName2, {force: true}) + .get(`[data-cy=${dbFacilityName2}]`) + .click() + .get('[data-cy=managers]') + .click() + .get('[data-cy=add-manager-button]') + .click() + .get('[data-cy=search-manager-input]') + .type(addManagerUser, {force: true}) + .get('[data-cy=search-manager-button]') + .click() + .wait('@findRichUsers') + .get(`[data-cy=${addManagerUser}-checkbox]`) + .click() + .get('[data-cy=add-manager-button-dialog]') + .click() + .intercept('**/authzResolver/getRichAdmins?**') + .as('getRichAdmins') + .wait('@getRichAdmins') + // assert that manager was added + .get(`[data-cy=${addManagerUser}-checkbox]`) + .should('exist'); + }); + + it('test remove facility manager', () => { + cy.intercept('**/facilitiesManager/getEnrichedFacilities') + .as('getEnrichedFacilities') + // .wait('@getEnrichedFacilities') + .get('[data-cy=filter-input]') + .type(dbFacilityName2, {force: true}) + .get(`[data-cy=${dbFacilityName2}]`) + .click() + .get('[data-cy=managers]') + .click() + .get(`[data-cy=${removeManagerUser}-checkbox]`) + .click() + .get('[data-cy=remove-manager-button]') + .should('have.attr', 'color', 'warn') // check if the button is enabled (due to the force click below) + .click({ force: true }) + .get('[data-cy=remove-manager-button-dialog]') + .click() + .intercept('**/authzResolver/getRichAdmins?**') + .as('getRichAdmins') + .wait('@getRichAdmins') + // assert that manager doesn't exist + .get(`[data-cy=${removeManagerUser}-checkbox]`) + .should('not.exist'); + }); }); }); diff --git a/apps/admin-gui-e2e/src/e2e/facilities/facility-observer.cy.js b/apps/admin-gui-e2e/src/e2e/facilities/facility-observer.cy.js index 5c5185ed2..d180554fb 100644 --- a/apps/admin-gui-e2e/src/e2e/facilities/facility-observer.cy.js +++ b/apps/admin-gui-e2e/src/e2e/facilities/facility-observer.cy.js @@ -36,8 +36,7 @@ describe('Facility management with role Facility observer', () => { .should('exist') }); - //FIXME: same problem as in the test below - it.skip('test list assigned users', () => { + it('test list assigned users', () => { cy.get('[data-cy=assigned-users]') .click() .get('[data-cy=filter-input]') @@ -49,12 +48,7 @@ describe('Facility management with role Facility observer', () => { .should('exist') }); - //FIXME: this test often fails when it is executed from command line (but NOT from UI) - // There is problem with policies - test sometimes fails with error "You are not - // authorized to perform this action", but according to getPerunPrincipal() method - // there should be the privilege for given facility and called method (getAllowedGroups). - // For the correct run in CI this test was skipped for this moment - it.skip('test list allowed groups', () => { + it('test list allowed groups', () => { cy.get('[data-cy=allowed-groups]') .click() .reload() @@ -103,23 +97,22 @@ describe('Facility management with role Facility observer', () => { .should('exist') }); - it('test list owners', () => { - cy.get('[data-cy=advanced-settings]') - .click() - .get('[data-cy=owners]') - .click() - .get('[data-cy=filter-input]') - .type(dbOwnerName, {force: true}) - .get(`[data-cy=${dbOwnerName}]`) - .should('exist') - }); + context('Advanced settings', () => { - it('test list managers', () => { - cy.get('[data-cy=advanced-settings]') - .click() - .get('[data-cy=managers]') - .click() - .get(`[data-cy=${dbManagerFirstName}-firstName-td]`) - .should('exist') + it('test list owners', () => { + cy.get('[data-cy=owners]') + .click() + .get('[data-cy=filter-input]') + .type(dbOwnerName, {force: true}) + .get(`[data-cy=${dbOwnerName}]`) + .should('exist') + }); + + it('test list managers', () => { + cy.get('[data-cy=managers]') + .click() + .get(`[data-cy=${dbManagerFirstName}-firstName-td]`) + .should('exist') + }); }); }); diff --git a/apps/admin-gui-e2e/src/e2e/groups/group-admin.cy.js b/apps/admin-gui-e2e/src/e2e/groups/group-admin.cy.js index 6138bafca..ae046bd4f 100644 --- a/apps/admin-gui-e2e/src/e2e/groups/group-admin.cy.js +++ b/apps/admin-gui-e2e/src/e2e/groups/group-admin.cy.js @@ -82,7 +82,8 @@ describe('Group management with role Group admin', () => { .get('[data-cy=attributes]') .click() .get('[data-cy=add-attributes]') - .click() + .should('be.enabled') + .click({force: true}) .get('.mat-mdc-dialog-container') .find('[data-cy=filter-input]') // finds the data-cy attribute inside the dialog container .type('footer', {force: true}) @@ -176,13 +177,8 @@ describe('Group management with role Group admin', () => { }); context('Advanced settings', () => { - beforeEach(() => { - cy.get('[data-cy=advanced-settings]') - .click(); - }); - // TODO fix - randomly failing due to a bug with privileges - it.skip('test create group application form item', () => { + it('test create group application form item', () => { cy.intercept('**/registrarManager/updateFormItems/**') .as('addFormItem') .get('[data-cy=application-form]') @@ -209,8 +205,7 @@ describe('Group management with role Group admin', () => { .should('exist'); }); - // TODO fix - randomly failing due to a bug with privileges - it.skip('test delete group application form item', () => { + it('test delete group application form item', () => { cy.intercept('**/registrarManager/updateFormItems/**') .as('deleteFormItem') .get('[data-cy=application-form]') diff --git a/apps/admin-gui-e2e/src/e2e/groups/group-observer.cy.js b/apps/admin-gui-e2e/src/e2e/groups/group-observer.cy.js index 416191890..18132f752 100644 --- a/apps/admin-gui-e2e/src/e2e/groups/group-observer.cy.js +++ b/apps/admin-gui-e2e/src/e2e/groups/group-observer.cy.js @@ -42,32 +42,9 @@ describe('Group management with role Group observer', () => { .should('exist') }); - it('test list managers', () => { - cy.get('[data-cy=advanced-settings]') - .click() - .get('[data-cy=managers]') - .click() - .get(`[data-cy=${dbGroupAdmin}-firstName-td]`) - .should('exist') - }); - - it('test list extsources', () => { - cy.get('[data-cy=advanced-settings]') - .click() - .get('[data-cy=external-sources]') - .click() - .get('[data-cy=filter-input]') - .type(dbExtsource, {force: true}) - .get(`[data-cy=${dbExtsource}-name-td]`) - .should('exist') - }); - it('test list vo members', () => { cy.get('[data-cy=vo-link]') .click({force: true}) - //FIXME: this is just a quick fix to reload the page cause there is a problem with policies otherwise - // this problem occurs only during the test not in real usage of admin-gui application - .reload() .get('[data-cy=members]') .click() .get('[data-cy=filter-input]') @@ -79,15 +56,6 @@ describe('Group management with role Group observer', () => { .should('exist') }); - it('test get application form', () => { - cy.get('[data-cy=advanced-settings]') - .click() - .get('[data-cy=application-form]') - .click() - .get(`[data-cy=${dbApplicationItemTextFieldName}-shortname-td]`) - .should('exist') - }); - it('test list applications', () => { cy.get('[data-cy=applications]') .click() @@ -97,4 +65,29 @@ describe('Group management with role Group observer', () => { .should('exist') }); + context('Advanced settings', () => { + + it('test list managers', () => { + cy.get('[data-cy=managers]') + .click() + .get(`[data-cy=${dbGroupAdmin}-firstName-td]`) + .should('exist') + }); + + it('test list extsources', () => { + cy.get('[data-cy=external-sources]') + .click() + .get('[data-cy=filter-input]') + .type(dbExtsource, {force: true}) + .get(`[data-cy=${dbExtsource}-name-td]`) + .should('exist') + }); + + it('test get application form', () => { + cy.get('[data-cy=application-form]') + .click() + .get(`[data-cy=${dbApplicationItemTextFieldName}-shortname-td]`) + .should('exist') + }); + }); }); diff --git a/apps/admin-gui-e2e/src/e2e/resources/resource-admin.cy.js b/apps/admin-gui-e2e/src/e2e/resources/resource-admin.cy.js index 06e2b680a..349a22499 100644 --- a/apps/admin-gui-e2e/src/e2e/resources/resource-admin.cy.js +++ b/apps/admin-gui-e2e/src/e2e/resources/resource-admin.cy.js @@ -25,8 +25,6 @@ describe('Resource management with role Resource admin', () => { .type(dbVoName, {force: true}) .get(`[data-cy=${dbVoName}]`) .click() - .get(`[data-cy=resources]`) - .click() .get(`[data-cy=resource-list]`) .click() .get('[data-cy=filter-input]') @@ -75,50 +73,6 @@ describe('Resource management with role Resource admin', () => { .should('not.exist'); }); - it('test add resource manager', () => { - cy.get('[data-cy=advanced-settings]') - .click() - .get('[data-cy=managers]') - .click() - .get('[data-cy=add-manager-button]') - .click() - .get('[data-cy=search-manager-input]') - .type(`${dbAddManager}`, {force: true}) - .get('[data-cy=search-manager-button]') - .click() - .get(`[data-cy=${dbAddManager}-checkbox]`) - .click() - .intercept('**/authzResolver/getRichAdmins**') - .as('getRichAdmins') - .get('[data-cy=add-manager-button-dialog]') - .click() - .wait('@getRichAdmins') - - // assert that manager was added - .get(`[data-cy=${dbAddManager}-checkbox]`) - .should('exist'); - }); - - it('test remove resource manager', () => { - cy.get('[data-cy=advanced-settings]') - .click() - .get('[data-cy=managers]') - .click() - .get(`[data-cy=${dbRemoveManager}-checkbox]`) - .click() - .get('[data-cy=remove-manager-button]') - .click() - .intercept('**/authzResolver/getRichAdmins**') - .as('getRichAdmins') - .get('[data-cy=remove-manager-button-dialog]') - .click() - .wait('@getRichAdmins') - - // assert that manager was removed - .get(`[data-cy=${dbRemoveManager}-checkbox]`) - .should('not.exist'); - }); - it('test assign group to resource', () => { cy.get('[data-cy=assigned-groups]') .click() @@ -160,4 +114,47 @@ describe('Resource management with role Resource admin', () => { .get(`[data-cy=${dbGroupToRemove}-checkbox]`) .should('not.exist'); }); + + context('Advanced settings', () => { + + it('test add resource manager', () => { + cy.get('[data-cy=managers]') + .click() + .get('[data-cy=add-manager-button]') + .click() + .get('[data-cy=search-manager-input]') + .type(`${dbAddManager}`, {force: true}) + .get('[data-cy=search-manager-button]') + .click() + .get(`[data-cy=${dbAddManager}-checkbox]`) + .click() + .intercept('**/authzResolver/getRichAdmins**') + .as('getRichAdmins') + .get('[data-cy=add-manager-button-dialog]') + .click() + .wait('@getRichAdmins') + + // assert that manager was added + .get(`[data-cy=${dbAddManager}-checkbox]`) + .should('exist'); + }); + + it('test remove resource manager', () => { + cy.get('[data-cy=managers]') + .click() + .get(`[data-cy=${dbRemoveManager}-checkbox]`) + .click() + .get('[data-cy=remove-manager-button]') + .click() + .intercept('**/authzResolver/getRichAdmins**') + .as('getRichAdmins') + .get('[data-cy=remove-manager-button-dialog]') + .click() + .wait('@getRichAdmins') + + // assert that manager was removed + .get(`[data-cy=${dbRemoveManager}-checkbox]`) + .should('not.exist'); + }); + }); }); diff --git a/apps/admin-gui-e2e/src/e2e/resources/resource-observer.cy.js b/apps/admin-gui-e2e/src/e2e/resources/resource-observer.cy.js index 78636db9b..6397fde8e 100644 --- a/apps/admin-gui-e2e/src/e2e/resources/resource-observer.cy.js +++ b/apps/admin-gui-e2e/src/e2e/resources/resource-observer.cy.js @@ -22,8 +22,6 @@ describe('Resource management with role Resource observer', () => { .type(dbVoName, {force: true}) .get(`[data-cy=${dbVoName}]`) .click() - .get(`[data-cy=resources]`) - .click() .get(`[data-cy=resource-list]`) .click() .get('[data-cy=filter-input]') @@ -34,7 +32,7 @@ describe('Resource management with role Resource observer', () => { it('view vo groups', () => { cy.get(`[data-cy=${dbVoName}]`) - .click() + .click({force: true}) .get("[data-cy=groups]") .click() @@ -57,9 +55,7 @@ describe('Resource management with role Resource observer', () => { }) it('view admins on resource', () => { - cy.get('[data-cy=advanced-settings]') - .click() - .get('[data-cy=managers]') + cy.get('[data-cy=managers]') .click() // resource admin should be visible diff --git a/apps/admin-gui-e2e/src/e2e/resources/resource-self-service.cy.js b/apps/admin-gui-e2e/src/e2e/resources/resource-self-service.cy.js index 9ea8c5bec..e84502340 100644 --- a/apps/admin-gui-e2e/src/e2e/resources/resource-self-service.cy.js +++ b/apps/admin-gui-e2e/src/e2e/resources/resource-self-service.cy.js @@ -22,8 +22,6 @@ describe('Resource management with role Resource self service', () => { .type(dbVoName, {force: true}) .get(`[data-cy=${dbVoName}]`) .click() - .get(`[data-cy=resources]`) - .click() .get(`[data-cy=resource-list]`) .click() .get('[data-cy=filter-input]') diff --git a/apps/admin-gui-e2e/src/e2e/resources/trusted-facility-admin.cy.js b/apps/admin-gui-e2e/src/e2e/resources/trusted-facility-admin.cy.js index 728075d80..03cbef54d 100644 --- a/apps/admin-gui-e2e/src/e2e/resources/trusted-facility-admin.cy.js +++ b/apps/admin-gui-e2e/src/e2e/resources/trusted-facility-admin.cy.js @@ -119,9 +119,7 @@ describe('Resource management with role Trusted facility admin', () => { context('Advanced settings - Managers', () => { beforeEach(() => { - cy.get('[data-cy=advanced-settings]') - .click() - .get('[data-cy=managers]') + cy.get('[data-cy=managers]') .click() }) it('test add resource manager', () => { diff --git a/apps/admin-gui-e2e/src/e2e/vos/perun-admin.cy.js b/apps/admin-gui-e2e/src/e2e/vos/perun-admin.cy.js index f1cf5b443..5fb68eb7e 100644 --- a/apps/admin-gui-e2e/src/e2e/vos/perun-admin.cy.js +++ b/apps/admin-gui-e2e/src/e2e/vos/perun-admin.cy.js @@ -1,6 +1,6 @@ /// -describe('VO management with role VO admin', () => { +describe('VO management with role Perun admin', () => { const dbVoName = 'test-e2e-vo-to-delete'; before(() => { diff --git a/apps/admin-gui-e2e/src/e2e/vos/vo-admin.cy.js b/apps/admin-gui-e2e/src/e2e/vos/vo-admin.cy.js index ec8d9703e..9f325c760 100644 --- a/apps/admin-gui-e2e/src/e2e/vos/vo-admin.cy.js +++ b/apps/admin-gui-e2e/src/e2e/vos/vo-admin.cy.js @@ -212,12 +212,9 @@ describe('VO management with role VO admin', () => { .type(dbVoName, {force: true}) .get(`[data-cy=${dbVoName}]`) .click() - .get('[data-cy=advanced-settings]') - .click() }) - // TODO fix - randomly failing due to a bug with privileges - it.skip('test create vo application form item', () => { + it('test create vo application form item', () => { cy.intercept('**/registrarManager/updateFormItems/**') .as('addFormItem') .get('[data-cy=application-form]') @@ -244,8 +241,7 @@ describe('VO management with role VO admin', () => { .should('exist'); }); - // TODO fix - randomly failing due to a bug with privileges - it.skip('test delete vo application form item', () => { + it('test delete vo application form item', () => { cy.intercept('**/registrarManager/updateFormItems/**') .as('deleteFormItem') .intercept('**/registrarManager/getFormItems/vo**') diff --git a/apps/admin-gui-e2e/src/e2e/vos/vo-observer.cy.js b/apps/admin-gui-e2e/src/e2e/vos/vo-observer.cy.js index f3d9f8227..8874ff681 100644 --- a/apps/admin-gui-e2e/src/e2e/vos/vo-observer.cy.js +++ b/apps/admin-gui-e2e/src/e2e/vos/vo-observer.cy.js @@ -67,10 +67,6 @@ describe('VO management with role VO observer', () => { }) context('Advanced settings', () => { - beforeEach(() => { - cy.get('[data-cy=advanced-settings]') - .click() - }) it('view vo managers', () => { cy.intercept('**/authzResolver/getRichAdmins**').as('getRichAdmins') diff --git a/apps/admin-gui-e2e/src/support/e2e.ts b/apps/admin-gui-e2e/src/support/e2e.ts index a4ed81a72..8a8e5d3b9 100644 --- a/apps/admin-gui-e2e/src/support/e2e.ts +++ b/apps/admin-gui-e2e/src/support/e2e.ts @@ -18,3 +18,7 @@ import './commands'; import failOnConsoleError from 'cypress-fail-on-console-error'; // eslint-disable-next-line failOnConsoleError(); + +// by default open Advanced settings and Resources in side menu/expandable tiles +window.localStorage.setItem('settings', 'true'); +window.localStorage.setItem('resourcesExpandable', 'true'); From ca99c2b2fd8d9ea5224f4f666ac6b85276946c16 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pavel=20B=C5=99ou=C5=A1ek?= Date: Tue, 5 Sep 2023 08:59:18 +0200 Subject: [PATCH 4/5] ci: fix sections in upgrade notes --- .releaserc.json | 62 ++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 51 insertions(+), 11 deletions(-) diff --git a/.releaserc.json b/.releaserc.json index efa4e610a..3a7467e63 100644 --- a/.releaserc.json +++ b/.releaserc.json @@ -20,17 +20,57 @@ "preset": "conventionalcommits", "presetConfig": { "types": [ - { "type": "feat", "hidden": false }, - { "type": "fix", "hidden": false }, - { "type": "perf", "hidden": false }, - { "type": "revert", "hidden": false }, - { "type": "docs", "hidden": true }, - { "type": "style", "hidden": true }, - { "type": "chore", "hidden": true }, - { "type": "refactor", "hidden": true }, - { "type": "test", "hidden": true }, - { "type": "build", "hidden": true }, - { "type": "ci", "hidden": true } + { + "type": "feat", + "section": "Features" + }, + { + "type": "fix", + "section": "Bug Fixes" + }, + { + "type": "perf", + "section": "Performance Improvements" + }, + { + "type": "revert", + "section": "Reverts" + }, + { + "type": "docs", + "section": "Documentation", + "hidden": true + }, + { + "type": "style", + "section": "Code style", + "hidden": true + }, + { + "type": "chore", + "section": "Others", + "hidden": true + }, + { + "type": "refactor", + "section": "Refactoring", + "hidden": true + }, + { + "type": "test", + "section": "Tests", + "hidden": true + }, + { + "type": "build", + "section": "Build", + "hidden": true + }, + { + "type": "ci", + "section": "CI", + "hidden": true + } ], "issuePrefixes": ["ST"], "issueUrlFormat": "https://perunaai.atlassian.net/browse/{{prefix}}{{id}}" From 316df4762ff6d2c0fdb3b94e8f743ea12c9c387c Mon Sep 17 00:00:00 2001 From: Adam Bodnar Date: Tue, 29 Aug 2023 12:01:15 +0200 Subject: [PATCH 5/5] feat: close session expired dialog in all tabs The reauthentication of user in multiple tabs works fine. However the session expired dialog stayed present aand prevented usage of the app. This is no longer the case --- libs/perun/services/src/lib/ApiInterceptor.ts | 19 +++++++++++-------- libs/perun/services/src/lib/auth.service.ts | 14 ++++++++++++++ 2 files changed, 25 insertions(+), 8 deletions(-) diff --git a/libs/perun/services/src/lib/ApiInterceptor.ts b/libs/perun/services/src/lib/ApiInterceptor.ts index d7d3c2cdc..d270bb4d9 100644 --- a/libs/perun/services/src/lib/ApiInterceptor.ts +++ b/libs/perun/services/src/lib/ApiInterceptor.ts @@ -56,20 +56,23 @@ export class ApiInterceptor implements HttpInterceptor { ) { const config = getDefaultDialogConfig(); config.width = '450px'; + config.id = 'SessionExpirationDialog'; // Skip if the dialog is already open - if (this.dialogRefSessionExpiration == null) { + if (!this.dialogRefSessionExpiration) { this.dialogRefSessionExpiration = this.dialog.open( SessionExpirationDialogComponent, config ); - this.dialogRefSessionExpiration.afterClosed().subscribe(() => { - finalize(() => (this.dialogRefSessionExpiration = undefined)); - sessionStorage.setItem('auth:redirect', location.pathname); - sessionStorage.setItem('auth:queryParams', location.search.substring(1)); - this.dialog.closeAll(); - this.oauthService.logOut(true); - this.reauthenticate(); + this.dialogRefSessionExpiration.afterClosed().subscribe((manuallyClosed: boolean) => { + finalize(() => (this.dialogRefSessionExpiration = null)); + // Only for the case when user closed the dialog manually to authenticate + // it can be automatically closed in other tabs once user refreshes session + if (manuallyClosed) { + this.dialog.closeAll(); + this.oauthService.logOut(true); + this.reauthenticate(); + } }); } } diff --git a/libs/perun/services/src/lib/auth.service.ts b/libs/perun/services/src/lib/auth.service.ts index 1a08af3d2..b53fec0ce 100644 --- a/libs/perun/services/src/lib/auth.service.ts +++ b/libs/perun/services/src/lib/auth.service.ts @@ -33,8 +33,22 @@ export class AuthService { this.filterShortname = String(params['idpFilter']); } }); + + // The storage event of the Window interface fires when a storage area (localStorage) has been modified in the context of another document. + window.addEventListener('storage', this.closeSessionDialogsForOtherTabs); } + closeSessionDialogsForOtherTabs = (event: StorageEvent): void => { + // Check if user authenticated in other tab and if so close the session expiration dialog + if (event.key === 'access_token' && this.oauthService.hasValidAccessToken()) { + this.dialog.openDialogs.forEach((dialog) => { + if (dialog.id === 'SessionExpirationDialog') { + dialog.close(); + } + }); + } + }; + loadOidcConfigData(): void { this.oauthService.configure(this.getClientConfig()); }