Files
zitadel/console/src/app/pages/projects/apps/app-detail/app-detail.component.html
T

278 lines
15 KiB
HTML

<app-meta-layout>
<div class="enlarged-container">
<div class="head">
<a [routerLink]="['/projects', projectId]" mat-icon-button>
<mat-icon class="icon">arrow_back</mat-icon>
</a>
<div class="title-col">
<h1>{{app?.name}}</h1>
<span *ngIf="app?.oidcConfig">{{'APP.OIDC.APPTYPE.'+app?.oidcConfig?.appType |
translate}}</span>
<span *ngIf="app?.apiConfig">API</span>
</div>
<ng-container *ngIf="isZitadel === false">
<ng-template appHasRole [appHasRole]="['project.app.write:'+projectId, 'project.app.write']">
<button *ngIf="!editState" matTooltip="{{'ACTIONS.EDIT' | translate}}" mat-icon-button
(click)="editState = !editState" aria-label="edit app name">
<i class="las la-edit"></i>
</button>
<button *ngIf="editState" (click)="saveApp()" [disabled]="appNameForm.invalid || name?.disabled"
mat-icon-button>
<i class="las la-save"></i>
</button>
</ng-template>
<ng-template appHasRole [appHasRole]="['project.app.delete:'+projectId, 'project.app.delete']">
<button matTooltip="{{'ACTIONS.DELETE' | translate}}" color="warn" mat-icon-button
(click)="deleteApp()" aria-label="delete app">
<i class="las la-trash"></i>
</button>
</ng-template>
</ng-container>
<p class="desc">{{ 'APP.PAGES.DESCRIPTION' | translate }}</p>
<p *ngIf="isZitadel" class="zitadel-warning">{{'PROJECT.PAGES.ZITADELPROJECT' | translate}}</p>
</div>
<span *ngIf="errorMessage" class="err-container">{{errorMessage}}</span>
<form *ngIf="app && editState" [formGroup]="appNameForm">
<div class="name-content">
<mat-button-toggle-group formControlName="state" class="toggle" (change)="changeState($event)">
<mat-button-toggle [value]="AppState.APP_STATE_INACTIVE"
matTooltip="{{ 'ACTIONS.DEACTIVATE' | translate}}">
{{'APP.PAGES.DETAIL.STATE.'+AppState.APP_STATE_INACTIVE | translate}}
</mat-button-toggle>
<mat-button-toggle [value]="AppState.APPSTATE_ACTIVE"
matTooltip="{{ 'ACTIONS.REACTIVATE' | translate}}">
{{'APP.PAGES.DETAIL.STATE.'+AppState.APP_STATE_ACTIVE | translate}}
</mat-button-toggle>
</mat-button-toggle-group>
<cnsl-form-field class="name-field">
<cnsl-label>{{ 'APP.NAME' | translate }}</cnsl-label>
<input cnslInput formControlName="name" />
</cnsl-form-field>
</div>
</form>
<div class="environment-wrapper">
<div class="environment" *ngIf="app?.oidcConfig?.clientId">
<span class="key">{{'APP.OIDC.INFO.CLIENTID' | translate}}</span>
<div class="environment-row">
<span>{{this.app.oidcConfig?.clientId}}</span>
<button color="primary" [disabled]="copiedKey == this.app.oidcConfig?.clientId"
[matTooltip]="(copiedKey != this.app.oidcConfig?.clientId ? 'USER.PAGES.COPY' : 'USER.PAGES.COPIED' ) | translate"
appCopyToClipboard [valueToCopy]="this.app.oidcConfig?.clientId"
(copiedValue)="copiedKey = 'clientId'" mat-icon-button>
<i *ngIf="copiedKey != 'clientId'" class="las la-clipboard"></i>
<i *ngIf="copiedKey == 'clientId'" class="las la-clipboard-check"></i>
</button>
</div>
</div>
<ng-container *ngFor="let environmentV of (environmentMap | keyvalue)">
<div *ngIf="environmentV.value" class="environment">
<span class="key">{{environmentV.key}}</span>
<div class="environment-row">
<span>{{environmentV.value}}</span>
<button color="primary" [disabled]="copiedKey == environmentV.value"
[matTooltip]="(copiedKey != environmentV.value ? 'USER.PAGES.COPY' : 'USER.PAGES.COPIED' ) | translate"
appCopyToClipboard [valueToCopy]="environmentV.value"
(copiedValue)="copiedKey = environmentV.key" mat-icon-button>
<i *ngIf="copiedKey != environmentV.key" class="las la-clipboard"></i>
<i *ngIf="copiedKey == environmentV.key" class="las la-clipboard-check"></i>
</button>
</div>
</div>
</ng-container>
</div>
<div class="compliance"
*ngIf="app?.oidcConfig?.complianceProblemsList && app.oidcConfig?.complianceProblemsList?.length">
<cnsl-info-section class="problem" type="WARN">
<ul style="margin: 0;">
<li style="margin: 0 0 .5rem 0;"
*ngFor="let problem of app.oidcConfig?.complianceProblemsList || []">
{{problem.localizedMessage}}</li>
</ul>
</cnsl-info-section>
</div>
<div class="content" *ngIf="app?.oidcConfig">
<h3 class="full-width section-title">{{'APP.OIDC.REDIRECTSECTIONTITLE' | translate}}</h3>
<mat-slide-toggle color="primary" class="devmode" [formControl]="devMode" name="devMode"
matTooltip="{{'APP.OIDC.DEVMODEDESC' | translate}}">
{{ 'APP.OIDC.DEVMODE' | translate }}
</mat-slide-toggle>
<cnsl-info-section class="step-description" *ngIf="appType?.value == OIDCAppType.OIDC_APP_TYPE_NATIVE">
<span>{{'APP.OIDC.REDIRECTDESCRIPTIONNATIVE' | translate}}</span>
</cnsl-info-section>
<cnsl-info-section class="step-description"
*ngIf="OIDCAppType?.value == OIDCAppType.OIDC_APP_TYPE_WEB || appType?.value == OIDCAppType.OIDC_APP_TYPE_USER_AGENT">
{{'APP.OIDC.REDIRECTDESCRIPTIONWEB' | translate}}
</cnsl-info-section>
<div style="margin: .5rem" class="divider"></div>
<cnsl-redirect-uris *ngIf="appType?.value !== undefined" class="redirect-section" [canWrite]="canWrite"
[devMode]="devMode?.value" [getValues]="requestRedirectValuesSubject$"
(changedUris)="redirectUrisList = $event" [urisList]="redirectUrisList"
title="{{ 'APP.OIDC.REDIRECT' | translate }}"
[isNative]="appType?.value == OIDCAppType.OIDC_APP_TYPE_NATIVE">
</cnsl-redirect-uris>
<cnsl-redirect-uris *ngIf="appType?.value !== undefined" class="redirect-section" [canWrite]="canWrite"
[devMode]="devMode?.value" (changedUris)="postLogoutRedirectUrisList = $event"
[urisList]="postLogoutRedirectUrisList" [getValues]="requestRedirectValuesSubject$"
title="{{ 'APP.OIDC.POSTLOGOUTREDIRECT' | translate }}"
[isNative]="appType?.value == OIDCAppType.OIDC_APP_TYPE_NATIVE">
</cnsl-redirect-uris>
</div>
<app-auth-method-radio *ngIf="authMethods && initialAuthMethod && (app?.oidcConfig || app?.apiConfig)"
[authMethods]="authMethods" [selected]="initialAuthMethod" [current]="currentAuthMethod"
[isOIDC]="app?.oidcConfig !== undefined" (selectedMethod)="setPartialConfigFromAuthMethod($event)">
</app-auth-method-radio>
<app-card *ngIf="currentAuthMethod == 'PK_JWT' && projectId && app?.id" [expanded]="false"
title="{{ 'USER.MACHINE.KEYSTITLE' | translate }}" description="{{ 'USER.MACHINE.KEYSDESC' | translate }}">
<app-client-keys [projectId]="projectId" [appId]="app.id"></app-client-keys>
</app-card>
<div *ngIf="oidcForm && app?.apiConfig" class="btn-container">
<button class="submit-button" (click)="saveAPIApp()" color="primary"
[disabled]="apiForm.invalid || !canWrite" mat-raised-button>
{{ 'ACTIONS.SAVE' | translate }}
</button>
</div>
<div *ngIf="currentAuthMethod == 'BASIC'">
<button [disabled]="!canWrite" mat-stroked-button
(click)="regenerateAPIClientSecret()">{{'APP.API.REGENERATESECRET' | translate}}</button>
</div>
<form *ngIf="oidcForm && app?.oidcConfig" [formGroup]="oidcForm" (ngSubmit)="saveOIDCApp()">
<app-card title=" {{ 'APP.OIDC.TITLE' | translate }}" *ngIf="app && app.oidcConfig" [expanded]="false">
<div card-actions *ngIf="currentAuthMethod == 'CODE' || currentAuthMethod == 'POST'">
<button type="button" [disabled]="!canWrite" mat-stroked-button
(click)="regenerateOIDCClientSecret()">{{'APP.OIDC.REGENERATESECRET' | translate}}</button>
</div>
<div class="content">
<cnsl-form-field class="formfield" appearance="outline">
<cnsl-label>{{ 'APP.OIDC.CLIENTID' | translate }}</cnsl-label>
<input cnslInput formControlName="clientId" />
</cnsl-form-field>
<cnsl-form-field class="formfield" appearance="outline">
<cnsl-label>{{ 'APP.OIDC.RESPONSETYPE' | translate }}</cnsl-label>
<mat-select formControlName="responseTypesList" multiple>
<mat-option *ngFor="let type of oidcResponseTypes" [value]="type">
{{ 'APP.OIDC.RESPONSE.'+type | translate }}
</mat-option>
</mat-select>
</cnsl-form-field>
<cnsl-form-field class="formfield" appearance="outline">
<cnsl-label>{{ 'APP.OIDC.GRANTTYPE' | translate }}</cnsl-label>
<mat-select formControlName="grantTypesList" multiple>
<mat-option *ngFor="let grant of oidcGrantTypes" [value]="grant">
{{ 'APP.OIDC.GRANT.'+grant | translate }}
</mat-option>
</mat-select>
</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 type of oidcAppTypes" [value]="type">
{{ 'APP.OIDC.APPTYPE.'+type | translate }}
</mat-option>
</mat-select>
</cnsl-form-field>
<cnsl-form-field appearance="outline" class="formfield">
<cnsl-label>{{ 'APP.AUTHMETHOD' | translate }}</cnsl-label>
<mat-select formControlName="authMethodType">
<mat-option *ngFor="let type of oidcAuthMethodType" [value]="type">
{{ 'APP.OIDC.AUTHMETHOD.'+type | translate }}
</mat-option>
</mat-select>
</cnsl-form-field>
<div class="divider"></div>
<p class="full-width section-title">{{'APP.OIDC.TOKENSECTIONTITLE' | translate}}</p>
<cnsl-form-field appearance="outline" class="formfield">
<cnsl-label>{{ 'APP.OIDC.TOKENTYPE' | translate }}</cnsl-label>
<mat-select formControlName="accessTokenType">
<mat-option *ngFor="let type of oidcTokenTypes" [value]="type">
{{ 'APP.OIDC.TOKENTYPE'+type | translate }}
</mat-option>
</mat-select>
</cnsl-form-field>
<mat-checkbox *ngIf="accessTokenType?.value === OIDCTokenType.OIDCTOKENTYPE_JWT" class="full-width"
formControlName="accessTokenRoleAssertion" color="primary">
{{'APP.OIDC.ACCESSTOKENROLEASSERTION' | translate}}</mat-checkbox>
<cnsl-info-section class="full-width desc">
<span>{{'APP.OIDC.ACCESSTOKENROLEASSERTION_DESCRIPTION' | translate}}</span>
</cnsl-info-section>
<mat-checkbox class="full-width" style="margin-bottom: .5rem" formControlName="idTokenRoleAssertion"
color="primary">
{{'APP.OIDC.IDTOKENROLEASSERTION' | translate}}</mat-checkbox>
<cnsl-info-section class="full-width desc">
<span>{{'APP.OIDC.IDTOKENROLEASSERTION_DESCRIPTION' | translate}}</span>
</cnsl-info-section>
<mat-checkbox class="full-width" style="margin-bottom: .5rem"
formControlName="idTokenUserinfoAssertion" color="primary">
{{'APP.OIDC.IDTOKENUSERINFOASSERTION' | translate}}</mat-checkbox>
<cnsl-info-section class="full-width desc">
<span>{{'APP.OIDC.IDTOKENUSERINFOASSERTION_DESCRIPTION' | translate}}</span>
</cnsl-info-section>
<p class="clockskew-title">ClockSkew</p>
<mat-slider color="primary" formControlName="clockSkewSeconds" class="clockskew-slider" thumbLabel
[displayWith]="formatClockSkewLabel" tickInterval=".1" min="0" [step]="1" max="5">
</mat-slider>
<cnsl-info-section class="full-width desc">
<span>{{'APP.OIDC.CLOCKSKEW' | translate}}</span>
</cnsl-info-section>
</div>
</app-card>
<div class="btn-container">
<button class="submit-button" type="submit" color="primary" [disabled]="oidcForm.invalid || !canWrite"
mat-raised-button>
{{ 'ACTIONS.SAVE' | translate }}
</button>
</div>
</form>
<cnsl-links [links]="nextLinks"></cnsl-links>
</div>
<div class="side" metainfo>
<div class="meta-details">
<div class="meta-row">
<span class="first">{{'RESOURCEID' | translate}}:</span>
<span *ngIf="app?.id" class="second">{{ app.id }}</span>
</div>
<div class="meta-row">
<span class="first">{{'PROJECT.STATE.TITLE' | translate}}:</span>
<span *ngIf="app && app.state !== undefined"
[ngClass]="{'active': app.state === AppState.APP_STATE_ACTIVE, 'inactive': app.state === AppState.APP_STATE_INACTIVE}"
class="state">{{'APP.PAGES.DETAIL.STATE.'+app.state | translate}}</span>
</div>
</div>
<app-changes *ngIf="app" [changeType]="ChangeType.APP" [id]="app.id" [secId]="projectId"></app-changes>
</div>
</app-meta-layout>