chore: deps update (#11968)

# Which Problems Are Solved
This pr updates major and minor dependencies and is the first step on
getting our dependabot alerts cut down.

# How the Problems Are Solved

Depedency updates across the board eg:
- Upgrade Angular to v21
- Upgrade next.js to v16.2
- Upgrade tailwind to v4 in the login
- Upgrade vitest to v4 in the login

This is an uncompleted list refer to the changed files for a full
overview of all the updates.

# Additional Changes

Migrated all control flow in the console to the modern control flow
syntax.
Fixed the dependsOn setting for the @zitadel/login:test-unit nx target.

# Additional Context

- Closes https://github.com/zitadel/zitadel/issues/11274

---------

Co-authored-by: Max Peintner <[email protected]>
This commit is contained in:
Ramon
2026-04-02 15:53:08 +02:00
committed by GitHub
co-authored by Max Peintner
parent 891c7473ca
commit 0945195f68
241 changed files with 15156 additions and 14966 deletions
+43 -44
View File
@@ -13,78 +13,77 @@
},
"private": true,
"dependencies": {
"@angular/animations": "^20.3.16",
"@angular/cdk": "^20.2.14",
"@angular/common": "^20.3.16",
"@angular/compiler": "^20.3.16",
"@angular/core": "^20.3.16",
"@angular/forms": "^20.3.16",
"@angular/material": "^20.2.14",
"@angular/material-moment-adapter": "^20.2.14",
"@angular/platform-browser": "^20.3.16",
"@angular/platform-browser-dynamic": "^20.3.16",
"@angular/router": "^20.3.16",
"@angular/service-worker": "^20.3.16",
"@angular/animations": "^21.2.6",
"@angular/cdk": "^21.2.4",
"@angular/common": "^21.2.6",
"@angular/compiler": "^21.2.6",
"@angular/core": "^21.2.6",
"@angular/forms": "^21.2.6",
"@angular/material": "^21.2.4",
"@angular/material-moment-adapter": "^21.2.4",
"@angular/platform-browser": "^21.2.6",
"@angular/platform-browser-dynamic": "^21.2.6",
"@angular/router": "^21.2.6",
"@angular/service-worker": "^21.2.6",
"@bufbuild/protobuf": "^2.11.0",
"@connectrpc/connect": "~2.0.4",
"@connectrpc/connect-web": "~2.0.4",
"@ctrl/ngx-codemirror": "^6.1.0",
"@fortawesome/angular-fontawesome": "^3.0.0",
"@fortawesome/fontawesome-svg-core": "^6.7.2",
"@fortawesome/free-brands-svg-icons": "^6.7.2",
"@netlify/build-info": "^10.3.0",
"@ng-icons/core": "^32.5.0",
"@ng-icons/heroicons": "^32.5.0",
"@connectrpc/connect": "^2.1.1",
"@connectrpc/connect-web": "^2.1.1",
"@ctrl/ngx-codemirror": "^7.0.0",
"@fortawesome/angular-fontawesome": "^4.0.0",
"@fortawesome/fontawesome-svg-core": "^7.2.0",
"@fortawesome/free-brands-svg-icons": "^7.2.0",
"@netlify/build-info": "^10.4.0",
"@ng-icons/core": "^33.2.0",
"@ng-icons/heroicons": "^33.2.0",
"@ngx-translate/core": "^17.0.0",
"@tanstack/angular-query-experimental": "^5.90.24",
"@tanstack/angular-query-experimental": "^5.96.1",
"angular-oauth2-oidc": "^20.0.2",
"angularx-qrcode": "^20.0.0",
"angularx-qrcode": "^21.0.5",
"buffer": "^6.0.3",
"codemirror": "^5.65.20",
"codemirror": "^5.65.21",
"file-saver": "^2.0.5",
"flag-icons": "^7.5.0",
"google-protobuf": "~3.21.4",
"grpc-web": "~1.5.0",
"google-protobuf": "^4.0.2",
"grpc-web": "^2.0.2",
"i18n-iso-countries": "^7.14.0",
"libphonenumber-js": "^1.12.35",
"libphonenumber-js": "^1.12.41",
"material-design-icons-iconfont": "^6.7.0",
"moment": "^2.30.1",
"ngx-color": "^9.0.0",
"ngx-color": "^10.1.0",
"opentype.js": "^1.3.4",
"posthog-js": "^1.335.3",
"posthog-js": "^1.364.5",
"rxjs": "^7.8.2",
"tinycolor2": "^1.6.0",
"tslib": "^2.8.1",
"uuid": "^10.0.0",
"uuid": "^13.0.0",
"zone.js": "~0.15.1"
},
"devDependencies": {
"@angular-eslint/eslint-plugin": "21.3.0",
"@angular-eslint/eslint-plugin-template": "21.3.0",
"@angular-eslint/template-parser": "21.3.0",
"@angular/build": "^20.3.15",
"@angular/cli": "^20.3.15",
"@angular/compiler-cli": "^20.3.16",
"@angular/language-service": "^20.3.16",
"@eslint/js": "^10.0.0",
"@angular/build": "^21.2.6",
"@angular/cli": "^21.2.6",
"@angular/compiler-cli": "^21.2.6",
"@angular/language-service": "^21.2.6",
"@eslint/js": "^10.0.1",
"@types/file-saver": "^2.0.7",
"@types/google-protobuf": "~3.15.12",
"@types/google-protobuf": "^3.15.12",
"@types/jasmine": "~5.1.15",
"@types/jasminewd2": "~2.0.13",
"@types/jsonwebtoken": "^9.0.10",
"@types/node": "^22.19.7",
"@types/node": "^25.5.0",
"@types/opentype.js": "^1.3.9",
"@types/qrcode": "^1.5.6",
"@types/uuid": "^10.0.0",
"@typescript-eslint/eslint-plugin": "^8.57.0",
"@typescript-eslint/parser": "^8.57.0",
"@types/uuid": "^11.0.0",
"@typescript-eslint/eslint-plugin": "^8.58.0",
"@typescript-eslint/parser": "^8.58.0",
"@zitadel/client": "workspace:*",
"@zitadel/proto": "workspace:*",
"eslint": "^10.0.0",
"eslint": "^10.1.0",
"eslint-config-prettier": "^10.1.8",
"eslint-import-resolver-typescript": "^4.4.4",
"eslint-plugin-import": "^2.32.0",
"globals": "^17.0.0",
"globals": "^17.4.0",
"jasmine-core": "~5.12.1",
"jasmine-spec-reporter": "~7.0.0",
"karma": "^6.4.4",
@@ -92,7 +91,7 @@
"karma-coverage": "^2.2.1",
"karma-coverage-istanbul-reporter": "^3.0.3",
"karma-jasmine": "^5.1.0",
"karma-jasmine-html-reporter": "^2.1.0",
"karma-jasmine-html-reporter": "^2.2.0",
"prettier": "^3.8.1",
"prettier-plugin-organize-imports": "^4.3.0",
"typescript": "5.9.2"
+2 -3
View File
@@ -1,12 +1,11 @@
<div class="main-container">
<ng-container *ngIf="authService.user | async as user">
@if (authService.user | async; as user) {
<cnsl-header
[org]="activeOrganizationQuery.data()"
[user]="user"
[isDarkTheme]="componentCssClass === 'dark-theme'"
(changedActiveOrg)="changedOrg()"
/>
<cnsl-nav
id="mainnav"
class="nav"
@@ -15,7 +14,7 @@
[user]="user"
[isDarkTheme]="componentCssClass === 'dark-theme'"
></cnsl-nav>
</ng-container>
}
<div class="router-container" [@routeAnimations]="prepareRoute(outlet)">
<div class="outlet">
@@ -1,40 +1,41 @@
<div class="feature-row" *ngIf="toggleState$ | async as toggleState">
<span>{{ 'SETTING.FEATURES.' + (toggleStateKey | uppercase) | translate }}</span>
<div class="row">
<mat-button-toggle-group
class="theme-toggle"
class="buttongroup"
[(ngModel)]="toggleState.enabled"
(change)="toggleChange.emit(toggleState)"
name="displayview"
>
<mat-button-toggle [value]="false">
<div class="toggle-row">
<span>{{ 'SETTING.FEATURES.STATES.DISABLED' | translate }}</span>
<div
*ngIf="!toggleState.enabled && (isInherited$ | async)"
class="current-dot"
matTooltip="{{ 'SETTING.FEATURES.INHERITEDINDICATOR_DESCRIPTION.DISABLED' | translate }}"
></div>
</div>
</mat-button-toggle>
<mat-button-toggle [value]="true">
<div class="toggle-row">
<span>{{ 'SETTING.FEATURES.STATES.ENABLED' | translate }}</span>
<div
*ngIf="toggleState.enabled && (isInherited$ | async)"
class="current-dot"
matTooltip="{{ 'SETTING.FEATURES.INHERITEDINDICATOR_DESCRIPTION.ENABLED' | translate }}"
></div>
</div>
</mat-button-toggle>
</mat-button-toggle-group>
@if (toggleState$ | async; as toggleState) {
<div class="feature-row">
<span>{{ 'SETTING.FEATURES.' + (toggleStateKey | uppercase) | translate }}</span>
<div class="row">
<mat-button-toggle-group
class="theme-toggle"
class="buttongroup"
[(ngModel)]="toggleState.enabled"
(change)="toggleChange.emit(toggleState)"
name="displayview"
>
<mat-button-toggle [value]="false">
<div class="toggle-row">
<span>{{ 'SETTING.FEATURES.STATES.DISABLED' | translate }}</span>
@if (!toggleState.enabled && (isInherited$ | async)) {
<div
class="current-dot"
matTooltip="{{ 'SETTING.FEATURES.INHERITEDINDICATOR_DESCRIPTION.DISABLED' | translate }}"
></div>
}
</div>
</mat-button-toggle>
<mat-button-toggle [value]="true">
<div class="toggle-row">
<span>{{ 'SETTING.FEATURES.STATES.ENABLED' | translate }}</span>
@if (toggleState.enabled && (isInherited$ | async)) {
<div
class="current-dot"
matTooltip="{{ 'SETTING.FEATURES.INHERITEDINDICATOR_DESCRIPTION.ENABLED' | translate }}"
></div>
}
</div>
</mat-button-toggle>
</mat-button-toggle-group>
</div>
<ng-content></ng-content>
@if ('SETTING.FEATURES.' + (toggleStateKey | uppercase) + '_DESCRIPTION' | translate; as i18nDescription) {
<cnsl-info-section class="feature-info">{{ i18nDescription }}</cnsl-info-section>
}
</div>
<ng-content></ng-content>
<cnsl-info-section
class="feature-info"
*ngIf="'SETTING.FEATURES.' + (toggleStateKey | uppercase) + '_DESCRIPTION' | translate as i18nDescription"
>{{ i18nDescription }}</cnsl-info-section
>
</div>
}
@@ -1,4 +1,4 @@
import { AsyncPipe, NgIf, UpperCasePipe } from '@angular/common';
import { AsyncPipe, UpperCasePipe } from '@angular/common';
import { ChangeDetectionStrategy, Component, EventEmitter, Input, Output } from '@angular/core';
import { TranslateModule } from '@ngx-translate/core';
import { MatTooltipModule } from '@angular/material/tooltip';
@@ -23,7 +23,6 @@ import { map } from 'rxjs/operators';
MatTooltipModule,
InfoSectionModule,
AsyncPipe,
NgIf,
],
})
export class FeatureToggleComponent<TKey extends ToggleStateKeys, TValue extends ToggleStates[TKey]> {
@@ -18,15 +18,21 @@
</button>
</ng-template>
<cnsl-card *ngIf="toggleStates$ | async as toggleStates">
<div class="features">
<cnsl-feature-toggle
*ngFor="let key of FEATURE_KEYS"
[toggleStateKey]="key"
[toggleState]="toggleStates[key]"
(toggleChange)="saveFeature(key, $event)"
></cnsl-feature-toggle>
<cnsl-login-v2-feature-toggle [toggleState]="toggleStates.loginV2" (toggleChanged)="saveFeature('loginV2', $event)" />
</div>
</cnsl-card>
@if (toggleStates$ | async; as toggleStates) {
<cnsl-card>
<div class="features">
@for (key of FEATURE_KEYS; track key) {
<cnsl-feature-toggle
[toggleStateKey]="key"
[toggleState]="toggleStates[key]"
(toggleChange)="saveFeature(key, $event)"
></cnsl-feature-toggle>
}
<cnsl-login-v2-feature-toggle
[toggleState]="toggleStates.loginV2"
(toggleChanged)="saveFeature('loginV2', $event)"
/>
</div>
</cnsl-card>
}
</div>
@@ -4,32 +4,40 @@
<input cnslInput type="text" placeholder="" #nameInput [formControl]="myControl" [matAutocomplete]="auto" />
<mat-autocomplete #auto="matAutocomplete" (optionSelected)="selected($event)">
<mat-option *ngIf="isLoading()" class="is-loading">
<mat-spinner diameter="30"></mat-spinner>
</mat-option>
<mat-option *ngFor="let framework of filteredOptions | async" [value]="framework.id">
<div class="framework-option">
<div class="framework-option-column">
<div class="img-wrapper">
<img class="dark-only" *ngIf="framework.imgSrcDark" [src]="framework.imgSrcDark" />
<img class="light-only" *ngIf="framework.imgSrcLight" [src]="framework.imgSrcLight" />
@if (isLoading()) {
<mat-option class="is-loading">
<mat-spinner diameter="30"></mat-spinner>
</mat-option>
}
@for (framework of filteredOptions | async; track framework) {
<mat-option [value]="framework.id">
<div class="framework-option">
<div class="framework-option-column">
<div class="img-wrapper">
@if (framework.imgSrcDark) {
<img class="dark-only" [src]="framework.imgSrcDark" />
}
@if (framework.imgSrcLight) {
<img class="light-only" [src]="framework.imgSrcLight" />
}
</div>
<span class="fill-space"></span>
<span>{{ framework.title }}</span>
</div>
<span class="fill-space"></span>
<span>{{ framework.title }}</span>
</div>
</div>
</mat-option>
<mat-option *ngIf="withCustom" [value]="'other'">
<div class="framework-option">
<div class="framework-option-column">
<div class="img-wrapper"></div>
<span class="fill-space"></span>
<span>{{ 'QUICKSTART.FRAMEWORK_OTHER' | translate }}</span>
</mat-option>
}
@if (withCustom) {
<mat-option [value]="'other'">
<div class="framework-option">
<div class="framework-option-column">
<div class="img-wrapper"></div>
<span class="fill-space"></span>
<span>{{ 'QUICKSTART.FRAMEWORK_OTHER' | translate }}</span>
</div>
</div>
</div>
</mat-option>
</mat-option>
}
</mat-autocomplete>
</cnsl-form-field>
</form>
@@ -1,18 +1,22 @@
<div class="framework-change-wrapper">
<div class="framework-card-wrapper">
<div class="framework-card card" *ngIf="framework | async as framework; else frameworkFallback">
<div>
<img class="dark-only" *ngIf="framework.imgSrcDark" [src]="framework.imgSrcDark" />
<img class="light-only" *ngIf="framework.imgSrcLight" [src]="framework.imgSrcLight" />
@if (framework | async; as framework) {
<div class="framework-card card">
<div>
@if (framework.imgSrcDark) {
<img class="dark-only" [src]="framework.imgSrcDark" />
}
@if (framework.imgSrcLight) {
<img class="light-only" [src]="framework.imgSrcLight" />
}
</div>
<span>{{ framework.title }}</span>
</div>
<span>{{ framework.title }}</span>
</div>
<ng-template #frameworkFallback>
} @else {
<div class="framework-card card">
<span>{{ 'QUICKSTART.SELECT_FRAMEWORK' | translate }}</span>
</div>
</ng-template>
}
<button (click)="openDialog()" mat-stroked-button>
{{ 'ACTIONS.CHANGE' | translate }}
@@ -21,23 +21,35 @@
<span class="left cnsl-secondary-text">
{{ 'APP.GRANT' | translate }}
</span>
<span class="right" *ngIf="configuration.grantTypesList && configuration.grantTypesList.length > 0">
[<span *ngFor="let element of configuration.grantTypesList ?? []; index as i">
{{ 'APP.OIDC.GRANT.' + element | translate }}
{{ i < configuration.grantTypesList.length - 1 ? ', ' : '' }} </span
>]
</span>
@if (configuration.grantTypesList && configuration.grantTypesList.length > 0) {
<span class="right">
[
@for (element of configuration.grantTypesList ?? []; track element; let i = $index) {
<span>
{{ 'APP.OIDC.GRANT.' + element | translate }}
{{ i < configuration.grantTypesList.length - 1 ? ', ' : '' }}
</span>
}
]
</span>
}
</div>
<div class="row">
<span class="left cnsl-secondary-text">
{{ 'APP.OIDC.RESPONSETYPE' | translate }}
</span>
<span class="right" *ngIf="configuration.responseTypesList && configuration.responseTypesList.length > 0">
[<span *ngFor="let element of configuration.responseTypesList ?? []; index as i">
{{ 'APP.OIDC.RESPONSE.' + element | translate }}
{{ i < configuration.responseTypesList.length - 1 ? ', ' : '' }} </span
>]
</span>
@if (configuration.responseTypesList && configuration.responseTypesList.length > 0) {
<span class="right">
[
@for (element of configuration.responseTypesList ?? []; track element; let i = $index) {
<span>
{{ 'APP.OIDC.RESPONSE.' + element | translate }}
{{ i < configuration.responseTypesList.length - 1 ? ', ' : '' }}
</span>
}
]
</span>
}
</div>
<div class="row">
@@ -1,4 +1,3 @@
import { CommonModule } from '@angular/common';
import { Component, EventEmitter, Input, Output } from '@angular/core';
import { RouterModule } from '@angular/router';
import { TranslateModule } from '@ngx-translate/core';
@@ -25,7 +24,7 @@ export type Framework = FrameworkDefinition & {
selector: 'cnsl-oidc-app-configuration',
templateUrl: './oidc-configuration.component.html',
styleUrls: ['./oidc-configuration.component.scss'],
imports: [TranslateModule, RouterModule, CommonModule, MatButtonModule],
imports: [TranslateModule, RouterModule, MatButtonModule],
})
export class OIDCConfigurationComponent {
@Input() public name?: string;
@@ -13,11 +13,15 @@
</div>
</div>
<div class="quickstart-card-wrapper">
<ng-container *ngFor="let framework of frameworks.slice(0, 18)">
@for (framework of frameworks.slice(0, 18); track framework) {
<a [routerLink]="['/projects', 'app-create']" [queryParams]="{ framework: framework.id }" class="quickstart-card card">
<img class="dark-only" *ngIf="framework.imgSrcDark" [src]="framework.imgSrcDark" alt="{{ framework.title }}" />
<img class="light-only" *ngIf="framework.imgSrcLight" [src]="framework.imgSrcLight" alt="{{ framework.title }}" />
@if (framework.imgSrcDark) {
<img class="dark-only" [src]="framework.imgSrcDark" alt="{{ framework.title }}" />
}
@if (framework.imgSrcLight) {
<img class="light-only" [src]="framework.imgSrcLight" alt="{{ framework.title }}" />
}
</a>
</ng-container>
}
</div>
</div>
@@ -1,4 +1,3 @@
import { CommonModule } from '@angular/common';
import { Component } from '@angular/core';
import { RouterModule } from '@angular/router';
import { TranslateModule } from '@ngx-translate/core';
@@ -27,7 +26,7 @@ export type Framework = FrameworkDefinition & {
selector: 'cnsl-quickstart',
templateUrl: './quickstart.component.html',
styleUrls: ['./quickstart.component.scss'],
imports: [TranslateModule, RouterModule, CommonModule, MatButtonModule],
imports: [TranslateModule, RouterModule, MatButtonModule],
})
export class QuickstartComponent {
public frameworks: FrameworkDefinition[] = frameworkDefinition
@@ -1,51 +1,56 @@
<div class="accounts-card" *ngIf="user$ | async as user">
<cnsl-avatar
(click)="editUserProfile()"
class="avatar"
[ngClass]="{ 'iam-user': iamuser }"
[forColor]="user.preferredLoginName"
[avatarUrl]="user.human?.profile?.avatarUrl || ''"
[name]="user.human?.profile?.displayName ?? ''"
[size]="80"
>
</cnsl-avatar>
<span class="u-name">{{ user?.human?.profile?.displayName ? user?.human?.profile?.displayName : 'A' }}</span>
<span class="u-email" *ngIf="user?.preferredLoginName">{{ user?.preferredLoginName }}</span>
<button (click)="editUserProfile()" mat-stroked-button>{{ 'USER.EDITACCOUNT' | translate }}</button>
<div class="l-accounts">
<mat-progress-bar *ngIf="(sessions$ | async) === null" color="primary" mode="indeterminate"></mat-progress-bar>
<a class="row" *ngFor="let session of sessions$ | async" (click)="selectAccount(session.loginName)">
<cnsl-avatar
*ngIf="session && session.displayName"
class="small-avatar"
[avatarUrl]="session.avatarUrl || ''"
[name]="session.displayName"
[forColor]="session.loginName"
[size]="32"
>
</cnsl-avatar>
<div class="col">
<span class="user-title">{{ session.displayName ? session.displayName : session.userName }} </span>
<span class="loginname">{{ session.loginName }}</span>
<span class="state inactive" *ngIf="$any(session.authState) === UserState.USER_STATE_INACTIVE">{{
'USER.STATE.' + session.authState | translate
}}</span>
</div>
<mat-icon>keyboard_arrow_right</mat-icon>
</a>
<a class="row" (click)="selectNewAccount()">
<div class="icon-wrapper">
<i class="las la-user-plus"></i>
</div>
<span class="col">
<span class="user-title">{{ 'USER.ADDACCOUNT' | translate }}</span>
</span>
<mat-icon>keyboard_arrow_right</mat-icon>
</a>
@if (user$ | async; as user) {
<div class="accounts-card">
<cnsl-avatar
(click)="editUserProfile()"
class="avatar"
[ngClass]="{ 'iam-user': iamuser }"
[forColor]="user.preferredLoginName"
[avatarUrl]="user.human?.profile?.avatarUrl || ''"
[name]="user.human?.profile?.displayName ?? ''"
[size]="80"
>
</cnsl-avatar>
<span class="u-name">{{ user?.human?.profile?.displayName ? user?.human?.profile?.displayName : 'A' }}</span>
@if (user?.preferredLoginName) {
<span class="u-email">{{ user?.preferredLoginName }}</span>
}
<button (click)="editUserProfile()" mat-stroked-button>{{ 'USER.EDITACCOUNT' | translate }}</button>
<div class="l-accounts">
@if ((sessions$ | async) === null) {
<mat-progress-bar color="primary" mode="indeterminate"></mat-progress-bar>
}
@for (session of sessions$ | async; track session) {
<a class="row" (click)="selectAccount(session.loginName)">
@if (session && session.displayName) {
<cnsl-avatar
class="small-avatar"
[avatarUrl]="session.avatarUrl || ''"
[name]="session.displayName"
[forColor]="session.loginName"
[size]="32"
>
</cnsl-avatar>
}
<div class="col">
<span class="user-title">{{ session.displayName ? session.displayName : session.userName }} </span>
<span class="loginname">{{ session.loginName }}</span>
@if ($any(session.authState) === UserState.USER_STATE_INACTIVE) {
<span class="state inactive">{{ 'USER.STATE.' + session.authState | translate }}</span>
}
</div>
<mat-icon>keyboard_arrow_right</mat-icon>
</a>
}
<a class="row" (click)="selectNewAccount()">
<div class="icon-wrapper">
<i class="las la-user-plus"></i>
</div>
<span class="col">
<span class="user-title">{{ 'USER.ADDACCOUNT' | translate }}</span>
</span>
<mat-icon>keyboard_arrow_right</mat-icon>
</a>
</div>
<button (click)="logout()" color="warn" mat-stroked-button>{{ 'MENU.LOGOUT' | translate }}</button>
</div>
<button (click)="logout()" color="warn" mat-stroked-button>{{ 'MENU.LOGOUT' | translate }}</button>
</div>
}
@@ -1,62 +1,81 @@
<div
*ngIf="type !== ActionKeysType.ORGSWITCHER && (isHandset$ | async) === false"
class="action-keys-wrapper"
[ngSwitch]="type"
[ngClass]="{ 'without-margin': withoutMargin, 'no-contrast-mode': doNotUseContrast }"
>
<div *ngSwitchCase="ActionKeysType.CLEAR" class="action-keys-row">
<div class="action-key esc">
<div class="key-overlay"></div>
<span>ESC</span>
</div>
@if (type !== ActionKeysType.ORGSWITCHER && (isHandset$ | async) === false) {
<div class="action-keys-wrapper" [ngClass]="{ 'without-margin': withoutMargin, 'no-contrast-mode': doNotUseContrast }">
@switch (type) {
@case (ActionKeysType.CLEAR) {
<div class="action-keys-row">
<div class="action-key esc">
<div class="key-overlay"></div>
<span>ESC</span>
</div>
</div>
}
@case (ActionKeysType.ADD) {
<div class="action-keys-row" data-e2e="action-key-add">
<div class="action-key">
<div class="key-overlay"></div>
<span>N</span>
</div>
</div>
}
@case (ActionKeysType.DELETE) {
<div class="action-keys-row">
<div class="action-key">
<div class="key-overlay"></div>
@if (isMacLike || isIOS) {
<span>⌘</span>
} @else {
<span>crtl</span>
}
</div>
+
<div class="action-key">
<div class="key-overlay"></div>
<span>BS</span>
</div>
</div>
}
@case (ActionKeysType.DEACTIVATE) {
<div class="action-keys-row">
<div class="action-key">
<div class="key-overlay"></div>
@if (isMacLike || isIOS) {
<span>⌘</span>
} @else {
<span>crtl</span>
}
</div>
+
<div class="action-key">
<div class="key-overlay"></div>
<span>↓</span>
</div>
</div>
}
@case (ActionKeysType.REACTIVATE) {
<div class="action-keys-row">
<div class="action-key">
<div class="key-overlay"></div>
@if (isMacLike || isIOS) {
<span>⌘</span>
} @else {
<span>crtl</span>
}
</div>
+
<div class="action-key">
<div class="key-overlay"></div>
<span>↑</span>
</div>
</div>
}
@case (ActionKeysType.FILTER) {
<div class="action-keys-row">
<div class="action-key">
<div class="key-overlay"></div>
<span>F</span>
</div>
</div>
}
}
</div>
<div *ngSwitchCase="ActionKeysType.ADD" class="action-keys-row" data-e2e="action-key-add">
<div class="action-key">
<div class="key-overlay"></div>
<span>N</span>
</div>
</div>
<div *ngSwitchCase="ActionKeysType.DELETE" class="action-keys-row">
<div class="action-key">
<div class="key-overlay"></div>
<span *ngIf="isMacLike || isIOS; else otherOS">⌘</span>
</div>
+
<div class="action-key">
<div class="key-overlay"></div>
<span>BS</span>
</div>
</div>
<div *ngSwitchCase="ActionKeysType.DEACTIVATE" class="action-keys-row">
<div class="action-key">
<div class="key-overlay"></div>
<span *ngIf="isMacLike || isIOS; else otherOS">⌘</span>
</div>
+
<div class="action-key">
<div class="key-overlay"></div>
<span>↓</span>
</div>
</div>
<div *ngSwitchCase="ActionKeysType.REACTIVATE" class="action-keys-row">
<div class="action-key">
<div class="key-overlay"></div>
<span *ngIf="isMacLike || isIOS; else otherOS">⌘</span>
</div>
+
<div class="action-key">
<div class="key-overlay"></div>
<span>↑</span>
</div>
</div>
<div *ngSwitchCase="ActionKeysType.FILTER" class="action-keys-row">
<div class="action-key">
<div class="key-overlay"></div>
<span>F</span>
</div>
</div>
</div>
<ng-template #otherOS>
<span>crtl</span>
</ng-template>
}
@@ -24,9 +24,11 @@
<th mat-header-cell *matHeaderCellDef>{{ 'ACTIONSTWO.EXECUTION.TABLE.TARGET' | translate }}</th>
<td mat-cell *cnslCellDef="let row; dataSource: dataSource">
<div class="target-key">
<cnsl-project-role-chip *ngFor="let target of row.mappedTargets; trackBy: trackTarget" [roleName]="target.name">
{{ target.name }}
</cnsl-project-role-chip>
@for (target of row.mappedTargets; track trackTarget($index, target)) {
<cnsl-project-role-chip [roleName]="target.name">
{{ target.name }}
</cnsl-project-role-chip>
}
</div>
</td>
</ng-container>
@@ -3,12 +3,16 @@
<input #input cnslInput type="text" placeholder="" [formControl]="control" [matAutocomplete]="autocomplete" />
<mat-autocomplete requireSelection #autocomplete="matAutocomplete">
<mat-option *ngIf="items === undefined" class="is-loading">
<mat-spinner diameter="30"></mat-spinner>
</mat-option>
<mat-option *ngFor="let item of items | filter: input | async" [value]="item">
<span>{{ item }}</span>
</mat-option>
@if (items === undefined) {
<mat-option class="is-loading">
<mat-spinner diameter="30"></mat-spinner>
</mat-option>
}
@for (item of items | filter: input | async; track item) {
<mat-option [value]="item">
<span>{{ item }}</span>
</mat-option>
}
</mat-autocomplete>
<ng-content></ng-content>
@@ -1,5 +1,5 @@
import { ChangeDetectionStrategy, Component, Input, Pipe, PipeTransform } from '@angular/core';
import { AsyncPipe, NgForOf, NgIf } from '@angular/common';
import { AsyncPipe } from '@angular/common';
import { FormFieldModule } from 'src/app/modules/form-field/form-field.module';
import { InputModule } from 'src/app/modules/input/input.module';
import { LabelModule } from 'src/app/modules/label/label.module';
@@ -39,8 +39,6 @@ class Filter implements PipeTransform {
MatOptionModule,
MatProgressSpinnerModule,
TranslateModule,
NgIf,
NgForOf,
ReactiveFormsModule,
],
})
@@ -1,79 +1,70 @@
<form *ngIf="form$ | async as form" [formGroup]="form.form" class="form-grid" (ngSubmit)="submit(form)">
<ng-container *ngIf="form.case === 'request' || form.case === 'response'">
<p class="cnsl-secondary-text">{{ 'ACTIONSTWO.EXECUTION.DIALOG.CONDITION.REQ_RESP_DESCRIPTION' | translate }}</p>
<div class="emailVerified">
<mat-checkbox [formControl]="form.form.controls.all">
<div class="execution-condition-text">
<span>{{ 'ACTIONSTWO.EXECUTION.DIALOG.CONDITION.ALL.TITLE' | translate }}</span>
<span class="description cnsl-secondary-text">{{
'ACTIONSTWO.EXECUTION.DIALOG.CONDITION.ALL.DESCRIPTION' | translate
}}</span>
</div>
</mat-checkbox>
@if (form$ | async; as form) {
<form [formGroup]="form.form" class="form-grid" (ngSubmit)="submit(form)">
@if (form.case === 'request' || form.case === 'response') {
<p class="cnsl-secondary-text">{{ 'ACTIONSTWO.EXECUTION.DIALOG.CONDITION.REQ_RESP_DESCRIPTION' | translate }}</p>
<div class="emailVerified">
<mat-checkbox [formControl]="form.form.controls.all">
<div class="execution-condition-text">
<span>{{ 'ACTIONSTWO.EXECUTION.DIALOG.CONDITION.ALL.TITLE' | translate }}</span>
<span class="description cnsl-secondary-text">{{
'ACTIONSTWO.EXECUTION.DIALOG.CONDITION.ALL.DESCRIPTION' | translate
}}</span>
</div>
</mat-checkbox>
</div>
<p class="condition-description">{{ 'ACTIONSTWO.EXECUTION.DIALOG.CONDITION.SELECT_SERVICE.TITLE' | translate }}</p>
<cnsl-actions-two-add-action-autocomplete-input
label="ACTIONSTWO.EXECUTION.DIALOG.CONDITION.SELECT_SERVICE.DESCRIPTION"
[items]="listExecutionServicesQuery.data()"
[control]="form.form.controls.service"
></cnsl-actions-two-add-action-autocomplete-input>
<p class="condition-description">{{ 'ACTIONSTWO.EXECUTION.DIALOG.CONDITION.SELECT_METHOD.TITLE' | translate }}</p>
<cnsl-actions-two-add-action-autocomplete-input
label="ACTIONSTWO.EXECUTION.DIALOG.CONDITION.SELECT_METHOD.DESCRIPTION"
[items]="filteredExecutionMethods()"
[control]="form.form.controls.method"
></cnsl-actions-two-add-action-autocomplete-input>
}
@if (form.case === 'function') {
<cnsl-actions-two-add-action-autocomplete-input
label="ACTIONSTWO.EXECUTION.DIALOG.CONDITION.FUNCTIONNAME.TITLE"
[items]="listExecutionFunctionsQuery.data()"
[control]="form.form.controls.name"
>
<span class="name-hint cnsl-secondary-text" cnslHint>{{
'ACTIONSTWO.EXECUTION.DIALOG.CONDITION.FUNCTIONNAME.DESCRIPTION' | translate
}}</span>
</cnsl-actions-two-add-action-autocomplete-input>
}
@if (form.case === 'event') {
<div class="emailVerified">
<mat-checkbox [formControl]="form.form.controls.all">
<div class="execution-condition-text">
<span>{{ 'ACTIONSTWO.EXECUTION.DIALOG.CONDITION.ALL.TITLE' | translate }}</span>
<span class="description cnsl-secondary-text">{{
'ACTIONSTWO.EXECUTION.DIALOG.CONDITION.ALL_EVENTS' | translate
}}</span>
</div>
</mat-checkbox>
</div>
<p class="condition-description">{{ 'ACTIONSTWO.EXECUTION.DIALOG.CONDITION.SELECT_GROUP.TITLE' | translate }}</p>
<cnsl-form-field class="full-width">
<cnsl-label>{{ 'ACTIONSTWO.EXECUTION.DIALOG.CONDITION.SELECT_GROUP.DESCRIPTION' | translate }}</cnsl-label>
<input cnslInput type="text" placeholder="" [formControl]="form.form.controls.group" />
</cnsl-form-field>
<p class="condition-description">{{ 'ACTIONSTWO.EXECUTION.DIALOG.CONDITION.SELECT_EVENT.TITLE' | translate }}</p>
<cnsl-form-field class="full-width">
<cnsl-label>{{ 'ACTIONSTWO.EXECUTION.DIALOG.CONDITION.SELECT_EVENT.DESCRIPTION' | translate }}</cnsl-label>
<input cnslInput type="text" placeholder="" [formControl]="form.form.controls.event" />
</cnsl-form-field>
}
<div class="actions">
<button mat-stroked-button (click)="back.emit()">
{{ 'ACTIONS.BACK' | translate }}
</button>
<button [disabled]="form.form.invalid" color="primary" mat-raised-button type="submit">
{{ 'ACTIONS.CONTINUE' | translate }}
</button>
</div>
<p class="condition-description">{{ 'ACTIONSTWO.EXECUTION.DIALOG.CONDITION.SELECT_SERVICE.TITLE' | translate }}</p>
<cnsl-actions-two-add-action-autocomplete-input
label="ACTIONSTWO.EXECUTION.DIALOG.CONDITION.SELECT_SERVICE.DESCRIPTION"
[items]="listExecutionServicesQuery.data()"
[control]="form.form.controls.service"
></cnsl-actions-two-add-action-autocomplete-input>
<p class="condition-description">{{ 'ACTIONSTWO.EXECUTION.DIALOG.CONDITION.SELECT_METHOD.TITLE' | translate }}</p>
<cnsl-actions-two-add-action-autocomplete-input
label="ACTIONSTWO.EXECUTION.DIALOG.CONDITION.SELECT_METHOD.DESCRIPTION"
[items]="filteredExecutionMethods()"
[control]="form.form.controls.method"
></cnsl-actions-two-add-action-autocomplete-input>
</ng-container>
<ng-container *ngIf="form.case === 'function'">
<cnsl-actions-two-add-action-autocomplete-input
label="ACTIONSTWO.EXECUTION.DIALOG.CONDITION.FUNCTIONNAME.TITLE"
[items]="listExecutionFunctionsQuery.data()"
[control]="form.form.controls.name"
>
<span class="name-hint cnsl-secondary-text" cnslHint>{{
'ACTIONSTWO.EXECUTION.DIALOG.CONDITION.FUNCTIONNAME.DESCRIPTION' | translate
}}</span>
</cnsl-actions-two-add-action-autocomplete-input>
</ng-container>
<ng-container *ngIf="form.case === 'event'">
<div class="emailVerified">
<mat-checkbox [formControl]="form.form.controls.all">
<div class="execution-condition-text">
<span>{{ 'ACTIONSTWO.EXECUTION.DIALOG.CONDITION.ALL.TITLE' | translate }}</span>
<span class="description cnsl-secondary-text">{{
'ACTIONSTWO.EXECUTION.DIALOG.CONDITION.ALL_EVENTS' | translate
}}</span>
</div>
</mat-checkbox>
</div>
<p class="condition-description">{{ 'ACTIONSTWO.EXECUTION.DIALOG.CONDITION.SELECT_GROUP.TITLE' | translate }}</p>
<cnsl-form-field class="full-width">
<cnsl-label>{{ 'ACTIONSTWO.EXECUTION.DIALOG.CONDITION.SELECT_GROUP.DESCRIPTION' | translate }}</cnsl-label>
<input cnslInput type="text" placeholder="" [formControl]="form.form.controls.group" />
</cnsl-form-field>
<p class="condition-description">{{ 'ACTIONSTWO.EXECUTION.DIALOG.CONDITION.SELECT_EVENT.TITLE' | translate }}</p>
<cnsl-form-field class="full-width">
<cnsl-label>{{ 'ACTIONSTWO.EXECUTION.DIALOG.CONDITION.SELECT_EVENT.DESCRIPTION' | translate }}</cnsl-label>
<input cnslInput type="text" placeholder="" [formControl]="form.form.controls.event" />
</cnsl-form-field>
</ng-container>
<div class="actions">
<button mat-stroked-button (click)="back.emit()">
{{ 'ACTIONS.BACK' | translate }}
</button>
<button [disabled]="form.form.invalid" color="primary" mat-raised-button type="submit">
{{ 'ACTIONS.CONTINUE' | translate }}
</button>
</div>
</form>
</form>
}
@@ -1,28 +1,35 @@
<h2 *ngIf="!data.execution" mat-dialog-title>{{ 'ACTIONSTWO.EXECUTION.DIALOG.CREATE_TITLE' | translate }}</h2>
<h2 *ngIf="data.execution" mat-dialog-title>{{ 'ACTIONSTWO.EXECUTION.DIALOG.UPDATE_TITLE' | translate }}</h2>
@if (!data.execution) {
<h2 mat-dialog-title>{{ 'ACTIONSTWO.EXECUTION.DIALOG.CREATE_TITLE' | translate }}</h2>
}
@if (data.execution) {
<h2 mat-dialog-title>{{ 'ACTIONSTWO.EXECUTION.DIALOG.UPDATE_TITLE' | translate }}</h2>
}
<mat-dialog-content>
<div class="framework-change-block" [ngSwitch]="page()">
<cnsl-actions-two-add-action-type
*ngSwitchCase="Page.Type"
[initialValue]="typeSignal()"
(back)="back()"
(continue)="typeSignal.set($event); continue()"
></cnsl-actions-two-add-action-type>
<cnsl-actions-two-add-action-condition
*ngSwitchCase="Page.Condition"
[conditionType]="typeSignal()"
(back)="back()"
(continue)="conditionSignal.set({ conditionType: { case: typeSignal(), value: $event } }); continue()"
></cnsl-actions-two-add-action-condition>
<cnsl-actions-two-add-action-target
*ngSwitchCase="Page.Target"
(back)="back()"
[hideBackButton]="!!data.execution"
(continue)="targetsSignal.set($event); continue()"
[preselectedTargetIds]="preselectedTargetIds"
></cnsl-actions-two-add-action-target>
<div class="framework-change-block">
@switch (page()) {
@case (Page.Type) {
<cnsl-actions-two-add-action-type
[initialValue]="typeSignal()"
(back)="back()"
(continue)="typeSignal.set($event); continue()"
></cnsl-actions-two-add-action-type>
}
@case (Page.Condition) {
<cnsl-actions-two-add-action-condition
[conditionType]="typeSignal()"
(back)="back()"
(continue)="conditionSignal.set({ conditionType: { case: typeSignal(), value: $event } }); continue()"
></cnsl-actions-two-add-action-condition>
}
@case (Page.Target) {
<cnsl-actions-two-add-action-target
(back)="back()"
[hideBackButton]="!!data.execution"
(continue)="targetsSignal.set($event); continue()"
[preselectedTargetIds]="preselectedTargetIds"
></cnsl-actions-two-add-action-target>
}
}
</div>
</mat-dialog-content>
@@ -9,7 +9,7 @@ import {
ConditionType,
} from './actions-two-add-action-condition/actions-two-add-action-condition.component';
import { ActionsTwoAddActionTargetComponent } from './actions-two-add-action-target/actions-two-add-action-target.component';
import { CommonModule } from '@angular/common';
import { Condition, Execution } from '@zitadel/proto/zitadel/action/v2/execution_pb';
import { Subject } from 'rxjs';
import { SetExecutionRequestSchema } from '@zitadel/proto/zitadel/action/v2/action_service_pb';
@@ -54,7 +54,6 @@ export type ActionTwoAddActionDialogResult = MessageInitShape<typeof SetExecutio
templateUrl: './actions-two-add-action-dialog.component.html',
styleUrls: ['./actions-two-add-action-dialog.component.scss'],
imports: [
CommonModule,
MatButtonModule,
MatDialogModule,
TranslateModule,
@@ -1,72 +1,72 @@
<form *ngIf="form$ | async as form" class="form-grid" [formGroup]="form" (ngSubmit)="submit()">
<p class="target-description">{{ 'ACTIONSTWO.EXECUTION.DIALOG.TARGET.DESCRIPTION' | translate }}</p>
<cnsl-form-field class="full-width">
<cnsl-label>{{ 'ACTIONSTWO.EXECUTION.DIALOG.TARGET.TARGET.DESCRIPTION' | translate }}</cnsl-label>
<input
cnslInput
#trigger="matAutocompleteTrigger"
#input
type="text"
[formControl]="form.controls.autocomplete"
[matAutocomplete]="autoservice"
(keydown.enter)="handleEnter($event, form); input.blur(); trigger.closePanel()"
/>
<mat-autocomplete #autoservice="matAutocomplete">
<mat-option *ngIf="targets().state === 'loading'" class="is-loading">
<mat-spinner diameter="30"></mat-spinner>
</mat-option>
<mat-option
*ngFor="let target of selectableTargets(); trackBy: trackTarget"
#option
(click)="addTarget(target, form); option.deselect()"
[value]="target.name"
>
{{ target.name }}
</mat-option>
</mat-autocomplete>
</cnsl-form-field>
<table mat-table cdkDropList (cdkDropListDropped)="drop($event, form)" [dataSource]="dataSource" [trackBy]="trackTarget">
<ng-container matColumnDef="order">
<th mat-header-cell *matHeaderCellDef>Reorder</th>
<td mat-cell *cnslCellDef="let row; let i = index; dataSource: dataSource">
<i class="las la-bars"></i>
</td>
</ng-container>
<ng-container matColumnDef="name">
<th mat-header-cell *matHeaderCellDef>Name</th>
<td mat-cell *cnslCellDef="let row; dataSource: dataSource">
<cnsl-project-role-chip [roleName]="row.name">{{ row.name }}</cnsl-project-role-chip>
</td>
</ng-container>
<ng-container matColumnDef="deleteAction" stickyEnd>
<th mat-header-cell *matHeaderCellDef></th>
<td mat-cell *cnslCellDef="let i = index; dataSource: dataSource">
<cnsl-table-actions>
<button
actions
matTooltip="{{ 'ACTIONS.REMOVE' | translate }}"
color="warn"
(click)="removeTarget(i, form)"
mat-icon-button
>
<i class="las la-trash"></i>
</button>
</cnsl-table-actions>
</td>
</ng-container>
<tr mat-header-row *matHeaderRowDef="['order', 'name', 'deleteAction']"></tr>
<tr class="drag-row" cdkDrag mat-row *matRowDef="let row; columns: ['order', 'name', 'deleteAction']"></tr>
</table>
<div class="actions">
<button *ngIf="!hideBackButton" mat-stroked-button (click)="back.emit()">
{{ 'ACTIONS.BACK' | translate }}
</button>
<span class="fill-space"></span>
<button color="primary" [disabled]="form.invalid" mat-raised-button type="submit">
{{ 'ACTIONS.CONTINUE' | translate }}
</button>
</div>
</form>
@if (form$ | async; as form) {
<form class="form-grid" [formGroup]="form" (ngSubmit)="submit()">
<p class="target-description">{{ 'ACTIONSTWO.EXECUTION.DIALOG.TARGET.DESCRIPTION' | translate }}</p>
<cnsl-form-field class="full-width">
<cnsl-label>{{ 'ACTIONSTWO.EXECUTION.DIALOG.TARGET.TARGET.DESCRIPTION' | translate }}</cnsl-label>
<input
cnslInput
#trigger="matAutocompleteTrigger"
#input
type="text"
[formControl]="form.controls.autocomplete"
[matAutocomplete]="autoservice"
(keydown.enter)="handleEnter($event, form); input.blur(); trigger.closePanel()"
/>
<mat-autocomplete #autoservice="matAutocomplete">
@if (targets().state === 'loading') {
<mat-option class="is-loading">
<mat-spinner diameter="30"></mat-spinner>
</mat-option>
}
@for (target of selectableTargets(); track trackTarget($index, target)) {
<mat-option #option (click)="addTarget(target, form); option.deselect()" [value]="target.name">
{{ target.name }}
</mat-option>
}
</mat-autocomplete>
</cnsl-form-field>
<table mat-table cdkDropList (cdkDropListDropped)="drop($event, form)" [dataSource]="dataSource" [trackBy]="trackTarget">
<ng-container matColumnDef="order">
<th mat-header-cell *matHeaderCellDef>Reorder</th>
<td mat-cell *cnslCellDef="let row; let i = index; dataSource: dataSource">
<i class="las la-bars"></i>
</td>
</ng-container>
<ng-container matColumnDef="name">
<th mat-header-cell *matHeaderCellDef>Name</th>
<td mat-cell *cnslCellDef="let row; dataSource: dataSource">
<cnsl-project-role-chip [roleName]="row.name">{{ row.name }}</cnsl-project-role-chip>
</td>
</ng-container>
<ng-container matColumnDef="deleteAction" stickyEnd>
<th mat-header-cell *matHeaderCellDef></th>
<td mat-cell *cnslCellDef="let i = index; dataSource: dataSource">
<cnsl-table-actions>
<button
actions
matTooltip="{{ 'ACTIONS.REMOVE' | translate }}"
color="warn"
(click)="removeTarget(i, form)"
mat-icon-button
>
<i class="las la-trash"></i>
</button>
</cnsl-table-actions>
</td>
</ng-container>
<tr mat-header-row *matHeaderRowDef="['order', 'name', 'deleteAction']"></tr>
<tr class="drag-row" cdkDrag mat-row *matRowDef="let row; columns: ['order', 'name', 'deleteAction']"></tr>
</table>
<div class="actions">
@if (!hideBackButton) {
<button mat-stroked-button (click)="back.emit()">
{{ 'ACTIONS.BACK' | translate }}
</button>
}
<span class="fill-space"></span>
<button color="primary" [disabled]="form.invalid" mat-raised-button type="submit">
{{ 'ACTIONS.CONTINUE' | translate }}
</button>
</div>
</form>
}
@@ -1,4 +1,3 @@
import { CommonModule } from '@angular/common';
import { ChangeDetectionStrategy, Component, EventEmitter, Input, OnInit, Output, signal } from '@angular/core';
import { RouterModule } from '@angular/router';
import { TranslateModule } from '@ngx-translate/core';
@@ -20,7 +19,7 @@ import { ConditionType } from '../actions-two-add-action-condition/actions-two-a
selector: 'cnsl-actions-two-add-action-type',
templateUrl: './actions-two-add-action-type.component.html',
styleUrls: ['./actions-two-add-action-type.component.scss'],
imports: [TranslateModule, MatRadioModule, RouterModule, ReactiveFormsModule, FormsModule, CommonModule, MatButtonModule],
imports: [TranslateModule, MatRadioModule, RouterModule, ReactiveFormsModule, FormsModule, MatButtonModule],
})
export class ActionsTwoAddActionTypeComponent {
protected readonly typeForm: ReturnType<typeof this.buildActionTypeForm> = this.buildActionTypeForm();
@@ -2,71 +2,70 @@
<mat-dialog-content>
<p class="target-description">{{ 'ACTIONSTWO.TARGET.CREATE.DESCRIPTION' | translate }}</p>
<form *ngIf="targetForm" class="form-grid" [formGroup]="targetForm" (ngSubmit)="closeWithResult()">
<cnsl-form-field class="full-width">
<cnsl-label>{{ 'ACTIONSTWO.TARGET.CREATE.NAME' | translate }}</cnsl-label>
<input cnslInput type="text" placeholder="" formControlName="name" />
<span class="name-hint cnsl-secondary-text" cnslHint>{{
'ACTIONSTWO.TARGET.CREATE.NAME_DESCRIPTION' | translate
}}</span>
</cnsl-form-field>
<cnsl-form-field class="full-width">
<cnsl-label>{{ 'ACTIONSTWO.TARGET.CREATE.ENDPOINT' | translate }}</cnsl-label>
<input cnslInput type="text" placeholder="" formControlName="endpoint" />
<span class="name-hint cnsl-secondary-text" cnslHint>{{
'ACTIONSTWO.TARGET.CREATE.ENDPOINT_DESCRIPTION' | translate
}}</span>
</cnsl-form-field>
<cnsl-form-field class="full-width">
<cnsl-label>{{ 'ACTIONSTWO.TARGET.CREATE.TYPE' | translate }}</cnsl-label>
<mat-select [formControl]="targetForm.controls.type" name="type">
<mat-option *ngFor="let type of targetTypes" [value]="type">
{{ 'ACTIONSTWO.TARGET.CREATE.TYPES.' + type | translate }}
</mat-option>
</mat-select>
<span class="name-hint cnsl-secondary-text types-description">
{{ 'ACTIONSTWO.TARGET.CREATE.TYPES_DESCRIPTION' | translate }}
</span>
</cnsl-form-field>
<cnsl-form-field class="full-width">
<cnsl-label>{{ 'ACTIONSTWO.TARGET.CREATE.PAYLOAD_TYPE' | translate }}</cnsl-label>
<mat-select [formControl]="targetForm.controls.payloadType" name="payloadType">
<mat-option *ngFor="let type of payloadTypes" [value]="type">
{{ 'ACTIONSTWO.TARGET.CREATE.PAYLOAD_TYPES.' + type | translate }}
</mat-option>
</mat-select>
<span class="name-hint cnsl-secondary-text types-description">
{{ 'ACTIONSTWO.TARGET.CREATE.PAYLOAD_TYPE_DESCRIPTION' | translate }}
</span>
</cnsl-form-field>
<cnsl-form-field class="full-width">
<cnsl-label>{{ 'ACTIONSTWO.TARGET.CREATE.TIMEOUT' | translate }}</cnsl-label>
<input cnslInput type="number" placeholder="10" [formControl]="targetForm.controls.timeout" />
<span class="name-hint cnsl-secondary-text" cnslHint>{{
'ACTIONSTWO.TARGET.CREATE.TIMEOUT_DESCRIPTION' | translate
}}</span>
</cnsl-form-field>
<mat-checkbox
*ngIf="targetForm.controls.type.value === 'restWebhook' || targetForm.controls.type.value === 'restCall'"
class="target-checkbox"
[formControl]="targetForm.controls.interruptOnError"
>
<div class="target-condition-text">
<span>{{ 'ACTIONSTWO.TARGET.CREATE.INTERRUPT_ON_ERROR' | translate }}</span>
<span class="description cnsl-secondary-text">{{
'ACTIONSTWO.TARGET.CREATE.INTERRUPT_ON_ERROR_DESCRIPTION' | translate
@if (targetForm) {
<form class="form-grid" [formGroup]="targetForm" (ngSubmit)="closeWithResult()">
<cnsl-form-field class="full-width">
<cnsl-label>{{ 'ACTIONSTWO.TARGET.CREATE.NAME' | translate }}</cnsl-label>
<input cnslInput type="text" placeholder="" formControlName="name" />
<span class="name-hint cnsl-secondary-text" cnslHint>{{
'ACTIONSTWO.TARGET.CREATE.NAME_DESCRIPTION' | translate
}}</span>
<span [style.color]="'var(--warn)'" class="description cnsl-secondary-text"
>{{ 'ACTIONSTWO.TARGET.CREATE.INTERRUPT_ON_ERROR_WARNING' | translate }}
</cnsl-form-field>
<cnsl-form-field class="full-width">
<cnsl-label>{{ 'ACTIONSTWO.TARGET.CREATE.ENDPOINT' | translate }}</cnsl-label>
<input cnslInput type="text" placeholder="" formControlName="endpoint" />
<span class="name-hint cnsl-secondary-text" cnslHint>{{
'ACTIONSTWO.TARGET.CREATE.ENDPOINT_DESCRIPTION' | translate
}}</span>
</cnsl-form-field>
<cnsl-form-field class="full-width">
<cnsl-label>{{ 'ACTIONSTWO.TARGET.CREATE.TYPE' | translate }}</cnsl-label>
<mat-select [formControl]="targetForm.controls.type" name="type">
@for (type of targetTypes; track type) {
<mat-option [value]="type">
{{ 'ACTIONSTWO.TARGET.CREATE.TYPES.' + type | translate }}
</mat-option>
}
</mat-select>
<span class="name-hint cnsl-secondary-text types-description">
{{ 'ACTIONSTWO.TARGET.CREATE.TYPES_DESCRIPTION' | translate }}
</span>
</div>
</mat-checkbox>
</form>
</cnsl-form-field>
<cnsl-form-field class="full-width">
<cnsl-label>{{ 'ACTIONSTWO.TARGET.CREATE.PAYLOAD_TYPE' | translate }}</cnsl-label>
<mat-select [formControl]="targetForm.controls.payloadType" name="payloadType">
@for (type of payloadTypes; track type) {
<mat-option [value]="type">
{{ 'ACTIONSTWO.TARGET.CREATE.PAYLOAD_TYPES.' + type | translate }}
</mat-option>
}
</mat-select>
<span class="name-hint cnsl-secondary-text types-description">
{{ 'ACTIONSTWO.TARGET.CREATE.PAYLOAD_TYPE_DESCRIPTION' | translate }}
</span>
</cnsl-form-field>
<cnsl-form-field class="full-width">
<cnsl-label>{{ 'ACTIONSTWO.TARGET.CREATE.TIMEOUT' | translate }}</cnsl-label>
<input cnslInput type="number" placeholder="10" [formControl]="targetForm.controls.timeout" />
<span class="name-hint cnsl-secondary-text" cnslHint>{{
'ACTIONSTWO.TARGET.CREATE.TIMEOUT_DESCRIPTION' | translate
}}</span>
</cnsl-form-field>
@if (targetForm.controls.type.value === 'restWebhook' || targetForm.controls.type.value === 'restCall') {
<mat-checkbox class="target-checkbox" [formControl]="targetForm.controls.interruptOnError">
<div class="target-condition-text">
<span>{{ 'ACTIONSTWO.TARGET.CREATE.INTERRUPT_ON_ERROR' | translate }}</span>
<span class="description cnsl-secondary-text">{{
'ACTIONSTWO.TARGET.CREATE.INTERRUPT_ON_ERROR_DESCRIPTION' | translate
}}</span>
<span [style.color]="'var(--warn)'" class="description cnsl-secondary-text"
>{{ 'ACTIONSTWO.TARGET.CREATE.INTERRUPT_ON_ERROR_WARNING' | translate }}
</span>
</div>
</mat-checkbox>
}
</form>
}
</mat-dialog-content>
<div>
<mat-dialog-actions class="actions">
@@ -2,7 +2,7 @@ import { Component, Inject } from '@angular/core';
import { MatButtonModule } from '@angular/material/button';
import { MAT_DIALOG_DATA, MatDialogModule, MatDialogRef } from '@angular/material/dialog';
import { TranslateModule } from '@ngx-translate/core';
import { CommonModule } from '@angular/common';
import { FormBuilder, FormControl, ReactiveFormsModule } from '@angular/forms';
import { MatCheckboxModule } from '@angular/material/checkbox';
import { InputModule } from '../../input/input.module';
@@ -21,7 +21,6 @@ type TargetTypes = ActionTwoAddTargetDialogComponent['targetTypes'][number];
templateUrl: './actions-two-add-target-dialog.component.html',
styleUrls: ['./actions-two-add-target-dialog.component.scss'],
imports: [
CommonModule,
MatButtonModule,
MatDialogModule,
ReactiveFormsModule,
@@ -5,9 +5,11 @@
<cnsl-form-field class="form-field">
<cnsl-label>{{ 'USER.MACHINE.TYPE' | translate }}</cnsl-label>
<mat-select [(ngModel)]="type">
<mat-option *ngFor="let t of types" [value]="t">
{{ 'USER.MACHINE.KEYTYPES.' + t | translate }}
</mat-option>
@for (t of types; track t) {
<mat-option [value]="t">
{{ 'USER.MACHINE.KEYTYPES.' + t | translate }}
</mat-option>
}
</mat-select>
</cnsl-form-field>
@@ -16,10 +18,12 @@
<input cnslInput [matDatepicker]="picker" [min]="startDate" [formControl]="dateControl" />
<mat-datepicker-toggle style="top: 0" cnslSuffix [for]="picker"></mat-datepicker-toggle>
<mat-datepicker #picker [startAt]="startDate"></mat-datepicker>
<span cnslError *ngIf="dateControl && dateControl.errors && dateControl.errors['matDatepickerMin']?.min">
{{ 'USER.MACHINE.CHOOSEDATEAFTER' | translate }}:
{{ dateControl.errors['matDatepickerMin'].min.toDate() | localizedDate: 'EEE dd. MMM' }}
</span>
@if (dateControl && dateControl.errors && dateControl.errors['matDatepickerMin']?.min) {
<span cnslError>
{{ 'USER.MACHINE.CHOOSEDATEAFTER' | translate }}:
{{ dateControl.errors['matDatepickerMin'].min.toDate() | localizedDate: 'EEE dd. MMM' }}
</span>
}
</cnsl-form-field>
</div>
<div mat-dialog-actions class="action">
@@ -5,17 +5,18 @@
<div mat-dialog-content>
<p class="desc cnsl-secondary-text">{{ 'ORG_DETAIL.MEMBER.ADDDESCRIPTION' | translate }}</p>
<ng-container *ngIf="showCreationTypeSelector">
@if (showCreationTypeSelector) {
<cnsl-form-field class="full-width">
<cnsl-label>{{ 'MEMBER.CREATIONTYPE' | translate }}</cnsl-label>
<mat-select [(ngModel)]="creationType" (selectionChange)="loadRoles()">
<mat-option *ngFor="let type of creationTypes" [value]="type.type" [disabled]="(type.disabled$ | async) === false">
{{ 'MEMBER.CREATIONTYPES.' + type.type | translate }}
</mat-option>
@for (type of creationTypes; track type) {
<mat-option [value]="type.type" [disabled]="(type.disabled$ | async) === false">
{{ 'MEMBER.CREATIONTYPES.' + type.type | translate }}
</mat-option>
}
</mat-select>
</cnsl-form-field>
<ng-container *ngIf="creationType === CreationType.PROJECT_OWNED || creationType === CreationType.PROJECT_GRANTED">
@if (creationType === CreationType.PROJECT_OWNED || creationType === CreationType.PROJECT_GRANTED) {
<p>{{ 'PROJECT.GRANT.CREATE.SEL_PROJECT' | translate }}</p>
<cnsl-search-project-autocomplete
class="block"
@@ -29,26 +30,22 @@
"
>
</cnsl-search-project-autocomplete>
</ng-container>
</ng-container>
}
}
<cnsl-search-user-autocomplete [users]="preselectedUsers" (selectionChanged)="users = $any($event)">
</cnsl-search-user-autocomplete>
<div class="roles-selection">
<mat-checkbox
class="role-cb"
*ngFor="let role of memberRoleOptions"
color="primary"
(change)="toggleRole(role)"
[checked]="roles.includes(role)"
>
<div class="role-cb-content">
<div class="cnsl-chip-dot" [style.background]="getColor(role)"></div>
<span data-e2e="role-checkbox">{{ role | roletransform }}</span>
<i class="info-hover las la-question-circle" matTooltip="{{ 'MEMBERROLES.' + role | translate }}"></i>
</div>
</mat-checkbox>
@for (role of memberRoleOptions; track role) {
<mat-checkbox class="role-cb" color="primary" (change)="toggleRole(role)" [checked]="roles.includes(role)">
<div class="role-cb-content">
<div class="cnsl-chip-dot" [style.background]="getColor(role)"></div>
<span data-e2e="role-checkbox">{{ role | roletransform }}</span>
<i class="info-hover las la-question-circle" matTooltip="{{ 'MEMBERROLES.' + role | translate }}"></i>
</div>
</mat-checkbox>
}
</div>
</div>
<div mat-dialog-actions class="action">
@@ -2,19 +2,15 @@
<div mat-dialog-content>
<p class="desc">{{ 'MEMBER.EDITFOR' | translate: { value: data.user } }}</p>
<div class="roles-selection">
<mat-checkbox
class="role-cb"
*ngFor="let role of allRoles"
color="primary"
(change)="toggleRole(role)"
[checked]="selectedRoles.includes(role)"
>
<div class="role-cb-content">
<div class="cnsl-chip-dot" [style.background]="getColor(role)"></div>
<span>{{ role | roletransform }}</span>
<i class="info-hover las la-question-circle" matTooltip="{{ 'MEMBERROLES.' + role | translate }}"></i>
</div>
</mat-checkbox>
@for (role of allRoles; track role) {
<mat-checkbox class="role-cb" color="primary" (change)="toggleRole(role)" [checked]="selectedRoles.includes(role)">
<div class="role-cb-content">
<div class="cnsl-chip-dot" [style.background]="getColor(role)"></div>
<span>{{ role | roletransform }}</span>
<i class="info-hover las la-question-circle" matTooltip="{{ 'MEMBERROLES.' + role | translate }}"></i>
</div>
</mat-checkbox>
}
</div>
</div>
<div mat-dialog-actions class="action">
@@ -7,10 +7,12 @@
<input cnslInput [matDatepicker]="picker" [min]="startDate" [formControl]="dateControl" />
<mat-datepicker-toggle style="top: 0" cnslSuffix [for]="picker"></mat-datepicker-toggle>
<mat-datepicker #picker startView="year" [startAt]="startDate"></mat-datepicker>
<span cnslError *ngIf="dateControl && dateControl.errors && dateControl.errors['matDatepickerMin']?.min">
{{ 'USER.PERSONALACCESSTOKEN.ADD.CHOOSEDATEAFTER' | translate }}:
{{ dateControl.errors['matDatepickerMin'].min.toDate() | localizedDate: 'EEE dd. MMM' }}
</span>
@if (dateControl && dateControl.errors && dateControl.errors['matDatepickerMin']?.min) {
<span cnslError>
{{ 'USER.PERSONALACCESSTOKEN.ADD.CHOOSEDATEAFTER' | translate }}:
{{ dateControl.errors['matDatepickerMin'].min.toDate() | localizedDate: 'EEE dd. MMM' }}
</span>
}
</cnsl-form-field>
</div>
<div mat-dialog-actions class="action">
@@ -1,5 +1,5 @@
<div class="auth-method-radio-button-wrapper" [ngClass]="{ compact: compact }">
<ng-container *ngFor="let method of authMethods; index as i">
@for (method of authMethods; track method; let i = $index) {
<input
type="radio"
[disabled]="method.disabled"
@@ -13,43 +13,50 @@
[ngClass]="{ compact: compact, first: i === 0, last: i === authMethods.length - 1 }"
[for]="method.key"
>
<div
class="recommended"
[ngClass]="{ not: method.notRecommended }"
*ngIf="method.recommended || method.notRecommended"
>
{{ (method.recommended ? 'APP.OIDC.RECOMMENDED' : 'APP.OIDC.NOTRECOMMENDED') | translate }}
</div>
@if (method.recommended || method.notRecommended) {
<div class="recommended" [ngClass]="{ not: method.notRecommended }">
{{ (method.recommended ? 'APP.OIDC.RECOMMENDED' : 'APP.OIDC.NOTRECOMMENDED') | translate }}
</div>
}
<div class="cnsl-radio-header" [ngStyle]="{ background: method.background }">
<span>{{ method.prefix }}</span>
<div class="current" *ngIf="current === method.key">{{ 'APP.OIDC.CURRENT' | translate }}</div>
@if (current === method.key) {
<div class="current">{{ 'APP.OIDC.CURRENT' | translate }}</div>
}
</div>
<p>{{ method.titleI18nKey | translate }}</p>
<p class="type-desc cnsl-secondary-text">{{ method.descI18nKey | translate }}</p>
<span class="fill-space"></span>
<div class="app-specs cnsl-secondary-text">
<div class="row" *ngIf="isOIDC && method && method.responseType !== undefined">
<span class="row-entry">{{ 'APP.OIDC.RESPONSETYPE' | translate }}</span>
<span>{{ 'APP.OIDC.RESPONSE.' + method.responseType.toString() | translate }}</span>
</div>
<div class="row" *ngIf="isOIDC && method.grantType !== undefined">
<span class="row-entry">{{ 'APP.GRANT' | translate }}</span>
<span
><span class="space" *ngFor="let grant of method.grantType">{{
'APP.OIDC.GRANT.' + grant.toString() | translate
}}</span></span
>
</div>
<div class="row" *ngIf="isOIDC && method.authMethod !== undefined">
<span class="row-entry">{{ 'APP.AUTHMETHOD' | translate }}</span>
<span>{{ 'APP.OIDC.AUTHMETHOD.' + method.authMethod.toString() | translate }}</span>
</div>
<div class="row" *ngIf="!isOIDC && method.apiAuthMethod !== undefined">
<span class="row-entry">{{ 'APP.AUTHMETHOD' | translate }}</span>
<span>{{ 'APP.API.AUTHMETHOD.' + method.apiAuthMethod.toString() | translate }}</span>
</div>
@if (isOIDC && method && method.responseType !== undefined) {
<div class="row">
<span class="row-entry">{{ 'APP.OIDC.RESPONSETYPE' | translate }}</span>
<span>{{ 'APP.OIDC.RESPONSE.' + method.responseType.toString() | translate }}</span>
</div>
}
@if (isOIDC && method.grantType !== undefined) {
<div class="row">
<span class="row-entry">{{ 'APP.GRANT' | translate }}</span>
<span>
@for (grant of method.grantType; track grant) {
<span class="space">{{ 'APP.OIDC.GRANT.' + grant.toString() | translate }}</span>
}
</span>
</div>
}
@if (isOIDC && method.authMethod !== undefined) {
<div class="row">
<span class="row-entry">{{ 'APP.AUTHMETHOD' | translate }}</span>
<span>{{ 'APP.OIDC.AUTHMETHOD.' + method.authMethod.toString() | translate }}</span>
</div>
}
@if (!isOIDC && method.apiAuthMethod !== undefined) {
<div class="row">
<span class="row-entry">{{ 'APP.AUTHMETHOD' | translate }}</span>
<span>{{ 'APP.API.AUTHMETHOD.' + method.apiAuthMethod.toString() | translate }}</span>
</div>
}
</div>
</label>
</ng-container>
}
</div>
@@ -1,5 +1,5 @@
<div class="app-type-radio-button-wrapper">
<ng-container *ngFor="let type of types">
@for (type of types; track type) {
<input class="app" type="radio" (change)="emitChange()" [value]="type" [(ngModel)]="selected" [id]="type.prefix" />
<label class="cnsl-type-radio-button" [for]="type.prefix">
<div class="cnsl-type-radio-header" [ngStyle]="{ background: type.background }">
@@ -8,7 +8,9 @@
<p>{{ type.titleI18nKey | translate }}</p>
<p class="type-desc cnsl-secondary-text">{{ type.descI18nKey | translate }}</p>
<span class="fill-space"></span>
<span class="cnsl-type-protocol state" *ngIf="type.protocol">{{ type.protocol }}</span>
@if (type.protocol) {
<span class="cnsl-type-protocol state">{{ type.protocol }}</span>
}
</label>
</ng-container>
}
</div>
@@ -13,11 +13,12 @@
}"
[ngClass]="{ active: active }"
>
<ng-container *ngIf="isMachine; else human">
@if (isMachine) {
<i class="machine-icon las la-robot"></i>
</ng-container>
<ng-template #human>
} @else {
<span class="dontcloseonclick">{{ credentials }}</span>
<img class="dontcloseonclick" *ngIf="avatarUrl" [src]="avatarUrl" (error)="errorHandler($event)" />
</ng-template>
@if (avatarUrl) {
<img class="dontcloseonclick" [src]="avatarUrl" (error)="errorHandler($event)" />
}
}
</div>
@@ -1,19 +1,37 @@
<div class="card" [ngClass]="{ nomargin: nomargin, warn: warn }" data-e2e="app-card">
<div *ngIf="title || description" class="header" [ngClass]="{ 'bottom-margin': expanded }">
<div *ngIf="title" class="row">
<h2 class="title" data-e2e="app-card-title">{{ title }}</h2>
<span class="fill-space"></span>
<ng-content select="[card-actions]"></ng-content>
<button class="button" type="button" matTooltip="Expand or collapse" mat-icon-button (click)="expanded = !expanded">
<mat-icon *ngIf="!expanded">keyboard_arrow_down</mat-icon>
<mat-icon *ngIf="expanded">keyboard_arrow_up</mat-icon>
</button>
@if (title || description) {
<div class="header" [ngClass]="{ 'bottom-margin': expanded }">
@if (title) {
<div class="row">
<h2 class="title" data-e2e="app-card-title">{{ title }}</h2>
<span class="fill-space"></span>
<ng-content select="[card-actions]"></ng-content>
<button
class="button"
type="button"
matTooltip="Expand or collapse"
mat-icon-button
(click)="expanded = !expanded"
>
@if (!expanded) {
<mat-icon>keyboard_arrow_down</mat-icon>
}
@if (expanded) {
<mat-icon>keyboard_arrow_up</mat-icon>
}
</button>
</div>
}
@if (description) {
<p class="desc cnsl-secondary-text">
{{ description }}
</p>
}
</div>
<p *ngIf="description" class="desc cnsl-secondary-text">
{{ description }}
</p>
</div>
<div class="card-content" *ngIf="expanded">
<ng-content></ng-content>
</div>
}
@if (expanded) {
<div class="card-content">
<ng-content></ng-content>
</div>
}
</div>
@@ -3,49 +3,63 @@
</div>
<div class="scroll-container">
<li class="item" *ngFor="let hist of data | async; index as histindex">
<span *ngIf="hist.values[0].dates[0]" class="date">
{{ hist.values[0].dates[0] | timestampToDate | localizedDate: 'dd. MMM yyyy' }}
</span>
<div class="item" *ngFor="let dayelement of hist.values; index as i">
<div class="row">
<cnsl-avatar
matTooltip="{{ dayelement.editorDisplayName }}"
*ngIf="dayelement.editorDisplayName; else spacer"
class="avatar"
[name]="dayelement.editorDisplayName"
[size]="32"
[forColor]="dayelement?.editorPreferredLoginName ?? 'A'"
[avatarUrl]="dayelement.editorAvatarUrl || ''"
>
</cnsl-avatar>
<ng-template #spacer>
<div class="spacer"></div>
</ng-template>
<div class="change-actions">
<div class="change-action" *ngFor="let action of dayelement.eventTypes; index as j">
<div>
<span class="msg">{{ action.localizedMessage }}</span>
<span
class="block"
matTooltip="{{ dayelement.dates[j] | timestampToDate | localizedDate: 'dd. MM yyyy, HH:mm:ss.SSS' }}"
>{{ dayelement.dates[j] | timestampToDate | localizedDate: 'HH:mm' }}</span
@for (hist of data | async; track hist; let histindex = $index) {
<li class="item">
@if (hist.values[0].dates[0]) {
<span class="date">
{{ hist.values[0].dates[0] | timestampToDate | localizedDate: 'dd. MMM yyyy' }}
</span>
}
@for (dayelement of hist.values; track dayelement; let i = $index) {
<div class="item">
<div class="row">
@if (dayelement.editorDisplayName) {
<cnsl-avatar
matTooltip="{{ dayelement.editorDisplayName }}"
class="avatar"
[name]="dayelement.editorDisplayName"
[size]="32"
[forColor]="dayelement?.editorPreferredLoginName ?? 'A'"
[avatarUrl]="dayelement.editorAvatarUrl || ''"
>
</cnsl-avatar>
} @else {
<div class="spacer"></div>
}
<div class="change-actions">
@for (action of dayelement.eventTypes; track action; let j = $index) {
<div class="change-action">
<div>
<span class="msg">{{ action.localizedMessage }}</span>
<span
class="block"
matTooltip="{{ dayelement.dates[j] | timestampToDate | localizedDate: 'dd. MM yyyy, HH:mm:ss.SSS' }}"
>{{ dayelement.dates[j] | timestampToDate | localizedDate: 'HH:mm' }}</span
>
</div>
</div>
}
</div>
</div>
</div>
</div>
</div>
</li>
}
</li>
}
<div class="ch-sp-wrapper">
<mat-spinner *ngIf="loading | async" diameter="25"></mat-spinner>
@if (loading | async) {
<mat-spinner diameter="25"></mat-spinner>
}
</div>
<button (click)="more()" class="load-more-button" *ngIf="!bottom" mat-stroked-button>
{{ 'CHANGES.LOADMORE' | translate }}
</button>
@if (!bottom) {
<button (click)="more()" class="load-more-button" mat-stroked-button>
{{ 'CHANGES.LOADMORE' | translate }}
</button>
}
<div *ngIf="bottom" class="end-container">
<span class="cnsl-secondary-text">{{ 'CHANGES.BOTTOM' | translate }}</span>
</div>
@if (bottom) {
<div class="end-container">
<span class="cnsl-secondary-text">{{ 'CHANGES.BOTTOM' | translate }}</span>
</div>
}
</div>
@@ -1,9 +1,11 @@
<div class="contributor-groups">
<div class="contributor-people">
<div class="contributor-img-list" [ngClass]="{ 'padd-left': totalResult > 0 }" [@cardAnimation]="totalResult">
<mat-spinner class="spinner" diameter="20" *ngIf="loading"></mat-spinner>
<ng-container *ngIf="totalResult < 10; else compact">
<ng-container *ngFor="let member of membersSubject | async; index as i">
@if (loading) {
<mat-spinner class="spinner" diameter="20"></mat-spinner>
}
@if (totalResult < 10) {
@for (member of membersSubject | async; track member; let i = $index) {
<div
@animate
(click)="emitShowDetail()"
@@ -12,24 +14,23 @@
[ngStyle]="{ 'z-index': 20 - i }"
data-e2e="member-avatar"
>
<cnsl-avatar
*ngIf="member && member.userType === UserType.TYPE_HUMAN; else cog"
class="contributor-avatar dontcloseonclick"
[avatarUrl]="member.avatarUrl || ''"
[name]="member.displayName"
[forColor]="member.preferredLoginName"
[size]="32"
>
</cnsl-avatar>
<ng-template #cog>
@if (member && member.userType === UserType.TYPE_HUMAN) {
<cnsl-avatar
class="contributor-avatar dontcloseonclick"
[avatarUrl]="member.avatarUrl || ''"
[name]="member.displayName"
[forColor]="member.preferredLoginName"
[size]="32"
>
</cnsl-avatar>
} @else {
<cnsl-avatar [forColor]="member.preferredLoginName" [isMachine]="true">
<i class="las la-robot"></i>
</cnsl-avatar>
</ng-template>
}
</div>
</ng-container>
</ng-container>
<ng-template #compact>
}
} @else {
<div
(click)="emitShowDetail()"
class="contributor-avatar-circle"
@@ -37,7 +38,7 @@
>
<span>{{ totalResult }}</span>
</div>
</ng-template>
}
<button
class="add-img"
[ngClass]="{ 'no-margin': totalResult === 0 }"
@@ -4,10 +4,12 @@
<button (click)="close()" mat-icon-button matTooltip="{{ 'ACTIONS.CLOSE' | translate }}">
<mat-icon>close</mat-icon>
</button>
<span class="abort">{{ title }}</span
><span class="abort-2" *ngIf="createSteps > 1"
>{{ 'ACTIONS.STEP' | translate }} {{ currentCreateStep }} {{ 'ACTIONS.OF' | translate }} {{ createSteps }}</span
>
<span class="abort">{{ title }}</span>
@if (createSteps > 1) {
<span class="abort-2"
>{{ 'ACTIONS.STEP' | translate }} {{ currentCreateStep }} {{ 'ACTIONS.OF' | translate }} {{ createSteps }}</span
>
}
</div>
<div class="create-layout-content">
@@ -4,9 +4,11 @@
<div class="detail-layout-top-view">
<div>
<div class="back-row">
<a *ngIf="hasBackButton" cnslBack mat-icon-button>
<mat-icon class="icon">arrow_back</mat-icon>
</a>
@if (hasBackButton) {
<a cnslBack mat-icon-button>
<mat-icon class="icon">arrow_back</mat-icon>
</a>
}
<div>
<h1>{{ title }}</h1>
<ng-content select="[sub]"></ng-content>
@@ -1,76 +1,87 @@
<h2 class="title" mat-dialog-title>{{ 'IAM.EVENTS.DIALOG.TITLE' | translate }}</h2>
<div mat-dialog-content>
<div class="event-data-column" *ngIf="event && (event | toobject) as event">
<div class="data-row" *ngIf="event && event.type && event.type.localized && event.type.localized.localizedMessage">
<span class="label cnsl-secondary-text">{{ 'IAM.EVENTS.TYPE' | translate }}</span>
<span>{{ event.type.localized.localizedMessage }}</span>
</div>
<div class="data-row" *ngIf="event && event.creationDate">
<span class="label cnsl-secondary-text">{{ 'IAM.EVENTS.CREATIONDATE' | translate }}</span>
<span>{{ event.creationDate | timestampToDate | localizedDate: 'EEE dd. MMM, HH:mm' }}</span>
</div>
<div class="data-row" *ngIf="event && event.aggregate && event.aggregate.id">
<span class="label cnsl-secondary-text">{{ 'IAM.EVENTS.AGGREGATEID' | translate }}</span>
<span>{{ event.aggregate.id }}</span>
</div>
<div class="data-row" *ngIf="event && event.aggregate && event.aggregate.resourceOwner">
<span class="label cnsl-secondary-text">{{ 'IAM.EVENTS.RESOURCEOWNER' | translate }}</span>
<span>{{ event.aggregate.resourceOwner }}</span>
</div>
<div
class="data-row"
*ngIf="
@if (event && (event | toobject); as event) {
<div class="event-data-column">
@if (event && event.type && event.type.localized && event.type.localized.localizedMessage) {
<div class="data-row">
<span class="label cnsl-secondary-text">{{ 'IAM.EVENTS.TYPE' | translate }}</span>
<span>{{ event.type.localized.localizedMessage }}</span>
</div>
}
@if (event && event.creationDate) {
<div class="data-row">
<span class="label cnsl-secondary-text">{{ 'IAM.EVENTS.CREATIONDATE' | translate }}</span>
<span>{{ event.creationDate | timestampToDate | localizedDate: 'EEE dd. MMM, HH:mm' }}</span>
</div>
}
@if (event && event.aggregate && event.aggregate.id) {
<div class="data-row">
<span class="label cnsl-secondary-text">{{ 'IAM.EVENTS.AGGREGATEID' | translate }}</span>
<span>{{ event.aggregate.id }}</span>
</div>
}
@if (event && event.aggregate && event.aggregate.resourceOwner) {
<div class="data-row">
<span class="label cnsl-secondary-text">{{ 'IAM.EVENTS.RESOURCEOWNER' | translate }}</span>
<span>{{ event.aggregate.resourceOwner }}</span>
</div>
}
@if (
event &&
event.aggregate &&
event.aggregate.type &&
event.aggregate.type.localized &&
event.aggregate.type.localized.localizedMessage
"
>
<span class="label cnsl-secondary-text">{{ 'IAM.EVENTS.AGGREGATETYPE' | translate }}</span>
<span class="state aggregate-type">{{ event.aggregate.type.localized.localizedMessage }}</span>
) {
<div class="data-row">
<span class="label cnsl-secondary-text">{{ 'IAM.EVENTS.AGGREGATETYPE' | translate }}</span>
<span class="state aggregate-type">{{ event.aggregate.type.localized.localizedMessage }}</span>
</div>
}
@if (event && event.editor?.userId) {
<div class="data-row">
<span class="label cnsl-secondary-text">{{ 'IAM.EVENTS.EDITORID' | translate }}</span>
<span>{{ event.editor?.userId }}</span>
</div>
}
@if (event && event.editor?.displayName) {
<div class="data-row">
<span class="label cnsl-secondary-text">{{ 'IAM.EVENTS.EDITOR' | translate }}</span>
<span>{{ event.editor?.displayName }}</span>
</div>
}
@if (event && event.sequence) {
<div class="data-row">
<span class="label cnsl-secondary-text">{{ 'IAM.EVENTS.SEQUENCE' | translate }}</span>
<span>{{ event.sequence }}</span>
</div>
}
</div>
}
<div class="data-row" *ngIf="event && event.editor?.userId">
<span class="label cnsl-secondary-text">{{ 'IAM.EVENTS.EDITORID' | translate }}</span>
<span>{{ event.editor?.userId }}</span>
@if (opened$ | async) {
<div class="code">
@if (event) {
<ngx-codemirror
[ngModel]="event | topayload | json"
[options]="{
height: 'auto',
readOnly: true,
lineNumbers: true,
lineWrapping: true,
indentWithTabs: false,
tabSize: 2,
theme: 'material',
mode: {
name: 'javascript',
json: true,
statementIndent: 2,
},
}"
></ngx-codemirror>
}
</div>
<div class="data-row" *ngIf="event && event.editor?.displayName">
<span class="label cnsl-secondary-text">{{ 'IAM.EVENTS.EDITOR' | translate }}</span>
<span>{{ event.editor?.displayName }}</span>
</div>
<div class="data-row" *ngIf="event && event.sequence">
<span class="label cnsl-secondary-text">{{ 'IAM.EVENTS.SEQUENCE' | translate }}</span>
<span>{{ event.sequence }}</span>
</div>
</div>
<div class="code" *ngIf="opened$ | async">
<ngx-codemirror
*ngIf="event"
[ngModel]="event | topayload | json"
[options]="{
height: 'auto',
readOnly: true,
lineNumbers: true,
lineWrapping: true,
indentWithTabs: false,
tabSize: 2,
theme: 'material',
mode: {
name: 'javascript',
json: true,
statementIndent: 2,
},
}"
></ngx-codemirror>
</div>
}
</div>
<div mat-dialog-actions class="action">
<button mat-stroked-button (click)="closeDialog()">
@@ -14,110 +14,139 @@
</div>
<div mat-dialog-content cdkFocusInitial autofocus>
<div *ngIf="showNew && !(dns || http)">
<p class="domain-desc">{{ 'ORG.PAGES.ORGDOMAIN.VERIFICATION' | translate }}</p>
<p class="domain-desc">
{{ 'ORG.PAGES.ORGDOMAIN.VERIFICATION_HTML' | translate }}
@if (showNew && !(dns || http)) {
<div>
<p class="domain-desc">{{ 'ORG.PAGES.ORGDOMAIN.VERIFICATION' | translate }}</p>
<p class="domain-desc">
{{ 'ORG.PAGES.ORGDOMAIN.VERIFICATION_HTML' | translate }}
</p>
<p class="domain-desc">{{ 'ORG.PAGES.ORGDOMAIN.VERIFICATION_DNS' | translate }}</p>
<p class="domain-desc">{{ 'ORG.PAGES.ORGDOMAIN.VERIFICATION_SKIP' | translate }}</p>
</div>
}
@if (showNew && !(dns || http)) {
<cnsl-info-section [type]="InfoSectionType.WARN" class="desc">{{
'ORG.PAGES.ORGDOMAIN.VERIFICATION_VALIDATION_DESC' | translate
}}</cnsl-info-section>
}
@if (!showNew && !(dns || http)) {
<p class="desc">
{{
'ORG.PAGES.ORGDOMAIN.VERIFICATION_VALIDATION_ONGOING'
| translate: { value: domain?.validationType == 1 ? 'HTTP' : 'DNS' }
}}
</p>
<p class="domain-desc">{{ 'ORG.PAGES.ORGDOMAIN.VERIFICATION_DNS' | translate }}</p>
<p class="domain-desc">{{ 'ORG.PAGES.ORGDOMAIN.VERIFICATION_SKIP' | translate }}</p>
</div>
}
<cnsl-info-section [type]="InfoSectionType.WARN" *ngIf="showNew && !(dns || http)" class="desc">{{
'ORG.PAGES.ORGDOMAIN.VERIFICATION_VALIDATION_DESC' | translate
}}</cnsl-info-section>
<p *ngIf="!showNew && !(dns || http)" class="desc">
{{
'ORG.PAGES.ORGDOMAIN.VERIFICATION_VALIDATION_ONGOING'
| translate: { value: domain?.validationType == 1 ? 'HTTP' : 'DNS' }
}}
</p>
<ng-container *ngIf="showNew">
<div *ngIf="http">
<p class="desc">{{ 'ORG.PAGES.ORGDOMAIN.VERIFICATION_HTTP_DESC' | translate: { value: domain?.domainName } }}</p>
<p class="desc">{{ 'ORG.PAGES.ORGDOMAIN.VERIFICATION_HTTP_URL_LABEL' | translate }}</p>
<div class="domain-entry" *ngIf="http.url">
<p>{{ http.url }}</p>
<button
color="primary"
[disabled]="copied === data.clientSecret"
matTooltip="copy to clipboard"
cnslCopyToClipboard
[valueToCopy]="http.url"
(copiedValue)="copied = $event"
mat-icon-button
>
<i *ngIf="copied !== http.url" class="las la-clipboard"></i>
<i *ngIf="copied === http.url" class="las la-clipboard-check"></i>
</button>
@if (showNew) {
@if (http) {
<div>
<p class="desc">{{ 'ORG.PAGES.ORGDOMAIN.VERIFICATION_HTTP_DESC' | translate: { value: domain?.domainName } }}</p>
<p class="desc">{{ 'ORG.PAGES.ORGDOMAIN.VERIFICATION_HTTP_URL_LABEL' | translate }}</p>
@if (http.url) {
<div class="domain-entry">
<p>{{ http.url }}</p>
<button
color="primary"
[disabled]="copied === data.clientSecret"
matTooltip="copy to clipboard"
cnslCopyToClipboard
[valueToCopy]="http.url"
(copiedValue)="copied = $event"
mat-icon-button
>
@if (copied !== http.url) {
<i class="las la-clipboard"></i>
}
@if (copied === http.url) {
<i class="las la-clipboard-check"></i>
}
</button>
</div>
}
<p class="desc">{{ 'ORG.PAGES.ORGDOMAIN.VERIFICATION_HTTP_FILE_LABEL' | translate }}</p>
<button mat-stroked-button (click)="saveFile()" color="primary">{{ 'ORG.PAGES.DOWNLOAD_FILE' | translate }}</button>
</div>
<p class="desc">{{ 'ORG.PAGES.ORGDOMAIN.VERIFICATION_HTTP_FILE_LABEL' | translate }}</p>
<button mat-stroked-button (click)="saveFile()" color="primary">{{ 'ORG.PAGES.DOWNLOAD_FILE' | translate }}</button>
</div>
<div *ngIf="dns">
<p class="desc">{{ 'ORG.PAGES.ORGDOMAIN.VERIFICATION_DNS_DESC' | translate: { value: domain?.domainName } }}</p>
<p class="desc">{{ 'ORG.PAGES.ORGDOMAIN.VERIFICATION_DNS_HOST_LABEL' | translate }}</p>
<div class="domain-line">
<div class="domain-entry" *ngIf="dns.token">
<p>{{ dnsChallenge }}</p>
<button
color="primary"
[disabled]="copied === data.clientSecret"
matTooltip="copy to clipboard"
cnslCopyToClipboard
[valueToCopy]="dnsChallenge"
(copiedValue)="copied = $event"
mat-icon-button
>
<i *ngIf="copied !== dnsChallenge" class="las la-clipboard"></i>
<i *ngIf="copied === dnsChallenge" class="las la-clipboard-check"></i>
</button>
}
@if (dns) {
<div>
<p class="desc">{{ 'ORG.PAGES.ORGDOMAIN.VERIFICATION_DNS_DESC' | translate: { value: domain?.domainName } }}</p>
<p class="desc">{{ 'ORG.PAGES.ORGDOMAIN.VERIFICATION_DNS_HOST_LABEL' | translate }}</p>
<div class="domain-line">
@if (dns.token) {
<div class="domain-entry">
<p>{{ dnsChallenge }}</p>
<button
color="primary"
[disabled]="copied === data.clientSecret"
matTooltip="copy to clipboard"
cnslCopyToClipboard
[valueToCopy]="dnsChallenge"
(copiedValue)="copied = $event"
mat-icon-button
>
@if (copied !== dnsChallenge) {
<i class="las la-clipboard"></i>
}
@if (copied === dnsChallenge) {
<i class="las la-clipboard-check"></i>
}
</button>
</div>
}
<span>.{{ domain?.domainName }}</span>
</div>
<span>.{{ domain?.domainName }}</span>
<p class="desc">{{ 'ORG.PAGES.ORGDOMAIN.VERIFICATION_DNS_CHALLENGE_LABEL' | translate }}</p>
@if (dns.token) {
<div class="domain-entry">
<p>{{ dns.token }}</p>
<button
color="primary"
[disabled]="copied === data.clientSecret"
matTooltip="copy to clipboard"
cnslCopyToClipboard
[valueToCopy]="dns.token"
(copiedValue)="copied = $event"
mat-icon-button
>
@if (copied !== dns.token) {
<i class="las la-clipboard"></i>
}
@if (copied === dns.token) {
<i class="las la-clipboard-check"></i>
}
</button>
</div>
}
</div>
<p class="desc">{{ 'ORG.PAGES.ORGDOMAIN.VERIFICATION_DNS_CHALLENGE_LABEL' | translate }}</p>
<div class="domain-entry" *ngIf="dns.token">
<p>{{ dns.token }}</p>
<button
color="primary"
[disabled]="copied === data.clientSecret"
matTooltip="copy to clipboard"
cnslCopyToClipboard
[valueToCopy]="dns.token"
(copiedValue)="copied = $event"
mat-icon-button
>
<i *ngIf="copied !== dns.token" class="las la-clipboard"></i>
<i *ngIf="copied === dns.token" class="las la-clipboard-check"></i>
</button>
</div>
</div>
</ng-container>
}
}
</div>
<div mat-dialog-actions class="action">
<button
*ngIf="!showNew || dns || http"
color="primary"
type="submit"
mat-raised-button
class="verify-button"
(click)="validate()"
>
{{ 'ACTIONS.VERIFY' | translate }}
</button>
<mat-spinner class="spinner" *ngIf="validating" diameter="20" mode="indeterminate"></mat-spinner>
@if (!showNew || dns || http) {
<button color="primary" type="submit" mat-raised-button class="verify-button" (click)="validate()">
{{ 'ACTIONS.VERIFY' | translate }}
</button>
}
@if (validating) {
<mat-spinner class="spinner" diameter="20" mode="indeterminate"></mat-spinner>
}
<button *ngIf="!showNew" mat-stroked-button color="primary" (click)="showNew = true">
{{ 'ORG.PAGES.ORGDOMAIN.RESETMETHOD' | translate }}
</button>
@if (!showNew) {
<button mat-stroked-button color="primary" (click)="showNew = true">
{{ 'ORG.PAGES.ORGDOMAIN.RESETMETHOD' | translate }}
</button>
}
<div>
<button color="primary" *ngIf="showNew && !(dns || http)" mat-raised-button (click)="loadHttpToken()">HTTP</button>
<button color="primary" *ngIf="showNew && !(dns || http)" mat-raised-button (click)="loadDnsToken()">DNS</button>
@if (showNew && !(dns || http)) {
<button color="primary" mat-raised-button (click)="loadHttpToken()">HTTP</button>
}
@if (showNew && !(dns || http)) {
<button color="primary" mat-raised-button (click)="loadDnsToken()">DNS</button>
}
</div>
<button mat-stroked-button (click)="closeDialog()">
@@ -1,4 +1,4 @@
<ng-container *ngIf="['org.write$'] | hasRole as canwrite$">
@if (['org.write$'] | hasRole; as canwrite$) {
<div class="domain-top-view">
<div>
<div class="domain-title-row">
@@ -15,7 +15,6 @@
<p class="domain-desc cnsl-secondary-text">{{ 'ORG.DOMAINS.DESCRIPTION' | translate }}</p>
</div>
<span class="fill-space"></span>
<button
[disabled]="(canwrite$ | async) === false"
matTooltip="Add domain"
@@ -31,39 +30,40 @@
</div>
</button>
</div>
<cnsl-card *ngFor="let domain of domains" class="domain-card">
<div class="domain">
<span class="title">{{ domain.domainName }}</span>
<i matTooltip="verified" *ngIf="domain.isVerified" class="verified las la-check-circle"></i>
<i matTooltip="primary" *ngIf="domain.isPrimary" class="primary las la-star"></i>
<a
*ngIf="domain.isVerified && !domain.isPrimary && (canwrite$ | async)"
class="primaryset"
(click)="setPrimary(domain)"
>{{ 'ORG.DOMAINS.SETPRIMARY' | translate }}</a
>
<span class="fill-space"></span>
<button
mat-icon-button
[disabled]="(canwrite$ | async) === false || domain.isVerified"
*ngIf="verifyOrgDomains"
(click)="verifyDomain(domain)"
>
<i class="las la-pen"></i>
</button>
<button
class="domain-rem-button"
[disabled]="(canwrite$ | async) === false || domain.isPrimary"
matTooltip="Remove domain"
color="warn"
mat-icon-button
(click)="removeDomain(domain.domainName)"
>
<i class="las la-trash"></i>
</button>
</div>
</cnsl-card>
</ng-container>
@for (domain of domains; track domain) {
<cnsl-card class="domain-card">
<div class="domain">
<span class="title">{{ domain.domainName }}</span>
@if (domain.isVerified) {
<i matTooltip="verified" class="verified las la-check-circle"></i>
}
@if (domain.isPrimary) {
<i matTooltip="primary" class="primary las la-star"></i>
}
@if (domain.isVerified && !domain.isPrimary && (canwrite$ | async)) {
<a class="primaryset" (click)="setPrimary(domain)">{{ 'ORG.DOMAINS.SETPRIMARY' | translate }}</a>
}
<span class="fill-space"></span>
@if (verifyOrgDomains) {
<button
mat-icon-button
[disabled]="(canwrite$ | async) === false || domain.isVerified"
(click)="verifyDomain(domain)"
>
<i class="las la-pen"></i>
</button>
}
<button
class="domain-rem-button"
[disabled]="(canwrite$ | async) === false || domain.isPrimary"
matTooltip="Remove domain"
color="warn"
mat-icon-button
(click)="removeDomain(domain.domainName)"
>
<i class="las la-trash"></i>
</button>
</div>
</cnsl-card>
}
}
@@ -1,66 +1,80 @@
<div *ngIf="currentMap">
<form [formGroup]="form">
<ng-container *ngFor="let key of current$ | async | keyvalue">
<div *ngIf="key.key !== 'isDefault'" class="edit-text-block">
<div class="edit-text-flex" *ngIf="default$ | async as defaultmap">
<cnsl-form-field class="edit-text-formfield">
<cnsl-label>{{ key.key }}</cnsl-label>
<textarea
class="edit-text-area"
cnslInput
[formControlName]="key.key"
[placeholder]="$any(defaultmap[key.key])"
[name]="key.key"
[ngClass]="{ defaulttext: form.get(key.key)?.value === '' }"
></textarea>
<div class="edit-text-chips" *ngIf="warnText[key.key] === undefined">
<ng-container *ngFor="let chip of chips">
<div
class="chip"
cnslCopyToClipboard
[valueToCopy]="chip.value"
(copiedValue)="copied = $event"
(click)="addChip(key.key, chip.value)"
>
<span class="key">{{ chip.key | translate }}</span>
<span class="value">{{ chip.value }}</span>
<i *ngIf="copied !== chip.value" class="las la-clipboard"></i>
<i *ngIf="copied === chip.value" class="las la-clipboard-check"></i>
@if (currentMap) {
<div>
<form [formGroup]="form">
@for (key of current$ | async | keyvalue; track key) {
@if (key.key !== 'isDefault') {
<div class="edit-text-block">
@if (default$ | async; as defaultmap) {
<div class="edit-text-flex">
<cnsl-form-field class="edit-text-formfield">
<cnsl-label>{{ key.key }}</cnsl-label>
<textarea
class="edit-text-area"
cnslInput
[formControlName]="key.key"
[placeholder]="$any(defaultmap[key.key])"
[name]="key.key"
[ngClass]="{ defaulttext: form.get(key.key)?.value === '' }"
></textarea>
@if (warnText[key.key] === undefined) {
<div class="edit-text-chips">
@for (chip of chips; track chip) {
<div
class="chip"
cnslCopyToClipboard
[valueToCopy]="chip.value"
(copiedValue)="copied = $event"
(click)="addChip(key.key, chip.value)"
>
<span class="key">{{ chip.key | translate }}</span>
<span class="value">{{ chip.value }}</span>
@if (copied !== chip.value) {
<i class="las la-clipboard"></i>
}
@if (copied === chip.value) {
<i class="las la-clipboard-check"></i>
}
</div>
}
</div>
}
</cnsl-form-field>
<div class="edit-text-actions">
<button
matTooltip="{{ 'ACTIONS.RESETDEFAULT' | translate }}"
mat-icon-button
[disabled]="form.get(key.key)?.value === defaultmap[key.key] || disabled"
(click)="form.get(key.key)?.setValue(defaultmap[key.key])"
(mouseenter)="
form.get(key.key)?.value !== defaultmap[key.key] && setWarnText(key.key, $any(defaultmap[key.key]))
"
(mouseleave)="setWarnText(key.key, undefined)"
>
<i class="las la-history"></i>
</button>
<button
matTooltip="{{ 'ACTIONS.RESETCURRENT' | translate }}"
mat-icon-button
[disabled]="form.get(key.key)?.value === currentMap[key.key] || disabled"
(click)="form.get(key.key)?.setValue(currentMap[key.key])"
(mouseenter)="
form.get(key.key)?.value !== currentMap[key.key] && setWarnText(key.key, $any(currentMap[key.key]))
"
(mouseleave)="setWarnText(key.key, undefined)"
>
<i class="las la-undo"></i>
</button>
</div>
</ng-container>
</div>
</cnsl-form-field>
<div class="edit-text-actions">
<button
matTooltip="{{ 'ACTIONS.RESETDEFAULT' | translate }}"
mat-icon-button
[disabled]="form.get(key.key)?.value === defaultmap[key.key] || disabled"
(click)="form.get(key.key)?.setValue(defaultmap[key.key])"
(mouseenter)="
form.get(key.key)?.value !== defaultmap[key.key] && setWarnText(key.key, $any(defaultmap[key.key]))
"
(mouseleave)="setWarnText(key.key, undefined)"
>
<i class="las la-history"></i>
</button>
<button
matTooltip="{{ 'ACTIONS.RESETCURRENT' | translate }}"
mat-icon-button
[disabled]="form.get(key.key)?.value === currentMap[key.key] || disabled"
(click)="form.get(key.key)?.setValue(currentMap[key.key])"
(mouseenter)="
form.get(key.key)?.value !== currentMap[key.key] && setWarnText(key.key, $any(currentMap[key.key]))
"
(mouseleave)="setWarnText(key.key, undefined)"
>
<i class="las la-undo"></i>
</button>
</div>
}
</div>
</div>
</div>
<cnsl-info-section *ngIf="warnText[key.key] !== undefined" class="edit-text-info" [type]="InfoSectionType.WARN">
{{ 'ACTIONS.RESETTO' | translate }} <cite>'{{ warnText[key.key] }}'</cite></cnsl-info-section
>
</ng-container>
</form>
</div>
}
@if (warnText[key.key] !== undefined) {
<cnsl-info-section class="edit-text-info" [type]="InfoSectionType.WARN">
{{ 'ACTIONS.RESETTO' | translate }} <cite>'{{ warnText[key.key] }}'</cite></cnsl-info-section
>
}
}
</form>
</div>
}
@@ -22,49 +22,57 @@
<ng-container matColumnDef="editor">
<th mat-header-cell *matHeaderCellDef>{{ 'IAM.EVENTS.EDITOR' | translate }}</th>
<td mat-cell *matCellDef="let event">
<ng-container *ngIf="event | toobject as event">
<div class="editor-row" *ngIf="event.editor as editor">
<!-- <cnsl-avatar
@if (event | toobject; as event) {
@if (event.editor; as editor) {
<div class="editor-row">
<!-- <cnsl-avatar
*ngIf="editor && editor.displayName; else cog"
class="avatar"
[name]="editor.displayName"
[avatarUrl]="editor.avatarUrl || ''"
[forColor]="editor.preferredLoginName ?? editor.displayName"
[size]="32"
>
>
</cnsl-avatar>
<ng-template #cog>
<cnsl-avatar [forColor]="editor?.preferredLoginName ?? 'franz'" [isMachine]="true">
<i class="las la-robot"></i>
</cnsl-avatar> </ng-template
> -->
<span class="name" *ngIf="editor.displayName">{{ editor.displayName }}</span>
<span class="state" *ngIf="editor.service">{{ editor.service }}</span>
</div>
</ng-container>
> -->
@if (editor.displayName) {
<span class="name">{{ editor.displayName }}</span>
}
@if (editor.service) {
<span class="state">{{ editor.service }}</span>
}
</div>
}
}
</td>
</ng-container>
<ng-container matColumnDef="aggregate">
<th mat-header-cell *matHeaderCellDef>{{ 'IAM.EVENTS.AGGREGATE' | translate }}</th>
<td mat-cell *matCellDef="let event">
<ng-container *ngIf="event | toobject as event">
@if (event | toobject; as event) {
<div class="aggregate-row">
<span class="id">{{ event.aggregate.id }}</span
><span class="state" *ngIf="event.aggregate?.type?.localized?.localizedMessage">{{
event.aggregate.type.localized.localizedMessage
}}</span>
<span class="id">{{ event.aggregate.id }}</span>
@if (event.aggregate?.type?.localized?.localizedMessage) {
<span class="state">{{ event.aggregate.type.localized.localizedMessage }}</span>
}
</div>
</ng-container>
}
</td>
</ng-container>
<ng-container matColumnDef="resourceOwner">
<th mat-header-cell *matHeaderCellDef>{{ 'IAM.EVENTS.RESOURCEOWNER' | translate }}</th>
<td mat-cell *matCellDef="let event">
<ng-container *ngIf="event | toobject as event">
<span *ngIf="event.aggregate.resourceOwner">{{ event.aggregate.resourceOwner }}</span>
</ng-container>
@if (event | toobject; as event) {
@if (event.aggregate.resourceOwner) {
<span>{{ event.aggregate.resourceOwner }}</span>
}
}
</td>
</ng-container>
@@ -73,9 +81,9 @@
{{ 'IAM.EVENTS.SEQUENCE' | translate }}
</th>
<td mat-cell *matCellDef="let event">
<ng-container *ngIf="event | toobject as event">
@if (event | toobject; as event) {
{{ event.sequence }}
</ng-container>
}
</td>
</ng-container>
@@ -84,32 +92,34 @@
{{ 'IAM.EVENTS.CREATIONDATE' | translate }}
</th>
<td mat-cell *matCellDef="let event">
<ng-container *ngIf="event | toobject as event">
@if (event | toobject; as event) {
<span>{{ event?.creationDate | timestampToDate | localizedDate: 'EEE dd. MMM, HH:mm:ss' }}</span>
</ng-container>
}
</td>
</ng-container>
<ng-container matColumnDef="type">
<th mat-header-cell *matHeaderCellDef>{{ 'IAM.EVENTS.TYPE' | translate }}</th>
<td mat-cell *matCellDef="let event" data-e2e="event-type-cell">
<ng-container *ngIf="event | toobject as event">
<span *ngIf="event.type?.localized?.localizedMessage">{{ event.type.localized.localizedMessage }}</span>
</ng-container>
@if (event | toobject; as event) {
@if (event.type?.localized?.localizedMessage) {
<span>{{ event.type.localized.localizedMessage }}</span>
}
}
</td>
</ng-container>
<ng-container matColumnDef="payload">
<th mat-header-cell *matHeaderCellDef>{{ 'IAM.EVENTS.PAYLOAD' | translate }}</th>
<td mat-cell *matCellDef="let event">
<ng-container *ngIf="event | topayload as payload">
@if (event | topayload; as payload) {
<span>{{ payload | json }}</span>
<div class="btn-wrapper">
<button class="open-in-dialog-btn" mat-icon-button (click)="openDialog(event)">
<mat-icon svgIcon="mdi_arrow_expand"></mat-icon>
</button>
</div>
</ng-container>
}
</td>
</ng-container>
@@ -9,7 +9,9 @@
<div class="cnsl-action-button">
<i class="las la-filter no-margin"></i>
<span>{{ 'ACTIONS.FILTER' | translate }}</span>
<span *ngIf="queryCount" class="filter-count">{{ queryCount }}</span>
@if (queryCount) {
<span class="filter-count">{{ queryCount }}</span>
}
<cnsl-action-keys
[doNotUseContrast]="true"
[type]="ActionKeysType.FILTER"
@@ -37,190 +39,211 @@
{{ 'ACTIONS.APPLY' | translate }}
</button>
</div>
<form *ngIf="form" [formGroup]="form" (ngSubmit)="emitChange()">
<div *ngIf="isLoading" class="sp_wrapper"><mat-spinner diameter="20"></mat-spinner></div>
<div class="filter-events-section">
<div class="checkbox-wrapper">
<mat-checkbox id="userFilterSet" name="userFilterSet" class="cb" formControlName="userFilterSet"
>{{ 'IAM.EVENTS.FILTERS.USER.CHECKBOX' | translate }}
</mat-checkbox>
</div>
<div class="filter-events-sub" *ngIf="userFilterSet?.value">
<cnsl-form-field class="filter-input-value">
<cnsl-label>{{ 'IAM.EVENTS.FILTERS.USER.IDLABEL' | translate }}</cnsl-label>
<input cnslInput id="editorUserId" name="editorUserId" formControlName="editorUserId" />
</cnsl-form-field>
</div>
</div>
<div class="filter-events-section">
<div class="checkbox-wrapper">
<mat-checkbox id="aggregateFilterSet" name="aggregateFilterSet" class="cb" formControlName="aggregateFilterSet"
>{{ 'IAM.EVENTS.FILTERS.AGGREGATE.CHECKBOX' | translate }}
</mat-checkbox>
</div>
<div class="filter-events-sub" *ngIf="aggregateFilterSet?.value">
<cnsl-form-field class="aggregate-type-select">
<cnsl-label>{{ 'IAM.EVENTS.FILTERS.AGGREGATE.TYPELABEL' | translate }}</cnsl-label>
<mat-select
id="aggregateTypesList"
name="aggregateTypesList"
formControlName="aggregateTypesList"
[multiple]="true"
>
<mat-select-trigger>
<span *ngIf="aggregateTypesList?.value && aggregateTypesList?.value.length">{{
aggregateTypesList?.value[0]?.localized?.localizedMessage || ''
}}</span>
<small *ngIf="(aggregateTypesList?.value?.length || 0) > 1" class="cnsl-secondary-text">
(+{{ (aggregateTypesList?.value?.length || 0) - 1 }}
{{ aggregateTypesList?.value?.length === 2 ? 'other' : 'others' }})
</small>
</mat-select-trigger>
<mat-option *ngFor="let aggregate of aggregateTypes" [value]="aggregate">
<span *ngIf="aggregate.localized && aggregate.localized.localizedMessage">
{{ aggregate.localized.localizedMessage }}
</span>
</mat-option>
</mat-select>
</cnsl-form-field>
<cnsl-form-field class="filter-input-value">
<cnsl-label>{{ 'IAM.EVENTS.FILTERS.AGGREGATE.IDLABEL' | translate }}</cnsl-label>
<input id="aggregateId" formControlName="aggregateId" cnslInput name="aggregateId" />
</cnsl-form-field>
</div>
</div>
<div class="filter-events-section">
<div class="checkbox-wrapper">
<mat-checkbox
id="eventTypesFilterSet"
name="eventTypesFilterSet"
class="cb"
formControlName="eventTypesFilterSet"
data-e2e="event-type-filter-checkbox"
>{{ 'IAM.EVENTS.FILTERS.TYPE.CHECKBOX' | translate }}
</mat-checkbox>
</div>
<div class="filter-events-sub" *ngIf="eventTypesFilterSet?.value">
<cnsl-form-field class="event-types-select">
<cnsl-label>{{ 'IAM.EVENTS.FILTERS.TYPE.TYPELABEL' | translate }}</cnsl-label>
<mat-select id="eventTypesList" formControlName="eventTypesList" [multiple]="true">
<mat-select-trigger>
<span *ngIf="eventTypesList?.value && eventTypesList?.value.length">{{
eventTypesList?.value[0]?.localized?.localizedMessage || ''
}}</span>
<small *ngIf="(eventTypesList?.value?.length || 0) > 1" class="cnsl-secondary-text">
(+{{ (eventTypesList?.value?.length || 0) - 1 }}
{{ eventTypesList?.value?.length === 2 ? 'other' : 'others' }})
</small>
</mat-select-trigger>
<mat-option *ngFor="let eventType of eventTypes" [value]="eventType">
<ng-container *ngIf="eventType.localized && eventType.localized.localizedMessage">
{{ eventType.localized.localizedMessage }}
</ng-container>
</mat-option>
</mat-select>
</cnsl-form-field>
</div>
</div>
<div class="filter-events-section">
<div class="checkbox-wrapper">
<mat-checkbox
id="resourceOwnerFilterSet"
name="resourceOwnerFilterSet"
class="cb"
formControlName="resourceOwnerFilterSet"
>{{ 'IAM.EVENTS.FILTERS.RESOURCEOWNER.CHECKBOX' | translate }}
</mat-checkbox>
</div>
<div class="filter-events-sub" *ngIf="resourceOwnerFilterSet?.value">
<cnsl-form-field class="filter-input-value">
<cnsl-label>{{ 'IAM.EVENTS.FILTERS.RESOURCEOWNER.LABEL' | translate }}</cnsl-label>
<input cnslInput id="resourceOwner" name="resourceOwner" formControlName="resourceOwner" />
</cnsl-form-field>
</div>
</div>
<div class="filter-events-section">
<div class="checkbox-wrapper">
<mat-checkbox id="sequenceFilterSet" name="sequenceFilterSet" class="cb" formControlName="sequenceFilterSet"
>{{ 'IAM.EVENTS.FILTERS.SEQUENCE.CHECKBOX' | translate }}
</mat-checkbox>
</div>
<div class="filter-events-sub" *ngIf="sequenceFilterSet?.value">
<cnsl-form-field class="filter-input-value">
<cnsl-label>{{ 'IAM.EVENTS.FILTERS.SEQUENCE.LABEL' | translate }}</cnsl-label>
<input cnslInput id="sequence" name="sequence" formControlName="sequence" />
</cnsl-form-field>
</div>
</div>
<div class="filter-events-section">
<mat-radio-group aria-label="Select an option" class="filter-events-sub" formControlName="creationDateFilterType">
<mat-radio-button [value]="CreationDateFilterType.FROM">
{{ 'IAM.EVENTS.FILTERS.CREATIONDATE.RADIO_FROM' | translate }}
</mat-radio-button>
<mat-radio-button [value]="CreationDateFilterType.RANGE">
{{ 'IAM.EVENTS.FILTERS.CREATIONDATE.RADIO_RANGE' | translate }}
</mat-radio-button>
</mat-radio-group>
<div class="filter-events-sub">
<ng-container *ngIf="creationDateFilterType!.value === CreationDateFilterType.FROM">
<mat-form-field class="datetime-input">
<input
class="datetime"
matInput
type="datetime-local"
name="creationDateFrom"
[value]="creationDateFrom!.value | date: 'yyyy-MM-dd HH:mm:ss'"
(change)="creationDateFrom = $event.target"
/>
</mat-form-field>
</ng-container>
<ng-container *ngIf="creationDateFilterType!.value === CreationDateFilterType.RANGE">
<div class="datetime-range">
<mat-form-field class="datetime-input">
<cnsl-label
>{{ 'IAM.EVENTS.FILTERS.CREATIONDATE.LABEL_SINCE' | translate }}
<input
matInput
type="datetime-local"
name="creationDateSince"
[value]="creationDateSince!.value | date: 'yyyy-MM-dd HH:mm:ss'"
(change)="creationDateSince = $event.target"
/>
</cnsl-label>
</mat-form-field>
<mat-form-field class="datetime-input">
<cnsl-label
>{{ 'IAM.EVENTS.FILTERS.CREATIONDATE.LABEL_UNTIL' | translate }}
<input
matInput
type="datetime-local"
name="creationDateUntil"
[value]="creationDateUntil!.value | date: 'yyyy-MM-dd HH:mm:ss'"
(change)="creationDateUntil = $event.target"
/>
</cnsl-label>
</mat-form-field>
@if (form) {
<form [formGroup]="form" (ngSubmit)="emitChange()">
@if (isLoading) {
<div class="sp_wrapper"><mat-spinner diameter="20"></mat-spinner></div>
}
<div class="filter-events-section">
<div class="checkbox-wrapper">
<mat-checkbox id="userFilterSet" name="userFilterSet" class="cb" formControlName="userFilterSet"
>{{ 'IAM.EVENTS.FILTERS.USER.CHECKBOX' | translate }}
</mat-checkbox>
</div>
@if (userFilterSet?.value) {
<div class="filter-events-sub">
<cnsl-form-field class="filter-input-value">
<cnsl-label>{{ 'IAM.EVENTS.FILTERS.USER.IDLABEL' | translate }}</cnsl-label>
<input cnslInput id="editorUserId" name="editorUserId" formControlName="editorUserId" />
</cnsl-form-field>
</div>
</ng-container>
}
</div>
</div>
<div class="filter-events-section">
<cnsl-form-field class="aggregate-type-select">
<cnsl-label>{{ 'IAM.EVENTS.FILTERS.SORT' | translate }}</cnsl-label>
<mat-select id="isAsc" formControlName="isAsc">
<mat-option [value]="false"> {{ 'IAM.EVENTS.FILTERS.DESC' | translate }} </mat-option>
<mat-option [value]="true">{{ 'IAM.EVENTS.FILTERS.ASC' | translate }} </mat-option>
</mat-select>
</cnsl-form-field>
</div>
</form>
<div class="filter-events-section">
<div class="checkbox-wrapper">
<mat-checkbox id="aggregateFilterSet" name="aggregateFilterSet" class="cb" formControlName="aggregateFilterSet"
>{{ 'IAM.EVENTS.FILTERS.AGGREGATE.CHECKBOX' | translate }}
</mat-checkbox>
</div>
@if (aggregateFilterSet?.value) {
<div class="filter-events-sub">
<cnsl-form-field class="aggregate-type-select">
<cnsl-label>{{ 'IAM.EVENTS.FILTERS.AGGREGATE.TYPELABEL' | translate }}</cnsl-label>
<mat-select
id="aggregateTypesList"
name="aggregateTypesList"
formControlName="aggregateTypesList"
[multiple]="true"
>
<mat-select-trigger>
@if (aggregateTypesList?.value && aggregateTypesList?.value.length) {
<span>{{ aggregateTypesList?.value[0]?.localized?.localizedMessage || '' }}</span>
}
@if ((aggregateTypesList?.value?.length || 0) > 1) {
<small class="cnsl-secondary-text">
(+{{ (aggregateTypesList?.value?.length || 0) - 1 }}
{{ aggregateTypesList?.value?.length === 2 ? 'other' : 'others' }})
</small>
}
</mat-select-trigger>
@for (aggregate of aggregateTypes; track aggregate) {
<mat-option [value]="aggregate">
@if (aggregate.localized && aggregate.localized.localizedMessage) {
<span>
{{ aggregate.localized.localizedMessage }}
</span>
}
</mat-option>
}
</mat-select>
</cnsl-form-field>
<cnsl-form-field class="filter-input-value">
<cnsl-label>{{ 'IAM.EVENTS.FILTERS.AGGREGATE.IDLABEL' | translate }}</cnsl-label>
<input id="aggregateId" formControlName="aggregateId" cnslInput name="aggregateId" />
</cnsl-form-field>
</div>
}
</div>
<div class="filter-events-section">
<div class="checkbox-wrapper">
<mat-checkbox
id="eventTypesFilterSet"
name="eventTypesFilterSet"
class="cb"
formControlName="eventTypesFilterSet"
data-e2e="event-type-filter-checkbox"
>{{ 'IAM.EVENTS.FILTERS.TYPE.CHECKBOX' | translate }}
</mat-checkbox>
</div>
@if (eventTypesFilterSet?.value) {
<div class="filter-events-sub">
<cnsl-form-field class="event-types-select">
<cnsl-label>{{ 'IAM.EVENTS.FILTERS.TYPE.TYPELABEL' | translate }}</cnsl-label>
<mat-select id="eventTypesList" formControlName="eventTypesList" [multiple]="true">
<mat-select-trigger>
@if (eventTypesList?.value && eventTypesList?.value.length) {
<span>{{ eventTypesList?.value[0]?.localized?.localizedMessage || '' }}</span>
}
@if ((eventTypesList?.value?.length || 0) > 1) {
<small class="cnsl-secondary-text">
(+{{ (eventTypesList?.value?.length || 0) - 1 }}
{{ eventTypesList?.value?.length === 2 ? 'other' : 'others' }})
</small>
}
</mat-select-trigger>
@for (eventType of eventTypes; track eventType) {
<mat-option [value]="eventType">
@if (eventType.localized && eventType.localized.localizedMessage) {
{{ eventType.localized.localizedMessage }}
}
</mat-option>
}
</mat-select>
</cnsl-form-field>
</div>
}
</div>
<div class="filter-events-section">
<div class="checkbox-wrapper">
<mat-checkbox
id="resourceOwnerFilterSet"
name="resourceOwnerFilterSet"
class="cb"
formControlName="resourceOwnerFilterSet"
>{{ 'IAM.EVENTS.FILTERS.RESOURCEOWNER.CHECKBOX' | translate }}
</mat-checkbox>
</div>
@if (resourceOwnerFilterSet?.value) {
<div class="filter-events-sub">
<cnsl-form-field class="filter-input-value">
<cnsl-label>{{ 'IAM.EVENTS.FILTERS.RESOURCEOWNER.LABEL' | translate }}</cnsl-label>
<input cnslInput id="resourceOwner" name="resourceOwner" formControlName="resourceOwner" />
</cnsl-form-field>
</div>
}
</div>
<div class="filter-events-section">
<div class="checkbox-wrapper">
<mat-checkbox id="sequenceFilterSet" name="sequenceFilterSet" class="cb" formControlName="sequenceFilterSet"
>{{ 'IAM.EVENTS.FILTERS.SEQUENCE.CHECKBOX' | translate }}
</mat-checkbox>
</div>
@if (sequenceFilterSet?.value) {
<div class="filter-events-sub">
<cnsl-form-field class="filter-input-value">
<cnsl-label>{{ 'IAM.EVENTS.FILTERS.SEQUENCE.LABEL' | translate }}</cnsl-label>
<input cnslInput id="sequence" name="sequence" formControlName="sequence" />
</cnsl-form-field>
</div>
}
</div>
<div class="filter-events-section">
<mat-radio-group
aria-label="Select an option"
class="filter-events-sub"
formControlName="creationDateFilterType"
>
<mat-radio-button [value]="CreationDateFilterType.FROM">
{{ 'IAM.EVENTS.FILTERS.CREATIONDATE.RADIO_FROM' | translate }}
</mat-radio-button>
<mat-radio-button [value]="CreationDateFilterType.RANGE">
{{ 'IAM.EVENTS.FILTERS.CREATIONDATE.RADIO_RANGE' | translate }}
</mat-radio-button>
</mat-radio-group>
<div class="filter-events-sub">
@if (creationDateFilterType!.value === CreationDateFilterType.FROM) {
<mat-form-field class="datetime-input">
<input
class="datetime"
matInput
type="datetime-local"
name="creationDateFrom"
[value]="creationDateFrom!.value | date: 'yyyy-MM-dd HH:mm:ss'"
(change)="creationDateFrom = $event.target"
/>
</mat-form-field>
}
@if (creationDateFilterType!.value === CreationDateFilterType.RANGE) {
<div class="datetime-range">
<mat-form-field class="datetime-input">
<cnsl-label
>{{ 'IAM.EVENTS.FILTERS.CREATIONDATE.LABEL_SINCE' | translate }}
<input
matInput
type="datetime-local"
name="creationDateSince"
[value]="creationDateSince!.value | date: 'yyyy-MM-dd HH:mm:ss'"
(change)="creationDateSince = $event.target"
/>
</cnsl-label>
</mat-form-field>
<mat-form-field class="datetime-input">
<cnsl-label
>{{ 'IAM.EVENTS.FILTERS.CREATIONDATE.LABEL_UNTIL' | translate }}
<input
matInput
type="datetime-local"
name="creationDateUntil"
[value]="creationDateUntil!.value | date: 'yyyy-MM-dd HH:mm:ss'"
(change)="creationDateUntil = $event.target"
/>
</cnsl-label>
</mat-form-field>
</div>
}
</div>
</div>
<div class="filter-events-section">
<cnsl-form-field class="aggregate-type-select">
<cnsl-label>{{ 'IAM.EVENTS.FILTERS.SORT' | translate }}</cnsl-label>
<mat-select id="isAsc" formControlName="isAsc">
<mat-option [value]="false"> {{ 'IAM.EVENTS.FILTERS.DESC' | translate }} </mat-option>
<mat-option [value]="true">{{ 'IAM.EVENTS.FILTERS.ASC' | translate }} </mat-option>
</mat-select>
</cnsl-form-field>
</div>
</form>
}
</div>
</ng-template>
</div>
@@ -8,19 +8,22 @@
(change)="changeCheckbox(SubQuery.NAME, $event)"
>{{ 'FILTER.ORGNAME' | translate }}
</mat-checkbox>
<div class="subquery" *ngIf="getSubFilter(SubQuery.NAME) as eq">
<cnsl-form-field class="filter-select-method">
<mat-select [value]="eq.getMethod()" (selectionChange)="setMethod(eq, $event)">
<mat-option *ngFor="let method of methods" [value]="method">
{{ 'FILTER.METHODS.' + method | translate }}
</mat-option>
</mat-select>
</cnsl-form-field>
<cnsl-form-field class="filter-input-value">
<input cnslInput name="value" [value]="eq.getName()" (change)="setValue(SubQuery.NAME, eq, $event)" />
</cnsl-form-field>
</div>
@if (getSubFilter(SubQuery.NAME); as eq) {
<div class="subquery">
<cnsl-form-field class="filter-select-method">
<mat-select [value]="eq.getMethod()" (selectionChange)="setMethod(eq, $event)">
@for (method of methods; track method) {
<mat-option [value]="method">
{{ 'FILTER.METHODS.' + method | translate }}
</mat-option>
}
</mat-select>
</cnsl-form-field>
<cnsl-form-field class="filter-input-value">
<input cnslInput name="value" [value]="eq.getName()" (change)="setValue(SubQuery.NAME, eq, $event)" />
</cnsl-form-field>
</div>
}
</div>
<div class="name-query">
@@ -31,19 +34,22 @@
(change)="changeCheckbox(SubQuery.STATE, $event)"
>{{ 'FILTER.STATE' | translate }}
</mat-checkbox>
<div class="subquery" *ngIf="getSubFilter(SubQuery.STATE) as sq">
<span class="nomethod cnsl-secondary-text">
{{ 'FILTER.METHODS.1' | translate }}
</span>
<cnsl-form-field class="filter-select-value">
<mat-select [value]="sq.getState()" (selectionChange)="setValue(SubQuery.STATE, sq, $event)">
<mat-option *ngFor="let state of states" [value]="state">
{{ 'USER.STATE.' + state | translate }}
</mat-option>
</mat-select>
</cnsl-form-field>
</div>
@if (getSubFilter(SubQuery.STATE); as sq) {
<div class="subquery">
<span class="nomethod cnsl-secondary-text">
{{ 'FILTER.METHODS.1' | translate }}
</span>
<cnsl-form-field class="filter-select-value">
<mat-select [value]="sq.getState()" (selectionChange)="setValue(SubQuery.STATE, sq, $event)">
@for (state of states; track state) {
<mat-option [value]="state">
{{ 'USER.STATE.' + state | translate }}
</mat-option>
}
</mat-select>
</cnsl-form-field>
</div>
}
</div>
</div>
@@ -55,33 +61,37 @@
(change)="changeCheckbox(SubQuery.DOMAIN, $event)"
>{{ 'FILTER.PRIMARYDOMAIN' | translate }}
</mat-checkbox>
<div class="subquery" *ngIf="getSubFilter(SubQuery.DOMAIN) as dq">
<cnsl-form-field class="filter-select-method">
<mat-select [value]="dq.getMethod()" (selectionChange)="setMethod(dq, $event)">
<mat-option *ngFor="let method of methods" [value]="method">
{{ 'FILTER.METHODS.' + method | translate }}
</mat-option>
</mat-select>
</cnsl-form-field>
<cnsl-form-field class="filter-input-value">
<input cnslInput name="value" [value]="dq.getDomain()" (change)="setValue(SubQuery.DOMAIN, dq, $event)" />
</cnsl-form-field>
</div>
@if (getSubFilter(SubQuery.DOMAIN); as dq) {
<div class="subquery">
<cnsl-form-field class="filter-select-method">
<mat-select [value]="dq.getMethod()" (selectionChange)="setMethod(dq, $event)">
@for (method of methods; track method) {
<mat-option [value]="method">
{{ 'FILTER.METHODS.' + method | translate }}
</mat-option>
}
</mat-select>
</cnsl-form-field>
<cnsl-form-field class="filter-input-value">
<input cnslInput name="value" [value]="dq.getDomain()" (change)="setValue(SubQuery.DOMAIN, dq, $event)" />
</cnsl-form-field>
</div>
}
</div>
<div class="id-query">
<mat-checkbox id="id" class="cb" [checked]="getSubFilter(SubQuery.ID)" (change)="changeCheckbox(SubQuery.ID, $event)"
>{{ 'FILTER.ORGID' | translate }}
</mat-checkbox>
<div class="subquery" *ngIf="getSubFilter(SubQuery.ID) as idq">
<span class="nomethod cnsl-secondary-text">
{{ 'FILTER.METHODS.1' | translate }}
</span>
<cnsl-form-field class="filter-input-value">
<input cnslInput name="value" [value]="idq.getId()" (change)="setValue(SubQuery.ID, idq, $event)" />
</cnsl-form-field>
</div>
@if (getSubFilter(SubQuery.ID); as idq) {
<div class="subquery">
<span class="nomethod cnsl-secondary-text">
{{ 'FILTER.METHODS.1' | translate }}
</span>
<cnsl-form-field class="filter-input-value">
<input cnslInput name="value" [value]="idq.getId()" (change)="setValue(SubQuery.ID, idq, $event)" />
</cnsl-form-field>
</div>
}
</div>
</cnsl-filter>
@@ -8,19 +8,22 @@
(change)="changeCheckbox(SubQuery.NAME, $event)"
>{{ 'FILTER.PROJECTNAME' | translate }}
</mat-checkbox>
<div class="subquery" *ngIf="getSubFilter(SubQuery.NAME) as eq">
<cnsl-form-field class="filter-select-method">
<mat-select [value]="eq.getMethod()" (selectionChange)="setMethod(eq, $event)">
<mat-option *ngFor="let method of methods" [value]="method">
{{ 'FILTER.METHODS.' + method | translate }}
</mat-option>
</mat-select>
</cnsl-form-field>
<cnsl-form-field class="filter-input-value">
<input cnslInput name="value" [value]="eq.getName()" (change)="setValue(SubQuery.NAME, eq, $event)" />
</cnsl-form-field>
</div>
@if (getSubFilter(SubQuery.NAME); as eq) {
<div class="subquery">
<cnsl-form-field class="filter-select-method">
<mat-select [value]="eq.getMethod()" (selectionChange)="setMethod(eq, $event)">
@for (method of methods; track method) {
<mat-option [value]="method">
{{ 'FILTER.METHODS.' + method | translate }}
</mat-option>
}
</mat-select>
</cnsl-form-field>
<cnsl-form-field class="filter-input-value">
<input cnslInput name="value" [value]="eq.getName()" (change)="setValue(SubQuery.NAME, eq, $event)" />
</cnsl-form-field>
</div>
}
</div>
</div>
</cnsl-filter>
@@ -8,24 +8,27 @@
(change)="changeCheckbox(SubQuery.DISPLAYNAME, $event)"
>{{ 'FILTER.DISPLAYNAME' | translate }}
</mat-checkbox>
<div class="subquery" *ngIf="getSubFilter(SubQuery.DISPLAYNAME) as dnq">
<cnsl-form-field class="filter-select-method">
<mat-select [value]="dnq.getMethod()" (selectionChange)="setMethod(dnq, $event)">
<mat-option *ngFor="let method of methods" [value]="method">
{{ 'FILTER.METHODS.' + method | translate }}
</mat-option>
</mat-select>
</cnsl-form-field>
<cnsl-form-field class="filter-input-value">
<input
cnslInput
name="value"
[value]="dnq.getDisplayName()"
(change)="setValue(SubQuery.DISPLAYNAME, dnq, $event)"
/>
</cnsl-form-field>
</div>
@if (getSubFilter(SubQuery.DISPLAYNAME); as dnq) {
<div class="subquery">
<cnsl-form-field class="filter-select-method">
<mat-select [value]="dnq.getMethod()" (selectionChange)="setMethod(dnq, $event)">
@for (method of methods; track method) {
<mat-option [value]="method">
{{ 'FILTER.METHODS.' + method | translate }}
</mat-option>
}
</mat-select>
</cnsl-form-field>
<cnsl-form-field class="filter-input-value">
<input
cnslInput
name="value"
[value]="dnq.getDisplayName()"
(change)="setValue(SubQuery.DISPLAYNAME, dnq, $event)"
/>
</cnsl-form-field>
</div>
}
</div>
<div class="usernane-query">
@@ -36,19 +39,22 @@
(change)="changeCheckbox(SubQuery.USERNAME, $event)"
>{{ 'FILTER.USERNAME' | translate }}
</mat-checkbox>
<div class="subquery" *ngIf="getSubFilter(SubQuery.USERNAME) as unq">
<cnsl-form-field class="filter-select-method">
<mat-select [value]="unq.getMethod()" (selectionChange)="setMethod(unq, $event)">
<mat-option *ngFor="let method of methods" [value]="method">
{{ 'FILTER.METHODS.' + method | translate }}
</mat-option>
</mat-select>
</cnsl-form-field>
<cnsl-form-field class="filter-input-value">
<input cnslInput name="value" [value]="unq.getUserName()" (change)="setValue(SubQuery.USERNAME, unq, $event)" />
</cnsl-form-field>
</div>
@if (getSubFilter(SubQuery.USERNAME); as unq) {
<div class="subquery">
<cnsl-form-field class="filter-select-method">
<mat-select [value]="unq.getMethod()" (selectionChange)="setMethod(unq, $event)">
@for (method of methods; track method) {
<mat-option [value]="method">
{{ 'FILTER.METHODS.' + method | translate }}
</mat-option>
}
</mat-select>
</cnsl-form-field>
<cnsl-form-field class="filter-input-value">
<input cnslInput name="value" [value]="unq.getUserName()" (change)="setValue(SubQuery.USERNAME, unq, $event)" />
</cnsl-form-field>
</div>
}
</div>
<div class="email-query">
@@ -59,19 +65,22 @@
(change)="changeCheckbox(SubQuery.ORGNAME, $event)"
>{{ 'FILTER.ORGNAME' | translate }}
</mat-checkbox>
<div class="subquery" *ngIf="getSubFilter(SubQuery.ORGNAME) as onq">
<cnsl-form-field class="filter-select-method">
<mat-select [value]="onq.getMethod()" (selectionChange)="setMethod(onq, $event)">
<mat-option *ngFor="let method of methods" [value]="method">
{{ 'FILTER.METHODS.' + method | translate }}
</mat-option>
</mat-select>
</cnsl-form-field>
<cnsl-form-field class="filter-input-value">
<input cnslInput name="value" [value]="onq.getOrgName()" (change)="setValue(SubQuery.ORGNAME, onq, $event)" />
</cnsl-form-field>
</div>
@if (getSubFilter(SubQuery.ORGNAME); as onq) {
<div class="subquery">
<cnsl-form-field class="filter-select-method">
<mat-select [value]="onq.getMethod()" (selectionChange)="setMethod(onq, $event)">
@for (method of methods; track method) {
<mat-option [value]="method">
{{ 'FILTER.METHODS.' + method | translate }}
</mat-option>
}
</mat-select>
</cnsl-form-field>
<cnsl-form-field class="filter-input-value">
<input cnslInput name="value" [value]="onq.getOrgName()" (change)="setValue(SubQuery.ORGNAME, onq, $event)" />
</cnsl-form-field>
</div>
}
</div>
<div class="email-query">
@@ -82,24 +91,27 @@
(change)="changeCheckbox(SubQuery.PROJECTNAME, $event)"
>{{ 'FILTER.PROJECTNAME' | translate }}
</mat-checkbox>
<div class="subquery" *ngIf="getSubFilter(SubQuery.PROJECTNAME) as pnq">
<cnsl-form-field class="filter-select-method">
<mat-select [value]="pnq.getMethod()" (selectionChange)="setMethod(pnq, $event)">
<mat-option *ngFor="let method of methods" [value]="method">
{{ 'FILTER.METHODS.' + method | translate }}
</mat-option>
</mat-select>
</cnsl-form-field>
<cnsl-form-field class="filter-input-value">
<input
cnslInput
name="value"
[value]="pnq.getProjectName()"
(change)="setValue(SubQuery.PROJECTNAME, pnq, $event)"
/>
</cnsl-form-field>
</div>
@if (getSubFilter(SubQuery.PROJECTNAME); as pnq) {
<div class="subquery">
<cnsl-form-field class="filter-select-method">
<mat-select [value]="pnq.getMethod()" (selectionChange)="setMethod(pnq, $event)">
@for (method of methods; track method) {
<mat-option [value]="method">
{{ 'FILTER.METHODS.' + method | translate }}
</mat-option>
}
</mat-select>
</cnsl-form-field>
<cnsl-form-field class="filter-input-value">
<input
cnslInput
name="value"
[value]="pnq.getProjectName()"
(change)="setValue(SubQuery.PROJECTNAME, pnq, $event)"
/>
</cnsl-form-field>
</div>
}
</div>
</div>
</cnsl-filter>
@@ -8,19 +8,22 @@
(change)="changeCheckbox(SubQuery.STATE, $event)"
>{{ 'FILTER.STATE' | translate }}
</mat-checkbox>
<div class="subquery" *ngIf="getSubFilter(SubQuery.STATE) as sq">
<span class="nomethod cnsl-secondary-text">
{{ 'FILTER.METHODS.1' | translate }}
</span>
<cnsl-form-field class="filter-select-value">
<mat-select [value]="sq.getState()" (selectionChange)="setValue(SubQuery.STATE, sq, $event)">
<mat-option *ngFor="let state of states" [value]="state">
{{ 'USER.STATE.' + state | translate }}
</mat-option>
</mat-select>
</cnsl-form-field>
</div>
@if (getSubFilter(SubQuery.STATE); as sq) {
<div class="subquery">
<span class="nomethod cnsl-secondary-text">
{{ 'FILTER.METHODS.1' | translate }}
</span>
<cnsl-form-field class="filter-select-value">
<mat-select [value]="sq.getState()" (selectionChange)="setValue(SubQuery.STATE, sq, $event)">
@for (state of states; track state) {
<mat-option [value]="state">
{{ 'USER.STATE.' + state | translate }}
</mat-option>
}
</mat-select>
</cnsl-form-field>
</div>
}
</div>
<div class="name-query">
@@ -31,24 +34,27 @@
(change)="changeCheckbox(SubQuery.DISPLAYNAME, $event)"
>{{ 'FILTER.DISPLAYNAME' | translate }}
</mat-checkbox>
<div class="subquery" *ngIf="getSubFilter(SubQuery.DISPLAYNAME) as dnq">
<cnsl-form-field class="filter-select-method">
<mat-select [value]="dnq.getMethod()" (selectionChange)="setMethod(dnq, $event)">
<mat-option *ngFor="let method of methods" [value]="method">
{{ 'FILTER.METHODS.' + method | translate }}
</mat-option>
</mat-select>
</cnsl-form-field>
<cnsl-form-field class="filter-input-value">
<input
cnslInput
name="value"
[value]="dnq.getDisplayName()"
(change)="setValue(SubQuery.DISPLAYNAME, dnq, $event)"
/>
</cnsl-form-field>
</div>
@if (getSubFilter(SubQuery.DISPLAYNAME); as dnq) {
<div class="subquery">
<cnsl-form-field class="filter-select-method">
<mat-select [value]="dnq.getMethod()" (selectionChange)="setMethod(dnq, $event)">
@for (method of methods; track method) {
<mat-option [value]="method">
{{ 'FILTER.METHODS.' + method | translate }}
</mat-option>
}
</mat-select>
</cnsl-form-field>
<cnsl-form-field class="filter-input-value">
<input
cnslInput
name="value"
[value]="dnq.getDisplayName()"
(change)="setValue(SubQuery.DISPLAYNAME, dnq, $event)"
/>
</cnsl-form-field>
</div>
}
</div>
<div class="email-query">
@@ -59,19 +65,22 @@
(change)="changeCheckbox(SubQuery.EMAIL, $event)"
>{{ 'FILTER.EMAIL' | translate }}
</mat-checkbox>
<div class="subquery" *ngIf="getSubFilter(SubQuery.EMAIL) as eq">
<cnsl-form-field class="filter-select-method">
<mat-select [value]="eq.getMethod()" (selectionChange)="setMethod(eq, $event)">
<mat-option *ngFor="let method of methods" [value]="method">
{{ 'FILTER.METHODS.' + method | translate }}
</mat-option>
</mat-select>
</cnsl-form-field>
<cnsl-form-field class="filter-input-value">
<input cnslInput name="value" [value]="eq.getEmailAddress()" (change)="setValue(SubQuery.EMAIL, eq, $event)" />
</cnsl-form-field>
</div>
@if (getSubFilter(SubQuery.EMAIL); as eq) {
<div class="subquery">
<cnsl-form-field class="filter-select-method">
<mat-select [value]="eq.getMethod()" (selectionChange)="setMethod(eq, $event)">
@for (method of methods; track method) {
<mat-option [value]="method">
{{ 'FILTER.METHODS.' + method | translate }}
</mat-option>
}
</mat-select>
</cnsl-form-field>
<cnsl-form-field class="filter-input-value">
<input cnslInput name="value" [value]="eq.getEmailAddress()" (change)="setValue(SubQuery.EMAIL, eq, $event)" />
</cnsl-form-field>
</div>
}
</div>
<div class="usernane-query">
@@ -82,19 +91,22 @@
(change)="changeCheckbox(SubQuery.USERNAME, $event)"
>{{ 'FILTER.USERNAME' | translate }}
</mat-checkbox>
<div class="subquery" *ngIf="getSubFilter(SubQuery.USERNAME) as unq">
<cnsl-form-field class="filter-select-method">
<mat-select [value]="unq.getMethod()" (selectionChange)="setMethod(unq, $event)">
<mat-option *ngFor="let method of methods" [value]="method">
{{ 'FILTER.METHODS.' + method | translate }}
</mat-option>
</mat-select>
</cnsl-form-field>
<cnsl-form-field class="filter-input-value">
<input cnslInput name="value" [value]="unq.getUserName()" (change)="setValue(SubQuery.USERNAME, unq, $event)" />
</cnsl-form-field>
</div>
@if (getSubFilter(SubQuery.USERNAME); as unq) {
<div class="subquery">
<cnsl-form-field class="filter-select-method">
<mat-select [value]="unq.getMethod()" (selectionChange)="setMethod(unq, $event)">
@for (method of methods; track method) {
<mat-option [value]="method">
{{ 'FILTER.METHODS.' + method | translate }}
</mat-option>
}
</mat-select>
</cnsl-form-field>
<cnsl-form-field class="filter-input-value">
<input cnslInput name="value" [value]="unq.getUserName()" (change)="setValue(SubQuery.USERNAME, unq, $event)" />
</cnsl-form-field>
</div>
}
</div>
</div>
</cnsl-filter>
@@ -3,7 +3,9 @@
<div class="cnsl-action-button">
<i class="las la-filter no-margin"></i>
<span>{{ 'ACTIONS.FILTER' | translate }}</span>
<span *ngIf="queryCount" class="filter-count">{{ queryCount }}</span>
@if (queryCount) {
<span class="filter-count">{{ queryCount }}</span>
}
<cnsl-action-keys [doNotUseContrast]="true" [type]="ActionKeysType.FILTER" (actionTriggered)="toggleFilter()">
</cnsl-action-keys>
</div>
@@ -1,35 +1,43 @@
<div class="footer-wrapper">
<div class="footer-row">
<div class="footer-links" *ngIf="authService.privacypolicy$ | async as pP">
<a target="_blank" *ngIf="pP?.tosLink" rel="noreferrer" [href]="pP?.tosLink" external>
<span>{{ 'FOOTER.LINKS.TOS' | translate }}</span>
<i class="las la-external-link-alt"></i>
</a>
<a target="_blank" *ngIf="pP?.privacyLink" rel="noreferrer" [href]="pP?.privacyLink" external>
<span>{{ 'FOOTER.LINKS.PP' | translate }}</span>
<i class="las la-external-link-alt"></i>
</a>
</div>
@if (authService.privacypolicy$ | async; as pP) {
<div class="footer-links">
@if (pP?.tosLink) {
<a target="_blank" rel="noreferrer" [href]="pP?.tosLink" external>
<span>{{ 'FOOTER.LINKS.TOS' | translate }}</span>
<i class="las la-external-link-alt"></i>
</a>
}
@if (pP?.privacyLink) {
<a target="_blank" rel="noreferrer" [href]="pP?.privacyLink" external>
<span>{{ 'FOOTER.LINKS.PP' | translate }}</span>
<i class="las la-external-link-alt"></i>
</a>
}
</div>
}
<div class="footer-socials" *ngIf="authService.labelpolicy$ | async as lP">
<ng-container *ngIf="lP?.disableWatermark === false">
<a target="_blank" rel="noreferrer" href="https://github.com/zitadel">
<i class="text-3xl lab la-github"></i>
</a>
<a target="_blank" rel="noreferrer" href="https://twitter.com/zitadel">
<fa-icon [icon]="faXTwitter" size="xl"></fa-icon>
</a>
<a target="_blank" rel="noreferrer" href="https://www.linkedin.com/company/zitadel/">
<i class="text-3xl lab la-linkedin"></i>
</a>
<a target="_blank" rel="noreferrer" href="https://zitadel.com/chat">
<i class="text-3xl lab la-discord"></i>
</a>
<a target="_blank" rel="noreferrer" href="https://www.youtube.com/channel/UCUAWJUNYaRn1yIVrZxEfsuA">
<i class="text-3xl lab la-youtube"></i>
</a>
</ng-container>
</div>
@if (authService.labelpolicy$ | async; as lP) {
<div class="footer-socials">
@if (lP?.disableWatermark === false) {
<a target="_blank" rel="noreferrer" href="https://github.com/zitadel">
<i class="text-3xl lab la-github"></i>
</a>
<a target="_blank" rel="noreferrer" href="https://twitter.com/zitadel">
<fa-icon [icon]="faXTwitter" size="xl"></fa-icon>
</a>
<a target="_blank" rel="noreferrer" href="https://www.linkedin.com/company/zitadel/">
<i class="text-3xl lab la-linkedin"></i>
</a>
<a target="_blank" rel="noreferrer" href="https://zitadel.com/chat">
<i class="text-3xl lab la-discord"></i>
</a>
<a target="_blank" rel="noreferrer" href="https://www.youtube.com/channel/UCUAWJUNYaRn1yIVrZxEfsuA">
<i class="text-3xl lab la-youtube"></i>
</a>
}
</div>
}
<div class="theme">
<cnsl-theme-setting></cnsl-theme-setting>
@@ -1,9 +1,9 @@
<ng-template #labelTemplate>
<label class="cnsl-label-wrapper" [attr.for]="_control.id" [attr.aria-owns]="_control.id">
<ng-content select="cnsl-label"></ng-content>
<span *ngIf="_control.required && !hideRequiredMarker" aria-hidden="true" class="cnsl-form-field-required-marker"
>*</span
>
@if (_control.required && !hideRequiredMarker) {
<span aria-hidden="true" class="cnsl-form-field-required-marker">*</span>
}
</label>
</ng-template>
@@ -13,17 +13,25 @@
<ng-content></ng-content>
<ng-content select="cnslSuffix"></ng-content>
</div>
<ng-container *ngIf="help$ && help$ | async as help">
<div [ngSwitch]="help.type" class="cnsl-form-field-subscript-wrapper">
<div *ngSwitchCase="'hints'" class="cnsl-form-field-hint-wrapper" [@transitionMessages]="_subscriptAnimationState">
<ng-content select="cnsl-hint"></ng-content>
</div>
<div *ngSwitchCase="'errors'" class="cnsl-form-field-error-wrapper" [@transitionMessages]="_subscriptAnimationState">
<span cnslError *ngFor="let err of help.validationErrors">
{{ err.i18nKey | translate: err.params }}
</span>
<ng-content select="cnsl-error"></ng-content>
</div>
@if (help$ && help$ | async; as help) {
<div class="cnsl-form-field-subscript-wrapper">
@switch (help.type) {
@case ('hints') {
<div class="cnsl-form-field-hint-wrapper" [@transitionMessages]="_subscriptAnimationState">
<ng-content select="cnsl-hint"></ng-content>
</div>
}
@case ('errors') {
<div class="cnsl-form-field-error-wrapper" [@transitionMessages]="_subscriptAnimationState">
@for (err of help.validationErrors; track err) {
<span cnslError>
{{ err.i18nKey | translate: err.params }}
</span>
}
<ng-content select="cnsl-error"></ng-content>
</div>
}
}
</div>
</ng-container>
}
</div>
@@ -1,44 +1,41 @@
<mat-toolbar class="header-wrapper">
<div class="header-content">
<div *ngIf="authService.labelPolicyLoading$ | async; else logo" class="logo-placeholder">
<mat-spinner [diameter]="20"></mat-spinner>
</div>
<ng-template #logo>
<a class="title custom" [routerLink]="['/']" *ngIf="authService.labelpolicy$ | async as lP; else defaultHome">
<img
class="logo"
alt="home logo"
*ngIf="isDarkTheme; else customlighttheme"
[src]="lP.iconUrlDark ? lP.iconUrlDark : './assets/images/zitadel-logo-solo-light.svg'"
(error)="errorHandler($event, './assets/images/zitadel-logo-solo-light.svg')"
/>
<ng-template #customlighttheme>
<img
alt="home logo"
class="logo"
[src]="lP.iconUrl ? lP.iconUrl : './assets/images/zitadel-logo-solo-dark.svg'"
(error)="errorHandler($event, './assets/images/zitadel-logo-solo-dark.svg')"
/>
</ng-template>
</a>
</ng-template>
<ng-template #defaultHome>
<a class="title" [routerLink]="(authService.zitadelPermissions | async)?.length ? ['/'] : ['/users', 'me']">
<img
class="logo"
alt="zitadel logo"
*ngIf="isDarkTheme; else lighttheme"
src="./assets/images/zitadel-logo-solo-light.svg"
/>
<ng-template #lighttheme>
<img alt="zitadel logo" class="logo" src="./assets/images/zitadel-logo-solo-dark.svg" />
</ng-template>
</a>
</ng-template>
@if (authService.labelPolicyLoading$ | async) {
<div class="logo-placeholder">
<mat-spinner [diameter]="20"></mat-spinner>
</div>
} @else {
@if (authService.labelpolicy$ | async; as lP) {
<a class="title custom" [routerLink]="['/']">
@if (isDarkTheme) {
<img
class="logo"
alt="home logo"
[src]="lP.iconUrlDark ? lP.iconUrlDark : './assets/images/zitadel-logo-solo-light.svg'"
(error)="errorHandler($event, './assets/images/zitadel-logo-solo-light.svg')"
/>
} @else {
<img
alt="home logo"
class="logo"
[src]="lP.iconUrl ? lP.iconUrl : './assets/images/zitadel-logo-solo-dark.svg'"
(error)="errorHandler($event, './assets/images/zitadel-logo-solo-dark.svg')"
/>
}
</a>
} @else {
<a class="title" [routerLink]="(authService.zitadelPermissions | async)?.length ? ['/'] : ['/users', 'me']">
@if (isDarkTheme) {
<img class="logo" alt="zitadel logo" src="./assets/images/zitadel-logo-solo-light.svg" />
} @else {
<img alt="zitadel logo" class="logo" src="./assets/images/zitadel-logo-solo-dark.svg" />
}
</a>
}
}
<ng-container *ngFor="let bread of breadcrumbService.breadcrumbs$ | async as bc; index as i">
<ng-container *ngIf="bread.type === BreadcrumbType.INSTANCE">
@if (bread.type === BreadcrumbType.INSTANCE) {
<ng-template cnslHasRole [hasRole]="['iam.read']">
<svg
class="slash hide-on-small"
@@ -53,16 +50,15 @@
>
<path d="M16.88 3.549L7.12 20.451"></path>
</svg>
<div class="breadcrumb-context hide-on-small">
<a matRipple [matRippleUnbounded]="false" class="breadcrumb-link" [routerLink]="bread.routerLink">
{{ 'MENU.INSTANCE' | translate }}
</a>
</div>
</ng-template>
</ng-container>
}
<ng-container *ngIf="bread.type === BreadcrumbType.ORG">
@if (bread.type === BreadcrumbType.ORG) {
<svg
class="slash"
viewBox="0 0 24 24"
@@ -76,20 +72,13 @@
>
<path d="M16.88 3.549L7.12 20.451"></path>
</svg>
<div class="org-context">
<a
*ngIf="org() as org"
matRipple
[matRippleUnbounded]="false"
class="org-link"
id="orglink"
[routerLink]="['/org']"
>
{{ org.name ? org.name : 'NO NAME' }}</a
>
<div class="org-context-wrapper" *ngIf="org">
@if (org(); as org) {
<a matRipple [matRippleUnbounded]="false" class="org-link" id="orglink" [routerLink]="['/org']">
{{ org.name ? org.name : 'NO NAME' }}</a
>
}
<div class="org-context-wrapper">
<button
cdkOverlayOrigin
#trigger="cdkOverlayOrigin"
@@ -113,7 +102,6 @@
[type]="ActionKeysType.ORGSWITCHER"
></cnsl-action-keys>
</button>
<ng-template
cdkConnectedOverlay
[cdkConnectedOverlayOrigin]="trigger"
@@ -125,20 +113,21 @@
(backdropClick)="showOrgContext = false"
(detach)="showOrgContext = false"
>
<cnsl-org-context
class="context_card"
*ngIf="showOrgContext && org() as org"
(closedCard)="showOrgContext = false"
[org]="org"
(setOrg)="setActiveOrg($event)"
>
</cnsl-org-context>
@if (showOrgContext && org(); as org) {
<cnsl-org-context
class="context_card"
(closedCard)="showOrgContext = false"
[org]="org"
(setOrg)="setActiveOrg($event)"
>
</cnsl-org-context>
}
</ng-template>
</div>
</div>
</ng-container>
}
<ng-container *ngIf="bread.type !== BreadcrumbType.INSTANCE && bread.type !== BreadcrumbType.ORG">
@if (bread.type !== BreadcrumbType.INSTANCE && bread.type !== BreadcrumbType.ORG) {
<svg
class="slash"
viewBox="0 0 24 24"
@@ -152,7 +141,6 @@
>
<path d="M16.88 3.549L7.12 20.451"></path>
</svg>
<div class="breadcrumb-context">
<a
matRipple
@@ -161,58 +149,54 @@
[ngClass]="{ maxwidth: bc.length > 1 }"
[routerLink]="bread.routerLink"
>
<ng-container *ngIf="i !== bc.length - 1; else defLabel">
@if (i !== bc.length - 1) {
<span class="desk">{{ bread.name }}</span>
<span class="mob">...</span>
</ng-container>
<ng-template #defLabel>
} @else {
<span>{{ bread.name }}</span>
</ng-template>
}
</a>
</div>
</ng-container>
}
</ng-container>
<span class="fill-space"></span>
<ng-container *ngIf="authService.privacypolicy$ | async as pP">
<a class="custom-link" *ngIf="pP.customLink" href="{{ pP.customLink }}" mat-stroked-button target="_blank">
{{ pP.customLinkText }}
</a>
@if (authService.privacypolicy$ | async; as pP) {
@if (pP.customLink) {
<a class="custom-link" href="{{ pP.customLink }}" mat-stroked-button target="_blank">
{{ pP.customLinkText }}
</a>
}
@if (pP.docsLink) {
<a class="doc-link" href="{{ pP.docsLink }}" mat-stroked-button target="_blank">
{{ 'MENU.DOCUMENTATION' | translate }}
</a>
}
}
<a class="doc-link" *ngIf="pP.docsLink" href="{{ pP.docsLink }}" mat-stroked-button target="_blank">
{{ 'MENU.DOCUMENTATION' | translate }}
</a>
</ng-container>
@if (!isOnMe) {
<div class="system-rel">
@if (!isOnInstance && (['iam.read$', 'iam.write$'] | hasRole | async)) {
<a id="systembutton" [routerLink]="['/instance']" class="iam-settings" mat-stroked-button>
<div class="cnsl-action-button">
<span class="iam-label">{{ 'MENU.INSTANCE' | translate }}</span>
<i class="las la-cog"></i>
</div>
</a>
}
@if (isOnInstance && (['org.read'] | hasRole | async)) {
<a id="orgbutton" [routerLink]="['/org']" class="org-settings" mat-stroked-button>
<div class="cnsl-action-button">
<span class="iam-label">{{ 'MENU.ORGANIZATION' | translate }}</span>
<i class="las la-cog"></i>
</div>
</a>
}
</div>
}
<div class="system-rel" *ngIf="!isOnMe">
<a
id="systembutton"
*ngIf="!isOnInstance && (['iam.read$', 'iam.write$'] | hasRole | async)"
[routerLink]="['/instance']"
class="iam-settings"
mat-stroked-button
>
<div class="cnsl-action-button">
<span class="iam-label">{{ 'MENU.INSTANCE' | translate }}</span>
<i class="las la-cog"></i>
</div>
</a>
<a
id="orgbutton"
*ngIf="isOnInstance && (['org.read'] | hasRole | async)"
[routerLink]="['/org']"
class="org-settings"
mat-stroked-button
>
<div class="cnsl-action-button">
<span class="iam-label">{{ 'MENU.ORGANIZATION' | translate }}</span>
<i class="las la-cog"></i>
</div>
</a>
</div>
<ng-container *ngIf="user && user.id">
@if (user && user.id) {
<div class="account-card-wrapper">
<button
cdkOverlayOrigin
@@ -244,15 +228,16 @@
(backdropClick)="showAccount = false"
(detach)="showAccount = false"
>
<cnsl-accounts-card
class="a_card"
*ngIf="showAccount"
(closedCard)="showAccount = false"
[user]="user"
[iamuser]="['iam.write$'] | hasRole | async"
>
</cnsl-accounts-card>
@if (showAccount) {
<cnsl-accounts-card
class="a_card"
(closedCard)="showAccount = false"
[user]="user"
[iamuser]="['iam.write$'] | hasRole | async"
>
</cnsl-accounts-card>
}
</ng-template>
</ng-container>
}
</div>
</mat-toolbar>
@@ -13,16 +13,12 @@
<span>{{ 'IDP.AVAILABILITY' | translate }}</span>
</th>
<td class="pointer availability" mat-cell *matCellDef="let idp">
<i
matTooltip="{{ 'IDP.AVAILABLE' | translate }}"
*ngIf="isEnabled(idp) && idp.state === IDPState.IDP_STATE_ACTIVE"
class="idp-available las la-check-circle"
></i>
<i
matTooltip="{{ 'IDP.AVAILABLEBUTINACTIVE' | translate }}"
*ngIf="isEnabled(idp) && idp.state === IDPState.IDP_STATE_INACTIVE"
class="idp-not-available las la-check-circle"
></i>
@if (isEnabled(idp) && idp.state === IDPState.IDP_STATE_ACTIVE) {
<i matTooltip="{{ 'IDP.AVAILABLE' | translate }}" class="idp-available las la-check-circle"></i>
}
@if (isEnabled(idp) && idp.state === IDPState.IDP_STATE_INACTIVE) {
<i matTooltip="{{ 'IDP.AVAILABLEBUTINACTIVE' | translate }}" class="idp-not-available las la-check-circle"></i>
}
</td>
</ng-container>
@@ -36,59 +32,87 @@
<ng-container matColumnDef="type">
<th mat-header-cell *matHeaderCellDef>{{ 'IDP.TYPE' | translate }}</th>
<td class="pointer" mat-cell *matCellDef="let idp">
<div [ngSwitch]="idp.type">
<div class="idp-table-provider-type" *ngSwitchCase="ProviderType.PROVIDER_TYPE_AZURE_AD">
<img class="idp-logo" src="./assets/images/idp/ms.svg" alt="azure ad" />
Microsoft
</div>
<div class="idp-table-provider-type" *ngSwitchCase="ProviderType.PROVIDER_TYPE_GOOGLE">
<img class="idp-logo" src="./assets/images/idp/google.png" alt="google" />
Google
</div>
<div class="idp-table-provider-type" *ngSwitchCase="ProviderType.PROVIDER_TYPE_GITHUB">
<img class="idp-logo dark" src="./assets/images/idp/github-dark.svg" alt="github" />
<img class="idp-logo light" src="./assets/images/idp/github.svg" alt="github" />
GitHub
</div>
<div class="idp-table-provider-type" *ngSwitchCase="ProviderType.PROVIDER_TYPE_OIDC">
<mat-icon class="idp-icon" svgIcon="mdi_openid" alt="oidc" />
Generic OIDC
</div>
<div class="idp-table-provider-type" *ngSwitchCase="ProviderType.PROVIDER_TYPE_OAUTH">
<img class="idp-logo" src="./assets/images/idp/oauth.svg" alt="oauth" />
Generic OAuth
</div>
<div class="idp-table-provider-type" *ngSwitchCase="ProviderType.PROVIDER_TYPE_JWT">
<mat-icon class="idp-icon" svgIcon="mdi_jwt" alt="jwt" />
Generic JWT
</div>
<div class="idp-table-provider-type" *ngSwitchCase="ProviderType.PROVIDER_TYPE_GITLAB">
<img class="idp-logo" src="./assets/images/idp/gitlab.svg" alt="gitlab" />
Gitlab
</div>
<div class="idp-table-provider-type" *ngSwitchCase="ProviderType.PROVIDER_TYPE_GITLAB_SELF_HOSTED">
<img class="idp-logo" src="./assets/images/idp/gitlab.svg" alt="gitlab self hosted" />
Gitlab Self Hosted
</div>
<div class="idp-table-provider-type" *ngSwitchCase="ProviderType.PROVIDER_TYPE_GITHUB_ES">
<img class="idp-logo dark" src="./assets/images/idp/github-dark.svg" alt="github" />
<img class="idp-logo light" src="./assets/images/idp/github.svg" alt="github" />
GitHub Enterprise Server
</div>
<div class="idp-table-provider-type" *ngSwitchCase="ProviderType.PROVIDER_TYPE_LDAP">
<i class="idp-icon las la-building"></i>
Active Directory / LDAP
</div>
<div class="idp-table-provider-type" *ngSwitchCase="ProviderType.PROVIDER_TYPE_APPLE">
<img class="idp-logo apple dark" src="./assets/images/idp/apple-dark.svg" alt="apple" />
<img class="idp-logo apple light" src="./assets/images/idp/apple.svg" alt="apple" />
Apple
</div>
<div class="idp-table-provider-type" *ngSwitchCase="ProviderType.PROVIDER_TYPE_SAML">
<img class="idp-logo" src="./assets/images/idp/saml-icon.svg" alt="saml" />
SAML
</div>
<div class="idp-table-provider-type" *ngSwitchDefault>coming soon</div>
<div>
@switch (idp.type) {
@case (ProviderType.PROVIDER_TYPE_AZURE_AD) {
<div class="idp-table-provider-type">
<img class="idp-logo" src="./assets/images/idp/ms.svg" alt="azure ad" />
Microsoft
</div>
}
@case (ProviderType.PROVIDER_TYPE_GOOGLE) {
<div class="idp-table-provider-type">
<img class="idp-logo" src="./assets/images/idp/google.png" alt="google" />
Google
</div>
}
@case (ProviderType.PROVIDER_TYPE_GITHUB) {
<div class="idp-table-provider-type">
<img class="idp-logo dark" src="./assets/images/idp/github-dark.svg" alt="github" />
<img class="idp-logo light" src="./assets/images/idp/github.svg" alt="github" />
GitHub
</div>
}
@case (ProviderType.PROVIDER_TYPE_OIDC) {
<div class="idp-table-provider-type">
<mat-icon class="idp-icon" svgIcon="mdi_openid" alt="oidc" />
Generic OIDC
</div>
}
@case (ProviderType.PROVIDER_TYPE_OAUTH) {
<div class="idp-table-provider-type">
<img class="idp-logo" src="./assets/images/idp/oauth.svg" alt="oauth" />
Generic OAuth
</div>
}
@case (ProviderType.PROVIDER_TYPE_JWT) {
<div class="idp-table-provider-type">
<mat-icon class="idp-icon" svgIcon="mdi_jwt" alt="jwt" />
Generic JWT
</div>
}
@case (ProviderType.PROVIDER_TYPE_GITLAB) {
<div class="idp-table-provider-type">
<img class="idp-logo" src="./assets/images/idp/gitlab.svg" alt="gitlab" />
Gitlab
</div>
}
@case (ProviderType.PROVIDER_TYPE_GITLAB_SELF_HOSTED) {
<div class="idp-table-provider-type">
<img class="idp-logo" src="./assets/images/idp/gitlab.svg" alt="gitlab self hosted" />
Gitlab Self Hosted
</div>
}
@case (ProviderType.PROVIDER_TYPE_GITHUB_ES) {
<div class="idp-table-provider-type">
<img class="idp-logo dark" src="./assets/images/idp/github-dark.svg" alt="github" />
<img class="idp-logo light" src="./assets/images/idp/github.svg" alt="github" />
GitHub Enterprise Server
</div>
}
@case (ProviderType.PROVIDER_TYPE_LDAP) {
<div class="idp-table-provider-type">
<i class="idp-icon las la-building"></i>
Active Directory / LDAP
</div>
}
@case (ProviderType.PROVIDER_TYPE_APPLE) {
<div class="idp-table-provider-type">
<img class="idp-logo apple dark" src="./assets/images/idp/apple-dark.svg" alt="apple" />
<img class="idp-logo apple light" src="./assets/images/idp/apple.svg" alt="apple" />
Apple
</div>
}
@case (ProviderType.PROVIDER_TYPE_SAML) {
<div class="idp-table-provider-type">
<img class="idp-logo" src="./assets/images/idp/saml-icon.svg" alt="saml" />
SAML
</div>
}
@default {
<div class="idp-table-provider-type">coming soon</div>
}
}
</div>
</td>
</ng-container>
@@ -132,71 +156,75 @@
<th class="idp-table-actions" mat-header-cell *matHeaderCellDef></th>
<td class="idp-table-actions" mat-cell *matCellDef="let idp">
<cnsl-table-actions>
<button
actions
*ngIf="!isEnabled(idp)"
[disabled]="
([
serviceType === PolicyComponentServiceType.ADMIN
? 'iam.idp.write'
: serviceType === PolicyComponentServiceType.MGMT
? 'org.idp.write'
: '',
]
| hasRole
| async) === false
"
mat-icon-button
matTooltip="{{ 'IDP.SETAVAILABLE' | translate }}"
(click)="addIdp(idp); $event.stopPropagation()"
>
<i class="las la-check-circle"></i>
</button>
<button
actions
*ngIf="isEnabled(idp)"
[disabled]="
([
serviceType === PolicyComponentServiceType.ADMIN
? 'iam.idp.write'
: serviceType === PolicyComponentServiceType.MGMT
? 'org.idp.write'
: '',
]
| hasRole
| async) === false
"
mat-icon-button
matTooltip="{{ 'IDP.SETUNAVAILABLE' | translate }}"
(click)="removeIdp(idp); $event.stopPropagation()"
>
<i class="las la-times-circle"></i>
</button>
<button
actions
*ngIf="
(serviceType === PolicyComponentServiceType.MGMT && idp.owner === IDPOwnerType.IDP_OWNER_TYPE_ORG) ||
(serviceType === PolicyComponentServiceType.ADMIN && idp.owner === IDPOwnerType.IDP_OWNER_TYPE_SYSTEM)
"
[disabled]="
(serviceType === PolicyComponentServiceType.MGMT && idp?.providerType === IDPOwnerType.IDP_OWNER_TYPE_ORG) ||
([
serviceType === PolicyComponentServiceType.ADMIN
? 'iam.idp.write'
: serviceType === PolicyComponentServiceType.MGMT
? 'org.idp.write'
: '',
]
| hasRole
| async) === false
"
mat-icon-button
color="warn"
matTooltip="{{ 'ACTIONS.REMOVE' | translate }}"
(click)="deleteIdp(idp); $event.stopPropagation()"
>
<i class="las la-trash"></i>
</button>
@if (!isEnabled(idp)) {
<button
actions
[disabled]="
([
serviceType === PolicyComponentServiceType.ADMIN
? 'iam.idp.write'
: serviceType === PolicyComponentServiceType.MGMT
? 'org.idp.write'
: '',
]
| hasRole
| async) === false
"
mat-icon-button
matTooltip="{{ 'IDP.SETAVAILABLE' | translate }}"
(click)="addIdp(idp); $event.stopPropagation()"
>
<i class="las la-check-circle"></i>
</button>
}
@if (isEnabled(idp)) {
<button
actions
[disabled]="
([
serviceType === PolicyComponentServiceType.ADMIN
? 'iam.idp.write'
: serviceType === PolicyComponentServiceType.MGMT
? 'org.idp.write'
: '',
]
| hasRole
| async) === false
"
mat-icon-button
matTooltip="{{ 'IDP.SETUNAVAILABLE' | translate }}"
(click)="removeIdp(idp); $event.stopPropagation()"
>
<i class="las la-times-circle"></i>
</button>
}
@if (
(serviceType === PolicyComponentServiceType.MGMT && idp.owner === IDPOwnerType.IDP_OWNER_TYPE_ORG) ||
(serviceType === PolicyComponentServiceType.ADMIN && idp.owner === IDPOwnerType.IDP_OWNER_TYPE_SYSTEM)
) {
<button
actions
[disabled]="
(serviceType === PolicyComponentServiceType.MGMT &&
idp?.providerType === IDPOwnerType.IDP_OWNER_TYPE_ORG) ||
([
serviceType === PolicyComponentServiceType.ADMIN
? 'iam.idp.write'
: serviceType === PolicyComponentServiceType.MGMT
? 'org.idp.write'
: '',
]
| hasRole
| async) === false
"
mat-icon-button
color="warn"
matTooltip="{{ 'ACTIONS.REMOVE' | translate }}"
(click)="deleteIdp(idp); $event.stopPropagation()"
>
<i class="las la-trash"></i>
</button>
}
</cnsl-table-actions>
</td>
</ng-container>
@@ -206,10 +234,12 @@
</table>
</div>
<div *ngIf="(loading$ | async) === false && !dataSource?.data?.length" class="no-content-row">
<i class="las la-exclamation"></i>
<span>{{ 'IDP.EMPTY' | translate }}</span>
</div>
@if ((loading$ | async) === false && !dataSource?.data?.length) {
<div class="no-content-row">
<i class="las la-exclamation"></i>
<span>{{ 'IDP.EMPTY' | translate }}</span>
</div>
}
<cnsl-paginator
#paginator
@@ -1,32 +1,19 @@
<span class="title" mat-dialog-title>{{ data.titleKey | translate: data.titleParam }}</span>
<span class="title" mat-dialog-title>{{ data.titleKey | translate }}</span>
<div mat-dialog-content>
<div class="icon-wrapper" *ngIf="data.icon">
<i class="icon {{ data.icon }}"></i>
</div>
<p class="desc cnsl-secondary-text">{{ data.descriptionKey | translate: data.descriptionParam }}</p>
<cnsl-info-section *ngIf="data.infoSectionKey" [type]="InfoSectionType.INFO">{{
data.warnSectionKey | translate
}}</cnsl-info-section>
<p *ngIf="data.hintKey" class="desc cnsl-secondary-text">{{ data.hintKey | translate: { value: data.confirmation } }}</p>
<cnsl-form-field *ngIf="data.confirmation && data.confirmationKey" class="formfield">
<cnsl-label>{{ data.confirmationKey | translate: { value: data.confirmation } }}</cnsl-label>
<input cnslInput [(ngModel)]="confirm" data-e2e="confirm-dialog-input" />
</cnsl-form-field>
<p class="desc cnsl-secondary-text">{{ data.descriptionKey | translate }}</p>
</div>
<div mat-dialog-actions class="action">
<button *ngIf="data.cancelKey" mat-stroked-button (click)="closeDialog()">
<button mat-stroked-button (click)="dialogRef.close(false)">
{{ data.cancelKey | translate }}
</button>
<span class="fill-space"></span>
<button
color="primary"
[disabled]="data.confirmation && confirm !== data.confirmation"
mat-raised-button
class="ok-button"
(click)="closeDialogWithSuccess()"
(click)="dialogRef.close(true)"
data-e2e="confirm-dialog-button"
>
{{ data.confirmKey | translate }}
@@ -1,24 +0,0 @@
import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';
import { InfoDialogComponent } from './info-dialog.component';
describe('InfoDialogComponent', () => {
let component: InfoDialogComponent;
let fixture: ComponentFixture<InfoDialogComponent>;
beforeEach(waitForAsync(() => {
TestBed.configureTestingModule({
declarations: [InfoDialogComponent],
}).compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(InfoDialogComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});
@@ -1,27 +1,28 @@
import { Component, Inject } from '@angular/core';
import { MatDialogRef, MAT_DIALOG_DATA } from '@angular/material/dialog';
import { Component, inject } from '@angular/core';
import { MatDialogRef, MAT_DIALOG_DATA, MatDialogModule } from '@angular/material/dialog';
import { InfoSectionType } from '../info-section/info-section.component';
import { TranslateModule } from '@ngx-translate/core';
import { MatButtonModule } from '@angular/material/button';
export type InfoDialogData = {
confirmKey: string;
cancelKey: string;
titleKey: string;
descriptionKey: string;
};
export type InfoDialogResult = boolean;
@Component({
selector: 'cnsl-info-dialog',
templateUrl: './info-dialog.component.html',
styleUrls: ['./info-dialog.component.scss'],
standalone: false,
imports: [TranslateModule, MatDialogModule, MatButtonModule],
})
export class InfoDialogComponent {
public confirm: string = '';
InfoSectionType: any = InfoSectionType;
constructor(
public dialogRef: MatDialogRef<InfoDialogComponent>,
@Inject(MAT_DIALOG_DATA) public data: any,
) {}
protected readonly InfoSectionType = InfoSectionType;
public closeDialog(): void {
this.dialogRef.close(false);
}
public closeDialogWithSuccess(): void {
this.dialogRef.close(true);
}
protected readonly dialogRef = inject<MatDialogRef<InfoDialogComponent>>(MatDialogRef);
protected readonly data = inject<InfoDialogData>(MAT_DIALOG_DATA);
}
@@ -1,16 +0,0 @@
import { CommonModule } from '@angular/common';
import { NgModule } from '@angular/core';
import { FormsModule } from '@angular/forms';
import { MatButtonModule } from '@angular/material/button';
import { TranslateModule } from '@ngx-translate/core';
import { MatDialogModule } from '@angular/material/dialog';
import { InfoSectionModule } from '../info-section/info-section.module';
import { InputModule } from '../input/input.module';
import { InfoDialogComponent } from './info-dialog.component';
@NgModule({
declarations: [InfoDialogComponent],
imports: [CommonModule, FormsModule, MatDialogModule, TranslateModule, InfoSectionModule, MatButtonModule, InputModule],
})
export class InfoDialogModule {}
@@ -1,24 +1,27 @@
<div class="context_intro_overlay">
<div class="overlay-info-row">
<span class="info"
>INFO <span *ngIf="data.number && data.count">{{ data.number }}/{{ data.count }}</span></span
>
>INFO
@if (data.number && data.count) {
<span>{{ data.number }}/{{ data.count }}</span>
}
</span>
<button mat-icon-button (click)="workflowService.reset()">
<mat-icon>close</mat-icon>
</button>
</div>
<p>{{ data.i18nText | translate }}</p>
<div class="overlay-actions">
<button
(click)="workflowService.nextStep()"
*ngIf="workflowService.nextPossible && !workflowService.isLast"
mat-stroked-button
>
{{ 'ACTIONS.NEXT' | translate }}
</button>
@if (workflowService.nextPossible && !workflowService.isLast) {
<button (click)="workflowService.nextStep()" mat-stroked-button>
{{ 'ACTIONS.NEXT' | translate }}
</button>
}
<button *ngIf="workflowService.isLast" (click)="workflowService.nextStep()" color="primary" mat-raised-button>
{{ 'ACTIONS.FINISHED' | translate }}
</button>
@if (workflowService.isLast) {
<button (click)="workflowService.nextStep()" color="primary" mat-raised-button>
{{ 'ACTIONS.FINISHED' | translate }}
</button>
}
</div>
</div>
@@ -1,308 +1,363 @@
<div class="info-row" *ngIf="user">
<div class="info-wrapper">
<p class="info-row-title">{{ 'USER.PAGES.STATE' | translate }}</p>
<p
*ngIf="user?.state"
class="state"
[ngClass]="{
active: user.state === UserState.USER_STATE_ACTIVE,
inactive: user.state === UserState.USER_STATE_INACTIVE,
}"
>
{{ (isV2(user) ? 'USER.STATEV2.' : 'USER.STATE.') + user.state | translate }}
</p>
</div>
<div class="info-wrapper">
<p class="info-row-title">{{ 'USER.ID' | translate }}</p>
<p *ngIf="userId" class="info-row-desc">{{ userId }}</p>
</div>
<div class="info-wrapper">
<p class="info-row-title">{{ 'USER.DETAILS.DATECREATED' | translate }}</p>
<p *ngIf="creationDate" class="info-row-desc">
{{ creationDate | timestampToDate | localizedDate: 'dd. MMMM yyyy, HH:mm' }}
</p>
</div>
<div class="info-wrapper">
<p class="info-row-title">{{ 'USER.DETAILS.DATECHANGED' | translate }}</p>
<p *ngIf="changeDate" class="info-row-desc">
{{ changeDate | timestampToDate | localizedDate: 'dd. MMMM yyyy, HH:mm' }}
</p>
</div>
<div class="info-wrapper width">
<p class="info-row-title">{{ 'USER.PAGES.LOGINMETHODS' | translate }}</p>
<div class="copy-row" *ngFor="let login of loginMethods">
<button
[disabled]="copied === login"
[matTooltip]="(copied !== login ? 'ACTIONS.COPY' : 'ACTIONS.COPIED') | translate"
cnslCopyToClipboard
[valueToCopy]="login"
(copiedValue)="copied = $event"
data-e2e="copy-loginname"
>
{{ login }}
</button>
@if (user) {
<div class="info-row">
<div class="info-wrapper">
<p class="info-row-title">{{ 'USER.PAGES.STATE' | translate }}</p>
@if (user?.state) {
<p
class="state"
[ngClass]="{
active: user.state === UserState.USER_STATE_ACTIVE,
inactive: user.state === UserState.USER_STATE_INACTIVE,
}"
>
{{ (isV2(user) ? 'USER.STATEV2.' : 'USER.STATE.') + user.state | translate }}
</p>
}
</div>
<div class="info-wrapper">
<p class="info-row-title">{{ 'USER.ID' | translate }}</p>
@if (userId) {
<p class="info-row-desc">{{ userId }}</p>
}
</div>
<div class="info-wrapper">
<p class="info-row-title">{{ 'USER.DETAILS.DATECREATED' | translate }}</p>
@if (creationDate) {
<p class="info-row-desc">
{{ creationDate | timestampToDate | localizedDate: 'dd. MMMM yyyy, HH:mm' }}
</p>
}
</div>
<div class="info-wrapper">
<p class="info-row-title">{{ 'USER.DETAILS.DATECHANGED' | translate }}</p>
@if (changeDate) {
<p class="info-row-desc">
{{ changeDate | timestampToDate | localizedDate: 'dd. MMMM yyyy, HH:mm' }}
</p>
}
</div>
<div class="info-wrapper width">
<p class="info-row-title">{{ 'USER.PAGES.LOGINMETHODS' | translate }}</p>
@for (login of loginMethods; track login) {
<div class="copy-row">
<button
[disabled]="copied === login"
[matTooltip]="(copied !== login ? 'ACTIONS.COPY' : 'ACTIONS.COPIED') | translate"
cnslCopyToClipboard
[valueToCopy]="login"
(copiedValue)="copied = $event"
data-e2e="copy-loginname"
>
{{ login }}
</button>
</div>
}
</div>
</div>
</div>
}
<div class="info-row" *ngIf="instance">
<div class="info-wrapper">
<p class="info-row-title">{{ 'IAM.PAGES.STATE' | translate }}</p>
<p
*ngIf="instance?.state"
class="state"
[ngClass]="{
active: instance.state === State.STATE_RUNNING,
inactive: instance.state === State.STATE_STOPPED || instance.state === State.STATE_STOPPING,
}"
>
{{ 'IAM.STATE.' + instance.state | translate }}
</p>
</div>
<div class="info-wrapper">
<p class="info-row-title">{{ 'INSTANCEID' | translate }}</p>
<p *ngIf="instance?.id" class="info-row-desc">{{ instance.id }}</p>
</div>
<div class="info-wrapper">
<p class="info-row-title">{{ 'NAME' | translate }}</p>
<p *ngIf="instance?.name" class="info-row-desc">{{ instance.name }}</p>
</div>
<div class="info-wrapper">
<p class="info-row-title">{{ 'VERSION' | translate }}</p>
<p *ngIf="instance?.version" class="info-row-desc">{{ instance.version }}</p>
</div>
<div class="info-wrapper width">
<p class="info-row-title">{{ 'IAM.PAGES.DOMAINLIST' | translate }}</p>
<div class="copy-row" *ngFor="let domain of instance?.domainsList">
<button
[disabled]="copied === domain.domain"
[matTooltip]="(copied !== domain.domain ? 'ACTIONS.COPY' : 'ACTIONS.COPIED') | translate"
cnslCopyToClipboard
[valueToCopy]="domain.domain"
(copiedValue)="copied = $event"
>
{{ domain.domain }}
</button>
@if (instance) {
<div class="info-row">
<div class="info-wrapper">
<p class="info-row-title">{{ 'IAM.PAGES.STATE' | translate }}</p>
@if (instance?.state) {
<p
class="state"
[ngClass]="{
active: instance.state === State.STATE_RUNNING,
inactive: instance.state === State.STATE_STOPPED || instance.state === State.STATE_STOPPING,
}"
>
{{ 'IAM.STATE.' + instance.state | translate }}
</p>
}
</div>
<div class="info-wrapper">
<p class="info-row-title">{{ 'INSTANCEID' | translate }}</p>
@if (instance?.id) {
<p class="info-row-desc">{{ instance.id }}</p>
}
</div>
<div class="info-wrapper">
<p class="info-row-title">{{ 'NAME' | translate }}</p>
@if (instance?.name) {
<p class="info-row-desc">{{ instance.name }}</p>
}
</div>
<div class="info-wrapper">
<p class="info-row-title">{{ 'VERSION' | translate }}</p>
@if (instance?.version) {
<p class="info-row-desc">{{ instance.version }}</p>
}
</div>
<div class="info-wrapper width">
<p class="info-row-title">{{ 'IAM.PAGES.DOMAINLIST' | translate }}</p>
@for (domain of instance?.domainsList; track domain) {
<div class="copy-row">
<button
[disabled]="copied === domain.domain"
[matTooltip]="(copied !== domain.domain ? 'ACTIONS.COPY' : 'ACTIONS.COPIED') | translate"
cnslCopyToClipboard
[valueToCopy]="domain.domain"
(copiedValue)="copied = $event"
>
{{ domain.domain }}
</button>
</div>
}
</div>
<div class="info-wrapper">
<p class="info-row-title">{{ 'ORG.PAGES.CREATIONDATE' | translate }}</p>
@if (instance?.details?.creationDate; as creationDate) {
<p class="info-row-desc">
{{ creationDate | timestampToDate | localizedDate: 'dd. MMMM yyyy, HH:mm' }}
</p>
}
</div>
<div class="info-wrapper">
<p class="info-row-title">{{ 'ORG.PAGES.DATECHANGED' | translate }}</p>
@if (instance?.details?.changeDate; as changeDate) {
<p class="info-row-desc">
{{ changeDate | timestampToDate | localizedDate: 'dd. MMMM yyyy, HH:mm' }}
</p>
}
</div>
</div>
}
<div class="info-wrapper">
<p class="info-row-title">{{ 'ORG.PAGES.CREATIONDATE' | translate }}</p>
<p *ngIf="instance?.details?.creationDate as creationDate" class="info-row-desc">
{{ creationDate | timestampToDate | localizedDate: 'dd. MMMM yyyy, HH:mm' }}
</p>
</div>
<div class="info-wrapper">
<p class="info-row-title">{{ 'ORG.PAGES.DATECHANGED' | translate }}</p>
<p *ngIf="instance?.details?.changeDate as changeDate" class="info-row-desc">
{{ changeDate | timestampToDate | localizedDate: 'dd. MMMM yyyy, HH:mm' }}
</p>
</div>
</div>
<div class="info-row" *ngIf="org">
<div class="info-wrapper">
<p class="info-row-title">{{ 'ORG.PAGES.STATE' | translate }}</p>
<p
*ngIf="org?.state"
class="state"
[ngClass]="{ active: org.state === OrgState.ORG_STATE_ACTIVE, inactive: org.state === OrgState.ORG_STATE_INACTIVE }"
>
{{ 'ORG.STATE.' + org.state | translate }}
</p>
</div>
<div class="info-wrapper">
<p class="info-row-title">{{ 'ORG.PAGES.ID' | translate }}</p>
<p *ngIf="org?.id" class="info-row-desc">{{ org.id }}</p>
</div>
<div class="info-wrapper width">
<p class="info-row-title">{{ 'ORG.PAGES.PRIMARYDOMAIN' | translate }}</p>
<div class="copy-row" *ngIf="org.primaryDomain">
<button
[disabled]="copied === org.primaryDomain"
[matTooltip]="(copied !== org.primaryDomain ? 'ACTIONS.COPY' : 'ACTIONS.COPIED') | translate"
cnslCopyToClipboard
[valueToCopy]="org.primaryDomain"
(copiedValue)="copied = $event"
>
{{ org.primaryDomain }}
</button>
@if (org) {
<div class="info-row">
<div class="info-wrapper">
<p class="info-row-title">{{ 'ORG.PAGES.STATE' | translate }}</p>
@if (org?.state) {
<p
class="state"
[ngClass]="{
active: org.state === OrgState.ORG_STATE_ACTIVE,
inactive: org.state === OrgState.ORG_STATE_INACTIVE,
}"
>
{{ 'ORG.STATE.' + org.state | translate }}
</p>
}
</div>
<div class="info-wrapper">
<p class="info-row-title">{{ 'ORG.PAGES.ID' | translate }}</p>
@if (org?.id) {
<p class="info-row-desc">{{ org.id }}</p>
}
</div>
<div class="info-wrapper width">
<p class="info-row-title">{{ 'ORG.PAGES.PRIMARYDOMAIN' | translate }}</p>
@if (org.primaryDomain) {
<div class="copy-row">
<button
[disabled]="copied === org.primaryDomain"
[matTooltip]="(copied !== org.primaryDomain ? 'ACTIONS.COPY' : 'ACTIONS.COPIED') | translate"
cnslCopyToClipboard
[valueToCopy]="org.primaryDomain"
(copiedValue)="copied = $event"
>
{{ org.primaryDomain }}
</button>
</div>
}
</div>
<div class="info-wrapper">
<p class="info-row-title">{{ 'ORG.PAGES.CREATIONDATE' | translate }}</p>
@if (org?.details?.creationDate; as creationDate) {
<p class="info-row-desc">
{{ creationDate | timestampToDate | localizedDate: 'dd. MMMM yyyy, HH:mm' }}
</p>
}
</div>
<div class="info-wrapper">
<p class="info-row-title">{{ 'ORG.PAGES.DATECHANGED' | translate }}</p>
@if (org?.details?.changeDate; as changeDate) {
<p class="info-row-desc">
{{ changeDate | timestampToDate | localizedDate: 'dd. MMMM yyyy, HH:mm' }}
</p>
}
</div>
</div>
}
<div class="info-wrapper">
<p class="info-row-title">{{ 'ORG.PAGES.CREATIONDATE' | translate }}</p>
<p *ngIf="org?.details?.creationDate as creationDate" class="info-row-desc">
{{ creationDate | timestampToDate | localizedDate: 'dd. MMMM yyyy, HH:mm' }}
</p>
@if (project) {
<div class="info-row">
<div class="info-wrapper">
<p class="info-row-title">{{ 'PROJECT.STATE.TITLE' | translate }}</p>
@if (project?.state) {
<p
class="state"
[ngClass]="{
active: project.state === ProjectState.PROJECT_STATE_ACTIVE,
inactive: project.state === ProjectState.PROJECT_STATE_INACTIVE,
}"
>
{{ 'PROJECT.STATE.' + project.state | translate }}
</p>
}
</div>
<div class="info-wrapper">
<p class="info-row-title">{{ 'PROJECT.PAGES.ID' | translate }}</p>
@if (project?.id) {
<p class="info-row-desc">{{ project.id }}</p>
}
</div>
<div class="info-wrapper">
<p class="info-row-title">{{ 'PROJECT.PAGES.CREATEDON' | translate }}</p>
@if (project?.details?.creationDate; as creationDate) {
<p class="info-row-desc">
{{ creationDate | timestampToDate | localizedDate: 'dd. MMMM yyyy, HH:mm' }}
</p>
}
</div>
<div class="info-wrapper">
<p class="info-row-title">{{ 'PROJECT.PAGES.LASTMODIFIED' | translate }}</p>
@if (project?.details?.changeDate; as changeDate) {
<p class="info-row-desc">
{{ changeDate | timestampToDate | localizedDate: 'dd. MMMM yyyy, HH:mm' }}
</p>
}
</div>
</div>
}
<div class="info-wrapper">
<p class="info-row-title">{{ 'ORG.PAGES.DATECHANGED' | translate }}</p>
<p *ngIf="org?.details?.changeDate as changeDate" class="info-row-desc">
{{ changeDate | timestampToDate | localizedDate: 'dd. MMMM yyyy, HH:mm' }}
</p>
@if (grantedProject) {
<div class="info-row">
<div class="info-wrapper">
<p class="info-row-title">{{ 'PROJECT.STATE.TITLE' | translate }}</p>
@if (grantedProject?.state) {
<p
class="state"
[ngClass]="{
active: grantedProject.state === ProjectGrantState.PROJECT_GRANT_STATE_ACTIVE,
inactive: grantedProject.state === ProjectGrantState.PROJECT_GRANT_STATE_INACTIVE,
}"
>
{{ 'PROJECT.STATE.' + grantedProject.state | translate }}
</p>
}
</div>
<div class="info-wrapper">
<p class="info-row-title">{{ 'PROJECT.PAGES.ID' | translate }}</p>
@if (grantedProject?.projectId) {
<p class="info-row-desc">{{ grantedProject.projectId }}</p>
}
</div>
<div class="info-wrapper">
<p class="info-row-title">{{ 'PROJECT.GRANT.GRANTID' | translate }}</p>
@if (grantedProject?.grantId) {
<p class="info-row-desc">{{ grantedProject.grantId }}</p>
}
</div>
<div class="info-wrapper">
<p class="info-row-title">{{ 'PROJECT.PAGES.CREATEDON' | translate }}</p>
@if (grantedProject?.details?.creationDate; as creationDate) {
<p class="info-row-desc">
{{ creationDate | timestampToDate | localizedDate: 'dd. MMMM yyyy, HH:mm' }}
</p>
}
</div>
<div class="info-wrapper">
<p class="info-row-title">{{ 'PROJECT.PAGES.LASTMODIFIED' | translate }}</p>
@if (grantedProject?.details?.changeDate; as changeDate) {
<p class="info-row-desc">
{{ changeDate | timestampToDate | localizedDate: 'dd. MMMM yyyy, HH:mm' }}
</p>
}
</div>
</div>
</div>
}
<div class="info-row" *ngIf="project">
<div class="info-wrapper">
<p class="info-row-title">{{ 'PROJECT.STATE.TITLE' | translate }}</p>
<p
*ngIf="project?.state"
class="state"
[ngClass]="{
active: project.state === ProjectState.PROJECT_STATE_ACTIVE,
inactive: project.state === ProjectState.PROJECT_STATE_INACTIVE,
}"
>
{{ 'PROJECT.STATE.' + project.state | translate }}
</p>
</div>
<div class="info-wrapper">
<p class="info-row-title">{{ 'PROJECT.PAGES.ID' | translate }}</p>
<p *ngIf="project?.id" class="info-row-desc">{{ project.id }}</p>
</div>
<div class="info-wrapper">
<p class="info-row-title">{{ 'PROJECT.PAGES.CREATEDON' | translate }}</p>
<p *ngIf="project?.details?.creationDate as creationDate" class="info-row-desc">
{{ creationDate | timestampToDate | localizedDate: 'dd. MMMM yyyy, HH:mm' }}
</p>
</div>
<div class="info-wrapper">
<p class="info-row-title">{{ 'PROJECT.PAGES.LASTMODIFIED' | translate }}</p>
<p *ngIf="project?.details?.changeDate as changeDate" class="info-row-desc">
{{ changeDate | timestampToDate | localizedDate: 'dd. MMMM yyyy, HH:mm' }}
</p>
</div>
</div>
<div class="info-row" *ngIf="grantedProject">
<div class="info-wrapper">
<p class="info-row-title">{{ 'PROJECT.STATE.TITLE' | translate }}</p>
<p
*ngIf="grantedProject?.state"
class="state"
[ngClass]="{
active: grantedProject.state === ProjectGrantState.PROJECT_GRANT_STATE_ACTIVE,
inactive: grantedProject.state === ProjectGrantState.PROJECT_GRANT_STATE_INACTIVE,
}"
>
{{ 'PROJECT.STATE.' + grantedProject.state | translate }}
</p>
</div>
<div class="info-wrapper">
<p class="info-row-title">{{ 'PROJECT.PAGES.ID' | translate }}</p>
<p *ngIf="grantedProject?.projectId" class="info-row-desc">{{ grantedProject.projectId }}</p>
</div>
<div class="info-wrapper">
<p class="info-row-title">{{ 'PROJECT.GRANT.GRANTID' | translate }}</p>
<p *ngIf="grantedProject?.grantId" class="info-row-desc">{{ grantedProject.grantId }}</p>
</div>
<div class="info-wrapper">
<p class="info-row-title">{{ 'PROJECT.PAGES.CREATEDON' | translate }}</p>
<p *ngIf="grantedProject?.details?.creationDate as creationDate" class="info-row-desc">
{{ creationDate | timestampToDate | localizedDate: 'dd. MMMM yyyy, HH:mm' }}
</p>
</div>
<div class="info-wrapper">
<p class="info-row-title">{{ 'PROJECT.PAGES.LASTMODIFIED' | translate }}</p>
<p *ngIf="grantedProject?.details?.changeDate as changeDate" class="info-row-desc">
{{ changeDate | timestampToDate | localizedDate: 'dd. MMMM yyyy, HH:mm' }}
</p>
</div>
</div>
<ng-container *ngIf="app">
@if (app) {
<div class="info-row">
<div class="info-wrapper">
<p class="info-row-title">{{ 'APP.PAGES.STATE' | translate }}</p>
<p
*ngIf="app?.state"
class="state"
[ngClass]="{ active: app.state === AppState.APP_STATE_ACTIVE, inactive: app.state === AppState.APP_STATE_INACTIVE }"
>
{{ 'APP.PAGES.DETAIL.STATE.' + app.state | translate }}
</p>
@if (app?.state) {
<p
class="state"
[ngClass]="{
active: app.state === AppState.APP_STATE_ACTIVE,
inactive: app.state === AppState.APP_STATE_INACTIVE,
}"
>
{{ 'APP.PAGES.DETAIL.STATE.' + app.state | translate }}
</p>
}
</div>
<div class="info-wrapper" *ngIf="app?.apiConfig?.authMethodType as authMethodType">
<p class="info-row-title">{{ 'APP.AUTHMETHOD' | translate }}</p>
<p class="info-row-desc">
{{ 'APP.API.AUTHMETHOD.' + authMethodType | translate }}
</p>
</div>
<div class="info-wrapper" *ngIf="app?.oidcConfig?.authMethodType as authMethodType">
<p class="info-row-title">{{ 'APP.AUTHMETHOD' | translate }}</p>
<p class="info-row-desc">
{{ 'APP.OIDC.AUTHMETHOD.' + authMethodType | translate }}
</p>
</div>
@if (app?.apiConfig?.authMethodType; as authMethodType) {
<div class="info-wrapper">
<p class="info-row-title">{{ 'APP.AUTHMETHOD' | translate }}</p>
<p class="info-row-desc">
{{ 'APP.API.AUTHMETHOD.' + authMethodType | translate }}
</p>
</div>
}
@if (app?.oidcConfig?.authMethodType; as authMethodType) {
<div class="info-wrapper">
<p class="info-row-title">{{ 'APP.AUTHMETHOD' | translate }}</p>
<p class="info-row-desc">
{{ 'APP.OIDC.AUTHMETHOD.' + authMethodType | translate }}
</p>
</div>
}
<div class="info-wrapper">
<p class="info-row-title">{{ 'APP.PAGES.ID' | translate }}</p>
<p *ngIf="app?.id" class="info-row-desc">{{ app.id }}</p>
@if (app?.id) {
<p class="info-row-desc">{{ app.id }}</p>
}
</div>
<div class="info-wrapper">
<p class="info-row-title">{{ 'APP.PAGES.DATECREATED' | translate }}</p>
<p *ngIf="app?.details?.creationDate as creationDate" class="info-row-desc">
{{ creationDate | timestampToDate | localizedDate: 'dd. MMMM yyyy, HH:mm' }}
</p>
@if (app?.details?.creationDate; as creationDate) {
<p class="info-row-desc">
{{ creationDate | timestampToDate | localizedDate: 'dd. MMMM yyyy, HH:mm' }}
</p>
}
</div>
<div class="info-wrapper">
<p class="info-row-title">{{ 'APP.PAGES.DATECHANGED' | translate }}</p>
<p *ngIf="app?.details?.changeDate as changeDate" class="info-row-desc">
{{ changeDate | timestampToDate | localizedDate: 'dd. MMMM yyyy, HH:mm' }}
</p>
@if (app?.details?.changeDate; as changeDate) {
<p class="info-row-desc">
{{ changeDate | timestampToDate | localizedDate: 'dd. MMMM yyyy, HH:mm' }}
</p>
}
</div>
<div class="info-wrapper" *ngIf="app">
<p class="info-row-title">{{ 'APP.OIDC.INFO.CLIENTID' | translate }}</p>
<div class="copy-row" *ngIf="app.oidcConfig?.clientId">
<button
*ngIf="app.oidcConfig?.clientId as clientId"
[disabled]="copied === clientId"
[matTooltip]="(copied !== clientId ? 'ACTIONS.COPY' : 'ACTIONS.COPIED') | translate"
cnslCopyToClipboard
[valueToCopy]="clientId"
(copiedValue)="copied = $event"
>
{{ clientId }}
</button>
@if (app) {
<div class="info-wrapper">
<p class="info-row-title">{{ 'APP.OIDC.INFO.CLIENTID' | translate }}</p>
@if (app.oidcConfig?.clientId) {
<div class="copy-row">
@if (app.oidcConfig?.clientId; as clientId) {
<button
[disabled]="copied === clientId"
[matTooltip]="(copied !== clientId ? 'ACTIONS.COPY' : 'ACTIONS.COPIED') | translate"
cnslCopyToClipboard
[valueToCopy]="clientId"
(copiedValue)="copied = $event"
>
{{ clientId }}
</button>
}
</div>
}
@if (app.apiConfig?.clientId) {
<div class="copy-row">
@if (app.apiConfig?.clientId; as clientId) {
<button
[disabled]="copied === clientId"
[matTooltip]="(copied !== clientId ? 'ACTIONS.COPY' : 'ACTIONS.COPIED') | translate"
cnslCopyToClipboard
[valueToCopy]="clientId"
(copiedValue)="copied = $event"
>
{{ clientId }}
</button>
}
</div>
}
</div>
<div class="copy-row" *ngIf="app.apiConfig?.clientId">
<button
*ngIf="app.apiConfig?.clientId as clientId"
[disabled]="copied === clientId"
[matTooltip]="(copied !== clientId ? 'ACTIONS.COPY' : 'ACTIONS.COPIED') | translate"
cnslCopyToClipboard
[valueToCopy]="clientId"
(copiedValue)="copied = $event"
>
{{ clientId }}
</button>
</div>
</div>
}
</div>
</ng-container>
}
@@ -7,9 +7,15 @@
fit: fitWidth,
}"
>
<i *ngIf="type === infoSectionType.INFO" class="icon las la-info"></i>
<i *ngIf="type === infoSectionType.WARN" class="icon las la-exclamation"></i>
<i *ngIf="type === infoSectionType.ALERT" class="icon las la-exclamation"></i>
@if (type === infoSectionType.INFO) {
<i class="icon las la-info"></i>
}
@if (type === infoSectionType.WARN) {
<i class="icon las la-exclamation"></i>
}
@if (type === infoSectionType.ALERT) {
<i class="icon las la-exclamation"></i>
}
<div class="info-section-content">
<ng-content></ng-content>
@@ -1,36 +1,42 @@
<div class="keyboard-shortcuts">
<h1 class="title" mat-dialog-title>{{ 'KEYBOARDSHORTCUTS.TITLE' | translate }}</h1>
<div mat-dialog-content>
<div *ngIf="isNotOnSystem" class="keyboard-shortcuts-group">
<h2>{{ 'KEYBOARDSHORTCUTS.UNDERORGCONTEXT' | translate }}</h2>
<div class="keyboard-shortcuts-wrapper">
<div class="keyboard-shortcut" *ngFor="let shortcut of orgShortcuts">
<span class="keyboard-shortcut-name cnsl-secondary-text" [innerHTML]="shortcut.i18nKey | translate"></span>
<span class="fill-space"></span>
<template
*ngFor="let key of shortcut.keyboardKeys; index as i"
[ngTemplateOutlet]="actionkey"
[ngTemplateOutletContext]="{ key: key, last: i === shortcut.keyboardKeys.length - 1 }"
></template>
@if (isNotOnSystem) {
<div class="keyboard-shortcuts-group">
<h2>{{ 'KEYBOARDSHORTCUTS.UNDERORGCONTEXT' | translate }}</h2>
<div class="keyboard-shortcuts-wrapper">
@for (shortcut of orgShortcuts; track shortcut) {
<div class="keyboard-shortcut">
<span class="keyboard-shortcut-name cnsl-secondary-text" [innerHTML]="shortcut.i18nKey | translate"></span>
<span class="fill-space"></span>
@for (key of shortcut.keyboardKeys; track key; let i = $index) {
<template
[ngTemplateOutlet]="actionkey"
[ngTemplateOutletContext]="{ key: key, last: i === shortcut.keyboardKeys.length - 1 }"
></template>
}
</div>
}
</div>
</div>
</div>
}
<div class="keyboard-shortcuts-group">
<h2>{{ 'KEYBOARDSHORTCUTS.SIDEWIDE' | translate }}</h2>
<div class="keyboard-shortcuts-wrapper">
<ng-container *ngFor="let shortcut of shortcuts">
@for (shortcut of shortcuts; track shortcut) {
<ng-template cnslHasRole [hasRole]="shortcut.permissions">
<div class="keyboard-shortcut">
<span class="keyboard-shortcut-name cnsl-secondary-text" [innerHTML]="shortcut.i18nKey | translate"></span>
<span class="fill-space"></span>
<template
*ngFor="let key of shortcut.keyboardKeys; index as i"
[ngTemplateOutlet]="actionkey"
[ngTemplateOutletContext]="{ key: key, last: i === shortcut.keyboardKeys.length - 1 }"
></template>
@for (key of shortcut.keyboardKeys; track key; let i = $index) {
<template
[ngTemplateOutlet]="actionkey"
[ngTemplateOutletContext]="{ key: key, last: i === shortcut.keyboardKeys.length - 1 }"
></template>
}
</div>
</ng-template>
</ng-container>
}
</div>
</div>
</div>
@@ -1,162 +1,157 @@
<cnsl-refresh-table
*ngIf="dataSource"
(refreshed)="changePage()"
[timestamp]="dataSource.viewTimestamp"
[selection]="selection"
[loading]="dataSource.loading$ | async"
>
<ng-container actions *ngIf="selection.hasValue()">
<ng-content select="[selectactions]"></ng-content>
</ng-container>
<div actions *ngIf="!selection.hasValue()">
<ng-content select="[writeactions]"></ng-content>
</div>
<div class="table-wrapper">
<table
*ngIf="displayedColumns$ | async as displayedColumns"
mat-table
class="table"
aria-label="Elements"
[dataSource]="dataSource"
>
<ng-container matColumnDef="select">
<th mat-header-cell *matHeaderCellDef>
<div class="selection">
<mat-checkbox
[disabled]="(canWrite$ | async) === false"
color="primary"
(change)="$event ? masterToggle() : null"
[checked]="selection.hasValue() && isAllSelected()"
[indeterminate]="selection.hasValue() && !isAllSelected()"
>
</mat-checkbox>
</div>
</th>
<td mat-cell *matCellDef="let row">
<div class="selection">
<mat-checkbox
[disabled]="(canWrite$ | async) === false"
color="primary"
(click)="$event.stopPropagation()"
(change)="$event ? selection.toggle(row) : null"
[checked]="selection.isSelected(row)"
>
<cnsl-avatar
*ngIf="row?.userType === UserType.TYPE_HUMAN; else cog"
class="avatar"
[name]="row.displayName"
[avatarUrl]="row.avatarUrl || ''"
[avatarUrl]="row.avatarUrl || ''"
[forColor]="row?.preferredLoginName"
[size]="32"
>
</cnsl-avatar>
<ng-template #cog>
<cnsl-avatar [forColor]="row.preferredLoginName" [isMachine]="true">
<i class="las la-robot"></i>
</cnsl-avatar>
</ng-template>
</mat-checkbox>
</div>
</td>
</ng-container>
<ng-container matColumnDef="userId">
<th mat-header-cell *matHeaderCellDef>{{ 'PROJECT.MEMBER.USERID' | translate }}</th>
<td mat-cell *matCellDef="let member">
{{ member.userId }}
</td>
</ng-container>
<ng-container matColumnDef="displayName">
<th mat-header-cell *matHeaderCellDef>{{ 'PROJECT.MEMBER.DISPLAYNAME' | translate }}</th>
<td mat-cell *matCellDef="let member">
{{ member.displayName }}
</td>
</ng-container>
<ng-container matColumnDef="loginname">
<th mat-header-cell *matHeaderCellDef>{{ 'PROJECT.MEMBER.LOGINNAME' | translate }}</th>
<td mat-cell *matCellDef="let member">
{{ member.preferredLoginName }}
</td>
</ng-container>
<ng-container matColumnDef="email">
<th mat-header-cell *matHeaderCellDef>{{ 'PROJECT.MEMBER.EMAIL' | translate }}</th>
<td mat-cell *matCellDef="let member">
{{ member.email }}
</td>
</ng-container>
<ng-container matColumnDef="actions" stickyEnd>
<th mat-header-cell *matHeaderCellDef></th>
<td mat-cell *matCellDef="let member" class="member-action-tr">
<cnsl-table-actions [hasActions]="true">
<button
actions
matTooltip="{{ 'ACTIONS.REMOVE' | translate }}"
color="warn"
(click)="$event.stopPropagation(); triggerDeleteMember(member)"
mat-icon-button
[disabled]="(canDelete$ | async) === false"
data-e2e="remove-member-button"
>
<i class="las la-trash"></i>
</button>
<button menuActions mat-menu-item [routerLink]="['/users', member.userId]">
{{ 'ACTIONS.TABLE.SHOWUSER' | translate: { value: member.displayName } }}
</button>
</cnsl-table-actions>
</td>
</ng-container>
<ng-container matColumnDef="roles">
<th mat-header-cell *matHeaderCellDef class="role-row">{{ 'ROLESLABEL' | translate }}</th>
<td mat-cell *matCellDef="let member" class="role-row">
<mat-chip-listbox class="cnsl-chip-list" aria-label="role selection">
<mat-chip-option
[selectable]="false"
class="cnsl-chip"
*ngFor="let role of member.rolesList"
[removable]="canWrite$ | async"
(removed)="removeRole(member, role)"
data-e2e="role"
>
<div class="cnsl-chip-content">
<div class="cnsl-chip-dot" [style.background]="getColor(role)"></div>
<span>{{ role | roletransform }}</span>
<button *ngIf="canWrite$ | async" matChipRemove data-e2e="remove-role-button">
<mat-icon>cancel</mat-icon>
</button>
</div>
</mat-chip-option>
</mat-chip-listbox>
</td>
</ng-container>
<tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
<tr
class="highlight"
[ngClass]="{ pointer: canWrite$ | async }"
(click)="addRole(member)"
mat-row
*matRowDef="let member; columns: displayedColumns"
></tr>
</table>
</div>
<cnsl-paginator
*ngIf="dataSource"
class="paginator"
#paginator
@if (dataSource) {
<cnsl-refresh-table
(refreshed)="changePage()"
[timestamp]="dataSource.viewTimestamp"
[pageSize]="INITIALPAGESIZE"
[length]="dataSource.totalResult"
[pageSizeOptions]="[25, 50, 100, 250]"
(page)="changePage($event)"
[selection]="selection"
[loading]="dataSource.loading$ | async"
>
</cnsl-paginator>
</cnsl-refresh-table>
@if (selection.hasValue()) {
<ng-container actions>
<ng-content select="[selectactions]"></ng-content>
</ng-container>
}
@if (!selection.hasValue()) {
<div actions>
<ng-content select="[writeactions]"></ng-content>
</div>
}
<div class="table-wrapper">
@if (displayedColumns$ | async; as displayedColumns) {
<table mat-table class="table" aria-label="Elements" [dataSource]="dataSource">
<ng-container matColumnDef="select">
<th mat-header-cell *matHeaderCellDef>
<div class="selection">
<mat-checkbox
[disabled]="(canWrite$ | async) === false"
color="primary"
(change)="$event ? masterToggle() : null"
[checked]="selection.hasValue() && isAllSelected()"
[indeterminate]="selection.hasValue() && !isAllSelected()"
>
</mat-checkbox>
</div>
</th>
<td mat-cell *matCellDef="let row">
<div class="selection">
<mat-checkbox
[disabled]="(canWrite$ | async) === false"
color="primary"
(click)="$event.stopPropagation()"
(change)="$event ? selection.toggle(row) : null"
[checked]="selection.isSelected(row)"
>
@if (row?.userType === UserType.TYPE_HUMAN) {
<cnsl-avatar
class="avatar"
[name]="row.displayName"
[avatarUrl]="row.avatarUrl || ''"
[avatarUrl]="row.avatarUrl || ''"
[forColor]="row?.preferredLoginName"
[size]="32"
>
</cnsl-avatar>
} @else {
<cnsl-avatar [forColor]="row.preferredLoginName" [isMachine]="true">
<i class="las la-robot"></i>
</cnsl-avatar>
}
</mat-checkbox>
</div>
</td>
</ng-container>
<ng-container matColumnDef="userId">
<th mat-header-cell *matHeaderCellDef>{{ 'PROJECT.MEMBER.USERID' | translate }}</th>
<td mat-cell *matCellDef="let member">
{{ member.userId }}
</td>
</ng-container>
<ng-container matColumnDef="displayName">
<th mat-header-cell *matHeaderCellDef>{{ 'PROJECT.MEMBER.DISPLAYNAME' | translate }}</th>
<td mat-cell *matCellDef="let member">
{{ member.displayName }}
</td>
</ng-container>
<ng-container matColumnDef="loginname">
<th mat-header-cell *matHeaderCellDef>{{ 'PROJECT.MEMBER.LOGINNAME' | translate }}</th>
<td mat-cell *matCellDef="let member">
{{ member.preferredLoginName }}
</td>
</ng-container>
<ng-container matColumnDef="email">
<th mat-header-cell *matHeaderCellDef>{{ 'PROJECT.MEMBER.EMAIL' | translate }}</th>
<td mat-cell *matCellDef="let member">
{{ member.email }}
</td>
</ng-container>
<ng-container matColumnDef="actions" stickyEnd>
<th mat-header-cell *matHeaderCellDef></th>
<td mat-cell *matCellDef="let member" class="member-action-tr">
<cnsl-table-actions [hasActions]="true">
<button
actions
matTooltip="{{ 'ACTIONS.REMOVE' | translate }}"
color="warn"
(click)="$event.stopPropagation(); triggerDeleteMember(member)"
mat-icon-button
[disabled]="(canDelete$ | async) === false"
data-e2e="remove-member-button"
>
<i class="las la-trash"></i>
</button>
<button menuActions mat-menu-item [routerLink]="['/users', member.userId]">
{{ 'ACTIONS.TABLE.SHOWUSER' | translate: { value: member.displayName } }}
</button>
</cnsl-table-actions>
</td>
</ng-container>
<ng-container matColumnDef="roles">
<th mat-header-cell *matHeaderCellDef class="role-row">{{ 'ROLESLABEL' | translate }}</th>
<td mat-cell *matCellDef="let member" class="role-row">
<mat-chip-listbox class="cnsl-chip-list" aria-label="role selection">
@for (role of member.rolesList; track role) {
<mat-chip-option
[selectable]="false"
class="cnsl-chip"
[removable]="canWrite$ | async"
(removed)="removeRole(member, role)"
data-e2e="role"
>
<div class="cnsl-chip-content">
<div class="cnsl-chip-dot" [style.background]="getColor(role)"></div>
<span>{{ role | roletransform }}</span>
@if (canWrite$ | async) {
<button matChipRemove data-e2e="remove-role-button">
<mat-icon>cancel</mat-icon>
</button>
}
</div>
</mat-chip-option>
}
</mat-chip-listbox>
</td>
</ng-container>
<tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
<tr
class="highlight"
[ngClass]="{ pointer: canWrite$ | async }"
(click)="addRole(member)"
mat-row
*matRowDef="let member; columns: displayedColumns"
></tr>
</table>
}
</div>
@if (dataSource) {
<cnsl-paginator
class="paginator"
#paginator
[timestamp]="dataSource.viewTimestamp"
[pageSize]="INITIALPAGESIZE"
[length]="dataSource.totalResult"
[pageSizeOptions]="[25, 50, 100, 250]"
(page)="changePage($event)"
>
</cnsl-paginator>
}
</cnsl-refresh-table>
}
@@ -1,115 +1,115 @@
<cnsl-refresh-table
*ngIf="dataSource"
(refreshed)="changePage()"
[timestamp]="dataSource.viewTimestamp"
[hideRefresh]="true"
[selection]="selection"
[loading]="dataSource.loading$ | async"
>
<ng-container actions *ngIf="selection.hasValue()">
<ng-content select="[selectactions]"></ng-content>
</ng-container>
<div actions>
<ng-content select="[writeactions]"></ng-content>
</div>
<div class="table-wrapper">
<table mat-table class="table" aria-label="Elements" [dataSource]="dataSource">
<ng-container matColumnDef="select">
<th mat-header-cell *matHeaderCellDef>
<div class="selection">
<mat-checkbox
[disabled]="false"
color="primary"
(change)="$event ? masterToggle() : null"
[checked]="selection.hasValue() && isAllSelected()"
[indeterminate]="selection.hasValue() && !isAllSelected()"
>
</mat-checkbox>
</div>
</th>
<td mat-cell *matCellDef="let row">
<div class="selection">
<mat-checkbox
[disabled]="false"
color="primary"
(click)="$event.stopPropagation()"
(change)="$event ? selection.toggle(row) : null"
[checked]="selection.isSelected(row)"
>
</mat-checkbox>
</div>
</td>
</ng-container>
<ng-container matColumnDef="displayName">
<th mat-header-cell *matHeaderCellDef>{{ 'USER.MEMBERSHIPS.DISPLAYNAME' | translate }}</th>
<td mat-cell *matCellDef="let membership">
{{ membership.displayName }}
</td>
</ng-container>
<ng-container matColumnDef="type">
<th mat-header-cell *matHeaderCellDef>{{ 'USER.MEMBERSHIPS.TYPE' | translate }}</th>
<td mat-cell *matCellDef="let membership">
<span class="state">{{ getType(membership) }}</span>
</td>
</ng-container>
<ng-container matColumnDef="orgId">
<th mat-header-cell *matHeaderCellDef>{{ 'USER.MEMBERSHIPS.ORGID' | translate }}</th>
<td mat-cell *matCellDef="let membership">
{{ membership.orgId }}
</td>
</ng-container>
<ng-container matColumnDef="rolesList">
<th mat-header-cell *matHeaderCellDef class="role-row">{{ 'ROLESLABEL' | translate }}</th>
<td mat-cell *matCellDef="let membership">
<div class="membership-line">
<mat-chip-listbox class="cnsl-chip-list" aria-label="role selection">
<mat-chip-option
[selectable]="false"
class="cnsl-chip"
*ngFor="let role of membership.rolesList"
[removable]="!!userId"
(removed)="removeRole(membership, role)"
>
<div class="cnsl-chip-content">
<div class="cnsl-chip-dot" [style.background]="getColor(role)"></div>
<span>{{ role | roletransform }}</span>
<button *ngIf="!!userId" matChipRemove>
<mat-icon>cancel</mat-icon>
</button>
</div>
</mat-chip-option>
</mat-chip-listbox>
<button
matTooltip="{{ 'ACTIONS.EDIT' | translate }}"
(click)="goto(membership)"
mat-icon-button
class="goto-btn"
>
<mat-icon>navigate_next</mat-icon>
</button>
</div>
</td>
</ng-container>
<tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
<tr class="highlight" mat-row *matRowDef="let row; columns: displayedColumns"></tr>
</table>
</div>
<cnsl-paginator
*ngIf="dataSource"
class="paginator"
#paginator
@if (dataSource) {
<cnsl-refresh-table
(refreshed)="changePage()"
[timestamp]="dataSource.viewTimestamp"
[pageSize]="INITIALPAGESIZE"
[length]="dataSource.totalResult"
[pageSizeOptions]="[25, 50, 100, 250]"
(page)="changePage($event)"
[hideRefresh]="true"
[selection]="selection"
[loading]="dataSource.loading$ | async"
>
</cnsl-paginator>
</cnsl-refresh-table>
@if (selection.hasValue()) {
<ng-container actions>
<ng-content select="[selectactions]"></ng-content>
</ng-container>
}
<div actions>
<ng-content select="[writeactions]"></ng-content>
</div>
<div class="table-wrapper">
<table mat-table class="table" aria-label="Elements" [dataSource]="dataSource">
<ng-container matColumnDef="select">
<th mat-header-cell *matHeaderCellDef>
<div class="selection">
<mat-checkbox
[disabled]="false"
color="primary"
(change)="$event ? masterToggle() : null"
[checked]="selection.hasValue() && isAllSelected()"
[indeterminate]="selection.hasValue() && !isAllSelected()"
>
</mat-checkbox>
</div>
</th>
<td mat-cell *matCellDef="let row">
<div class="selection">
<mat-checkbox
[disabled]="false"
color="primary"
(click)="$event.stopPropagation()"
(change)="$event ? selection.toggle(row) : null"
[checked]="selection.isSelected(row)"
>
</mat-checkbox>
</div>
</td>
</ng-container>
<ng-container matColumnDef="displayName">
<th mat-header-cell *matHeaderCellDef>{{ 'USER.MEMBERSHIPS.DISPLAYNAME' | translate }}</th>
<td mat-cell *matCellDef="let membership">
{{ membership.displayName }}
</td>
</ng-container>
<ng-container matColumnDef="type">
<th mat-header-cell *matHeaderCellDef>{{ 'USER.MEMBERSHIPS.TYPE' | translate }}</th>
<td mat-cell *matCellDef="let membership">
<span class="state">{{ getType(membership) }}</span>
</td>
</ng-container>
<ng-container matColumnDef="orgId">
<th mat-header-cell *matHeaderCellDef>{{ 'USER.MEMBERSHIPS.ORGID' | translate }}</th>
<td mat-cell *matCellDef="let membership">
{{ membership.orgId }}
</td>
</ng-container>
<ng-container matColumnDef="rolesList">
<th mat-header-cell *matHeaderCellDef class="role-row">{{ 'ROLESLABEL' | translate }}</th>
<td mat-cell *matCellDef="let membership">
<div class="membership-line">
<mat-chip-listbox class="cnsl-chip-list" aria-label="role selection">
@for (role of membership.rolesList; track role) {
<mat-chip-option
[selectable]="false"
class="cnsl-chip"
[removable]="!!userId"
(removed)="removeRole(membership, role)"
>
<div class="cnsl-chip-content">
<div class="cnsl-chip-dot" [style.background]="getColor(role)"></div>
<span>{{ role | roletransform }}</span>
@if (!!userId) {
<button matChipRemove>
<mat-icon>cancel</mat-icon>
</button>
}
</div>
</mat-chip-option>
}
</mat-chip-listbox>
<button
matTooltip="{{ 'ACTIONS.EDIT' | translate }}"
(click)="goto(membership)"
mat-icon-button
class="goto-btn"
>
<mat-icon>navigate_next</mat-icon>
</button>
</div>
</td>
</ng-container>
<tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
<tr class="highlight" mat-row *matRowDef="let row; columns: displayedColumns"></tr>
</table>
</div>
@if (dataSource) {
<cnsl-paginator
class="paginator"
#paginator
[timestamp]="dataSource.viewTimestamp"
[pageSize]="INITIALPAGESIZE"
[length]="dataSource.totalResult"
[pageSizeOptions]="[25, 50, 100, 250]"
(page)="changePage($event)"
>
</cnsl-paginator>
}
</cnsl-refresh-table>
}
@@ -1,43 +1,46 @@
<div class="title-row">
<h1 class="metadata-title" mat-dialog-title>{{ 'METADATA.TITLE' | translate }}</h1>
<span class="fill-space"></span>
<p *ngIf="ts" class="ts cnsl-secondary-text">{{ ts | timestampToDate | localizedDate: 'dd. MMM, HH:mm' }}</p>
@if (ts) {
<p class="ts cnsl-secondary-text">{{ ts | timestampToDate | localizedDate: 'dd. MMM, HH:mm' }}</p>
}
</div>
<div mat-dialog-content class="metadata-dialog-content">
<form *ngFor="let md of metadata; index as i" (ngSubmit)="saveElement(i)">
<div class="content">
<cnsl-form-field #key id="key{{ i }}" class="formfield">
<cnsl-label>{{ 'METADATA.KEY' | translate }}</cnsl-label>
<input cnslInput [(ngModel)]="md.key" [ngModelOptions]="{ standalone: true }" />
</cnsl-form-field>
<cnsl-form-field #value id="value{{ i }}" class="formfield">
<cnsl-label>{{ 'METADATA.VALUE' | translate }}</cnsl-label>
<input cnslInput [(ngModel)]="md.value" [ngModelOptions]="{ standalone: true }" />
</cnsl-form-field>
<button
mat-icon-button
[disabled]="!(md.key && md.value)"
class="set-button"
type="submit"
color="primary"
matTooltip="{{ 'ACTIONS.SAVE' | translate }}"
>
<i class="las la-save"></i>
</button>
<button
mat-icon-button
(click)="removeEntry(i)"
[disabled]="metadata.length < 2 && i === 0 && !md.key"
class="rm-button"
type="button"
color="warn"
matTooltip="{{ 'ACTIONS.REMOVE' | translate }}"
>
<i class="las la-trash"></i>
</button>
</div>
</form>
@for (md of metadata; track md; let i = $index) {
<form (ngSubmit)="saveElement(i)">
<div class="content">
<cnsl-form-field #key id="key{{ i }}" class="formfield">
<cnsl-label>{{ 'METADATA.KEY' | translate }}</cnsl-label>
<input cnslInput [(ngModel)]="md.key" [ngModelOptions]="{ standalone: true }" />
</cnsl-form-field>
<cnsl-form-field #value id="value{{ i }}" class="formfield">
<cnsl-label>{{ 'METADATA.VALUE' | translate }}</cnsl-label>
<input cnslInput [(ngModel)]="md.value" [ngModelOptions]="{ standalone: true }" />
</cnsl-form-field>
<button
mat-icon-button
[disabled]="!(md.key && md.value)"
class="set-button"
type="submit"
color="primary"
matTooltip="{{ 'ACTIONS.SAVE' | translate }}"
>
<i class="las la-save"></i>
</button>
<button
mat-icon-button
(click)="removeEntry(i)"
[disabled]="metadata.length < 2 && i === 0 && !md.key"
class="rm-button"
type="button"
color="warn"
matTooltip="{{ 'ACTIONS.REMOVE' | translate }}"
>
<i class="las la-trash"></i>
</button>
</div>
</form>
}
<button (click)="addEntry()" mat-stroked-button type="button">
<div class="cnsl-action-button">
<mat-icon>add</mat-icon>
@@ -1,36 +1,43 @@
<cnsl-card class="metadata-details" [title]="'DESCRIPTIONS.METADATA_TITLE' | translate" [description]="description">
<mat-spinner card-actions class="spinner" diameter="20" *ngIf="loading"></mat-spinner>
@if (loading) {
<mat-spinner card-actions class="spinner" diameter="20"></mat-spinner>
}
<cnsl-refresh-table *ngIf="dataSource$ | async as dataSource" [loading]="loading" (refreshed)="refresh.emit()">
<button actions [disabled]="disabled" mat-raised-button color="primary" class="edit" (click)="editClicked.emit()">
{{ 'ACTIONS.EDIT' | translate }}
</button>
<table class="table" mat-table [dataSource]="dataSource">
<ng-container matColumnDef="key">
<th mat-header-cell *matHeaderCellDef>{{ 'METADATA.KEY' | translate }}</th>
<td mat-cell *matCellDef="let metadata">
<span *ngIf="metadata?.key" class="centered">
{{ metadata.key }}
</span>
</td>
</ng-container>
<ng-container matColumnDef="value">
<th mat-header-cell *matHeaderCellDef>{{ 'METADATA.VALUE' | translate }}</th>
<td mat-cell *matCellDef="let metadata">
<span *ngIf="metadata?.value" class="centered">
{{ metadata.value }}
</span>
</td>
</ng-container>
<tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
<tr class="highlight" mat-row *matRowDef="let row; columns: displayedColumns"></tr>
</table>
<div *ngIf="!loading && !dataSource?.data?.length" class="no-content-row">
<i class="las la-exclamation"></i>
<span>{{ 'USER.MFA.EMPTY' | translate }}</span>
</div>
</cnsl-refresh-table>
@if (dataSource$ | async; as dataSource) {
<cnsl-refresh-table [loading]="loading" (refreshed)="refresh.emit()">
<button actions [disabled]="disabled" mat-raised-button color="primary" class="edit" (click)="editClicked.emit()">
{{ 'ACTIONS.EDIT' | translate }}
</button>
<table class="table" mat-table [dataSource]="dataSource">
<ng-container matColumnDef="key">
<th mat-header-cell *matHeaderCellDef>{{ 'METADATA.KEY' | translate }}</th>
<td mat-cell *matCellDef="let metadata">
@if (metadata?.key) {
<span class="centered">
{{ metadata.key }}
</span>
}
</td>
</ng-container>
<ng-container matColumnDef="value">
<th mat-header-cell *matHeaderCellDef>{{ 'METADATA.VALUE' | translate }}</th>
<td mat-cell *matCellDef="let metadata">
@if (metadata?.value) {
<span class="centered">
{{ metadata.value }}
</span>
}
</td>
</ng-container>
<tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
<tr class="highlight" mat-row *matRowDef="let row; columns: displayedColumns"></tr>
</table>
@if (!loading && !dataSource?.data?.length) {
<div class="no-content-row">
<i class="las la-exclamation"></i>
<span>{{ 'USER.MFA.EMPTY' | translate }}</span>
</div>
}
</cnsl-refresh-table>
}
</cnsl-card>
@@ -1,11 +1,15 @@
<button class="nav-toggle" [ngClass]="{ active }" (click)="clicked.emit()">
<div class="c_label">
<span> {{ label }} </span>
<div *ngIf="count && count < 100" class="count">
<span>{{ count }}</span>
</div>
<div *ngIf="count && count >= 100" class="count">
<span>99+</span>
</div>
@if (count && count < 100) {
<div class="count">
<span>{{ count }}</span>
</div>
}
@if (count && count >= 100) {
<div class="count">
<span>99+</span>
</div>
}
</div>
</button>
@@ -1,6 +1,8 @@
<div class="onboarding-card" cdkTrapFocus>
<div class="spinner-w">
<mat-spinner diameter="20" *ngIf="loading$ | async" color="accent"> </mat-spinner>
@if (loading$ | async) {
<mat-spinner diameter="20" color="accent"> </mat-spinner>
}
</div>
<div class="progress-header">
<h2>{{ 'ONBOARDING.CARD.TITLE' | translate }}</h2>
@@ -15,7 +17,7 @@
</div>
<div class="actions-list">
<ng-container *ngFor="let action of actions | async">
@for (action of actions | async; track action) {
<a
[routerLink]="action[1].link"
[queryParams]="{ id: action[1].fragment }"
@@ -23,18 +25,14 @@
[ngClass]="{ done: action[1].reached !== undefined }"
>
<div class="state-circle">
<mat-icon
*ngIf="action[1]?.reached !== undefined"
class="success-icon"
matTooltip="{{ action[1].reached | milestone }}"
>check_circle</mat-icon
>
@if (action[1]?.reached !== undefined) {
<mat-icon class="success-icon" matTooltip="{{ action[1].reached | milestone }}">check_circle</mat-icon>
}
</div>
<span class="name">{{ 'ONBOARDING.MILESTONES.' + action[0] + '.title' | translate }}</span>
<mat-icon class="arrow-right">keyboard_arrow_right</mat-icon>
</a>
</ng-container>
}
</div>
<div class="no-thanks-wrapper">
<a class="no-thanks-btn" (click)="dismiss()">{{ 'ONBOARDING.DISMISS' | translate }}</a>
@@ -1,62 +1,60 @@
<div class="onboarding-header">
<h2 class="desc">{{ 'ONBOARDING.DESCRIPTION' | translate }}</h2>
<ng-container *ngIf="!adminService.hideOnboarding && (adminService.progressAllDone | async) === false">
@if (!adminService.hideOnboarding && (adminService.progressAllDone | async) === false) {
<div class="onboarding-progress-bar-wrapper">
<mat-progress-bar
class="progress"
mode="determinate"
[value]="adminService.progressPercentage | async"
></mat-progress-bar>
<div class="prog-desc cnsl-secondary-text">
{{ adminService.progressDone | async }} / {{ adminService.progressTotal | async }}
{{ 'ONBOARDING.COMPLETED' | translate }}
</div>
<mat-spinner diameter="20" *ngIf="adminService.onboardingLoading | async"></mat-spinner>
@if (adminService.onboardingLoading | async) {
<mat-spinner diameter="20"></mat-spinner>
}
</div>
</ng-container>
}
<div
class="action-card-wrapper"
[ngClass]="{ alldone: adminService.hideOnboarding || (adminService.progressAllDone | async) }"
>
<ng-container *ngFor="let action of actions | async">
<a
*ngIf="!action[1].externalLink"
[routerLink]="action[1].link"
[queryParams]="{ id: action[1].fragment }"
class="action-card card"
[ngClass]="{ done: action[1].reached !== undefined }"
>
<ng-template
[ngTemplateOutlet]="onboardingContent"
[ngTemplateOutletContext]="{ title: action[0], action: action[1] }"
@for (action of actions | async; track action) {
@if (!action[1].externalLink) {
<a
[routerLink]="action[1].link"
[queryParams]="{ id: action[1].fragment }"
class="action-card card"
[ngClass]="{ done: action[1].reached !== undefined }"
>
</ng-template>
</a>
<a
*ngIf="action[1].externalLink"
[href]="action[1].link"
class="action-card card"
[ngClass]="{ done: action[1].reached !== undefined }"
>
<ng-template
[ngTemplateOutlet]="onboardingContent"
[ngTemplateOutletContext]="{ title: action[0], action: action[1] }"
>
</ng-template>
</a>
</ng-container>
<ng-template
[ngTemplateOutlet]="onboardingContent"
[ngTemplateOutletContext]="{ title: action[0], action: action[1] }"
>
</ng-template>
</a>
}
@if (action[1].externalLink) {
<a [href]="action[1].link" class="action-card card" [ngClass]="{ done: action[1].reached !== undefined }">
<ng-template
[ngTemplateOutlet]="onboardingContent"
[ngTemplateOutletContext]="{ title: action[0], action: action[1] }"
>
</ng-template>
</a>
}
}
</div>
</div>
<ng-template #onboardingContent let-action="action" let-title="title">
<div class="state-circle">
<mat-icon *ngIf="action?.reached !== undefined" matTooltip="{{ action.reached | milestone }}" class="success-icon"
>check_circle</mat-icon
>
@if (action?.reached !== undefined) {
<mat-icon matTooltip="{{ action.reached | milestone }}" class="success-icon">check_circle</mat-icon>
}
</div>
<div class="action-content">
@@ -1,6 +1,8 @@
<div class="org-context-card" cdkTrapFocus>
<div class="spinner-w">
<mat-spinner diameter="20" *ngIf="orgLoading$ | async" color="accent"> </mat-spinner>
@if (orgLoading$ | async) {
<mat-spinner diameter="20" color="accent"> </mat-spinner>
}
</div>
<div class="filter-wrapper">
@@ -16,37 +18,39 @@
</div>
<div class="org-wrapper" cnslScrollable (scrollPosition)="onNearEndScroll($event)">
<button
class="org-button-with-pin"
mat-button
[ngClass]="{
active: pinnedorg.id === org.id,
'border-bottom': pinned.selected.length && i === pinned.selected.length - 1,
}"
[disabled]="!pinnedorg.id"
*ngFor="let pinnedorg of pinned.selected; index as i"
(click)="setActiveOrg(pinnedorg)"
>
<div class="org-flex-row">
<span class="org-span">{{ pinnedorg?.name ? pinnedorg.name : 'NO NAME' }}</span>
<template [ngTemplateOutlet]="toggleButton" [ngTemplateOutletContext]="{ key: pinnedorg }"></template>
</div>
</button>
<ng-container *ngFor="let temporg of orgs$ | async">
@for (pinnedorg of pinned.selected; track pinnedorg; let i = $index) {
<button
*ngIf="!pinned.isSelected(temporg)"
class="org-button-with-pin"
mat-button
[ngClass]="{ active: temporg.id === org.id }"
[disabled]="!temporg.id"
(click)="setActiveOrg(temporg)"
[ngClass]="{
active: pinnedorg.id === org.id,
'border-bottom': pinned.selected.length && i === pinned.selected.length - 1,
}"
[disabled]="!pinnedorg.id"
(click)="setActiveOrg(pinnedorg)"
>
<div class="org-flex-row">
<span class="org-span">{{ temporg?.name ? temporg.name : 'NO NAME' }}</span>
<template [ngTemplateOutlet]="toggleButton" [ngTemplateOutletContext]="{ key: temporg }"></template>
<span class="org-span">{{ pinnedorg?.name ? pinnedorg.name : 'NO NAME' }}</span>
<template [ngTemplateOutlet]="toggleButton" [ngTemplateOutletContext]="{ key: pinnedorg }"></template>
</div>
</button>
</ng-container>
}
@for (temporg of orgs$ | async; track temporg) {
@if (!pinned.isSelected(temporg)) {
<button
class="org-button-with-pin"
mat-button
[ngClass]="{ active: temporg.id === org.id }"
[disabled]="!temporg.id"
(click)="setActiveOrg(temporg)"
>
<div class="org-flex-row">
<span class="org-span">{{ temporg?.name ? temporg.name : 'NO NAME' }}</span>
<template [ngTemplateOutlet]="toggleButton" [ngTemplateOutletContext]="{ key: temporg }"></template>
</div>
</button>
}
}
</div>
<ng-template cnslHasRole [hasRole]="['iam.read']">
@@ -73,7 +77,11 @@
class="edit-button"
mat-icon-button
>
<mat-icon *ngIf="pinned.isSelected(key)" svgIcon="mdi_pin"></mat-icon>
<mat-icon svgIcon="mdi_pin_outline" *ngIf="!pinned.isSelected(key)"></mat-icon>
@if (pinned.isSelected(key)) {
<mat-icon svgIcon="mdi_pin"></mat-icon>
}
@if (!pinned.isSelected(key)) {
<mat-icon svgIcon="mdi_pin_outline"></mat-icon>
}
</button>
</ng-template>
@@ -38,8 +38,12 @@
[valueToCopy]="org.primaryDomain"
(copiedValue)="copied = $event"
>
<i *ngIf="copied !== org.primaryDomain" class="las la-clipboard"></i>
<i *ngIf="copied === org.primaryDomain" class="las la-clipboard-check"></i>
@if (copied !== org.primaryDomain) {
<i class="las la-clipboard"></i>
}
@if (copied === org.primaryDomain) {
<i class="las la-clipboard-check"></i>
}
</button>
</div>
</td>
@@ -50,25 +54,26 @@
{{ 'ORG.PAGES.NAME' | translate }}
</th>
<td mat-cell *cnslCellDef="let org; dataSource: dataSource" (click)="setAndNavigateToOrg(org)">
<span>{{ org.name }}</span
><span *ngIf="defaultOrgId === org.id" class="state orgdefaultlabel">{{
'ORG.PAGES.DEFAULTLABEL' | translate
}}</span>
<span>{{ org.name }}</span>
@if (defaultOrgId === org.id) {
<span class="state orgdefaultlabel">{{ 'ORG.PAGES.DEFAULTLABEL' | translate }}</span>
}
</td>
</ng-container>
<ng-container matColumnDef="state">
<th mat-header-cell *matHeaderCellDef>{{ 'ORG.PAGES.STATE' | translate }}</th>
<td mat-cell *cnslCellDef="let org; dataSource: dataSource" (click)="setAndNavigateToOrg(org)">
<span
class="state"
[ngClass]="{
active: org.state === OrganizationState.ACTIVE,
inactive: org.state === OrganizationState.INACTIVE,
}"
*ngIf="org.state"
>{{ 'ORG.STATE.' + org.state | translate }}</span
>
@if (org.state) {
<span
class="state"
[ngClass]="{
active: org.state === OrganizationState.ACTIVE,
inactive: org.state === OrganizationState.INACTIVE,
}"
>{{ 'ORG.STATE.' + org.state | translate }}</span
>
}
</td>
</ng-container>
@@ -3,31 +3,45 @@
<p class="length">
<span>{{ length }} </span>{{ 'PAGINATOR.COUNT' | translate }}
</p>
<p class="ts cnsl-secondary-text" *ngIf="timestamp" data-e2e="timestamp">
{{ timestamp | timestampToDate | localizedDate: 'EEEE dd. MMM yyyy, HH:mm' }}
</p>
@if (timestamp) {
<p class="ts cnsl-secondary-text" data-e2e="timestamp">
{{ timestamp | timestampToDate | localizedDate: 'EEEE dd. MMM yyyy, HH:mm' }}
</p>
}
</div>
<span class="fill-space"></span>
<span class="pos cnsl-secondary-text" *ngIf="!hidePagination">{{ startIndex }} - {{ endIndex }} </span>
<div class="row" *ngIf="!hidePagination">
<cnsl-form-field class="size">
<mat-select class="paginator-select" [value]="pageSize" (selectionChange)="updatePageSize($event.value)">
<mat-option *ngFor="let sizeOption of pageSizeOptions" [value]="sizeOption">
{{ sizeOption }}
</mat-option>
</mat-select>
</cnsl-form-field>
<button *ngIf="previousPossible" (click)="previous()" [disabled]="!previousPossible" mat-stroked-button>
{{ 'PAGINATOR.PREVIOUS' | translate }}
</button>
<button *ngIf="nextPossible" (click)="next()" [disabled]="!nextPossible" mat-stroked-button>
{{ 'PAGINATOR.NEXT' | translate }}
</button>
</div>
@if (!hidePagination) {
<span class="pos cnsl-secondary-text">{{ startIndex }} - {{ endIndex }} </span>
}
@if (!hidePagination) {
<div class="row">
<cnsl-form-field class="size">
<mat-select class="paginator-select" [value]="pageSize" (selectionChange)="updatePageSize($event.value)">
@for (sizeOption of pageSizeOptions; track sizeOption) {
<mat-option [value]="sizeOption">
{{ sizeOption }}
</mat-option>
}
</mat-select>
</cnsl-form-field>
@if (previousPossible) {
<button (click)="previous()" [disabled]="!previousPossible" mat-stroked-button>
{{ 'PAGINATOR.PREVIOUS' | translate }}
</button>
}
@if (nextPossible) {
<button (click)="next()" [disabled]="!nextPossible" mat-stroked-button>
{{ 'PAGINATOR.NEXT' | translate }}
</button>
}
</div>
}
<div class="row" *ngIf="showMoreButton">
<button (click)="moreRequested.emit()" mat-stroked-button [disabled]="disableShowMore">
{{ 'PAGINATOR.MORE' | translate }}
</button>
</div>
@if (showMoreButton) {
<div class="row">
<button (click)="moreRequested.emit()" mat-stroked-button [disabled]="disableShowMore">
{{ 'PAGINATOR.MORE' | translate }}
</button>
</div>
}
</div>
@@ -1,58 +1,85 @@
<div class="validation-col">
<div class="val" *ngIf="policy.minLength">
<i *ngIf="password?.value?.length === 0; else showSpinner" class="las la-times red"></i>
<ng-template #showSpinner>
<div
*ngIf="
(password && password.errors && password.errors['minlength']) || password?.value?.length === 0 as currentError;
else trueminlength
"
class="complexity-sp-wrapper"
>
<mat-progress-spinner
class="complexity-spinner"
diameter="20"
[color]="currentError ? 'warn' : 'valid'"
mode="determinate"
[value]="(password?.value?.length / minLength) * 100"
>
</mat-progress-spinner>
</div>
</ng-template>
<ng-template #trueminlength>
<i class="las la-check green"></i>
</ng-template>
<span class="cnsl-secondary-text"
>{{ 'USER.PASSWORD.MINLENGTHERROR' | translate: { value: policy.minLength } }} ({{ password?.value?.length }}/{{
policy.minLength
}})
</span>
</div>
<div class="val" *ngIf="policy.hasSymbol">
<i *ngIf="password?.pristine || password?.errors?.['errorssymbolerror']" class="las la-times red"></i>
<i *ngIf="password?.dirty && !password?.errors?.['errorssymbolerror']" class="las la-check green"></i>
<span class="cnsl-secondary-text"> {{ 'ERRORS.SYMBOLERROR' | translate }}</span>
</div>
<div class="val" *ngIf="policy.hasNumber">
<i *ngIf="password?.pristine || password?.errors?.['errorsnumbererror']" class="las la-times red"></i>
<i *ngIf="password?.dirty && !password?.errors?.['errorsnumbererror']" class="las la-check green"></i>
<span class="cnsl-secondary-text"> {{ 'ERRORS.NUMBERERROR' | translate }}</span>
</div>
<div class="val" *ngIf="policy.hasUppercase">
<i *ngIf="password?.pristine || password?.errors?.['errorsuppercasemissing']" class="las la-times red"></i>
<i *ngIf="password?.dirty && !password?.errors?.['errorsuppercasemissing']" class="las la-check green"></i>
<span class="cnsl-secondary-text"> {{ 'ERRORS.UPPERCASEMISSING' | translate }}</span>
</div>
<div class="val" *ngIf="policy.hasLowercase">
<i *ngIf="password?.pristine || password?.errors?.['errorslowercasemissing']" class="las la-times red"></i>
<i *ngIf="password?.dirty && !password?.errors?.['errorslowercasemissing']" class="las la-check green"></i>
<span class="cnsl-secondary-text">{{ 'ERRORS.LOWERCASEMISSING' | translate }}</span>
</div>
@if (policy.minLength) {
<div class="val">
@if (password?.value?.length === 0) {
<i class="las la-times red"></i>
} @else {
@if (
(password && password.errors && password.errors['minlength']) || password?.value?.length === 0;
as currentError
) {
<div class="complexity-sp-wrapper">
<mat-progress-spinner
class="complexity-spinner"
diameter="20"
[color]="currentError ? 'warn' : 'valid'"
mode="determinate"
[value]="(password?.value?.length / minLength) * 100"
>
</mat-progress-spinner>
</div>
} @else {
<i class="las la-check green"></i>
}
}
<span class="cnsl-secondary-text"
>{{ 'USER.PASSWORD.MINLENGTHERROR' | translate: { value: policy.minLength } }} ({{ password?.value?.length }}/{{
policy.minLength
}})
</span>
</div>
}
@if (policy.hasSymbol) {
<div class="val">
@if (password?.pristine || password?.errors?.['errorssymbolerror']) {
<i class="las la-times red"></i>
}
@if (password?.dirty && !password?.errors?.['errorssymbolerror']) {
<i class="las la-check green"></i>
}
<span class="cnsl-secondary-text"> {{ 'ERRORS.SYMBOLERROR' | translate }}</span>
</div>
}
@if (policy.hasNumber) {
<div class="val">
@if (password?.pristine || password?.errors?.['errorsnumbererror']) {
<i class="las la-times red"></i>
}
@if (password?.dirty && !password?.errors?.['errorsnumbererror']) {
<i class="las la-check green"></i>
}
<span class="cnsl-secondary-text"> {{ 'ERRORS.NUMBERERROR' | translate }}</span>
</div>
}
@if (policy.hasUppercase) {
<div class="val">
@if (password?.pristine || password?.errors?.['errorsuppercasemissing']) {
<i class="las la-times red"></i>
}
@if (password?.dirty && !password?.errors?.['errorsuppercasemissing']) {
<i class="las la-check green"></i>
}
<span class="cnsl-secondary-text"> {{ 'ERRORS.UPPERCASEMISSING' | translate }}</span>
</div>
}
@if (policy.hasLowercase) {
<div class="val">
@if (password?.pristine || password?.errors?.['errorslowercasemissing']) {
<i class="las la-times red"></i>
}
@if (password?.dirty && !password?.errors?.['errorslowercasemissing']) {
<i class="las la-check green"></i>
}
<span class="cnsl-secondary-text">{{ 'ERRORS.LOWERCASEMISSING' | translate }}</span>
</div>
}
<div class="val">
<i *ngIf="password?.value?.length === 0 || password?.value?.length <= 70" class="las la-check green"></i>
<i *ngIf="password?.value?.length > 70" class="las la-times red"></i>
@if (password?.value?.length === 0 || password?.value?.length <= 70) {
<i class="las la-check green"></i>
}
@if (password?.value?.length > 70) {
<i class="las la-times red"></i>
}
<span class="cnsl-secondary-text"
>{{ 'USER.PASSWORD.MAXLENGTHERROR' | translate: { value: 70 } }} ({{ password?.value?.length }}/{{ 70 }})
@@ -1,140 +1,167 @@
<div class="spinner-wr">
<mat-spinner diameter="30" *ngIf="loading" color="primary"></mat-spinner>
@if (loading) {
<mat-spinner diameter="30" color="primary"></mat-spinner>
}
</div>
<h2>{{ 'DESCRIPTIONS.SETTINGS.DOMAINS.TITLE' | translate }}</h2>
<p class="cnsl-secondary-text">{{ 'DESCRIPTIONS.SETTINGS.DOMAINS.DESCRIPTION' | translate }}</p>
<cnsl-info-section *ngIf="isDefault"> {{ 'POLICY.DEFAULTLABEL' | translate }}</cnsl-info-section>
<button
*ngIf="serviceType === PolicyComponentServiceType.MGMT && !isDefault"
matTooltip="{{ 'POLICY.RESET' | translate }}"
color="warn"
(click)="removePolicy()"
mat-stroked-button
[disabled]="
([
serviceType === PolicyComponentServiceType.ADMIN
? 'iam.policy.write'
: serviceType === PolicyComponentServiceType.MGMT
? 'policy.write'
: '',
]
| hasRole
| async) === false
"
>
{{ 'POLICY.RESET' | translate }}
</button>
<div class="domain-policy-content" *ngIf="domainData">
<cnsl-card
[title]="'DESCRIPTIONS.SETTINGS.DOMAINS.LOGIN_NAME_PATTERN.TITLE' | translate"
[description]="'DESCRIPTIONS.SETTINGS.DOMAINS.LOGIN_NAME_PATTERN.DESCRIPTION' | translate"
@if (isDefault) {
<cnsl-info-section> {{ 'POLICY.DEFAULTLABEL' | translate }}</cnsl-info-section>
}
@if (serviceType === PolicyComponentServiceType.MGMT && !isDefault) {
<button
matTooltip="{{ 'POLICY.RESET' | translate }}"
color="warn"
(click)="removePolicy()"
mat-stroked-button
[disabled]="
([
serviceType === PolicyComponentServiceType.ADMIN
? 'iam.policy.write'
: serviceType === PolicyComponentServiceType.MGMT
? 'policy.write'
: '',
]
| hasRole
| async) === false
"
>
<div class="row">
<mat-checkbox
color="primary"
name="hasNumber"
ngDefaultControl
[(ngModel)]="domainData.userLoginMustBeDomain"
[disabled]="
([
serviceType === PolicyComponentServiceType.ADMIN
? 'iam.policy.write'
: serviceType === PolicyComponentServiceType.MGMT
? 'policy.write'
: '',
]
| hasRole
| async) === false
"
>
{{ 'POLICY.DATA.USERLOGINMUSTBEDOMAIN' | translate }}
</mat-checkbox>
</div>
{{ 'POLICY.RESET' | translate }}
</button>
}
<cnsl-info-section>
<div>
<span>{{ 'POLICY.DATA.USERLOGINMUSTBEDOMAIN_DESCRIPTION' | translate }}</span>
<div class="loginname-preview">
<div class="left-right">
<div *ngIf="domainData.userLoginMustBeDomain"><small>domain</small><span>acme.com</span></div>
<div *ngIf="domainData.userLoginMustBeDomain"><small>username</small><span>john</span></div>
<div *ngIf="domainData.userLoginMustBeDomain"><small>loginname</small><span>john&#64;acme.com</span></div>
<div *ngIf="!domainData.userLoginMustBeDomain"><small>domain</small><span>acme.com</span></div>
<div *ngIf="!domainData.userLoginMustBeDomain"><small>username</small><span>john&#64;acme.com</span></div>
<div *ngIf="!domainData.userLoginMustBeDomain"><small>loginname</small><span>john&#64;acme.com</span></div>
</div>
<i class="las la-arrow-right"></i>
<div class="left-right">
<div *ngIf="domainData.userLoginMustBeDomain"><small>domain</small><span>acme.com</span></div>
<div *ngIf="domainData.userLoginMustBeDomain"><small>username</small><span>john&#64;acme.com</span></div>
<div *ngIf="domainData.userLoginMustBeDomain"><small>loginname</small><span>john&#64;acme.com</span></div>
<div *ngIf="!domainData.userLoginMustBeDomain"><small>domain</small><span>acme.com</span></div>
<div *ngIf="!domainData.userLoginMustBeDomain"><small>username</small><span>john</span></div>
<div *ngIf="!domainData.userLoginMustBeDomain"><small>loginname</small><span>john&#64;acme.com</span></div>
@if (domainData) {
<div class="domain-policy-content">
<cnsl-card
[title]="'DESCRIPTIONS.SETTINGS.DOMAINS.LOGIN_NAME_PATTERN.TITLE' | translate"
[description]="'DESCRIPTIONS.SETTINGS.DOMAINS.LOGIN_NAME_PATTERN.DESCRIPTION' | translate"
>
<div class="row">
<mat-checkbox
color="primary"
name="hasNumber"
ngDefaultControl
[(ngModel)]="domainData.userLoginMustBeDomain"
[disabled]="
([
serviceType === PolicyComponentServiceType.ADMIN
? 'iam.policy.write'
: serviceType === PolicyComponentServiceType.MGMT
? 'policy.write'
: '',
]
| hasRole
| async) === false
"
>
{{ 'POLICY.DATA.USERLOGINMUSTBEDOMAIN' | translate }}
</mat-checkbox>
</div>
<cnsl-info-section>
<div>
<span>{{ 'POLICY.DATA.USERLOGINMUSTBEDOMAIN_DESCRIPTION' | translate }}</span>
<div class="loginname-preview">
<div class="left-right">
@if (domainData.userLoginMustBeDomain) {
<div><small>domain</small><span>acme.com</span></div>
}
@if (domainData.userLoginMustBeDomain) {
<div><small>username</small><span>john</span></div>
}
@if (domainData.userLoginMustBeDomain) {
<div><small>loginname</small><span>john&#64;acme.com</span></div>
}
@if (!domainData.userLoginMustBeDomain) {
<div><small>domain</small><span>acme.com</span></div>
}
@if (!domainData.userLoginMustBeDomain) {
<div><small>username</small><span>john&#64;acme.com</span></div>
}
@if (!domainData.userLoginMustBeDomain) {
<div><small>loginname</small><span>john&#64;acme.com</span></div>
}
</div>
<i class="las la-arrow-right"></i>
<div class="left-right">
@if (domainData.userLoginMustBeDomain) {
<div><small>domain</small><span>acme.com</span></div>
}
@if (domainData.userLoginMustBeDomain) {
<div><small>username</small><span>john&#64;acme.com</span></div>
}
@if (domainData.userLoginMustBeDomain) {
<div><small>loginname</small><span>john&#64;acme.com</span></div>
}
@if (!domainData.userLoginMustBeDomain) {
<div><small>domain</small><span>acme.com</span></div>
}
@if (!domainData.userLoginMustBeDomain) {
<div><small>username</small><span>john</span></div>
}
@if (!domainData.userLoginMustBeDomain) {
<div><small>loginname</small><span>john&#64;acme.com</span></div>
}
</div>
</div>
</div>
</cnsl-info-section>
</cnsl-card>
<cnsl-card
[title]="'DESCRIPTIONS.SETTINGS.DOMAINS.DOMAIN_VERIFICATION.TITLE' | translate"
[description]="'DESCRIPTIONS.SETTINGS.DOMAINS.DOMAIN_VERIFICATION.DESCRIPTION' | translate"
>
<div class="row">
<mat-checkbox
color="primary"
name="hasNumber"
ngDefaultControl
[(ngModel)]="domainData.validateOrgDomains"
[disabled]="
([
serviceType === PolicyComponentServiceType.ADMIN
? 'iam.policy.write'
: serviceType === PolicyComponentServiceType.MGMT
? 'policy.write'
: '',
]
| hasRole
| async) === false
"
>
{{ 'POLICY.DATA.VALIDATEORGDOMAINS' | translate }}
</mat-checkbox>
</div>
</cnsl-info-section>
</cnsl-card>
<cnsl-card
[title]="'DESCRIPTIONS.SETTINGS.DOMAINS.DOMAIN_VERIFICATION.TITLE' | translate"
[description]="'DESCRIPTIONS.SETTINGS.DOMAINS.DOMAIN_VERIFICATION.DESCRIPTION' | translate"
>
<div class="row">
<mat-checkbox
color="primary"
name="hasNumber"
ngDefaultControl
[(ngModel)]="domainData.validateOrgDomains"
[disabled]="
([
serviceType === PolicyComponentServiceType.ADMIN
? 'iam.policy.write'
: serviceType === PolicyComponentServiceType.MGMT
? 'policy.write'
: '',
]
| hasRole
| async) === false
"
>
{{ 'POLICY.DATA.VALIDATEORGDOMAINS' | translate }}
</mat-checkbox>
</div>
</cnsl-card>
<cnsl-card
[title]="'DESCRIPTIONS.SETTINGS.DOMAINS.SMTP_SENDER_ADDRESS.TITLE' | translate"
[description]="'DESCRIPTIONS.SETTINGS.DOMAINS.SMTP_SENDER_ADDRESS.DESCRIPTION' | translate"
>
<div class="row">
<mat-checkbox
color="primary"
name="hasNumber"
ngDefaultControl
[(ngModel)]="domainData.smtpSenderAddressMatchesInstanceDomain"
[disabled]="
([
serviceType === PolicyComponentServiceType.ADMIN
? 'iam.policy.write'
: serviceType === PolicyComponentServiceType.MGMT
? 'policy.write'
: '',
]
| hasRole
| async) === false
"
>
{{ 'POLICY.DATA.SMTPSENDERADDRESSMATCHESINSTANCEDOMAIN' | translate }}
</mat-checkbox>
</div>
</cnsl-card>
</div>
</cnsl-card>
<cnsl-card
[title]="'DESCRIPTIONS.SETTINGS.DOMAINS.SMTP_SENDER_ADDRESS.TITLE' | translate"
[description]="'DESCRIPTIONS.SETTINGS.DOMAINS.SMTP_SENDER_ADDRESS.DESCRIPTION' | translate"
>
<div class="row">
<mat-checkbox
color="primary"
name="hasNumber"
ngDefaultControl
[(ngModel)]="domainData.smtpSenderAddressMatchesInstanceDomain"
[disabled]="
([
serviceType === PolicyComponentServiceType.ADMIN
? 'iam.policy.write'
: serviceType === PolicyComponentServiceType.MGMT
? 'policy.write'
: '',
]
| hasRole
| async) === false
"
>
{{ 'POLICY.DATA.SMTPSENDERADDRESSMATCHESINSTANCEDOMAIN' | translate }}
</mat-checkbox>
</div>
</cnsl-card>
</div>
}
<div class="btn-container">
<button
(click)="savePolicy()"
@@ -2,7 +2,9 @@
<p class="cnsl-secondary-text">{{ 'DESCRIPTIONS.SETTINGS.LANGUAGES.DESCRIPTION' | translate }}</p>
<div class="spinner-wr">
<mat-spinner diameter="30" *ngIf="loading" color="primary"></mat-spinner>
@if (loading) {
<mat-spinner diameter="30" color="primary"></mat-spinner>
}
</div>
<div>
@@ -30,43 +32,43 @@
</button>
</div>
<div class="languages-drop-target">
<div
class="card languages-box"
*ngFor="let lang of (localState$ | async)!.allowed; index as i"
[cdkDragData]="lang"
cdkDrag
[cdkDragDisabled]="(canWriteRestrictions$ | async) === false"
mat-list-item
>
<span class="index">{{ i + 1 }}</span>
<span class="locale">{{ lang }}</span>
<span class="lang">{{ 'SETTING.LANGUAGES.OPTIONS.' + lang | translate }} </span>
<span *ngIf="lang === (defaultLang$ | async)" class="state orgdefaultlabel">{{
'SETTING.LANGUAGES.DEFAULT' | translate
}}</span>
<button
(click)="$event.stopPropagation()"
*ngIf="lang !== (defaultLang$ | async) && (isRemotelyAllowed$(lang) | async) === true"
mat-icon-button
class="more-button"
[matMenuTriggerFor]="actions"
data-e2e="table-actions-button"
@for (lang of (localState$ | async)!.allowed; track lang; let i = $index) {
<div
class="card languages-box"
[cdkDragData]="lang"
cdkDrag
[cdkDragDisabled]="(canWriteRestrictions$ | async) === false"
mat-list-item
>
<mat-icon>more_vert</mat-icon>
</button>
<mat-menu #actions="matMenu" xPosition="before" class="language-actions-menu">
<button
menuActions
mat-menu-item
(click)="setDefaultLang(lang)"
[disabled]="(canWriteDefaultLanguage$ | async) === false"
>
{{ 'SETTING.LANGUAGES.SETASDEFAULT' | translate }}
</button>
</mat-menu>
</div>
<span class="index">{{ i + 1 }}</span>
<span class="locale">{{ lang }}</span>
<span class="lang">{{ 'SETTING.LANGUAGES.OPTIONS.' + lang | translate }} </span>
@if (lang === (defaultLang$ | async)) {
<span class="state orgdefaultlabel">{{ 'SETTING.LANGUAGES.DEFAULT' | translate }}</span>
}
@if (lang !== (defaultLang$ | async) && (isRemotelyAllowed$(lang) | async) === true) {
<button
(click)="$event.stopPropagation()"
mat-icon-button
class="more-button"
[matMenuTriggerFor]="actions"
data-e2e="table-actions-button"
>
<mat-icon>more_vert</mat-icon>
</button>
}
<mat-menu #actions="matMenu" xPosition="before" class="language-actions-menu">
<button
menuActions
mat-menu-item
(click)="setDefaultLang(lang)"
[disabled]="(canWriteDefaultLanguage$ | async) === false"
>
{{ 'SETTING.LANGUAGES.SETASDEFAULT' | translate }}
</button>
</mat-menu>
</div>
}
</div>
</div>
</div>
@@ -95,17 +97,18 @@
</button>
</div>
<div class="languages-drop-target">
<div
class="card languages-box"
*ngFor="let lang of (localState$ | async)!.notAllowed"
[cdkDragData]="lang"
cdkDrag
[cdkDragDisabled]="(canWriteRestrictions$ | async) === false"
mat-list-item
>
<span class="locale">{{ lang }}</span>
<span class="lang">{{ 'SETTING.LANGUAGES.OPTIONS.' + lang | translate }} </span>
</div>
@for (lang of (localState$ | async)!.notAllowed; track lang) {
<div
class="card languages-box"
[cdkDragData]="lang"
cdkDrag
[cdkDragDisabled]="(canWriteRestrictions$ | async) === false"
mat-list-item
>
<span class="locale">{{ lang }}</span>
<span class="lang">{{ 'SETTING.LANGUAGES.OPTIONS.' + lang | translate }} </span>
</div>
}
</div>
</div>
</div>
@@ -7,15 +7,17 @@
<cnsl-form-field class="form-field" label="Access Code" required="true">
<cnsl-label>{{ 'MFA.TYPE' | translate }}</cnsl-label>
<mat-select [(ngModel)]="newMfaType">
<mat-option *ngFor="let mfa of availableMfaTypes" [value]="mfa">
{{
(data.componentType === LoginMethodComponentType.SecondFactor
? 'MFA.SECONDFACTORTYPES.'
: LoginMethodComponentType.MultiFactor
? 'MFA.MULTIFACTORTYPES.'
: '') + mfa | translate
}}
</mat-option>
@for (mfa of availableMfaTypes; track mfa) {
<mat-option [value]="mfa">
{{
(data.componentType === LoginMethodComponentType.SecondFactor
? 'MFA.SECONDFACTORTYPES.'
: LoginMethodComponentType.MultiFactor
? 'MFA.MULTIFACTORTYPES.'
: '') + mfa | translate
}}
</mat-option>
}
</mat-select>
</cnsl-form-field>
</div>
@@ -1,23 +1,28 @@
<div class="sp_wrapper">
<mat-spinner diameter="30" *ngIf="loading$ | async"></mat-spinner>
@if (loading$ | async) {
<mat-spinner diameter="30"></mat-spinner>
}
</div>
<div class="login-policy-mfa-list">
<div class="mfa" *ngFor="let mfa of list">
<span>
{{
(componentType === LoginMethodComponentType.SecondFactor
? 'MFA.SECONDFACTORTYPES.'
: LoginMethodComponentType.MultiFactor
? 'MFA.MULTIFACTORTYPES.'
: '') + mfa | translate
}}
</span>
<button color="warn" *ngIf="!disabled" mat-icon-button (click)="removeMfa(mfa)" class="rm">
<i matTooltip="{{ 'ACTIONS.REMOVE' | translate }}" class="las la-times-circle"></i>
</button>
</div>
@for (mfa of list; track mfa) {
<div class="mfa">
<span>
{{
(componentType === LoginMethodComponentType.SecondFactor
? 'MFA.SECONDFACTORTYPES.'
: LoginMethodComponentType.MultiFactor
? 'MFA.MULTIFACTORTYPES.'
: '') + mfa | translate
}}
</span>
@if (!disabled) {
<button color="warn" mat-icon-button (click)="removeMfa(mfa)" class="rm">
<i matTooltip="{{ 'ACTIONS.REMOVE' | translate }}" class="las la-times-circle"></i>
</button>
}
</div>
}
<div class="mfa-list-btns">
<button
mat-stroked-button
@@ -1,10 +1,12 @@
<div class="spinner-wr">
<mat-spinner diameter="30" *ngIf="loading" color="primary"></mat-spinner>
@if (loading) {
<mat-spinner diameter="30" color="primary"></mat-spinner>
}
</div>
<h2>{{ 'SETTINGS.LIST.LOGIN' | translate }}</h2>
<ng-container *ngIf="serviceType === PolicyComponentServiceType.MGMT && !isDefault">
@if (serviceType === PolicyComponentServiceType.MGMT && !isDefault) {
<ng-template cnslHasRole [hasRole]="['policy.delete']">
<button
color="primary"
@@ -17,18 +19,81 @@
{{ 'POLICY.RESET' | translate }}
</button>
</ng-template>
</ng-container>
}
<br />
<h3>{{ 'MFA.LIST.MULTIFACTORTITLE' | translate }}</h3>
<p class="cnsl-secondary-text">{{ 'MFA.LIST.MULTIFACTORDESCRIPTION' | translate }}</p>
<div class="login-policy-row" *ngIf="loginData">
<cnsl-form-field class="passwordless-allowed" label="Access Code" required="true">
<cnsl-label>{{ 'LOGINPOLICY.PASSWORDLESS' | translate }}</cnsl-label>
<mat-select
[(ngModel)]="loginData.passwordlessType"
@if (loginData) {
<div class="login-policy-row">
<cnsl-form-field class="passwordless-allowed" label="Access Code" required="true">
<cnsl-label>{{ 'LOGINPOLICY.PASSWORDLESS' | translate }}</cnsl-label>
<mat-select
[(ngModel)]="loginData.passwordlessType"
[disabled]="
([
serviceType === PolicyComponentServiceType.ADMIN
? 'iam.policy.write'
: serviceType === PolicyComponentServiceType.MGMT
? 'policy.write'
: '',
]
| hasRole
| async) === false
"
>
@for (pt of passwordlessTypes; track pt) {
<mat-option [value]="pt">
{{ 'LOGINPOLICY.PASSWORDLESSTYPE.' + pt | translate }}
</mat-option>
}
</mat-select>
</cnsl-form-field>
</div>
}
@if (loginData) {
<cnsl-card class="max-card-width">
<cnsl-factor-table
[service]="service"
[serviceType]="serviceType"
[componentType]="LoginMethodComponentType.MultiFactor"
[list]="loginData.multiFactorsList"
(typeRemoved)="removeFactor($event)"
(beforeTypeAdd)="beforeAddFactor($event)"
(typeAdded)="addFactor($event)"
[disabled]="
loginData.passwordlessType === PasswordlessType.PASSWORDLESS_TYPE_NOT_ALLOWED ||
([
serviceType === PolicyComponentServiceType.ADMIN
? 'iam.policy.write'
: serviceType === PolicyComponentServiceType.MGMT
? 'policy.write'
: '',
]
| hasRole
| async) === false
"
>
</cnsl-factor-table>
</cnsl-card>
}
<br />
<h3>{{ 'MFA.LIST.SECONDFACTORTITLE' | translate }}</h3>
<p class="cnsl-secondary-text">{{ 'MFA.LIST.SECONDFACTORDESCRIPTION' | translate }}</p>
@if (loginData) {
<div class="login-policy-row">
<mat-checkbox
card-actions
class="login-policy-toggle"
color="primary"
ngDefaultControl
[(ngModel)]="loginData.forceMfa"
[disabled]="
([
serviceType === PolicyComponentServiceType.ADMIN
@@ -41,110 +106,59 @@
| async) === false
"
>
<mat-option *ngFor="let pt of passwordlessTypes" [value]="pt">
{{ 'LOGINPOLICY.PASSWORDLESSTYPE.' + pt | translate }}
</mat-option>
</mat-select>
</cnsl-form-field>
</div>
<cnsl-card class="max-card-width" *ngIf="loginData">
<cnsl-factor-table
[service]="service"
[serviceType]="serviceType"
[componentType]="LoginMethodComponentType.MultiFactor"
[list]="loginData.multiFactorsList"
(typeRemoved)="removeFactor($event)"
(beforeTypeAdd)="beforeAddFactor($event)"
(typeAdded)="addFactor($event)"
[disabled]="
loginData.passwordlessType === PasswordlessType.PASSWORDLESS_TYPE_NOT_ALLOWED ||
([
serviceType === PolicyComponentServiceType.ADMIN
? 'iam.policy.write'
: serviceType === PolicyComponentServiceType.MGMT
? 'policy.write'
: '',
]
| hasRole
| async) === false
"
>
</cnsl-factor-table>
</cnsl-card>
<br />
<h3>{{ 'MFA.LIST.SECONDFACTORTITLE' | translate }}</h3>
<p class="cnsl-secondary-text">{{ 'MFA.LIST.SECONDFACTORDESCRIPTION' | translate }}</p>
<div *ngIf="loginData" class="login-policy-row">
<mat-checkbox
card-actions
class="login-policy-toggle"
color="primary"
ngDefaultControl
[(ngModel)]="loginData.forceMfa"
[disabled]="
([
serviceType === PolicyComponentServiceType.ADMIN
? 'iam.policy.write'
: serviceType === PolicyComponentServiceType.MGMT
? 'policy.write'
: '',
]
| hasRole
| async) === false
"
>
{{ 'POLICY.DATA.FORCEMFA' | translate }}
</mat-checkbox>
</div>
<div *ngIf="loginData" class="login-policy-row">
<mat-checkbox
card-actions
class="login-policy-toggle"
color="primary"
ngDefaultControl
[(ngModel)]="loginData.forceMfaLocalOnly"
[disabled]="
([
serviceType === PolicyComponentServiceType.ADMIN
? 'iam.policy.write'
: serviceType === PolicyComponentServiceType.MGMT
? 'policy.write'
: '',
]
| hasRole
| async) === false
"
>
{{ 'POLICY.DATA.FORCEMFALOCALONLY' | translate }}
</mat-checkbox>
</div>
<cnsl-card class="max-card-width" *ngIf="loginData">
<cnsl-factor-table
[service]="service"
[serviceType]="serviceType"
[componentType]="LoginMethodComponentType.SecondFactor"
[list]="loginData.secondFactorsList"
(typeRemoved)="removeFactor($event)"
(beforeTypeAdd)="beforeAddFactor($event)"
(typeAdded)="addFactor($event)"
[disabled]="
([
serviceType === PolicyComponentServiceType.ADMIN
? 'iam.policy.write'
: serviceType === PolicyComponentServiceType.MGMT
? 'policy.write'
: '',
]
| hasRole
| async) === false
"
>
</cnsl-factor-table>
</cnsl-card>
{{ 'POLICY.DATA.FORCEMFA' | translate }}
</mat-checkbox>
</div>
}
@if (loginData) {
<div class="login-policy-row">
<mat-checkbox
card-actions
class="login-policy-toggle"
color="primary"
ngDefaultControl
[(ngModel)]="loginData.forceMfaLocalOnly"
[disabled]="
([
serviceType === PolicyComponentServiceType.ADMIN
? 'iam.policy.write'
: serviceType === PolicyComponentServiceType.MGMT
? 'policy.write'
: '',
]
| hasRole
| async) === false
"
>
{{ 'POLICY.DATA.FORCEMFALOCALONLY' | translate }}
</mat-checkbox>
</div>
}
@if (loginData) {
<cnsl-card class="max-card-width">
<cnsl-factor-table
[service]="service"
[serviceType]="serviceType"
[componentType]="LoginMethodComponentType.SecondFactor"
[list]="loginData.secondFactorsList"
(typeRemoved)="removeFactor($event)"
(beforeTypeAdd)="beforeAddFactor($event)"
(typeAdded)="addFactor($event)"
[disabled]="
([
serviceType === PolicyComponentServiceType.ADMIN
? 'iam.policy.write'
: serviceType === PolicyComponentServiceType.MGMT
? 'policy.write'
: '',
]
| hasRole
| async) === false
"
>
</cnsl-factor-table>
</cnsl-card>
}
<br />
@@ -224,225 +238,15 @@
<h3>{{ 'DESCRIPTIONS.SETTINGS.LOGIN.FORM.TITLE' | translate }}</h3>
<p class="cnsl-secondary-text">{{ 'DESCRIPTIONS.SETTINGS.LOGIN.FORM.DESCRIPTION' | translate }}</p>
<div class="max-card-width login-policy-content" *ngIf="loginData">
<div class="login-policy-row">
<mat-checkbox
class="login-policy-toggle"
color="primary"
matTooltip="{{ 'DESCRIPTIONS.SETTINGS.LOGIN.FORM.LOCAL_AUTHENTICATION_ALLOWED.DESCRIPTION' | translate }}"
ngDefaultControl
[(ngModel)]="loginData.allowUsernamePassword"
[disabled]="
([
serviceType === PolicyComponentServiceType.ADMIN
? 'iam.policy.write'
: serviceType === PolicyComponentServiceType.MGMT
? 'policy.write'
: '',
]
| hasRole
| async) === false
"
>
{{ 'DESCRIPTIONS.SETTINGS.LOGIN.FORM.LOCAL_AUTHENTICATION_ALLOWED.TITLE' | translate }}
</mat-checkbox>
<!-- <cnsl-info-section class="info">
{{ 'POLICY.DATA.ALLOWUSERNAMEPASSWORD_DESC' | translate }}
</cnsl-info-section> -->
</div>
<div class="login-policy-row">
<mat-checkbox
class="login-policy-toggle"
color="primary"
ngDefaultControl
matTooltip="{{ 'DESCRIPTIONS.SETTINGS.LOGIN.FORM.USER_REGISTRATION_ALLOWED.DESCRIPTION' | translate }}"
[(ngModel)]="loginData.allowRegister"
[disabled]="
([
serviceType === PolicyComponentServiceType.ADMIN
? 'iam.policy.write'
: serviceType === PolicyComponentServiceType.MGMT
? 'policy.write'
: '',
]
| hasRole
| async) === false
"
>
{{ 'DESCRIPTIONS.SETTINGS.LOGIN.FORM.USER_REGISTRATION_ALLOWED.TITLE' | translate }}
</mat-checkbox>
</div>
<div class="login-policy-row">
<mat-checkbox
class="login-policy-toggle"
color="primary"
ngDefaultControl
matTooltip="{{ 'DESCRIPTIONS.SETTINGS.LOGIN.FORM.ORG_REGISTRATION_ALLOWED.DESCRIPTION' | translate }}"
[(ngModel)]="allowOrgRegistration"
*ngIf="serviceType === PolicyComponentServiceType.ADMIN"
[disabled]="(['iam.restrictions.write'] | hasRole | async) === false"
>
{{ 'DESCRIPTIONS.SETTINGS.LOGIN.FORM.ORG_REGISTRATION_ALLOWED.TITLE' | translate }}
</mat-checkbox>
</div>
<div class="login-policy-row">
<mat-checkbox
class="login-policy-toggle"
color="primary"
ngDefaultControl
matTooltip="{{ 'DESCRIPTIONS.SETTINGS.LOGIN.FORM.EXTERNAL_LOGIN_ALLOWED.DESCRIPTION' | translate }}"
[(ngModel)]="loginData.allowExternalIdp"
[disabled]="
([
serviceType === PolicyComponentServiceType.ADMIN
? 'iam.policy.write'
: serviceType === PolicyComponentServiceType.MGMT
? 'policy.write'
: '',
]
| hasRole
| async) === false
"
>
{{ 'DESCRIPTIONS.SETTINGS.LOGIN.FORM.EXTERNAL_LOGIN_ALLOWED.TITLE' | translate }}
</mat-checkbox>
<!-- <ng-template #idpInfo>
<cnsl-info-section class="info">
{{ 'POLICY.DATA.ALLOWEXTERNALIDP_DESC' | translate }}
</cnsl-info-section>
</ng-template> -->
</div>
<div class="login-policy-row">
<mat-checkbox
class="login-policy-toggle"
color="primary"
ngDefaultControl
matTooltip="{{ 'DESCRIPTIONS.SETTINGS.LOGIN.FORM.HIDE_PASSWORD_RESET.DESCRIPTION' | translate }}"
[(ngModel)]="loginData.hidePasswordReset"
[disabled]="
([
serviceType === PolicyComponentServiceType.ADMIN
? 'iam.policy.write'
: serviceType === PolicyComponentServiceType.MGMT
? 'policy.write'
: '',
]
| hasRole
| async) === false
"
>
{{ 'DESCRIPTIONS.SETTINGS.LOGIN.FORM.HIDE_PASSWORD_RESET.TITLE' | translate }}
</mat-checkbox>
<!-- <ng-template #passwordResetInfo>
<cnsl-info-section class="info">
{{ 'POLICY.DATA.HIDEPASSWORDRESET_DESC' | translate }}
</cnsl-info-section>
</ng-template> -->
</div>
<div class="login-policy-row">
<mat-checkbox
class="login-policy-toggle"
color="primary"
ngDefaultControl
matTooltip="{{ 'DESCRIPTIONS.SETTINGS.LOGIN.FORM.DOMAIN_DISCOVERY_ALLOWED.DESCRIPTION' | translate }}"
[(ngModel)]="loginData.allowDomainDiscovery"
[disabled]="
([
serviceType === PolicyComponentServiceType.ADMIN
? 'iam.policy.write'
: serviceType === PolicyComponentServiceType.MGMT
? 'policy.write'
: '',
]
| hasRole
| async) === false
"
>
{{ 'DESCRIPTIONS.SETTINGS.LOGIN.FORM.DOMAIN_DISCOVERY_ALLOWED.TITLE' | translate }}
</mat-checkbox>
</div>
<div class="login-policy-row">
<mat-checkbox
class="login-policy-toggle"
color="primary"
ngDefaultControl
matTooltip="{{ 'DESCRIPTIONS.SETTINGS.LOGIN.FORM.IGNORE_UNKNOWN_USERNAMES.DESCRIPTION' | translate }}"
[(ngModel)]="loginData.ignoreUnknownUsernames"
[disabled]="
([
serviceType === PolicyComponentServiceType.ADMIN
? 'iam.policy.write'
: serviceType === PolicyComponentServiceType.MGMT
? 'policy.write'
: '',
]
| hasRole
| async) === false
"
>
{{ 'DESCRIPTIONS.SETTINGS.LOGIN.FORM.IGNORE_UNKNOWN_USERNAMES.TITLE' | translate }}
</mat-checkbox>
</div>
<div class="login-policy-row">
<mat-checkbox
class="login-policy-toggle"
color="primary"
ngDefaultControl
matTooltip="{{ 'DESCRIPTIONS.SETTINGS.LOGIN.FORM.DISABLE_EMAIL_LOGIN.DESCRIPTION' | translate }}"
[(ngModel)]="loginData.disableLoginWithEmail"
[disabled]="
([
serviceType === PolicyComponentServiceType.ADMIN
? 'iam.policy.write'
: serviceType === PolicyComponentServiceType.MGMT
? 'policy.write'
: '',
]
| hasRole
| async) === false
"
>
{{ 'DESCRIPTIONS.SETTINGS.LOGIN.FORM.DISABLE_EMAIL_LOGIN.TITLE' | translate }}
</mat-checkbox>
</div>
<div class="login-policy-row">
<mat-checkbox
class="login-policy-toggle"
color="primary"
ngDefaultControl
matTooltip="{{ 'DESCRIPTIONS.SETTINGS.LOGIN.FORM.DISABLE_PHONE_LOGIN.DESCRIPTION' | translate }}"
[(ngModel)]="loginData.disableLoginWithPhone"
[disabled]="
([
serviceType === PolicyComponentServiceType.ADMIN
? 'iam.policy.write'
: serviceType === PolicyComponentServiceType.MGMT
? 'policy.write'
: '',
]
| hasRole
| async) === false
"
>
{{ 'DESCRIPTIONS.SETTINGS.LOGIN.FORM.DISABLE_PHONE_LOGIN.TITLE' | translate }}
</mat-checkbox>
</div>
<div class="login-policy-row">
<cnsl-form-field class="form-field" label="Access Code" required="true">
<cnsl-label>{{ 'POLICY.DATA.DEFAULTREDIRECTURI' | translate }}</cnsl-label>
<input
cnslInput
placeholder="https://"
[(ngModel)]="loginData.defaultRedirectUri"
@if (loginData) {
<div class="max-card-width login-policy-content">
<div class="login-policy-row">
<mat-checkbox
class="login-policy-toggle"
color="primary"
matTooltip="{{ 'DESCRIPTIONS.SETTINGS.LOGIN.FORM.LOCAL_AUTHENTICATION_ALLOWED.DESCRIPTION' | translate }}"
ngDefaultControl
[(ngModel)]="loginData.allowUsernamePassword"
[disabled]="
([
serviceType === PolicyComponentServiceType.ADMIN
@@ -454,10 +258,214 @@
| hasRole
| async) === false
"
/>
</cnsl-form-field>
>
{{ 'DESCRIPTIONS.SETTINGS.LOGIN.FORM.LOCAL_AUTHENTICATION_ALLOWED.TITLE' | translate }}
</mat-checkbox>
<!-- <cnsl-info-section class="info">
{{ 'POLICY.DATA.ALLOWUSERNAMEPASSWORD_DESC' | translate }}
</cnsl-info-section> -->
</div>
<div class="login-policy-row">
<mat-checkbox
class="login-policy-toggle"
color="primary"
ngDefaultControl
matTooltip="{{ 'DESCRIPTIONS.SETTINGS.LOGIN.FORM.USER_REGISTRATION_ALLOWED.DESCRIPTION' | translate }}"
[(ngModel)]="loginData.allowRegister"
[disabled]="
([
serviceType === PolicyComponentServiceType.ADMIN
? 'iam.policy.write'
: serviceType === PolicyComponentServiceType.MGMT
? 'policy.write'
: '',
]
| hasRole
| async) === false
"
>
{{ 'DESCRIPTIONS.SETTINGS.LOGIN.FORM.USER_REGISTRATION_ALLOWED.TITLE' | translate }}
</mat-checkbox>
</div>
<div class="login-policy-row">
@if (serviceType === PolicyComponentServiceType.ADMIN) {
<mat-checkbox
class="login-policy-toggle"
color="primary"
ngDefaultControl
matTooltip="{{ 'DESCRIPTIONS.SETTINGS.LOGIN.FORM.ORG_REGISTRATION_ALLOWED.DESCRIPTION' | translate }}"
[(ngModel)]="allowOrgRegistration"
[disabled]="(['iam.restrictions.write'] | hasRole | async) === false"
>
{{ 'DESCRIPTIONS.SETTINGS.LOGIN.FORM.ORG_REGISTRATION_ALLOWED.TITLE' | translate }}
</mat-checkbox>
}
</div>
<div class="login-policy-row">
<mat-checkbox
class="login-policy-toggle"
color="primary"
ngDefaultControl
matTooltip="{{ 'DESCRIPTIONS.SETTINGS.LOGIN.FORM.EXTERNAL_LOGIN_ALLOWED.DESCRIPTION' | translate }}"
[(ngModel)]="loginData.allowExternalIdp"
[disabled]="
([
serviceType === PolicyComponentServiceType.ADMIN
? 'iam.policy.write'
: serviceType === PolicyComponentServiceType.MGMT
? 'policy.write'
: '',
]
| hasRole
| async) === false
"
>
{{ 'DESCRIPTIONS.SETTINGS.LOGIN.FORM.EXTERNAL_LOGIN_ALLOWED.TITLE' | translate }}
</mat-checkbox>
<!-- <ng-template #idpInfo>
<cnsl-info-section class="info">
{{ 'POLICY.DATA.ALLOWEXTERNALIDP_DESC' | translate }}
</cnsl-info-section>
</ng-template> -->
</div>
<div class="login-policy-row">
<mat-checkbox
class="login-policy-toggle"
color="primary"
ngDefaultControl
matTooltip="{{ 'DESCRIPTIONS.SETTINGS.LOGIN.FORM.HIDE_PASSWORD_RESET.DESCRIPTION' | translate }}"
[(ngModel)]="loginData.hidePasswordReset"
[disabled]="
([
serviceType === PolicyComponentServiceType.ADMIN
? 'iam.policy.write'
: serviceType === PolicyComponentServiceType.MGMT
? 'policy.write'
: '',
]
| hasRole
| async) === false
"
>
{{ 'DESCRIPTIONS.SETTINGS.LOGIN.FORM.HIDE_PASSWORD_RESET.TITLE' | translate }}
</mat-checkbox>
<!-- <ng-template #passwordResetInfo>
<cnsl-info-section class="info">
{{ 'POLICY.DATA.HIDEPASSWORDRESET_DESC' | translate }}
</cnsl-info-section>
</ng-template> -->
</div>
<div class="login-policy-row">
<mat-checkbox
class="login-policy-toggle"
color="primary"
ngDefaultControl
matTooltip="{{ 'DESCRIPTIONS.SETTINGS.LOGIN.FORM.DOMAIN_DISCOVERY_ALLOWED.DESCRIPTION' | translate }}"
[(ngModel)]="loginData.allowDomainDiscovery"
[disabled]="
([
serviceType === PolicyComponentServiceType.ADMIN
? 'iam.policy.write'
: serviceType === PolicyComponentServiceType.MGMT
? 'policy.write'
: '',
]
| hasRole
| async) === false
"
>
{{ 'DESCRIPTIONS.SETTINGS.LOGIN.FORM.DOMAIN_DISCOVERY_ALLOWED.TITLE' | translate }}
</mat-checkbox>
</div>
<div class="login-policy-row">
<mat-checkbox
class="login-policy-toggle"
color="primary"
ngDefaultControl
matTooltip="{{ 'DESCRIPTIONS.SETTINGS.LOGIN.FORM.IGNORE_UNKNOWN_USERNAMES.DESCRIPTION' | translate }}"
[(ngModel)]="loginData.ignoreUnknownUsernames"
[disabled]="
([
serviceType === PolicyComponentServiceType.ADMIN
? 'iam.policy.write'
: serviceType === PolicyComponentServiceType.MGMT
? 'policy.write'
: '',
]
| hasRole
| async) === false
"
>
{{ 'DESCRIPTIONS.SETTINGS.LOGIN.FORM.IGNORE_UNKNOWN_USERNAMES.TITLE' | translate }}
</mat-checkbox>
</div>
<div class="login-policy-row">
<mat-checkbox
class="login-policy-toggle"
color="primary"
ngDefaultControl
matTooltip="{{ 'DESCRIPTIONS.SETTINGS.LOGIN.FORM.DISABLE_EMAIL_LOGIN.DESCRIPTION' | translate }}"
[(ngModel)]="loginData.disableLoginWithEmail"
[disabled]="
([
serviceType === PolicyComponentServiceType.ADMIN
? 'iam.policy.write'
: serviceType === PolicyComponentServiceType.MGMT
? 'policy.write'
: '',
]
| hasRole
| async) === false
"
>
{{ 'DESCRIPTIONS.SETTINGS.LOGIN.FORM.DISABLE_EMAIL_LOGIN.TITLE' | translate }}
</mat-checkbox>
</div>
<div class="login-policy-row">
<mat-checkbox
class="login-policy-toggle"
color="primary"
ngDefaultControl
matTooltip="{{ 'DESCRIPTIONS.SETTINGS.LOGIN.FORM.DISABLE_PHONE_LOGIN.DESCRIPTION' | translate }}"
[(ngModel)]="loginData.disableLoginWithPhone"
[disabled]="
([
serviceType === PolicyComponentServiceType.ADMIN
? 'iam.policy.write'
: serviceType === PolicyComponentServiceType.MGMT
? 'policy.write'
: '',
]
| hasRole
| async) === false
"
>
{{ 'DESCRIPTIONS.SETTINGS.LOGIN.FORM.DISABLE_PHONE_LOGIN.TITLE' | translate }}
</mat-checkbox>
</div>
<div class="login-policy-row">
<cnsl-form-field class="form-field" label="Access Code" required="true">
<cnsl-label>{{ 'POLICY.DATA.DEFAULTREDIRECTURI' | translate }}</cnsl-label>
<input
cnslInput
placeholder="https://"
[(ngModel)]="loginData.defaultRedirectUri"
[disabled]="
([
serviceType === PolicyComponentServiceType.ADMIN
? 'iam.policy.write'
: serviceType === PolicyComponentServiceType.MGMT
? 'policy.write'
: '',
]
| hasRole
| async) === false
"
/>
</cnsl-form-field>
</div>
</div>
</div>
}
<br />
@@ -1,24 +1,34 @@
<h2>{{ 'POLICY.LOGIN_TEXTS.TITLE' | translate }}</h2>
<p class="cnsl-secondary-text">{{ 'POLICY.LOGIN_TEXTS.DESCRIPTION' | translate }}</p>
<cnsl-info-section class="locked" *ngIf="langSvc.isNotAllowed(language) | async" [type]="InfoSectionType.WARN">
{{ 'POLICY.LOGIN_TEXTS.ACTIVE_LANGUAGE_NOT_ALLOWED' | translate }}</cnsl-info-section
>
@if (langSvc.isNotAllowed(language) | async) {
<cnsl-info-section class="locked" [type]="InfoSectionType.WARN">
{{ 'POLICY.LOGIN_TEXTS.ACTIVE_LANGUAGE_NOT_ALLOWED' | translate }}</cnsl-info-section
>
}
<div *ngIf="loading" class="spinner-wr">
<mat-spinner diameter="30" color="primary"></mat-spinner>
</div>
@if (loading) {
<div class="spinner-wr">
<mat-spinner diameter="30" color="primary"></mat-spinner>
</div>
}
<div class="date">
<div>
<p class="newer-title" *ngIf="newerVersionExists">{{ 'POLICY.LOGIN_TEXTS.NEWERVERSIONEXISTS' | translate }}</p>
<p *ngIf="newerPolicyChangeDate && newerVersionExists">
{{ 'POLICY.LOGIN_TEXTS.CHANGEDATE' | translate }}:
{{ newerPolicyChangeDate | timestampToDate | localizedDate: 'dd. MMMM yyyy, HH:mm:ss' }}
</p>
<p class="cnsl-secondary-text" *ngIf="currentPolicyChangeDate">
{{ 'POLICY.LOGIN_TEXTS.CURRENTDATE' | translate }}:
{{ currentPolicyChangeDate | timestampToDate | localizedDate: 'dd. MMMM yyyy, HH:mm:ss' }}
</p>
@if (newerVersionExists) {
<p class="newer-title">{{ 'POLICY.LOGIN_TEXTS.NEWERVERSIONEXISTS' | translate }}</p>
}
@if (newerPolicyChangeDate && newerVersionExists) {
<p>
{{ 'POLICY.LOGIN_TEXTS.CHANGEDATE' | translate }}:
{{ newerPolicyChangeDate | timestampToDate | localizedDate: 'dd. MMMM yyyy, HH:mm:ss' }}
</p>
}
@if (currentPolicyChangeDate) {
<p class="cnsl-secondary-text">
{{ 'POLICY.LOGIN_TEXTS.CURRENTDATE' | translate }}:
{{ currentPolicyChangeDate | timestampToDate | localizedDate: 'dd. MMMM yyyy, HH:mm:ss' }}
</p>
}
</div>
<button [disabled]="!newerVersionExists" color="primary" mat-raised-button (click)="loadData()">
<div class="cnsl-action-button">
@@ -27,44 +37,53 @@
</div>
</button>
</div>
<form *ngIf="allowed$ | async" class="top-actions" [formGroup]="form">
<cnsl-form-field class="keys">
<cnsl-label>{{ 'POLICY.LOGIN_TEXTS.KEYNAME' | translate }}</cnsl-label>
<mat-select formControlName="currentSubMap" name="currentSubMap">
<mat-option *ngFor="let key of KeyNamesArray" [value]="key">
{{ 'POLICY.LOGIN_TEXTS.KEYS.' + key | translate }}
</mat-option>
</mat-select>
</cnsl-form-field>
<cnsl-form-field class="language">
<cnsl-label>{{ 'POLICY.LOGIN_TEXTS.LANGUAGE' | translate }}</cnsl-label>
<mat-select formControlName="language" name="language">
<mat-option *ngFor="let lang of allowed$ | async" [value]="lang">
<div class="centerline">
<span
>{{ lang }}
<span class="lighter cnsl-secondary-text"
>|&nbsp;{{ 'POLICY.LOGIN_TEXTS.LANGUAGES.' + lang | translate }}</span
></span
>
</div>
</mat-option>
<mat-optgroup [label]="'POLICY.LOGIN_TEXTS.LANGUAGES_NOT_ALLOWED' | translate" *ngIf="langSvc.restricted$ | async">
<mat-option *ngFor="let lang of langSvc.notAllowed$ | async" [value]="lang">
<div class="centerline">
<span
>{{ lang }}
<span class="lighter cnsl-secondary-text"
>|&nbsp;{{ 'POLICY.LOGIN_TEXTS.LANGUAGES.' + lang | translate }}</span
></span
>
</div>
</mat-option>
</mat-optgroup>
</mat-select>
</cnsl-form-field>
</form>
@if (allowed$ | async) {
<form class="top-actions" [formGroup]="form">
<cnsl-form-field class="keys">
<cnsl-label>{{ 'POLICY.LOGIN_TEXTS.KEYNAME' | translate }}</cnsl-label>
<mat-select formControlName="currentSubMap" name="currentSubMap">
@for (key of KeyNamesArray; track key) {
<mat-option [value]="key">
{{ 'POLICY.LOGIN_TEXTS.KEYS.' + key | translate }}
</mat-option>
}
</mat-select>
</cnsl-form-field>
<cnsl-form-field class="language">
<cnsl-label>{{ 'POLICY.LOGIN_TEXTS.LANGUAGE' | translate }}</cnsl-label>
<mat-select formControlName="language" name="language">
@for (lang of allowed$ | async; track lang) {
<mat-option [value]="lang">
<div class="centerline">
<span
>{{ lang }}
<span class="lighter cnsl-secondary-text"
>|&nbsp;{{ 'POLICY.LOGIN_TEXTS.LANGUAGES.' + lang | translate }}</span
></span
>
</div>
</mat-option>
}
@if (langSvc.restricted$ | async) {
<mat-optgroup [label]="'POLICY.LOGIN_TEXTS.LANGUAGES_NOT_ALLOWED' | translate">
@for (lang of langSvc.notAllowed$ | async; track lang) {
<mat-option [value]="lang">
<div class="centerline">
<span
>{{ lang }}
<span class="lighter cnsl-secondary-text"
>|&nbsp;{{ 'POLICY.LOGIN_TEXTS.LANGUAGES.' + lang | translate }}</span
></span
>
</div>
</mat-option>
}
</mat-optgroup>
}
</mat-select>
</cnsl-form-field>
</form>
}
<div class="divider"></div>
@@ -1,88 +1,102 @@
<h2>{{ 'DESCRIPTIONS.SETTINGS.MESSAGE_TEXTS.TITLE' | translate }}</h2>
<p class="cnsl-secondary-text">{{ 'DESCRIPTIONS.SETTINGS.MESSAGE_TEXTS.DESCRIPTION' | translate }}</p>
<cnsl-info-section class="locked" *ngIf="langSvc.isNotAllowed(language) | async" [type]="InfoSectionType.WARN">
{{ 'POLICY.LOGIN_TEXTS.ACTIVE_LANGUAGE_NOT_ALLOWED' | translate }}</cnsl-info-section
>
@if (langSvc.isNotAllowed(language) | async) {
<cnsl-info-section class="locked" [type]="InfoSectionType.WARN">
{{ 'POLICY.LOGIN_TEXTS.ACTIVE_LANGUAGE_NOT_ALLOWED' | translate }}</cnsl-info-section
>
}
<div *ngIf="loading" class="spinner-wr">
<mat-spinner diameter="30" color="primary"></mat-spinner>
</div>
@if (loading) {
<div class="spinner-wr">
<mat-spinner diameter="30" color="primary"></mat-spinner>
</div>
}
<div *ngIf="allowed$ | async">
<div class="message-texts-top-actions">
<cnsl-form-field class="type">
<cnsl-label>{{ 'POLICY.MESSAGE_TEXTS.TYPE' | translate }}</cnsl-label>
<mat-select [(ngModel)]="currentType" name="currentSubMap" (selectionChange)="changedCurrentType()">
<mat-option *ngFor="let type of MESSAGETYPES | keyvalue" [value]="type.value">
{{ 'POLICY.MESSAGE_TEXTS.TYPES.' + type.value | translate }}
</mat-option>
</mat-select>
</cnsl-form-field>
<cnsl-form-field class="language">
<cnsl-label>{{ 'POLICY.LOGIN_TEXTS.LANGUAGE' | translate }}</cnsl-label>
<mat-select [(ngModel)]="language" (selectionChange)="changeLocale($event)" name="language">
<mat-option *ngFor="let lang of langSvc.allowed$ | async" [value]="lang">
<div class="centerline">
<span
>{{ lang }}
<span class="lighter cnsl-secondary-text"
>|&nbsp;{{ 'POLICY.LOGIN_TEXTS.LANGUAGES.' + lang | translate }}</span
></span
>
@if (allowed$ | async) {
<div>
<div class="message-texts-top-actions">
<cnsl-form-field class="type">
<cnsl-label>{{ 'POLICY.MESSAGE_TEXTS.TYPE' | translate }}</cnsl-label>
<mat-select [(ngModel)]="currentType" name="currentSubMap" (selectionChange)="changedCurrentType()">
@for (type of MESSAGETYPES | keyvalue; track type) {
<mat-option [value]="type.value">
{{ 'POLICY.MESSAGE_TEXTS.TYPES.' + type.value | translate }}
</mat-option>
}
</mat-select>
</cnsl-form-field>
<cnsl-form-field class="language">
<cnsl-label>{{ 'POLICY.LOGIN_TEXTS.LANGUAGE' | translate }}</cnsl-label>
<mat-select [(ngModel)]="language" (selectionChange)="changeLocale($event)" name="language">
@for (lang of langSvc.allowed$ | async; track lang) {
<mat-option [value]="lang">
<div class="centerline">
<span
>{{ lang }}
<span class="lighter cnsl-secondary-text"
>|&nbsp;{{ 'POLICY.LOGIN_TEXTS.LANGUAGES.' + lang | translate }}</span
></span
>
</div>
</mat-option>
}
@if (langSvc.restricted$ | async) {
<mat-optgroup [label]="'POLICY.LOGIN_TEXTS.LANGUAGES_NOT_ALLOWED' | translate">
@for (lang of langSvc.notAllowed$ | async; track lang) {
<mat-option [value]="lang">
<div class="centerline">
<span
>{{ lang }}
<span class="lighter cnsl-secondary-text"
>|&nbsp;{{ 'POLICY.LOGIN_TEXTS.LANGUAGES.' + lang | translate }}</span
></span
>
</div>
</mat-option>
}
</mat-optgroup>
}
</mat-select>
</cnsl-form-field>
</div>
<p class="cnsl-secondary-text">
{{ 'DESCRIPTIONS.SETTINGS.MESSAGE_TEXTS.TYPE_DESCRIPTIONS.' + currentType | translate }}
</p>
<div class="message-text-content">
<cnsl-edit-text
[chips]="chips[currentType]"
[disabled]="(canWrite$ | async) === false"
label="one"
[default$]="getDefaultMessageTextMap$"
[current$]="getCustomMessageTextMap$"
(changedValues)="updateCurrentValues($event)"
></cnsl-edit-text>
</div>
<div class="message-text-actions">
@if ((getCustomMessageTextMap$ | async) && (getCustomMessageTextMap$ | async)?.['isDefault'] === false) {
<button
class="reset-button"
[disabled]="(canWrite$ | async) === false"
(click)="resetDefault()"
color="message-text-warn"
type="submit"
mat-stroked-button
>
<div class="cnsl-action-button">
<i class="las la-history"></i><span>{{ 'ACTIONS.RESETDEFAULT' | translate }}</span>
</div>
</mat-option>
<mat-optgroup [label]="'POLICY.LOGIN_TEXTS.LANGUAGES_NOT_ALLOWED' | translate" *ngIf="langSvc.restricted$ | async">
<mat-option *ngFor="let lang of langSvc.notAllowed$ | async" [value]="lang">
<div class="centerline">
<span
>{{ lang }}
<span class="lighter cnsl-secondary-text"
>|&nbsp;{{ 'POLICY.LOGIN_TEXTS.LANGUAGES.' + lang | translate }}</span
></span
>
</div>
</mat-option>
</mat-optgroup>
</mat-select>
</cnsl-form-field>
</button>
}
<button
class="save-button"
[disabled]="!updateRequest || (canWrite$ | async) === false"
(click)="saveCurrentMessage()"
color="primary"
type="submit"
mat-raised-button
>
{{ 'ACTIONS.SAVE' | translate }}
</button>
</div>
</div>
<p class="cnsl-secondary-text">{{ 'DESCRIPTIONS.SETTINGS.MESSAGE_TEXTS.TYPE_DESCRIPTIONS.' + currentType | translate }}</p>
<div class="message-text-content">
<cnsl-edit-text
[chips]="chips[currentType]"
[disabled]="(canWrite$ | async) === false"
label="one"
[default$]="getDefaultMessageTextMap$"
[current$]="getCustomMessageTextMap$"
(changedValues)="updateCurrentValues($event)"
></cnsl-edit-text>
</div>
<div class="message-text-actions">
<button
class="reset-button"
*ngIf="(getCustomMessageTextMap$ | async) && (getCustomMessageTextMap$ | async)?.['isDefault'] === false"
[disabled]="(canWrite$ | async) === false"
(click)="resetDefault()"
color="message-text-warn"
type="submit"
mat-stroked-button
>
<div class="cnsl-action-button">
<i class="las la-history"></i><span>{{ 'ACTIONS.RESETDEFAULT' | translate }}</span>
</div>
</button>
<button
class="save-button"
[disabled]="!updateRequest || (canWrite$ | async) === false"
(click)="saveCurrentMessage()"
color="primary"
type="submit"
mat-raised-button
>
{{ 'ACTIONS.SAVE' | translate }}
</button>
</div>
</div>
}
@@ -1,40 +1,40 @@
<h2>{{ 'POLICY.NOTIFICATION.TITLE' | translate }}</h2>
<p class="cnsl-secondary-text">{{ 'POLICY.NOTIFICATION.DESCRIPTION' | translate }}</p>
<div *ngIf="loading" class="spinner-wr">
<mat-spinner diameter="30" color="primary"></mat-spinner>
</div>
@if (loading) {
<div class="spinner-wr">
<mat-spinner diameter="30" color="primary"></mat-spinner>
</div>
}
<ng-template cnslHasRole [hasRole]="['policy.delete']">
<button
*ngIf="serviceType === PolicyComponentServiceType.MGMT && !isDefault"
matTooltip="{{ 'POLICY.RESET' | translate }}"
color="warn"
(click)="removePolicy()"
mat-stroked-button
>
{{ 'POLICY.RESET' | translate }}
</button>
@if (serviceType === PolicyComponentServiceType.MGMT && !isDefault) {
<button matTooltip="{{ 'POLICY.RESET' | translate }}" color="warn" (click)="removePolicy()" mat-stroked-button>
{{ 'POLICY.RESET' | translate }}
</button>
}
</ng-template>
<div class="notification-policy-card">
<cnsl-card *ngIf="notificationData">
<div class="notification-policy-content">
<div class="row">
<mat-checkbox
class="slide-toggle"
color="primary"
name="hasUppercase"
ngDefaultControl
data-e2e="notification-policy-checkbox"
[(ngModel)]="notificationData.passwordChange"
[disabled]="(['policy.write'] | hasRole | async) === false"
>
{{ 'POLICY.NOTIFICATION.PASSWORDCHANGE' | translate }}
</mat-checkbox>
@if (notificationData) {
<cnsl-card>
<div class="notification-policy-content">
<div class="row">
<mat-checkbox
class="slide-toggle"
color="primary"
name="hasUppercase"
ngDefaultControl
data-e2e="notification-policy-checkbox"
[(ngModel)]="notificationData.passwordChange"
[disabled]="(['policy.write'] | hasRole | async) === false"
>
{{ 'POLICY.NOTIFICATION.PASSWORDCHANGE' | translate }}
</mat-checkbox>
</div>
</div>
</div>
</cnsl-card>
</cnsl-card>
}
</div>
<div class="btn-container">
@@ -2,34 +2,36 @@
<span>{{ provider === SMSProviderType.Twilio ? 'Twilio' : ('SETTING.SMS.ADDPROVIDER' | translate) }}</span>
</h1>
<div mat-dialog-content>
<form *ngIf="provider === SMSProviderType.Twilio" (ngSubmit)="closeDialogWithRequest()" [formGroup]="twilioForm">
<cnsl-form-field class="sms-form-field" label="sid">
<cnsl-label>{{ 'SETTING.SMS.TWILIO.SID' | translate }}</cnsl-label>
<input cnslInput name="sid" formControlName="sid" />
</cnsl-form-field>
<cnsl-form-field *ngIf="token" class="sms-form-field" label="Token">
<cnsl-label>{{ 'SETTING.SMS.TWILIO.TOKEN' | translate }}</cnsl-label>
<input cnslInput name="token" formControlName="token" />
</cnsl-form-field>
<cnsl-form-field class="sms-form-field" label="Sender Number">
<cnsl-label>{{ 'SETTING.SMS.TWILIO.SENDERNUMBER' | translate }}</cnsl-label>
<input cnslInput name="senderNumber" formControlName="senderNumber" />
</cnsl-form-field>
<cnsl-form-field class="sms-form-field" label="Verification Service Sid">
<cnsl-label>{{ 'SETTING.SMS.TWILIO.VERIFYSERVICESID' | translate }}</cnsl-label>
<input cnslInput name="verifyServiceSid" formControlName="verifyServiceSid" />
</cnsl-form-field>
<cnsl-info-section class="feature-info">{{
'SETTING.SMS.TWILIO.VERIFYSERVICESID_DESCRIPTION' | translate
}}</cnsl-info-section>
<button *ngIf="twilio" type="button" mat-stroked-button (click)="changeToken()" data-e2e="edit-sms-token-button">
{{ 'SETTING.SMS.TWILIO.CHANGETOKEN' | translate }}
</button>
</form>
@if (provider === SMSProviderType.Twilio) {
<form (ngSubmit)="closeDialogWithRequest()" [formGroup]="twilioForm">
<cnsl-form-field class="sms-form-field" label="sid">
<cnsl-label>{{ 'SETTING.SMS.TWILIO.SID' | translate }}</cnsl-label>
<input cnslInput name="sid" formControlName="sid" />
</cnsl-form-field>
@if (token) {
<cnsl-form-field class="sms-form-field" label="Token">
<cnsl-label>{{ 'SETTING.SMS.TWILIO.TOKEN' | translate }}</cnsl-label>
<input cnslInput name="token" formControlName="token" />
</cnsl-form-field>
}
<cnsl-form-field class="sms-form-field" label="Sender Number">
<cnsl-label>{{ 'SETTING.SMS.TWILIO.SENDERNUMBER' | translate }}</cnsl-label>
<input cnslInput name="senderNumber" formControlName="senderNumber" />
</cnsl-form-field>
<cnsl-form-field class="sms-form-field" label="Verification Service Sid">
<cnsl-label>{{ 'SETTING.SMS.TWILIO.VERIFYSERVICESID' | translate }}</cnsl-label>
<input cnslInput name="verifyServiceSid" formControlName="verifyServiceSid" />
</cnsl-form-field>
<cnsl-info-section class="feature-info">{{
'SETTING.SMS.TWILIO.VERIFYSERVICESID_DESCRIPTION' | translate
}}</cnsl-info-section>
@if (twilio) {
<button type="button" mat-stroked-button (click)="changeToken()" data-e2e="edit-sms-token-button">
{{ 'SETTING.SMS.TWILIO.CHANGETOKEN' | translate }}
</button>
}
</form>
}
</div>
<div mat-dialog-actions class="action">
<button mat-stroked-button (click)="closeDialog()">
@@ -2,57 +2,62 @@
<p class="cnsl-secondary-text">{{ 'DESCRIPTIONS.SETTINGS.SMS_PROVIDER.DESCRIPTION' | translate }}</p>
<div class="spinner-wr">
<mat-spinner diameter="30" *ngIf="smsProvidersLoading" color="primary"></mat-spinner>
@if (smsProvidersLoading) {
<mat-spinner diameter="30" color="primary"></mat-spinner>
}
</div>
<div class="sms-providers" *ngIf="!smsProvidersLoading">
<cnsl-card class="sms-card" [nomargin]="true">
<div class="sms-provider">
<h4 class="title">Twilio</h4>
<span
*ngIf="twilio"
class="state"
[ngClass]="{
active: twilio.state === SMSProviderConfigState.SMS_PROVIDER_CONFIG_ACTIVE,
inactive: twilio.state === SMSProviderConfigState.SMS_PROVIDER_CONFIG_INACTIVE,
}"
>{{ 'SETTING.SMS.SMSPROVIDERSTATE.' + twilio.state | translate }}</span
>
<span class="fill-space"></span>
<button
*ngIf="twilio && twilio.id"
[disabled]="(['iam.write'] | hasRole | async) === false"
mat-stroked-button
data-e2e="activate-sms-provider-button"
(click)="toggleSMSProviderState(twilio.id)"
>
<span *ngIf="twilio.state === SMSProviderConfigState.SMS_PROVIDER_CONFIG_ACTIVE">{{
'ACTIONS.DEACTIVATE' | translate
}}</span>
<span *ngIf="twilio.state === SMSProviderConfigState.SMS_PROVIDER_CONFIG_INACTIVE">{{
'ACTIONS.ACTIVATE' | translate
}}</span>
</button>
<button
*ngIf="twilio && twilio.id"
color="warn"
[disabled]="(['iam.write'] | hasRole | async) === false"
mat-icon-button
(click)="removeSMSProvider(twilio.id)"
data-e2e="remove-sms-provider-button"
>
<i class="las la-trash"></i>
</button>
<button
[disabled]="(['iam.write'] | hasRole | async) === false"
mat-icon-button
(click)="editSMSProvider()"
data-e2e="new-twilio-button"
>
<i class="las la-pen"></i>
</button>
</div>
</cnsl-card>
</div>
@if (!smsProvidersLoading) {
<div class="sms-providers">
<cnsl-card class="sms-card" [nomargin]="true">
<div class="sms-provider">
<h4 class="title">Twilio</h4>
@if (twilio) {
<span
class="state"
[ngClass]="{
active: twilio.state === SMSProviderConfigState.SMS_PROVIDER_CONFIG_ACTIVE,
inactive: twilio.state === SMSProviderConfigState.SMS_PROVIDER_CONFIG_INACTIVE,
}"
>{{ 'SETTING.SMS.SMSPROVIDERSTATE.' + twilio.state | translate }}</span
>
}
<span class="fill-space"></span>
@if (twilio && twilio.id) {
<button
[disabled]="(['iam.write'] | hasRole | async) === false"
mat-stroked-button
data-e2e="activate-sms-provider-button"
(click)="toggleSMSProviderState(twilio.id)"
>
@if (twilio.state === SMSProviderConfigState.SMS_PROVIDER_CONFIG_ACTIVE) {
<span>{{ 'ACTIONS.DEACTIVATE' | translate }}</span>
}
@if (twilio.state === SMSProviderConfigState.SMS_PROVIDER_CONFIG_INACTIVE) {
<span>{{ 'ACTIONS.ACTIVATE' | translate }}</span>
}
</button>
}
@if (twilio && twilio.id) {
<button
color="warn"
[disabled]="(['iam.write'] | hasRole | async) === false"
mat-icon-button
(click)="removeSMSProvider(twilio.id)"
data-e2e="remove-sms-provider-button"
>
<i class="las la-trash"></i>
</button>
}
<button
[disabled]="(['iam.write'] | hasRole | async) === false"
mat-icon-button
(click)="editSMSProvider()"
data-e2e="new-twilio-button"
>
<i class="las la-pen"></i>
</button>
</div>
</cnsl-card>
</div>
}
@@ -1,5 +1,7 @@
<div class="spinner-wr">
<mat-spinner diameter="30" *ngIf="loading" color="primary"></mat-spinner>
@if (loading) {
<mat-spinner diameter="30" color="primary"></mat-spinner>
}
</div>
<h2>{{ 'DESCRIPTIONS.SETTINGS.OIDC.TITLE' | translate }}</h2>
<p class="cnsl-secondary-text">{{ 'DESCRIPTIONS.SETTINGS.OIDC.DESCRIPTION' | translate }}</p>
@@ -4,37 +4,32 @@
>
<cnsl-refresh-table [hideRefresh]="true" [loading]="(dataSource$ | async) === null">
<div class="table-wrapper">
<table
*ngIf="dataSource$ | async as dataSource"
mat-table
class="table"
aria-label="Elements"
[dataSource]="dataSource"
>
<ng-container matColumnDef="timestamp">
<th mat-header-cell *matHeaderCellDef>
{{ 'DESCRIPTIONS.SETTINGS.WEB_KEYS.PREVIOUS_TABLE.DEACTIVATED_ON' | translate }}
</th>
<td mat-cell *cnslCellDef="let row; dataSource: dataSource">
{{ row.changeDate | timestampToDate | localizedDate: 'EEE dd. MMM, HH:mm' }}
</td>
</ng-container>
<ng-container matColumnDef="id">
<th mat-header-cell *matHeaderCellDef>{{ 'APP.PAGES.ID' | translate }}</th>
<td mat-cell *cnslCellDef="let row; dataSource: dataSource">
{{ row.id }}
</td>
</ng-container>
<ng-container matColumnDef="type">
<th mat-header-cell *matHeaderCellDef>{{ 'PROJECT.TYPE.TITLE' | translate }}</th>
<td mat-cell *cnslCellDef="let row; dataSource: dataSource">
{{ row.key.case | uppercase }}
</td>
</ng-container>
<tr mat-header-row *matHeaderRowDef="['timestamp', 'id', 'type']"></tr>
<tr mat-row *matRowDef="let row; columns: ['timestamp', 'id', 'type']"></tr>
</table>
@if (dataSource$ | async; as dataSource) {
<table mat-table class="table" aria-label="Elements" [dataSource]="dataSource">
<ng-container matColumnDef="timestamp">
<th mat-header-cell *matHeaderCellDef>
{{ 'DESCRIPTIONS.SETTINGS.WEB_KEYS.PREVIOUS_TABLE.DEACTIVATED_ON' | translate }}
</th>
<td mat-cell *cnslCellDef="let row; dataSource: dataSource">
{{ row.changeDate | timestampToDate | localizedDate: 'EEE dd. MMM, HH:mm' }}
</td>
</ng-container>
<ng-container matColumnDef="id">
<th mat-header-cell *matHeaderCellDef>{{ 'APP.PAGES.ID' | translate }}</th>
<td mat-cell *cnslCellDef="let row; dataSource: dataSource">
{{ row.id }}
</td>
</ng-container>
<ng-container matColumnDef="type">
<th mat-header-cell *matHeaderCellDef>{{ 'PROJECT.TYPE.TITLE' | translate }}</th>
<td mat-cell *cnslCellDef="let row; dataSource: dataSource">
{{ row.key.case | uppercase }}
</td>
</ng-container>
<tr mat-header-row *matHeaderRowDef="['timestamp', 'id', 'type']"></tr>
<tr mat-row *matRowDef="let row; columns: ['timestamp', 'id', 'type']"></tr>
</table>
}
</div>
</cnsl-refresh-table>
</cnsl-card>
@@ -3,55 +3,65 @@
<ng-content></ng-content>
</div>
<div class="table-wrapper">
<table *ngIf="dataSource$ | async as dataSource" mat-table class="table" aria-label="Elements" [dataSource]="dataSource">
<ng-container matColumnDef="state">
<th mat-header-cell *matHeaderCellDef>{{ 'APP.PAGES.STATE' | translate }}</th>
<td mat-cell *cnslCellDef="let row; let i = index; dataSource: dataSource">
<span
class="state"
[ngClass]="{
active: i === 0,
neutral: i === 1,
}"
[ngSwitch]="i"
>
<ng-container *ngSwitchCase="0">{{ 'DESCRIPTIONS.SETTINGS.WEB_KEYS.TABLE.ACTIVE' | translate }}</ng-container>
<ng-container *ngSwitchCase="1">{{ 'DESCRIPTIONS.SETTINGS.WEB_KEYS.TABLE.NEXT' | translate }}</ng-container>
<ng-container *ngSwitchDefault>{{ 'DESCRIPTIONS.SETTINGS.WEB_KEYS.TABLE.FUTURE' | translate }}</ng-container>
</span>
</td>
</ng-container>
<ng-container matColumnDef="id">
<th mat-header-cell *matHeaderCellDef>{{ 'APP.PAGES.ID' | translate }}</th>
<td mat-cell *cnslCellDef="let row; dataSource: dataSource">
{{ row.id }}
</td>
</ng-container>
<ng-container matColumnDef="type">
<th mat-header-cell *matHeaderCellDef>{{ 'PROJECT.TYPE.TITLE' | translate }}</th>
<td mat-cell *cnslCellDef="let row; dataSource: dataSource">
{{ row.key.case | uppercase }}
</td>
</ng-container>
<ng-container matColumnDef="actions" stickyEnd>
<th mat-header-cell *matHeaderCellDef></th>
<td mat-cell *cnslCellDef="let row; dataSource: dataSource">
<cnsl-table-actions *ngIf="row.state === State.INITIAL">
<button
actions
matTooltip="{{ 'ACTIONS.REMOVE' | translate }}"
color="warn"
(click)="delete.emit(row)"
mat-icon-button
@if (dataSource$ | async; as dataSource) {
<table mat-table class="table" aria-label="Elements" [dataSource]="dataSource">
<ng-container matColumnDef="state">
<th mat-header-cell *matHeaderCellDef>{{ 'APP.PAGES.STATE' | translate }}</th>
<td mat-cell *cnslCellDef="let row; let i = index; dataSource: dataSource">
<span
class="state"
[ngClass]="{
active: i === 0,
neutral: i === 1,
}"
>
<i class="las la-trash"></i>
</button>
</cnsl-table-actions>
</td>
</ng-container>
<tr mat-header-row *matHeaderRowDef="['state', 'id', 'type', 'actions']"></tr>
<tr mat-row *matRowDef="let row; columns: ['state', 'id', 'type', 'actions']"></tr>
</table>
@switch (i) {
@case (0) {
{{ 'DESCRIPTIONS.SETTINGS.WEB_KEYS.TABLE.ACTIVE' | translate }}
}
@case (1) {
{{ 'DESCRIPTIONS.SETTINGS.WEB_KEYS.TABLE.NEXT' | translate }}
}
@default {
{{ 'DESCRIPTIONS.SETTINGS.WEB_KEYS.TABLE.FUTURE' | translate }}
}
}
</span>
</td>
</ng-container>
<ng-container matColumnDef="id">
<th mat-header-cell *matHeaderCellDef>{{ 'APP.PAGES.ID' | translate }}</th>
<td mat-cell *cnslCellDef="let row; dataSource: dataSource">
{{ row.id }}
</td>
</ng-container>
<ng-container matColumnDef="type">
<th mat-header-cell *matHeaderCellDef>{{ 'PROJECT.TYPE.TITLE' | translate }}</th>
<td mat-cell *cnslCellDef="let row; dataSource: dataSource">
{{ row.key.case | uppercase }}
</td>
</ng-container>
<ng-container matColumnDef="actions" stickyEnd>
<th mat-header-cell *matHeaderCellDef></th>
<td mat-cell *cnslCellDef="let row; dataSource: dataSource">
@if (row.state === State.INITIAL) {
<cnsl-table-actions>
<button
actions
matTooltip="{{ 'ACTIONS.REMOVE' | translate }}"
color="warn"
(click)="delete.emit(row)"
mat-icon-button
>
<i class="las la-trash"></i>
</button>
</cnsl-table-actions>
}
</td>
</ng-container>
<tr mat-header-row *matHeaderRowDef="['state', 'id', 'type', 'actions']"></tr>
<tr mat-row *matRowDef="let row; columns: ['state', 'id', 'type', 'actions']"></tr>
</table>
}
</div>
</cnsl-refresh-table>
@@ -4,16 +4,16 @@
<p>{{ 'DESCRIPTIONS.SETTINGS.WEB_KEYS.TABLE.DESCRIPTION' | translate }}</p>
<p>{{ 'DESCRIPTIONS.SETTINGS.WEB_KEYS.TABLE.NOTE' | translate }}</p>
<cnsl-oidc-webkeys-table (refresh)="refresh.next(true)" (delete)="deleteWebKey($event)" [webKeys]="webKeys$ | async">
<button
*ngIf="nextWebKeyCandidate$ | async as nextWebKeyCandidate"
[disabled]="activateLoading()"
mat-raised-button
color="primary"
(click)="activateWebKey(nextWebKeyCandidate)"
>
<mat-spinner diameter="20" *ngIf="activateLoading()"></mat-spinner>
<span *ngIf="!activateLoading()">{{ 'DESCRIPTIONS.SETTINGS.WEB_KEYS.TABLE.ACTIVATE' | translate }}</span>
</button>
@if (nextWebKeyCandidate$ | async; as nextWebKeyCandidate) {
<button [disabled]="activateLoading()" mat-raised-button color="primary" (click)="activateWebKey(nextWebKeyCandidate)">
@if (activateLoading()) {
<mat-spinner diameter="20"></mat-spinner>
}
@if (!activateLoading()) {
<span>{{ 'DESCRIPTIONS.SETTINGS.WEB_KEYS.TABLE.ACTIVATE' | translate }}</span>
}
</button>
}
</cnsl-oidc-webkeys-table>
<cnsl-oidc-webkeys-create [loading]="createLoading()" (ngSubmit)="createWebKey($event)" />
<cnsl-oidc-webkeys-inactive-table [inactiveWebKeys]="inactiveWebKeys$ | async" />
@@ -1,40 +1,39 @@
<h2>{{ 'POLICY.PWD_AGE.TITLE' | translate }}</h2>
<p class="cnsl-secondary-text">{{ 'POLICY.PWD_AGE.DESCRIPTION' | translate }}</p>
<div *ngIf="loading" class="spinner-wr">
<mat-spinner diameter="30" color="primary"></mat-spinner>
</div>
@if (loading) {
<div class="spinner-wr">
<mat-spinner diameter="30" color="primary"></mat-spinner>
</div>
}
<ng-template cnslHasRole [hasRole]="['policy.delete']">
<button
*ngIf="serviceType === PolicyComponentServiceType.MGMT && !isDefault"
matTooltip="{{ 'POLICY.RESET' | translate }}"
color="warn"
(click)="resetPolicy()"
mat-stroked-button
>
{{ 'POLICY.RESET' | translate }}
</button>
@if (serviceType === PolicyComponentServiceType.MGMT && !isDefault) {
<button matTooltip="{{ 'POLICY.RESET' | translate }}" color="warn" (click)="resetPolicy()" mat-stroked-button>
{{ 'POLICY.RESET' | translate }}
</button>
}
</ng-template>
<form class="lifetime-form" (ngSubmit)="savePolicy()" [formGroup]="passwordAgeForm" autocomplete="off">
<cnsl-card *ngIf="passwordAgeData">
<div class="age-content">
<div class="row">
<cnsl-form-field class="pwd-age-form-field" required="true">
<cnsl-label>{{ 'POLICY.DATA.MAXAGEDAYS' | translate }}</cnsl-label>
<input cnslInput type="number" name="maxAgeDays" formControlName="maxAgeDays" />
</cnsl-form-field>
@if (passwordAgeData) {
<cnsl-card>
<div class="age-content">
<div class="row">
<cnsl-form-field class="pwd-age-form-field" required="true">
<cnsl-label>{{ 'POLICY.DATA.MAXAGEDAYS' | translate }}</cnsl-label>
<input cnslInput type="number" name="maxAgeDays" formControlName="maxAgeDays" />
</cnsl-form-field>
</div>
<div class="row">
<cnsl-form-field class="pwd-age-form-field" required="true">
<cnsl-label>{{ 'POLICY.DATA.EXPIREWARNDAYS' | translate }}</cnsl-label>
<input cnslInput type="number" name="expireWarnDays" formControlName="expireWarnDays" />
</cnsl-form-field>
</div>
</div>
<div class="row">
<cnsl-form-field class="pwd-age-form-field" required="true">
<cnsl-label>{{ 'POLICY.DATA.EXPIREWARNDAYS' | translate }}</cnsl-label>
<input cnslInput type="number" name="expireWarnDays" formControlName="expireWarnDays" />
</cnsl-form-field>
</div>
</div>
</cnsl-card>
</cnsl-card>
}
</form>
<div class="btn-container">
@@ -1,106 +1,105 @@
<!-- <cnsl-card
title="{{ 'POLICY.PWD_COMPLEXITY.TITLE' | translate }}"
description="{{ 'POLICY.PWD_COMPLEXITY.DESCRIPTION' | translate }}"
title="{{ 'POLICY.PWD_COMPLEXITY.TITLE' | translate }}"
description="{{ 'POLICY.PWD_COMPLEXITY.DESCRIPTION' | translate }}"
> -->
<h2>{{ 'DESCRIPTIONS.SETTINGS.PW_COMPLEXITY.TITLE' | translate }}</h2>
<p class="cnsl-secondary-text">{{ 'DESCRIPTIONS.SETTINGS.PW_COMPLEXITY.DESCRIPTION' | translate }}</p>
<div *ngIf="loading" class="spinner-wr">
<mat-spinner diameter="30" color="primary"></mat-spinner>
</div>
@if (loading) {
<div class="spinner-wr">
<mat-spinner diameter="30" color="primary"></mat-spinner>
</div>
}
<ng-template cnslHasRole [hasRole]="['policy.delete']">
<button
*ngIf="serviceType === PolicyComponentServiceType.MGMT && !isDefault"
matTooltip="{{ 'POLICY.RESET' | translate }}"
color="warn"
(click)="removePolicy()"
mat-stroked-button
>
{{ 'POLICY.RESET' | translate }}
</button>
@if (serviceType === PolicyComponentServiceType.MGMT && !isDefault) {
<button matTooltip="{{ 'POLICY.RESET' | translate }}" color="warn" (click)="removePolicy()" mat-stroked-button>
{{ 'POLICY.RESET' | translate }}
</button>
}
</ng-template>
<cnsl-card *ngIf="complexityData">
<div class="complexity-content">
<div class="row">
<div class="length-wrapper">
<button mat-icon-button (click)="decrementLength()" [disabled]="(['policy.write'] | hasRole | async) === false">
<mat-icon>remove</mat-icon>
</button>
<span>{{ complexityData.minLength }}</span>
<button mat-icon-button (click)="incrementLength()" [disabled]="(['policy.write'] | hasRole | async) === false">
<mat-icon>add</mat-icon>
</button>
@if (complexityData) {
<cnsl-card>
<div class="complexity-content">
<div class="row">
<div class="length-wrapper">
<button mat-icon-button (click)="decrementLength()" [disabled]="(['policy.write'] | hasRole | async) === false">
<mat-icon>remove</mat-icon>
</button>
<span>{{ complexityData.minLength }}</span>
<button mat-icon-button (click)="incrementLength()" [disabled]="(['policy.write'] | hasRole | async) === false">
<mat-icon>add</mat-icon>
</button>
</div>
<div class="number-toggle-row">
<mat-icon class="icon" svgIcon="mdi_counter"></mat-icon>
<span class="left-desc">{{ 'POLICY.DATA.MINLENGTH' | translate }}</span>
</div>
</div>
<div class="number-toggle-row">
<mat-icon class="icon" svgIcon="mdi_counter"></mat-icon>
<span class="left-desc">{{ 'POLICY.DATA.MINLENGTH' | translate }}</span>
<div class="row">
<mat-checkbox
class="slide-toggle"
color="primary"
name="hasNumber"
ngDefaultControl
[(ngModel)]="complexityData.hasNumber"
[disabled]="(['policy.write'] | hasRole | async) === false"
>
<div class="slide-toggle-row">
<mat-icon class="icon" svgIcon="mdi_numeric"></mat-icon>
<span class="left-desc">{{ 'POLICY.DATA.HASNUMBER' | translate }}</span>
</div>
</mat-checkbox>
</div>
<div class="row">
<mat-checkbox
class="slide-toggle"
color="primary"
name="hasSymbol"
ngDefaultControl
[(ngModel)]="complexityData.hasSymbol"
[disabled]="(['policy.write'] | hasRole | async) === false"
>
<div class="slide-toggle-row">
<mat-icon class="icon" svgIcon="mdi_symbol"></mat-icon>
<span class="left-desc">{{ 'POLICY.DATA.HASSYMBOL' | translate }}</span>
</div>
</mat-checkbox>
</div>
<div class="row">
<mat-checkbox
class="slide-toggle"
color="primary"
name="hasLowercase"
ngDefaultControl
[(ngModel)]="complexityData.hasLowercase"
[disabled]="(['policy.write'] | hasRole | async) === false"
>
<div class="slide-toggle-row">
<mat-icon class="icon" svgIcon="mdi_format-letter-case-lower"></mat-icon>
<span class="left-desc">{{ 'POLICY.DATA.HASLOWERCASE' | translate }}</span>
</div>
</mat-checkbox>
</div>
<div class="row">
<mat-checkbox
class="slide-toggle"
color="primary"
name="hasUppercase"
ngDefaultControl
[(ngModel)]="complexityData.hasUppercase"
[disabled]="(['policy.write'] | hasRole | async) === false"
>
<div class="slide-toggle-row">
<mat-icon class="icon" svgIcon="mdi_format-letter-case-upper"></mat-icon>
<span class="left-desc">{{ 'POLICY.DATA.HASUPPERCASE' | translate }}</span>
</div>
</mat-checkbox>
</div>
</div>
<div class="row">
<mat-checkbox
class="slide-toggle"
color="primary"
name="hasNumber"
ngDefaultControl
[(ngModel)]="complexityData.hasNumber"
[disabled]="(['policy.write'] | hasRole | async) === false"
>
<div class="slide-toggle-row">
<mat-icon class="icon" svgIcon="mdi_numeric"></mat-icon>
<span class="left-desc">{{ 'POLICY.DATA.HASNUMBER' | translate }}</span>
</div>
</mat-checkbox>
</div>
<div class="row">
<mat-checkbox
class="slide-toggle"
color="primary"
name="hasSymbol"
ngDefaultControl
[(ngModel)]="complexityData.hasSymbol"
[disabled]="(['policy.write'] | hasRole | async) === false"
>
<div class="slide-toggle-row">
<mat-icon class="icon" svgIcon="mdi_symbol"></mat-icon>
<span class="left-desc">{{ 'POLICY.DATA.HASSYMBOL' | translate }}</span>
</div>
</mat-checkbox>
</div>
<div class="row">
<mat-checkbox
class="slide-toggle"
color="primary"
name="hasLowercase"
ngDefaultControl
[(ngModel)]="complexityData.hasLowercase"
[disabled]="(['policy.write'] | hasRole | async) === false"
>
<div class="slide-toggle-row">
<mat-icon class="icon" svgIcon="mdi_format-letter-case-lower"></mat-icon>
<span class="left-desc">{{ 'POLICY.DATA.HASLOWERCASE' | translate }}</span>
</div>
</mat-checkbox>
</div>
<div class="row">
<mat-checkbox
class="slide-toggle"
color="primary"
name="hasUppercase"
ngDefaultControl
[(ngModel)]="complexityData.hasUppercase"
[disabled]="(['policy.write'] | hasRole | async) === false"
>
<div class="slide-toggle-row">
<mat-icon class="icon" svgIcon="mdi_format-letter-case-upper"></mat-icon>
<span class="left-desc">{{ 'POLICY.DATA.HASUPPERCASE' | translate }}</span>
</div>
</mat-checkbox>
</div>
</div>
</cnsl-card>
</cnsl-card>
}
<div class="btn-container">
<button
@@ -2,69 +2,65 @@
<p class="cnsl-secondary-text">{{ 'POLICY.PWD_LOCKOUT.DESCRIPTION' | translate }}</p>
<ng-template cnslHasRole [hasRole]="['policy.delete']">
<button
*ngIf="serviceType === PolicyComponentServiceType.MGMT && !isDefault"
matTooltip="{{ 'POLICY.RESET' | translate }}"
color="warn"
(click)="resetPolicy()"
mat-stroked-button
>
{{ 'POLICY.RESET' | translate }}
</button>
@if (serviceType === PolicyComponentServiceType.MGMT && !isDefault) {
<button matTooltip="{{ 'POLICY.RESET' | translate }}" color="warn" (click)="resetPolicy()" mat-stroked-button>
{{ 'POLICY.RESET' | translate }}
</button>
}
</ng-template>
<cnsl-card *ngIf="lockoutData">
<div class="lockout-content">
<div class="row">
<div class="length-wrapper">
<button
[disabled]="(['policy.write'] | hasRole | async) === false"
mat-icon-button
(click)="decrementPasswordMaxAttempts()"
>
<mat-icon>remove</mat-icon>
</button>
<span>{{ lockoutData.maxPasswordAttempts }}</span>
<button
[disabled]="(['policy.write'] | hasRole | async) === false"
mat-icon-button
(click)="incrementPasswordMaxAttempts()"
>
<mat-icon>add</mat-icon>
</button>
@if (lockoutData) {
<cnsl-card>
<div class="lockout-content">
<div class="row">
<div class="length-wrapper">
<button
[disabled]="(['policy.write'] | hasRole | async) === false"
mat-icon-button
(click)="decrementPasswordMaxAttempts()"
>
<mat-icon>remove</mat-icon>
</button>
<span>{{ lockoutData.maxPasswordAttempts }}</span>
<button
[disabled]="(['policy.write'] | hasRole | async) === false"
mat-icon-button
(click)="incrementPasswordMaxAttempts()"
>
<mat-icon>add</mat-icon>
</button>
</div>
<div class="number-toggle-row">
<span class="left-desc">{{ 'POLICY.DATA.MAXPASSWORDATTEMPTS' | translate }}</span>
<span class="fill-space"></span>
</div>
</div>
<div class="number-toggle-row">
<span class="left-desc">{{ 'POLICY.DATA.MAXPASSWORDATTEMPTS' | translate }}</span>
<span class="fill-space"></span>
<div class="row">
<div class="length-wrapper">
<button
[disabled]="(['policy.write'] | hasRole | async) === false"
mat-icon-button
(click)="decrementOTPMaxAttempts()"
>
<mat-icon>remove</mat-icon>
</button>
<span>{{ lockoutData.maxOtpAttempts }}</span>
<button
[disabled]="(['policy.write'] | hasRole | async) === false"
mat-icon-button
(click)="incrementOTPMaxAttempts()"
>
<mat-icon>add</mat-icon>
</button>
</div>
<div class="number-toggle-row">
<span class="left-desc">{{ 'POLICY.DATA.MAXOTPATTEMPTS' | translate }}</span>
<span class="fill-space"></span>
</div>
</div>
</div>
<div class="row">
<div class="length-wrapper">
<button
[disabled]="(['policy.write'] | hasRole | async) === false"
mat-icon-button
(click)="decrementOTPMaxAttempts()"
>
<mat-icon>remove</mat-icon>
</button>
<span>{{ lockoutData.maxOtpAttempts }}</span>
<button
[disabled]="(['policy.write'] | hasRole | async) === false"
mat-icon-button
(click)="incrementOTPMaxAttempts()"
>
<mat-icon>add</mat-icon>
</button>
</div>
<div class="number-toggle-row">
<span class="left-desc">{{ 'POLICY.DATA.MAXOTPATTEMPTS' | translate }}</span>
<span class="fill-space"></span>
</div>
</div>
</div>
</cnsl-card>
</cnsl-card>
}
<div class="btn-container">
<button
@@ -1,7 +1,7 @@
<h2>{{ 'DESCRIPTIONS.SETTINGS.PRIVACY_POLICY.TITLE' | translate }}</h2>
<p class="cnsl-secondary-text">{{ 'DESCRIPTIONS.SETTINGS.PRIVACY_POLICY.DESCRIPTION' | translate }}</p>
<ng-container *ngIf="serviceType === PolicyComponentServiceType.MGMT && !isDefault">
@if (serviceType === PolicyComponentServiceType.MGMT && !isDefault) {
<ng-template cnslHasRole [hasRole]="['policy.delete']">
<button
color="primary"
@@ -14,52 +14,48 @@
{{ 'POLICY.RESET' | translate }}
</button>
</ng-template>
</ng-container>
}
<!-- <cnsl-info-section *ngIf="isDefault"> {{ 'POLICY.DEFAULTLABEL' | translate }}</cnsl-info-section> -->
<div>
<form *ngIf="form" [formGroup]="form" class="policy-content">
<cnsl-form-field class="privacy-policy-formfield">
<cnsl-label>{{ 'POLICY.PRIVACY_POLICY.TOSLINK' | translate }}</cnsl-label>
<input cnslInput name="tosLink" formControlName="tosLink" />
<template [ngTemplateOutlet]="templateRef" [ngTemplateOutletContext]="{ key: 'tosLink' }"></template>
</cnsl-form-field>
<cnsl-form-field class="privacy-policy-formfield">
<cnsl-label>{{ 'POLICY.PRIVACY_POLICY.POLICYLINK' | translate }}</cnsl-label>
<input cnslInput name="privacyLink" formControlName="privacyLink" />
<template [ngTemplateOutlet]="templateRef" [ngTemplateOutletContext]="{ key: 'privacyLink' }"></template>
</cnsl-form-field>
<cnsl-form-field class="privacy-policy-formfield">
<cnsl-label>{{ 'POLICY.PRIVACY_POLICY.HELPLINK' | translate }}</cnsl-label>
<input cnslInput name="helpLink" formControlName="helpLink" />
<template [ngTemplateOutlet]="templateRef" [ngTemplateOutletContext]="{ key: 'helpLink' }"></template>
</cnsl-form-field>
<cnsl-form-field class="privacy-policy-formfield">
<cnsl-label>{{ 'POLICY.PRIVACY_POLICY.SUPPORTEMAIL' | translate }}</cnsl-label>
<input cnslInput name="supportEmail" formControlName="supportEmail" />
</cnsl-form-field>
<cnsl-form-field class="privacy-policy-formfield">
<cnsl-label>{{ 'POLICY.PRIVACY_POLICY.CUSTOMLINK' | translate }}</cnsl-label>
<input cnslInput name="customLink" formControlName="customLink" />
<template [ngTemplateOutlet]="templateRef" [ngTemplateOutletContext]="{ key: 'customLink' }"></template>
</cnsl-form-field>
<cnsl-form-field class="privacy-policy-formfield">
<cnsl-label>{{ 'POLICY.PRIVACY_POLICY.CUSTOMLINKTEXT' | translate }}</cnsl-label>
<input cnslInput name="customLinkText" formControlName="customLinkText" />
</cnsl-form-field>
<cnsl-form-field class="privacy-policy-formfield">
<cnsl-label>{{ 'POLICY.PRIVACY_POLICY.DOCSLINK' | translate }}</cnsl-label>
<input cnslInput name="docsLink" formControlName="docsLink" />
<template [ngTemplateOutlet]="templateRef" [ngTemplateOutletContext]="{ key: 'docsLink' }"></template>
</cnsl-form-field>
</form>
@if (form) {
<form [formGroup]="form" class="policy-content">
<cnsl-form-field class="privacy-policy-formfield">
<cnsl-label>{{ 'POLICY.PRIVACY_POLICY.TOSLINK' | translate }}</cnsl-label>
<input cnslInput name="tosLink" formControlName="tosLink" />
<template [ngTemplateOutlet]="templateRef" [ngTemplateOutletContext]="{ key: 'tosLink' }"></template>
</cnsl-form-field>
<cnsl-form-field class="privacy-policy-formfield">
<cnsl-label>{{ 'POLICY.PRIVACY_POLICY.POLICYLINK' | translate }}</cnsl-label>
<input cnslInput name="privacyLink" formControlName="privacyLink" />
<template [ngTemplateOutlet]="templateRef" [ngTemplateOutletContext]="{ key: 'privacyLink' }"></template>
</cnsl-form-field>
<cnsl-form-field class="privacy-policy-formfield">
<cnsl-label>{{ 'POLICY.PRIVACY_POLICY.HELPLINK' | translate }}</cnsl-label>
<input cnslInput name="helpLink" formControlName="helpLink" />
<template [ngTemplateOutlet]="templateRef" [ngTemplateOutletContext]="{ key: 'helpLink' }"></template>
</cnsl-form-field>
<cnsl-form-field class="privacy-policy-formfield">
<cnsl-label>{{ 'POLICY.PRIVACY_POLICY.SUPPORTEMAIL' | translate }}</cnsl-label>
<input cnslInput name="supportEmail" formControlName="supportEmail" />
</cnsl-form-field>
<cnsl-form-field class="privacy-policy-formfield">
<cnsl-label>{{ 'POLICY.PRIVACY_POLICY.CUSTOMLINK' | translate }}</cnsl-label>
<input cnslInput name="customLink" formControlName="customLink" />
<template [ngTemplateOutlet]="templateRef" [ngTemplateOutletContext]="{ key: 'customLink' }"></template>
</cnsl-form-field>
<cnsl-form-field class="privacy-policy-formfield">
<cnsl-label>{{ 'POLICY.PRIVACY_POLICY.CUSTOMLINKTEXT' | translate }}</cnsl-label>
<input cnslInput name="customLinkText" formControlName="customLinkText" />
</cnsl-form-field>
<cnsl-form-field class="privacy-policy-formfield">
<cnsl-label>{{ 'POLICY.PRIVACY_POLICY.DOCSLINK' | translate }}</cnsl-label>
<input cnslInput name="docsLink" formControlName="docsLink" />
<template [ngTemplateOutlet]="templateRef" [ngTemplateOutletContext]="{ key: 'docsLink' }"></template>
</cnsl-form-field>
</form>
}
</div>
<div class="policy-actions">
@@ -86,8 +82,12 @@
(click)="addChip(key, LANGPLACEHOLDER)"
>
<span class="key">{{ LANGPLACEHOLDER }}</span>
<i *ngIf="copied !== LANGPLACEHOLDER" class="las la-clipboard"></i>
<i *ngIf="copied === LANGPLACEHOLDER" class="las la-clipboard-check"></i>
@if (copied !== LANGPLACEHOLDER) {
<i class="las la-clipboard"></i>
}
@if (copied === LANGPLACEHOLDER) {
<i class="las la-clipboard-check"></i>
}
</div>
</div>
</ng-template>
@@ -1,63 +1,60 @@
<div class="preview" *ngIf="policy">
<div
class="dashed"
[ngClass]="{ dark: theme === Theme.DARK, light: theme === Theme.LIGHT }"
[style.background]="theme === Theme.DARK ? policy.backgroundColorDark : policy.backgroundColor"
>
<div class="login-wrapper" [style.color]="theme === Theme.DARK ? policy.fontColorDark : policy.fontColor">
<img *ngIf="policy.logoUrl && theme === Theme.LIGHT" [src]="policy.logoUrl" alt="logo-mock" />
<img *ngIf="policy.logoUrlDark && theme === Theme.DARK" [src]="policy.logoUrlDark" alt="logo-mock" />
<h1 [style.color]="theme === Theme.DARK ? policy.fontColorDark : policy.fontColor">
{{ 'POLICY.PRIVATELABELING.PREVIEW.TITLE' | translate }}
</h1>
<p [style.color]="theme === Theme.DARK ? policy.fontColorDark : policy.fontColor" class="desc-text">
{{ 'POLICY.PRIVATELABELING.PREVIEW.SECOND' | translate }}
</p>
<cnsl-form-field class="formfield">
<cnsl-label>Loginname</cnsl-label>
<input
cnslInput
[style.color]="theme === Theme.DARK ? policy.fontColorDark : policy.fontColor"
value="road.runner"
/>
</cnsl-form-field>
<div class="error-msg" [style.color]="theme === Theme.DARK ? policy.warnColorDark : policy.warnColor">
<i
class="las la-exclamation-circle"
[style.color]="theme === Theme.DARK ? policy.warnColorDark : policy.warnColor"
></i>
<span [style.color]="theme === Theme.DARK ? policy.warnColorDark : policy.warnColor">{{
'POLICY.PRIVATELABELING.PREVIEW.ERROR' | translate
}}</span>
</div>
<div class="btn-wrapper">
<button
mat-stroked-button
[style.borderColor]="theme === Theme.DARK ? '#ffffff1f' : '#0000001f'"
[style.color]="theme === Theme.DARK ? policy.fontColorDark : policy.fontColor"
>
{{ 'POLICY.PRIVATELABELING.PREVIEW.SECONDARYBUTTON' | translate }}
</button>
<button
*ngIf="theme === Theme.DARK"
mat-raised-button
[style.background]="policy.primaryColorDark"
[style.color]="contrastTextColor"
>
{{ 'POLICY.PRIVATELABELING.PREVIEW.PRIMARYBUTTON' | translate }}
</button>
<button
*ngIf="theme === Theme.LIGHT"
mat-raised-button
[style.background]="policy.primaryColor"
[style.color]="contrastTextColor"
>
{{ 'POLICY.PRIVATELABELING.PREVIEW.PRIMARYBUTTON' | translate }}
</button>
@if (policy) {
<div class="preview">
<div
class="dashed"
[ngClass]="{ dark: theme === Theme.DARK, light: theme === Theme.LIGHT }"
[style.background]="theme === Theme.DARK ? policy.backgroundColorDark : policy.backgroundColor"
>
<div class="login-wrapper" [style.color]="theme === Theme.DARK ? policy.fontColorDark : policy.fontColor">
@if (policy.logoUrl && theme === Theme.LIGHT) {
<img [src]="policy.logoUrl" alt="logo-mock" />
}
@if (policy.logoUrlDark && theme === Theme.DARK) {
<img [src]="policy.logoUrlDark" alt="logo-mock" />
}
<h1 [style.color]="theme === Theme.DARK ? policy.fontColorDark : policy.fontColor">
{{ 'POLICY.PRIVATELABELING.PREVIEW.TITLE' | translate }}
</h1>
<p [style.color]="theme === Theme.DARK ? policy.fontColorDark : policy.fontColor" class="desc-text">
{{ 'POLICY.PRIVATELABELING.PREVIEW.SECOND' | translate }}
</p>
<cnsl-form-field class="formfield">
<cnsl-label>Loginname</cnsl-label>
<input
cnslInput
[style.color]="theme === Theme.DARK ? policy.fontColorDark : policy.fontColor"
value="road.runner"
/>
</cnsl-form-field>
<div class="error-msg" [style.color]="theme === Theme.DARK ? policy.warnColorDark : policy.warnColor">
<i
class="las la-exclamation-circle"
[style.color]="theme === Theme.DARK ? policy.warnColorDark : policy.warnColor"
></i>
<span [style.color]="theme === Theme.DARK ? policy.warnColorDark : policy.warnColor">{{
'POLICY.PRIVATELABELING.PREVIEW.ERROR' | translate
}}</span>
</div>
<div class="btn-wrapper">
<button
mat-stroked-button
[style.borderColor]="theme === Theme.DARK ? '#ffffff1f' : '#0000001f'"
[style.color]="theme === Theme.DARK ? policy.fontColorDark : policy.fontColor"
>
{{ 'POLICY.PRIVATELABELING.PREVIEW.SECONDARYBUTTON' | translate }}
</button>
@if (theme === Theme.DARK) {
<button mat-raised-button [style.background]="policy.primaryColorDark" [style.color]="contrastTextColor">
{{ 'POLICY.PRIVATELABELING.PREVIEW.PRIMARYBUTTON' | translate }}
</button>
}
@if (theme === Theme.LIGHT) {
<button mat-raised-button [style.background]="policy.primaryColor" [style.color]="contrastTextColor">
{{ 'POLICY.PRIVATELABELING.PREVIEW.PRIMARYBUTTON' | translate }}
</button>
}
</div>
</div>
</div>
</div>
</div>
}
@@ -1,69 +1,66 @@
<cnsl-card title="{{ 'SETTING.SECRETS.TYPE.' + generatorType | translate }}">
<form *ngIf="specsForm" [formGroup]="specsForm" (ngSubmit)="saveSecretGenerator()">
<cnsl-form-field class="generator-form-field" label="Expiration">
<cnsl-label>{{ 'SETTING.SECRETS.EXPIRY' | translate }}</cnsl-label>
<input cnslInput name="expiry" type="number" formControlName="expiry" id="{{ 'expiry' + generatorType }}" />
</cnsl-form-field>
<cnsl-form-field class="generator-form-field" label="Length">
<cnsl-label>{{ 'SETTING.SECRETS.LENGTH' | translate }}</cnsl-label>
<input cnslInput name="length" type="number" formControlName="length" id="{{ 'length' + generatorType }}" />
</cnsl-form-field>
<div class="slide-toggle-wrapper">
<mat-slide-toggle
class="slide-toggle"
color="primary"
name="includeDigits"
formControlName="includeDigits"
id="{{ 'includeDigits' + generatorType }}"
>
<div class="slide-toggle-row">
<mat-icon class="icon" svgIcon="mdi_numeric"></mat-icon>
<span class="left-desc">{{ 'SETTING.SECRETS.INCLUDEDIGITS' | translate }}</span>
</div>
</mat-slide-toggle>
<mat-slide-toggle
class="slide-toggle"
color="primary"
name="includeSymbols"
formControlName="includeSymbols"
id="{{ 'includeSymbols' + generatorType }}"
>
<div class="slide-toggle-row">
<mat-icon class="icon" svgIcon="mdi_symbol"></mat-icon>
<span class="left-desc">{{ 'SETTING.SECRETS.INCLUDESYMBOLS' | translate }}</span>
</div>
</mat-slide-toggle>
<mat-slide-toggle
class="slide-toggle"
color="primary"
name="includeLowerLetters"
formControlName="includeLowerLetters"
id="{{ 'includeLowerLetters' + generatorType }}"
>
<div class="slide-toggle-row">
<mat-icon class="icon" svgIcon="mdi_format-letter-case-lower"></mat-icon>
<span class="left-desc">{{ 'SETTING.SECRETS.INCLUDELOWERLETTERS' | translate }}</span>
</div>
</mat-slide-toggle>
<mat-slide-toggle
class="slide-toggle"
color="primary"
name="includeUpperLetters"
formControlName="includeUpperLetters"
id="{{ 'includeUpperLetters' + generatorType }}"
>
<div class="slide-toggle-row">
<mat-icon class="icon" svgIcon="mdi_format-letter-case-upper"></mat-icon>
<span class="left-desc">{{ 'SETTING.SECRETS.INCLUDEUPPERLETTERS' | translate }}</span>
</div>
</mat-slide-toggle>
</div>
</form>
@if (specsForm) {
<form [formGroup]="specsForm" (ngSubmit)="saveSecretGenerator()">
<cnsl-form-field class="generator-form-field" label="Expiration">
<cnsl-label>{{ 'SETTING.SECRETS.EXPIRY' | translate }}</cnsl-label>
<input cnslInput name="expiry" type="number" formControlName="expiry" id="{{ 'expiry' + generatorType }}" />
</cnsl-form-field>
<cnsl-form-field class="generator-form-field" label="Length">
<cnsl-label>{{ 'SETTING.SECRETS.LENGTH' | translate }}</cnsl-label>
<input cnslInput name="length" type="number" formControlName="length" id="{{ 'length' + generatorType }}" />
</cnsl-form-field>
<div class="slide-toggle-wrapper">
<mat-slide-toggle
class="slide-toggle"
color="primary"
name="includeDigits"
formControlName="includeDigits"
id="{{ 'includeDigits' + generatorType }}"
>
<div class="slide-toggle-row">
<mat-icon class="icon" svgIcon="mdi_numeric"></mat-icon>
<span class="left-desc">{{ 'SETTING.SECRETS.INCLUDEDIGITS' | translate }}</span>
</div>
</mat-slide-toggle>
<mat-slide-toggle
class="slide-toggle"
color="primary"
name="includeSymbols"
formControlName="includeSymbols"
id="{{ 'includeSymbols' + generatorType }}"
>
<div class="slide-toggle-row">
<mat-icon class="icon" svgIcon="mdi_symbol"></mat-icon>
<span class="left-desc">{{ 'SETTING.SECRETS.INCLUDESYMBOLS' | translate }}</span>
</div>
</mat-slide-toggle>
<mat-slide-toggle
class="slide-toggle"
color="primary"
name="includeLowerLetters"
formControlName="includeLowerLetters"
id="{{ 'includeLowerLetters' + generatorType }}"
>
<div class="slide-toggle-row">
<mat-icon class="icon" svgIcon="mdi_format-letter-case-lower"></mat-icon>
<span class="left-desc">{{ 'SETTING.SECRETS.INCLUDELOWERLETTERS' | translate }}</span>
</div>
</mat-slide-toggle>
<mat-slide-toggle
class="slide-toggle"
color="primary"
name="includeUpperLetters"
formControlName="includeUpperLetters"
id="{{ 'includeUpperLetters' + generatorType }}"
>
<div class="slide-toggle-row">
<mat-icon class="icon" svgIcon="mdi_format-letter-case-upper"></mat-icon>
<span class="left-desc">{{ 'SETTING.SECRETS.INCLUDEUPPERLETTERS' | translate }}</span>
</div>
</mat-slide-toggle>
</div>
</form>
}
<div class="action">
<button
(click)="saveSecretGenerator()"
@@ -73,8 +70,12 @@
type="submit"
id="{{ 'saveSecretGenerator' + generatorType }}"
>
<mat-spinner diameter="20" *ngIf="loading"></mat-spinner>
<span *ngIf="!loading">{{ 'ACTIONS.SAVE' | translate }}</span>
@if (loading) {
<mat-spinner diameter="20"></mat-spinner>
}
@if (!loading) {
<span>{{ 'ACTIONS.SAVE' | translate }}</span>
}
</button>
</div>
</cnsl-card>
@@ -2,5 +2,7 @@
<p class="cnsl-secondary-text">{{ 'DESCRIPTIONS.SETTINGS.SECRET_GENERATORS.DESCRIPTION' | translate }}</p>
<div class="generators">
<cnsl-secret-generator-card *ngFor="let type of AVAILABLEGENERATORS" [generatorType]="type" />
@for (type of AVAILABLEGENERATORS; track type) {
<cnsl-secret-generator-card [generatorType]="type" />
}
</div>
@@ -2,7 +2,9 @@
<p class="cnsl-secondary-text">{{ 'DESCRIPTIONS.SETTINGS.SECURITY.DESCRIPTION' | translate }}</p>
<div class="spinner-wr">
<mat-spinner diameter="30" *ngIf="loading" color="primary"></mat-spinner>
@if (loading) {
<mat-spinner diameter="30" color="primary"></mat-spinner>
}
</div>
<div class="security-wrapper">
@@ -40,14 +42,15 @@
</form>
<div class="security-allowed-uris-list">
<div *ngFor="let uri of originsList" class="uri-line" [ngClass]="{ disabled: !iframeEnabled }">
<span class="uri">{{ uri }}</span>
<span class="fill-space"></span>
<button matTooltip="{{ 'ACTIONS.DELETE' | translate }}" mat-icon-button (click)="remove(uri)" class="icon-button">
<mat-icon class="icon">cancel</mat-icon>
</button>
</div>
@for (uri of originsList; track uri) {
<div class="uri-line" [ngClass]="{ disabled: !iframeEnabled }">
<span class="uri">{{ uri }}</span>
<span class="fill-space"></span>
<button matTooltip="{{ 'ACTIONS.DELETE' | translate }}" mat-icon-button (click)="remove(uri)" class="icon-button">
<mat-icon class="icon">cancel</mat-icon>
</button>
</div>
}
</div>
<h3>{{ 'SETTING.SECURITY.IMPERSONATIONTITLE' | translate }}</h3>
@@ -1,89 +1,88 @@
<cnsl-detail-layout
*ngIf="project"
[hasBackButton]="true"
title="{{ projectName }} {{ 'PROJECT.MEMBER.TITLE' | translate }}"
>
<p class="subinfo" sub>
<span class="cnsl-secondary-text">{{ 'PROJECT.MEMBER.DESCRIPTION' | translate }}</span>
<a mat-icon-button href="https://zitadel.com/docs/concepts/structure/administrators" target="_blank">
<mat-icon class="icon">info_outline</mat-icon>
</a>
</p>
<cnsl-members-table
*ngIf="project"
[dataSource]="dataSource"
[memberRoleOptions]="memberRoleOptions"
(updateRoles)="updateRoles($event.member, $event.change)"
[factoryLoadFunc]="changePageFactory"
(changedSelection)="selection = $event"
[refreshTrigger]="changePage"
[canWrite]="
[
'project.member.write$',
'project.member.write:' + (projectType === ProjectType.PROJECTTYPE_OWNED)
? $any(project)?.id
: projectType === ProjectType.PROJECTTYPE_GRANTED
? $any(project)?.projectId
: '',
]
| hasRole
| async
"
[canDelete]="
[
'project.member.delete$',
'project.member.delete:' + (projectType === ProjectType.PROJECTTYPE_OWNED)
? $any(project)?.id
: projectType === ProjectType.PROJECTTYPE_GRANTED
? $any(project)?.projectId
: '',
]
| hasRole
| async
"
(deleteMember)="removeProjectMember($event)"
>
<ng-template
cnslHasRole
selectactions
[hasRole]="[
'project.member.delete:' + (projectType === ProjectType.PROJECTTYPE_OWNED)
? $any(project)?.id
: projectType === ProjectType.PROJECTTYPE_GRANTED
? $any(project)?.projectId
: '',
'project.member.delete',
]"
>
<button
(click)="removeProjectMemberSelection()"
color="warn"
matTooltip="{{ 'ORG_DETAIL.TABLE.DELETE' | translate }}"
mat-raised-button
@if (project) {
<cnsl-detail-layout [hasBackButton]="true" title="{{ projectName }} {{ 'PROJECT.MEMBER.TITLE' | translate }}">
<p class="subinfo" sub>
<span class="cnsl-secondary-text">{{ 'PROJECT.MEMBER.DESCRIPTION' | translate }}</span>
<a mat-icon-button href="https://zitadel.com/docs/concepts/structure/administrators" target="_blank">
<mat-icon class="icon">info_outline</mat-icon>
</a>
</p>
@if (project) {
<cnsl-members-table
[dataSource]="dataSource"
[memberRoleOptions]="memberRoleOptions"
(updateRoles)="updateRoles($event.member, $event.change)"
[factoryLoadFunc]="changePageFactory"
(changedSelection)="selection = $event"
[refreshTrigger]="changePage"
[canWrite]="
[
'project.member.write$',
'project.member.write:' + (projectType === ProjectType.PROJECTTYPE_OWNED)
? $any(project)?.id
: projectType === ProjectType.PROJECTTYPE_GRANTED
? $any(project)?.projectId
: '',
]
| hasRole
| async
"
[canDelete]="
[
'project.member.delete$',
'project.member.delete:' + (projectType === ProjectType.PROJECTTYPE_OWNED)
? $any(project)?.id
: projectType === ProjectType.PROJECTTYPE_GRANTED
? $any(project)?.projectId
: '',
]
| hasRole
| async
"
(deleteMember)="removeProjectMember($event)"
>
<i class="las la-trash"></i>
<span>{{ 'ACTIONS.SELECTIONDELETE' | translate }}</span>
<cnsl-action-keys [type]="ActionKeysType.DELETE" (actionTriggered)="removeProjectMemberSelection()">
</cnsl-action-keys>
</button>
</ng-template>
<ng-template
cnslHasRole
writeactions
[hasRole]="[
'project.member.write:' + (projectType === ProjectType.PROJECTTYPE_OWNED)
? $any(project)?.id
: projectType === ProjectType.PROJECTTYPE_GRANTED
? $any(project)?.projectId
: '',
'project.member.write',
]"
>
<button color="primary" (click)="openAddMember()" class="cnsl-action-button" mat-raised-button>
<mat-icon class="icon">add</mat-icon>
<span>{{ 'ACTIONS.NEW' | translate }}</span>
<cnsl-action-keys (actionTriggered)="openAddMember()"> </cnsl-action-keys>
</button>
</ng-template>
</cnsl-members-table>
</cnsl-detail-layout>
<ng-template
cnslHasRole
selectactions
[hasRole]="[
'project.member.delete:' + (projectType === ProjectType.PROJECTTYPE_OWNED)
? $any(project)?.id
: projectType === ProjectType.PROJECTTYPE_GRANTED
? $any(project)?.projectId
: '',
'project.member.delete',
]"
>
<button
(click)="removeProjectMemberSelection()"
color="warn"
matTooltip="{{ 'ORG_DETAIL.TABLE.DELETE' | translate }}"
mat-raised-button
>
<i class="las la-trash"></i>
<span>{{ 'ACTIONS.SELECTIONDELETE' | translate }}</span>
<cnsl-action-keys [type]="ActionKeysType.DELETE" (actionTriggered)="removeProjectMemberSelection()">
</cnsl-action-keys>
</button>
</ng-template>
<ng-template
cnslHasRole
writeactions
[hasRole]="[
'project.member.write:' + (projectType === ProjectType.PROJECTTYPE_OWNED)
? $any(project)?.id
: projectType === ProjectType.PROJECTTYPE_GRANTED
? $any(project)?.projectId
: '',
'project.member.write',
]"
>
<button color="primary" (click)="openAddMember()" class="cnsl-action-button" mat-raised-button>
<mat-icon class="icon">add</mat-icon>
<span>{{ 'ACTIONS.NEW' | translate }}</span>
<cnsl-action-keys (actionTriggered)="openAddMember()"> </cnsl-action-keys>
</button>
</ng-template>
</cnsl-members-table>
}
</cnsl-detail-layout>
}
@@ -4,9 +4,11 @@
<p class="desc cnsl-secondary-text">{{ 'PROJECT.PAGES.PRIVATELABEL.DIALOG.DESCRIPTION' | translate }}</p>
<mat-radio-group class="project-radio-group" [(ngModel)]="setting">
<mat-radio-button class="radio-button" *ngFor="let selection of settings" [value]="selection">
<span class="label">{{ 'PROJECT.PAGES.PRIVATELABEL.' + selection + '.TITLE' | translate }}</span>
</mat-radio-button>
@for (selection of settings; track selection) {
<mat-radio-button class="radio-button" [value]="selection">
<span class="label">{{ 'PROJECT.PAGES.PRIVATELABEL.' + selection + '.TITLE' | translate }}</span>
</mat-radio-button>
}
</mat-radio-group>
<cnsl-info-section class="info">{{ 'PROJECT.PAGES.PRIVATELABEL.' + setting + '.DESC' | translate }}</cnsl-info-section>
</div>
@@ -5,7 +5,9 @@
[style.borderColor]="role.color.hex + '30'"
>
<ng-content></ng-content>
<button class="role-rm" mat-icon-button *ngIf="showRemove" (click)="emitRemove()">
<mat-icon class="role-rm-icon">clear</mat-icon>
</button>
@if (showRemove) {
<button class="role-rm" mat-icon-button (click)="emitRemove()">
<mat-icon class="role-rm-icon">clear</mat-icon>
</button>
}
</div>
@@ -3,20 +3,22 @@
</h1>
<p class="desc cnsl-secondary-text">{{ 'PROJECT.ROLE.EDITDESCRIPTION' | translate }}</p>
<div mat-dialog-content>
<form *ngIf="formGroup" class="role-detail-full-width" [formGroup]="formGroup" (ngSubmit)="submitForm()">
<cnsl-form-field>
<cnsl-label>{{ 'PROJECT.ROLE.KEY' | translate }}</cnsl-label>
<input cnslInput formControlName="key" />
</cnsl-form-field>
<cnsl-form-field>
<cnsl-label>{{ 'PROJECT.ROLE.DISPLAY_NAME' | translate }}</cnsl-label>
<input cnslInput formControlName="displayName" />
</cnsl-form-field>
<cnsl-form-field>
<cnsl-label>{{ 'PROJECT.ROLE.GROUP' | translate }}</cnsl-label>
<input cnslInput formControlName="group" />
</cnsl-form-field>
</form>
@if (formGroup) {
<form class="role-detail-full-width" [formGroup]="formGroup" (ngSubmit)="submitForm()">
<cnsl-form-field>
<cnsl-label>{{ 'PROJECT.ROLE.KEY' | translate }}</cnsl-label>
<input cnslInput formControlName="key" />
</cnsl-form-field>
<cnsl-form-field>
<cnsl-label>{{ 'PROJECT.ROLE.DISPLAY_NAME' | translate }}</cnsl-label>
<input cnslInput formControlName="displayName" />
</cnsl-form-field>
<cnsl-form-field>
<cnsl-label>{{ 'PROJECT.ROLE.GROUP' | translate }}</cnsl-label>
<input cnslInput formControlName="group" />
</cnsl-form-field>
</form>
}
</div>
<div mat-dialog-actions class="action">
@@ -1,142 +1,137 @@
<cnsl-refresh-table
[showSelectionActionButton]="showSelectionActionButton"
*ngIf="projectId"
(refreshed)="refreshPage()"
[emitRefreshOnPreviousRoutes]="['/projects/' + projectId + '/roles/create']"
[selection]="selection"
[loading]="dataSource.loading$ | async"
[timestamp]="dataSource.viewTimestamp"
>
<ng-template cnslHasRole [hasRole]="['project.role.write:' + projectId, 'project.role.write']" actions>
<a
*ngIf="actionsVisible"
[disabled]="disabled"
[routerLink]="['/projects', projectId, 'roles', 'create']"
color="primary"
mat-raised-button
data-e2e="create-project-role-button"
>
<div class="cnsl-action-button">
<mat-icon data-e2e="add-new-role" class="icon">add</mat-icon>
<span>{{ 'ACTIONS.NEW' | translate }}</span>
<cnsl-action-keys (actionTriggered)="gotoRouterLink(['/projects', projectId, 'roles', 'create'])">
</cnsl-action-keys>
</div>
</a>
</ng-template>
<div class="table-wrapper">
<table [dataSource]="dataSource" mat-table class="table" matSort aria-label="Elements">
<ng-container matColumnDef="select">
<th mat-header-cell *matHeaderCellDef>
<div class="selection">
<mat-checkbox
[disabled]="disabled"
color="primary"
(change)="$event ? masterToggle() : null"
[checked]="isAnySelected() && isAllSelected()"
[indeterminate]="isAnySelected() && !isAllSelected()"
>
</mat-checkbox>
</div>
</th>
<td mat-cell *matCellDef="let row">
<div class="selection">
<mat-checkbox
color="primary"
[disabled]="disabled"
(click)="$event.stopPropagation()"
(change)="$event ? selection.toggle(row.key) : null"
[checked]="selection.isSelected(row.key)"
>
</mat-checkbox>
</div>
</td>
</ng-container>
<ng-container matColumnDef="key">
<th mat-header-cell *matHeaderCellDef>{{ 'PROJECT.ROLE.KEY' | translate }}</th>
<td class="pointer" (click)="openDetailDialog(role)" mat-cell *matCellDef="let role">
<div class="role-key">
<cnsl-project-role-chip [roleName]="role.key">{{ role.key }}</cnsl-project-role-chip>
</div>
</td>
</ng-container>
<ng-container matColumnDef="displayname">
<th mat-header-cell *matHeaderCellDef>{{ 'PROJECT.ROLE.DISPLAY_NAME' | translate }}</th>
<td class="pointer" (click)="openDetailDialog(role)" mat-cell *matCellDef="let role">{{ role.displayName }}</td>
</ng-container>
<ng-container matColumnDef="group">
<th mat-header-cell *matHeaderCellDef>{{ 'PROJECT.ROLE.GROUP' | translate }}</th>
<td mat-cell *matCellDef="let role" class="pointer">
<span
class="role state"
[ngClass]="{ 'no-selection': !selectionAllowed }"
*ngIf="role.group"
(click)="selectionAllowed ? groupMasterToggle(role.group) : openDetailDialog(role)"
[matTooltip]="selectionAllowed ? ('PROJECT.ROLE.SELECTGROUPTOOLTIP' | translate: role) : null"
>{{ role.group }}</span
>
</td>
</ng-container>
<ng-container matColumnDef="creationDate">
<th mat-header-cell *matHeaderCellDef>{{ 'PROJECT.ROLE.CREATIONDATE' | translate }}</th>
<td class="pointer" (click)="openDetailDialog(role)" mat-cell *matCellDef="let role">
<span *ngIf="role?.details?.creationDate">{{
role.details.creationDate | timestampToDate | localizedDate: 'dd. MMM, HH:mm'
}}</span>
</td>
</ng-container>
<ng-container matColumnDef="changeDate">
<th mat-header-cell *matHeaderCellDef>{{ 'PROJECT.ROLE.CHANGEDATE' | translate }}</th>
<td class="pointer" (click)="openDetailDialog(role)" mat-cell *matCellDef="let role">
<span *ngIf="role?.details?.changeDate">{{
role.details.changeDate | timestampToDate | localizedDate: 'dd. MMM, HH:mm'
}}</span>
</td>
</ng-container>
<ng-container matColumnDef="actions" stickyEnd>
<th mat-header-cell *matHeaderCellDef class="role-table-actions"></th>
<td mat-cell *matCellDef="let role" class="role-table-actions">
<cnsl-table-actions>
<button
actions
[disabled]="
disabled || (['project.role.delete', 'project.role.delete:' + projectId] | hasRole | async) === false
"
mat-icon-button
color="warn"
matTooltip="{{ 'ACTIONS.DELETE' | translate }}"
(click)="deleteRole(role)"
>
<i class="las la-trash"></i>
</button>
</cnsl-table-actions>
</td>
</ng-container>
<tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
<tr class="highlight" mat-row *matRowDef="let role; columns: displayedColumns"></tr>
</table>
</div>
<div *ngIf="(dataSource.loading$ | async) === false && !dataSource?.totalResult" class="no-content-row">
<i class="las la-exclamation"></i>
<span>{{ 'PROJECT.ROLE.EMPTY' | translate }}</span>
</div>
<cnsl-paginator
#paginator
@if (projectId) {
<cnsl-refresh-table
[showSelectionActionButton]="showSelectionActionButton"
(refreshed)="refreshPage()"
[emitRefreshOnPreviousRoutes]="['/projects/' + projectId + '/roles/create']"
[selection]="selection"
[loading]="dataSource.loading$ | async"
[timestamp]="dataSource.viewTimestamp"
[length]="dataSource.totalResult"
[pageSize]="INITIAL_PAGE_SIZE"
(page)="changePage()"
[pageSizeOptions]="[25, 50, 100, 250]"
>
</cnsl-paginator>
</cnsl-refresh-table>
<ng-template cnslHasRole [hasRole]="['project.role.write:' + projectId, 'project.role.write']" actions>
@if (actionsVisible) {
<a
[disabled]="disabled"
[routerLink]="['/projects', projectId, 'roles', 'create']"
color="primary"
mat-raised-button
data-e2e="create-project-role-button"
>
<div class="cnsl-action-button">
<mat-icon data-e2e="add-new-role" class="icon">add</mat-icon>
<span>{{ 'ACTIONS.NEW' | translate }}</span>
<cnsl-action-keys (actionTriggered)="gotoRouterLink(['/projects', projectId, 'roles', 'create'])">
</cnsl-action-keys>
</div>
</a>
}
</ng-template>
<div class="table-wrapper">
<table [dataSource]="dataSource" mat-table class="table" matSort aria-label="Elements">
<ng-container matColumnDef="select">
<th mat-header-cell *matHeaderCellDef>
<div class="selection">
<mat-checkbox
[disabled]="disabled"
color="primary"
(change)="$event ? masterToggle() : null"
[checked]="isAnySelected() && isAllSelected()"
[indeterminate]="isAnySelected() && !isAllSelected()"
>
</mat-checkbox>
</div>
</th>
<td mat-cell *matCellDef="let row">
<div class="selection">
<mat-checkbox
color="primary"
[disabled]="disabled"
(click)="$event.stopPropagation()"
(change)="$event ? selection.toggle(row.key) : null"
[checked]="selection.isSelected(row.key)"
>
</mat-checkbox>
</div>
</td>
</ng-container>
<ng-container matColumnDef="key">
<th mat-header-cell *matHeaderCellDef>{{ 'PROJECT.ROLE.KEY' | translate }}</th>
<td class="pointer" (click)="openDetailDialog(role)" mat-cell *matCellDef="let role">
<div class="role-key">
<cnsl-project-role-chip [roleName]="role.key">{{ role.key }}</cnsl-project-role-chip>
</div>
</td>
</ng-container>
<ng-container matColumnDef="displayname">
<th mat-header-cell *matHeaderCellDef>{{ 'PROJECT.ROLE.DISPLAY_NAME' | translate }}</th>
<td class="pointer" (click)="openDetailDialog(role)" mat-cell *matCellDef="let role">{{ role.displayName }}</td>
</ng-container>
<ng-container matColumnDef="group">
<th mat-header-cell *matHeaderCellDef>{{ 'PROJECT.ROLE.GROUP' | translate }}</th>
<td mat-cell *matCellDef="let role" class="pointer">
@if (role.group) {
<span
class="role state"
[ngClass]="{ 'no-selection': !selectionAllowed }"
(click)="selectionAllowed ? groupMasterToggle(role.group) : openDetailDialog(role)"
[matTooltip]="selectionAllowed ? ('PROJECT.ROLE.SELECTGROUPTOOLTIP' | translate: role) : null"
>{{ role.group }}</span
>
}
</td>
</ng-container>
<ng-container matColumnDef="creationDate">
<th mat-header-cell *matHeaderCellDef>{{ 'PROJECT.ROLE.CREATIONDATE' | translate }}</th>
<td class="pointer" (click)="openDetailDialog(role)" mat-cell *matCellDef="let role">
@if (role?.details?.creationDate) {
<span>{{ role.details.creationDate | timestampToDate | localizedDate: 'dd. MMM, HH:mm' }}</span>
}
</td>
</ng-container>
<ng-container matColumnDef="changeDate">
<th mat-header-cell *matHeaderCellDef>{{ 'PROJECT.ROLE.CHANGEDATE' | translate }}</th>
<td class="pointer" (click)="openDetailDialog(role)" mat-cell *matCellDef="let role">
@if (role?.details?.changeDate) {
<span>{{ role.details.changeDate | timestampToDate | localizedDate: 'dd. MMM, HH:mm' }}</span>
}
</td>
</ng-container>
<ng-container matColumnDef="actions" stickyEnd>
<th mat-header-cell *matHeaderCellDef class="role-table-actions"></th>
<td mat-cell *matCellDef="let role" class="role-table-actions">
<cnsl-table-actions>
<button
actions
[disabled]="
disabled || (['project.role.delete', 'project.role.delete:' + projectId] | hasRole | async) === false
"
mat-icon-button
color="warn"
matTooltip="{{ 'ACTIONS.DELETE' | translate }}"
(click)="deleteRole(role)"
>
<i class="las la-trash"></i>
</button>
</cnsl-table-actions>
</td>
</ng-container>
<tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
<tr class="highlight" mat-row *matRowDef="let role; columns: displayedColumns"></tr>
</table>
</div>
@if ((dataSource.loading$ | async) === false && !dataSource?.totalResult) {
<div class="no-content-row">
<i class="las la-exclamation"></i>
<span>{{ 'PROJECT.ROLE.EMPTY' | translate }}</span>
</div>
}
<cnsl-paginator
#paginator
[timestamp]="dataSource.viewTimestamp"
[length]="dataSource.totalResult"
[pageSize]="INITIAL_PAGE_SIZE"
(page)="changePage()"
[pageSizeOptions]="[25, 50, 100, 250]"
>
</cnsl-paginator>
</cnsl-refresh-table>
}
@@ -26,9 +26,11 @@
<cnsl-info-section class="auto-reg-info">
<p class="checkbox-desc">{{ 'IDP.OPTIONS.AUTOLINKING_DESC' | translate }}</p>
<mat-select formControlName="autoLinking">
<mat-option *ngFor="let linkingType of linkingTypes" [value]="linkingType">
{{ 'IDP.OPTIONS.AUTOLINKINGTYPE.' + linkingType | translate }}
</mat-option>
@for (linkingType of linkingTypes; track linkingType) {
<mat-option [value]="linkingType">
{{ 'IDP.OPTIONS.AUTOLINKINGTYPE.' + linkingType | translate }}
</mat-option>
}
</mat-select>
</cnsl-info-section>
</form>
@@ -7,12 +7,16 @@
<div class="attribute-more-row">
<span>{{ 'ACTIONS.MORE' | translate }}</span>
<button (click)="showMore = !showMore" type="button" mat-icon-button>
<mat-icon *ngIf="showMore">keyboard_arrow_up</mat-icon>
<mat-icon *ngIf="!showMore">keyboard_arrow_down</mat-icon>
@if (showMore) {
<mat-icon>keyboard_arrow_up</mat-icon>
}
@if (!showMore) {
<mat-icon>keyboard_arrow_down</mat-icon>
}
</button>
</div>
<ng-container *ngIf="showMore">
@if (showMore) {
<cnsl-form-field class="formfield">
<cnsl-label>{{ 'IDP.AVATARURLATTRIBUTE' | translate }}</cnsl-label>
<input cnslInput formControlName="avatarUrlAttribute" />
@@ -61,5 +65,5 @@
<cnsl-label>{{ 'IDP.PROFILEATTRIBUTE' | translate }}</cnsl-label>
<input cnslInput formControlName="profileAttribute" />
</cnsl-form-field>
</ng-container>
}
</form>
@@ -7,15 +7,18 @@
<img class="idp-logo apple dark" src="./assets/images/idp/apple-dark.svg" alt="apple" />
<img class="idp-logo apple light" src="./assets/images/idp/apple.svg" alt="apple" />
<h1>{{ 'IDP.CREATE.APPLE.TITLE' | translate }}</h1>
<ng-container *ngIf="exists$ | async">
<div
*ngIf="{ isNotActive: (activateLink$ | async) } as idp"
class="cnsl-state-dot"
[matTooltip]="(idp.isNotActive ? 'IDP.STATES.2' : 'IDP.STATES.1') | translate"
[ngClass]="{ active: !idp.isNotActive, inactive: !!idp.isNotActive }"
></div>
</ng-container>
<mat-spinner diameter="25" *ngIf="loading" color="primary"></mat-spinner>
@if (exists$ | async) {
@if ({ isNotActive: (activateLink$ | async) }; as idp) {
<div
class="cnsl-state-dot"
[matTooltip]="(idp.isNotActive ? 'IDP.STATES.2' : 'IDP.STATES.1') | translate"
[ngClass]="{ active: !idp.isNotActive, inactive: !!idp.isNotActive }"
></div>
}
}
@if (loading) {
<mat-spinner diameter="25" color="primary"></mat-spinner>
}
</div>
<cnsl-provider-next
@@ -51,18 +54,19 @@
<input cnslInput formControlName="keyId" />
</cnsl-form-field>
<mat-checkbox
class="update-secret-checkbox"
*ngIf="provider"
[(ngModel)]="updatePrivateKey"
[ngModelOptions]="{ standalone: true }"
>{{ 'IDP.APPLE.UPDATEPRIVATEKEY' | translate }}</mat-checkbox
>
@if (provider) {
<mat-checkbox
class="update-secret-checkbox"
[(ngModel)]="updatePrivateKey"
[ngModelOptions]="{ standalone: true }"
>{{ 'IDP.APPLE.UPDATEPRIVATEKEY' | translate }}</mat-checkbox
>
}
<ng-container *ngIf="!provider || (provider && updatePrivateKey)">
@if (!provider || (provider && updatePrivateKey)) {
<span class="pk-label cnsl-secondary-text">{{ 'IDP.APPLE.PRIVATEKEY' | translate }}</span>
<div class="private-key-wrapper">
<ng-container *ngIf="privateKey?.value; else addLogoButton">
@if (privateKey?.value) {
<i class="las la-file"></i>
<button
class="dl-btn"
@@ -73,8 +77,7 @@
>
<i class="las la-trash"></i>
</button>
</ng-container>
<ng-template #addLogoButton>
} @else {
<input
#keyFileInput
style="display: none"
@@ -91,56 +94,60 @@
>
<mat-icon>add</mat-icon>
</button>
</ng-template>
}
</div>
</ng-container>
}
<div class="identity-provider-optional-h-wrapper">
<h2>{{ 'IDP.OPTIONAL' | translate }}</h2>
<button (click)="showOptional = !showOptional" type="button" mat-icon-button>
<mat-icon *ngIf="showOptional">keyboard_arrow_up</mat-icon
><mat-icon *ngIf="!showOptional">keyboard_arrow_down</mat-icon>
@if (showOptional) {
<mat-icon>keyboard_arrow_up</mat-icon>
}
@if (!showOptional) {
<mat-icon>keyboard_arrow_down</mat-icon>
}
</button>
</div>
<div *ngIf="showOptional">
<div class="idp-scopes">
<div class="flex-line">
@if (showOptional) {
<div>
<div class="idp-scopes">
<div class="flex-line">
<cnsl-form-field class="formfield">
<cnsl-label>{{ 'IDP.SCOPESLIST' | translate }}</cnsl-label>
<input
cnslInput
[matChipInputFor]="chipScopesList"
[matChipInputSeparatorKeyCodes]="separatorKeysCodes"
[matChipInputAddOnBlur]="true"
(matChipInputTokenEnd)="addScope($event)"
/>
</cnsl-form-field>
<button class="scope-add-button" (click)="addScope($any($event))" mat-icon-button>
<mat-icon>add</mat-icon>
</button>
</div>
<cnsl-form-field class="formfield">
<cnsl-label>{{ 'IDP.SCOPESLIST' | translate }}</cnsl-label>
<input
cnslInput
[matChipInputFor]="chipScopesList"
[matChipInputSeparatorKeyCodes]="separatorKeysCodes"
[matChipInputAddOnBlur]="true"
(matChipInputTokenEnd)="addScope($event)"
/>
<mat-chip-grid #chipScopesList aria-label="scope selection">
@for (scope of scopesList?.value; track scope) {
<mat-chip-row class="chip" removable (removed)="removeScope(scope)">
{{ scope }} <mat-icon matChipRemove>cancel</mat-icon>
</mat-chip-row>
}
</mat-chip-grid>
</cnsl-form-field>
<button class="scope-add-button" (click)="addScope($any($event))" mat-icon-button>
<mat-icon>add</mat-icon>
</button>
</div>
<cnsl-form-field class="formfield">
<mat-chip-grid #chipScopesList aria-label="scope selection">
<mat-chip-row class="chip" *ngFor="let scope of scopesList?.value" removable (removed)="removeScope(scope)">
{{ scope }} <mat-icon matChipRemove>cancel</mat-icon>
</mat-chip-row>
</mat-chip-grid>
<cnsl-label>{{ 'IDP.NAME' | translate }}</cnsl-label>
<input cnslInput formControlName="name" />
<span class="name-hint cnsl-secondary-text" cnslHint>{{ 'IDP.NAMEHINT' | translate }}</span>
</cnsl-form-field>
<cnsl-provider-options
[initialOptions]="provider?.config?.options"
(optionsChanged)="options = $event"
></cnsl-provider-options>
</div>
<cnsl-form-field class="formfield">
<cnsl-label>{{ 'IDP.NAME' | translate }}</cnsl-label>
<input cnslInput formControlName="name" />
<span class="name-hint cnsl-secondary-text" cnslHint>{{ 'IDP.NAMEHINT' | translate }}</span>
</cnsl-form-field>
<cnsl-provider-options
[initialOptions]="provider?.config?.options"
(optionsChanged)="options = $event"
></cnsl-provider-options>
</div>
}
</div>
<div class="identity-provider-create-actions">
@@ -151,9 +158,9 @@
[disabled]="form.invalid || form.disabled"
type="submit"
>
<span *ngIf="{ exists: (exists$ | async) } as idp">{{
(!!idp.exists ? 'ACTIONS.SAVE' : 'ACTIONS.CREATE') | translate
}}</span>
@if ({ exists: (exists$ | async) }; as idp) {
<span>{{ (!!idp.exists ? 'ACTIONS.SAVE' : 'ACTIONS.CREATE') | translate }}</span>
}
</button>
</div>
</form>

Some files were not shown because too many files have changed in this diff Show More