fix(console): dependencies, list my memberships, passwordless texts, privatelabelling issues (#2142)

* fix: list my memberships in console

* show manager context in detail page

* console dependencies (#2161)

* feat: User metadata (#2025)

* feat: user meta data events

* feat: user meta data set tests

* feat: user meta data tests

* feat: user meta data in protos

* feat: user meta data command api

* feat: user meta data query side

* feat: proto correct order, fix handlers

* feat: proto correct order

* feat: fixes of pr comments

* feat: fixes of pr comments

* feat: value as byte array

* feat: metadata feature

* Update internal/auth/repository/eventsourcing/handler/meta_data.go

Co-authored-by: Silvan <silvan.reusser@gmail.com>

* Update internal/command/user_meta_data.go

Co-authored-by: Silvan <silvan.reusser@gmail.com>

* Update proto/zitadel/metadata.proto

Co-authored-by: Silvan <silvan.reusser@gmail.com>

* Update proto/zitadel/metadata.proto

Co-authored-by: Silvan <silvan.reusser@gmail.com>

* fix: rename metadata files and table

* fix: rename meta data to metadat in protos

* Update internal/domain/metadata.go

Co-authored-by: Silvan <silvan.reusser@gmail.com>

* fix: rename vars

* fix: rebiuld docs

* Update internal/iam/repository/view/metadata_view.go

Co-authored-by: Silvan <silvan.reusser@gmail.com>

Co-authored-by: Silvan <silvan.reusser@gmail.com>

* fix(auth): read privacy policy from eventstore if not found (#2125)

* fix(auth): read privacy policy from eventstore if not found

* Update internal/auth/repository/eventsourcing/eventstore/auth_request.go

Co-authored-by: Fabi <38692350+fgerschwiler@users.noreply.github.com>

Co-authored-by: Fabi <38692350+fgerschwiler@users.noreply.github.com>

* chore(deps-dev): bump @angular/cli from 12.1.1 to 12.2.0 in /console (#2149)

Bumps [@angular/cli](https://github.com/angular/angular-cli) from 12.1.1 to 12.2.0.
- [Release notes](https://github.com/angular/angular-cli/releases)
- [Changelog](https://github.com/angular/angular-cli/blob/master/CHANGELOG.md)
- [Commits](https://github.com/angular/angular-cli/compare/v12.1.1...12.2.0)

---
updated-dependencies:
- dependency-name: "@angular/cli"
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* chore(deps): bump @angular/material-moment-adapter in /console (#2147)

Bumps [@angular/material-moment-adapter](https://github.com/angular/components) from 12.1.1 to 12.2.0.
- [Release notes](https://github.com/angular/components/releases)
- [Changelog](https://github.com/angular/components/blob/master/CHANGELOG.md)
- [Commits](https://github.com/angular/components/compare/12.1.1...12.2.0)

---
updated-dependencies:
- dependency-name: "@angular/material-moment-adapter"
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* chore(deps-dev): bump ts-node from 9.1.1 to 10.2.0 in /console (#2145)

Bumps [ts-node](https://github.com/TypeStrong/ts-node) from 9.1.1 to 10.2.0.
- [Release notes](https://github.com/TypeStrong/ts-node/releases)
- [Commits](https://github.com/TypeStrong/ts-node/compare/v9.1.1...v10.2.0)

---
updated-dependencies:
- dependency-name: ts-node
  dependency-type: direct:development
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* chore(deps-dev): bump @types/jasmine from 3.7.7 to 3.8.2 in /console (#2115)

Bumps [@types/jasmine](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/jasmine) from 3.7.7 to 3.8.2.
- [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases)
- [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/jasmine)

---
updated-dependencies:
- dependency-name: "@types/jasmine"
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* chore(deps): bump libphonenumber-js from 1.9.19 to 1.9.23 in /console (#2114)

Bumps [libphonenumber-js](https://gitlab.com/catamphetamine/libphonenumber-js) from 1.9.19 to 1.9.23.
- [Release notes](https://gitlab.com/catamphetamine/libphonenumber-js/tags)
- [Changelog](https://gitlab.com/catamphetamine/libphonenumber-js/blob/master/CHANGELOG.md)
- [Commits](https://gitlab.com/catamphetamine/libphonenumber-js/compare/v1.9.19...v1.9.23)

---
updated-dependencies:
- dependency-name: libphonenumber-js
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* chore(deps): bump @angular/core and @angular/animations in /console (#2072)

Bumps [@angular/core](https://github.com/angular/angular/tree/HEAD/packages/core) and [@angular/animations](https://github.com/angular/angular/tree/HEAD/packages/animations). These dependencies needed to be updated together.

Updates `@angular/core` from 12.0.3 to 12.1.3
- [Release notes](https://github.com/angular/angular/releases)
- [Changelog](https://github.com/angular/angular/blob/master/CHANGELOG.md)
- [Commits](https://github.com/angular/angular/commits/12.1.3/packages/core)

Updates `@angular/animations` from 12.0.3 to 12.1.3
- [Release notes](https://github.com/angular/angular/releases)
- [Changelog](https://github.com/angular/angular/blob/master/CHANGELOG.md)
- [Commits](https://github.com/angular/angular/commits/12.1.3/packages/animations)

---
updated-dependencies:
- dependency-name: "@angular/core"
  dependency-type: direct:production
  update-type: version-update:semver-minor
- dependency-name: "@angular/animations"
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* chore(deps-dev): bump stylelint-config-standard in /console (#2065)

Bumps [stylelint-config-standard](https://github.com/stylelint/stylelint-config-standard) from 20.0.0 to 22.0.0.
- [Release notes](https://github.com/stylelint/stylelint-config-standard/releases)
- [Changelog](https://github.com/stylelint/stylelint-config-standard/blob/master/CHANGELOG.md)
- [Commits](https://github.com/stylelint/stylelint-config-standard/compare/20.0.0...22.0.0)

---
updated-dependencies:
- dependency-name: stylelint-config-standard
  dependency-type: direct:development
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* chore(deps): bump @types/google-protobuf in /console (#2000)

Bumps [@types/google-protobuf](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/google-protobuf) from 3.15.2 to 3.15.3.
- [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases)
- [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/google-protobuf)

---
updated-dependencies:
- dependency-name: "@types/google-protobuf"
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* package

* angular core

* update angular core, cdk, allow commonjs deps

Co-authored-by: Fabi <38692350+fgerschwiler@users.noreply.github.com>
Co-authored-by: Silvan <silvan.reusser@gmail.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* fix labelpolicy max size, double trigger, labels

* lint styles

* disable rule, add passwordless message texts

* lint exceeding linelimit

* login texts

* remove duplicate keyname

* rm unused

* fix: read lockout policy

Co-authored-by: Fabi <38692350+fgerschwiler@users.noreply.github.com>
Co-authored-by: Silvan <silvan.reusser@gmail.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Livio Amstutz <livio.a@gmail.com>
This commit is contained in:
Max Peintner
2021-08-16 14:44:20 +02:00
committed by GitHub
parent 490d087d45
commit 90f1647bb9
40 changed files with 1970 additions and 996 deletions

View File

@@ -3,55 +3,75 @@ 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 MembershipDetailDataSource extends DataSource<Membership.AsObject> {
public totalResult: number = 0;
public viewTimestamp!: Timestamp.AsObject;
public membersSubject: BehaviorSubject<Membership.AsObject[]>
= new BehaviorSubject<Membership.AsObject[]>([]);
private loadingSubject: BehaviorSubject<boolean> = new BehaviorSubject<boolean>(false);
public loading$: Observable<boolean> = this.loadingSubject.asObservable();
public totalResult: number = 0;
public viewTimestamp!: Timestamp.AsObject;
public membersSubject: BehaviorSubject<Membership.AsObject[]>
= new BehaviorSubject<Membership.AsObject[]>([]);
private loadingSubject: BehaviorSubject<boolean> = new BehaviorSubject<boolean>(false);
public loading$: Observable<boolean> = this.loadingSubject.asObservable();
constructor(private mgmtUserService: ManagementService) {
super();
}
constructor(private mgmtUserService: ManagementService, private authServce: GrpcAuthService) {
super();
}
public loadMemberships(userId: string, pageIndex: number, pageSize: number): void {
const offset = pageIndex * pageSize;
public loadMemberships(userId: string, pageIndex: number, pageSize: number): void {
const offset = pageIndex * pageSize;
this.loadingSubject.next(true);
from(this.mgmtUserService.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.membersSubject.next(members);
});
}
this.loadingSubject.next(true);
from(this.mgmtUserService.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.membersSubject.next(members);
});
}
public loadMyMemberships(pageIndex: number, pageSize: number): void {
const offset = pageIndex * pageSize;
this.loadingSubject.next(true);
from(this.authServce.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.membersSubject.next(members);
});
}
/**
* Connect this data source to the table. The table will only update when
* the returned stream emits new items.
* @returns A stream of the items to be rendered.
*/
public connect(): Observable<Membership.AsObject[]> {
return this.membersSubject.asObservable();
}
/**
* Connect this data source to the table. The table will only update when
* the returned stream emits new items.
* @returns A stream of the items to be rendered.
*/
public connect(): Observable<Membership.AsObject[]> {
return this.membersSubject.asObservable();
}
/**
* Called when the table is being destroyed. Use this function, to clean up
* any open connections or free any held resources that were set up during connect.
*/
public disconnect(): void {
this.membersSubject.complete();
this.loadingSubject.complete();
}
/**
* Called when the table is being destroyed. Use this function, to clean up
* any open connections or free any held resources that were set up during connect.
*/
public disconnect(): void {
this.membersSubject.complete();
this.loadingSubject.complete();
}
}

View File

@@ -1,6 +1,11 @@
<app-detail-layout [backRouterLink]="[ '/users', user?.id]"
title="{{user?.human?.displayName}} {{ 'USER.MEMBERSHIPS.TITLE' | translate }}"
description="{{ 'USER.MEMBERSHIPS.DESCRIPTION' | translate }}">
<cnsl-info-section class="context-wrapper">
<span *ngIf="isMe">{{'USER.MEMBERSHIPS.USERCONTEXT' | translate}}</span>
<span *ngIf="!isMe">{{'USER.MEMBERSHIPS.ORGCONTEXT' | translate}}</span>
</cnsl-info-section>
<app-refresh-table class="refresh-table" (refreshed)="refreshPage()" [dataSize]="dataSource?.totalResult"
[timestamp]="dataSource?.viewTimestamp" [selection]="selection" [loading]="dataSource?.loading$ | async">

View File

@@ -1,3 +1,8 @@
.context-wrapper {
margin-bottom: 1rem;
display: block;
}
.refresh-table {
width: 100%;
}

View File

@@ -3,233 +3,257 @@ import { AfterViewInit, Component, ViewChild } from '@angular/core';
import { MatDialog } from '@angular/material/dialog';
import { MatTable } from '@angular/material/table';
import { ActivatedRoute } from '@angular/router';
import { tap } from 'rxjs/operators';
import { map, switchMap, tap } from 'rxjs/operators';
import { CreationType, MemberCreateDialogComponent } from 'src/app/modules/add-member-dialog/member-create-dialog.component';
import { PaginatorComponent } from 'src/app/modules/paginator/paginator.component';
import { Membership, User } 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 { ToastService } from 'src/app/services/toast.service';
import { MembershipDetailDataSource } from './membership-detail-datasource';
@Component({
selector: 'app-membership-detail',
templateUrl: './membership-detail.component.html',
styleUrls: ['./membership-detail.component.scss'],
selector: 'app-membership-detail',
templateUrl: './membership-detail.component.html',
styleUrls: ['./membership-detail.component.scss'],
})
export class MembershipDetailComponent implements AfterViewInit {
public user!: User.AsObject;
public user!: User.AsObject;
@ViewChild(PaginatorComponent) public paginator!: PaginatorComponent;
@ViewChild(MatTable) public table!: MatTable<Membership.AsObject>;
public dataSource!: MembershipDetailDataSource;
public selection: SelectionModel<Membership.AsObject>
= new SelectionModel<Membership.AsObject>(true, []);
@ViewChild(PaginatorComponent) public paginator!: PaginatorComponent;
@ViewChild(MatTable) public table!: MatTable<Membership.AsObject>;
public dataSource!: MembershipDetailDataSource;
public selection: SelectionModel<Membership.AsObject>
= new SelectionModel<Membership.AsObject>(true, []);
public memberRoleOptions: string[] = [];
public memberRoleOptions: string[] = [];
/** Columns displayed in the table. Columns IDs can be added, removed, or reordered. */
public displayedColumns: string[] = ['select', 'memberType', 'displayName', 'creationDate', 'changeDate', 'roles', 'actions'];
/** Columns displayed in the table. Columns IDs can be added, removed, or reordered. */
public displayedColumns: string[] = ['select', 'memberType', 'displayName', 'creationDate', 'changeDate', 'roles', 'actions'];
public loading: boolean = false;
public memberships!: Membership.AsObject[];
public loading: boolean = false;
public memberships!: Membership.AsObject[];
constructor(
activatedRoute: ActivatedRoute,
private dialog: MatDialog,
private toast: ToastService,
private mgmtService: ManagementService,
private adminService: AdminService,
) {
activatedRoute.params.subscribe(data => {
const { id } = data;
if (id) {
this.mgmtService.getUserByID(id).then(resp => {
if (resp.user) {
this.user = resp.user;
this.dataSource = new MembershipDetailDataSource(this.mgmtService);
this.dataSource.loadMemberships(
this.user.id,
0,
50,
);
}
}).catch(err => {
console.error(err);
});
}
});
}
public isMe: boolean = false;
public ngAfterViewInit(): void {
this.paginator.page
.pipe(
tap(() => this.loadMembershipsPage()),
)
.subscribe();
}
constructor(
authService: GrpcAuthService,
activatedRoute: ActivatedRoute,
private dialog: MatDialog,
private toast: ToastService,
private mgmtService: ManagementService,
private adminService: AdminService,
) {
activatedRoute.params
.pipe(switchMap(({ id }) => {
return authService.user.pipe(
map(user => user?.id === id),
tap((isMe) => {
this.isMe = isMe;
private loadMembershipsPage(): void {
this.dataSource.loadMemberships(
this.user.id,
this.paginator.pageIndex,
this.paginator.pageSize,
);
}
public isAllSelected(): boolean {
const numSelected = this.selection.selected.length;
const numRows = this.dataSource.membersSubject.value.length;
return numSelected === numRows;
}
public masterToggle(): void {
this.isAllSelected() ?
this.selection.clear() :
this.dataSource.membersSubject.value.forEach(row => this.selection.select(row));
}
public addMember(): void {
const dialogRef = this.dialog.open(MemberCreateDialogComponent, {
width: '400px',
data: {
user: this.user,
},
});
dialogRef.afterClosed().subscribe(resp => {
if (resp && resp.creationType !== undefined) {
switch (resp.creationType) {
case CreationType.IAM:
this.createIamMember(resp);
break;
case CreationType.ORG:
this.createOrgMember(resp);
break;
case CreationType.PROJECT_OWNED:
this.createOwnedProjectMember(resp);
break;
case CreationType.PROJECT_GRANTED:
this.createGrantedProjectMember(resp);
break;
if (isMe) {
this.mgmtService.getUserByID(id).then(resp => {
if (resp.user) {
this.user = resp.user;
this.dataSource = new MembershipDetailDataSource(this.mgmtService, authService);
this.dataSource.loadMyMemberships(
0,
50,
);
}
}).catch(err => {
console.error(err);
});
} else {
this.mgmtService.getUserByID(id).then(resp => {
if (resp.user) {
this.user = resp.user;
this.dataSource = new MembershipDetailDataSource(this.mgmtService, authService);
this.dataSource.loadMemberships(
this.user.id,
0,
50,
);
}
}).catch(err => {
console.error(err);
});
}
}),
);
})).subscribe();
}
public ngAfterViewInit(): void {
this.paginator.page
.pipe(
tap(() => this.loadMembershipsPage()),
)
.subscribe();
}
private loadMembershipsPage(): void {
this.dataSource.loadMemberships(
this.user.id,
this.paginator.pageIndex,
this.paginator.pageSize,
);
}
public isAllSelected(): boolean {
const numSelected = this.selection.selected.length;
const numRows = this.dataSource.membersSubject.value.length;
return numSelected === numRows;
}
public masterToggle(): void {
this.isAllSelected() ?
this.selection.clear() :
this.dataSource.membersSubject.value.forEach(row => this.selection.select(row));
}
public addMember(): void {
const dialogRef = this.dialog.open(MemberCreateDialogComponent, {
width: '400px',
data: {
user: this.user,
},
});
dialogRef.afterClosed().subscribe(resp => {
if (resp && resp.creationType !== undefined) {
switch (resp.creationType) {
case CreationType.IAM:
this.createIamMember(resp);
break;
case CreationType.ORG:
this.createOrgMember(resp);
break;
case CreationType.PROJECT_OWNED:
this.createOwnedProjectMember(resp);
break;
case CreationType.PROJECT_GRANTED:
this.createGrantedProjectMember(resp);
break;
}
}
});
}
public async loadManager(userId: string): Promise<void> {
this.mgmtService.listUserMemberships(userId, 100, 0, []).then(response => {
this.memberships = response.resultList;
this.loading = false;
});
}
public createIamMember(response: any): void {
const users: User.AsObject[] = response.users;
const roles: string[] = response.roles;
if (users && users.length && roles && roles.length) {
Promise.all(users.map(user => {
return this.adminService.addIAMMember(user.id, roles);
})).then(() => {
this.toast.showInfo('IAM.TOAST.MEMBERADDED', true);
setTimeout(() => {
this.refreshPage();
}, 1000);
}).catch(error => {
this.toast.showError(error);
});
}
}
private createOrgMember(response: any): void {
const users: User.AsObject[] = response.users;
const roles: string[] = response.roles;
if (users && users.length && roles && roles.length) {
Promise.all(users.map(user => {
return this.mgmtService.addOrgMember(user.id, roles);
})).then(() => {
this.toast.showInfo('ORG.TOAST.MEMBERADDED', true);
setTimeout(() => {
this.refreshPage();
}, 1000);
}).catch(error => {
this.toast.showError(error);
});
}
}
private createGrantedProjectMember(response: any): void {
const users: User.AsObject[] = response.users;
const roles: string[] = response.roles;
if (users && users.length && roles && roles.length) {
users.forEach(user => {
return this.mgmtService.addProjectGrantMember(
response.projectId,
response.grantId,
user.id,
roles,
).then(() => {
this.toast.showInfo('PROJECT.TOAST.MEMBERADDED', true);
setTimeout(() => {
this.refreshPage();
}, 1000);
}).catch(error => {
this.toast.showError(error);
});
});
}
}
private createOwnedProjectMember(response: any): void {
const users: User.AsObject[] = response.users;
const roles: string[] = response.roles;
if (users && users.length && roles && roles.length) {
users.forEach(user => {
return this.mgmtService.addProjectMember(response.projectId, user.id, roles)
.then(() => {
this.toast.showInfo('PROJECT.TOAST.MEMBERADDED', true);
setTimeout(() => {
this.refreshPage();
}, 1000);
}).catch(error => {
this.toast.showError(error);
});
});
}
}
public removeMembership(membership: Membership.AsObject): void {
let prom;
if (membership.projectId && membership.projectGrantId && membership.userId) {
prom = this.mgmtService.removeProjectGrantMember(
membership.projectId,
membership.projectGrantId,
membership.userId,
);
} else if (membership.projectId && membership.userId) {
prom = this.mgmtService.removeProjectMember(membership.projectId, membership.userId);
} else if (membership.orgId && membership.userId) {
prom = this.mgmtService.removeOrgMember(membership.userId);
} else if (membership.userId) {
prom = this.adminService.removeIAMMember(membership.userId);
}
public async loadManager(userId: string): Promise<void> {
this.mgmtService.listUserMemberships(userId, 100, 0, []).then(response => {
this.memberships = response.resultList;
this.loading = false;
});
if (prom) {
prom.then(() => {
this.toast.showInfo('PROJECT.TOAST.MEMBERREMOVED', true);
this.refreshPage();
}).catch(error => this.toast.showError(error));
}
}
public createIamMember(response: any): void {
const users: User.AsObject[] = response.users;
const roles: string[] = response.roles;
if (users && users.length && roles && roles.length) {
Promise.all(users.map(user => {
return this.adminService.addIAMMember(user.id, roles);
})).then(() => {
this.toast.showInfo('IAM.TOAST.MEMBERADDED', true);
setTimeout(() => {
this.refreshPage();
}, 1000);
}).catch(error => {
this.toast.showError(error);
});
}
}
private createOrgMember(response: any): void {
const users: User.AsObject[] = response.users;
const roles: string[] = response.roles;
if (users && users.length && roles && roles.length) {
Promise.all(users.map(user => {
return this.mgmtService.addOrgMember(user.id, roles);
})).then(() => {
this.toast.showInfo('ORG.TOAST.MEMBERADDED', true);
setTimeout(() => {
this.refreshPage();
}, 1000);
}).catch(error => {
this.toast.showError(error);
});
}
}
private createGrantedProjectMember(response: any): void {
const users: User.AsObject[] = response.users;
const roles: string[] = response.roles;
if (users && users.length && roles && roles.length) {
users.forEach(user => {
return this.mgmtService.addProjectGrantMember(
response.projectId,
response.grantId,
user.id,
roles,
).then(() => {
this.toast.showInfo('PROJECT.TOAST.MEMBERADDED', true);
setTimeout(() => {
this.refreshPage();
}, 1000);
}).catch(error => {
this.toast.showError(error);
});
});
}
}
private createOwnedProjectMember(response: any): void {
const users: User.AsObject[] = response.users;
const roles: string[] = response.roles;
if (users && users.length && roles && roles.length) {
users.forEach(user => {
return this.mgmtService.addProjectMember(response.projectId, user.id, roles)
.then(() => {
this.toast.showInfo('PROJECT.TOAST.MEMBERADDED', true);
setTimeout(() => {
this.refreshPage();
}, 1000);
}).catch(error => {
this.toast.showError(error);
});
});
}
}
public removeMembership(membership: Membership.AsObject): void {
let prom;
if (membership.projectId && membership.projectGrantId && membership.userId) {
prom = this.mgmtService.removeProjectGrantMember(
membership.projectId,
membership.projectGrantId,
membership.userId,
);
} else if (membership.projectId && membership.userId) {
prom = this.mgmtService.removeProjectMember(membership.projectId, membership.userId);
} else if (membership.orgId && membership.userId) {
prom = this.mgmtService.removeOrgMember(membership.userId);
} else if (membership.userId) {
prom = this.adminService.removeIAMMember(membership.userId);
}
if (prom) {
prom.then(() => {
this.toast.showInfo('PROJECT.TOAST.MEMBERREMOVED', true);
this.refreshPage();
}).catch(error => this.toast.showError(error));
}
}
public refreshPage(): void {
this.selection.clear();
this.dataSource.loadMemberships(this.user.id, this.paginator.pageIndex, this.paginator.pageSize);
}
public refreshPage(): void {
this.selection.clear();
this.dataSource.loadMemberships(this.user.id, this.paginator.pageIndex, this.paginator.pageSize);
}
}

View File

@@ -10,6 +10,7 @@ import { RouterModule, Routes } from '@angular/router';
import { TranslateModule } from '@ngx-translate/core';
import { HasRoleModule } from 'src/app/directives/has-role/has-role.module';
import { DetailLayoutModule } from 'src/app/modules/detail-layout/detail-layout.module';
import { InfoSectionModule } from 'src/app/modules/info-section/info-section.module';
import { PaginatorModule } from 'src/app/modules/paginator/paginator.module';
import { RefreshTableModule } from 'src/app/modules/refresh-table/refresh-table.module';
import { HasRolePipeModule } from 'src/app/pipes/has-role-pipe/has-role-pipe.module';
@@ -19,34 +20,35 @@ import { TimestampToDatePipeModule } from 'src/app/pipes/timestamp-to-date-pipe/
import { MembershipDetailComponent } from './membership-detail.component';
const routes: Routes = [
{
path: '',
component: MembershipDetailComponent,
canActivate: [],
data: {
roles: ['user.write'],
},
{
path: '',
component: MembershipDetailComponent,
canActivate: [],
data: {
roles: ['user.write'],
},
},
];
@NgModule({
declarations: [MembershipDetailComponent],
imports: [
CommonModule,
RouterModule.forChild(routes),
TranslateModule,
DetailLayoutModule,
MatCheckboxModule,
MatTableModule,
PaginatorModule,
MatProgressSpinnerModule,
LocalizedDatePipeModule,
TimestampToDatePipeModule,
HasRoleModule,
MatIconModule,
MatButtonModule,
HasRolePipeModule,
RefreshTableModule,
MatTooltipModule,
],
declarations: [MembershipDetailComponent],
imports: [
CommonModule,
RouterModule.forChild(routes),
TranslateModule,
DetailLayoutModule,
MatCheckboxModule,
MatTableModule,
PaginatorModule,
MatProgressSpinnerModule,
LocalizedDatePipeModule,
TimestampToDatePipeModule,
HasRoleModule,
MatIconModule,
MatButtonModule,
HasRolePipeModule,
RefreshTableModule,
MatTooltipModule,
InfoSectionModule,
],
})
export class MembershipDetailModule { }

View File

@@ -98,7 +98,7 @@
span {
max-width: 30px;
text-overflow: ellipsis;
font-weight: 800;
font-weight: 300;
display: block;
white-space: nowrap;
overflow: hidden;

View File

@@ -55,7 +55,7 @@ export class MembershipsComponent implements OnInit {
public async loadManager(userId: string): Promise<void> {
if (this.auth) {
this.authService.listMyUserGrants(100, 0, []).then(resp => {
this.authService.listMyMemberships(100, 0, []).then(resp => {
this.memberships = resp.resultList;
this.totalResult = resp.details?.totalResult || 0;
this.loading = false;