mirror of
https://github.com/zitadel/zitadel.git
synced 2024-12-12 02:54:20 +00:00
fix(console): permission regex, account switcher null check, restrict app and member create access (#821)
* fix member table disable, gerneal regexp * fix user session card, app disable * memberships max count * fix policy permissions * permission check for member add dialog * lint * rm accounts log * rm id regex
This commit is contained in:
parent
8fe635d3fd
commit
010a5815f4
@ -1,5 +1,5 @@
|
|||||||
<ng-container *ngIf="(authService.user | async) || {} as user">
|
<ng-container *ngIf="(authService.user | async) || {} as user">
|
||||||
<ng-container *ngIf="((['iam.read','iam.write'] | hasRole)) as iamuser$">
|
<ng-container *ngIf="((['iam.read$','iam.write$'] | hasRole)) as iamuser$">
|
||||||
<mat-toolbar class="root-header">
|
<mat-toolbar class="root-header">
|
||||||
<button aria-label="Toggle sidenav" mat-icon-button (click)="drawer.toggle()">
|
<button aria-label="Toggle sidenav" mat-icon-button (click)="drawer.toggle()">
|
||||||
<i class="icon las la-bars"></i>
|
<i class="icon las la-bars"></i>
|
||||||
|
@ -21,7 +21,9 @@ export class AccountsCardComponent implements OnInit {
|
|||||||
this.userService.getMyUserSessions().then(sessions => {
|
this.userService.getMyUserSessions().then(sessions => {
|
||||||
this.users = sessions.toObject().userSessionsList;
|
this.users = sessions.toObject().userSessionsList;
|
||||||
const index = this.users.findIndex(user => user.loginName === this.profile.preferredLoginName);
|
const index = this.users.findIndex(user => user.loginName === this.profile.preferredLoginName);
|
||||||
this.users.splice(index, 1);
|
if (index > -1) {
|
||||||
|
this.users.splice(index, 1);
|
||||||
|
}
|
||||||
|
|
||||||
this.loadingUsers = false;
|
this.loadingUsers = false;
|
||||||
}).catch(() => {
|
}).catch(() => {
|
||||||
|
@ -9,8 +9,9 @@
|
|||||||
<mat-form-field class="full-width" appearance="outline">
|
<mat-form-field class="full-width" appearance="outline">
|
||||||
<mat-label>{{ 'MEMBER.CREATIONTYPE' | translate }}</mat-label>
|
<mat-label>{{ 'MEMBER.CREATIONTYPE' | translate }}</mat-label>
|
||||||
<mat-select [(ngModel)]="creationType" (selectionChange)="loadRoles()">
|
<mat-select [(ngModel)]="creationType" (selectionChange)="loadRoles()">
|
||||||
<mat-option *ngFor="let type of creationTypes" [value]="type">
|
<mat-option *ngFor="let type of creationTypes" [value]="type.type"
|
||||||
{{ 'MEMBER.CREATIONTYPES.'+type | translate}}
|
[disabled]="(type.disabled$ | async) == false">
|
||||||
|
{{ 'MEMBER.CREATIONTYPES.'+type.type | translate}}
|
||||||
</mat-option>
|
</mat-option>
|
||||||
</mat-select>
|
</mat-select>
|
||||||
</mat-form-field>
|
</mat-form-field>
|
||||||
|
@ -1,7 +1,9 @@
|
|||||||
import { Component, Inject } from '@angular/core';
|
import { Component, Inject } from '@angular/core';
|
||||||
import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog';
|
import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog';
|
||||||
|
import { Observable } from 'rxjs';
|
||||||
import { ProjectGrantView, ProjectRole, ProjectView, UserView } from 'src/app/proto/generated/management_pb';
|
import { ProjectGrantView, ProjectRole, ProjectView, UserView } from 'src/app/proto/generated/management_pb';
|
||||||
import { AdminService } from 'src/app/services/admin.service';
|
import { AdminService } from 'src/app/services/admin.service';
|
||||||
|
import { GrpcAuthService } from 'src/app/services/grpc-auth.service';
|
||||||
import { ManagementService } from 'src/app/services/mgmt.service';
|
import { ManagementService } from 'src/app/services/mgmt.service';
|
||||||
import { ToastService } from 'src/app/services/toast.service';
|
import { ToastService } from 'src/app/services/toast.service';
|
||||||
|
|
||||||
@ -24,11 +26,17 @@ export class MemberCreateDialogComponent {
|
|||||||
public preselectedUsers: Array<UserView.AsObject> = [];
|
public preselectedUsers: Array<UserView.AsObject> = [];
|
||||||
|
|
||||||
public creationType!: CreationType;
|
public creationType!: CreationType;
|
||||||
public creationTypes: CreationType[] = [
|
|
||||||
CreationType.IAM,
|
/**
|
||||||
CreationType.ORG,
|
* Specifies options for creating members,
|
||||||
CreationType.PROJECT_OWNED,
|
* without ending $, to enable write event permission even if user is allowed
|
||||||
CreationType.PROJECT_GRANTED,
|
* to create members for only one specific project.
|
||||||
|
*/
|
||||||
|
public creationTypes: Array<{ type: CreationType, disabled$: Observable<boolean>; }> = [
|
||||||
|
{ type: CreationType.IAM, disabled$: this.authService.isAllowed(['iam.member.write$']) },
|
||||||
|
{ type: CreationType.ORG, disabled$: this.authService.isAllowed(['org.member.write$']) },
|
||||||
|
{ type: CreationType.PROJECT_OWNED, disabled$: this.authService.isAllowed(['project.member.write']) },
|
||||||
|
{ type: CreationType.PROJECT_GRANTED, disabled$: this.authService.isAllowed(['project.grant.member.write']) },
|
||||||
];
|
];
|
||||||
public users: Array<UserView.AsObject> = [];
|
public users: Array<UserView.AsObject> = [];
|
||||||
public roles: Array<ProjectRole.AsObject> | string[] = [];
|
public roles: Array<ProjectRole.AsObject> | string[] = [];
|
||||||
@ -40,6 +48,7 @@ export class MemberCreateDialogComponent {
|
|||||||
constructor(
|
constructor(
|
||||||
private mgmtService: ManagementService,
|
private mgmtService: ManagementService,
|
||||||
private adminService: AdminService,
|
private adminService: AdminService,
|
||||||
|
private authService: GrpcAuthService,
|
||||||
public dialogRef: MatDialogRef<MemberCreateDialogComponent>,
|
public dialogRef: MatDialogRef<MemberCreateDialogComponent>,
|
||||||
@Inject(MAT_DIALOG_DATA) public data: any,
|
@Inject(MAT_DIALOG_DATA) public data: any,
|
||||||
private toastService: ToastService,
|
private toastService: ToastService,
|
||||||
|
@ -13,13 +13,13 @@
|
|||||||
<table mat-table class="table" aria-label="Elements" [dataSource]="dataSource">
|
<table mat-table class="table" aria-label="Elements" [dataSource]="dataSource">
|
||||||
<ng-container matColumnDef="select">
|
<ng-container matColumnDef="select">
|
||||||
<th class="selection" mat-header-cell *matHeaderCellDef>
|
<th class="selection" mat-header-cell *matHeaderCellDef>
|
||||||
<mat-checkbox color="primary" (change)="$event ? masterToggle() : null"
|
<mat-checkbox [disabled]="!canWrite" color="primary" (change)="$event ? masterToggle() : null"
|
||||||
[checked]="selection.hasValue() && isAllSelected()"
|
[checked]="selection.hasValue() && isAllSelected()"
|
||||||
[indeterminate]="selection.hasValue() && !isAllSelected()">
|
[indeterminate]="selection.hasValue() && !isAllSelected()">
|
||||||
</mat-checkbox>
|
</mat-checkbox>
|
||||||
</th>
|
</th>
|
||||||
<td class="selection" mat-cell *matCellDef="let row">
|
<td class="selection" mat-cell *matCellDef="let row">
|
||||||
<mat-checkbox color="primary" (click)="$event.stopPropagation()"
|
<mat-checkbox [disabled]="!canWrite" color="primary" (click)="$event.stopPropagation()"
|
||||||
(change)="$event ? selection.toggle(row) : null" [checked]="selection.isSelected(row)">
|
(change)="$event ? selection.toggle(row) : null" [checked]="selection.isSelected(row)">
|
||||||
<app-avatar *ngIf="row?.displayName && row.firstName && row.lastName; else cog" class="avatar"
|
<app-avatar *ngIf="row?.displayName && row.firstName && row.lastName; else cog" class="avatar"
|
||||||
[name]="row.displayName" [size]="32">
|
[name]="row.displayName" [size]="32">
|
||||||
@ -77,7 +77,7 @@
|
|||||||
<td mat-cell *matCellDef="let member">
|
<td mat-cell *matCellDef="let member">
|
||||||
<mat-form-field class="form-field" appearance="outline">
|
<mat-form-field class="form-field" appearance="outline">
|
||||||
<mat-label>{{ 'ROLESLABEL' | translate }}</mat-label>
|
<mat-label>{{ 'ROLESLABEL' | translate }}</mat-label>
|
||||||
<mat-select [(ngModel)]="member.rolesList" multiple [disabled]="disableWrite"
|
<mat-select [(ngModel)]="member.rolesList" multiple [disabled]="!canWrite"
|
||||||
(selectionChange)="updateRoles.emit({member: member, change: $event})">
|
(selectionChange)="updateRoles.emit({member: member, change: $event})">
|
||||||
<mat-option *ngFor="let role of memberRoleOptions" [value]="role">
|
<mat-option *ngFor="let role of memberRoleOptions" [value]="role">
|
||||||
{{ role }}
|
{{ role }}
|
||||||
|
@ -22,8 +22,8 @@ type MemberDatasource = OrgMembersDataSource | ProjectMembersDataSource | IamMem
|
|||||||
})
|
})
|
||||||
export class MembersTableComponent implements OnInit, OnDestroy {
|
export class MembersTableComponent implements OnInit, OnDestroy {
|
||||||
public INITIALPAGESIZE: number = 25;
|
public INITIALPAGESIZE: number = 25;
|
||||||
@Input() public disableWrite: boolean = false;
|
|
||||||
@Input() public canDelete: boolean = false;
|
@Input() public canDelete: boolean = false;
|
||||||
|
@Input() public canWrite: boolean = false;
|
||||||
@ViewChild(MatPaginator) public paginator!: MatPaginator;
|
@ViewChild(MatPaginator) public paginator!: MatPaginator;
|
||||||
@ViewChild(MatTable) public table!: MatTable<View>;
|
@ViewChild(MatTable) public table!: MatTable<View>;
|
||||||
@Input() public dataSource!: MemberDatasource;
|
@Input() public dataSource!: MemberDatasource;
|
||||||
|
@ -1,11 +1,11 @@
|
|||||||
<app-detail-layout [backRouterLink]="backroutes" [title]="'ORG.POLICY.LOGIN_POLICY.TITLECREATE' | translate"
|
<app-detail-layout [backRouterLink]="backroutes" [title]="'ORG.POLICY.LOGIN_POLICY.TITLECREATE' | translate"
|
||||||
[description]="(serviceType==PolicyComponentServiceType.MGMT ? 'ORG.POLICY.LOGIN_POLICY.DESCRIPTIONCREATEMGMT' : PolicyComponentServiceType.ADMIN ? 'ORG.POLICY.LOGIN_POLICY.DESCRIPTIONCREATEADMIN' : '') | translate">
|
[description]="(serviceType==PolicyComponentServiceType.MGMT ? 'ORG.POLICY.LOGIN_POLICY.DESCRIPTIONCREATEMGMT' : PolicyComponentServiceType.ADMIN ? 'ORG.POLICY.LOGIN_POLICY.DESCRIPTIONCREATEADMIN' : '') | translate">
|
||||||
<ng-container *ngIf="(['policy.delete'] | hasRole | async) && serviceType == PolicyComponentServiceType.MGMT">
|
<!--<ng-container *ngIf="(['policy.delete'] | hasRole | async) && serviceType == PolicyComponentServiceType.MGMT">
|
||||||
<!--<button matTooltip="{{'ORG.POLICY.DELETE' | translate}}" color="warn" (click)="deletePolicy()"
|
<button matTooltip="{{'ORG.POLICY.DELETE' | translate}}" color="warn" (click)="deletePolicy()"
|
||||||
mat-stroked-button>
|
mat-stroked-button>
|
||||||
{{'ORG.POLICY.DELETE' | translate}}
|
{{'ORG.POLICY.DELETE' | translate}}
|
||||||
</button>-->
|
</button>
|
||||||
</ng-container>
|
</ng-container>-->
|
||||||
|
|
||||||
<div class="content" *ngIf="loginData">
|
<div class="content" *ngIf="loginData">
|
||||||
<div class="row">
|
<div class="row">
|
||||||
@ -56,7 +56,7 @@
|
|||||||
<ng-template appHasRole [appHasRole]="['org.idp.read']">
|
<ng-template appHasRole [appHasRole]="['org.idp.read']">
|
||||||
<app-card title="{{ 'IDP.LIST.TITLE' | translate }}" description="{{ 'IDP.LIST.DESCRIPTION' | translate }}">
|
<app-card title="{{ 'IDP.LIST.TITLE' | translate }}" description="{{ 'IDP.LIST.DESCRIPTION' | translate }}">
|
||||||
<app-idp-table [service]="service" [serviceType]="serviceType"
|
<app-idp-table [service]="service" [serviceType]="serviceType"
|
||||||
[disabled]="(['iam.idp.write'] | hasRole | async) == false">
|
[disabled]="(['iam.idp.write$'] | hasRole | async) == false">
|
||||||
</app-idp-table>
|
</app-idp-table>
|
||||||
</app-card>
|
</app-card>
|
||||||
</ng-template>
|
</ng-template>
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
<app-detail-layout [backRouterLink]="[ '/org']" [title]="title ? (title | translate) : ''"
|
<app-detail-layout [backRouterLink]="[ '/org']" [title]="title ? (title | translate) : ''"
|
||||||
[description]="desc ? (desc | translate) : ''">
|
[description]="desc ? (desc | translate) : ''">
|
||||||
<ng-template appHasRole [appHasRole]="['iam.policy.write']">
|
<ng-template appHasRole [appHasRole]="['policy.write$']">
|
||||||
<button matTooltip="{{'ORG.POLICY.DELETE' | translate}}" color="warn" (click)="deletePolicy()"
|
<button matTooltip="{{'ORG.POLICY.DELETE' | translate}}" color="warn" (click)="deletePolicy()"
|
||||||
mat-stroked-button>
|
mat-stroked-button>
|
||||||
{{'ORG.POLICY.DELETE' | translate}}
|
{{'ORG.POLICY.DELETE' | translate}}
|
||||||
|
@ -4,7 +4,8 @@
|
|||||||
<app-members-table *ngIf="project" [dataSource]="dataSource" [memberRoleOptions]="memberRoleOptions"
|
<app-members-table *ngIf="project" [dataSource]="dataSource" [memberRoleOptions]="memberRoleOptions"
|
||||||
(updateRoles)="updateRoles($event.member, $event.change)" [factoryLoadFunc]="changePageFactory"
|
(updateRoles)="updateRoles($event.member, $event.change)" [factoryLoadFunc]="changePageFactory"
|
||||||
(changedSelection)="selection = $event" [refreshTrigger]="changePage"
|
(changedSelection)="selection = $event" [refreshTrigger]="changePage"
|
||||||
[canDelete]="['project.member.delete', 'project.member.delete:'+project.projectId] | hasRole | async"
|
[canWrite]="['project.member.write$', 'project.member.write:'+ project.projectId] | hasRole | async"
|
||||||
|
[canDelete]="['project.member.delete$', 'project.member.delete:'+project.projectId] | hasRole | async"
|
||||||
(deleteMember)="removeProjectMember($event)">
|
(deleteMember)="removeProjectMember($event)">
|
||||||
<ng-template appHasRole selectactions
|
<ng-template appHasRole selectactions
|
||||||
[appHasRole]="['project.member.delete:' + project.projectId, 'project.member.delete']">
|
[appHasRole]="['project.member.delete:' + project.projectId, 'project.member.delete']">
|
||||||
|
@ -19,13 +19,13 @@
|
|||||||
<table [dataSource]="dataSource" mat-table class="table" matSort aria-label="Elements">
|
<table [dataSource]="dataSource" mat-table class="table" matSort aria-label="Elements">
|
||||||
<ng-container matColumnDef="select">
|
<ng-container matColumnDef="select">
|
||||||
<th class="selection" mat-header-cell *matHeaderCellDef>
|
<th class="selection" mat-header-cell *matHeaderCellDef>
|
||||||
<mat-checkbox color="primary" (change)="$event ? masterToggle() : null"
|
<mat-checkbox [disabled]="disabled" color="primary" (change)="$event ? masterToggle() : null"
|
||||||
[checked]="selection.hasValue() && isAllSelected()"
|
[checked]="selection.hasValue() && isAllSelected()"
|
||||||
[indeterminate]="selection.hasValue() && !isAllSelected()">
|
[indeterminate]="selection.hasValue() && !isAllSelected()">
|
||||||
</mat-checkbox>
|
</mat-checkbox>
|
||||||
</th>
|
</th>
|
||||||
<td class="selection" mat-cell *matCellDef="let row">
|
<td class="selection" mat-cell *matCellDef="let row">
|
||||||
<mat-checkbox color="primary" (click)="$event.stopPropagation()"
|
<mat-checkbox color="primary" [disabled]="disabled" (click)="$event.stopPropagation()"
|
||||||
(change)="$event ? selection.toggle(row) : null" [checked]="selection.isSelected(row)">
|
(change)="$event ? selection.toggle(row) : null" [checked]="selection.isSelected(row)">
|
||||||
</mat-checkbox>
|
</mat-checkbox>
|
||||||
</td>
|
</td>
|
||||||
|
@ -4,7 +4,8 @@
|
|||||||
<app-members-table [dataSource]="dataSource" [memberRoleOptions]="memberRoleOptions"
|
<app-members-table [dataSource]="dataSource" [memberRoleOptions]="memberRoleOptions"
|
||||||
(updateRoles)="updateRoles($event.member, $event.change)" [factoryLoadFunc]="changePageFactory"
|
(updateRoles)="updateRoles($event.member, $event.change)" [factoryLoadFunc]="changePageFactory"
|
||||||
(changedSelection)="selection = $event" [refreshTrigger]="changePage"
|
(changedSelection)="selection = $event" [refreshTrigger]="changePage"
|
||||||
[canDelete]="['iam.member.delete'] | hasRole | async" (deleteMember)="removeMember($event)">
|
[canWrite]="['iam.member.write$'] | hasRole | async" [canDelete]="['iam.member.delete$'] | hasRole | async"
|
||||||
|
(deleteMember)="removeMember($event)">
|
||||||
|
|
||||||
<ng-template appHasRole selectactions [appHasRole]="['iam.member.delete']">
|
<ng-template appHasRole selectactions [appHasRole]="['iam.member.delete']">
|
||||||
<button color="warn" (click)="removeMemberSelection()"
|
<button color="warn" (click)="removeMemberSelection()"
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
<div class="enlarged-container">
|
<div class="enlarged-container">
|
||||||
<h1 class="h1">{{org?.name}}</h1>
|
<h1 class="h1">{{org?.name}}</h1>
|
||||||
<p class="sub">{{'ORG_DETAIL.DESCRIPTION' | translate}}</p>
|
<p class="sub">{{'ORG_DETAIL.DESCRIPTION' | translate}}</p>
|
||||||
<ng-container *ngIf="(['org.write'] | hasRole) as canwrite$">
|
<ng-container *ngIf="(['org.write$'] | hasRole) as canwrite$">
|
||||||
<app-card title="{{ 'ORG.DOMAINS.TITLE' | translate }}"
|
<app-card title="{{ 'ORG.DOMAINS.TITLE' | translate }}"
|
||||||
description="{{ 'ORG.DOMAINS.DESCRIPTION' | translate }}">
|
description="{{ 'ORG.DOMAINS.DESCRIPTION' | translate }}">
|
||||||
|
|
||||||
|
@ -3,8 +3,8 @@
|
|||||||
<app-members-table [dataSource]="dataSource" [memberRoleOptions]="memberRoleOptions"
|
<app-members-table [dataSource]="dataSource" [memberRoleOptions]="memberRoleOptions"
|
||||||
(updateRoles)="updateRoles($event.member, $event.change)" [factoryLoadFunc]="changePageFactory"
|
(updateRoles)="updateRoles($event.member, $event.change)" [factoryLoadFunc]="changePageFactory"
|
||||||
(changedSelection)="selection = $event" [refreshTrigger]="changePage"
|
(changedSelection)="selection = $event" [refreshTrigger]="changePage"
|
||||||
[canDelete]="['org.member.delete:'+org?.id,'org.member.delete'] | hasRole | async"
|
[canDelete]="['org.member.delete:'+org?.id,'org.member.delete$'] | hasRole | async"
|
||||||
(deleteMember)="removeOrgMember($event)">
|
[canWrite]="['org.member.write$'] | hasRole | async" (deleteMember)="removeOrgMember($event)">
|
||||||
<ng-template appHasRole selectactions [appHasRole]="['org.member.delete:'+org?.id,'org.member.delete']">
|
<ng-template appHasRole selectactions [appHasRole]="['org.member.delete:'+org?.id,'org.member.delete']">
|
||||||
<button (click)="removeOrgMemberSelection()" matTooltip="{{'ORG_DETAIL.TABLE.DELETE' | translate}}"
|
<button (click)="removeOrgMemberSelection()" matTooltip="{{'ORG_DETAIL.TABLE.DELETE' | translate}}"
|
||||||
class="del-button" mat-raised-button color="warn">
|
class="del-button" mat-raised-button color="warn">
|
||||||
|
@ -22,11 +22,12 @@
|
|||||||
</ng-template>
|
</ng-template>
|
||||||
|
|
||||||
<span class="fill-space"></span>
|
<span class="fill-space"></span>
|
||||||
<div class="btn-wrapper">
|
<div class="btn-wrapper" *ngIf="(['policy.write'] | hasRole) as writePolicy$">
|
||||||
<button [disabled]="complexityPolicy" [routerLink]="[ 'policy', PolicyComponentType.COMPLEXITY,'create' ]"
|
<button [disabled]="complexityPolicy || (writePolicy$ | async) == false"
|
||||||
color="primary" mat-raised-button>{{'ORG.POLICY.BTN_INSTALL' | translate}}</button>
|
[routerLink]="[ 'policy', PolicyComponentType.COMPLEXITY,'create' ]" color="primary"
|
||||||
<button [disabled]="!complexityPolicy" [routerLink]="[ 'policy', PolicyComponentType.COMPLEXITY ]"
|
mat-raised-button>{{'ORG.POLICY.BTN_INSTALL' | translate}}</button>
|
||||||
mat-stroked-button
|
<button [disabled]="!complexityPolicy || (writePolicy$ | async) == false"
|
||||||
|
[routerLink]="[ 'policy', PolicyComponentType.COMPLEXITY ]" mat-stroked-button
|
||||||
[matTooltip]="'ACTIONS.CONFIGURE' | translate">{{'ORG.POLICY.BTN_EDIT' | translate}}</button>
|
[matTooltip]="'ACTIONS.CONFIGURE' | translate">{{'ORG.POLICY.BTN_EDIT' | translate}}</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -51,14 +52,14 @@
|
|||||||
</ng-template>
|
</ng-template>
|
||||||
|
|
||||||
<span class="fill-space"></span>
|
<span class="fill-space"></span>
|
||||||
<div class="btn-wrapper">
|
|
||||||
<ng-template appHasRole [appHasRole]="['iam.policy.write']">
|
<div class="btn-wrapper" *ngIf="(['iam.policy.write$'] | hasRole) as iamWritePolicy$">
|
||||||
<button [disabled]="iamPolicy" [routerLink]="[ 'policy', PolicyComponentType.IAM,'create' ]"
|
<button [disabled]="iamPolicy || (iamWritePolicy$ | async) == false"
|
||||||
color="primary" mat-raised-button>{{'ORG.POLICY.BTN_INSTALL' | translate}}</button>
|
[routerLink]="[ 'policy', PolicyComponentType.IAM,'create' ]" color="primary"
|
||||||
<button [disabled]="!iamPolicy" [routerLink]="[ 'policy', PolicyComponentType.IAM ]"
|
mat-raised-button>{{'ORG.POLICY.BTN_INSTALL' | translate}}</button>
|
||||||
mat-stroked-button
|
<button [disabled]="!iamPolicy || (iamWritePolicy$ | async) == false"
|
||||||
[matTooltip]="'ACTIONS.CONFIGURE' | translate">{{'ORG.POLICY.BTN_EDIT' | translate}}</button>
|
[routerLink]="[ 'policy', PolicyComponentType.IAM ]" mat-stroked-button
|
||||||
</ng-template>
|
[matTooltip]="'ACTIONS.CONFIGURE' | translate">{{'ORG.POLICY.BTN_EDIT' | translate}}</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</ng-template>
|
</ng-template>
|
||||||
@ -81,14 +82,13 @@
|
|||||||
</ng-template>
|
</ng-template>
|
||||||
|
|
||||||
<span class="fill-space"></span>
|
<span class="fill-space"></span>
|
||||||
<div class="btn-wrapper">
|
<div class="btn-wrapper" *ngIf="(['policy.write'] | hasRole) as writePolicy$">
|
||||||
<ng-template appHasRole [appHasRole]="['policy.write']">
|
<button [disabled]="loginPolicy || (writePolicy$ | async) == false"
|
||||||
<button [disabled]="loginPolicy" [routerLink]="[ 'policy', PolicyComponentType.LOGIN,'create' ]"
|
[routerLink]="[ 'policy', PolicyComponentType.LOGIN,'create' ]" color="primary"
|
||||||
color="primary" mat-raised-button>{{'ORG.POLICY.BTN_INSTALL' | translate}}</button>
|
mat-raised-button>{{'ORG.POLICY.BTN_INSTALL' | translate}}</button>
|
||||||
<button [disabled]="!loginPolicy" [routerLink]="[ 'policy', PolicyComponentType.LOGIN ]"
|
<button [disabled]="!loginPolicy || (writePolicy$ | async) == false"
|
||||||
mat-stroked-button
|
[routerLink]="[ 'policy', PolicyComponentType.LOGIN ]" mat-stroked-button
|
||||||
[matTooltip]="'ACTIONS.CONFIGURE' | translate">{{'ORG.POLICY.BTN_EDIT' | translate}}</button>
|
[matTooltip]="'ACTIONS.CONFIGURE' | translate">{{'ORG.POLICY.BTN_EDIT' | translate}}</button>
|
||||||
</ng-template>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</ng-template>
|
</ng-template>
|
||||||
|
@ -43,7 +43,7 @@
|
|||||||
|
|
||||||
<app-card title="{{ 'APP.OIDC.TITLE' | translate }}" *ngIf="app && app.oidcConfig">
|
<app-card title="{{ 'APP.OIDC.TITLE' | translate }}" *ngIf="app && app.oidcConfig">
|
||||||
<div card-actions *ngIf="app?.oidcConfig?.authMethodType !== OIDCAuthMethodType.OIDCAUTHMETHODTYPE_NONE">
|
<div card-actions *ngIf="app?.oidcConfig?.authMethodType !== OIDCAuthMethodType.OIDCAUTHMETHODTYPE_NONE">
|
||||||
<button mat-stroked-button
|
<button [disabled]="!canWrite" mat-stroked-button
|
||||||
(click)="regenerateOIDCClientSecret()">{{'APP.OIDC.REGENERATESECRET' | translate}}</button>
|
(click)="regenerateOIDCClientSecret()">{{'APP.OIDC.REGENERATESECRET' | translate}}</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@ -109,7 +109,7 @@
|
|||||||
|
|
||||||
<mat-form-field class="formfield full-width" appearance="outline">
|
<mat-form-field class="formfield full-width" appearance="outline">
|
||||||
<mat-label>{{ 'APP.OIDC.REDIRECT' | translate }}</mat-label>
|
<mat-label>{{ 'APP.OIDC.REDIRECT' | translate }}</mat-label>
|
||||||
<mat-chip-list #chipRedirectList>
|
<mat-chip-list [disabled]="!canWrite" #chipRedirectList>
|
||||||
<mat-chip class="chip" *ngFor="let redirect of redirectUrisList" selected
|
<mat-chip class="chip" *ngFor="let redirect of redirectUrisList" selected
|
||||||
[matTooltip]="!redirect.startsWith('https://') ? ('APP.OIDC.UNSECUREREDIRECT' | translate): ''"
|
[matTooltip]="!redirect.startsWith('https://') ? ('APP.OIDC.UNSECUREREDIRECT' | translate): ''"
|
||||||
[color]="!redirect.startsWith('https://') ? 'warn': 'green'"
|
[color]="!redirect.startsWith('https://') ? 'warn': 'green'"
|
||||||
@ -128,7 +128,7 @@
|
|||||||
|
|
||||||
<mat-form-field class="formfield full-width" appearance="outline">
|
<mat-form-field class="formfield full-width" appearance="outline">
|
||||||
<mat-label>{{ 'APP.OIDC.POSTLOGOUTREDIRECT' | translate }}</mat-label>
|
<mat-label>{{ 'APP.OIDC.POSTLOGOUTREDIRECT' | translate }}</mat-label>
|
||||||
<mat-chip-list #chipPostRedirectList>
|
<mat-chip-list [disabled]="!canWrite" #chipPostRedirectList>
|
||||||
<mat-chip class="chip" *ngFor="let redirect of postLogoutRedirectUrisList" selected
|
<mat-chip class="chip" *ngFor="let redirect of postLogoutRedirectUrisList" selected
|
||||||
(removed)="remove(redirect, RedirectType.POSTREDIRECT)"
|
(removed)="remove(redirect, RedirectType.POSTREDIRECT)"
|
||||||
[matTooltip]="!redirect.startsWith('https://') ? ('APP.OIDC.UNSECUREREDIRECT' | translate): ''"
|
[matTooltip]="!redirect.startsWith('https://') ? ('APP.OIDC.UNSECUREREDIRECT' | translate): ''"
|
||||||
@ -148,7 +148,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="btn-container">
|
<div class="btn-container">
|
||||||
|
|
||||||
<button class="submit-button" type="submit" color="primary" [disabled]="appForm.invalid"
|
<button class="submit-button" type="submit" color="primary" [disabled]="appForm.invalid || !canWrite"
|
||||||
mat-raised-button>{{ 'ACTIONS.SAVE' | translate }}</button>
|
mat-raised-button>{{ 'ACTIONS.SAVE' | translate }}</button>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
|
@ -86,11 +86,16 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.toggle {
|
.toggle {
|
||||||
|
outline: none;
|
||||||
align-self: flex-start;
|
align-self: flex-start;
|
||||||
margin-bottom: 1rem;
|
margin-bottom: 1rem;
|
||||||
margin-right: 1rem;
|
margin-right: 1rem;
|
||||||
border-radius: .5rem;
|
border-radius: .5rem;
|
||||||
|
|
||||||
|
* {
|
||||||
|
outline: none;
|
||||||
|
}
|
||||||
|
|
||||||
i {
|
i {
|
||||||
margin-right: 1rem;
|
margin-right: 1rem;
|
||||||
}
|
}
|
||||||
|
@ -1,13 +1,14 @@
|
|||||||
import { COMMA, ENTER, SPACE } from '@angular/cdk/keycodes';
|
import { COMMA, ENTER, SPACE } from '@angular/cdk/keycodes';
|
||||||
import { Location } from '@angular/common';
|
import { Location } from '@angular/common';
|
||||||
import { Component, OnDestroy, OnInit } from '@angular/core';
|
import { Component, OnDestroy, OnInit } from '@angular/core';
|
||||||
import { AbstractControl, FormBuilder, FormControl, FormGroup, ValidatorFn, Validators } from '@angular/forms';
|
import { AbstractControl, FormBuilder, FormControl, FormGroup, Validators } from '@angular/forms';
|
||||||
import { MatButtonToggleChange } from '@angular/material/button-toggle';
|
import { MatButtonToggleChange } from '@angular/material/button-toggle';
|
||||||
import { MatChipInputEvent } from '@angular/material/chips';
|
import { MatChipInputEvent } from '@angular/material/chips';
|
||||||
import { MatDialog } from '@angular/material/dialog';
|
import { MatDialog } from '@angular/material/dialog';
|
||||||
import { ActivatedRoute, Params } from '@angular/router';
|
import { ActivatedRoute, Params } from '@angular/router';
|
||||||
import { TranslateService } from '@ngx-translate/core';
|
import { TranslateService } from '@ngx-translate/core';
|
||||||
import { Subscription } from 'rxjs';
|
import { Subscription } from 'rxjs';
|
||||||
|
import { take } from 'rxjs/operators';
|
||||||
import {
|
import {
|
||||||
Application,
|
Application,
|
||||||
AppState,
|
AppState,
|
||||||
@ -18,6 +19,7 @@ import {
|
|||||||
OIDCResponseType,
|
OIDCResponseType,
|
||||||
ZitadelDocs,
|
ZitadelDocs,
|
||||||
} from 'src/app/proto/generated/management_pb';
|
} from 'src/app/proto/generated/management_pb';
|
||||||
|
import { GrpcAuthService } from 'src/app/services/grpc-auth.service';
|
||||||
import { ManagementService } from 'src/app/services/mgmt.service';
|
import { ManagementService } from 'src/app/services/mgmt.service';
|
||||||
import { ToastService } from 'src/app/services/toast.service';
|
import { ToastService } from 'src/app/services/toast.service';
|
||||||
|
|
||||||
@ -34,6 +36,7 @@ enum RedirectType {
|
|||||||
styleUrls: ['./app-detail.component.scss'],
|
styleUrls: ['./app-detail.component.scss'],
|
||||||
})
|
})
|
||||||
export class AppDetailComponent implements OnInit, OnDestroy {
|
export class AppDetailComponent implements OnInit, OnDestroy {
|
||||||
|
public canWrite: boolean = false;
|
||||||
public errorMessage: string = '';
|
public errorMessage: string = '';
|
||||||
public removable: boolean = true;
|
public removable: boolean = true;
|
||||||
public addOnBlur: boolean = true;
|
public addOnBlur: boolean = true;
|
||||||
@ -78,8 +81,8 @@ export class AppDetailComponent implements OnInit, OnDestroy {
|
|||||||
public OIDCApplicationType: any = OIDCApplicationType;
|
public OIDCApplicationType: any = OIDCApplicationType;
|
||||||
public OIDCAuthMethodType: any = OIDCAuthMethodType;
|
public OIDCAuthMethodType: any = OIDCAuthMethodType;
|
||||||
|
|
||||||
public redirectControl: FormControl = new FormControl('');
|
public redirectControl: FormControl = new FormControl({ value: '', disabled: true });
|
||||||
public postRedirectControl: FormControl = new FormControl('');
|
public postRedirectControl: FormControl = new FormControl({ value: '', disabled: true });
|
||||||
|
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
@ -90,18 +93,19 @@ export class AppDetailComponent implements OnInit, OnDestroy {
|
|||||||
private _location: Location,
|
private _location: Location,
|
||||||
private dialog: MatDialog,
|
private dialog: MatDialog,
|
||||||
private mgmtService: ManagementService,
|
private mgmtService: ManagementService,
|
||||||
|
private authService: GrpcAuthService,
|
||||||
) {
|
) {
|
||||||
this.appNameForm = this.fb.group({
|
this.appNameForm = this.fb.group({
|
||||||
state: ['', []],
|
state: [{ value: '', disabled: true }, []],
|
||||||
name: ['', [Validators.required]],
|
name: [{ value: '', disabled: true }, [Validators.required]],
|
||||||
});
|
});
|
||||||
this.appForm = this.fb.group({
|
this.appForm = this.fb.group({
|
||||||
devMode: [false, []],
|
devMode: [{ value: false, disabled: true }, []],
|
||||||
clientId: [{ value: '', disabled: true }],
|
clientId: [{ value: '', disabled: true }],
|
||||||
responseTypesList: [],
|
responseTypesList: [{ value: [], disabled: true }],
|
||||||
grantTypesList: [],
|
grantTypesList: [{ value: [], disabled: true }],
|
||||||
applicationType: [],
|
applicationType: [{ value: '', disabled: true }],
|
||||||
authMethodType: [],
|
authMethodType: [{ value: '', disabled: true }],
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -118,36 +122,35 @@ export class AppDetailComponent implements OnInit, OnDestroy {
|
|||||||
this.mgmtService.GetIam().then(iam => {
|
this.mgmtService.GetIam().then(iam => {
|
||||||
this.isZitadel = iam.toObject().iamProjectId === this.projectId;
|
this.isZitadel = iam.toObject().iamProjectId === this.projectId;
|
||||||
});
|
});
|
||||||
|
this.authService.isAllowed(['project.app.write$', 'project.app.write:' + id]).pipe(take(1)).subscribe((allowed) => {
|
||||||
|
this.canWrite = allowed;
|
||||||
|
this.mgmtService.GetApplicationById(projectid, id).then(app => {
|
||||||
|
this.app = app.toObject();
|
||||||
|
this.appNameForm.patchValue(this.app);
|
||||||
|
if (allowed) {
|
||||||
|
this.appNameForm.enable();
|
||||||
|
this.appForm.enable();
|
||||||
|
this.redirectControl.enable();
|
||||||
|
this.postRedirectControl.enable();
|
||||||
|
}
|
||||||
|
|
||||||
this.mgmtService.GetApplicationById(projectid, id).then(app => {
|
if (this.app.oidcConfig?.redirectUrisList) {
|
||||||
this.app = app.toObject();
|
this.redirectUrisList = this.app.oidcConfig.redirectUrisList;
|
||||||
this.appNameForm.patchValue(this.app);
|
}
|
||||||
|
if (this.app.oidcConfig?.postLogoutRedirectUrisList) {
|
||||||
if (this.app.state !== AppState.APPSTATE_ACTIVE) {
|
this.postLogoutRedirectUrisList = this.app.oidcConfig.postLogoutRedirectUrisList;
|
||||||
this.appNameForm.controls['name'].disable();
|
}
|
||||||
this.appForm.disable();
|
if (this.app.oidcConfig) {
|
||||||
} else {
|
this.appForm.patchValue(this.app.oidcConfig);
|
||||||
this.appNameForm.controls['name'].enable();
|
}
|
||||||
this.appForm.enable();
|
}).catch(error => {
|
||||||
}
|
console.error(error);
|
||||||
if (this.app.oidcConfig?.redirectUrisList) {
|
this.toast.showError(error);
|
||||||
this.redirectUrisList = this.app.oidcConfig.redirectUrisList;
|
this.errorMessage = error.message;
|
||||||
|
});
|
||||||
// this.redirectControl = new FormControl('', [nativeValidator as ValidatorFn]);
|
|
||||||
}
|
|
||||||
if (this.app.oidcConfig?.postLogoutRedirectUrisList) {
|
|
||||||
this.postLogoutRedirectUrisList = this.app.oidcConfig.postLogoutRedirectUrisList;
|
|
||||||
// this.postRedirectControl = new FormControl('', [nativeValidator as ValidatorFn]);
|
|
||||||
}
|
|
||||||
if (this.app.oidcConfig) {
|
|
||||||
this.appForm.patchValue(this.app.oidcConfig);
|
|
||||||
}
|
|
||||||
}).catch(error => {
|
|
||||||
console.error(error);
|
|
||||||
this.toast.showError(error);
|
|
||||||
this.errorMessage = error.message;
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
this.docs = (await this.mgmtService.GetZitadelDocs()).toObject();
|
this.docs = (await this.mgmtService.GetZitadelDocs()).toObject();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -160,20 +163,11 @@ export class AppDetailComponent implements OnInit, OnDestroy {
|
|||||||
});
|
});
|
||||||
} else if (event.value === AppState.APPSTATE_INACTIVE) {
|
} else if (event.value === AppState.APPSTATE_INACTIVE) {
|
||||||
this.mgmtService.DeactivateApplication(this.projectId, this.app.id).then(() => {
|
this.mgmtService.DeactivateApplication(this.projectId, this.app.id).then(() => {
|
||||||
this.toast.showInfo('APP.TOAST.REACTIVATED', true);
|
this.toast.showInfo('APP.TOAST.DEACTIVATED', true);
|
||||||
}).catch((error: any) => {
|
}).catch((error: any) => {
|
||||||
this.toast.showError(error);
|
this.toast.showError(error);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if (event.value !== AppState.APPSTATE_ACTIVE) {
|
|
||||||
this.appNameForm.controls['name'].disable();
|
|
||||||
this.appForm.disable();
|
|
||||||
} else {
|
|
||||||
this.appNameForm.controls['name'].enable();
|
|
||||||
this.appForm.enable();
|
|
||||||
this.clientId?.disable();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public add(event: MatChipInputEvent, target: RedirectType): void {
|
public add(event: MatChipInputEvent, target: RedirectType): void {
|
||||||
|
@ -18,8 +18,8 @@
|
|||||||
<app-user-grants *ngIf="projectId && grantId" [context]="UserGrantContext.GRANTED_PROJECT"
|
<app-user-grants *ngIf="projectId && grantId" [context]="UserGrantContext.GRANTED_PROJECT"
|
||||||
[projectId]="projectId" [grantId]="grantId"
|
[projectId]="projectId" [grantId]="grantId"
|
||||||
[displayedColumns]="['select','user', 'projectId', 'creationDate', 'changeDate', 'roleNamesList']"
|
[displayedColumns]="['select','user', 'projectId', 'creationDate', 'changeDate', 'roleNamesList']"
|
||||||
[allowWrite]="['user.grant.write','user.grant.write:'+grantId] | hasRole | async"
|
[allowWrite]="['user.grant.write$','user.grant.write:'+grantId] | hasRole | async"
|
||||||
[allowDelete]="['user.grant.delete','user.grant.delete:'+grantId] | hasRole | async"
|
[allowDelete]="['user.grant.delete$','user.grant.delete:'+grantId] | hasRole | async"
|
||||||
refreshOnPreviousRoute="/grant-create/project/{{projectId}}/grant/{{grantId}}">
|
refreshOnPreviousRoute="/grant-create/project/{{projectId}}/grant/{{grantId}}">
|
||||||
</app-user-grants>
|
</app-user-grants>
|
||||||
</app-card>
|
</app-card>
|
||||||
@ -40,7 +40,7 @@
|
|||||||
[membersSubject]="membersSubject" title="{{ 'PROJECT.MEMBER.TITLE' | translate }}"
|
[membersSubject]="membersSubject" title="{{ 'PROJECT.MEMBER.TITLE' | translate }}"
|
||||||
description="{{ 'PROJECT.MEMBER.TITLEDESC' | translate }}" (addClicked)="openAddMember()"
|
description="{{ 'PROJECT.MEMBER.TITLEDESC' | translate }}" (addClicked)="openAddMember()"
|
||||||
(showDetailClicked)="showDetail()" (refreshClicked)="loadMembers()"
|
(showDetailClicked)="showDetail()" (refreshClicked)="loadMembers()"
|
||||||
[disabled]="(['project.grant.member.write', 'project.grant.member.write:'+ project.projectId]| hasRole | async) == false">
|
[disabled]="(['project.grant.member.write$', 'project.grant.member.write:'+ project.projectId]| hasRole | async) == false">
|
||||||
</app-contributors>
|
</app-contributors>
|
||||||
</mat-tab>
|
</mat-tab>
|
||||||
<mat-tab label="{{ 'CHANGES.PROJECT.TITLE' | translate }}" class="flex-col">
|
<mat-tab label="{{ 'CHANGES.PROJECT.TITLE' | translate }}" class="flex-col">
|
||||||
|
@ -22,11 +22,11 @@
|
|||||||
<span class="fill-space"></span>
|
<span class="fill-space"></span>
|
||||||
|
|
||||||
<button mat-stroked-button color="warn"
|
<button mat-stroked-button color="warn"
|
||||||
[disabled]="isZitadel || (['project.write', 'project.write:'+ project.projectId]| hasRole | async) == false"
|
[disabled]="isZitadel || (['project.write$', 'project.write:'+ project.projectId]| hasRole | async) == false"
|
||||||
*ngIf="project?.state === ProjectState.PROJECTSTATE_ACTIVE"
|
*ngIf="project?.state === ProjectState.PROJECTSTATE_ACTIVE"
|
||||||
(click)="changeState(ProjectState.PROJECTSTATE_INACTIVE)">{{'PROJECT.TABLE.DEACTIVATE' | translate}}</button>
|
(click)="changeState(ProjectState.PROJECTSTATE_INACTIVE)">{{'PROJECT.TABLE.DEACTIVATE' | translate}}</button>
|
||||||
<button mat-stroked-button color="warn"
|
<button mat-stroked-button color="warn"
|
||||||
[disabled]="isZitadel || (['project.write', 'project.write:'+ project.projectId]| hasRole | async) == false"
|
[disabled]="isZitadel || (['project.write$', 'project.write:'+ project.projectId]| hasRole | async) == false"
|
||||||
*ngIf="project?.state === ProjectState.PROJECTSTATE_INACTIVE"
|
*ngIf="project?.state === ProjectState.PROJECTSTATE_INACTIVE"
|
||||||
(click)="changeState(ProjectState.PROJECTSTATE_ACTIVE)">{{'PROJECT.TABLE.ACTIVATE' | translate}}</button>
|
(click)="changeState(ProjectState.PROJECTSTATE_ACTIVE)">{{'PROJECT.TABLE.ACTIVATE' | translate}}</button>
|
||||||
|
|
||||||
@ -69,7 +69,7 @@
|
|||||||
<app-card title="{{ 'PROJECT.GRANT.TITLE' | translate }}"
|
<app-card title="{{ 'PROJECT.GRANT.TITLE' | translate }}"
|
||||||
description="{{ 'PROJECT.GRANT.DESCRIPTION' | translate }}">
|
description="{{ 'PROJECT.GRANT.DESCRIPTION' | translate }}">
|
||||||
<app-project-grants refreshOnPreviousRoute="/projects/{{projectId}}/grants/create"
|
<app-project-grants refreshOnPreviousRoute="/projects/{{projectId}}/grants/create"
|
||||||
[disabled]="((['project.grant.write', 'project.grant.write:'+ project.projectId]| hasRole | async) && (['org.global.read']| hasRole | async))== false"
|
[disabled]="((['project.grant.write$', 'project.grant.write:'+ project.projectId]| hasRole | async))== false"
|
||||||
[projectId]="projectId">
|
[projectId]="projectId">
|
||||||
</app-project-grants>
|
</app-project-grants>
|
||||||
</app-card>
|
</app-card>
|
||||||
@ -79,7 +79,7 @@
|
|||||||
<app-card title="{{ 'PROJECT.ROLE.TITLE' | translate }}"
|
<app-card title="{{ 'PROJECT.ROLE.TITLE' | translate }}"
|
||||||
description="{{ 'PROJECT.ROLE.DESCRIPTION' | translate }}">
|
description="{{ 'PROJECT.ROLE.DESCRIPTION' | translate }}">
|
||||||
<app-project-roles
|
<app-project-roles
|
||||||
[disabled]="(['project.role.write', 'project.role.write:'+ project.projectId]| hasRole | async) == false"
|
[disabled]="(['project.role.write$', 'project.role.write:'+ project.projectId]| hasRole | async) == false"
|
||||||
[actionsVisible]="true" [projectId]="projectId">
|
[actionsVisible]="true" [projectId]="projectId">
|
||||||
</app-project-roles>
|
</app-project-roles>
|
||||||
</app-card>
|
</app-card>
|
||||||
@ -90,8 +90,8 @@
|
|||||||
description="{{'GRANTS.PROJECT.DESCRIPTION' | translate }}">
|
description="{{'GRANTS.PROJECT.DESCRIPTION' | translate }}">
|
||||||
<app-user-grants [context]="UserGrantContext.OWNED_PROJECT" [projectId]="projectId"
|
<app-user-grants [context]="UserGrantContext.OWNED_PROJECT" [projectId]="projectId"
|
||||||
refreshOnPreviousRoute="/grant-create/project/{{projectId}}"
|
refreshOnPreviousRoute="/grant-create/project/{{projectId}}"
|
||||||
[allowWrite]="(['user.grant.write', 'user.grant.write:'+projectId] | hasRole) | async"
|
[allowWrite]="(['user.grant.write$', 'user.grant.write:'+projectId] | hasRole) | async"
|
||||||
[allowDelete]="(['user.grant.delete','user.grant.delete:'+projectId] | hasRole) | async">
|
[allowDelete]="(['user.grant.delete$','user.grant.delete:'+projectId] | hasRole) | async">
|
||||||
</app-user-grants>
|
</app-user-grants>
|
||||||
</app-card>
|
</app-card>
|
||||||
</ng-template>
|
</ng-template>
|
||||||
@ -113,7 +113,7 @@
|
|||||||
[membersSubject]="membersSubject" title="{{ 'PROJECT.MEMBER.TITLE' | translate }}"
|
[membersSubject]="membersSubject" title="{{ 'PROJECT.MEMBER.TITLE' | translate }}"
|
||||||
description="{{ 'PROJECT.MEMBER.TITLEDESC' | translate }}" (addClicked)="openAddMember()"
|
description="{{ 'PROJECT.MEMBER.TITLEDESC' | translate }}" (addClicked)="openAddMember()"
|
||||||
(showDetailClicked)="showDetail()" (refreshClicked)="loadMembers()"
|
(showDetailClicked)="showDetail()" (refreshClicked)="loadMembers()"
|
||||||
[disabled]="(['project.member.write', 'project.member.write:'+ project.projectId]| hasRole | async) == false">
|
[disabled]="(['project.member.write$', 'project.member.write:'+ project.projectId]| hasRole | async) == false">
|
||||||
</app-contributors>
|
</app-contributors>
|
||||||
</mat-tab>
|
</mat-tab>
|
||||||
<mat-tab label="{{ 'CHANGES.PROJECT.TITLE' | translate }}" class="flex-col">
|
<mat-tab label="{{ 'CHANGES.PROJECT.TITLE' | translate }}" class="flex-col">
|
||||||
|
@ -21,13 +21,13 @@
|
|||||||
|
|
||||||
<ng-container matColumnDef="select">
|
<ng-container matColumnDef="select">
|
||||||
<th class="selection" mat-header-cell *matHeaderCellDef>
|
<th class="selection" mat-header-cell *matHeaderCellDef>
|
||||||
<mat-checkbox color="primary" (change)="$event ? masterToggle() : null"
|
<mat-checkbox [disabled]="disabled" color="primary" (change)="$event ? masterToggle() : null"
|
||||||
[checked]="selection.hasValue() && isAllSelected()"
|
[checked]="selection.hasValue() && isAllSelected()"
|
||||||
[indeterminate]="selection.hasValue() && !isAllSelected()">
|
[indeterminate]="selection.hasValue() && !isAllSelected()">
|
||||||
</mat-checkbox>
|
</mat-checkbox>
|
||||||
</th>
|
</th>
|
||||||
<td class="selection" mat-cell *matCellDef="let row">
|
<td class="selection" mat-cell *matCellDef="let row">
|
||||||
<mat-checkbox color="primary" (click)="$event.stopPropagation()"
|
<mat-checkbox [disabled]="disabled" color="primary" (click)="$event.stopPropagation()"
|
||||||
(change)="$event ? selection.toggle(row) : null" [checked]="selection.isSelected(row)">
|
(change)="$event ? selection.toggle(row) : null" [checked]="selection.isSelected(row)">
|
||||||
</mat-checkbox>
|
</mat-checkbox>
|
||||||
</td>
|
</td>
|
||||||
|
@ -3,8 +3,7 @@
|
|||||||
<div class="people" *ngIf="memberships">
|
<div class="people" *ngIf="memberships">
|
||||||
<div class="img-list" [@cardAnimation]="memberships.totalResult">
|
<div class="img-list" [@cardAnimation]="memberships.totalResult">
|
||||||
<mat-spinner class="spinner" diameter="20" *ngIf="loading"></mat-spinner>
|
<mat-spinner class="spinner" diameter="20" *ngIf="loading"></mat-spinner>
|
||||||
|
<ng-container *ngIf="memberships.totalResult < 8; else compact">
|
||||||
<ng-container *ngIf="memberships.totalResult < 10; else compact">
|
|
||||||
<ng-container *ngFor="let membership of memberships.resultList; index as i">
|
<ng-container *ngFor="let membership of memberships.resultList; index as i">
|
||||||
<div @animate class="avatar-circle" (click)="navigateToObject()"
|
<div @animate class="avatar-circle" (click)="navigateToObject()"
|
||||||
matTooltip="{{ membership.displayName }} | {{membership.rolesList?.join(' ')}}"
|
matTooltip="{{ membership.displayName }} | {{membership.rolesList?.join(' ')}}"
|
||||||
@ -25,7 +24,9 @@
|
|||||||
</ng-container>
|
</ng-container>
|
||||||
<ng-template #compact>
|
<ng-template #compact>
|
||||||
<div class="avatar-circle" matTooltip="Click to show detail">
|
<div class="avatar-circle" matTooltip="Click to show detail">
|
||||||
<span>{{memberships.totalResult}}</span>
|
<div class="membership-avatar">
|
||||||
|
<span style="font-size: 16px;">{{memberships.totalResult}}</span>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</ng-template>
|
</ng-template>
|
||||||
<button [disabled]="disabled" class="add-img" (click)="addMember()" mat-icon-button
|
<button [disabled]="disabled" class="add-img" (click)="addMember()" mat-icon-button
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
<app-meta-layout *ngIf="user && (['user.write','user.write:' + user.id] | hasRole) as canWrite$">
|
<app-meta-layout *ngIf="user && (['user.write$','user.write:' + user.id] | hasRole) as canWrite$">
|
||||||
<div class="max-width-container">
|
<div class="max-width-container">
|
||||||
<div class="head">
|
<div class="head">
|
||||||
<a (click)="navigateBack()" mat-icon-button>
|
<a (click)="navigateBack()" mat-icon-button>
|
||||||
@ -55,7 +55,7 @@
|
|||||||
|
|
||||||
<app-card *ngIf="user.machine" title="{{ 'USER.MACHINE.TITLE' | translate }}">
|
<app-card *ngIf="user.machine" title="{{ 'USER.MACHINE.TITLE' | translate }}">
|
||||||
<app-detail-form-machine
|
<app-detail-form-machine
|
||||||
[disabled]="(['user.write:' + user?.id, 'user.write'] | hasRole | async) == false"
|
[disabled]="(['user.write:' + user?.id, 'user.write$'] | hasRole | async) == false"
|
||||||
[username]="user.userName" [user]="user.machine" (submitData)="saveMachine($event)">
|
[username]="user.userName" [user]="user.machine" (submitData)="saveMachine($event)">
|
||||||
</app-detail-form-machine>
|
</app-detail-form-machine>
|
||||||
</app-card>
|
</app-card>
|
||||||
@ -70,7 +70,7 @@
|
|||||||
description="{{ 'USER.LOGINMETHODS.DESCRIPTION' | translate }}">
|
description="{{ 'USER.LOGINMETHODS.DESCRIPTION' | translate }}">
|
||||||
|
|
||||||
<app-contact disablePhoneCode="true"
|
<app-contact disablePhoneCode="true"
|
||||||
[canWrite]="(['user.write:' + user?.id, 'user.write'] | hasRole | async)" *ngIf="user?.human"
|
[canWrite]="(['user.write:' + user?.id, 'user.write$'] | hasRole | async)" *ngIf="user?.human"
|
||||||
[human]="user.human" (savedPhone)="savePhone($event)" (savedEmail)="saveEmail($event)"
|
[human]="user.human" (savedPhone)="savePhone($event)" (savedEmail)="saveEmail($event)"
|
||||||
(deletedPhone)="deletePhone()" (resendEmailVerification)="resendEmailVerification()"
|
(deletedPhone)="deletePhone()" (resendEmailVerification)="resendEmailVerification()"
|
||||||
(resendPhoneVerification)="resendPhoneVerification()">
|
(resendPhoneVerification)="resendPhoneVerification()">
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
<h1>{{ 'USER.PAGES.LIST' | translate }}</h1>
|
<h1>{{ 'USER.PAGES.LIST' | translate }}</h1>
|
||||||
<p class="sub">{{ 'USER.PAGES.DESCRIPTION' | translate }}</p>
|
<p class="sub">{{ 'USER.PAGES.DESCRIPTION' | translate }}</p>
|
||||||
|
|
||||||
<app-user-table [userType]="UserType.HUMAN" [disabled]="(['user.write'] | hasRole | async) == false">
|
<app-user-table [userType]="UserType.HUMAN" [disabled]="(['user.write$'] | hasRole | async) == false">
|
||||||
</app-user-table>
|
</app-user-table>
|
||||||
</ng-container>
|
</ng-container>
|
||||||
|
|
||||||
@ -13,7 +13,7 @@
|
|||||||
|
|
||||||
<app-user-table [userType]="UserType.MACHINE"
|
<app-user-table [userType]="UserType.MACHINE"
|
||||||
[displayedColumns]="['select','name', 'username', 'description','state', 'actions']"
|
[displayedColumns]="['select','name', 'username', 'description','state', 'actions']"
|
||||||
[disabled]="(['user.write'] | hasRole | async) == false">
|
[disabled]="(['user.write$'] | hasRole | async) == false">
|
||||||
</app-user-table>
|
</app-user-table>
|
||||||
</ng-container>
|
</ng-container>
|
||||||
</div>
|
</div>
|
@ -26,13 +26,13 @@
|
|||||||
<table class="table" mat-table [dataSource]="dataSource">
|
<table class="table" mat-table [dataSource]="dataSource">
|
||||||
<ng-container matColumnDef="select">
|
<ng-container matColumnDef="select">
|
||||||
<th mat-header-cell *matHeaderCellDef class="selection">
|
<th mat-header-cell *matHeaderCellDef class="selection">
|
||||||
<mat-checkbox color="primary" (change)="$event ? masterToggle() : null"
|
<mat-checkbox [disabled]="disabled" color="primary" (change)="$event ? masterToggle() : null"
|
||||||
[checked]="selection.hasValue() && isAllSelected()"
|
[checked]="selection.hasValue() && isAllSelected()"
|
||||||
[indeterminate]="selection.hasValue() && !isAllSelected()">
|
[indeterminate]="selection.hasValue() && !isAllSelected()">
|
||||||
</mat-checkbox>
|
</mat-checkbox>
|
||||||
</th>
|
</th>
|
||||||
<td mat-cell *matCellDef="let user" class="selection">
|
<td mat-cell *matCellDef="let user" class="selection">
|
||||||
<mat-checkbox color="primary" (click)="$event.stopPropagation()"
|
<mat-checkbox [disabled]="disabled" color="primary" (click)="$event.stopPropagation()"
|
||||||
(change)="$event ? selection.toggle(user) : null" [checked]="selection.isSelected(user)">
|
(change)="$event ? selection.toggle(user) : null" [checked]="selection.isSelected(user)">
|
||||||
<app-avatar
|
<app-avatar
|
||||||
*ngIf="user[userType] && user[userType].displayName && user[userType]?.firstName && user[userType]?.lastName; else cog"
|
*ngIf="user[userType] && user[userType].displayName && user[userType]?.firstName && user[userType]?.lastName; else cog"
|
||||||
|
Loading…
Reference in New Issue
Block a user