mirror of
https://github.com/zitadel/zitadel.git
synced 2025-12-13 16:53:05 +00:00
feat(console-v2): login policy extension, domain policy, filter and UI fixes (#3644)
* show filter count when set * toast contrast color * fix notification settings, password dialog * app-create, user-create layout * domain policy * login-policy, project grid loader, i18n * login policy * login policy save lifetimes * private labeling optim * granted project grantId * smtp address matching * i18n * i18n * i18n * replace url strategy * fix privatelabeling color picker saving * stylelint Co-authored-by: Livio Amstutz <livio.a@gmail.com>
This commit is contained in:
@@ -8,6 +8,7 @@ import { Breadcrumb, BreadcrumbService, BreadcrumbType } from 'src/app/services/
|
||||
import {
|
||||
BRANDING,
|
||||
COMPLEXITY,
|
||||
DOMAIN,
|
||||
GENERAL,
|
||||
IDP,
|
||||
LOCKOUT,
|
||||
@@ -31,12 +32,14 @@ export class InstanceSettingsComponent {
|
||||
public settingsList: SidenavSetting[] = [
|
||||
GENERAL,
|
||||
// notifications
|
||||
{ showWarn: true, ...NOTIFICATIONS },
|
||||
// { showWarn: true, ...NOTIFICATIONS },
|
||||
NOTIFICATIONS,
|
||||
// login
|
||||
LOGIN,
|
||||
COMPLEXITY,
|
||||
LOCKOUT,
|
||||
IDP,
|
||||
DOMAIN,
|
||||
// appearance
|
||||
BRANDING,
|
||||
MESSAGETEXTS,
|
||||
|
||||
@@ -8,6 +8,7 @@ import { Breadcrumb, BreadcrumbService, BreadcrumbType } from 'src/app/services/
|
||||
import {
|
||||
BRANDING,
|
||||
COMPLEXITY,
|
||||
DOMAIN,
|
||||
IDP,
|
||||
LOCKOUT,
|
||||
LOGIN,
|
||||
@@ -29,6 +30,7 @@ export class OrgSettingsComponent {
|
||||
COMPLEXITY,
|
||||
LOCKOUT,
|
||||
IDP,
|
||||
DOMAIN,
|
||||
BRANDING,
|
||||
MESSAGETEXTS,
|
||||
LOGINTEXTS,
|
||||
|
||||
@@ -1,275 +1,349 @@
|
||||
<div class="app-create-container">
|
||||
<div class="abort-container">
|
||||
<button (click)="close()" mat-icon-button>
|
||||
<mat-icon>close</mat-icon>
|
||||
</button>
|
||||
<span class="abort">{{ 'APP.PAGES.CREATE_OIDC' | translate }}</span>
|
||||
</div>
|
||||
<div class="max-width-container">
|
||||
<div class="enlarged-container">
|
||||
<div class="abort-container">
|
||||
<button (click)="close()" mat-icon-button>
|
||||
<mat-icon>close</mat-icon>
|
||||
</button>
|
||||
<span class="abort">{{ 'APP.PAGES.CREATE_OIDC' | translate }}</span
|
||||
><span class="abort-2">Step {{ currentCreateStep }} of {{ createSteps }}</span>
|
||||
</div>
|
||||
|
||||
<h1>{{'APP.PAGES.CREATE_OIDC_DESC_TITLE' | translate}}</h1>
|
||||
<p class="desc cnsl-secondary-text">{{'APP.PAGES.CREATE_OIDC_DESC_SUB' | translate}}</p>
|
||||
<div class="app-create-content">
|
||||
<h1>{{ 'APP.PAGES.CREATE_OIDC_DESC_TITLE' | translate }}</h1>
|
||||
<mat-progress-bar class="progress-bar" color="primary" *ngIf="loading" mode="indeterminate"></mat-progress-bar>
|
||||
|
||||
<mat-progress-bar class="progress-bar" color="primary" *ngIf="loading" mode="indeterminate"></mat-progress-bar>
|
||||
<mat-checkbox class="proswitch" color="primary" [(ngModel)]="devmode">
|
||||
{{ 'APP.OIDC.PROSWITCH' | translate }}
|
||||
</mat-checkbox>
|
||||
|
||||
<mat-checkbox class="proswitch" color="primary" [(ngModel)]="devmode">
|
||||
{{'APP.OIDC.PROSWITCH' | translate}}
|
||||
</mat-checkbox>
|
||||
<mat-horizontal-stepper
|
||||
class="stepper"
|
||||
*ngIf="!devmode"
|
||||
linear
|
||||
#stepper
|
||||
labelPosition="bottom"
|
||||
(selectionChange)="changeStep($event)"
|
||||
>
|
||||
<mat-step [stepControl]="firstFormGroup" [editable]="true">
|
||||
<form [formGroup]="firstFormGroup">
|
||||
<ng-template matStepLabel>{{ 'APP.OIDC.NAMEANDTYPESECTION' | translate }}</ng-template>
|
||||
|
||||
<mat-horizontal-stepper class="stepper" *ngIf="!devmode" linear #stepper labelPosition="bottom"
|
||||
(selectionChange)="changeStep($event)">
|
||||
<mat-step [stepControl]="firstFormGroup" [editable]="true">
|
||||
<form [formGroup]="firstFormGroup">
|
||||
<ng-template matStepLabel>{{'APP.OIDC.NAMEANDTYPESECTION' | translate}}</ng-template>
|
||||
<p class="step-title">{{ 'APP.OIDC.TITLEFIRST' | translate }}</p>
|
||||
<cnsl-form-field appearance="outline" class="name-formfield">
|
||||
<cnsl-label>{{ 'APP.NAME' | translate }}</cnsl-label>
|
||||
<input cnslInput cdkFocusInitial formControlName="name" />
|
||||
<span cnslError *ngIf="name?.errors?.required">{{ 'PROJECT.APP.NAMEREQUIRED' | translate }}</span>
|
||||
</cnsl-form-field>
|
||||
|
||||
<p class="step-title">{{'APP.OIDC.TITLEFIRST' | translate}}</p>
|
||||
<cnsl-form-field appearance="outline" class="formfield">
|
||||
<cnsl-label>{{ 'APP.NAME' | translate }}</cnsl-label>
|
||||
<input cnslInput cdkFocusInitial formControlName="name" />
|
||||
<span cnslError *ngIf="name?.errors?.required">{{'PROJECT.APP.NAMEREQUIRED' | translate}}</span>
|
||||
</cnsl-form-field>
|
||||
<p class="step-title">{{ 'APP.OIDC.TYPETITLE' | translate }}</p>
|
||||
|
||||
<p class="step-title">{{'APP.OIDC.TYPETITLE' | translate}}</p>
|
||||
<cnsl-type-radio [types]="appTypes" (selectedType)="appType?.setValue($event)" [selected]="appType?.value">
|
||||
</cnsl-type-radio>
|
||||
<div class="app-create-actions">
|
||||
<button
|
||||
mat-raised-button
|
||||
[disabled]="firstFormGroup.invalid"
|
||||
color="primary"
|
||||
matStepperNext
|
||||
[attr.data-e2e]="'continue-button-nameandtype'"
|
||||
>
|
||||
{{ 'ACTIONS.CONTINUE' | translate }}
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
</mat-step>
|
||||
|
||||
<cnsl-type-radio [types]="appTypes" (selectedType)="appType?.setValue($event)" [selected]="appType?.value">
|
||||
</cnsl-type-radio>
|
||||
<div class="app-create-actions">
|
||||
<span class="fill-space"></span>
|
||||
<button mat-raised-button [disabled]="firstFormGroup.invalid" color="primary" matStepperNext
|
||||
[attr.data-e2e]="'continue-button-nameandtype'">{{'ACTIONS.CONTINUE' | translate}}</button>
|
||||
</div>
|
||||
</form>
|
||||
</mat-step>
|
||||
<!-- skip for native applications -->
|
||||
<mat-step
|
||||
*ngIf="oidcAppRequest.appType !== OIDCAppType.OIDC_APP_TYPE_NATIVE"
|
||||
[stepControl]="secondFormGroup"
|
||||
[editable]="true"
|
||||
>
|
||||
<form [formGroup]="secondFormGroup">
|
||||
<ng-template matStepLabel>{{ 'APP.AUTHMETHODSECTION' | translate }}</ng-template>
|
||||
|
||||
<!-- skip for native applications -->
|
||||
<mat-step *ngIf="oidcAppRequest.appType !== OIDCAppType.OIDC_APP_TYPE_NATIVE" [stepControl]="secondFormGroup"
|
||||
[editable]="true">
|
||||
<form [formGroup]="secondFormGroup">
|
||||
<ng-template matStepLabel>{{'APP.AUTHMETHODSECTION' | translate}}</ng-template>
|
||||
<cnsl-auth-method-radio
|
||||
[authMethods]="authMethods"
|
||||
[selected]="authMethod?.value"
|
||||
[isOIDC]="appType?.value?.createType === AppCreateType.OIDC"
|
||||
(selectedMethod)="authMethod?.setValue($event)"
|
||||
>
|
||||
</cnsl-auth-method-radio>
|
||||
|
||||
<cnsl-auth-method-radio [authMethods]="authMethods" [selected]="authMethod?.value"
|
||||
[isOIDC]="appType?.value?.createType === AppCreateType.OIDC" (selectedMethod)="authMethod?.setValue($event)">
|
||||
</cnsl-auth-method-radio>
|
||||
<div class="app-create-actions">
|
||||
<button class="bck-button" mat-stroked-button matStepperPrevious>{{ 'ACTIONS.BACK' | translate }}</button>
|
||||
<button
|
||||
mat-raised-button
|
||||
color="primary"
|
||||
[disabled]="secondFormGroup.invalid"
|
||||
matStepperNext
|
||||
[attr.data-e2e]="'continue-button-authmethod'"
|
||||
>
|
||||
{{ 'ACTIONS.CONTINUE' | translate }}
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
</mat-step>
|
||||
|
||||
<div class="app-create-actions">
|
||||
<button mat-stroked-button color="primary" matStepperPrevious>{{'ACTIONS.BACK' |
|
||||
translate}}</button>
|
||||
<span class="fill-space"></span>
|
||||
<button mat-raised-button color="primary" [disabled]="secondFormGroup.invalid" matStepperNext
|
||||
[attr.data-e2e]="'continue-button-authmethod'">{{'ACTIONS.CONTINUE' | translate}}</button>
|
||||
</div>
|
||||
</form>
|
||||
</mat-step>
|
||||
<!-- show redirect step only for OIDC apps -->
|
||||
<mat-step *ngIf="appType?.value?.createType === AppCreateType.OIDC" [editable]="true">
|
||||
<ng-template matStepLabel>{{ 'APP.OIDC.REDIRECTSECTION' | translate }}</ng-template>
|
||||
|
||||
<!-- show redirect step only for OIDC apps -->
|
||||
<mat-step *ngIf="appType?.value?.createType === AppCreateType.OIDC" [editable]="true">
|
||||
<ng-template matStepLabel>{{'APP.OIDC.REDIRECTSECTION' | translate}}</ng-template>
|
||||
<p class="step-title">{{ 'APP.OIDC.REDIRECTTITLE' | translate }}</p>
|
||||
<p
|
||||
class="step-description cnsl-secondary-text"
|
||||
*ngIf="oidcAppRequest.appType === OIDCAppType.OIDC_APP_TYPE_NATIVE"
|
||||
>
|
||||
{{ 'APP.OIDC.REDIRECTDESCRIPTIONNATIVE' | translate }}
|
||||
</p>
|
||||
<p class="step-description cnsl-secondary-text" *ngIf="oidcAppRequest.appType === OIDCAppType.OIDC_APP_TYPE_WEB">
|
||||
{{ 'APP.OIDC.REDIRECTDESCRIPTIONWEB' | translate }}
|
||||
</p>
|
||||
|
||||
<p class="step-title">{{'APP.OIDC.REDIRECTTITLE' | translate}}</p>
|
||||
<p class="step-description cnsl-secondary-text"
|
||||
*ngIf="oidcAppRequest.appType === OIDCAppType.OIDC_APP_TYPE_NATIVE">
|
||||
{{'APP.OIDC.REDIRECTDESCRIPTIONNATIVE' | translate}}</p>
|
||||
<p class="step-description cnsl-secondary-text" *ngIf="oidcAppRequest.appType === OIDCAppType.OIDC_APP_TYPE_WEB">
|
||||
{{'APP.OIDC.REDIRECTDESCRIPTIONWEB' | translate}}</p>
|
||||
|
||||
<cnsl-redirect-uris class="redirect-section" [canWrite]="true"
|
||||
[isNative]="oidcAppRequest.appType === OIDCAppType.OIDC_APP_TYPE_NATIVE"
|
||||
(changedUris)="oidcAppRequest.redirectUrisList = $any($event)" [urisList]="oidcAppRequest.redirectUrisList"
|
||||
[getValues]="requestRedirectValuesSubject$" title="{{ 'APP.OIDC.REDIRECT' | translate }}">
|
||||
</cnsl-redirect-uris>
|
||||
|
||||
<p class="step-title">{{'APP.OIDC.POSTREDIRECTTITLE' | translate}}</p>
|
||||
<p class="step-description cnsl-secondary-text"
|
||||
*ngIf="oidcAppRequest.appType === OIDCAppType.OIDC_APP_TYPE_NATIVE">
|
||||
{{'APP.OIDC.REDIRECTDESCRIPTIONNATIVE' | translate}}</p>
|
||||
<p class="step-description cnsl-secondary-text"
|
||||
*ngIf="oidcAppRequest.appType === OIDCAppType.OIDC_APP_TYPE_WEB || oidcAppRequest.appType === OIDCAppType.OIDC_APP_TYPE_USER_AGENT">
|
||||
{{'APP.OIDC.REDIRECTDESCRIPTIONWEB' | translate}}</p>
|
||||
|
||||
<cnsl-redirect-uris class="redirect-section" [canWrite]="true"
|
||||
(changedUris)="oidcAppRequest.postLogoutRedirectUrisList = $any($event)"
|
||||
[urisList]="oidcAppRequest.postLogoutRedirectUrisList" title="{{ 'APP.OIDC.POSTLOGOUTREDIRECT' | translate }}"
|
||||
[getValues]="requestRedirectValuesSubject$"
|
||||
[isNative]="oidcAppRequest.appType === OIDCAppType.OIDC_APP_TYPE_NATIVE">
|
||||
</cnsl-redirect-uris>
|
||||
|
||||
<div class="app-create-actions">
|
||||
<button mat-stroked-button color="primary" matStepperPrevious>{{'ACTIONS.BACK' | translate}}</button>
|
||||
<span class="fill-space"></span>
|
||||
<button mat-raised-button color="primary" matStepperNext
|
||||
[attr.data-e2e]="'continue-button-redirecturis'">{{'ACTIONS.CONTINUE' | translate}}</button>
|
||||
</div>
|
||||
</mat-step>
|
||||
|
||||
|
||||
<mat-step>
|
||||
<ng-template matStepLabel>{{'APP.OIDC.OVERVIEWSECTION'| translate}}</ng-template>
|
||||
<p class="step-title">{{'APP.OIDC.OVERVIEWTITLE' | translate}}</p>
|
||||
<div class="row cnsl-secondary-text">
|
||||
<span class="left">
|
||||
{{ 'APP.NAME' | translate }}
|
||||
</span>
|
||||
<span class="right">
|
||||
{{oidcAppRequest.name}}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<ng-container *ngIf="appType?.value?.createType === AppCreateType.OIDC">
|
||||
<div class="row cnsl-secondary-text">
|
||||
<span class="left">
|
||||
{{ 'APP.TYPE' | translate }}
|
||||
</span>
|
||||
<span class="right">
|
||||
{{'APP.OIDC.APPTYPE.'+oidcAppRequest.appType | translate}}
|
||||
</span>
|
||||
</div>
|
||||
<div class="row cnsl-secondary-text">
|
||||
<span class="left">
|
||||
{{ 'APP.GRANT' | translate }}
|
||||
</span>
|
||||
<span class="right" *ngIf="oidcAppRequest.grantTypesList && oidcAppRequest.grantTypesList.length > 0">
|
||||
[<span *ngFor="let element of oidcAppRequest.grantTypesList; index as i">
|
||||
{{'APP.OIDC.GRANT.'+element | translate}}
|
||||
{{i < oidcAppRequest.grantTypesList.length - 1 ? ', ' : '' }} </span>]
|
||||
</span>
|
||||
</div>
|
||||
<div class="row cnsl-secondary-text">
|
||||
<span class="left">
|
||||
{{ 'APP.OIDC.RESPONSETYPE' | translate }}
|
||||
</span>
|
||||
<span class="right" *ngIf="oidcAppRequest.responseTypesList && oidcAppRequest.responseTypesList.length > 0">
|
||||
[<span *ngFor="let element of oidcAppRequest.responseTypesList; index as i">
|
||||
{{('APP.OIDC.RESPONSE.'+element | translate)}}
|
||||
{{i < oidcAppRequest.responseTypesList.length - 1 ? ', ' : '' }} </span>]
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div class="row cnsl-secondary-text">
|
||||
<span class="left">
|
||||
{{ 'APP.AUTHMETHOD' | translate }}
|
||||
</span>
|
||||
<span class="right">
|
||||
<span>
|
||||
{{'APP.OIDC.AUTHMETHOD.'+oidcAppRequest?.authMethodType | translate}}
|
||||
</span>
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div class="row cnsl-secondary-text">
|
||||
<span class="left">
|
||||
{{ 'APP.OIDC.REDIRECT' | translate }}
|
||||
</span>
|
||||
<span class="right" *ngIf="oidcAppRequest.redirectUrisList && oidcAppRequest.redirectUrisList.length > 0">
|
||||
[<span *ngFor="let redirect of oidcAppRequest.redirectUrisList; index as i">
|
||||
{{redirect}}
|
||||
{{i < oidcAppRequest.redirectUrisList.length - 1 ? ', ' : '' }} </span>]
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div class="row cnsl-secondary-text">
|
||||
<span class="left">
|
||||
{{ 'APP.OIDC.POSTLOGOUTREDIRECT' | translate }}
|
||||
</span>
|
||||
<span class="right"
|
||||
*ngIf="oidcAppRequest.postLogoutRedirectUrisList && oidcAppRequest.postLogoutRedirectUrisList.length > 0">
|
||||
[<span *ngFor="let redirect of oidcAppRequest.postLogoutRedirectUrisList; index as i">
|
||||
{{redirect}}
|
||||
{{i < oidcAppRequest.postLogoutRedirectUrisList.length - 1 ? ', ' : '' }} </span>]
|
||||
</span>
|
||||
</div>
|
||||
</ng-container>
|
||||
|
||||
<ng-container *ngIf="appType?.value?.createType === AppCreateType.API">
|
||||
<div class="row cnsl-secondary-text">
|
||||
<span class="left">
|
||||
{{ 'APP.AUTHMETHOD' | translate }}
|
||||
</span>
|
||||
<span class="right">
|
||||
<span>
|
||||
{{'APP.API.AUTHMETHOD.'+apiAppRequest?.authMethodType | translate}}
|
||||
</span>
|
||||
</span>
|
||||
</div>
|
||||
</ng-container>
|
||||
|
||||
<div class="app-create-actions">
|
||||
<button mat-stroked-button color="primary" matStepperPrevious>{{'ACTIONS.BACK' | translate}}</button>
|
||||
<span class="fill-space"></span>
|
||||
<button mat-raised-button color="primary" (click)="createApp()"
|
||||
[attr.data-e2e]="'create-button'">{{'ACTIONS.CREATE' |
|
||||
translate}}</button>
|
||||
</div>
|
||||
</mat-step>
|
||||
</mat-horizontal-stepper>
|
||||
|
||||
<div *ngIf="devmode" class="dev">
|
||||
<form [formGroup]="form" (ngSubmit)="createApp()" [attr.data-e2e]="'create-app-wizzard-3'">
|
||||
<div class="content">
|
||||
<cnsl-form-field appearance="outline" class="formfield">
|
||||
<cnsl-label>{{ 'APP.NAME' | translate }}</cnsl-label>
|
||||
<input cnslInput formControlName="name" />
|
||||
</cnsl-form-field>
|
||||
|
||||
<cnsl-form-field appearance="outline" class="formfield">
|
||||
<cnsl-label>{{ 'APP.TYPE' | translate }}</cnsl-label>
|
||||
<mat-select formControlName="appType">
|
||||
<mat-option *ngFor="let appType of appTypes" [value]="appType">
|
||||
{{ appType.titleI18nKey | translate }}
|
||||
</mat-option>
|
||||
</mat-select>
|
||||
</cnsl-form-field>
|
||||
|
||||
<ng-container *ngIf="formappType?.value?.createType === AppCreateType.OIDC">
|
||||
<cnsl-form-field appearance="outline" class="formfield">
|
||||
<cnsl-label>{{ 'APP.OIDC.GRANTTYPE' | translate }}</cnsl-label>
|
||||
<mat-select formControlName="grantTypesList" multiple>
|
||||
<mat-option *ngFor="let grant of oidcGrantTypes" [value]="grant.type">
|
||||
{{ ('APP.OIDC.GRANT.' + grant.type) | translate }}
|
||||
</mat-option>
|
||||
</mat-select>
|
||||
</cnsl-form-field>
|
||||
|
||||
<cnsl-form-field appearance="outline" class="formfield">
|
||||
<cnsl-label>{{ 'APP.OIDC.RESPONSETYPE' | translate }}</cnsl-label>
|
||||
<mat-select formControlName="responseTypesList" multiple>
|
||||
<mat-option *ngFor="let type of oidcResponseTypes" [value]="type.type">
|
||||
{{ 'APP.OIDC.RESPONSE.'+type.type | translate }}
|
||||
</mat-option>
|
||||
</mat-select>
|
||||
</cnsl-form-field>
|
||||
</ng-container>
|
||||
|
||||
<cnsl-form-field appearance="outline" class="formfield">
|
||||
<cnsl-label>{{ 'APP.AUTHMETHOD' | translate }}</cnsl-label>
|
||||
<mat-select formControlName="authMethodType">
|
||||
<mat-option *ngFor="let type of authMethodTypes" [value]="type.type">
|
||||
<span *ngIf="type.oidc">{{ 'APP.OIDC.AUTHMETHOD.'+type.type | translate }}</span>
|
||||
<span *ngIf="type.api">{{ 'APP.API.AUTHMETHOD.'+type.type | translate }}</span>
|
||||
</mat-option>
|
||||
</mat-select>
|
||||
</cnsl-form-field>
|
||||
</div>
|
||||
|
||||
<div class="content" *ngIf="formappType?.value?.createType === AppCreateType.OIDC">
|
||||
<div class="formfield full-width">
|
||||
<cnsl-redirect-uris class="redirect-section" [canWrite]="true"
|
||||
(changedUris)="oidcAppRequest.redirectUrisList = $any($event)" [urisList]="oidcAppRequest.redirectUrisList"
|
||||
title="{{ 'APP.OIDC.REDIRECT' | translate }}" [getValues]="requestRedirectValuesSubject$"
|
||||
[isNative]="oidcAppRequest.appType === OIDCAppType.OIDC_APP_TYPE_NATIVE">
|
||||
<cnsl-redirect-uris
|
||||
class="redirect-section"
|
||||
[canWrite]="true"
|
||||
[isNative]="oidcAppRequest.appType === OIDCAppType.OIDC_APP_TYPE_NATIVE"
|
||||
(changedUris)="oidcAppRequest.redirectUrisList = $any($event)"
|
||||
[urisList]="oidcAppRequest.redirectUrisList"
|
||||
[getValues]="requestRedirectValuesSubject$"
|
||||
title="{{ 'APP.OIDC.REDIRECT' | translate }}"
|
||||
>
|
||||
</cnsl-redirect-uris>
|
||||
|
||||
<cnsl-redirect-uris class="redirect-section" [canWrite]="true"
|
||||
<p class="step-title">{{ 'APP.OIDC.POSTREDIRECTTITLE' | translate }}</p>
|
||||
<p
|
||||
class="step-description cnsl-secondary-text"
|
||||
*ngIf="oidcAppRequest.appType === OIDCAppType.OIDC_APP_TYPE_NATIVE"
|
||||
>
|
||||
{{ 'APP.OIDC.REDIRECTDESCRIPTIONNATIVE' | translate }}
|
||||
</p>
|
||||
<p
|
||||
class="step-description cnsl-secondary-text"
|
||||
*ngIf="
|
||||
oidcAppRequest.appType === OIDCAppType.OIDC_APP_TYPE_WEB ||
|
||||
oidcAppRequest.appType === OIDCAppType.OIDC_APP_TYPE_USER_AGENT
|
||||
"
|
||||
>
|
||||
{{ 'APP.OIDC.REDIRECTDESCRIPTIONWEB' | translate }}
|
||||
</p>
|
||||
|
||||
<cnsl-redirect-uris
|
||||
class="redirect-section"
|
||||
[canWrite]="true"
|
||||
(changedUris)="oidcAppRequest.postLogoutRedirectUrisList = $any($event)"
|
||||
[urisList]="oidcAppRequest.postLogoutRedirectUrisList"
|
||||
title="{{ 'APP.OIDC.POSTLOGOUTREDIRECT' | translate }}" [getValues]="requestRedirectValuesSubject$"
|
||||
[isNative]="oidcAppRequest.appType === OIDCAppType.OIDC_APP_TYPE_NATIVE">
|
||||
title="{{ 'APP.OIDC.POSTLOGOUTREDIRECT' | translate }}"
|
||||
[getValues]="requestRedirectValuesSubject$"
|
||||
[isNative]="oidcAppRequest.appType === OIDCAppType.OIDC_APP_TYPE_NATIVE"
|
||||
>
|
||||
</cnsl-redirect-uris>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<button color="primary" mat-raised-button class="continue-button" [disabled]="form.invalid" cdkFocusInitial
|
||||
type="submit">
|
||||
{{ 'ACTIONS.SAVE' | translate }}
|
||||
</button>
|
||||
</form>
|
||||
<div class="app-create-actions">
|
||||
<button mat-stroked-button class="bck-button" matStepperPrevious>{{ 'ACTIONS.BACK' | translate }}</button>
|
||||
<button mat-raised-button color="primary" matStepperNext [attr.data-e2e]="'continue-button-redirecturis'">
|
||||
{{ 'ACTIONS.CONTINUE' | translate }}
|
||||
</button>
|
||||
</div>
|
||||
</mat-step>
|
||||
|
||||
<mat-step>
|
||||
<ng-template matStepLabel>{{ 'APP.OIDC.OVERVIEWSECTION' | translate }}</ng-template>
|
||||
<p class="step-title">{{ 'APP.OIDC.OVERVIEWTITLE' | translate }}</p>
|
||||
<div class="row cnsl-secondary-text">
|
||||
<span class="left">
|
||||
{{ 'APP.NAME' | translate }}
|
||||
</span>
|
||||
<span class="right">
|
||||
{{ oidcAppRequest.name }}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<ng-container *ngIf="appType?.value?.createType === AppCreateType.OIDC">
|
||||
<div class="row cnsl-secondary-text">
|
||||
<span class="left">
|
||||
{{ 'APP.TYPE' | translate }}
|
||||
</span>
|
||||
<span class="right">
|
||||
{{ 'APP.OIDC.APPTYPE.' + oidcAppRequest.appType | translate }}
|
||||
</span>
|
||||
</div>
|
||||
<div class="row cnsl-secondary-text">
|
||||
<span class="left">
|
||||
{{ 'APP.GRANT' | translate }}
|
||||
</span>
|
||||
<span class="right" *ngIf="oidcAppRequest.grantTypesList && oidcAppRequest.grantTypesList.length > 0">
|
||||
[<span *ngFor="let element of oidcAppRequest.grantTypesList; index as i">
|
||||
{{ 'APP.OIDC.GRANT.' + element | translate }}
|
||||
{{ i < oidcAppRequest.grantTypesList.length - 1 ? ', ' : '' }} </span
|
||||
>]
|
||||
</span>
|
||||
</div>
|
||||
<div class="row cnsl-secondary-text">
|
||||
<span class="left">
|
||||
{{ 'APP.OIDC.RESPONSETYPE' | translate }}
|
||||
</span>
|
||||
<span class="right" *ngIf="oidcAppRequest.responseTypesList && oidcAppRequest.responseTypesList.length > 0">
|
||||
[<span *ngFor="let element of oidcAppRequest.responseTypesList; index as i">
|
||||
{{ 'APP.OIDC.RESPONSE.' + element | translate }}
|
||||
{{ i < oidcAppRequest.responseTypesList.length - 1 ? ', ' : '' }} </span
|
||||
>]
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div class="row cnsl-secondary-text">
|
||||
<span class="left">
|
||||
{{ 'APP.AUTHMETHOD' | translate }}
|
||||
</span>
|
||||
<span class="right">
|
||||
<span>
|
||||
{{ 'APP.OIDC.AUTHMETHOD.' + oidcAppRequest?.authMethodType | translate }}
|
||||
</span>
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div class="row cnsl-secondary-text">
|
||||
<span class="left">
|
||||
{{ 'APP.OIDC.REDIRECT' | translate }}
|
||||
</span>
|
||||
<span class="right" *ngIf="oidcAppRequest.redirectUrisList && oidcAppRequest.redirectUrisList.length > 0">
|
||||
[<span *ngFor="let redirect of oidcAppRequest.redirectUrisList; index as i">
|
||||
{{ redirect }}
|
||||
{{ i < oidcAppRequest.redirectUrisList.length - 1 ? ', ' : '' }} </span
|
||||
>]
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div class="row cnsl-secondary-text">
|
||||
<span class="left">
|
||||
{{ 'APP.OIDC.POSTLOGOUTREDIRECT' | translate }}
|
||||
</span>
|
||||
<span
|
||||
class="right"
|
||||
*ngIf="oidcAppRequest.postLogoutRedirectUrisList && oidcAppRequest.postLogoutRedirectUrisList.length > 0"
|
||||
>
|
||||
[<span *ngFor="let redirect of oidcAppRequest.postLogoutRedirectUrisList; index as i">
|
||||
{{ redirect }}
|
||||
{{ i < oidcAppRequest.postLogoutRedirectUrisList.length - 1 ? ', ' : '' }} </span
|
||||
>]
|
||||
</span>
|
||||
</div>
|
||||
</ng-container>
|
||||
|
||||
<ng-container *ngIf="appType?.value?.createType === AppCreateType.API">
|
||||
<div class="row cnsl-secondary-text">
|
||||
<span class="left">
|
||||
{{ 'APP.AUTHMETHOD' | translate }}
|
||||
</span>
|
||||
<span class="right">
|
||||
<span>
|
||||
{{ 'APP.API.AUTHMETHOD.' + apiAppRequest?.authMethodType | translate }}
|
||||
</span>
|
||||
</span>
|
||||
</div>
|
||||
</ng-container>
|
||||
|
||||
<div class="app-create-actions">
|
||||
<button mat-stroked-button matStepperPrevious class="bck-button">{{ 'ACTIONS.BACK' | translate }}</button>
|
||||
<button
|
||||
mat-raised-button
|
||||
class="create-button"
|
||||
color="primary"
|
||||
(click)="createApp()"
|
||||
[attr.data-e2e]="'create-button'"
|
||||
>
|
||||
{{ 'ACTIONS.CREATE' | translate }}
|
||||
</button>
|
||||
</div>
|
||||
</mat-step>
|
||||
</mat-horizontal-stepper>
|
||||
|
||||
<div *ngIf="devmode" class="dev">
|
||||
<form [formGroup]="form" (ngSubmit)="createApp()" [attr.data-e2e]="'create-app-wizzard-3'">
|
||||
<div class="content">
|
||||
<cnsl-form-field appearance="outline" class="formfield">
|
||||
<cnsl-label>{{ 'APP.NAME' | translate }}</cnsl-label>
|
||||
<input cnslInput formControlName="name" />
|
||||
</cnsl-form-field>
|
||||
|
||||
<cnsl-form-field appearance="outline" class="formfield">
|
||||
<cnsl-label>{{ 'APP.TYPE' | translate }}</cnsl-label>
|
||||
<mat-select formControlName="appType">
|
||||
<mat-option *ngFor="let appType of appTypes" [value]="appType">
|
||||
{{ appType.titleI18nKey | translate }}
|
||||
</mat-option>
|
||||
</mat-select>
|
||||
</cnsl-form-field>
|
||||
|
||||
<ng-container *ngIf="formappType?.value?.createType === AppCreateType.OIDC">
|
||||
<cnsl-form-field appearance="outline" class="formfield">
|
||||
<cnsl-label>{{ 'APP.OIDC.GRANTTYPE' | translate }}</cnsl-label>
|
||||
<mat-select formControlName="grantTypesList" multiple>
|
||||
<mat-option *ngFor="let grant of oidcGrantTypes" [value]="grant.type">
|
||||
{{ 'APP.OIDC.GRANT.' + grant.type | translate }}
|
||||
</mat-option>
|
||||
</mat-select>
|
||||
</cnsl-form-field>
|
||||
|
||||
<cnsl-form-field appearance="outline" class="formfield">
|
||||
<cnsl-label>{{ 'APP.OIDC.RESPONSETYPE' | translate }}</cnsl-label>
|
||||
<mat-select formControlName="responseTypesList" multiple>
|
||||
<mat-option *ngFor="let type of oidcResponseTypes" [value]="type.type">
|
||||
{{ 'APP.OIDC.RESPONSE.' + type.type | translate }}
|
||||
</mat-option>
|
||||
</mat-select>
|
||||
</cnsl-form-field>
|
||||
</ng-container>
|
||||
|
||||
<cnsl-form-field appearance="outline" class="formfield">
|
||||
<cnsl-label>{{ 'APP.AUTHMETHOD' | translate }}</cnsl-label>
|
||||
<mat-select formControlName="authMethodType">
|
||||
<mat-option *ngFor="let type of authMethodTypes" [value]="type.type">
|
||||
<span *ngIf="type.oidc">{{ 'APP.OIDC.AUTHMETHOD.' + type.type | translate }}</span>
|
||||
<span *ngIf="type.api">{{ 'APP.API.AUTHMETHOD.' + type.type | translate }}</span>
|
||||
</mat-option>
|
||||
</mat-select>
|
||||
</cnsl-form-field>
|
||||
</div>
|
||||
|
||||
<div class="content" *ngIf="formappType?.value?.createType === AppCreateType.OIDC">
|
||||
<div class="formfield full-width">
|
||||
<cnsl-redirect-uris
|
||||
class="redirect-section"
|
||||
[canWrite]="true"
|
||||
(changedUris)="oidcAppRequest.redirectUrisList = $any($event)"
|
||||
[urisList]="oidcAppRequest.redirectUrisList"
|
||||
title="{{ 'APP.OIDC.REDIRECT' | translate }}"
|
||||
[getValues]="requestRedirectValuesSubject$"
|
||||
[isNative]="oidcAppRequest.appType === OIDCAppType.OIDC_APP_TYPE_NATIVE"
|
||||
>
|
||||
</cnsl-redirect-uris>
|
||||
|
||||
<cnsl-redirect-uris
|
||||
class="redirect-section"
|
||||
[canWrite]="true"
|
||||
(changedUris)="oidcAppRequest.postLogoutRedirectUrisList = $any($event)"
|
||||
[urisList]="oidcAppRequest.postLogoutRedirectUrisList"
|
||||
title="{{ 'APP.OIDC.POSTLOGOUTREDIRECT' | translate }}"
|
||||
[getValues]="requestRedirectValuesSubject$"
|
||||
[isNative]="oidcAppRequest.appType === OIDCAppType.OIDC_APP_TYPE_NATIVE"
|
||||
>
|
||||
</cnsl-redirect-uris>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<button
|
||||
color="primary"
|
||||
mat-raised-button
|
||||
class="continue-button"
|
||||
[disabled]="form.invalid"
|
||||
cdkFocusInitial
|
||||
type="submit"
|
||||
>
|
||||
{{ 'ACTIONS.CREATE' | translate }}
|
||||
</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -12,109 +12,122 @@ p.desc {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.app-create-container {
|
||||
padding-top: 2rem;
|
||||
.abort-container {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-bottom: 2rem;
|
||||
|
||||
.progress-bar {
|
||||
margin-bottom: 1rem;
|
||||
.abort {
|
||||
font-size: 1.2rem;
|
||||
margin-left: 2rem;
|
||||
}
|
||||
|
||||
.abort-container {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-bottom: 2rem;
|
||||
|
||||
.abort {
|
||||
font-size: 1.2rem;
|
||||
margin-left: 2rem;
|
||||
}
|
||||
|
||||
.abort-2 {
|
||||
font-size: 1.2rem;
|
||||
margin-left: 2rem;
|
||||
white-space: nowrap;
|
||||
}
|
||||
.abort-2 {
|
||||
font-size: 1.2rem;
|
||||
margin-left: 2rem;
|
||||
white-space: nowrap;
|
||||
}
|
||||
}
|
||||
|
||||
.margin-right {
|
||||
margin-right: 0.5rem;
|
||||
}
|
||||
.app-create-content {
|
||||
padding-left: 4.5rem;
|
||||
|
||||
.full-width {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.stepper {
|
||||
background: inherit !important;
|
||||
margin: 0 -1.5rem;
|
||||
|
||||
.formfield {
|
||||
.name-formfield {
|
||||
max-width: 400px;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.step-title {
|
||||
font-size: 1rem;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.05em;
|
||||
.app-create-container {
|
||||
padding-top: 2rem;
|
||||
|
||||
.progress-bar {
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
}
|
||||
|
||||
.step-description {
|
||||
font-size: 0.9rem;
|
||||
.margin-right {
|
||||
margin-right: 0.5rem;
|
||||
}
|
||||
}
|
||||
|
||||
.checkbox-container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
.checkbox {
|
||||
margin: 0.5rem 0;
|
||||
.full-width {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
.row {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
|
||||
.left,
|
||||
.right {
|
||||
margin-bottom: 0.5rem;
|
||||
font-size: 14px;
|
||||
}
|
||||
}
|
||||
|
||||
.app-create-actions {
|
||||
margin-top: 1rem;
|
||||
display: flex;
|
||||
|
||||
.fill-space {
|
||||
flex: 1;
|
||||
}
|
||||
}
|
||||
|
||||
.dev {
|
||||
.content {
|
||||
display: flex;
|
||||
margin: 0 -0.5rem;
|
||||
flex-wrap: wrap;
|
||||
flex-direction: row;
|
||||
.stepper {
|
||||
background: inherit !important;
|
||||
margin: 0 -1.5rem;
|
||||
|
||||
.formfield {
|
||||
flex: 1;
|
||||
box-sizing: border-box;
|
||||
margin: 0 0.5rem;
|
||||
max-width: 400px;
|
||||
}
|
||||
|
||||
&.full-width {
|
||||
flex-basis: 80%;
|
||||
}
|
||||
.step-title {
|
||||
font-size: 1rem;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.05em;
|
||||
}
|
||||
|
||||
.step-description {
|
||||
font-size: 0.9rem;
|
||||
}
|
||||
}
|
||||
|
||||
.continue-button {
|
||||
margin-top: 3rem;
|
||||
display: block;
|
||||
padding: 0.5rem 4rem;
|
||||
float: right;
|
||||
.checkbox-container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
.checkbox {
|
||||
margin: 0.5rem 0;
|
||||
}
|
||||
}
|
||||
|
||||
.row {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
|
||||
.left,
|
||||
.right {
|
||||
margin-bottom: 0.5rem;
|
||||
font-size: 14px;
|
||||
}
|
||||
}
|
||||
|
||||
.app-create-actions {
|
||||
margin-top: 1rem;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
.bck-button {
|
||||
margin-right: 1rem;
|
||||
}
|
||||
|
||||
.create-button {
|
||||
padding: 0.5rem 4rem;
|
||||
}
|
||||
}
|
||||
|
||||
.dev {
|
||||
.content {
|
||||
display: flex;
|
||||
margin: 0 -0.5rem;
|
||||
flex-wrap: wrap;
|
||||
flex-direction: row;
|
||||
|
||||
.formfield {
|
||||
flex: 1;
|
||||
box-sizing: border-box;
|
||||
margin: 0 0.5rem;
|
||||
|
||||
&.full-width {
|
||||
flex-basis: 80%;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.continue-button {
|
||||
margin-top: 3rem;
|
||||
display: block;
|
||||
padding: 0.5rem 4rem;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -49,6 +49,9 @@ export class AppCreateComponent implements OnInit, OnDestroy {
|
||||
public projectId: string = '';
|
||||
public loading: boolean = false;
|
||||
|
||||
public createSteps: number = 4;
|
||||
public currentCreateStep: number = 1;
|
||||
|
||||
public oidcAppRequest: AddOIDCAppRequest.AsObject = new AddOIDCAppRequest().toObject();
|
||||
public apiAppRequest: AddAPIAppRequest.AsObject = new AddAPIAppRequest().toObject();
|
||||
|
||||
@@ -270,6 +273,8 @@ export class AppCreateComponent implements OnInit, OnDestroy {
|
||||
}
|
||||
|
||||
public changeStep(event: StepperSelectionEvent): void {
|
||||
this.currentCreateStep = event.selectedIndex + 1;
|
||||
|
||||
if (event.selectedIndex >= 2) {
|
||||
this.requestRedirectValuesSubject$.next();
|
||||
}
|
||||
|
||||
@@ -1,32 +1,54 @@
|
||||
<cnsl-top-view title="{{project?.projectName}}" [hasActions]="false"
|
||||
<cnsl-top-view
|
||||
title="{{ project?.projectName }}"
|
||||
[hasActions]="false"
|
||||
docLink="https://docs.zitadel.ch/docs/guides/basics/projects#what-is-a-granted-project"
|
||||
sub="{{'PROJECT.PAGES.TYPE.GRANTED_SINGULAR' | translate}} {{'ACTIONS.OF' | translate}} <strong>{{project?.projectOwnerName}}</strong>"
|
||||
sub="{{ 'PROJECT.PAGES.TYPE.GRANTED_SINGULAR' | translate }} {{ 'ACTIONS.OF' | translate }} <strong>{{
|
||||
project?.projectOwnerName
|
||||
}}</strong>"
|
||||
[isActive]="project?.state === ProjectGrantState.PROJECT_GRANT_STATE_ACTIVE"
|
||||
[isInactive]="project?.state === ProjectGrantState.PROJECT_GRANT_STATE_INACTIVE"
|
||||
stateTooltip="{{'ORG.STATE.'+project.state | translate}}" [hasContributors]="true">
|
||||
stateTooltip="{{ 'ORG.STATE.' + project?.state | translate }}"
|
||||
[hasContributors]="true"
|
||||
>
|
||||
<p topContent *ngIf="isZitadel" class="granted-project-sub zitadel-warning">
|
||||
{{'PROJECT.PAGES.ZITADELPROJECT' | translate}}
|
||||
{{ 'PROJECT.PAGES.ZITADELPROJECT' | translate }}
|
||||
</p>
|
||||
<cnsl-contributors topContributors class="project-contributors" *ngIf="project" [loading]="loading$ | async"
|
||||
[totalResult]="totalMemberResult" [membersSubject]="membersSubject" title="{{ 'PROJECT.MEMBER.TITLE' | translate }}"
|
||||
description="{{ 'PROJECT.MEMBER.TITLEDESC' | translate }}" (addClicked)="openAddMember()"
|
||||
(showDetailClicked)="showDetail()" (refreshClicked)="loadMembers()"
|
||||
[disabled]="(['project.member.write$', 'project.member.write:'+ project.projectId]| hasRole | async) === false">
|
||||
<cnsl-contributors
|
||||
topContributors
|
||||
class="project-contributors"
|
||||
*ngIf="project"
|
||||
[loading]="loading$ | async"
|
||||
[totalResult]="totalMemberResult"
|
||||
[membersSubject]="membersSubject"
|
||||
title="{{ 'PROJECT.MEMBER.TITLE' | translate }}"
|
||||
description="{{ 'PROJECT.MEMBER.TITLEDESC' | translate }}"
|
||||
(addClicked)="openAddMember()"
|
||||
(showDetailClicked)="showDetail()"
|
||||
(refreshClicked)="loadMembers()"
|
||||
[disabled]="(['project.member.write$', 'project.member.write:' + project.projectId] | hasRole | async) === false"
|
||||
>
|
||||
</cnsl-contributors>
|
||||
<cnsl-info-row topContent *ngIf="project" [grantedProject]="project"></cnsl-info-row>
|
||||
</cnsl-top-view>
|
||||
|
||||
<div class="max-width-container">
|
||||
<cnsl-meta-layout>
|
||||
<ng-template cnslHasRole [hasRole]="['user.grant.read', 'user.grant.read:'+grantId]">
|
||||
<cnsl-card *ngIf="project?.projectId" title="{{ 'GRANTS.PROJECT.TITLE' | translate }}"
|
||||
description="{{'GRANTS.PROJECT.DESCRIPTION' | translate }}">
|
||||
<cnsl-user-grants *ngIf="projectId && grantId" [context]="UserGrantContext.GRANTED_PROJECT"
|
||||
[projectId]="projectId" [grantId]="grantId"
|
||||
[displayedColumns]="['select','user', 'projectId', 'creationDate','changeDate', 'roleNamesList','actions']"
|
||||
[disableWrite]="(['user.grant.write$','user.grant.write:'+grantId] | hasRole | async) === false"
|
||||
[disableDelete]="(['user.grant.delete$','user.grant.delete:'+grantId] | hasRole | async) === false"
|
||||
[refreshOnPreviousRoutes]="['/grant-create/project/{{projectId}}/grant/{{grantId}}']">
|
||||
<ng-template cnslHasRole [hasRole]="['user.grant.read', 'user.grant.read:' + grantId]">
|
||||
<cnsl-card
|
||||
*ngIf="project?.projectId"
|
||||
title="{{ 'GRANTS.PROJECT.TITLE' | translate }}"
|
||||
description="{{ 'GRANTS.PROJECT.DESCRIPTION' | translate }}"
|
||||
>
|
||||
<cnsl-user-grants
|
||||
*ngIf="projectId && grantId"
|
||||
[context]="UserGrantContext.GRANTED_PROJECT"
|
||||
[projectId]="projectId"
|
||||
[grantId]="grantId"
|
||||
[displayedColumns]="['select', 'user', 'projectId', 'creationDate', 'changeDate', 'roleNamesList', 'actions']"
|
||||
[disableWrite]="(['user.grant.write$', 'user.grant.write:' + grantId] | hasRole | async) === false"
|
||||
[disableDelete]="(['user.grant.delete$', 'user.grant.delete:' + grantId] | hasRole | async) === false"
|
||||
[refreshOnPreviousRoutes]="['/grant-create/project/{{projectId}}/grant/{{grantId}}']"
|
||||
>
|
||||
</cnsl-user-grants>
|
||||
</cnsl-card>
|
||||
</ng-template>
|
||||
@@ -34,6 +56,5 @@
|
||||
<div metainfo>
|
||||
<cnsl-changes *ngIf="project" [changeType]="ChangeType.PROJECT" [id]="project.projectId"></cnsl-changes>
|
||||
</div>
|
||||
|
||||
</cnsl-meta-layout>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -89,7 +89,7 @@ export class ProjectRoleCreateComponent implements OnInit, OnDestroy {
|
||||
.bulkAddProjectRoles(this.projectId, rolesToAdd)
|
||||
.then(() => {
|
||||
this.toast.showInfo('PROJECT.TOAST.ROLESCREATED', true);
|
||||
this.router.navigate(['projects', this.projectId, 'roles']);
|
||||
this.router.navigate(['projects', this.projectId], { queryParams: { id: 'roles' } });
|
||||
})
|
||||
.catch((error) => {
|
||||
this.toast.showError(error);
|
||||
|
||||
@@ -4,27 +4,31 @@
|
||||
<button (click)="close()" mat-icon-button>
|
||||
<mat-icon>close</mat-icon>
|
||||
</button>
|
||||
<span class="abort">{{ 'PROJECT.PAGES.CREATE' | translate }}</span><span class="abort-2">Step
|
||||
{{ currentCreateStep }} of
|
||||
{{ createSteps }}</span>
|
||||
<span class="abort">{{ 'PROJECT.PAGES.CREATE' | translate }}</span>
|
||||
</div>
|
||||
|
||||
<div class="project-create-content">
|
||||
<h1>{{'PROJECT.PAGES.CREATE_DESC' | translate}}</h1>
|
||||
<h1>{{ 'PROJECT.PAGES.CREATE_DESC' | translate }}</h1>
|
||||
<form cdkFocusRegionStart (ngSubmit)="saveProject()">
|
||||
<div class="column">
|
||||
<cnsl-form-field class="formfield" hintLabel="The name is required!">
|
||||
<cnsl-label>{{'PROJECT.NAME' | translate}}</cnsl-label>
|
||||
<input cnslInput cdkFocusInitial autofocus [(ngModel)]="project.name"
|
||||
[ngModelOptions]="{ standalone: true }" />
|
||||
<cnsl-label>{{ 'PROJECT.NAME' | translate }}</cnsl-label>
|
||||
<input cnslInput cdkFocusInitial autofocus [(ngModel)]="project.name" [ngModelOptions]="{ standalone: true }" />
|
||||
</cnsl-form-field>
|
||||
</div>
|
||||
|
||||
<button color="primary" mat-raised-button class="continue-button" [disabled]="!project.name" cdkFocusInitial
|
||||
type="submit" [attr.data-e2e]="'continue-button'">
|
||||
{{'ACTIONS.CONTINUE' | translate}}
|
||||
<button
|
||||
color="primary"
|
||||
mat-raised-button
|
||||
class="continue-button"
|
||||
[disabled]="!project.name"
|
||||
cdkFocusInitial
|
||||
type="submit"
|
||||
[attr.data-e2e]="'continue-button'"
|
||||
>
|
||||
{{ 'ACTIONS.CONTINUE' | translate }}
|
||||
</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -11,12 +11,6 @@ h1 {
|
||||
font-size: 1.2rem;
|
||||
margin-left: 2rem;
|
||||
}
|
||||
|
||||
.abort-2 {
|
||||
font-size: 1.2rem;
|
||||
margin-left: 2rem;
|
||||
white-space: nowrap;
|
||||
}
|
||||
}
|
||||
|
||||
.project-create-content {
|
||||
|
||||
@@ -28,9 +28,6 @@ export class ProjectCreateComponent {
|
||||
breadcrumbService.setBreadcrumb([bread]);
|
||||
}
|
||||
|
||||
public createSteps: number = 1;
|
||||
public currentCreateStep: number = 1;
|
||||
|
||||
public saveProject(): void {
|
||||
this.mgmtService
|
||||
.addProject(this.project)
|
||||
|
||||
@@ -1,79 +1,95 @@
|
||||
<div class="grid-main-container" *ngIf="projectType$ | async as type">
|
||||
<div class="loading-sp-wrapper">
|
||||
<mat-progress-spinner diameter="25" *ngIf="(loading$| async) === false" class="spinner" color="primary">
|
||||
</mat-progress-spinner>
|
||||
<div class="loading-sp-wrapper" *ngIf="loading$ | async">
|
||||
<mat-spinner diameter="25" class="spinner" color="primary"> </mat-spinner>
|
||||
</div>
|
||||
|
||||
<div class="owned-project-grid-container">
|
||||
<div class="item card" matRipple *ngFor="let item of selection.selected; index as i"
|
||||
<div
|
||||
class="item card"
|
||||
matRipple
|
||||
*ngFor="let item of selection.selected; index as i"
|
||||
(click)="navigateToProject(type, item, $event)"
|
||||
[ngClass]="{ inactive: item.state !== ProjectState.PROJECT_STATE_ACTIVE}">
|
||||
[ngClass]="{ inactive: item.state !== ProjectState.PROJECT_STATE_ACTIVE }"
|
||||
>
|
||||
<div class="text-part">
|
||||
<span *ngIf="item.details && item.details.changeDate"
|
||||
class="top cnsl-secondary-text">{{'PROJECT.PAGES.LASTMODIFIED' |
|
||||
translate}}
|
||||
{{ item.details.changeDate | timestampToDate | localizedDate: 'EEE dd. MMM, HH:mm' }}</span>
|
||||
<span *ngIf="item.details && item.details.changeDate" class="top cnsl-secondary-text"
|
||||
>{{ 'PROJECT.PAGES.LASTMODIFIED' | translate }}
|
||||
{{ item.details.changeDate | timestampToDate | localizedDate: 'EEE dd. MMM, HH:mm' }}</span
|
||||
>
|
||||
<div class="name-row">
|
||||
<span class="name" *ngIf="$any(item).name">{{ $any(item).name }}</span>
|
||||
<span class="name" *ngIf="$any(item).projectName">{{ $any(item).projectName }}</span>
|
||||
|
||||
<div class="state-dot"
|
||||
[ngClass]="{'active': item.state === ProjectState.PROJECT_STATE_ACTIVE, 'inactive': item.state === ProjectState.PROJECT_STATE_INACTIVE}">
|
||||
</div>
|
||||
<div
|
||||
class="state-dot"
|
||||
[ngClass]="{
|
||||
active: item.state === ProjectState.PROJECT_STATE_ACTIVE,
|
||||
inactive: item.state === ProjectState.PROJECT_STATE_INACTIVE
|
||||
}"
|
||||
></div>
|
||||
</div>
|
||||
|
||||
<span *ngIf="item.details && item.details.creationDate" class="created">{{'PROJECT.PAGES.CREATEDON' |
|
||||
translate}}
|
||||
{{ item.details.creationDate | timestampToDate | localizedDate: 'EEE dd. MMM, HH:mm' }}</span>
|
||||
<span *ngIf="item.details && item.details.creationDate" class="created"
|
||||
>{{ 'PROJECT.PAGES.CREATEDON' | translate }}
|
||||
{{ item.details.creationDate | timestampToDate | localizedDate: 'EEE dd. MMM, HH:mm' }}</span
|
||||
>
|
||||
<span class="fill-space"></span>
|
||||
</div>
|
||||
|
||||
<template [ngTemplateOutlet]="deleteButton" [ngTemplateOutletContext]="{key: item}"></template>
|
||||
<template [ngTemplateOutlet]="toggleButton" [ngTemplateOutletContext]="{key: item}"></template>
|
||||
<template [ngTemplateOutlet]="deleteButton" [ngTemplateOutletContext]="{ key: item }"></template>
|
||||
<template [ngTemplateOutlet]="toggleButton" [ngTemplateOutletContext]="{ key: item }"></template>
|
||||
</div>
|
||||
</div>
|
||||
<div class="owned-project-grid-container">
|
||||
<div class="item card" matRipple *ngFor="let item of notPinned; index as i"
|
||||
<div
|
||||
class="item card"
|
||||
matRipple
|
||||
*ngFor="let item of notPinned; index as i"
|
||||
(click)="navigateToProject(type, $any(item), $event)"
|
||||
[ngClass]="{ inactive: item.state !== ProjectState.PROJECT_STATE_ACTIVE}" [attr.data-e2e]="'grid-card'">
|
||||
[ngClass]="{ inactive: item.state !== ProjectState.PROJECT_STATE_ACTIVE }"
|
||||
[attr.data-e2e]="'grid-card'"
|
||||
>
|
||||
<div class="text-part">
|
||||
<span *ngIf="item.details && item.details.changeDate"
|
||||
class="top cnsl-secondary-text">{{'PROJECT.PAGES.LASTMODIFIED' | translate}}
|
||||
{{ item.details.changeDate | timestampToDate | localizedDate: 'EEE dd. MMM, HH:mm' }}</span>
|
||||
<span *ngIf="item.details && item.details.changeDate" class="top cnsl-secondary-text"
|
||||
>{{ 'PROJECT.PAGES.LASTMODIFIED' | translate }}
|
||||
{{ item.details.changeDate | timestampToDate | localizedDate: 'EEE dd. MMM, HH:mm' }}</span
|
||||
>
|
||||
<div class="name-row">
|
||||
<span class="name" *ngIf="$any(item).name">{{ $any(item).name }}</span>
|
||||
<span class="name" *ngIf="$any(item).projectName">{{ $any(item).projectName }}</span>
|
||||
|
||||
<div class="state-dot"
|
||||
[ngClass]="{'active': item.state === ProjectState.PROJECT_STATE_ACTIVE, 'inactive': item.state === ProjectState.PROJECT_STATE_INACTIVE}">
|
||||
</div>
|
||||
<div
|
||||
class="state-dot"
|
||||
[ngClass]="{
|
||||
active: item.state === ProjectState.PROJECT_STATE_ACTIVE,
|
||||
inactive: item.state === ProjectState.PROJECT_STATE_INACTIVE
|
||||
}"
|
||||
></div>
|
||||
</div>
|
||||
|
||||
<span class="owning-org" *ngIf="$any(item).projectOwnerName">{{$any(item).projectOwnerName}}</span>
|
||||
<span *ngIf="item.details && item.details.creationDate"
|
||||
class="created cnsl-secondary-text">{{'PROJECT.PAGES.CREATEDON' |
|
||||
translate}}
|
||||
{{
|
||||
item.details.creationDate | timestampToDate | localizedDate: 'EEE dd. MMM, HH:mm'
|
||||
}}</span>
|
||||
<span class="owning-org" *ngIf="$any(item).projectOwnerName">{{ $any(item).projectOwnerName }}</span>
|
||||
<span *ngIf="item.details && item.details.creationDate" class="created cnsl-secondary-text"
|
||||
>{{ 'PROJECT.PAGES.CREATEDON' | translate }}
|
||||
{{ item.details.creationDate | timestampToDate | localizedDate: 'EEE dd. MMM, HH:mm' }}</span
|
||||
>
|
||||
<span class="fill-space"></span>
|
||||
</div>
|
||||
|
||||
<ng-container *ngIf="type === ProjectType.PROJECTTYPE_OWNED">
|
||||
<template [ngTemplateOutlet]="deleteButton" [ngTemplateOutletContext]="{key: item}"></template>
|
||||
<template [ngTemplateOutlet]="deleteButton" [ngTemplateOutletContext]="{ key: item }"></template>
|
||||
</ng-container>
|
||||
<template [ngTemplateOutlet]="toggleButton" [ngTemplateOutletContext]="{key: item}"></template>
|
||||
<template [ngTemplateOutlet]="toggleButton" [ngTemplateOutletContext]="{ key: item }"></template>
|
||||
</div>
|
||||
|
||||
<p class="n-items cnsl-secondary-text" *ngIf="(loading$ | async) === false && projectList.length === 0">
|
||||
{{'PROJECT.PAGES.NOITEMS' |
|
||||
translate}}</p>
|
||||
{{ 'PROJECT.PAGES.NOITEMS' | translate }}
|
||||
</p>
|
||||
|
||||
<ng-container *ngIf="type === ProjectType.PROJECTTYPE_OWNED">
|
||||
<ng-template cnslHasRole [hasRole]="['project.create']">
|
||||
<div class="add-project-button card" matRipple (click)="addItem()">
|
||||
<mat-icon class="icon">add</mat-icon>
|
||||
<span>{{'PROJECT.PAGES.ADDNEW' | translate}}</span>
|
||||
<span>{{ 'PROJECT.PAGES.ADDNEW' | translate }}</span>
|
||||
<cnsl-action-keys [doNotUseContrast]="true" [withoutMargin]="true" (actionTriggered)="addItem()">
|
||||
</cnsl-action-keys>
|
||||
</div>
|
||||
@@ -83,17 +99,28 @@
|
||||
</div>
|
||||
|
||||
<ng-template #deleteButton let-key="key">
|
||||
<button *ngIf="key.id !== zitadelProjectId" matTooltip="{{'ACTIONS.DELETE' | translate}}" color="warn"
|
||||
(click)="deleteProject($event, key)" class="delete-button" mat-icon-button
|
||||
[attr.data-e2e]="'delete-project-button'">
|
||||
<button
|
||||
*ngIf="key.id !== zitadelProjectId"
|
||||
matTooltip="{{ 'ACTIONS.DELETE' | translate }}"
|
||||
color="warn"
|
||||
(click)="deleteProject($event, key)"
|
||||
class="delete-button"
|
||||
mat-icon-button
|
||||
[attr.data-e2e]="'delete-project-button'"
|
||||
>
|
||||
<i class="las la-trash"></i>
|
||||
</button>
|
||||
</ng-template>
|
||||
|
||||
<ng-template #toggleButton let-key="key">
|
||||
<button matTooltip="{{'ACTIONS.PIN' | translate}}" [ngClass]="{ selected: selection.isSelected(key)}"
|
||||
(click)="toggle(key,$event)" class="edit-button" mat-icon-button>
|
||||
<button
|
||||
matTooltip="{{ 'ACTIONS.PIN' | translate }}"
|
||||
[ngClass]="{ selected: selection.isSelected(key) }"
|
||||
(click)="toggle(key, $event)"
|
||||
class="edit-button"
|
||||
mat-icon-button
|
||||
>
|
||||
<mat-icon *ngIf="selection.isSelected(key)" svgIcon="mdi_pin"></mat-icon>
|
||||
<mat-icon svgIcon="mdi_pin_outline" *ngIf="!selection.isSelected(key)"></mat-icon>
|
||||
</button>
|
||||
</ng-template>
|
||||
</ng-template>
|
||||
|
||||
@@ -25,17 +25,12 @@
|
||||
}
|
||||
}
|
||||
|
||||
.spinner {
|
||||
margin: 1rem;
|
||||
}
|
||||
|
||||
.grid-main-container {
|
||||
position: relative;
|
||||
|
||||
.loading-sp-wrapper {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
display: block;
|
||||
margin: 1rem 0.5rem 0 0.5rem;
|
||||
}
|
||||
|
||||
.owned-project-grid-container {
|
||||
|
||||
@@ -144,7 +144,6 @@ export class ProjectGridComponent implements OnInit, OnDestroy {
|
||||
this.loadingSubject.next(false);
|
||||
})
|
||||
.catch((error) => {
|
||||
console.error(error);
|
||||
this.toast.showError(error);
|
||||
this.loadingSubject.next(false);
|
||||
});
|
||||
|
||||
@@ -10,12 +10,20 @@
|
||||
|
||||
<div class="projects-controls">
|
||||
<div class="project-type-actions">
|
||||
<button class="type-button" [ngClass]="{'active': (projectType$ | async) === ProjectType.PROJECTTYPE_OWNED}"
|
||||
(click)="setType(ProjectType.PROJECTTYPE_OWNED)">{{'PROJECT.PAGES.TYPE.OWNED' | translate}}
|
||||
({{((mgmtService?.ownedProjectsCount | async) ?? 0)}})</button>
|
||||
<button class="type-button" [ngClass]="{'active': (projectType$ | async) === ProjectType.PROJECTTYPE_GRANTED}"
|
||||
(click)="setType(ProjectType.PROJECTTYPE_GRANTED)">{{'PROJECT.PAGES.TYPE.GRANTED' | translate}}
|
||||
({{((mgmtService?.grantedProjectsCount | async) ?? 0)}})</button>
|
||||
<button
|
||||
class="type-button"
|
||||
[ngClass]="{ active: (projectType$ | async) === ProjectType.PROJECTTYPE_OWNED }"
|
||||
(click)="setType(ProjectType.PROJECTTYPE_OWNED)"
|
||||
>
|
||||
{{ 'PROJECT.PAGES.TYPE.OWNED' | translate }} ({{ (mgmtService?.ownedProjectsCount | async) ?? 0 }})
|
||||
</button>
|
||||
<button
|
||||
class="type-button"
|
||||
[ngClass]="{ active: (projectType$ | async) === ProjectType.PROJECTTYPE_GRANTED }"
|
||||
(click)="setType(ProjectType.PROJECTTYPE_GRANTED)"
|
||||
>
|
||||
{{ 'PROJECT.PAGES.TYPE.GRANTED' | translate }} ({{ (mgmtService?.grantedProjectsCount | async) ?? 0 }})
|
||||
</button>
|
||||
</div>
|
||||
<span class="fill-space"></span>
|
||||
<button class="grid-btn" (click)="grid = !grid" mat-icon-button [attr.data-e2e]="'toggle-grid'">
|
||||
@@ -24,11 +32,15 @@
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<cnsl-project-grid *ngIf="grid" [projectType$]="projectType$" [zitadelProjectId]="zitadelProjectId"
|
||||
(emitAddProject)="addProject()">
|
||||
<cnsl-project-grid
|
||||
*ngIf="grid"
|
||||
[projectType$]="projectType$"
|
||||
[zitadelProjectId]="zitadelProjectId"
|
||||
(emitAddProject)="addProject()"
|
||||
>
|
||||
</cnsl-project-grid>
|
||||
|
||||
<cnsl-project-list *ngIf="!grid" [projectType$]="projectType$" [zitadelProjectId]="zitadelProjectId">
|
||||
</cnsl-project-list>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -53,6 +53,7 @@ export class ProjectsComponent {
|
||||
type:
|
||||
type === ProjectType.PROJECTTYPE_OWNED ? 'owned' : type === ProjectType.PROJECTTYPE_GRANTED ? 'granted' : 'owned',
|
||||
},
|
||||
replaceUrl: true,
|
||||
queryParamsHandling: 'merge',
|
||||
skipLocationChange: false,
|
||||
});
|
||||
|
||||
@@ -4,53 +4,64 @@
|
||||
<button (click)="close()" mat-icon-button>
|
||||
<mat-icon>close</mat-icon>
|
||||
</button>
|
||||
<h1 class="abort">{{ 'GRANTS.CREATE.TITLE' | translate }}</h1><span class="abort-2">Step
|
||||
{{ currentCreateStep }} of
|
||||
{{ STEPS }}</span>
|
||||
<h1 class="abort">{{ 'GRANTS.CREATE.TITLE' | translate }}</h1>
|
||||
<span class="abort-2">Step {{ currentCreateStep }} of {{ STEPS }}</span>
|
||||
</div>
|
||||
|
||||
<div class="user-grant-create-content">
|
||||
<ng-container *ngIf="currentCreateStep === 1">
|
||||
<p class="user-grant-create-desc cnsl-secondary-text">
|
||||
{{'PROJECT.GRANT.CREATE.ORG_DESCRIPTION' | translate: org}}
|
||||
<br>
|
||||
{{'PROJECT.GRANT.CREATE.ORG_DESCRIPTION_DESC' | translate}}
|
||||
{{ 'PROJECT.GRANT.CREATE.ORG_DESCRIPTION' | translate: org }}
|
||||
<br />
|
||||
{{ 'PROJECT.GRANT.CREATE.ORG_DESCRIPTION_DESC' | translate }}
|
||||
</p>
|
||||
|
||||
<ng-container>
|
||||
<h2>{{'PROJECT.GRANT.CREATE.SEL_USER' | translate}}</h2>
|
||||
<h2>{{ 'PROJECT.GRANT.CREATE.SEL_USER' | translate }}</h2>
|
||||
|
||||
<cnsl-search-user-autocomplete [editState]="context !== UserGrantContext.USER" class="block"
|
||||
[users]="user ? [user] : []" (selectionChanged)="selectUsers($event)" [target]="UserTarget.SELF">
|
||||
<cnsl-search-user-autocomplete
|
||||
[editState]="context !== UserGrantContext.USER"
|
||||
class="block"
|
||||
[users]="user ? [user] : []"
|
||||
(selectionChanged)="selectUsers($event)"
|
||||
[target]="UserTarget.SELF"
|
||||
>
|
||||
</cnsl-search-user-autocomplete>
|
||||
</ng-container>
|
||||
|
||||
<ng-container *ngIf="context && (context === UserGrantContext.USER || context === UserGrantContext.NONE)">
|
||||
<h2 class="project-search">{{'PROJECT.GRANT.CREATE.SEL_PROJECT' | translate}}</h2>
|
||||
<h2 class="project-search">{{ 'PROJECT.GRANT.CREATE.SEL_PROJECT' | translate }}</h2>
|
||||
|
||||
<cnsl-search-project-autocomplete class="block"
|
||||
(selectionChanged)="selectProject($event.project, $event.type)">
|
||||
<cnsl-search-project-autocomplete class="block" (selectionChanged)="selectProject($event.project, $event.type)">
|
||||
</cnsl-search-project-autocomplete>
|
||||
</ng-container>
|
||||
</ng-container>
|
||||
|
||||
<ng-container *ngIf="currentCreateStep === STEPS">
|
||||
<h1>{{'PROJECT.GRANT.CREATE.SEL_ROLES' | translate}}</h1>
|
||||
<h1>{{ 'PROJECT.GRANT.CREATE.SEL_ROLES' | translate }}</h1>
|
||||
|
||||
<cnsl-card>
|
||||
{{ $any(project)?.grantId }}
|
||||
<cnsl-project-roles-table
|
||||
[displayedColumns]="['select', 'key', 'displayname', 'group', 'creationDate', 'changeDate']"
|
||||
(changedSelection)="selectRoles($event)"
|
||||
[projectId]="project?.id ? project.id : grantedProject?.projectId ? grantedProject.projectId : ''"
|
||||
[grantId]="$any(project)?.grantId ? $any(project)?.grantId : ''">
|
||||
[grantId]="$any(grantedProject)?.grantId ? $any(grantedProject)?.grantId : ''"
|
||||
>
|
||||
</cnsl-project-roles-table>
|
||||
</cnsl-card>
|
||||
</ng-container>
|
||||
|
||||
<div class="btn-container">
|
||||
<ng-container *ngIf="currentCreateStep === 1">
|
||||
<button [disabled]="!org || !(project?.id || grantedProject?.projectId) || userIds.length < 1"
|
||||
(click)="next()" color="primary" mat-raised-button class="big-button" cdkFocusInitial>
|
||||
<button
|
||||
[disabled]="!org || !(project?.id || grantedProject?.projectId) || userIds.length < 1"
|
||||
(click)="next()"
|
||||
color="primary"
|
||||
mat-raised-button
|
||||
class="big-button"
|
||||
cdkFocusInitial
|
||||
>
|
||||
{{ 'ACTIONS.CONTINUE' | translate }}
|
||||
</button>
|
||||
</ng-container>
|
||||
@@ -66,4 +77,4 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1,11 +1,10 @@
|
||||
<div class="max-width-container">
|
||||
<div class="enlarged-container">
|
||||
<div class="abort-container">
|
||||
<a [routerLink]="[ '/users']" mat-icon-button>
|
||||
<a [routerLink]="['/users']" mat-icon-button>
|
||||
<mat-icon>close</mat-icon>
|
||||
</a>
|
||||
<h1 class="abort">{{ 'USER.CREATE.TITLE' | translate }}</h1><span class="abort-2">Step
|
||||
1 of 1</span>
|
||||
<h1 class="abort">{{ 'USER.CREATE.TITLE' | translate }}</h1>
|
||||
</div>
|
||||
|
||||
<div class="user-create-main-content">
|
||||
@@ -13,63 +12,69 @@
|
||||
|
||||
<form *ngIf="userForm" [formGroup]="userForm" (ngSubmit)="createUser()" class="user-create-form">
|
||||
<div class="user-create-content">
|
||||
<p class="user-create-section cnsl-secondary-text">{{ 'USER.CREATE.NAMEANDEMAILSECTION' | translate }}</p>
|
||||
<cnsl-form-field class="formfield">
|
||||
<cnsl-label>{{ 'USER.PROFILE.EMAIL' | translate }}*</cnsl-label>
|
||||
<input cnslInput matRipple formControlName="email" required />
|
||||
<span cnslError *ngIf="email?.invalid && !email?.errors?.required">
|
||||
{{ 'USER.VALIDATION.NOTANEMAIL' | translate }}
|
||||
</span>
|
||||
<span cnslError *ngIf="email?.invalid && email?.errors?.required">
|
||||
{{ 'USER.VALIDATION.REQUIRED' | translate }}
|
||||
</span>
|
||||
</cnsl-form-field>
|
||||
<cnsl-form-field class="formfield">
|
||||
<cnsl-label>{{ 'USER.PROFILE.USERNAME' | translate }}*</cnsl-label>
|
||||
<input cnslInput formControlName="userName" required
|
||||
[ngStyle]="{'padding-right': suffixPadding ? suffixPadding : '10px'}" />
|
||||
<span #suffix *ngIf="envSuffixLabel" cnslSuffix>{{envSuffixLabel}}</span>
|
||||
<p class="user-create-section">{{ 'USER.CREATE.NAMEANDEMAILSECTION' | translate }}</p>
|
||||
|
||||
<span cnslError *ngIf="userName?.invalid && userName?.errors?.required">
|
||||
{{ 'USER.VALIDATION.REQUIRED' | translate }}
|
||||
</span>
|
||||
<span cnslError *ngIf="userName?.invalid && userName?.errors?.noEmailValidator">
|
||||
{{ 'USER.VALIDATION.NOEMAIL' | translate }}
|
||||
</span>
|
||||
</cnsl-form-field>
|
||||
</div>
|
||||
<div class="user-create-content">
|
||||
<cnsl-form-field class="formfield">
|
||||
<cnsl-label>{{ 'USER.PROFILE.FIRSTNAME' | translate }}*</cnsl-label>
|
||||
<input cnslInput formControlName="firstName" required />
|
||||
<span cnslError *ngIf="firstName?.invalid && firstName?.errors?.required">
|
||||
{{ 'USER.VALIDATION.REQUIRED' | translate }}
|
||||
</span>
|
||||
</cnsl-form-field>
|
||||
<cnsl-form-field class="formfield">
|
||||
<cnsl-label>{{ 'USER.PROFILE.LASTNAME' | translate }}*</cnsl-label>
|
||||
<input cnslInput formControlName="lastName" required />
|
||||
<span cnslError *ngIf="lastName?.invalid && lastName?.errors?.required">
|
||||
{{ 'USER.VALIDATION.REQUIRED' | translate }}
|
||||
</span>
|
||||
</cnsl-form-field>
|
||||
<cnsl-form-field class="formfield">
|
||||
<cnsl-label>{{ 'USER.PROFILE.NICKNAME' | translate }}</cnsl-label>
|
||||
<input cnslInput formControlName="nickName" />
|
||||
<span cnslError *ngIf="nickName?.invalid && nickName?.errors?.required">
|
||||
{{ 'USER.VALIDATION.REQUIRED' | translate }}
|
||||
</span>
|
||||
</cnsl-form-field>
|
||||
<div class="user-create-grid">
|
||||
<cnsl-form-field>
|
||||
<cnsl-label>{{ 'USER.PROFILE.EMAIL' | translate }}*</cnsl-label>
|
||||
<input cnslInput matRipple formControlName="email" required />
|
||||
<span cnslError *ngIf="email?.invalid && !email?.errors?.required">
|
||||
{{ 'USER.VALIDATION.NOTANEMAIL' | translate }}
|
||||
</span>
|
||||
<span cnslError *ngIf="email?.invalid && email?.errors?.required">
|
||||
{{ 'USER.VALIDATION.REQUIRED' | translate }}
|
||||
</span>
|
||||
</cnsl-form-field>
|
||||
<cnsl-form-field>
|
||||
<cnsl-label>{{ 'USER.PROFILE.USERNAME' | translate }}*</cnsl-label>
|
||||
<input
|
||||
cnslInput
|
||||
formControlName="userName"
|
||||
required
|
||||
[ngStyle]="{ 'padding-right': suffixPadding ? suffixPadding : '10px' }"
|
||||
/>
|
||||
<span #suffix *ngIf="envSuffixLabel" cnslSuffix>{{ envSuffixLabel }}</span>
|
||||
|
||||
<span cnslError *ngIf="userName?.invalid && userName?.errors?.required">
|
||||
{{ 'USER.VALIDATION.REQUIRED' | translate }}
|
||||
</span>
|
||||
<span cnslError *ngIf="userName?.invalid && userName?.errors?.noEmailValidator">
|
||||
{{ 'USER.VALIDATION.NOEMAIL' | translate }}
|
||||
</span>
|
||||
</cnsl-form-field>
|
||||
|
||||
<cnsl-form-field>
|
||||
<cnsl-label>{{ 'USER.PROFILE.FIRSTNAME' | translate }}*</cnsl-label>
|
||||
<input cnslInput formControlName="firstName" required />
|
||||
<span cnslError *ngIf="firstName?.invalid && firstName?.errors?.required">
|
||||
{{ 'USER.VALIDATION.REQUIRED' | translate }}
|
||||
</span>
|
||||
</cnsl-form-field>
|
||||
<cnsl-form-field>
|
||||
<cnsl-label>{{ 'USER.PROFILE.LASTNAME' | translate }}*</cnsl-label>
|
||||
<input cnslInput formControlName="lastName" required />
|
||||
<span cnslError *ngIf="lastName?.invalid && lastName?.errors?.required">
|
||||
{{ 'USER.VALIDATION.REQUIRED' | translate }}
|
||||
</span>
|
||||
</cnsl-form-field>
|
||||
<cnsl-form-field>
|
||||
<cnsl-label>{{ 'USER.PROFILE.NICKNAME' | translate }}</cnsl-label>
|
||||
<input cnslInput formControlName="nickName" />
|
||||
<span cnslError *ngIf="nickName?.invalid && nickName?.errors?.required">
|
||||
{{ 'USER.VALIDATION.REQUIRED' | translate }}
|
||||
</span>
|
||||
</cnsl-form-field>
|
||||
</div>
|
||||
|
||||
<div class="email-is-verified">
|
||||
<mat-checkbox class="block-checkbox" formControlName="isVerified">
|
||||
{{'USER.LOGINMETHODS.EMAIL.ISVERIFIED' | translate}}
|
||||
{{ 'USER.LOGINMETHODS.EMAIL.ISVERIFIED' | translate }}
|
||||
</mat-checkbox>
|
||||
<mat-checkbox class="block-checkbox" [(ngModel)]="usePassword" [ngModelOptions]="{standalone: true}">
|
||||
{{'ORG.PAGES.USEPASSWORD' | translate}}
|
||||
<mat-checkbox class="block-checkbox" [(ngModel)]="usePassword" [ngModelOptions]="{ standalone: true }">
|
||||
{{ 'ORG.PAGES.USEPASSWORD' | translate }}
|
||||
</mat-checkbox>
|
||||
<cnsl-info-section class="full-width desc">
|
||||
<span>{{'USER.CREATE.INITMAILDESCRIPTION' | translate}}</span>
|
||||
<span>{{ 'USER.CREATE.INITMAILDESCRIPTION' | translate }}</span>
|
||||
</cnsl-info-section>
|
||||
</div>
|
||||
|
||||
@@ -77,59 +82,67 @@
|
||||
<cnsl-password-complexity-view class="complexity-view" [policy]="this.policy" [password]="password">
|
||||
</cnsl-password-complexity-view>
|
||||
|
||||
<form [formGroup]="pwdForm" class="user-create-pwd-form">
|
||||
<cnsl-form-field class="pwd-field" *ngIf="password" appearance="outline">
|
||||
<cnsl-label>{{ 'USER.PASSWORD.NEWINITIAL' | translate }}</cnsl-label>
|
||||
<input cnslInput autocomplete="off" name="firstpassword" formControlName="password" type="password" />
|
||||
<form [formGroup]="pwdForm">
|
||||
<div class="user-create-grid">
|
||||
<cnsl-form-field *ngIf="password">
|
||||
<cnsl-label>{{ 'USER.PASSWORD.NEWINITIAL' | translate }}</cnsl-label>
|
||||
<input cnslInput autocomplete="off" name="firstpassword" formControlName="password" type="password" />
|
||||
|
||||
<span cnslError *ngIf="password?.errors?.required">
|
||||
{{ 'USER.VALIDATION.REQUIRED' | translate }}
|
||||
</span>
|
||||
<span cnslError *ngIf="password?.errors?.required">
|
||||
{{ 'USER.VALIDATION.REQUIRED' | translate }}
|
||||
</span>
|
||||
</cnsl-form-field>
|
||||
<cnsl-form-field *ngIf="confirmPassword">
|
||||
<cnsl-label>{{ 'USER.PASSWORD.CONFIRMINITIAL' | translate }}</cnsl-label>
|
||||
<input
|
||||
cnslInput
|
||||
autocomplete="off"
|
||||
name="confirmPassword"
|
||||
formControlName="confirmPassword"
|
||||
type="password"
|
||||
/>
|
||||
|
||||
</cnsl-form-field>
|
||||
<cnsl-form-field class="pwd-field" *ngIf="confirmPassword" appearance="outline">
|
||||
<cnsl-label>{{ 'USER.PASSWORD.CONFIRMINITIAL' | translate }}</cnsl-label>
|
||||
<input cnslInput autocomplete="off" name="confirmPassword" formControlName="confirmPassword"
|
||||
type="password" />
|
||||
|
||||
<span cnslError *ngIf="confirmPassword?.errors?.required">
|
||||
{{ 'USER.VALIDATION.REQUIRED' | translate }}
|
||||
</span>
|
||||
<span cnslError *ngIf="confirmPassword?.errors?.notequal">
|
||||
{{ 'USER.PASSWORD.NOTEQUAL' | translate }}
|
||||
</span>
|
||||
</cnsl-form-field>
|
||||
<span cnslError *ngIf="confirmPassword?.errors?.required">
|
||||
{{ 'USER.VALIDATION.REQUIRED' | translate }}
|
||||
</span>
|
||||
<span cnslError *ngIf="confirmPassword?.errors?.notequal">
|
||||
{{ 'USER.PASSWORD.NOTEQUAL' | translate }}
|
||||
</span>
|
||||
</cnsl-form-field>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<p class="user-create-section cnsl-secondary-text">{{ 'USER.CREATE.GENDERLANGSECTION' | translate }}</p>
|
||||
<p class="user-create-section">{{ 'USER.CREATE.GENDERLANGSECTION' | translate }}</p>
|
||||
|
||||
<cnsl-form-field class="formfield">
|
||||
<cnsl-label>{{ 'USER.PROFILE.GENDER' | translate }}</cnsl-label>
|
||||
<mat-select formControlName="gender">
|
||||
<mat-option *ngFor="let gender of genders" [value]="gender">
|
||||
{{ 'GENDERS.'+gender | translate }}
|
||||
</mat-option>
|
||||
</mat-select>
|
||||
<span cnslError *ngIf="gender?.invalid && gender?.errors?.required">
|
||||
{{ 'USER.VALIDATION.REQUIRED' | translate }}
|
||||
</span>
|
||||
</cnsl-form-field>
|
||||
<cnsl-form-field class="formfield">
|
||||
<cnsl-label>{{ 'USER.PROFILE.PREFERRED_LANGUAGE' | translate }}</cnsl-label>
|
||||
<mat-select formControlName="preferredLanguage">
|
||||
<mat-option *ngFor="let language of languages" [value]="language">
|
||||
{{ 'LANGUAGES.'+language | translate }}
|
||||
</mat-option>
|
||||
<span cnslError *ngIf="preferredLanguage?.invalid && preferredLanguage?.errors?.required">
|
||||
<div class="user-create-grid">
|
||||
<cnsl-form-field>
|
||||
<cnsl-label>{{ 'USER.PROFILE.GENDER' | translate }}</cnsl-label>
|
||||
<mat-select formControlName="gender">
|
||||
<mat-option *ngFor="let gender of genders" [value]="gender">
|
||||
{{ 'GENDERS.' + gender | translate }}
|
||||
</mat-option>
|
||||
</mat-select>
|
||||
<span cnslError *ngIf="gender?.invalid && gender?.errors?.required">
|
||||
{{ 'USER.VALIDATION.REQUIRED' | translate }}
|
||||
</span>
|
||||
</mat-select>
|
||||
</cnsl-form-field>
|
||||
</cnsl-form-field>
|
||||
<cnsl-form-field>
|
||||
<cnsl-label>{{ 'USER.PROFILE.PREFERRED_LANGUAGE' | translate }}</cnsl-label>
|
||||
<mat-select formControlName="preferredLanguage">
|
||||
<mat-option *ngFor="let language of languages" [value]="language">
|
||||
{{ 'LANGUAGES.' + language | translate }}
|
||||
</mat-option>
|
||||
<span cnslError *ngIf="preferredLanguage?.invalid && preferredLanguage?.errors?.required">
|
||||
{{ 'USER.VALIDATION.REQUIRED' | translate }}
|
||||
</span>
|
||||
</mat-select>
|
||||
</cnsl-form-field>
|
||||
</div>
|
||||
|
||||
<p class="user-create-section cnsl-secondary-text">{{ 'USER.CREATE.ADDRESSANDPHONESECTION' | translate }}</p>
|
||||
<p class="user-create-section">{{ 'USER.CREATE.ADDRESSANDPHONESECTION' | translate }}</p>
|
||||
|
||||
<cnsl-form-field class="formfield">
|
||||
<cnsl-form-field>
|
||||
<cnsl-label>{{ 'USER.PROFILE.PHONE' | translate }}</cnsl-label>
|
||||
<input cnslInput formControlName="phone" />
|
||||
<span cnslError *ngIf="phone?.invalid && phone?.errors?.required">
|
||||
@@ -138,12 +151,17 @@
|
||||
</cnsl-form-field>
|
||||
</div>
|
||||
<div class="user-create-btn-container">
|
||||
<button [attr.data-e2e]="'create-button'" color="primary"
|
||||
[disabled]="userForm.invalid || (this.usePassword && this.pwdForm.invalid)" type="submit"
|
||||
mat-raised-button>{{ 'ACTIONS.CREATE' |
|
||||
translate }}</button>
|
||||
<button
|
||||
[attr.data-e2e]="'create-button'"
|
||||
color="primary"
|
||||
[disabled]="userForm.invalid || (this.usePassword && this.pwdForm.invalid)"
|
||||
type="submit"
|
||||
mat-raised-button
|
||||
>
|
||||
{{ 'ACTIONS.CREATE' | translate }}
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -7,20 +7,47 @@
|
||||
font-size: 1.2rem;
|
||||
margin-left: 2rem;
|
||||
}
|
||||
|
||||
.abort-2 {
|
||||
font-size: 1.2rem;
|
||||
margin-left: 2rem;
|
||||
white-space: nowrap;
|
||||
}
|
||||
}
|
||||
|
||||
.user-create-main-content {
|
||||
padding-left: 4.5rem;
|
||||
max-width: 35rem;
|
||||
|
||||
@media only screen and (max-width: 500px) {
|
||||
padding: 0 0.5rem;
|
||||
}
|
||||
|
||||
.user-create-form {
|
||||
padding-top: 1rem;
|
||||
.user-create-content {
|
||||
.user-create-section {
|
||||
padding: 1rem 0 0 0;
|
||||
flex-basis: 100%;
|
||||
font-size: 14px;
|
||||
letter-spacing: 0.05em;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
|
||||
.user-create-grid {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1fr;
|
||||
column-gap: 1rem;
|
||||
|
||||
@media only screen and (max-width: 500px) {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
}
|
||||
|
||||
.email-is-verified,
|
||||
.use-password-block {
|
||||
flex-basis: 100%;
|
||||
margin-top: 1.5rem;
|
||||
|
||||
.block-checkbox {
|
||||
display: block;
|
||||
margin: 0.25rem 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.user-create-btn-container {
|
||||
button {
|
||||
@@ -32,49 +59,9 @@
|
||||
}
|
||||
}
|
||||
|
||||
.user-create-content {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
flex-direction: row;
|
||||
margin: 0 -0.5rem;
|
||||
|
||||
.user-create-section {
|
||||
padding: 0.5rem;
|
||||
flex-basis: 100%;
|
||||
font-size: 0.9rem;
|
||||
letter-spacing: 0.05em;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
|
||||
.formfield {
|
||||
flex: 1 0 33%;
|
||||
margin: 0 0.5rem;
|
||||
}
|
||||
|
||||
.email-is-verified,
|
||||
.use-password-block {
|
||||
margin: 0 0.5rem;
|
||||
flex-basis: 100%;
|
||||
margin-top: 1.5rem;
|
||||
|
||||
.block-checkbox {
|
||||
display: block;
|
||||
margin: 0.25rem 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.pwd-section {
|
||||
margin: 0 0.5rem;
|
||||
|
||||
.section {
|
||||
padding: 0.5rem 0;
|
||||
}
|
||||
|
||||
.user-create-pwd-form {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1fr;
|
||||
grid-gap: 1rem;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -75,7 +75,7 @@ export class UserCreateComponent implements OnDestroy {
|
||||
this.loading = true;
|
||||
this.loadOrg();
|
||||
this.mgmtService
|
||||
.getOrgIAMPolicy()
|
||||
.getDomainPolicy()
|
||||
.then((resp) => {
|
||||
if (resp.policy?.userLoginMustBeDomain) {
|
||||
this.userLoginMustBeDomain = resp.policy.userLoginMustBeDomain;
|
||||
|
||||
@@ -40,7 +40,9 @@
|
||||
<mat-progress-spinner diameter="25" color="primary" mode="indeterminate"></mat-progress-spinner>
|
||||
</div>
|
||||
|
||||
<p class="no-user-error" *ngIf="!loading && !user">{{ 'USER.PAGES.NOUSER' | translate }}</p>
|
||||
<div *ngIf="!loading && !user" class="max-width-container">
|
||||
<p class="no-user-error">{{ 'USER.PAGES.NOUSER' | translate }}</p>
|
||||
</div>
|
||||
|
||||
<div class="max-width-container" *ngIf="user && (['user.write$', 'user.write:' + user.id] | hasRole) as canWrite$">
|
||||
<cnsl-meta-layout>
|
||||
|
||||
@@ -76,6 +76,7 @@ export class UserTableComponent implements OnInit {
|
||||
public ActionKeysType: any = ActionKeysType;
|
||||
public filterOpen: boolean = false;
|
||||
|
||||
private searchQueries: SearchQuery[] = [];
|
||||
constructor(
|
||||
private router: Router,
|
||||
public translate: TranslateService,
|
||||
@@ -109,6 +110,7 @@ export class UserTableComponent implements OnInit {
|
||||
queryParams: {
|
||||
type: type === Type.TYPE_HUMAN ? 'human' : type === Type.TYPE_MACHINE ? 'machine' : 'human',
|
||||
},
|
||||
replaceUrl: true,
|
||||
queryParamsHandling: 'merge',
|
||||
skipLocationChange: false,
|
||||
});
|
||||
@@ -225,14 +227,12 @@ export class UserTableComponent implements OnInit {
|
||||
}
|
||||
|
||||
public refreshPage(): void {
|
||||
this.getData(this.paginator.pageSize, this.paginator.pageIndex * this.paginator.pageSize, this.type);
|
||||
this.getData(this.paginator.pageSize, this.paginator.pageIndex * this.paginator.pageSize, this.type, this.searchQueries);
|
||||
}
|
||||
|
||||
public sortChange(sortState: Sort) {
|
||||
console.log(sortState.active, sortState.direction);
|
||||
|
||||
if (sortState.direction && sortState.active) {
|
||||
this._liveAnnouncer.announce(`Sorted ${sortState.direction}ending`);
|
||||
this._liveAnnouncer.announce(`Sorted ${sortState.direction} ending`);
|
||||
this.refreshPage();
|
||||
} else {
|
||||
this._liveAnnouncer.announce('Sorting cleared');
|
||||
@@ -241,6 +241,7 @@ export class UserTableComponent implements OnInit {
|
||||
|
||||
public applySearchQuery(searchQueries: SearchQuery[]): void {
|
||||
this.selection.clear();
|
||||
this.searchQueries = searchQueries;
|
||||
this.getData(
|
||||
this.paginator ? this.paginator.pageSize : this.INITIAL_PAGE_SIZE,
|
||||
this.paginator ? this.paginator.pageIndex * this.paginator.pageSize : 0,
|
||||
|
||||
Reference in New Issue
Block a user