mirror of
https://github.com/andwati/zitadel.git
synced 2026-11-15 10:25:11 +00:00
feat: rehauled console (#3525)
* new console * move npm ci to angular build * rel path for assets * local grpc copy * login policy, rm clear views, features rel path * lock Co-authored-by: Livio Amstutz <[email protected]>
This commit is contained in:
co-authored by
Livio Amstutz
parent
00f7dbe875
commit
08ae39ae19
@@ -0,0 +1,72 @@
|
||||
import { DataSource } from '@angular/cdk/collections';
|
||||
import { Timestamp } from 'google-protobuf/google/protobuf/timestamp_pb';
|
||||
import { BehaviorSubject, from, Observable, of } from 'rxjs';
|
||||
import { catchError, finalize, map } from 'rxjs/operators';
|
||||
import { Membership } from 'src/app/proto/generated/zitadel/user_pb';
|
||||
import { GrpcAuthService } from 'src/app/services/grpc-auth.service';
|
||||
import { ManagementService } from 'src/app/services/mgmt.service';
|
||||
|
||||
export class MembershipsDataSource extends DataSource<Membership.AsObject> {
|
||||
public totalResult: number = 0;
|
||||
public viewTimestamp!: Timestamp.AsObject;
|
||||
public membershipsSubject: BehaviorSubject<Membership.AsObject[]> = new BehaviorSubject<Membership.AsObject[]>([]);
|
||||
private loadingSubject: BehaviorSubject<boolean> = new BehaviorSubject<boolean>(false);
|
||||
public loading$: Observable<boolean> = this.loadingSubject.asObservable();
|
||||
|
||||
constructor(private auth: GrpcAuthService, private service: ManagementService) {
|
||||
super();
|
||||
}
|
||||
|
||||
public loadMemberships(userId: string, pageIndex: number, pageSize: number): void {
|
||||
const offset = pageIndex * pageSize;
|
||||
|
||||
this.loadingSubject.next(true);
|
||||
|
||||
from(this.service.listUserMemberships(userId, pageSize, offset))
|
||||
.pipe(
|
||||
map((resp) => {
|
||||
this.totalResult = resp.details?.totalResult || 0;
|
||||
if (resp.details?.viewTimestamp) {
|
||||
this.viewTimestamp = resp.details?.viewTimestamp;
|
||||
}
|
||||
return resp.resultList;
|
||||
}),
|
||||
catchError(() => of([])),
|
||||
finalize(() => this.loadingSubject.next(false)),
|
||||
)
|
||||
.subscribe((members) => {
|
||||
this.membershipsSubject.next(members);
|
||||
});
|
||||
}
|
||||
|
||||
public loadMyMemberships(pageIndex: number, pageSize: number): void {
|
||||
const offset = pageIndex * pageSize;
|
||||
|
||||
this.loadingSubject.next(true);
|
||||
|
||||
from(this.auth.listMyMemberships(pageSize, offset))
|
||||
.pipe(
|
||||
map((resp) => {
|
||||
this.totalResult = resp.details?.totalResult || 0;
|
||||
if (resp.details?.viewTimestamp) {
|
||||
this.viewTimestamp = resp.details?.viewTimestamp;
|
||||
}
|
||||
return resp.resultList;
|
||||
}),
|
||||
catchError(() => of([])),
|
||||
finalize(() => this.loadingSubject.next(false)),
|
||||
)
|
||||
.subscribe((members) => {
|
||||
this.membershipsSubject.next(members);
|
||||
});
|
||||
}
|
||||
|
||||
public connect(): Observable<Membership.AsObject[]> {
|
||||
return this.membershipsSubject.asObservable();
|
||||
}
|
||||
|
||||
public disconnect(): void {
|
||||
this.membershipsSubject.complete();
|
||||
this.loadingSubject.complete();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,80 @@
|
||||
<cnsl-refresh-table *ngIf="dataSource" (refreshed)="changePage()" [dataSize]="dataSource.totalResult"
|
||||
[timestamp]="dataSource.viewTimestamp" [hideRefresh]="true" [selection]="selection"
|
||||
[loading]="dataSource?.loading$ | async">
|
||||
|
||||
<ng-container actions *ngIf="selection.hasValue()">
|
||||
<ng-content select="[selectactions]"></ng-content>
|
||||
</ng-container>
|
||||
|
||||
<div actions>
|
||||
<ng-content select="[writeactions]"></ng-content>
|
||||
</div>
|
||||
|
||||
<div class="table-wrapper">
|
||||
<table mat-table class="table" aria-label="Elements" [dataSource]="dataSource">
|
||||
<ng-container matColumnDef="select">
|
||||
<th class="selection" mat-header-cell *matHeaderCellDef>
|
||||
<mat-checkbox [disabled]="false" color="primary" (change)="$event ? masterToggle() : null"
|
||||
[checked]="selection.hasValue() && isAllSelected()"
|
||||
[indeterminate]="selection.hasValue() && !isAllSelected()">
|
||||
</mat-checkbox>
|
||||
</th>
|
||||
<td class="selection" mat-cell *matCellDef="let row">
|
||||
<mat-checkbox [disabled]="false" color="primary" (click)="$event.stopPropagation()"
|
||||
(change)="$event ? selection.toggle(row) : null" [checked]="selection.isSelected(row)">
|
||||
|
||||
</mat-checkbox>
|
||||
</td>
|
||||
</ng-container>
|
||||
|
||||
<ng-container matColumnDef="displayName">
|
||||
<th mat-header-cell *matHeaderCellDef> {{ 'USER.MEMBERSHIPS.DISPLAYNAME' | translate }} </th>
|
||||
<td mat-cell *matCellDef="let membership">
|
||||
{{membership.displayName}} </td>
|
||||
</ng-container>
|
||||
|
||||
<ng-container matColumnDef="type">
|
||||
<th mat-header-cell *matHeaderCellDef> {{ 'USER.MEMBERSHIPS.TYPE' | translate }} </th>
|
||||
<td mat-cell *matCellDef="let membership">
|
||||
<span class="state">{{getType(membership)}}</span>
|
||||
</td>
|
||||
</ng-container>
|
||||
|
||||
<ng-container matColumnDef="orgId">
|
||||
<th mat-header-cell *matHeaderCellDef> {{ 'USER.MEMBERSHIPS.ORGID' | translate }} </th>
|
||||
<td mat-cell *matCellDef="let membership">
|
||||
{{membership.orgId}} </td>
|
||||
</ng-container>
|
||||
|
||||
<ng-container matColumnDef="rolesList">
|
||||
<th mat-header-cell *matHeaderCellDef class="role-row"> {{ 'ROLESLABEL' | translate }} </th>
|
||||
<td mat-cell *matCellDef="let membership">
|
||||
<div class="membership-line">
|
||||
<mat-chip-list class="cnsl-chip-list" aria-label="role selection">
|
||||
<mat-chip class="cnsl-chip" *ngFor="let role of membership.rolesList" [removable]="!!userId"
|
||||
[selectable]="false" (removed)="removeRole(membership, role)">
|
||||
<div class="cnsl-chip-dot" [style.background]="getColor(role)"></div>
|
||||
<span>{{role | roletransform}}</span>
|
||||
<button *ngIf="!!userId" matChipRemove>
|
||||
<mat-icon>cancel</mat-icon>
|
||||
</button>
|
||||
</mat-chip>
|
||||
</mat-chip-list>
|
||||
<button matTooltip="{{'ACTIONS.EDIT' | translate}}" (click)="goto(membership)" mat-icon-button
|
||||
class="goto-btn">
|
||||
<i class="las la-angle-right"></i>
|
||||
</button>
|
||||
</div>
|
||||
</td>
|
||||
</ng-container>
|
||||
|
||||
<tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
|
||||
<tr class="highlight" mat-row *matRowDef="let row; columns: displayedColumns;">
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
<cnsl-paginator *ngIf="dataSource" class="paginator" #paginator [timestamp]="dataSource?.viewTimestamp"
|
||||
[pageSize]="INITIALPAGESIZE" [length]="dataSource.totalResult" [pageSizeOptions]="[25, 50, 100, 250]"
|
||||
(page)="changePage($event)">
|
||||
</cnsl-paginator>
|
||||
</cnsl-refresh-table>
|
||||
@@ -0,0 +1,93 @@
|
||||
.icon-button {
|
||||
margin-right: 0.5rem;
|
||||
}
|
||||
|
||||
.action {
|
||||
width: 40px;
|
||||
}
|
||||
|
||||
.form-field {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.roles-sp-wrapper {
|
||||
padding: 0.5rem;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
// .membership-auth-line {
|
||||
// display: flex;
|
||||
// flex-direction: row;
|
||||
// align-items: center;
|
||||
// justify-content: space-between;
|
||||
|
||||
// .membership-role-list {
|
||||
// display: flex;
|
||||
// flex-direction: column;
|
||||
// margin: 0.25rem;
|
||||
// font-size: 14px;
|
||||
// text-overflow: ellipsis;
|
||||
// overflow: hidden;
|
||||
// justify-items: center;
|
||||
// align-self: center;
|
||||
// }
|
||||
|
||||
// .goto-btn {
|
||||
// margin-left: 0.5rem;
|
||||
|
||||
// i {
|
||||
// height: 1rem;
|
||||
// line-height: 1rem;
|
||||
// font-size: 1rem;
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
.membership-line {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
|
||||
.membership-role-list {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
margin: 0.25rem;
|
||||
font-size: 14px;
|
||||
text-overflow: ellipsis;
|
||||
overflow: hidden;
|
||||
justify-items: center;
|
||||
align-self: center;
|
||||
}
|
||||
|
||||
.goto-btn {
|
||||
margin-left: 0.5rem;
|
||||
|
||||
i {
|
||||
height: 1rem;
|
||||
line-height: 1rem;
|
||||
font-size: 1rem;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.sa-icon {
|
||||
display: block;
|
||||
width: 32px;
|
||||
margin: 0 0.5rem;
|
||||
|
||||
i {
|
||||
margin: auto;
|
||||
}
|
||||
}
|
||||
|
||||
.pointer {
|
||||
outline: none;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.role-row {
|
||||
min-width: 200px;
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';
|
||||
import { MatSortModule } from '@angular/material/sort';
|
||||
import { MatTableModule } from '@angular/material/table';
|
||||
import { NoopAnimationsModule } from '@angular/platform-browser/animations';
|
||||
|
||||
import { MembershipsTableComponent } from './memberships-table.component';
|
||||
|
||||
describe('MembershipsTableComponent', () => {
|
||||
let component: MembershipsTableComponent;
|
||||
let fixture: ComponentFixture<MembershipsTableComponent>;
|
||||
|
||||
beforeEach(
|
||||
waitForAsync(() => {
|
||||
TestBed.configureTestingModule({
|
||||
declarations: [MembershipsTableComponent],
|
||||
imports: [NoopAnimationsModule, MatSortModule, MatTableModule],
|
||||
}).compileComponents();
|
||||
}),
|
||||
);
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(MembershipsTableComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should compile', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,295 @@
|
||||
import { SelectionModel } from '@angular/cdk/collections';
|
||||
import { Component, EventEmitter, Input, OnDestroy, OnInit, Output, ViewChild } from '@angular/core';
|
||||
import { MatTable } from '@angular/material/table';
|
||||
import { Router } from '@angular/router';
|
||||
import { Subject } from 'rxjs';
|
||||
import { takeUntil } from 'rxjs/operators';
|
||||
import { Org } from 'src/app/proto/generated/zitadel/org_pb';
|
||||
import { Membership } from 'src/app/proto/generated/zitadel/user_pb';
|
||||
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 { OverlayWorkflowService } from 'src/app/services/overlay/overlay-workflow.service';
|
||||
import { OrgContextChangedWorkflowOverlays } from 'src/app/services/overlay/workflows';
|
||||
import { StorageLocation, StorageService } from 'src/app/services/storage.service';
|
||||
import { ToastService } from 'src/app/services/toast.service';
|
||||
import { getMembershipColor } from 'src/app/utils/color';
|
||||
|
||||
import { PageEvent, PaginatorComponent } from '../paginator/paginator.component';
|
||||
import { MembershipsDataSource } from './memberships-datasource';
|
||||
|
||||
@Component({
|
||||
selector: 'cnsl-memberships-table',
|
||||
templateUrl: './memberships-table.component.html',
|
||||
styleUrls: ['./memberships-table.component.scss'],
|
||||
})
|
||||
export class MembershipsTableComponent implements OnInit, OnDestroy {
|
||||
public INITIALPAGESIZE: number = 25;
|
||||
@ViewChild(PaginatorComponent) public paginator!: PaginatorComponent;
|
||||
@ViewChild(MatTable) public table!: MatTable<Membership.AsObject>;
|
||||
@Input() public userId: string = '';
|
||||
public dataSource!: MembershipsDataSource;
|
||||
public selection: SelectionModel<any> = new SelectionModel<any>(true, []);
|
||||
|
||||
@Output() public changedSelection: EventEmitter<any[]> = new EventEmitter();
|
||||
@Output() public deleteMembership: EventEmitter<Membership.AsObject> = new EventEmitter();
|
||||
|
||||
private destroyed: Subject<void> = new Subject();
|
||||
public membershipRoleOptions: string[] = [];
|
||||
|
||||
public displayedColumns: string[] = ['displayName', 'type', 'rolesList'];
|
||||
public membershipToEdit: string = '';
|
||||
public loadingRoles: boolean = false;
|
||||
|
||||
constructor(
|
||||
private authService: GrpcAuthService,
|
||||
private toastService: ToastService,
|
||||
private mgmtService: ManagementService,
|
||||
private adminService: AdminService,
|
||||
private toast: ToastService,
|
||||
private router: Router,
|
||||
private workflowService: OverlayWorkflowService,
|
||||
private storageService: StorageService,
|
||||
) {
|
||||
this.dataSource = new MembershipsDataSource(this.authService, this.mgmtService);
|
||||
|
||||
this.selection.changed.pipe(takeUntil(this.destroyed)).subscribe((_) => {
|
||||
this.changedSelection.emit(this.selection.selected);
|
||||
});
|
||||
}
|
||||
|
||||
public ngOnInit(): void {
|
||||
this.changePage(this.paginator);
|
||||
}
|
||||
|
||||
public loadRoles(membership: Membership.AsObject, opened: boolean): void {
|
||||
if (opened) {
|
||||
this.loadingRoles = true;
|
||||
|
||||
if (membership.orgId && !membership.projectId && !membership.projectGrantId) {
|
||||
this.membershipToEdit = `${membership.orgId}${membership.projectId}${membership.projectGrantId}`;
|
||||
this.mgmtService
|
||||
.listOrgMemberRoles()
|
||||
.then((resp) => {
|
||||
this.membershipRoleOptions = resp.resultList;
|
||||
this.loadingRoles = false;
|
||||
})
|
||||
.catch((error) => {
|
||||
this.toastService.showError(error);
|
||||
this.loadingRoles = false;
|
||||
});
|
||||
} else if (membership.projectGrantId) {
|
||||
this.membershipToEdit = `${membership.orgId}${membership.projectId}${membership.projectGrantId}`;
|
||||
this.mgmtService
|
||||
.listProjectGrantMemberRoles()
|
||||
.then((resp) => {
|
||||
this.membershipRoleOptions = resp.resultList;
|
||||
this.loadingRoles = false;
|
||||
})
|
||||
.catch((error) => {
|
||||
this.toastService.showError(error);
|
||||
this.loadingRoles = false;
|
||||
});
|
||||
} else if (membership.projectId) {
|
||||
this.membershipToEdit = `${membership.orgId}${membership.projectId}${membership.projectGrantId}`;
|
||||
this.mgmtService
|
||||
.listProjectMemberRoles()
|
||||
.then((resp) => {
|
||||
this.membershipRoleOptions = resp.resultList;
|
||||
this.loadingRoles = false;
|
||||
})
|
||||
.catch((error) => {
|
||||
this.toastService.showError(error);
|
||||
this.loadingRoles = false;
|
||||
});
|
||||
} else if (membership.iam) {
|
||||
this.membershipToEdit = `IAM`;
|
||||
this.adminService
|
||||
.listIAMMemberRoles()
|
||||
.then((resp) => {
|
||||
console.log(resp);
|
||||
this.membershipRoleOptions = resp.rolesList;
|
||||
this.loadingRoles = false;
|
||||
})
|
||||
.catch((error) => {
|
||||
this.toastService.showError(error);
|
||||
this.loadingRoles = false;
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public goto(membership: Membership.AsObject): void {
|
||||
const org: Org.AsObject | null = this.storageService.getItem('organization', StorageLocation.session);
|
||||
|
||||
if (membership.orgId && !membership.projectId && !membership.projectGrantId) {
|
||||
// only shown on auth user, or if currentOrg === resourceOwner
|
||||
this.authService
|
||||
.getActiveOrg(membership.orgId)
|
||||
.then((membershipOrg) => {
|
||||
this.router.navigate(['/org/members']).then(() => {
|
||||
this.startOrgContextWorkflow(membershipOrg, org);
|
||||
});
|
||||
})
|
||||
.catch(() => {
|
||||
this.toast.showInfo('USER.MEMBERSHIPS.NOPERMISSIONTOEDIT', true);
|
||||
});
|
||||
} else if (membership.projectGrantId && membership.details?.resourceOwner) {
|
||||
// only shown on auth user
|
||||
this.authService
|
||||
.getActiveOrg(membership.details?.resourceOwner)
|
||||
.then((membershipOrg) => {
|
||||
this.router.navigate(['/granted-projects', membership.projectId, 'grants', membership.projectGrantId]).then(() => {
|
||||
this.startOrgContextWorkflow(membershipOrg, org);
|
||||
});
|
||||
})
|
||||
.catch(() => {
|
||||
this.toast.showInfo('USER.MEMBERSHIPS.NOPERMISSIONTOEDIT', true);
|
||||
});
|
||||
} else if (membership.projectId && membership.details?.resourceOwner) {
|
||||
// only shown on auth user, or if currentOrg === resourceOwner
|
||||
this.authService
|
||||
.getActiveOrg(membership.details?.resourceOwner)
|
||||
.then((membershipOrg) => {
|
||||
this.router.navigate(['/projects', membership.projectId, 'members']).then(() => {
|
||||
this.startOrgContextWorkflow(membershipOrg, org);
|
||||
});
|
||||
})
|
||||
.catch(() => {
|
||||
this.toast.showInfo('USER.MEMBERSHIPS.NOPERMISSIONTOEDIT', true);
|
||||
});
|
||||
} else if (membership.iam) {
|
||||
// only shown on auth user
|
||||
this.router.navigate(['/system/members']);
|
||||
}
|
||||
}
|
||||
|
||||
// public canNavigateToEdit(membership: Membership.AsObject): Observable<boolean> {
|
||||
// if (membership.orgId && !membership.projectId && !membership.projectGrantId) {
|
||||
// return this.authService.isAllowed(['org.member.read:' + membership.orgId]);
|
||||
// } else if (membership.projectGrantId && membership.details?.resourceOwner) {
|
||||
// return from(this.authService.getActiveOrg(membership.details?.resourceOwner)).pipe(
|
||||
// switchMap(() => this.authService.isAllowed(['project.grant.member.read:' + membership.projectId])),
|
||||
// catchError(() => of(false)),
|
||||
// );
|
||||
// } else if (membership.projectId && membership.details?.resourceOwner) {
|
||||
// return from(this.authService.getActiveOrg(membership.details?.resourceOwner)).pipe(
|
||||
// take(1),
|
||||
// switchMap(() => this.authService.isAllowed(['project.member.read:' + membership.projectId])),
|
||||
// catchError(() => of(false)),
|
||||
// );
|
||||
// } else if (membership.iam) {
|
||||
// return this.authService.isAllowed(['iam.member.read']);
|
||||
// } else {
|
||||
// return of(false);
|
||||
// }
|
||||
// }
|
||||
|
||||
private startOrgContextWorkflow(membershipOrg: Org.AsObject, currentOrg?: Org.AsObject | null): void {
|
||||
if (!currentOrg || (membershipOrg.id && currentOrg.id && currentOrg.id !== membershipOrg.id)) {
|
||||
setTimeout(() => {
|
||||
this.workflowService.startWorkflow(OrgContextChangedWorkflowOverlays, null);
|
||||
}, 1000);
|
||||
}
|
||||
}
|
||||
|
||||
public getType(membership: Membership.AsObject): string {
|
||||
if (membership.orgId && !membership.projectId && !membership.projectGrantId) {
|
||||
return 'Organization';
|
||||
} else if (membership.projectGrantId) {
|
||||
return 'Project Grant';
|
||||
} else if (membership.projectId) {
|
||||
return 'Project';
|
||||
} else if (membership.iam) {
|
||||
return 'IAM';
|
||||
} else {
|
||||
return '';
|
||||
}
|
||||
}
|
||||
|
||||
public ngOnDestroy(): void {
|
||||
this.destroyed.next();
|
||||
}
|
||||
|
||||
public isAllSelected(): boolean {
|
||||
const numSelected = this.selection.selected.length;
|
||||
const numRows = this.dataSource.membershipsSubject.value.length;
|
||||
return numSelected === numRows;
|
||||
}
|
||||
|
||||
public masterToggle(): void {
|
||||
this.isAllSelected()
|
||||
? this.selection.clear()
|
||||
: this.dataSource.membershipsSubject.value.forEach((row) => this.selection.select(row));
|
||||
}
|
||||
|
||||
public changePage(event?: PageEvent): any {
|
||||
this.selection.clear();
|
||||
return this.userId
|
||||
? this.dataSource.loadMemberships(this.userId, event?.pageIndex ?? 0, event?.pageSize ?? this.INITIALPAGESIZE)
|
||||
: this.dataSource.loadMyMemberships(event?.pageIndex ?? 0, event?.pageSize ?? this.INITIALPAGESIZE);
|
||||
}
|
||||
|
||||
public isCurrentMembership(membership: Membership.AsObject): boolean {
|
||||
return (
|
||||
this.membershipToEdit ===
|
||||
(membership.iam ? 'IAM' : `${membership.orgId}${membership.projectId}${membership.projectGrantId}`)
|
||||
);
|
||||
}
|
||||
|
||||
public getColor(role: string): string {
|
||||
const color = getMembershipColor(role);
|
||||
return color[500];
|
||||
}
|
||||
|
||||
public removeRole(membership: Membership.AsObject, role: string): void {
|
||||
const newRoles = Object.assign([], membership.rolesList);
|
||||
const index = newRoles.findIndex((r) => r === role);
|
||||
if (index > -1) {
|
||||
newRoles.splice(index);
|
||||
if (membership.orgId) {
|
||||
console.log('org member', membership.userId, newRoles);
|
||||
this.mgmtService
|
||||
.updateOrgMember(membership.userId, newRoles)
|
||||
.then(() => {
|
||||
this.toast.showInfo('USER.MEMBERSHIPS.UPDATED', true);
|
||||
this.changePage(this.paginator);
|
||||
})
|
||||
.catch((error) => {
|
||||
this.toastService.showError(error);
|
||||
});
|
||||
} else if (membership.projectGrantId) {
|
||||
this.mgmtService
|
||||
.updateProjectGrantMember(membership.projectId, membership.projectGrantId, membership.userId, newRoles)
|
||||
.then(() => {
|
||||
this.toast.showInfo('USER.MEMBERSHIPS.UPDATED', true);
|
||||
this.changePage(this.paginator);
|
||||
})
|
||||
.catch((error) => {
|
||||
this.toastService.showError(error);
|
||||
});
|
||||
} else if (membership.projectId) {
|
||||
console.log(membership.projectId, membership.userId, newRoles);
|
||||
this.mgmtService
|
||||
.updateProjectMember(membership.projectId, membership.userId, newRoles)
|
||||
.then(() => {
|
||||
this.toast.showInfo('USER.MEMBERSHIPS.UPDATED', true);
|
||||
this.changePage(this.paginator);
|
||||
})
|
||||
.catch((error) => {
|
||||
this.toastService.showError(error);
|
||||
});
|
||||
} else if (membership.iam) {
|
||||
this.adminService
|
||||
.updateIAMMember(membership.userId, newRoles)
|
||||
.then(() => {
|
||||
this.toast.showInfo('USER.MEMBERSHIPS.UPDATED', true);
|
||||
this.changePage(this.paginator);
|
||||
})
|
||||
.catch((error) => {
|
||||
this.toastService.showError(error);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { NgModule } from '@angular/core';
|
||||
import { FormsModule } from '@angular/forms';
|
||||
import { MatButtonModule } from '@angular/material/button';
|
||||
import { MatCheckboxModule } from '@angular/material/checkbox';
|
||||
import { MatChipsModule } from '@angular/material/chips';
|
||||
import { MatIconModule } from '@angular/material/icon';
|
||||
import { MatProgressSpinnerModule } from '@angular/material/progress-spinner';
|
||||
import { MatSelectModule } from '@angular/material/select';
|
||||
import { MatSortModule } from '@angular/material/sort';
|
||||
import { MatTableModule } from '@angular/material/table';
|
||||
import { MatTooltipModule } from '@angular/material/tooltip';
|
||||
import { RouterModule } from '@angular/router';
|
||||
import { TranslateModule } from '@ngx-translate/core';
|
||||
import { InputModule } from 'src/app/modules/input/input.module';
|
||||
import { HasRolePipeModule } from 'src/app/pipes/has-role-pipe/has-role-pipe.module';
|
||||
import { RoleTransformPipeModule } from 'src/app/pipes/role-transform/role-transform.module';
|
||||
|
||||
import { AvatarModule } from '../avatar/avatar.module';
|
||||
import { PaginatorModule } from '../paginator/paginator.module';
|
||||
import { RefreshTableModule } from '../refresh-table/refresh-table.module';
|
||||
import { MembershipsTableComponent } from './memberships-table.component';
|
||||
|
||||
@NgModule({
|
||||
declarations: [MembershipsTableComponent],
|
||||
imports: [
|
||||
CommonModule,
|
||||
InputModule,
|
||||
MatSelectModule,
|
||||
MatCheckboxModule,
|
||||
MatIconModule,
|
||||
PaginatorModule,
|
||||
MatChipsModule,
|
||||
MatTooltipModule,
|
||||
RoleTransformPipeModule,
|
||||
FormsModule,
|
||||
TranslateModule,
|
||||
RefreshTableModule,
|
||||
RouterModule,
|
||||
AvatarModule,
|
||||
MatTableModule,
|
||||
MatSortModule,
|
||||
MatProgressSpinnerModule,
|
||||
MatButtonModule,
|
||||
HasRolePipeModule,
|
||||
],
|
||||
exports: [MembershipsTableComponent],
|
||||
})
|
||||
export class MembershipsTableModule {}
|
||||
Reference in New Issue
Block a user