mirror of
https://github.com/andwati/zitadel.git
synced 2026-11-14 09:55:12 +00:00
fix(console): text color shades, ui fixes, state handle restore (#3698)
* common project grant dialog, info box, label policy * text styles, statehandler fix * dialog, btn alignment, i18n * search-user theme colors * filter formfield sizing * redirect uris * shortcut layout * settings grid type rest, shortcuts linking * login policy, reset button consistency, metadata * permission checks
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
<cnsl-top-view
|
||||
title="{{ app?.name }}"
|
||||
[hasActions]="isZitadel === false && (['project.app.write:' + projectId, 'project.app.write'] | hasRole | async)"
|
||||
docLink="https://docs.zitadel.ch/docs/guides/basics/projects"
|
||||
docLink="https://docs.zitadel.com/docs/guides/basics/projects"
|
||||
[sub]="app?.oidcConfig ? ('APP.OIDC.APPTYPE.' + app?.oidcConfig?.appType | translate) : 'API'"
|
||||
[isActive]="app?.state === AppState.APP_STATE_ACTIVE"
|
||||
[isInactive]="app?.state === AppState.APP_STATE_INACTIVE"
|
||||
|
||||
@@ -30,6 +30,11 @@
|
||||
}
|
||||
}
|
||||
|
||||
.redirect-section {
|
||||
display: block;
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
.app-desc {
|
||||
font-size: 14px;
|
||||
margin: 0;
|
||||
@@ -131,6 +136,7 @@
|
||||
display: flex;
|
||||
align-items: center;
|
||||
border: 1px solid if($is-dark-theme, rgba(#8795a1, 0.2), rgba(#8795a1, 0.2));
|
||||
color: white;
|
||||
border-radius: 0.5rem;
|
||||
padding: 0.5rem 1rem;
|
||||
margin-bottom: 1rem;
|
||||
|
||||
+2
-9
@@ -14,18 +14,11 @@
|
||||
</cnsl-auth-method-radio>
|
||||
</div>
|
||||
<div mat-dialog-actions class="action">
|
||||
<button color="primary" mat-stroked-button class="ok-button" (click)="closeDialog()">
|
||||
<button color="primary" mat-stroked-button (click)="closeDialog()">
|
||||
{{ 'ACTIONS.CLOSE' | translate }}
|
||||
</button>
|
||||
|
||||
<button
|
||||
[disabled]="!authmethod"
|
||||
cdkFocusInitial
|
||||
color="primary"
|
||||
mat-raised-button
|
||||
class="ok-button"
|
||||
(click)="closeDialogWithMethod()"
|
||||
>
|
||||
<button [disabled]="!authmethod" cdkFocusInitial color="primary" mat-raised-button (click)="closeDialogWithMethod()">
|
||||
{{ 'ACTIONS.SELECT' | translate }}
|
||||
</button>
|
||||
</div>
|
||||
|
||||
+1
-5
@@ -13,11 +13,7 @@ h1 {
|
||||
|
||||
.action {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
|
||||
.ok-button {
|
||||
margin-left: 0.5rem;
|
||||
}
|
||||
justify-content: space-between;
|
||||
|
||||
button {
|
||||
border-radius: 0.5rem;
|
||||
|
||||
@@ -1,27 +1,40 @@
|
||||
<form class="form" (ngSubmit)="add(redInput)" [attr.data-e2e]="'redirect-uris'">
|
||||
<cnsl-form-field class="formfield">
|
||||
<cnsl-label>{{ title }}</cnsl-label>
|
||||
<form class="redirect-uris-form" (ngSubmit)="add(redInput)" [attr.data-e2e]="'redirect-uris'">
|
||||
<cnsl-form-field class="formfield">
|
||||
<cnsl-label>{{ title }}</cnsl-label>
|
||||
|
||||
<input #redInput cnslInput placeholder="ex. https://" [formControl]="redirectControl">
|
||||
</cnsl-form-field>
|
||||
<button matTooltip="{{'ACTIONS.ADD' | translate}}" type="submit" mat-icon-button
|
||||
[disabled]="redirectControl.invalid || !canWrite">
|
||||
<mat-icon>add</mat-icon>
|
||||
</button>
|
||||
<input #redInput cnslInput placeholder="ex. https://" [formControl]="redirectControl" />
|
||||
</cnsl-form-field>
|
||||
<button
|
||||
matTooltip="{{ 'ACTIONS.ADD' | translate }}"
|
||||
type="submit"
|
||||
mat-icon-button
|
||||
[disabled]="redirectControl.invalid || !canWrite"
|
||||
>
|
||||
<mat-icon>add</mat-icon>
|
||||
</button>
|
||||
</form>
|
||||
|
||||
<div class="uri-list">
|
||||
<div *ngFor="let uri of urisList" class="uri-line">
|
||||
<span class="uri"
|
||||
[ngClass]="{'green': !devMode && uri?.startsWith('https://'), 'red': !devMode && !uri?.startsWith('https://')}">{{uri}}</span>
|
||||
<span class="fill-space"></span>
|
||||
<i *ngIf="!devMode && !(uri | redirect : isNative)" class="las la-exclamation red" [matTooltip]="isNative ? ('APP.OIDC.REDIRECTDESCRIPTIONNATIVE' | translate) : ('APP.OIDC.REDIRECTDESCRIPTIONWEB' | translate)"></i>
|
||||
<div class="redirect-uris-list">
|
||||
<div *ngFor="let uri of urisList" class="uri-line" [ngClass]="{ alert: !devMode && !(uri | redirect: isNative) }">
|
||||
<span
|
||||
class="uri"
|
||||
[ngClass]="{ green: !devMode && uri?.startsWith('https://'), red: !devMode && !uri?.startsWith('https://') }"
|
||||
>{{ uri }}</span
|
||||
>
|
||||
<span class="fill-space"></span>
|
||||
<i
|
||||
class="alerticon las la-exclamation red"
|
||||
[matTooltip]="
|
||||
isNative ? ('APP.OIDC.REDIRECTDESCRIPTIONNATIVE' | translate) : ('APP.OIDC.REDIRECTDESCRIPTIONWEB' | translate)
|
||||
"
|
||||
></i>
|
||||
|
||||
<button matTooltip="{{'ACTIONS.DELETE' | translate}}" mat-icon-button (click)="remove(uri)" class="icon-button">
|
||||
<mat-icon class="icon">cancel</mat-icon>
|
||||
</button>
|
||||
</div>
|
||||
<button matTooltip="{{ 'ACTIONS.DELETE' | translate }}" mat-icon-button (click)="remove(uri)" class="icon-button">
|
||||
<mat-icon class="icon">cancel</mat-icon>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<p *ngIf="redirectControl.value && redirectControl.invalid" class="error">
|
||||
{{'APP.OIDC.REDIRECTNOTVALID' | translate}}</p>
|
||||
<p *ngIf="redirectControl.value && redirectControl.invalid" class="redirect-uris-error">
|
||||
{{ 'APP.OIDC.REDIRECTNOTVALID' | translate }}
|
||||
</p>
|
||||
|
||||
@@ -1,4 +1,80 @@
|
||||
.form {
|
||||
@use '@angular/material' as mat;
|
||||
|
||||
@mixin redirect-uris-theme($theme) {
|
||||
$foreground: map-get($theme, foreground);
|
||||
$background: map-get($theme, background);
|
||||
$is-dark-theme: map-get($theme, is-dark);
|
||||
$warn: map-get($theme, warn);
|
||||
$warn-color: map-get($warn, 500);
|
||||
$button-text-color: map-get($foreground, text);
|
||||
$button-disabled-text-color: map-get($foreground, disabled-button);
|
||||
$divider-color: map-get($foreground, dividers);
|
||||
$secondary-text: map-get($foreground, secondary-text);
|
||||
|
||||
.redirect-uris-list {
|
||||
width: 100%;
|
||||
|
||||
.uri-line {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin: 0.5rem 0;
|
||||
padding: 0 0 0 0.75rem;
|
||||
border-radius: 4px;
|
||||
background: map-get($background, infosection);
|
||||
|
||||
.uri {
|
||||
font-family: Consolas, Monaco, 'Andale Mono', 'Ubuntu Mono', monospace;
|
||||
font-size: 14px;
|
||||
overflow-x: auto;
|
||||
}
|
||||
|
||||
.fill-space {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
i.green {
|
||||
font-size: 1rem;
|
||||
line-height: 35px;
|
||||
height: 30px;
|
||||
}
|
||||
|
||||
.icon-button {
|
||||
height: 30px;
|
||||
line-height: 30px;
|
||||
|
||||
.icon {
|
||||
font-size: 1rem;
|
||||
margin-bottom: 3px;
|
||||
}
|
||||
|
||||
&:not(:hover) {
|
||||
color: $secondary-text;
|
||||
}
|
||||
}
|
||||
|
||||
.alerticon {
|
||||
display: none;
|
||||
}
|
||||
|
||||
&.alert {
|
||||
background-color: map-get($background, alertinfosection);
|
||||
color: map-get($foreground, alertinfosection);
|
||||
|
||||
.alerticon {
|
||||
display: inline;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.redirect-uris-error {
|
||||
font-size: 13px;
|
||||
color: $warn-color;
|
||||
margin: 0 0.5rem 1.5rem 0.5rem;
|
||||
}
|
||||
}
|
||||
|
||||
.redirect-uris-form {
|
||||
display: flex;
|
||||
align-items: flex-end;
|
||||
min-width: 320px;
|
||||
@@ -12,52 +88,3 @@
|
||||
margin-right: -0.5rem;
|
||||
}
|
||||
}
|
||||
|
||||
.uri-list {
|
||||
margin: 0 0.5rem;
|
||||
width: 100%;
|
||||
|
||||
.uri-line {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
.uri {
|
||||
font-family: Consolas, Monaco, 'Andale Mono', 'Ubuntu Mono', monospace;
|
||||
font-size: 14px;
|
||||
overflow-x: auto;
|
||||
}
|
||||
|
||||
.fill-space {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
i.green {
|
||||
font-size: 1rem;
|
||||
line-height: 35px;
|
||||
height: 30px;
|
||||
}
|
||||
|
||||
i.red {
|
||||
font-size: 1.2rem;
|
||||
}
|
||||
|
||||
.icon-button {
|
||||
height: 30px;
|
||||
line-height: 30px;
|
||||
|
||||
.icon {
|
||||
font-size: 1rem !important;
|
||||
}
|
||||
|
||||
&:not(:hover) {
|
||||
color: var(--grey);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.error {
|
||||
font-size: 13px;
|
||||
color: var(--warn);
|
||||
margin: 0 0.5rem 1.5rem 0.5rem;
|
||||
}
|
||||
|
||||
+1
-1
@@ -11,7 +11,7 @@ import { ManagementService } from 'src/app/services/mgmt.service';
|
||||
})
|
||||
export class ApplicationGridComponent implements OnInit {
|
||||
@Input() public projectId: string = '';
|
||||
@Input() public disabled: boolean = false;
|
||||
@Input() public disabled: boolean = true;
|
||||
@Output() public changeView: EventEmitter<void> = new EventEmitter();
|
||||
public appsSubject: BehaviorSubject<App.AsObject[]> = new BehaviorSubject<App.AsObject[]>([]);
|
||||
private loadingSubject: BehaviorSubject<boolean> = new BehaviorSubject<boolean>(true);
|
||||
|
||||
+31
-8
@@ -6,7 +6,7 @@
|
||||
[isInactive]="project?.state === ProjectState.PROJECT_STATE_INACTIVE"
|
||||
[hasContributors]="true"
|
||||
stateTooltip="{{ 'PROJECT.STATE.' + project?.state | translate }}"
|
||||
[hasActions]="true"
|
||||
[hasActions]="['project.app.write:' + project?.id, 'project.app.write$'] | hasRole | async"
|
||||
>
|
||||
<ng-template topActions cnslHasRole [hasRole]="['project.write:' + projectId, 'project.write']">
|
||||
<button mat-menu-item (click)="openNameDialog()" aria-label="Edit project name" *ngIf="isZitadel === false">
|
||||
@@ -68,8 +68,13 @@
|
||||
<cnsl-meta-layout>
|
||||
<cnsl-sidenav [(ngModel)]="currentSetting" [settingsList]="settingsList" [queryParam]="'id'">
|
||||
<ng-container *ngIf="currentSetting === 'general' && project">
|
||||
<ng-template cnslHasRole [hasRole]="['project.app.read:' + project.id, 'project.app.read']">
|
||||
<cnsl-application-grid *ngIf="grid" [disabled]="isZitadel" (changeView)="grid = false" [projectId]="projectId">
|
||||
<ng-template cnslHasRole [hasRole]="['project.app.read:' + project.id, 'project.app.read$']">
|
||||
<cnsl-application-grid
|
||||
*ngIf="grid"
|
||||
[disabled]="isZitadel || (['project.app.write:' + project.id, 'project.app.write$'] | hasRole | async) === false"
|
||||
(changeView)="grid = false"
|
||||
[projectId]="projectId"
|
||||
>
|
||||
</cnsl-application-grid>
|
||||
<cnsl-card *ngIf="!grid" title="{{ 'PROJECT.APP.TITLE' | translate }}">
|
||||
<div class="card-actions" card-actions>
|
||||
@@ -77,7 +82,12 @@
|
||||
<i matTooltip="show grid view" class="las la-th-large"></i>
|
||||
</button>
|
||||
</div>
|
||||
<cnsl-applications [disabled]="isZitadel" [projectId]="projectId"></cnsl-applications>
|
||||
<cnsl-applications
|
||||
[disabled]="
|
||||
isZitadel || (['project.app.write:' + project.id, 'project.app.write$'] | hasRole | async) === false
|
||||
"
|
||||
[projectId]="projectId"
|
||||
></cnsl-applications>
|
||||
</cnsl-card>
|
||||
</ng-template>
|
||||
|
||||
@@ -111,7 +121,9 @@
|
||||
>
|
||||
{{ 'PROJECT.ROLE.ASSERTION' | translate }}</mat-checkbox
|
||||
>
|
||||
<p class="desc cnsl-secondary-text">{{ 'PROJECT.ROLE.ASSERTION_DESCRIPTION' | translate }}</p>
|
||||
<cnsl-info-section class="desc cnsl-secondary-text">{{
|
||||
'PROJECT.ROLE.ASSERTION_DESCRIPTION' | translate
|
||||
}}</cnsl-info-section>
|
||||
<mat-checkbox
|
||||
[(ngModel)]="project.projectRoleCheck"
|
||||
[disabled]="(['project.write$', 'project.write:' + project.id] | hasRole | async) === false"
|
||||
@@ -119,7 +131,9 @@
|
||||
>
|
||||
{{ 'PROJECT.ROLE.CHECK' | translate }}</mat-checkbox
|
||||
>
|
||||
<p class="desc cnsl-secondary-text">{{ 'PROJECT.ROLE.CHECK_DESCRIPTION' | translate }}</p>
|
||||
<cnsl-info-section class="desc cnsl-secondary-text">{{
|
||||
'PROJECT.ROLE.CHECK_DESCRIPTION' | translate
|
||||
}}</cnsl-info-section>
|
||||
<mat-checkbox
|
||||
[(ngModel)]="project.hasProjectCheck"
|
||||
[disabled]="(['project.write$', 'project.write:' + project.id] | hasRole | async) === false"
|
||||
@@ -127,10 +141,19 @@
|
||||
>
|
||||
{{ 'PROJECT.HAS_PROJECT' | translate }}</mat-checkbox
|
||||
>
|
||||
<p class="desc cnsl-secondary-text">{{ 'PROJECT.HAS_PROJECT_DESCRIPTION' | translate }}</p>
|
||||
<cnsl-info-section class="desc cnsl-secondary-text">{{
|
||||
'PROJECT.HAS_PROJECT_DESCRIPTION' | translate
|
||||
}}</cnsl-info-section>
|
||||
|
||||
<div class="project-detail-btn-container">
|
||||
<button mat-raised-button color="primary" (click)="saveProject()">{{ 'ACTIONS.SAVE' | translate }}</button>
|
||||
<button
|
||||
mat-raised-button
|
||||
[disabled]="(['project.app.write:' + project.id, 'project.app.write$'] | hasRole | async) === false"
|
||||
color="primary"
|
||||
(click)="saveProject()"
|
||||
>
|
||||
{{ 'ACTIONS.SAVE' | translate }}
|
||||
</button>
|
||||
</div>
|
||||
</cnsl-card>
|
||||
</ng-template>
|
||||
|
||||
+1
-1
@@ -55,5 +55,5 @@
|
||||
|
||||
.desc {
|
||||
font-size: 14px;
|
||||
margin-bottom: 2rem;
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
+2
@@ -19,6 +19,7 @@ import { CardModule } from 'src/app/modules/card/card.module';
|
||||
import { ChangesModule } from 'src/app/modules/changes/changes.module';
|
||||
import { ContributorsModule } from 'src/app/modules/contributors/contributors.module';
|
||||
import { InfoRowModule } from 'src/app/modules/info-row/info-row.module';
|
||||
import { InfoSectionModule } from 'src/app/modules/info-section/info-section.module';
|
||||
import { InputModule } from 'src/app/modules/input/input.module';
|
||||
import { MetaLayoutModule } from 'src/app/modules/meta-layout/meta-layout.module';
|
||||
import { PaginatorModule } from 'src/app/modules/paginator/paginator.module';
|
||||
@@ -71,6 +72,7 @@ import { OwnedProjectDetailComponent } from './owned-project-detail.component';
|
||||
TopViewModule,
|
||||
MatCheckboxModule,
|
||||
MatSelectModule,
|
||||
InfoSectionModule,
|
||||
MatMenuModule,
|
||||
MatProgressSpinnerModule,
|
||||
ChangesModule,
|
||||
|
||||
+72
-33
@@ -1,65 +1,104 @@
|
||||
<cnsl-detail-layout [hasBackButton]="true" title="{{ 'PROJECT.GRANT.DETAIL.TITLE' | translate }}">
|
||||
<p class="subinfo" sub>
|
||||
<span class="cnsl-secondary-text">{{ 'PROJECT.GRANT.DETAIL.DESC' | translate }}</span>
|
||||
<a mat-icon-button href="https://docs.zitadel.com/docs/concepts/structure/projects#granted-organizations"
|
||||
target="_blank">
|
||||
<a
|
||||
mat-icon-button
|
||||
href="https://docs.zitadel.com/docs/concepts/structure/projects#granted-organizations"
|
||||
target="_blank"
|
||||
>
|
||||
<i class="las la-info-circle"></i>
|
||||
</a>
|
||||
</p>
|
||||
|
||||
<div actions>
|
||||
<button class="actions-trigger-desk" mat-raised-button color="primary" [matMenuTriggerFor]="actions">
|
||||
<span>{{'ACTIONS.ACTIONS' | translate}}</span>
|
||||
<span>{{ 'ACTIONS.ACTIONS' | translate }}</span>
|
||||
<mat-icon class="icon">keyboard_arrow_down</mat-icon>
|
||||
</button>
|
||||
<button class="actions-trigger-mob" matTooltip="{{'ACTIONS.ACTIONS' | translate}}" mat-icon-button
|
||||
[matMenuTriggerFor]="actions">
|
||||
<button
|
||||
class="actions-trigger-mob"
|
||||
matTooltip="{{ 'ACTIONS.ACTIONS' | translate }}"
|
||||
mat-icon-button
|
||||
[matMenuTriggerFor]="actions"
|
||||
>
|
||||
<i class="las la-ellipsis-v"></i>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<mat-menu #actions="matMenu" xPosition="before">
|
||||
<button mat-menu-item *ngIf="grant?.state === ProjectGrantState.PROJECT_GRANT_STATE_ACTIVE"
|
||||
(click)="changeState(ProjectGrantState.PROJECT_GRANT_STATE_INACTIVE)">{{'USER.PAGES.DEACTIVATE' |
|
||||
translate}}</button>
|
||||
<button mat-menu-item *ngIf="grant?.state === ProjectGrantState.PROJECT_GRANT_STATE_INACTIVE"
|
||||
(click)="changeState(ProjectGrantState.PROJECT_GRANT_STATE_ACTIVE)">{{'USER.PAGES.REACTIVATE' |
|
||||
translate}}</button>
|
||||
<button
|
||||
mat-menu-item
|
||||
*ngIf="grant?.state === ProjectGrantState.PROJECT_GRANT_STATE_ACTIVE"
|
||||
(click)="changeState(ProjectGrantState.PROJECT_GRANT_STATE_INACTIVE)"
|
||||
>
|
||||
{{ 'USER.PAGES.DEACTIVATE' | translate }}
|
||||
</button>
|
||||
<button
|
||||
mat-menu-item
|
||||
*ngIf="grant?.state === ProjectGrantState.PROJECT_GRANT_STATE_INACTIVE"
|
||||
(click)="changeState(ProjectGrantState.PROJECT_GRANT_STATE_ACTIVE)"
|
||||
>
|
||||
{{ 'USER.PAGES.REACTIVATE' | translate }}
|
||||
</button>
|
||||
</mat-menu>
|
||||
|
||||
<div class="master-row">
|
||||
<div>
|
||||
|
||||
</div>
|
||||
<div></div>
|
||||
</div>
|
||||
|
||||
<cnsl-project-grant-illustration *ngIf="grant" [grantedProject]="grant" [projectRoleOptions]="projectRoleOptions"
|
||||
(roleRemoved)="removeRole($event)" (editRoleClicked)="editRoles()">
|
||||
<cnsl-project-grant-illustration
|
||||
*ngIf="grant && projectRoleOptions"
|
||||
[grantedProject]="grant"
|
||||
[projectRoleOptions]="projectRoleOptions"
|
||||
(roleRemoved)="removeRole($event)"
|
||||
(editRoleClicked)="editRoles()"
|
||||
>
|
||||
</cnsl-project-grant-illustration>
|
||||
|
||||
<h2 class="project-grant-h2">{{ 'PROJECT.GRANT.DETAIL.MEMBERTITLE' | translate }}</h2>
|
||||
<p class="desc max-width-description">{{ 'PROJECT.GRANT.DETAIL.MEMBERDESC' | translate }}</p>
|
||||
<p class="desc cnsl-secondary-text max-width-description">{{ 'PROJECT.GRANT.DETAIL.MEMBERDESC' | translate }}</p>
|
||||
|
||||
<cnsl-members-table *ngIf="grant" [dataSource]="dataSource"
|
||||
[canWrite]="['project.grant.member.write','project.grant.member.write:' + grant.grantId] | hasRole | async"
|
||||
[canDelete]="['project.grant.member.delete','project.grant.member.delete:' + grant.grantId] | hasRole | async"
|
||||
[memberRoleOptions]="memberRoleOptions" (updateRoles)="updateMemberRoles($event.member, $event.change)"
|
||||
(deleteMember)="removeProjectMember($event)" [factoryLoadFunc]="changePageFactory"
|
||||
(changedSelection)="selection = $event" [refreshTrigger]="changePage">
|
||||
<button class="cnsl-action-button" selectactions (click)="removeProjectMemberSelection()"
|
||||
[disabled]="(['project.grant.member.delete','project.grant.member.delete:' + grant.grantId] | hasRole | async) === false"
|
||||
matTooltip="{{'ORG_DETAIL.TABLE.DELETE' | translate}}" color="warn" mat-raised-button>
|
||||
<cnsl-members-table
|
||||
*ngIf="grant"
|
||||
[dataSource]="dataSource"
|
||||
[canWrite]="['project.grant.member.write', 'project.grant.member.write:' + grant.grantId] | hasRole | async"
|
||||
[canDelete]="['project.grant.member.delete', 'project.grant.member.delete:' + grant.grantId] | hasRole | async"
|
||||
[memberRoleOptions]="memberRoleOptions"
|
||||
(updateRoles)="updateMemberRoles($event.member, $event.change)"
|
||||
(deleteMember)="removeProjectMember($event)"
|
||||
[factoryLoadFunc]="changePageFactory"
|
||||
(changedSelection)="selection = $event"
|
||||
[refreshTrigger]="changePage"
|
||||
>
|
||||
<button
|
||||
class="cnsl-action-button"
|
||||
selectactions
|
||||
(click)="removeProjectMemberSelection()"
|
||||
[disabled]="
|
||||
(['project.grant.member.delete', 'project.grant.member.delete:' + grant.grantId] | hasRole | async) === false
|
||||
"
|
||||
matTooltip="{{ 'ORG_DETAIL.TABLE.DELETE' | translate }}"
|
||||
color="warn"
|
||||
mat-raised-button
|
||||
>
|
||||
<i class="las la-trash"></i>
|
||||
<span>{{'ACTIONS.SELECTIONDELETE' | translate}}</span>
|
||||
<span>{{ 'ACTIONS.SELECTIONDELETE' | translate }}</span>
|
||||
<cnsl-action-keys [type]="ActionKeysType.DELETE" (actionTriggered)="removeProjectMemberSelection()">
|
||||
</cnsl-action-keys>
|
||||
</button>
|
||||
<button class="cnsl-action-button" writeactions color="primary"
|
||||
[disabled]="(['project.grant.member.write','project.grant.member.write:' + grant.grantId] | hasRole | async) === false"
|
||||
(click)="openAddMember()" color="primary" mat-raised-button>
|
||||
<button
|
||||
class="cnsl-action-button"
|
||||
writeactions
|
||||
color="primary"
|
||||
[disabled]="
|
||||
(['project.grant.member.write', 'project.grant.member.write:' + grant.grantId] | hasRole | async) === false
|
||||
"
|
||||
(click)="openAddMember()"
|
||||
color="primary"
|
||||
mat-raised-button
|
||||
>
|
||||
<mat-icon class="icon">add</mat-icon>{{ 'ACTIONS.NEW' | translate }}
|
||||
<cnsl-action-keys (actionTriggered)="openAddMember()">
|
||||
</cnsl-action-keys>
|
||||
<cnsl-action-keys (actionTriggered)="openAddMember()"> </cnsl-action-keys>
|
||||
</button>
|
||||
</cnsl-members-table>
|
||||
</cnsl-detail-layout>
|
||||
</cnsl-detail-layout>
|
||||
|
||||
+48
-47
@@ -3,17 +3,15 @@ import { MatDialog } from '@angular/material/dialog';
|
||||
import { PageEvent } from '@angular/material/paginator';
|
||||
import { ActivatedRoute } from '@angular/router';
|
||||
import { ActionKeysType } from 'src/app/modules/action-keys/action-keys.component';
|
||||
import { CreationType, MemberCreateDialogComponent } from 'src/app/modules/add-member-dialog/member-create-dialog.component';
|
||||
import { UserGrantRoleDialogComponent } from 'src/app/modules/user-grant-role-dialog/user-grant-role-dialog.component';
|
||||
import { Member } from 'src/app/proto/generated/zitadel/member_pb';
|
||||
import { GrantedProject, ProjectGrantState, Role } from 'src/app/proto/generated/zitadel/project_pb';
|
||||
import { User } from 'src/app/proto/generated/zitadel/user_pb';
|
||||
import { Breadcrumb, BreadcrumbService, BreadcrumbType } from 'src/app/services/breadcrumb.service';
|
||||
import { ManagementService } from 'src/app/services/mgmt.service';
|
||||
import { ToastService } from 'src/app/services/toast.service';
|
||||
|
||||
import {
|
||||
ProjectGrantMembersCreateDialogComponent,
|
||||
ProjectGrantMembersCreateDialogExportType,
|
||||
} from './project-grant-members-create-dialog/project-grant-members-create-dialog.component';
|
||||
import { ProjectGrantMembersDataSource } from './project-grant-members-datasource';
|
||||
|
||||
@Component({
|
||||
@@ -69,25 +67,29 @@ export class ProjectGrantDetailComponent {
|
||||
);
|
||||
};
|
||||
|
||||
this.mgmtService.getProjectGrantByID(this.grantid, this.projectid).then((resp) => {
|
||||
if (resp.projectGrant) {
|
||||
this.grant = resp.projectGrant;
|
||||
this.mgmtService
|
||||
.getProjectGrantByID(this.grantid, this.projectid)
|
||||
.then((resp) => {
|
||||
console.log(resp);
|
||||
if (resp.projectGrant) {
|
||||
this.grant = resp.projectGrant;
|
||||
|
||||
const breadcrumbs = [
|
||||
new Breadcrumb({
|
||||
type: BreadcrumbType.ORG,
|
||||
routerLink: ['/org'],
|
||||
}),
|
||||
new Breadcrumb({
|
||||
type: BreadcrumbType.PROJECT,
|
||||
name: '',
|
||||
param: { key: 'projectid', value: resp.projectGrant.projectId },
|
||||
routerLink: ['/projects', resp.projectGrant.projectId],
|
||||
}),
|
||||
];
|
||||
this.breadcrumbService.setBreadcrumb(breadcrumbs);
|
||||
}
|
||||
});
|
||||
const breadcrumbs = [
|
||||
new Breadcrumb({
|
||||
type: BreadcrumbType.ORG,
|
||||
routerLink: ['/org'],
|
||||
}),
|
||||
new Breadcrumb({
|
||||
type: BreadcrumbType.PROJECT,
|
||||
name: '',
|
||||
param: { key: 'projectid', value: resp.projectGrant.projectId },
|
||||
routerLink: ['/projects', resp.projectGrant.projectId],
|
||||
}),
|
||||
];
|
||||
this.breadcrumbService.setBreadcrumb(breadcrumbs);
|
||||
}
|
||||
})
|
||||
.catch(this.toast.showError);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -176,36 +178,35 @@ export class ProjectGrantDetailComponent {
|
||||
}
|
||||
|
||||
public async openAddMember(): Promise<any> {
|
||||
const keysList = await this.mgmtService.listProjectGrantMemberRoles();
|
||||
|
||||
const dialogRef = this.dialog.open(ProjectGrantMembersCreateDialogComponent, {
|
||||
const dialogRef = this.dialog.open(MemberCreateDialogComponent, {
|
||||
data: {
|
||||
roleKeysList: keysList.resultList,
|
||||
creationType: CreationType.PROJECT_GRANTED,
|
||||
},
|
||||
width: '400px',
|
||||
});
|
||||
|
||||
dialogRef.afterClosed().subscribe((dataToAdd: ProjectGrantMembersCreateDialogExportType) => {
|
||||
if (dataToAdd) {
|
||||
Promise.all(
|
||||
dataToAdd.userIds.map((userid: string) => {
|
||||
return this.mgmtService.addProjectGrantMember(
|
||||
this.grant.projectId,
|
||||
this.grant.grantId,
|
||||
userid,
|
||||
dataToAdd.rolesKeyList,
|
||||
);
|
||||
}),
|
||||
)
|
||||
.then(() => {
|
||||
this.toast.showInfo('PROJECT.GRANT.TOAST.PROJECTGRANTMEMBERADDED', true);
|
||||
setTimeout(() => {
|
||||
this.changePage.emit();
|
||||
}, 3000);
|
||||
})
|
||||
.catch((error) => {
|
||||
this.toast.showError(error);
|
||||
});
|
||||
dialogRef.afterClosed().subscribe((resp) => {
|
||||
if (resp) {
|
||||
const users: User.AsObject[] = resp.users;
|
||||
const roles: string[] = resp.roles;
|
||||
|
||||
if (users && users.length && roles && roles.length) {
|
||||
const userIds = users.map((user) => user.id);
|
||||
Promise.all(
|
||||
userIds.map((userid: string) => {
|
||||
return this.mgmtService.addProjectGrantMember(this.grant.projectId, this.grant.grantId, userid, resp.roles);
|
||||
}),
|
||||
)
|
||||
.then(() => {
|
||||
this.toast.showInfo('PROJECT.GRANT.TOAST.PROJECTGRANTMEMBERADDED', true);
|
||||
setTimeout(() => {
|
||||
this.changePage.emit();
|
||||
}, 3000);
|
||||
})
|
||||
.catch((error) => {
|
||||
this.toast.showError(error);
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
+2
-4
@@ -15,6 +15,7 @@ import { MatTooltipModule } from '@angular/material/tooltip';
|
||||
import { TranslateModule } from '@ngx-translate/core';
|
||||
import { HasRoleModule } from 'src/app/directives/has-role/has-role.module';
|
||||
import { ActionKeysModule } from 'src/app/modules/action-keys/action-keys.module';
|
||||
import { MemberCreateDialogModule } from 'src/app/modules/add-member-dialog/member-create-dialog.module';
|
||||
import { DetailLayoutModule } from 'src/app/modules/detail-layout/detail-layout.module';
|
||||
import { InputModule } from 'src/app/modules/input/input.module';
|
||||
import { MembersTableModule } from 'src/app/modules/members-table/members-table.module';
|
||||
@@ -25,16 +26,12 @@ import { HasRolePipeModule } from 'src/app/pipes/has-role-pipe/has-role-pipe.mod
|
||||
import { ProjectGrantDetailRoutingModule } from './project-grant-detail-routing.module';
|
||||
import { ProjectGrantDetailComponent } from './project-grant-detail.component';
|
||||
import { ProjectGrantIllustrationComponent } from './project-grant-illustration/project-grant-illustration.component';
|
||||
import {
|
||||
ProjectGrantMembersCreateDialogModule,
|
||||
} from './project-grant-members-create-dialog/project-grant-members-create-dialog.module';
|
||||
|
||||
@NgModule({
|
||||
declarations: [ProjectGrantDetailComponent, ProjectGrantIllustrationComponent],
|
||||
imports: [
|
||||
CommonModule,
|
||||
ProjectGrantDetailRoutingModule,
|
||||
ProjectGrantMembersCreateDialogModule,
|
||||
MatAutocompleteModule,
|
||||
HasRoleModule,
|
||||
MatChipsModule,
|
||||
@@ -54,6 +51,7 @@ import {
|
||||
TranslateModule,
|
||||
MatSelectModule,
|
||||
DetailLayoutModule,
|
||||
MemberCreateDialogModule,
|
||||
HasRolePipeModule,
|
||||
MembersTableModule,
|
||||
MatDialogModule,
|
||||
|
||||
-1
@@ -13,7 +13,6 @@ export class ProjectGrantIllustrationComponent {
|
||||
@Output() public editRoleClicked: EventEmitter<void> = new EventEmitter();
|
||||
|
||||
ProjectGrantState: any = ProjectGrantState;
|
||||
constructor() {}
|
||||
|
||||
public removeRole(roleKey: string): void {
|
||||
this.roleRemoved.emit(roleKey);
|
||||
|
||||
-27
@@ -1,27 +0,0 @@
|
||||
<h1 mat-dialog-title>
|
||||
<span class="title">{{'MEMBER.ADD' | translate}}</span>
|
||||
</h1>
|
||||
<p class="desc"> {{'ORG_DETAIL.MEMBER.ADDDESCRIPTION' | translate}}</p>
|
||||
<div mat-dialog-content>
|
||||
<cnsl-search-user-autocomplete (selectionChanged)="selectUsers($event)">
|
||||
</cnsl-search-user-autocomplete>
|
||||
|
||||
<cnsl-form-field class="full-width" appearance="outline">
|
||||
<cnsl-label>{{ 'PROJECT.MEMBER.ROLES' | translate }}</cnsl-label>
|
||||
<mat-select [(ngModel)]="roleKeyList" multiple>
|
||||
<mat-option *ngFor="let key of data.roleKeysList" [value]="key">
|
||||
{{ key }}
|
||||
</mat-option>
|
||||
</mat-select>
|
||||
</cnsl-form-field>
|
||||
</div>
|
||||
<div mat-dialog-actions class="action">
|
||||
<button mat-stroked-button (click)="closeDialog()">
|
||||
{{'ACTIONS.CANCEL' | translate}}
|
||||
</button>
|
||||
|
||||
<button [disabled]="userIds.length === 0 || roleKeyList.length === 0" color="primary" mat-raised-button
|
||||
class="ok-button" (click)="closeDialogWithSuccess()">
|
||||
{{'ACTIONS.ADD' | translate}}
|
||||
</button>
|
||||
</div>
|
||||
-12
@@ -1,12 +0,0 @@
|
||||
.full-width {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.action {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
|
||||
.ok-button {
|
||||
margin-left: .5rem;
|
||||
}
|
||||
}
|
||||
-25
@@ -1,25 +0,0 @@
|
||||
import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';
|
||||
|
||||
import { ProjectGrantMembersCreateDialogComponent } from './project-grant-members-create-dialog.component';
|
||||
|
||||
describe('ProjectGrantMembersCreateDialogComponent', () => {
|
||||
let component: ProjectGrantMembersCreateDialogComponent;
|
||||
let fixture: ComponentFixture<ProjectGrantMembersCreateDialogComponent>;
|
||||
|
||||
beforeEach(waitForAsync(() => {
|
||||
TestBed.configureTestingModule({
|
||||
declarations: [ProjectGrantMembersCreateDialogComponent],
|
||||
})
|
||||
.compileComponents();
|
||||
}));
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(ProjectGrantMembersCreateDialogComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
||||
-42
@@ -1,42 +0,0 @@
|
||||
import { Component, Inject } from '@angular/core';
|
||||
import { FormGroup } from '@angular/forms';
|
||||
import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog';
|
||||
import { User } from 'src/app/proto/generated/zitadel/user_pb';
|
||||
|
||||
export interface ProjectGrantMembersCreateDialogExportType {
|
||||
userIds: string[];
|
||||
rolesKeyList: string[];
|
||||
}
|
||||
@Component({
|
||||
selector: 'cnsl-project-grant-members-create-dialog',
|
||||
templateUrl: './project-grant-members-create-dialog.component.html',
|
||||
styleUrls: ['./project-grant-members-create-dialog.component.scss'],
|
||||
})
|
||||
export class ProjectGrantMembersCreateDialogComponent {
|
||||
public form!: FormGroup;
|
||||
public userIds: string[] = [];
|
||||
public roleKeyList: string[] = [];
|
||||
|
||||
constructor(
|
||||
public dialogRef: MatDialogRef<ProjectGrantMembersCreateDialogComponent>,
|
||||
@Inject(MAT_DIALOG_DATA) public data: any,
|
||||
) { }
|
||||
|
||||
public selectUsers(users: User.AsObject | User.AsObject[]): void {
|
||||
if (Array.isArray(users)) {
|
||||
this.userIds = users.map(user => user.id);
|
||||
}
|
||||
}
|
||||
|
||||
public closeDialog(): void {
|
||||
this.dialogRef.close(false);
|
||||
}
|
||||
|
||||
public closeDialogWithSuccess(): void {
|
||||
const exportData: ProjectGrantMembersCreateDialogExportType = {
|
||||
userIds: this.userIds,
|
||||
rolesKeyList: this.roleKeyList,
|
||||
};
|
||||
this.dialogRef.close(exportData);
|
||||
}
|
||||
}
|
||||
-27
@@ -1,27 +0,0 @@
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { NgModule } from '@angular/core';
|
||||
import { FormsModule } from '@angular/forms';
|
||||
import { MatButtonModule } from '@angular/material/button';
|
||||
import { MatDialogModule } from '@angular/material/dialog';
|
||||
import { MatSelectModule } from '@angular/material/select';
|
||||
import { TranslateModule } from '@ngx-translate/core';
|
||||
import { InputModule } from 'src/app/modules/input/input.module';
|
||||
import { SearchUserAutocompleteModule } from 'src/app/modules/search-user-autocomplete/search-user-autocomplete.module';
|
||||
|
||||
import { ProjectGrantMembersCreateDialogComponent } from './project-grant-members-create-dialog.component';
|
||||
|
||||
@NgModule({
|
||||
declarations: [ProjectGrantMembersCreateDialogComponent],
|
||||
imports: [
|
||||
CommonModule,
|
||||
FormsModule,
|
||||
MatDialogModule,
|
||||
MatButtonModule,
|
||||
TranslateModule,
|
||||
MatSelectModule,
|
||||
InputModule,
|
||||
SearchUserAutocompleteModule,
|
||||
],
|
||||
})
|
||||
export class ProjectGrantMembersCreateDialogModule { }
|
||||
|
||||
@@ -1,4 +1,9 @@
|
||||
<cnsl-create-layout title="{{ 'PROJECT.PAGES.CREATE' | translate }}" [createSteps]="1" [currentCreateStep]="1">
|
||||
<cnsl-create-layout
|
||||
title="{{ 'PROJECT.PAGES.CREATE' | translate }}"
|
||||
[createSteps]="1"
|
||||
[currentCreateStep]="1"
|
||||
(closed)="close()"
|
||||
>
|
||||
<h1>{{ 'PROJECT.PAGES.CREATE_DESC' | translate }}</h1>
|
||||
<form cdkFocusRegionStart (ngSubmit)="saveProject()">
|
||||
<div class="column">
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
}
|
||||
|
||||
.sub {
|
||||
margin-bottom: 2rem;
|
||||
margin-bottom: 1.5rem;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
@@ -38,7 +38,7 @@
|
||||
opacity: 0.6;
|
||||
font-size: 15px;
|
||||
cursor: pointer;
|
||||
color: map-get($foreground, base);
|
||||
color: map-get($foreground, text);
|
||||
|
||||
&:first-child {
|
||||
margin-right: 1rem;
|
||||
|
||||
Reference in New Issue
Block a user