mirror of
https://github.com/zitadel/zitadel.git
synced 2024-12-12 02:54:20 +00:00
fix(console): ui issues (#1670)
* mark required fields * membership overflow, deactivate btn * app create show info * remove padding * lint scss * fix count of results * rm log
This commit is contained in:
parent
c4607409a5
commit
10e85d999e
@ -7,8 +7,8 @@ import { Member } from 'src/app/proto/generated/zitadel/member_pb';
|
||||
import { ManagementService } from 'src/app/services/mgmt.service';
|
||||
|
||||
export enum ProjectType {
|
||||
PROJECTTYPE_OWNED = 'OWNED',
|
||||
PROJECTTYPE_GRANTED = 'GRANTED',
|
||||
PROJECTTYPE_OWNED = 'OWNED',
|
||||
PROJECTTYPE_GRANTED = 'GRANTED',
|
||||
}
|
||||
|
||||
/**
|
||||
@ -17,68 +17,70 @@ export enum ProjectType {
|
||||
* (including sorting, pagination, and filtering).
|
||||
*/
|
||||
export class ProjectMembersDataSource extends DataSource<Member.AsObject> {
|
||||
public totalResult: number = 0;
|
||||
public viewTimestamp!: Timestamp.AsObject;
|
||||
public totalResult: number = 0;
|
||||
public viewTimestamp!: Timestamp.AsObject;
|
||||
|
||||
public membersSubject: BehaviorSubject<Member.AsObject[]> = new BehaviorSubject<Member.AsObject[]>([]);
|
||||
private loadingSubject: BehaviorSubject<boolean> = new BehaviorSubject<boolean>(false);
|
||||
public loading$: Observable<boolean> = this.loadingSubject.asObservable();
|
||||
public membersSubject: BehaviorSubject<Member.AsObject[]> = new BehaviorSubject<Member.AsObject[]>([]);
|
||||
private loadingSubject: BehaviorSubject<boolean> = new BehaviorSubject<boolean>(false);
|
||||
public loading$: Observable<boolean> = this.loadingSubject.asObservable();
|
||||
|
||||
constructor(private mgmtService: ManagementService) {
|
||||
super();
|
||||
}
|
||||
|
||||
public loadMembers(projectId: string,
|
||||
projectType: ProjectType,
|
||||
pageIndex: number, pageSize: number, grantId?: string): void {
|
||||
const offset = pageIndex * pageSize;
|
||||
|
||||
this.loadingSubject.next(true);
|
||||
|
||||
const promise:
|
||||
Promise<ListProjectMembersResponse.AsObject> |
|
||||
Promise<ListProjectGrantMembersResponse.AsObject>
|
||||
| undefined =
|
||||
projectType === ProjectType.PROJECTTYPE_OWNED ?
|
||||
this.mgmtService.listProjectMembers(projectId, pageSize, offset) :
|
||||
projectType === ProjectType.PROJECTTYPE_GRANTED && grantId ?
|
||||
this.mgmtService.listProjectGrantMembers(projectId,
|
||||
grantId, pageSize, offset) : undefined;
|
||||
if (promise) {
|
||||
from(promise).pipe(
|
||||
map(resp => {
|
||||
if (resp.details?.totalResult) {
|
||||
this.totalResult = resp.details?.totalResult;
|
||||
}
|
||||
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);
|
||||
});
|
||||
}
|
||||
constructor(private mgmtService: ManagementService) {
|
||||
super();
|
||||
}
|
||||
|
||||
public loadMembers(projectId: string,
|
||||
projectType: ProjectType,
|
||||
pageIndex: number, pageSize: number, grantId?: string): void {
|
||||
const offset = pageIndex * pageSize;
|
||||
|
||||
this.loadingSubject.next(true);
|
||||
|
||||
const promise:
|
||||
Promise<ListProjectMembersResponse.AsObject> |
|
||||
Promise<ListProjectGrantMembersResponse.AsObject>
|
||||
| undefined =
|
||||
projectType === ProjectType.PROJECTTYPE_OWNED ?
|
||||
this.mgmtService.listProjectMembers(projectId, pageSize, offset) :
|
||||
projectType === ProjectType.PROJECTTYPE_GRANTED && grantId ?
|
||||
this.mgmtService.listProjectGrantMembers(projectId,
|
||||
grantId, pageSize, offset) : undefined;
|
||||
if (promise) {
|
||||
from(promise).pipe(
|
||||
map(resp => {
|
||||
if (resp.details?.totalResult) {
|
||||
this.totalResult = resp.details?.totalResult;
|
||||
} else {
|
||||
this.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<Member.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<Member.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();
|
||||
}
|
||||
}
|
||||
|
@ -4,150 +4,152 @@ import { BehaviorSubject, from, Observable, of } from 'rxjs';
|
||||
import { catchError, finalize, map } from 'rxjs/operators';
|
||||
import { ListUserGrantResponse } from 'src/app/proto/generated/zitadel/management_pb';
|
||||
import {
|
||||
UserGrant,
|
||||
UserGrantProjectGrantIDQuery,
|
||||
UserGrantProjectIDQuery,
|
||||
UserGrantQuery,
|
||||
UserGrantUserIDQuery,
|
||||
UserGrant,
|
||||
UserGrantProjectGrantIDQuery,
|
||||
UserGrantProjectIDQuery,
|
||||
UserGrantQuery,
|
||||
UserGrantUserIDQuery,
|
||||
} from 'src/app/proto/generated/zitadel/user_pb';
|
||||
import { ManagementService } from 'src/app/services/mgmt.service';
|
||||
|
||||
export enum UserGrantContext {
|
||||
NONE = 'none',
|
||||
USER = 'user',
|
||||
OWNED_PROJECT = 'owned',
|
||||
GRANTED_PROJECT = 'granted',
|
||||
NONE = 'none',
|
||||
USER = 'user',
|
||||
OWNED_PROJECT = 'owned',
|
||||
GRANTED_PROJECT = 'granted',
|
||||
}
|
||||
|
||||
export class UserGrantsDataSource extends DataSource<UserGrant.AsObject> {
|
||||
public totalResult: number = 0;
|
||||
public viewTimestamp!: Timestamp.AsObject;
|
||||
public totalResult: number = 0;
|
||||
public viewTimestamp!: Timestamp.AsObject;
|
||||
|
||||
public grantsSubject: BehaviorSubject<UserGrant.AsObject[]> = new BehaviorSubject<UserGrant.AsObject[]>([]);
|
||||
private loadingSubject: BehaviorSubject<boolean> = new BehaviorSubject<boolean>(false);
|
||||
public loading$: Observable<boolean> = this.loadingSubject.asObservable();
|
||||
public grantsSubject: BehaviorSubject<UserGrant.AsObject[]> = new BehaviorSubject<UserGrant.AsObject[]>([]);
|
||||
private loadingSubject: BehaviorSubject<boolean> = new BehaviorSubject<boolean>(false);
|
||||
public loading$: Observable<boolean> = this.loadingSubject.asObservable();
|
||||
|
||||
constructor(private userService: ManagementService) {
|
||||
super();
|
||||
}
|
||||
constructor(private userService: ManagementService) {
|
||||
super();
|
||||
}
|
||||
|
||||
public loadGrants(
|
||||
context: UserGrantContext,
|
||||
pageIndex: number,
|
||||
pageSize: number,
|
||||
data: {
|
||||
projectId?: string;
|
||||
grantId?: string;
|
||||
userId?: string;
|
||||
},
|
||||
queries?: UserGrantQuery[],
|
||||
): void {
|
||||
switch (context) {
|
||||
case UserGrantContext.USER:
|
||||
if (data && data.userId) {
|
||||
this.loadingSubject.next(true);
|
||||
public loadGrants(
|
||||
context: UserGrantContext,
|
||||
pageIndex: number,
|
||||
pageSize: number,
|
||||
data: {
|
||||
projectId?: string;
|
||||
grantId?: string;
|
||||
userId?: string;
|
||||
},
|
||||
queries?: UserGrantQuery[],
|
||||
): void {
|
||||
switch (context) {
|
||||
case UserGrantContext.USER:
|
||||
if (data && data.userId) {
|
||||
this.loadingSubject.next(true);
|
||||
|
||||
const userfilter = new UserGrantQuery();
|
||||
const ugUiq = new UserGrantUserIDQuery();
|
||||
ugUiq.setUserId(data.userId);
|
||||
userfilter.setUserIdQuery(ugUiq);
|
||||
const userfilter = new UserGrantQuery();
|
||||
const ugUiq = new UserGrantUserIDQuery();
|
||||
ugUiq.setUserId(data.userId);
|
||||
userfilter.setUserIdQuery(ugUiq);
|
||||
|
||||
if (queries) {
|
||||
queries.push(userfilter);
|
||||
} else {
|
||||
queries = [userfilter];
|
||||
}
|
||||
if (queries) {
|
||||
queries.push(userfilter);
|
||||
} else {
|
||||
queries = [userfilter];
|
||||
}
|
||||
|
||||
const promise = this.userService.listUserGrants(pageSize, pageSize * pageIndex, queries);
|
||||
this.loadResponse(promise);
|
||||
}
|
||||
break;
|
||||
case UserGrantContext.OWNED_PROJECT:
|
||||
if (data && data.projectId) {
|
||||
this.loadingSubject.next(true);
|
||||
|
||||
const projectfilter = new UserGrantQuery();
|
||||
const ugPfq = new UserGrantProjectIDQuery();
|
||||
ugPfq.setProjectId(data.projectId);
|
||||
projectfilter.setProjectIdQuery(ugPfq);
|
||||
|
||||
if (queries) {
|
||||
queries.push(projectfilter);
|
||||
} else {
|
||||
queries = [projectfilter];
|
||||
}
|
||||
|
||||
const promise1 = this.userService.listUserGrants(pageSize, pageSize * pageIndex, queries);
|
||||
this.loadResponse(promise1);
|
||||
}
|
||||
break;
|
||||
case UserGrantContext.GRANTED_PROJECT:
|
||||
if (data && data.grantId && data.projectId) {
|
||||
this.loadingSubject.next(true);
|
||||
|
||||
const grantfilter = new UserGrantQuery();
|
||||
|
||||
const uggiq = new UserGrantProjectGrantIDQuery();
|
||||
uggiq.setProjectGrantId(data.grantId);
|
||||
grantfilter.setProjectGrantIdQuery(uggiq);
|
||||
|
||||
const projectfilter = new UserGrantQuery();
|
||||
const ugPfq = new UserGrantProjectIDQuery();
|
||||
ugPfq.setProjectId(data.projectId);
|
||||
projectfilter.setProjectIdQuery(ugPfq);
|
||||
|
||||
if (queries) {
|
||||
queries.push(grantfilter);
|
||||
} else {
|
||||
queries = [grantfilter];
|
||||
}
|
||||
|
||||
const promise2 = this.userService.listUserGrants(pageSize, pageSize * pageIndex, queries);
|
||||
this.loadResponse(promise2);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
this.loadingSubject.next(true);
|
||||
const promise3 = this.userService.listUserGrants(pageSize, pageSize * pageIndex, queries ?? []);
|
||||
this.loadResponse(promise3);
|
||||
break;
|
||||
const promise = this.userService.listUserGrants(pageSize, pageSize * pageIndex, queries);
|
||||
this.loadResponse(promise);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case UserGrantContext.OWNED_PROJECT:
|
||||
if (data && data.projectId) {
|
||||
this.loadingSubject.next(true);
|
||||
|
||||
private loadResponse(promise: Promise<ListUserGrantResponse.AsObject>): void {
|
||||
from(promise).pipe(
|
||||
map(resp => {
|
||||
if (resp.details?.totalResult) {
|
||||
this.totalResult = resp.details.totalResult;
|
||||
}
|
||||
if (resp.details?.viewTimestamp) {
|
||||
this.viewTimestamp = resp.details.viewTimestamp;
|
||||
}
|
||||
return resp.resultList;
|
||||
}),
|
||||
catchError(() => of([])),
|
||||
finalize(() => this.loadingSubject.next(false)),
|
||||
).subscribe(grants => {
|
||||
this.grantsSubject.next(grants);
|
||||
});
|
||||
const projectfilter = new UserGrantQuery();
|
||||
const ugPfq = new UserGrantProjectIDQuery();
|
||||
ugPfq.setProjectId(data.projectId);
|
||||
projectfilter.setProjectIdQuery(ugPfq);
|
||||
|
||||
if (queries) {
|
||||
queries.push(projectfilter);
|
||||
} else {
|
||||
queries = [projectfilter];
|
||||
}
|
||||
|
||||
const promise1 = this.userService.listUserGrants(pageSize, pageSize * pageIndex, queries);
|
||||
this.loadResponse(promise1);
|
||||
}
|
||||
break;
|
||||
case UserGrantContext.GRANTED_PROJECT:
|
||||
if (data && data.grantId && data.projectId) {
|
||||
this.loadingSubject.next(true);
|
||||
|
||||
const grantfilter = new UserGrantQuery();
|
||||
|
||||
const uggiq = new UserGrantProjectGrantIDQuery();
|
||||
uggiq.setProjectGrantId(data.grantId);
|
||||
grantfilter.setProjectGrantIdQuery(uggiq);
|
||||
|
||||
const projectfilter = new UserGrantQuery();
|
||||
const ugPfq = new UserGrantProjectIDQuery();
|
||||
ugPfq.setProjectId(data.projectId);
|
||||
projectfilter.setProjectIdQuery(ugPfq);
|
||||
|
||||
if (queries) {
|
||||
queries.push(grantfilter);
|
||||
} else {
|
||||
queries = [grantfilter];
|
||||
}
|
||||
|
||||
const promise2 = this.userService.listUserGrants(pageSize, pageSize * pageIndex, queries);
|
||||
this.loadResponse(promise2);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
this.loadingSubject.next(true);
|
||||
const promise3 = this.userService.listUserGrants(pageSize, pageSize * pageIndex, queries ?? []);
|
||||
this.loadResponse(promise3);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private loadResponse(promise: Promise<ListUserGrantResponse.AsObject>): void {
|
||||
from(promise).pipe(
|
||||
map(resp => {
|
||||
if (resp.details?.totalResult) {
|
||||
this.totalResult = resp.details.totalResult;
|
||||
} else {
|
||||
this.totalResult = 0;
|
||||
}
|
||||
if (resp.details?.viewTimestamp) {
|
||||
this.viewTimestamp = resp.details.viewTimestamp;
|
||||
}
|
||||
return resp.resultList;
|
||||
}),
|
||||
catchError(() => of([])),
|
||||
finalize(() => this.loadingSubject.next(false)),
|
||||
).subscribe(grants => {
|
||||
this.grantsSubject.next(grants);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 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<UserGrant.AsObject[]> {
|
||||
return this.grantsSubject.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<UserGrant.AsObject[]> {
|
||||
return this.grantsSubject.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.grantsSubject.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.grantsSubject.complete();
|
||||
this.loadingSubject.complete();
|
||||
}
|
||||
}
|
||||
|
@ -13,83 +13,85 @@ import { AdminService } from 'src/app/services/admin.service';
|
||||
import { ToastService } from 'src/app/services/toast.service';
|
||||
|
||||
@Component({
|
||||
selector: 'app-iam',
|
||||
templateUrl: './iam.component.html',
|
||||
styleUrls: ['./iam.component.scss'],
|
||||
selector: 'app-iam',
|
||||
templateUrl: './iam.component.html',
|
||||
styleUrls: ['./iam.component.scss'],
|
||||
})
|
||||
export class IamComponent {
|
||||
public PolicyComponentServiceType: any = PolicyComponentServiceType;
|
||||
private loadingSubject: BehaviorSubject<boolean> = new BehaviorSubject<boolean>(false);
|
||||
public loading$: Observable<boolean> = this.loadingSubject.asObservable();
|
||||
public totalMemberResult: number = 0;
|
||||
public membersSubject: BehaviorSubject<Member.AsObject[]>
|
||||
= new BehaviorSubject<Member.AsObject[]>([]);
|
||||
public PolicyComponentServiceType: any = PolicyComponentServiceType;
|
||||
private loadingSubject: BehaviorSubject<boolean> = new BehaviorSubject<boolean>(false);
|
||||
public loading$: Observable<boolean> = this.loadingSubject.asObservable();
|
||||
public totalMemberResult: number = 0;
|
||||
public membersSubject: BehaviorSubject<Member.AsObject[]>
|
||||
= new BehaviorSubject<Member.AsObject[]>([]);
|
||||
|
||||
public PolicyGridType: any = PolicyGridType;
|
||||
public features!: Features.AsObject;
|
||||
public PolicyGridType: any = PolicyGridType;
|
||||
public features!: Features.AsObject;
|
||||
|
||||
constructor(public adminService: AdminService, private dialog: MatDialog, private toast: ToastService,
|
||||
private router: Router) {
|
||||
this.loadMembers();
|
||||
this.loadFeatures();
|
||||
this.adminService.getDefaultFeatures();
|
||||
}
|
||||
constructor(public adminService: AdminService, private dialog: MatDialog, private toast: ToastService,
|
||||
private router: Router) {
|
||||
this.loadMembers();
|
||||
this.loadFeatures();
|
||||
this.adminService.getDefaultFeatures();
|
||||
}
|
||||
|
||||
public loadMembers(): void {
|
||||
this.loadingSubject.next(true);
|
||||
from(this.adminService.listIAMMembers(100, 0)).pipe(
|
||||
map(resp => {
|
||||
if (resp.details?.totalResult) {
|
||||
this.totalMemberResult = resp.details.totalResult;
|
||||
}
|
||||
return resp.resultList;
|
||||
}),
|
||||
catchError(() => of([])),
|
||||
finalize(() => this.loadingSubject.next(false)),
|
||||
).subscribe(members => {
|
||||
this.membersSubject.next(members);
|
||||
});
|
||||
}
|
||||
public loadMembers(): void {
|
||||
this.loadingSubject.next(true);
|
||||
from(this.adminService.listIAMMembers(100, 0)).pipe(
|
||||
map(resp => {
|
||||
if (resp.details?.totalResult) {
|
||||
this.totalMemberResult = resp.details.totalResult;
|
||||
} else {
|
||||
this.totalMemberResult = 0;
|
||||
}
|
||||
return resp.resultList;
|
||||
}),
|
||||
catchError(() => of([])),
|
||||
finalize(() => this.loadingSubject.next(false)),
|
||||
).subscribe(members => {
|
||||
this.membersSubject.next(members);
|
||||
});
|
||||
}
|
||||
|
||||
public openAddMember(): void {
|
||||
const dialogRef = this.dialog.open(MemberCreateDialogComponent, {
|
||||
data: {
|
||||
creationType: CreationType.IAM,
|
||||
},
|
||||
width: '400px',
|
||||
});
|
||||
public openAddMember(): void {
|
||||
const dialogRef = this.dialog.open(MemberCreateDialogComponent, {
|
||||
data: {
|
||||
creationType: CreationType.IAM,
|
||||
},
|
||||
width: '400px',
|
||||
});
|
||||
|
||||
dialogRef.afterClosed().subscribe(resp => {
|
||||
if (resp) {
|
||||
const users: User.AsObject[] = resp.users;
|
||||
const roles: string[] = resp.roles;
|
||||
dialogRef.afterClosed().subscribe(resp => {
|
||||
if (resp) {
|
||||
const users: User.AsObject[] = resp.users;
|
||||
const roles: string[] = resp.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');
|
||||
setTimeout(() => {
|
||||
this.loadMembers();
|
||||
}, 1000);
|
||||
}).catch(error => {
|
||||
this.toast.showError(error);
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
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');
|
||||
setTimeout(() => {
|
||||
this.loadMembers();
|
||||
}, 1000);
|
||||
}).catch(error => {
|
||||
this.toast.showError(error);
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public showDetail(): void {
|
||||
this.router.navigate(['iam/members']);
|
||||
}
|
||||
public showDetail(): void {
|
||||
this.router.navigate(['iam/members']);
|
||||
}
|
||||
|
||||
public loadFeatures(): void {
|
||||
this.loadingSubject.next(true);
|
||||
this.adminService.getDefaultFeatures().then(resp => {
|
||||
if (resp.features) {
|
||||
this.features = resp.features;
|
||||
}
|
||||
});
|
||||
}
|
||||
public loadFeatures(): void {
|
||||
this.loadingSubject.next(true);
|
||||
this.adminService.getDefaultFeatures().then(resp => {
|
||||
if (resp.features) {
|
||||
this.features = resp.features;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -204,7 +204,10 @@ export class OrgDetailComponent implements OnInit {
|
||||
map(resp => {
|
||||
if (resp.details?.totalResult) {
|
||||
this.totalMemberResult = resp.details?.totalResult;
|
||||
} else {
|
||||
this.totalMemberResult = 0;
|
||||
}
|
||||
|
||||
return resp.resultList;
|
||||
}),
|
||||
catchError(() => of([])),
|
||||
|
@ -3,16 +3,27 @@
|
||||
</h1>
|
||||
<p class="desc">{{'APP.OIDC.CLIENTSECRET_DESCRIPTION' | translate}}</p>
|
||||
<div mat-dialog-content>
|
||||
<p *ngIf="data.clientId">ClientId: {{data.clientId}}</p>
|
||||
<div class="flex" *ngIf="data.clientId">
|
||||
<span class="overflow-auto"><span class="desc">ClientId:</span> {{data.clientId}}</span>
|
||||
<button color="primary" [disabled]="copied == data.clientId" matTooltip="copy to clipboard" appCopyToClipboard
|
||||
[valueToCopy]="data.clientId" (copiedValue)="this.copied = $event" mat-icon-button>
|
||||
<i *ngIf="copied != data.clientId" class="las la-clipboard"></i>
|
||||
<i *ngIf="copied == data.clientId" class="las la-clipboard-check"></i>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div *ngIf="data.clientSecret" class="flex">
|
||||
<div *ngIf="data.clientSecret; else showNoSecretInfo" class="flex">
|
||||
<span class="overflow-auto"><span class="desc">ClientSecret:</span> {{data.clientSecret}}</span>
|
||||
<button color="primary" [disabled]="copied == data.clientSecret" matTooltip="copy to clipboard"
|
||||
appCopyToClipboard [valueToCopy]="data.clientSecret" (copiedValue)="this.copied = $event" mat-icon-button>
|
||||
<i *ngIf="copied != data.clientSecret" class="las la-clipboard"></i>
|
||||
<i *ngIf="copied == data.clientSecret" class="las la-clipboard-check"></i>
|
||||
</button>
|
||||
<span class="secret">{{data.clientSecret}}</span>
|
||||
</div>
|
||||
|
||||
<ng-template #showNoSecretInfo>
|
||||
<cnsl-info-section>{{'APP.OIDC.CLIENTSECRET_NOSECRET' | translate}}</cnsl-info-section>
|
||||
</ng-template>
|
||||
</div>
|
||||
<div mat-dialog-actions class="action">
|
||||
|
||||
|
@ -23,11 +23,16 @@
|
||||
.flex {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: .5rem;
|
||||
border: 1px solid #ffffff20;
|
||||
border-radius: .5rem;
|
||||
justify-content: space-between;
|
||||
|
||||
.secret {
|
||||
.overflow-auto {
|
||||
overflow: auto;
|
||||
|
||||
.desc {
|
||||
font-size: 14px;
|
||||
color: var(--grey);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -15,127 +15,129 @@ import { ManagementService } from 'src/app/services/mgmt.service';
|
||||
import { ToastService } from 'src/app/services/toast.service';
|
||||
|
||||
@Component({
|
||||
selector: 'app-granted-project-detail',
|
||||
templateUrl: './granted-project-detail.component.html',
|
||||
styleUrls: ['./granted-project-detail.component.scss'],
|
||||
selector: 'app-granted-project-detail',
|
||||
templateUrl: './granted-project-detail.component.html',
|
||||
styleUrls: ['./granted-project-detail.component.scss'],
|
||||
})
|
||||
export class GrantedProjectDetailComponent implements OnInit, OnDestroy {
|
||||
public projectId: string = '';
|
||||
public grantId: string = '';
|
||||
public project!: GrantedProject.AsObject;
|
||||
public projectId: string = '';
|
||||
public grantId: string = '';
|
||||
public project!: GrantedProject.AsObject;
|
||||
|
||||
public ProjectState: any = ProjectState;
|
||||
public ChangeType: any = ChangeType;
|
||||
public ProjectState: any = ProjectState;
|
||||
public ChangeType: any = ChangeType;
|
||||
|
||||
private subscription?: Subscription;
|
||||
private subscription?: Subscription;
|
||||
|
||||
public isZitadel: boolean = false;
|
||||
public isZitadel: boolean = false;
|
||||
|
||||
UserGrantContext: any = UserGrantContext;
|
||||
UserGrantContext: any = UserGrantContext;
|
||||
|
||||
// members
|
||||
public totalMemberResult: number = 0;
|
||||
public membersSubject: BehaviorSubject<Member.AsObject[]>
|
||||
= new BehaviorSubject<Member.AsObject[]>([]);
|
||||
private loadingSubject: BehaviorSubject<boolean> = new BehaviorSubject<boolean>(true);
|
||||
public loading$: Observable<boolean> = this.loadingSubject.asObservable();
|
||||
// members
|
||||
public totalMemberResult: number = 0;
|
||||
public membersSubject: BehaviorSubject<Member.AsObject[]>
|
||||
= new BehaviorSubject<Member.AsObject[]>([]);
|
||||
private loadingSubject: BehaviorSubject<boolean> = new BehaviorSubject<boolean>(true);
|
||||
public loading$: Observable<boolean> = this.loadingSubject.asObservable();
|
||||
|
||||
constructor(
|
||||
public translate: TranslateService,
|
||||
private route: ActivatedRoute,
|
||||
private toast: ToastService,
|
||||
private mgmtService: ManagementService,
|
||||
private _location: Location,
|
||||
private router: Router,
|
||||
private dialog: MatDialog,
|
||||
) {
|
||||
}
|
||||
constructor(
|
||||
public translate: TranslateService,
|
||||
private route: ActivatedRoute,
|
||||
private toast: ToastService,
|
||||
private mgmtService: ManagementService,
|
||||
private _location: Location,
|
||||
private router: Router,
|
||||
private dialog: MatDialog,
|
||||
) {
|
||||
}
|
||||
|
||||
public ngOnInit(): void {
|
||||
this.subscription = this.route.params.subscribe(params => this.getData(params));
|
||||
}
|
||||
public ngOnInit(): void {
|
||||
this.subscription = this.route.params.subscribe(params => this.getData(params));
|
||||
}
|
||||
|
||||
public ngOnDestroy(): void {
|
||||
this.subscription?.unsubscribe();
|
||||
}
|
||||
public ngOnDestroy(): void {
|
||||
this.subscription?.unsubscribe();
|
||||
}
|
||||
|
||||
private async getData({ id, grantId }: Params): Promise<void> {
|
||||
this.projectId = id;
|
||||
this.grantId = grantId;
|
||||
private async getData({ id, grantId }: Params): Promise<void> {
|
||||
this.projectId = id;
|
||||
this.grantId = grantId;
|
||||
|
||||
this.mgmtService.getIAM().then(iam => {
|
||||
this.isZitadel = iam.iamProjectId === this.projectId;
|
||||
});
|
||||
this.mgmtService.getIAM().then(iam => {
|
||||
this.isZitadel = iam.iamProjectId === this.projectId;
|
||||
});
|
||||
|
||||
if (this.projectId && this.grantId) {
|
||||
this.mgmtService.getGrantedProjectByID(this.projectId, this.grantId).then(proj => {
|
||||
if (proj.grantedProject) {
|
||||
this.project = proj.grantedProject;
|
||||
}
|
||||
}).catch(error => {
|
||||
this.toast.showError(error);
|
||||
});
|
||||
|
||||
this.loadMembers();
|
||||
if (this.projectId && this.grantId) {
|
||||
this.mgmtService.getGrantedProjectByID(this.projectId, this.grantId).then(proj => {
|
||||
if (proj.grantedProject) {
|
||||
this.project = proj.grantedProject;
|
||||
}
|
||||
}
|
||||
}).catch(error => {
|
||||
this.toast.showError(error);
|
||||
});
|
||||
|
||||
public loadMembers(): void {
|
||||
this.loadingSubject.next(true);
|
||||
from(this.mgmtService.listProjectGrantMembers(this.projectId,
|
||||
this.grantId, 100, 0)).pipe(
|
||||
map(resp => {
|
||||
if (resp.details?.totalResult) {
|
||||
this.totalMemberResult = resp.details.totalResult;
|
||||
}
|
||||
return resp.resultList;
|
||||
}),
|
||||
catchError(() => of([])),
|
||||
finalize(() => this.loadingSubject.next(false)),
|
||||
).subscribe(members => {
|
||||
this.membersSubject.next(members);
|
||||
this.loadMembers();
|
||||
}
|
||||
}
|
||||
|
||||
public loadMembers(): void {
|
||||
this.loadingSubject.next(true);
|
||||
from(this.mgmtService.listProjectGrantMembers(this.projectId,
|
||||
this.grantId, 100, 0)).pipe(
|
||||
map(resp => {
|
||||
if (resp.details?.totalResult) {
|
||||
this.totalMemberResult = resp.details.totalResult;
|
||||
} else {
|
||||
this.totalMemberResult = 0;
|
||||
}
|
||||
return resp.resultList;
|
||||
}),
|
||||
catchError(() => of([])),
|
||||
finalize(() => this.loadingSubject.next(false)),
|
||||
).subscribe(members => {
|
||||
this.membersSubject.next(members);
|
||||
});
|
||||
}
|
||||
|
||||
public navigateBack(): void {
|
||||
this._location.back();
|
||||
}
|
||||
|
||||
public openAddMember(): void {
|
||||
const dialogRef = this.dialog.open(MemberCreateDialogComponent, {
|
||||
data: {
|
||||
creationType: CreationType.PROJECT_GRANTED,
|
||||
},
|
||||
width: '400px',
|
||||
});
|
||||
|
||||
dialogRef.afterClosed().subscribe(resp => {
|
||||
if (resp) {
|
||||
const users: User.AsObject[] = resp.users;
|
||||
const roles: string[] = resp.roles;
|
||||
|
||||
if (users && users.length && roles && roles.length) {
|
||||
users.forEach(user => {
|
||||
return this.mgmtService.addProjectGrantMember(
|
||||
this.projectId,
|
||||
this.grantId,
|
||||
user.id,
|
||||
roles,
|
||||
).then(() => {
|
||||
this.toast.showInfo('PROJECT.TOAST.MEMBERADDED', true);
|
||||
setTimeout(() => {
|
||||
this.loadMembers();
|
||||
}, 1000);
|
||||
}).catch(error => {
|
||||
this.toast.showError(error);
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public navigateBack(): void {
|
||||
this._location.back();
|
||||
}
|
||||
|
||||
public openAddMember(): void {
|
||||
const dialogRef = this.dialog.open(MemberCreateDialogComponent, {
|
||||
data: {
|
||||
creationType: CreationType.PROJECT_GRANTED,
|
||||
},
|
||||
width: '400px',
|
||||
});
|
||||
|
||||
dialogRef.afterClosed().subscribe(resp => {
|
||||
if (resp) {
|
||||
const users: User.AsObject[] = resp.users;
|
||||
const roles: string[] = resp.roles;
|
||||
|
||||
if (users && users.length && roles && roles.length) {
|
||||
users.forEach(user => {
|
||||
return this.mgmtService.addProjectGrantMember(
|
||||
this.projectId,
|
||||
this.grantId,
|
||||
user.id,
|
||||
roles,
|
||||
).then(() => {
|
||||
this.toast.showInfo('PROJECT.TOAST.MEMBERADDED', true);
|
||||
setTimeout(() => {
|
||||
this.loadMembers();
|
||||
}, 1000);
|
||||
}).catch(error => {
|
||||
this.toast.showError(error);
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public showDetail(): void {
|
||||
this.router.navigate(['granted-projects', this.project.projectId, 'grant', this.grantId, 'members']);
|
||||
}
|
||||
public showDetail(): void {
|
||||
this.router.navigate(['granted-projects', this.project.projectId, 'grant', this.grantId, 'members']);
|
||||
}
|
||||
}
|
||||
|
@ -12,107 +12,109 @@ import { ManagementService } from 'src/app/services/mgmt.service';
|
||||
import { ToastService } from 'src/app/services/toast.service';
|
||||
|
||||
@Component({
|
||||
selector: 'app-granted-project-list',
|
||||
templateUrl: './granted-project-list.component.html',
|
||||
styleUrls: ['./granted-project-list.component.scss'],
|
||||
animations: [
|
||||
trigger('list', [
|
||||
transition(':enter', [
|
||||
query('@animate',
|
||||
stagger(80, animateChild()),
|
||||
),
|
||||
]),
|
||||
]),
|
||||
trigger('animate', [
|
||||
transition(':enter', [
|
||||
style({ opacity: 0, transform: 'translateY(-100%)' }),
|
||||
animate('100ms', style({ opacity: 1, transform: 'translateY(0)' })),
|
||||
]),
|
||||
transition(':leave', [
|
||||
style({ opacity: 1, transform: 'translateY(0)' }),
|
||||
animate('100ms', style({ opacity: 0, transform: 'translateY(100%)' })),
|
||||
]),
|
||||
]),
|
||||
],
|
||||
selector: 'app-granted-project-list',
|
||||
templateUrl: './granted-project-list.component.html',
|
||||
styleUrls: ['./granted-project-list.component.scss'],
|
||||
animations: [
|
||||
trigger('list', [
|
||||
transition(':enter', [
|
||||
query('@animate',
|
||||
stagger(80, animateChild()),
|
||||
),
|
||||
]),
|
||||
]),
|
||||
trigger('animate', [
|
||||
transition(':enter', [
|
||||
style({ opacity: 0, transform: 'translateY(-100%)' }),
|
||||
animate('100ms', style({ opacity: 1, transform: 'translateY(0)' })),
|
||||
]),
|
||||
transition(':leave', [
|
||||
style({ opacity: 1, transform: 'translateY(0)' }),
|
||||
animate('100ms', style({ opacity: 0, transform: 'translateY(100%)' })),
|
||||
]),
|
||||
]),
|
||||
],
|
||||
})
|
||||
export class GrantedProjectListComponent implements OnInit, OnDestroy {
|
||||
public totalResult: number = 0;
|
||||
public viewTimestamp!: Timestamp.AsObject;
|
||||
public totalResult: number = 0;
|
||||
public viewTimestamp!: Timestamp.AsObject;
|
||||
|
||||
public dataSource: MatTableDataSource<GrantedProject.AsObject> =
|
||||
new MatTableDataSource<GrantedProject.AsObject>();
|
||||
@ViewChild(PaginatorComponent) public paginator!: PaginatorComponent;
|
||||
public dataSource: MatTableDataSource<GrantedProject.AsObject> =
|
||||
new MatTableDataSource<GrantedProject.AsObject>();
|
||||
@ViewChild(PaginatorComponent) public paginator!: PaginatorComponent;
|
||||
|
||||
public grantedProjectList: GrantedProject.AsObject[] = [];
|
||||
public displayedColumns: string[] = ['select', 'name', 'resourceOwnerName', 'state', 'creationDate', 'changeDate'];
|
||||
public selection: SelectionModel<GrantedProject.AsObject> = new SelectionModel<GrantedProject.AsObject>(true, []);
|
||||
public grantedProjectList: GrantedProject.AsObject[] = [];
|
||||
public displayedColumns: string[] = ['select', 'name', 'resourceOwnerName', 'state', 'creationDate', 'changeDate'];
|
||||
public selection: SelectionModel<GrantedProject.AsObject> = new SelectionModel<GrantedProject.AsObject>(true, []);
|
||||
|
||||
private loadingSubject: BehaviorSubject<boolean> = new BehaviorSubject<boolean>(false);
|
||||
public loading$: Observable<boolean> = this.loadingSubject.asObservable();
|
||||
private loadingSubject: BehaviorSubject<boolean> = new BehaviorSubject<boolean>(false);
|
||||
public loading$: Observable<boolean> = this.loadingSubject.asObservable();
|
||||
|
||||
public grid: boolean = true;
|
||||
private subscription?: Subscription;
|
||||
public grid: boolean = true;
|
||||
private subscription?: Subscription;
|
||||
|
||||
constructor(private router: Router,
|
||||
public translate: TranslateService,
|
||||
private mgmtService: ManagementService,
|
||||
private toast: ToastService,
|
||||
) { }
|
||||
constructor(private router: Router,
|
||||
public translate: TranslateService,
|
||||
private mgmtService: ManagementService,
|
||||
private toast: ToastService,
|
||||
) { }
|
||||
|
||||
public ngOnInit(): void {
|
||||
this.getData(10, 0);
|
||||
}
|
||||
public ngOnInit(): void {
|
||||
this.getData(10, 0);
|
||||
}
|
||||
|
||||
public ngOnDestroy(): void {
|
||||
this.subscription?.unsubscribe();
|
||||
}
|
||||
public ngOnDestroy(): void {
|
||||
this.subscription?.unsubscribe();
|
||||
}
|
||||
|
||||
public isAllSelected(): boolean {
|
||||
const numSelected = this.selection.selected.length;
|
||||
const numRows = this.dataSource.data.length;
|
||||
return numSelected === numRows;
|
||||
}
|
||||
public isAllSelected(): boolean {
|
||||
const numSelected = this.selection.selected.length;
|
||||
const numRows = this.dataSource.data.length;
|
||||
return numSelected === numRows;
|
||||
}
|
||||
|
||||
public masterToggle(): void {
|
||||
this.isAllSelected() ?
|
||||
this.selection.clear() :
|
||||
this.dataSource.data.forEach(row => this.selection.select(row));
|
||||
}
|
||||
public masterToggle(): void {
|
||||
this.isAllSelected() ?
|
||||
this.selection.clear() :
|
||||
this.dataSource.data.forEach(row => this.selection.select(row));
|
||||
}
|
||||
|
||||
public changePage(event: PageEvent): void {
|
||||
this.getData(event.pageSize, event.pageIndex);
|
||||
}
|
||||
public changePage(event: PageEvent): void {
|
||||
this.getData(event.pageSize, event.pageIndex);
|
||||
}
|
||||
|
||||
public addProject(): void {
|
||||
this.router.navigate(['/projects', 'create']);
|
||||
}
|
||||
public addProject(): void {
|
||||
this.router.navigate(['/projects', 'create']);
|
||||
}
|
||||
|
||||
private async getData(limit: number, offset: number): Promise<void> {
|
||||
this.loadingSubject.next(true);
|
||||
this.mgmtService.listGrantedProjects(limit, offset).then(resp => {
|
||||
this.grantedProjectList = resp.resultList;
|
||||
if (resp.details?.totalResult) {
|
||||
this.totalResult = resp.details.totalResult;
|
||||
}
|
||||
if (resp.details?.viewTimestamp) {
|
||||
this.viewTimestamp = resp.details?.viewTimestamp;
|
||||
}
|
||||
if (this.totalResult > 5) {
|
||||
this.grid = false;
|
||||
}
|
||||
this.dataSource.data = this.grantedProjectList;
|
||||
console.log(resp.resultList);
|
||||
private async getData(limit: number, offset: number): Promise<void> {
|
||||
this.loadingSubject.next(true);
|
||||
this.mgmtService.listGrantedProjects(limit, offset).then(resp => {
|
||||
this.grantedProjectList = resp.resultList;
|
||||
if (resp.details?.totalResult) {
|
||||
this.totalResult = resp.details.totalResult;
|
||||
} else {
|
||||
this.totalResult = 0;
|
||||
}
|
||||
if (resp.details?.viewTimestamp) {
|
||||
this.viewTimestamp = resp.details?.viewTimestamp;
|
||||
}
|
||||
if (this.totalResult > 5) {
|
||||
this.grid = false;
|
||||
}
|
||||
this.dataSource.data = this.grantedProjectList;
|
||||
console.log(resp.resultList);
|
||||
|
||||
this.loadingSubject.next(false);
|
||||
}).catch(error => {
|
||||
console.error(error);
|
||||
this.toast.showError(error);
|
||||
this.loadingSubject.next(false);
|
||||
});
|
||||
}
|
||||
this.loadingSubject.next(false);
|
||||
}).catch(error => {
|
||||
console.error(error);
|
||||
this.toast.showError(error);
|
||||
this.loadingSubject.next(false);
|
||||
});
|
||||
}
|
||||
|
||||
public refreshPage(): void {
|
||||
this.selection.clear();
|
||||
this.getData(this.paginator.pageSize, this.paginator.pageIndex * this.paginator.pageSize);
|
||||
}
|
||||
public refreshPage(): void {
|
||||
this.selection.clear();
|
||||
this.getData(this.paginator.pageSize, this.paginator.pageIndex * this.paginator.pageSize);
|
||||
}
|
||||
}
|
||||
|
@ -19,220 +19,222 @@ import { ManagementService } from 'src/app/services/mgmt.service';
|
||||
import { ToastService } from 'src/app/services/toast.service';
|
||||
|
||||
@Component({
|
||||
selector: 'app-owned-project-detail',
|
||||
templateUrl: './owned-project-detail.component.html',
|
||||
styleUrls: ['./owned-project-detail.component.scss'],
|
||||
selector: 'app-owned-project-detail',
|
||||
templateUrl: './owned-project-detail.component.html',
|
||||
styleUrls: ['./owned-project-detail.component.scss'],
|
||||
|
||||
})
|
||||
export class OwnedProjectDetailComponent implements OnInit, OnDestroy {
|
||||
public projectId: string = '';
|
||||
public project!: Project.AsObject;
|
||||
public projectId: string = '';
|
||||
public project!: Project.AsObject;
|
||||
|
||||
public pageSizeApps: number = 10;
|
||||
public appsDataSource: MatTableDataSource<App.AsObject> = new MatTableDataSource<App.AsObject>();
|
||||
public appsResult!: ListAppsResponse.AsObject;
|
||||
public appsColumns: string[] = ['name'];
|
||||
public pageSizeApps: number = 10;
|
||||
public appsDataSource: MatTableDataSource<App.AsObject> = new MatTableDataSource<App.AsObject>();
|
||||
public appsResult!: ListAppsResponse.AsObject;
|
||||
public appsColumns: string[] = ['name'];
|
||||
|
||||
public ProjectState: any = ProjectState;
|
||||
public ChangeType: any = ChangeType;
|
||||
public ProjectState: any = ProjectState;
|
||||
public ChangeType: any = ChangeType;
|
||||
|
||||
public grid: boolean = true;
|
||||
private subscription?: Subscription;
|
||||
public editstate: boolean = false;
|
||||
public grid: boolean = true;
|
||||
private subscription?: Subscription;
|
||||
public editstate: boolean = false;
|
||||
|
||||
public isZitadel: boolean = false;
|
||||
public isZitadel: boolean = false;
|
||||
|
||||
public UserGrantContext: any = UserGrantContext;
|
||||
public UserGrantContext: any = UserGrantContext;
|
||||
|
||||
// members
|
||||
public totalMemberResult: number = 0;
|
||||
public membersSubject: BehaviorSubject<Member.AsObject[]>
|
||||
= new BehaviorSubject<Member.AsObject[]>([]);
|
||||
private loadingSubject: BehaviorSubject<boolean> = new BehaviorSubject<boolean>(true);
|
||||
public loading$: Observable<boolean> = this.loadingSubject.asObservable();
|
||||
public refreshChanges$: EventEmitter<void> = new EventEmitter();
|
||||
// members
|
||||
public totalMemberResult: number = 0;
|
||||
public membersSubject: BehaviorSubject<Member.AsObject[]>
|
||||
= new BehaviorSubject<Member.AsObject[]>([]);
|
||||
private loadingSubject: BehaviorSubject<boolean> = new BehaviorSubject<boolean>(true);
|
||||
public loading$: Observable<boolean> = this.loadingSubject.asObservable();
|
||||
public refreshChanges$: EventEmitter<void> = new EventEmitter();
|
||||
|
||||
constructor(
|
||||
public translate: TranslateService,
|
||||
private route: ActivatedRoute,
|
||||
private toast: ToastService,
|
||||
private mgmtService: ManagementService,
|
||||
private _location: Location,
|
||||
private dialog: MatDialog,
|
||||
private router: Router,
|
||||
) { }
|
||||
constructor(
|
||||
public translate: TranslateService,
|
||||
private route: ActivatedRoute,
|
||||
private toast: ToastService,
|
||||
private mgmtService: ManagementService,
|
||||
private _location: Location,
|
||||
private dialog: MatDialog,
|
||||
private router: Router,
|
||||
) { }
|
||||
|
||||
public ngOnInit(): void {
|
||||
this.subscription = this.route.params.subscribe(params => this.getData(params));
|
||||
}
|
||||
public ngOnInit(): void {
|
||||
this.subscription = this.route.params.subscribe(params => this.getData(params));
|
||||
}
|
||||
|
||||
public ngOnDestroy(): void {
|
||||
this.subscription?.unsubscribe();
|
||||
}
|
||||
public ngOnDestroy(): void {
|
||||
this.subscription?.unsubscribe();
|
||||
}
|
||||
|
||||
private async getData({ id }: Params): Promise<void> {
|
||||
this.projectId = id;
|
||||
private async getData({ id }: Params): Promise<void> {
|
||||
this.projectId = id;
|
||||
|
||||
this.mgmtService.getIAM().then(iam => {
|
||||
this.isZitadel = iam.iamProjectId === this.projectId;
|
||||
});
|
||||
this.mgmtService.getIAM().then(iam => {
|
||||
this.isZitadel = iam.iamProjectId === this.projectId;
|
||||
});
|
||||
|
||||
this.mgmtService.getProjectByID(id).then(resp => {
|
||||
if (resp.project) {
|
||||
this.project = resp.project;
|
||||
}
|
||||
}).catch(error => {
|
||||
console.error(error);
|
||||
this.toast.showError(error);
|
||||
});
|
||||
this.mgmtService.getProjectByID(id).then(resp => {
|
||||
if (resp.project) {
|
||||
this.project = resp.project;
|
||||
}
|
||||
}).catch(error => {
|
||||
console.error(error);
|
||||
this.toast.showError(error);
|
||||
});
|
||||
|
||||
this.loadMembers();
|
||||
}
|
||||
this.loadMembers();
|
||||
}
|
||||
|
||||
public loadMembers(): void {
|
||||
this.loadingSubject.next(true);
|
||||
from(this.mgmtService.listProjectMembers(this.projectId, 100, 0)).pipe(
|
||||
map(resp => {
|
||||
if (resp.details?.totalResult) {
|
||||
this.totalMemberResult = resp.details?.totalResult;
|
||||
}
|
||||
return resp.resultList;
|
||||
}),
|
||||
catchError(() => of([])),
|
||||
finalize(() => this.loadingSubject.next(false)),
|
||||
).subscribe(members => {
|
||||
this.membersSubject.next(members);
|
||||
});
|
||||
}
|
||||
|
||||
public changeState(newState: ProjectState): void {
|
||||
if (newState === ProjectState.PROJECT_STATE_ACTIVE) {
|
||||
const dialogRef = this.dialog.open(WarnDialogComponent, {
|
||||
data: {
|
||||
confirmKey: 'ACTIONS.REACTIVATE',
|
||||
cancelKey: 'ACTIONS.CANCEL',
|
||||
titleKey: 'PROJECT.PAGES.DIALOG.REACTIVATE.TITLE',
|
||||
descriptionKey: 'PROJECT.PAGES.DIALOG.REACTIVATE.DESCRIPTION',
|
||||
},
|
||||
width: '400px',
|
||||
});
|
||||
dialogRef.afterClosed().subscribe(resp => {
|
||||
if (resp) {
|
||||
this.mgmtService.reactivateProject(this.projectId).then(() => {
|
||||
this.toast.showInfo('PROJECT.TOAST.REACTIVATED', true);
|
||||
this.project.state = ProjectState.PROJECT_STATE_ACTIVE;
|
||||
this.refreshChanges$.emit();
|
||||
}).catch(error => {
|
||||
this.toast.showError(error);
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
} else if (newState === ProjectState.PROJECT_STATE_INACTIVE) {
|
||||
const dialogRef = this.dialog.open(WarnDialogComponent, {
|
||||
data: {
|
||||
confirmKey: 'ACTIONS.DEACTIVATE',
|
||||
cancelKey: 'ACTIONS.CANCEL',
|
||||
titleKey: 'PROJECT.PAGES.DIALOG.DEACTIVATE.TITLE',
|
||||
descriptionKey: 'PROJECT.PAGES.DIALOG.DEACTIVATE.DESCRIPTION',
|
||||
},
|
||||
width: '400px',
|
||||
});
|
||||
dialogRef.afterClosed().subscribe(resp => {
|
||||
if (resp) {
|
||||
this.mgmtService.deactivateProject(this.projectId).then(() => {
|
||||
this.toast.showInfo('PROJECT.TOAST.DEACTIVATED', true);
|
||||
this.project.state = ProjectState.PROJECT_STATE_INACTIVE;
|
||||
this.refreshChanges$.emit();
|
||||
}).catch(error => {
|
||||
this.toast.showError(error);
|
||||
});
|
||||
}
|
||||
});
|
||||
public loadMembers(): void {
|
||||
this.loadingSubject.next(true);
|
||||
from(this.mgmtService.listProjectMembers(this.projectId, 100, 0)).pipe(
|
||||
map(resp => {
|
||||
if (resp.details?.totalResult) {
|
||||
this.totalMemberResult = resp.details?.totalResult;
|
||||
} else {
|
||||
this.totalMemberResult = 0;
|
||||
}
|
||||
}
|
||||
return resp.resultList;
|
||||
}),
|
||||
catchError(() => of([])),
|
||||
finalize(() => this.loadingSubject.next(false)),
|
||||
).subscribe(members => {
|
||||
this.membersSubject.next(members);
|
||||
});
|
||||
}
|
||||
|
||||
public deleteProject(): void {
|
||||
const dialogRef = this.dialog.open(WarnDialogComponent, {
|
||||
data: {
|
||||
confirmKey: 'ACTIONS.DELETE',
|
||||
cancelKey: 'ACTIONS.CANCEL',
|
||||
titleKey: 'PROJECT.PAGES.DIALOG.DELETE.TITLE',
|
||||
descriptionKey: 'PROJECT.PAGES.DIALOG.DELETE.DESCRIPTION',
|
||||
},
|
||||
width: '400px',
|
||||
});
|
||||
dialogRef.afterClosed().subscribe(resp => {
|
||||
if (resp) {
|
||||
this.mgmtService.removeProject(this.projectId).then(() => {
|
||||
this.toast.showInfo('PROJECT.TOAST.DELETED', true);
|
||||
const params: Params = {
|
||||
'deferredReload': true,
|
||||
};
|
||||
this.router.navigate(['/projects'], { queryParams: params });
|
||||
}).catch(error => {
|
||||
this.toast.showError(error);
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public saveProject(): void {
|
||||
const req = new UpdateProjectRequest();
|
||||
req.setId(this.project.id);
|
||||
req.setName(this.project.name);
|
||||
req.setProjectRoleAssertion(this.project.projectRoleAssertion);
|
||||
req.setProjectRoleCheck(this.project.projectRoleCheck);
|
||||
|
||||
this.mgmtService.updateProject(req).then(() => {
|
||||
this.toast.showInfo('PROJECT.TOAST.UPDATED', true);
|
||||
public changeState(newState: ProjectState): void {
|
||||
if (newState === ProjectState.PROJECT_STATE_ACTIVE) {
|
||||
const dialogRef = this.dialog.open(WarnDialogComponent, {
|
||||
data: {
|
||||
confirmKey: 'ACTIONS.REACTIVATE',
|
||||
cancelKey: 'ACTIONS.CANCEL',
|
||||
titleKey: 'PROJECT.PAGES.DIALOG.REACTIVATE.TITLE',
|
||||
descriptionKey: 'PROJECT.PAGES.DIALOG.REACTIVATE.DESCRIPTION',
|
||||
},
|
||||
width: '400px',
|
||||
});
|
||||
dialogRef.afterClosed().subscribe(resp => {
|
||||
if (resp) {
|
||||
this.mgmtService.reactivateProject(this.projectId).then(() => {
|
||||
this.toast.showInfo('PROJECT.TOAST.REACTIVATED', true);
|
||||
this.project.state = ProjectState.PROJECT_STATE_ACTIVE;
|
||||
this.refreshChanges$.emit();
|
||||
}).catch(error => {
|
||||
}).catch(error => {
|
||||
this.toast.showError(error);
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
} else if (newState === ProjectState.PROJECT_STATE_INACTIVE) {
|
||||
const dialogRef = this.dialog.open(WarnDialogComponent, {
|
||||
data: {
|
||||
confirmKey: 'ACTIONS.DEACTIVATE',
|
||||
cancelKey: 'ACTIONS.CANCEL',
|
||||
titleKey: 'PROJECT.PAGES.DIALOG.DEACTIVATE.TITLE',
|
||||
descriptionKey: 'PROJECT.PAGES.DIALOG.DEACTIVATE.DESCRIPTION',
|
||||
},
|
||||
width: '400px',
|
||||
});
|
||||
dialogRef.afterClosed().subscribe(resp => {
|
||||
if (resp) {
|
||||
this.mgmtService.deactivateProject(this.projectId).then(() => {
|
||||
this.toast.showInfo('PROJECT.TOAST.DEACTIVATED', true);
|
||||
this.project.state = ProjectState.PROJECT_STATE_INACTIVE;
|
||||
this.refreshChanges$.emit();
|
||||
}).catch(error => {
|
||||
this.toast.showError(error);
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public deleteProject(): void {
|
||||
const dialogRef = this.dialog.open(WarnDialogComponent, {
|
||||
data: {
|
||||
confirmKey: 'ACTIONS.DELETE',
|
||||
cancelKey: 'ACTIONS.CANCEL',
|
||||
titleKey: 'PROJECT.PAGES.DIALOG.DELETE.TITLE',
|
||||
descriptionKey: 'PROJECT.PAGES.DIALOG.DELETE.DESCRIPTION',
|
||||
},
|
||||
width: '400px',
|
||||
});
|
||||
dialogRef.afterClosed().subscribe(resp => {
|
||||
if (resp) {
|
||||
this.mgmtService.removeProject(this.projectId).then(() => {
|
||||
this.toast.showInfo('PROJECT.TOAST.DELETED', true);
|
||||
const params: Params = {
|
||||
'deferredReload': true,
|
||||
};
|
||||
this.router.navigate(['/projects'], { queryParams: params });
|
||||
}).catch(error => {
|
||||
this.toast.showError(error);
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public navigateBack(): void {
|
||||
this._location.back();
|
||||
}
|
||||
public saveProject(): void {
|
||||
const req = new UpdateProjectRequest();
|
||||
req.setId(this.project.id);
|
||||
req.setName(this.project.name);
|
||||
req.setProjectRoleAssertion(this.project.projectRoleAssertion);
|
||||
req.setProjectRoleCheck(this.project.projectRoleCheck);
|
||||
|
||||
public updateName(): void {
|
||||
this.saveProject();
|
||||
this.editstate = false;
|
||||
}
|
||||
this.mgmtService.updateProject(req).then(() => {
|
||||
this.toast.showInfo('PROJECT.TOAST.UPDATED', true);
|
||||
this.refreshChanges$.emit();
|
||||
}).catch(error => {
|
||||
this.toast.showError(error);
|
||||
});
|
||||
}
|
||||
|
||||
public openAddMember(): void {
|
||||
const dialogRef = this.dialog.open(MemberCreateDialogComponent, {
|
||||
data: {
|
||||
creationType: CreationType.PROJECT_OWNED,
|
||||
projectId: this.project.id,
|
||||
},
|
||||
width: '400px',
|
||||
});
|
||||
public navigateBack(): void {
|
||||
this._location.back();
|
||||
}
|
||||
|
||||
dialogRef.afterClosed().subscribe(resp => {
|
||||
if (resp) {
|
||||
const users: User.AsObject[] = resp.users;
|
||||
const roles: string[] = resp.roles;
|
||||
public updateName(): void {
|
||||
this.saveProject();
|
||||
this.editstate = false;
|
||||
}
|
||||
|
||||
if (users && users.length && roles && roles.length) {
|
||||
users.forEach(user => {
|
||||
return this.mgmtService.addProjectMember(this.projectId, user.id, roles)
|
||||
.then(() => {
|
||||
this.toast.showInfo('PROJECT.TOAST.MEMBERADDED', true);
|
||||
setTimeout(() => {
|
||||
this.loadMembers();
|
||||
}, 1000);
|
||||
}).catch(error => {
|
||||
this.toast.showError(error);
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
public openAddMember(): void {
|
||||
const dialogRef = this.dialog.open(MemberCreateDialogComponent, {
|
||||
data: {
|
||||
creationType: CreationType.PROJECT_OWNED,
|
||||
projectId: this.project.id,
|
||||
},
|
||||
width: '400px',
|
||||
});
|
||||
|
||||
public showDetail(): void {
|
||||
this.router.navigate(['projects', this.project.id, 'members']);
|
||||
}
|
||||
dialogRef.afterClosed().subscribe(resp => {
|
||||
if (resp) {
|
||||
const users: User.AsObject[] = resp.users;
|
||||
const roles: string[] = resp.roles;
|
||||
|
||||
if (users && users.length && roles && roles.length) {
|
||||
users.forEach(user => {
|
||||
return this.mgmtService.addProjectMember(this.projectId, user.id, roles)
|
||||
.then(() => {
|
||||
this.toast.showInfo('PROJECT.TOAST.MEMBERADDED', true);
|
||||
setTimeout(() => {
|
||||
this.loadMembers();
|
||||
}, 1000);
|
||||
}).catch(error => {
|
||||
this.toast.showError(error);
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public showDetail(): void {
|
||||
this.router.navigate(['projects', this.project.id, 'members']);
|
||||
}
|
||||
}
|
||||
|
@ -11,53 +11,55 @@ import { ManagementService } from 'src/app/services/mgmt.service';
|
||||
* (including sorting, pagination, and filtering).
|
||||
*/
|
||||
export class ProjectGrantsDataSource extends DataSource<GrantedProject.AsObject> {
|
||||
public totalResult: number = 0;
|
||||
public viewTimestamp!: Timestamp.AsObject;
|
||||
public grantsSubject: BehaviorSubject<GrantedProject.AsObject[]> = new BehaviorSubject<GrantedProject.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 grantsSubject: BehaviorSubject<GrantedProject.AsObject[]> = new BehaviorSubject<GrantedProject.AsObject[]>([]);
|
||||
private loadingSubject: BehaviorSubject<boolean> = new BehaviorSubject<boolean>(false);
|
||||
public loading$: Observable<boolean> = this.loadingSubject.asObservable();
|
||||
|
||||
constructor(private mgmtService: ManagementService) {
|
||||
super();
|
||||
}
|
||||
constructor(private mgmtService: ManagementService) {
|
||||
super();
|
||||
}
|
||||
|
||||
public loadGrants(projectId: string, pageIndex: number, pageSize: number, sortDirection?: string): void {
|
||||
const offset = pageIndex * pageSize;
|
||||
public loadGrants(projectId: string, pageIndex: number, pageSize: number, sortDirection?: string): void {
|
||||
const offset = pageIndex * pageSize;
|
||||
|
||||
this.loadingSubject.next(true);
|
||||
from(this.mgmtService.listProjectGrants(projectId, pageSize, offset)).pipe(
|
||||
map(resp => {
|
||||
if (resp.details?.totalResult) {
|
||||
this.totalResult = resp.details.totalResult;
|
||||
}
|
||||
if (resp.details?.viewTimestamp) {
|
||||
this.viewTimestamp = resp.details?.viewTimestamp;
|
||||
}
|
||||
return resp.resultList;
|
||||
}),
|
||||
catchError(() => of([])),
|
||||
finalize(() => this.loadingSubject.next(false)),
|
||||
).subscribe(grants => {
|
||||
this.grantsSubject.next(grants);
|
||||
});
|
||||
}
|
||||
this.loadingSubject.next(true);
|
||||
from(this.mgmtService.listProjectGrants(projectId, pageSize, offset)).pipe(
|
||||
map(resp => {
|
||||
if (resp.details?.totalResult) {
|
||||
this.totalResult = resp.details.totalResult;
|
||||
} else {
|
||||
this.totalResult = 0;
|
||||
}
|
||||
if (resp.details?.viewTimestamp) {
|
||||
this.viewTimestamp = resp.details?.viewTimestamp;
|
||||
}
|
||||
return resp.resultList;
|
||||
}),
|
||||
catchError(() => of([])),
|
||||
finalize(() => this.loadingSubject.next(false)),
|
||||
).subscribe(grants => {
|
||||
this.grantsSubject.next(grants);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 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<GrantedProject.AsObject[]> {
|
||||
return this.grantsSubject.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<GrantedProject.AsObject[]> {
|
||||
return this.grantsSubject.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.grantsSubject.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.grantsSubject.complete();
|
||||
this.loadingSubject.complete();
|
||||
}
|
||||
}
|
||||
|
@ -15,173 +15,175 @@ import { ManagementService } from 'src/app/services/mgmt.service';
|
||||
import { ToastService } from 'src/app/services/toast.service';
|
||||
|
||||
@Component({
|
||||
selector: 'app-owned-project-list',
|
||||
templateUrl: './owned-project-list.component.html',
|
||||
styleUrls: ['./owned-project-list.component.scss'],
|
||||
animations: [
|
||||
trigger('list', [
|
||||
transition(':enter', [
|
||||
query('@animate',
|
||||
stagger(80, animateChild()),
|
||||
),
|
||||
]),
|
||||
]),
|
||||
trigger('animate', [
|
||||
transition(':enter', [
|
||||
style({ opacity: 0, transform: 'translateY(-100%)' }),
|
||||
animate('100ms', style({ opacity: 1, transform: 'translateY(0)' })),
|
||||
]),
|
||||
transition(':leave', [
|
||||
style({ opacity: 1, transform: 'translateY(0)' }),
|
||||
animate('100ms', style({ opacity: 0, transform: 'translateY(100%)' })),
|
||||
]),
|
||||
]),
|
||||
],
|
||||
selector: 'app-owned-project-list',
|
||||
templateUrl: './owned-project-list.component.html',
|
||||
styleUrls: ['./owned-project-list.component.scss'],
|
||||
animations: [
|
||||
trigger('list', [
|
||||
transition(':enter', [
|
||||
query('@animate',
|
||||
stagger(80, animateChild()),
|
||||
),
|
||||
]),
|
||||
]),
|
||||
trigger('animate', [
|
||||
transition(':enter', [
|
||||
style({ opacity: 0, transform: 'translateY(-100%)' }),
|
||||
animate('100ms', style({ opacity: 1, transform: 'translateY(0)' })),
|
||||
]),
|
||||
transition(':leave', [
|
||||
style({ opacity: 1, transform: 'translateY(0)' }),
|
||||
animate('100ms', style({ opacity: 0, transform: 'translateY(100%)' })),
|
||||
]),
|
||||
]),
|
||||
],
|
||||
})
|
||||
export class OwnedProjectListComponent implements OnInit, OnDestroy {
|
||||
public totalResult: number = 0;
|
||||
public viewTimestamp!: Timestamp.AsObject;
|
||||
public totalResult: number = 0;
|
||||
public viewTimestamp!: Timestamp.AsObject;
|
||||
|
||||
public dataSource: MatTableDataSource<Project.AsObject> =
|
||||
new MatTableDataSource<Project.AsObject>();
|
||||
public dataSource: MatTableDataSource<Project.AsObject> =
|
||||
new MatTableDataSource<Project.AsObject>();
|
||||
|
||||
@ViewChild(PaginatorComponent) public paginator!: PaginatorComponent;
|
||||
@ViewChild(PaginatorComponent) public paginator!: PaginatorComponent;
|
||||
|
||||
public ownedProjectList: Project.AsObject[] = [];
|
||||
public displayedColumns: string[] = ['select', 'name', 'state', 'creationDate', 'changeDate', 'actions'];
|
||||
public selection: SelectionModel<Project.AsObject> = new SelectionModel<Project.AsObject>(true, []);
|
||||
public ownedProjectList: Project.AsObject[] = [];
|
||||
public displayedColumns: string[] = ['select', 'name', 'state', 'creationDate', 'changeDate', 'actions'];
|
||||
public selection: SelectionModel<Project.AsObject> = new SelectionModel<Project.AsObject>(true, []);
|
||||
|
||||
private loadingSubject: BehaviorSubject<boolean> = new BehaviorSubject<boolean>(false);
|
||||
public loading$: Observable<boolean> = this.loadingSubject.asObservable();
|
||||
private loadingSubject: BehaviorSubject<boolean> = new BehaviorSubject<boolean>(false);
|
||||
public loading$: Observable<boolean> = this.loadingSubject.asObservable();
|
||||
|
||||
public grid: boolean = true;
|
||||
private subscription?: Subscription;
|
||||
public grid: boolean = true;
|
||||
private subscription?: Subscription;
|
||||
|
||||
public zitadelProjectId: string = '';
|
||||
public zitadelProjectId: string = '';
|
||||
|
||||
constructor(private router: Router,
|
||||
private route: ActivatedRoute,
|
||||
public translate: TranslateService,
|
||||
private mgmtService: ManagementService,
|
||||
private toast: ToastService,
|
||||
private dialog: MatDialog,
|
||||
) {
|
||||
this.mgmtService.getIAM().then(iam => {
|
||||
this.zitadelProjectId = iam.iamProjectId;
|
||||
});
|
||||
}
|
||||
constructor(private router: Router,
|
||||
private route: ActivatedRoute,
|
||||
public translate: TranslateService,
|
||||
private mgmtService: ManagementService,
|
||||
private toast: ToastService,
|
||||
private dialog: MatDialog,
|
||||
) {
|
||||
this.mgmtService.getIAM().then(iam => {
|
||||
this.zitadelProjectId = iam.iamProjectId;
|
||||
});
|
||||
}
|
||||
|
||||
public ngOnInit(): void {
|
||||
this.route.queryParams.pipe(take(1)).subscribe(params => {
|
||||
this.getData();
|
||||
if (params.deferredReload) {
|
||||
setTimeout(() => {
|
||||
this.getData();
|
||||
}, 2000);
|
||||
}
|
||||
});
|
||||
}
|
||||
public ngOnInit(): void {
|
||||
this.route.queryParams.pipe(take(1)).subscribe(params => {
|
||||
this.getData();
|
||||
if (params.deferredReload) {
|
||||
setTimeout(() => {
|
||||
this.getData();
|
||||
}, 2000);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public ngOnDestroy(): void {
|
||||
this.subscription?.unsubscribe();
|
||||
}
|
||||
public ngOnDestroy(): void {
|
||||
this.subscription?.unsubscribe();
|
||||
}
|
||||
|
||||
public isAllSelected(): boolean {
|
||||
const numSelected = this.selection.selected.length;
|
||||
const numRows = this.dataSource.data.length;
|
||||
return numSelected === numRows;
|
||||
}
|
||||
public isAllSelected(): boolean {
|
||||
const numSelected = this.selection.selected.length;
|
||||
const numRows = this.dataSource.data.length;
|
||||
return numSelected === numRows;
|
||||
}
|
||||
|
||||
public masterToggle(): void {
|
||||
this.isAllSelected() ?
|
||||
this.selection.clear() :
|
||||
this.dataSource.data.forEach(row => this.selection.select(row));
|
||||
}
|
||||
public masterToggle(): void {
|
||||
this.isAllSelected() ?
|
||||
this.selection.clear() :
|
||||
this.dataSource.data.forEach(row => this.selection.select(row));
|
||||
}
|
||||
|
||||
public changePage(event: PageEvent): void {
|
||||
this.getData(event.pageSize, event.pageSize * event.pageIndex);
|
||||
}
|
||||
public changePage(event: PageEvent): void {
|
||||
this.getData(event.pageSize, event.pageSize * event.pageIndex);
|
||||
}
|
||||
|
||||
public addProject(): void {
|
||||
this.router.navigate(['/projects', 'create']);
|
||||
}
|
||||
public addProject(): void {
|
||||
this.router.navigate(['/projects', 'create']);
|
||||
}
|
||||
|
||||
private async getData(limit?: number, offset?: number): Promise<void> {
|
||||
this.loadingSubject.next(true);
|
||||
this.mgmtService.listProjects(limit, offset).then(resp => {
|
||||
this.ownedProjectList = resp.resultList;
|
||||
if (resp.details?.totalResult) {
|
||||
this.totalResult = resp.details.totalResult;
|
||||
}
|
||||
if (this.totalResult > 10) {
|
||||
this.grid = false;
|
||||
}
|
||||
if (resp.details?.viewTimestamp) {
|
||||
this.viewTimestamp = resp.details?.viewTimestamp;
|
||||
}
|
||||
this.dataSource.data = this.ownedProjectList;
|
||||
this.loadingSubject.next(false);
|
||||
private async getData(limit?: number, offset?: number): Promise<void> {
|
||||
this.loadingSubject.next(true);
|
||||
this.mgmtService.listProjects(limit, offset).then(resp => {
|
||||
this.ownedProjectList = resp.resultList;
|
||||
if (resp.details?.totalResult) {
|
||||
this.totalResult = resp.details.totalResult;
|
||||
} else {
|
||||
this.totalResult = 0;
|
||||
}
|
||||
if (this.totalResult > 10) {
|
||||
this.grid = false;
|
||||
}
|
||||
if (resp.details?.viewTimestamp) {
|
||||
this.viewTimestamp = resp.details?.viewTimestamp;
|
||||
}
|
||||
this.dataSource.data = this.ownedProjectList;
|
||||
this.loadingSubject.next(false);
|
||||
}).catch(error => {
|
||||
console.error(error);
|
||||
this.toast.showError(error);
|
||||
this.loadingSubject.next(false);
|
||||
});
|
||||
|
||||
this.ownedProjectList = [];
|
||||
}
|
||||
|
||||
public reactivateSelectedProjects(): void {
|
||||
const promises = this.selection.selected.map(project => {
|
||||
this.mgmtService.reactivateProject(project.id);
|
||||
});
|
||||
|
||||
Promise.all(promises).then(() => {
|
||||
this.toast.showInfo('PROJECT.TOAST.REACTIVATED', true);
|
||||
}).catch(error => {
|
||||
this.toast.showError(error);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
public deactivateSelectedProjects(): void {
|
||||
const promises = this.selection.selected.map(project => {
|
||||
this.mgmtService.deactivateProject(project.id);
|
||||
});
|
||||
|
||||
Promise.all(promises).then(() => {
|
||||
this.toast.showInfo('PROJECT.TOAST.DEACTIVATED', true);
|
||||
}).catch(error => {
|
||||
this.toast.showError(error);
|
||||
});
|
||||
}
|
||||
|
||||
public refreshPage(): void {
|
||||
this.selection.clear();
|
||||
this.getData(this.paginator.pageSize, this.paginator.pageIndex * this.paginator.pageSize);
|
||||
}
|
||||
|
||||
public deleteProject(item: Project.AsObject): void {
|
||||
const dialogRef = this.dialog.open(WarnDialogComponent, {
|
||||
data: {
|
||||
confirmKey: 'ACTIONS.DELETE',
|
||||
cancelKey: 'ACTIONS.CANCEL',
|
||||
titleKey: 'PROJECT.PAGES.DIALOG.DELETE.TITLE',
|
||||
descriptionKey: 'PROJECT.PAGES.DIALOG.DELETE.DESCRIPTION',
|
||||
},
|
||||
width: '400px',
|
||||
});
|
||||
|
||||
dialogRef.afterClosed().subscribe(resp => {
|
||||
if (this.zitadelProjectId && resp && item.id !== this.zitadelProjectId) {
|
||||
this.mgmtService.removeProject(item.id).then(() => {
|
||||
this.toast.showInfo('PROJECT.TOAST.DELETED', true);
|
||||
setTimeout(() => {
|
||||
this.refreshPage();
|
||||
}, 1000);
|
||||
}).catch(error => {
|
||||
console.error(error);
|
||||
this.toast.showError(error);
|
||||
this.loadingSubject.next(false);
|
||||
this.toast.showError(error);
|
||||
});
|
||||
|
||||
this.ownedProjectList = [];
|
||||
}
|
||||
|
||||
public reactivateSelectedProjects(): void {
|
||||
const promises = this.selection.selected.map(project => {
|
||||
this.mgmtService.reactivateProject(project.id);
|
||||
});
|
||||
|
||||
Promise.all(promises).then(() => {
|
||||
this.toast.showInfo('PROJECT.TOAST.REACTIVATED', true);
|
||||
}).catch(error => {
|
||||
this.toast.showError(error);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
public deactivateSelectedProjects(): void {
|
||||
const promises = this.selection.selected.map(project => {
|
||||
this.mgmtService.deactivateProject(project.id);
|
||||
});
|
||||
|
||||
Promise.all(promises).then(() => {
|
||||
this.toast.showInfo('PROJECT.TOAST.DEACTIVATED', true);
|
||||
}).catch(error => {
|
||||
this.toast.showError(error);
|
||||
});
|
||||
}
|
||||
|
||||
public refreshPage(): void {
|
||||
this.selection.clear();
|
||||
this.getData(this.paginator.pageSize, this.paginator.pageIndex * this.paginator.pageSize);
|
||||
}
|
||||
|
||||
public deleteProject(item: Project.AsObject): void {
|
||||
const dialogRef = this.dialog.open(WarnDialogComponent, {
|
||||
data: {
|
||||
confirmKey: 'ACTIONS.DELETE',
|
||||
cancelKey: 'ACTIONS.CANCEL',
|
||||
titleKey: 'PROJECT.PAGES.DIALOG.DELETE.TITLE',
|
||||
descriptionKey: 'PROJECT.PAGES.DIALOG.DELETE.DESCRIPTION',
|
||||
},
|
||||
width: '400px',
|
||||
});
|
||||
|
||||
dialogRef.afterClosed().subscribe(resp => {
|
||||
if (this.zitadelProjectId && resp && item.id !== this.zitadelProjectId) {
|
||||
this.mgmtService.removeProject(item.id).then(() => {
|
||||
this.toast.showInfo('PROJECT.TOAST.DELETED', true);
|
||||
setTimeout(() => {
|
||||
this.refreshPage();
|
||||
}, 1000);
|
||||
}).catch(error => {
|
||||
this.toast.showError(error);
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -5,7 +5,7 @@
|
||||
<form *ngIf="userForm" [formGroup]="userForm" (ngSubmit)="createUser()" class="form">
|
||||
<div class="content">
|
||||
<cnsl-form-field class="formfield">
|
||||
<cnsl-label>{{ 'USER.MACHINE.USERNAME' | translate }}</cnsl-label>
|
||||
<cnsl-label>{{ 'USER.MACHINE.USERNAME' | translate }}*</cnsl-label>
|
||||
<input cnslInput formControlName="userName" required />
|
||||
<span cnsl-error *ngIf="userName?.invalid && userName?.errors?.required">
|
||||
{{ 'USER.VALIDATION.REQUIRED' | translate }}
|
||||
@ -15,7 +15,7 @@
|
||||
</span>
|
||||
</cnsl-form-field>
|
||||
<cnsl-form-field class="formfield">
|
||||
<cnsl-label>{{ 'USER.MACHINE.NAME' | translate }}</cnsl-label>
|
||||
<cnsl-label>{{ 'USER.MACHINE.NAME' | translate }}*</cnsl-label>
|
||||
<input cnslInput formControlName="name" required />
|
||||
<span cnsl-error *ngIf="name?.invalid && name?.errors?.required">
|
||||
{{ 'USER.VALIDATION.REQUIRED' | translate }}
|
||||
|
@ -5,7 +5,7 @@
|
||||
<form *ngIf="userForm" [formGroup]="userForm" (ngSubmit)="createUser()" class="form">
|
||||
<div class="content">
|
||||
<p class="section">{{ 'USER.CREATE.NAMEANDEMAILSECTION' | translate }}</p>
|
||||
<cnsl-form-field class="formfield" appearance="fill">
|
||||
<cnsl-form-field class="formfield">
|
||||
<cnsl-label>{{ 'USER.PROFILE.EMAIL' | translate }}*</cnsl-label>
|
||||
<input cnslInput matRipple formControlName="email" required />
|
||||
<span cnsl-error *ngIf="email?.invalid && !email?.errors?.required">
|
||||
@ -15,7 +15,7 @@
|
||||
{{ 'USER.VALIDATION.REQUIRED' | translate }}
|
||||
</span>
|
||||
</cnsl-form-field>
|
||||
<cnsl-form-field class="formfield" appearance="fill">
|
||||
<cnsl-form-field class="formfield">
|
||||
<cnsl-label>{{ 'USER.PROFILE.USERNAME' | translate }}*</cnsl-label>
|
||||
<input cnslInput formControlName="userName" required
|
||||
[ngStyle]="{'padding-right': suffixPadding ? suffixPadding : '10px'}" />
|
||||
@ -30,21 +30,21 @@
|
||||
</cnsl-form-field>
|
||||
</div>
|
||||
<div class="content">
|
||||
<cnsl-form-field class="formfield" appearance="fill">
|
||||
<cnsl-form-field class="formfield">
|
||||
<cnsl-label>{{ 'USER.PROFILE.FIRSTNAME' | translate }}*</cnsl-label>
|
||||
<input cnslInput formControlName="firstName" required />
|
||||
<span cnsl-error *ngIf="firstName?.invalid && firstName?.errors?.required">
|
||||
{{ 'USER.VALIDATION.REQUIRED' | translate }}
|
||||
</span>
|
||||
</cnsl-form-field>
|
||||
<cnsl-form-field class="formfield" appearance="fill">
|
||||
<cnsl-form-field class="formfield">
|
||||
<cnsl-label>{{ 'USER.PROFILE.LASTNAME' | translate }}*</cnsl-label>
|
||||
<input cnslInput formControlName="lastName" required />
|
||||
<span cnsl-error *ngIf="lastName?.invalid && lastName?.errors?.required">
|
||||
{{ 'USER.VALIDATION.REQUIRED' | translate }}
|
||||
</span>
|
||||
</cnsl-form-field>
|
||||
<cnsl-form-field class="formfield" appearance="fill">
|
||||
<cnsl-form-field class="formfield">
|
||||
<cnsl-label>{{ 'USER.PROFILE.NICKNAME' | translate }}</cnsl-label>
|
||||
<input cnslInput formControlName="nickName" />
|
||||
<span cnsl-error *ngIf="nickName?.invalid && nickName?.errors?.required">
|
||||
@ -54,7 +54,7 @@
|
||||
|
||||
<p class="section">{{ 'USER.CREATE.GENDERLANGSECTION' | translate }}</p>
|
||||
|
||||
<cnsl-form-field class="formfield" appearance="fill">
|
||||
<cnsl-form-field class="formfield">
|
||||
<cnsl-label>{{ 'USER.PROFILE.GENDER' | translate }}</cnsl-label>
|
||||
<mat-select formControlName="gender">
|
||||
<mat-option *ngFor="let gender of genders" [value]="gender">
|
||||
@ -65,7 +65,7 @@
|
||||
{{ 'USER.VALIDATION.REQUIRED' | translate }}
|
||||
</span>
|
||||
</cnsl-form-field>
|
||||
<cnsl-form-field class="formfield" appearance="fill">
|
||||
<cnsl-form-field class="formfield">
|
||||
<cnsl-label>{{ 'USER.PROFILE.PREFERRED_LANGUAGE' | translate }}</cnsl-label>
|
||||
<mat-select formControlName="preferredLanguage">
|
||||
<mat-option *ngFor="let language of languages" [value]="language">
|
||||
@ -79,7 +79,7 @@
|
||||
|
||||
<p class="section">{{ 'USER.CREATE.ADDRESSANDPHONESECTION' | translate }}</p>
|
||||
|
||||
<cnsl-form-field class="formfield" appearance="fill">
|
||||
<cnsl-form-field class="formfield">
|
||||
<cnsl-label>{{ 'USER.PROFILE.PHONE' | translate }}</cnsl-label>
|
||||
<input cnslInput formControlName="phone" />
|
||||
<span cnsl-error *ngIf="phone?.invalid && phone?.errors?.required">
|
||||
|
@ -13,109 +13,111 @@ import { ManagementService } from '../../../../services/mgmt.service';
|
||||
import { ToastService } from '../../../../services/toast.service';
|
||||
|
||||
@Component({
|
||||
selector: 'app-external-idps',
|
||||
templateUrl: './external-idps.component.html',
|
||||
styleUrls: ['./external-idps.component.scss'],
|
||||
selector: 'app-external-idps',
|
||||
templateUrl: './external-idps.component.html',
|
||||
styleUrls: ['./external-idps.component.scss'],
|
||||
})
|
||||
export class ExternalIdpsComponent implements OnInit {
|
||||
@Input() service!: GrpcAuthService | ManagementService;
|
||||
@Input() userId!: string;
|
||||
@ViewChild(PaginatorComponent) public paginator!: PaginatorComponent;
|
||||
public totalResult: number = 0;
|
||||
public viewTimestamp!: Timestamp.AsObject;
|
||||
public dataSource: MatTableDataSource<IDPUserLink.AsObject>
|
||||
= new MatTableDataSource<IDPUserLink.AsObject>();
|
||||
public selection: SelectionModel<IDPUserLink.AsObject>
|
||||
= new SelectionModel<IDPUserLink.AsObject>(true, []);
|
||||
private loadingSubject: BehaviorSubject<boolean> = new BehaviorSubject<boolean>(false);
|
||||
public loading$: Observable<boolean> = this.loadingSubject.asObservable();
|
||||
@Input() public displayedColumns: string[] = ['idpConfigId', 'idpName', 'externalUserId', 'externalUserDisplayName', 'actions'];
|
||||
@Input() service!: GrpcAuthService | ManagementService;
|
||||
@Input() userId!: string;
|
||||
@ViewChild(PaginatorComponent) public paginator!: PaginatorComponent;
|
||||
public totalResult: number = 0;
|
||||
public viewTimestamp!: Timestamp.AsObject;
|
||||
public dataSource: MatTableDataSource<IDPUserLink.AsObject>
|
||||
= new MatTableDataSource<IDPUserLink.AsObject>();
|
||||
public selection: SelectionModel<IDPUserLink.AsObject>
|
||||
= new SelectionModel<IDPUserLink.AsObject>(true, []);
|
||||
private loadingSubject: BehaviorSubject<boolean> = new BehaviorSubject<boolean>(false);
|
||||
public loading$: Observable<boolean> = this.loadingSubject.asObservable();
|
||||
@Input() public displayedColumns: string[] = ['idpConfigId', 'idpName', 'externalUserId', 'externalUserDisplayName', 'actions'];
|
||||
|
||||
constructor(private toast: ToastService, private dialog: MatDialog) { }
|
||||
constructor(private toast: ToastService, private dialog: MatDialog) { }
|
||||
|
||||
ngOnInit(): void {
|
||||
this.getData(10, 0);
|
||||
ngOnInit(): void {
|
||||
this.getData(10, 0);
|
||||
}
|
||||
|
||||
public isAllSelected(): boolean {
|
||||
const numSelected = this.selection.selected.length;
|
||||
const numRows = this.dataSource.data.length;
|
||||
return numSelected === numRows;
|
||||
}
|
||||
|
||||
public masterToggle(): void {
|
||||
this.isAllSelected() ?
|
||||
this.selection.clear() :
|
||||
this.dataSource.data.forEach(row => this.selection.select(row));
|
||||
}
|
||||
|
||||
public changePage(event: PageEvent): void {
|
||||
this.getData(event.pageSize, event.pageIndex * event.pageSize);
|
||||
}
|
||||
|
||||
private async getData(limit: number, offset: number): Promise<void> {
|
||||
this.loadingSubject.next(true);
|
||||
|
||||
let promise;
|
||||
if (this.service instanceof ManagementService) {
|
||||
promise = (this.service as ManagementService).listHumanLinkedIDPs(this.userId, limit, offset);
|
||||
} else if (this.service instanceof GrpcAuthService) {
|
||||
promise = (this.service as GrpcAuthService).listMyLinkedIDPs(limit, offset);
|
||||
}
|
||||
|
||||
public isAllSelected(): boolean {
|
||||
const numSelected = this.selection.selected.length;
|
||||
const numRows = this.dataSource.data.length;
|
||||
return numSelected === numRows;
|
||||
if (promise) {
|
||||
promise.then(resp => {
|
||||
this.dataSource.data = resp.resultList;
|
||||
if (resp.details?.viewTimestamp) {
|
||||
this.viewTimestamp = resp.details.viewTimestamp;
|
||||
}
|
||||
if (resp.details?.totalResult) {
|
||||
this.totalResult = resp.details?.totalResult;
|
||||
} else {
|
||||
this.totalResult = 0;
|
||||
}
|
||||
this.loadingSubject.next(false);
|
||||
}).catch((error: any) => {
|
||||
this.toast.showError(error);
|
||||
this.loadingSubject.next(false);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public masterToggle(): void {
|
||||
this.isAllSelected() ?
|
||||
this.selection.clear() :
|
||||
this.dataSource.data.forEach(row => this.selection.select(row));
|
||||
}
|
||||
public refreshPage(): void {
|
||||
this.getData(this.paginator.pageSize, this.paginator.pageIndex * this.paginator.pageSize);
|
||||
}
|
||||
|
||||
public changePage(event: PageEvent): void {
|
||||
this.getData(event.pageSize, event.pageIndex * event.pageSize);
|
||||
}
|
||||
|
||||
private async getData(limit: number, offset: number): Promise<void> {
|
||||
this.loadingSubject.next(true);
|
||||
public removeExternalIdp(idp: IDPUserLink.AsObject): void {
|
||||
const dialogRef = this.dialog.open(WarnDialogComponent, {
|
||||
data: {
|
||||
confirmKey: 'ACTIONS.REMOVE',
|
||||
cancelKey: 'ACTIONS.CANCEL',
|
||||
titleKey: 'USER.EXTERNALIDP.DIALOG.DELETE_TITLE',
|
||||
descriptionKey: 'USER.EXTERNALIDP.DIALOG.DELETE_DESCRIPTION',
|
||||
},
|
||||
width: '400px',
|
||||
});
|
||||
|
||||
dialogRef.afterClosed().subscribe(resp => {
|
||||
if (resp) {
|
||||
let promise;
|
||||
if (this.service instanceof ManagementService) {
|
||||
promise = (this.service as ManagementService).listHumanLinkedIDPs(this.userId, limit, offset);
|
||||
promise = (this.service as ManagementService)
|
||||
.removeHumanLinkedIDP(idp.providedUserId, idp.idpId, idp.userId);
|
||||
} else if (this.service instanceof GrpcAuthService) {
|
||||
promise = (this.service as GrpcAuthService).listMyLinkedIDPs(limit, offset);
|
||||
promise = (this.service as GrpcAuthService)
|
||||
.removeMyLinkedIDP(idp.providedUserId, idp.idpId);
|
||||
}
|
||||
|
||||
if (promise) {
|
||||
promise.then(resp => {
|
||||
this.dataSource.data = resp.resultList;
|
||||
if (resp.details?.viewTimestamp) {
|
||||
this.viewTimestamp = resp.details.viewTimestamp;
|
||||
}
|
||||
if (resp.details?.totalResult) {
|
||||
this.totalResult = resp.details?.totalResult;
|
||||
}
|
||||
this.loadingSubject.next(false);
|
||||
}).catch((error: any) => {
|
||||
this.toast.showError(error);
|
||||
this.loadingSubject.next(false);
|
||||
});
|
||||
promise.then(_ => {
|
||||
setTimeout(() => {
|
||||
this.refreshPage();
|
||||
}, 1000);
|
||||
}).catch((error: any) => {
|
||||
this.toast.showError(error);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public refreshPage(): void {
|
||||
this.getData(this.paginator.pageSize, this.paginator.pageIndex * this.paginator.pageSize);
|
||||
}
|
||||
|
||||
public removeExternalIdp(idp: IDPUserLink.AsObject): void {
|
||||
const dialogRef = this.dialog.open(WarnDialogComponent, {
|
||||
data: {
|
||||
confirmKey: 'ACTIONS.REMOVE',
|
||||
cancelKey: 'ACTIONS.CANCEL',
|
||||
titleKey: 'USER.EXTERNALIDP.DIALOG.DELETE_TITLE',
|
||||
descriptionKey: 'USER.EXTERNALIDP.DIALOG.DELETE_DESCRIPTION',
|
||||
},
|
||||
width: '400px',
|
||||
});
|
||||
|
||||
dialogRef.afterClosed().subscribe(resp => {
|
||||
if (resp) {
|
||||
let promise;
|
||||
if (this.service instanceof ManagementService) {
|
||||
promise = (this.service as ManagementService)
|
||||
.removeHumanLinkedIDP(idp.providedUserId, idp.idpId, idp.userId);
|
||||
} else if (this.service instanceof GrpcAuthService) {
|
||||
promise = (this.service as GrpcAuthService)
|
||||
.removeMyLinkedIDP(idp.providedUserId, idp.idpId);
|
||||
}
|
||||
|
||||
if (promise) {
|
||||
promise.then(_ => {
|
||||
setTimeout(() => {
|
||||
this.refreshPage();
|
||||
}, 1000);
|
||||
}).catch((error: any) => {
|
||||
this.toast.showError(error);
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -63,6 +63,7 @@ export class MembershipsComponent implements OnInit {
|
||||
} else {
|
||||
this.mgmtService.listUserMemberships(userId, 100, 0, []).then(resp => {
|
||||
this.memberships = resp.resultList;
|
||||
this.totalResult = resp.details?.totalResult || 0;
|
||||
this.loading = false;
|
||||
});
|
||||
}
|
||||
|
@ -19,7 +19,7 @@
|
||||
(click)="changeState(UserState.USER_STATE_INACTIVE)">{{'USER.PAGES.DEACTIVATE' |
|
||||
translate}}</button>
|
||||
<button class="state-button" mat-stroked-button color="warn"
|
||||
*ngIf="user?.state !== UserState.USER_STATE_ACTIVE"
|
||||
*ngIf="user?.state == UserState.USER_STATE_INACTIVE"
|
||||
(click)="changeState(UserState.USER_STATE_ACTIVE)">{{'USER.PAGES.REACTIVATE' | translate}}</button>
|
||||
</ng-template>
|
||||
</div>
|
||||
|
@ -12,242 +12,244 @@ import { WarnDialogComponent } from 'src/app/modules/warn-dialog/warn-dialog.com
|
||||
import { Timestamp } from 'src/app/proto/generated/google/protobuf/timestamp_pb';
|
||||
import { TextQueryMethod } from 'src/app/proto/generated/zitadel/object_pb';
|
||||
import {
|
||||
DisplayNameQuery,
|
||||
EmailQuery,
|
||||
FirstNameQuery,
|
||||
LastNameQuery,
|
||||
SearchQuery,
|
||||
Type,
|
||||
TypeQuery,
|
||||
User,
|
||||
UserNameQuery,
|
||||
UserState,
|
||||
DisplayNameQuery,
|
||||
EmailQuery,
|
||||
FirstNameQuery,
|
||||
LastNameQuery,
|
||||
SearchQuery,
|
||||
Type,
|
||||
TypeQuery,
|
||||
User,
|
||||
UserNameQuery,
|
||||
UserState,
|
||||
} from 'src/app/proto/generated/zitadel/user_pb';
|
||||
import { ManagementService } from 'src/app/services/mgmt.service';
|
||||
import { ToastService } from 'src/app/services/toast.service';
|
||||
|
||||
enum UserListSearchKey {
|
||||
FIRST_NAME,
|
||||
LAST_NAME,
|
||||
DISPLAY_NAME,
|
||||
USER_NAME,
|
||||
EMAIL,
|
||||
FIRST_NAME,
|
||||
LAST_NAME,
|
||||
DISPLAY_NAME,
|
||||
USER_NAME,
|
||||
EMAIL,
|
||||
}
|
||||
|
||||
@Component({
|
||||
selector: 'app-user-table',
|
||||
templateUrl: './user-table.component.html',
|
||||
styleUrls: ['./user-table.component.scss'],
|
||||
animations: [
|
||||
enterAnimations,
|
||||
],
|
||||
selector: 'app-user-table',
|
||||
templateUrl: './user-table.component.html',
|
||||
styleUrls: ['./user-table.component.scss'],
|
||||
animations: [
|
||||
enterAnimations,
|
||||
],
|
||||
})
|
||||
export class UserTableComponent implements OnInit {
|
||||
public userSearchKey: UserListSearchKey | undefined = undefined;
|
||||
public Type: any = Type;
|
||||
@Input() type: Type = Type.TYPE_HUMAN;
|
||||
@Input() refreshOnPreviousRoutes: string[] = [];
|
||||
@Input() disabled: boolean = false;
|
||||
@ViewChild(PaginatorComponent) public paginator!: PaginatorComponent;
|
||||
@ViewChild('input') public filter!: Input;
|
||||
public userSearchKey: UserListSearchKey | undefined = undefined;
|
||||
public Type: any = Type;
|
||||
@Input() type: Type = Type.TYPE_HUMAN;
|
||||
@Input() refreshOnPreviousRoutes: string[] = [];
|
||||
@Input() disabled: boolean = false;
|
||||
@ViewChild(PaginatorComponent) public paginator!: PaginatorComponent;
|
||||
@ViewChild('input') public filter!: Input;
|
||||
|
||||
public viewTimestamp!: Timestamp.AsObject;
|
||||
public totalResult: number = 0;
|
||||
public dataSource: MatTableDataSource<User.AsObject> = new MatTableDataSource<User.AsObject>();
|
||||
public selection: SelectionModel<User.AsObject> = new SelectionModel<User.AsObject>(true, []);
|
||||
private loadingSubject: BehaviorSubject<boolean> = new BehaviorSubject<boolean>(false);
|
||||
public loading$: Observable<boolean> = this.loadingSubject.asObservable();
|
||||
@Input() public displayedColumns: string[] = ['select', 'displayName', 'username', 'email', 'state', 'actions'];
|
||||
public viewTimestamp!: Timestamp.AsObject;
|
||||
public totalResult: number = 0;
|
||||
public dataSource: MatTableDataSource<User.AsObject> = new MatTableDataSource<User.AsObject>();
|
||||
public selection: SelectionModel<User.AsObject> = new SelectionModel<User.AsObject>(true, []);
|
||||
private loadingSubject: BehaviorSubject<boolean> = new BehaviorSubject<boolean>(false);
|
||||
public loading$: Observable<boolean> = this.loadingSubject.asObservable();
|
||||
@Input() public displayedColumns: string[] = ['select', 'displayName', 'username', 'email', 'state', 'actions'];
|
||||
|
||||
@Output() public changedSelection: EventEmitter<Array<User.AsObject>> = new EventEmitter();
|
||||
@Output() public changedSelection: EventEmitter<Array<User.AsObject>> = new EventEmitter();
|
||||
|
||||
public UserState: any = UserState;
|
||||
public UserListSearchKey: any = UserListSearchKey;
|
||||
public UserState: any = UserState;
|
||||
public UserListSearchKey: any = UserListSearchKey;
|
||||
|
||||
constructor(
|
||||
public translate: TranslateService,
|
||||
private userService: ManagementService,
|
||||
private toast: ToastService,
|
||||
private dialog: MatDialog,
|
||||
private route: ActivatedRoute,
|
||||
) {
|
||||
this.selection.changed.subscribe(() => {
|
||||
this.changedSelection.emit(this.selection.selected);
|
||||
});
|
||||
}
|
||||
constructor(
|
||||
public translate: TranslateService,
|
||||
private userService: ManagementService,
|
||||
private toast: ToastService,
|
||||
private dialog: MatDialog,
|
||||
private route: ActivatedRoute,
|
||||
) {
|
||||
this.selection.changed.subscribe(() => {
|
||||
this.changedSelection.emit(this.selection.selected);
|
||||
});
|
||||
}
|
||||
|
||||
ngOnInit(): void {
|
||||
this.route.queryParams.pipe(take(1)).subscribe(params => {
|
||||
this.getData(10, 0, this.type);
|
||||
if (params.deferredReload) {
|
||||
setTimeout(() => {
|
||||
this.getData(10, 0, this.type);
|
||||
}, 2000);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public isAllSelected(): boolean {
|
||||
const numSelected = this.selection.selected.length;
|
||||
const numRows = this.dataSource.data.length;
|
||||
return numSelected === numRows;
|
||||
}
|
||||
|
||||
public masterToggle(): void {
|
||||
this.isAllSelected() ?
|
||||
this.selection.clear() :
|
||||
this.dataSource.data.forEach(row => this.selection.select(row));
|
||||
}
|
||||
|
||||
|
||||
public changePage(event: PageEvent): void {
|
||||
this.selection.clear();
|
||||
this.getData(event.pageSize, event.pageIndex * event.pageSize, this.type);
|
||||
}
|
||||
|
||||
public deactivateSelectedUsers(): void {
|
||||
Promise.all(this.selection.selected.map(value => {
|
||||
return this.userService.deactivateUser(value.id);
|
||||
})).then(() => {
|
||||
this.toast.showInfo('USER.TOAST.SELECTEDDEACTIVATED', true);
|
||||
this.selection.clear();
|
||||
setTimeout(() => {
|
||||
this.refreshPage();
|
||||
}, 1000);
|
||||
}).catch(error => {
|
||||
this.toast.showError(error);
|
||||
});
|
||||
}
|
||||
|
||||
public reactivateSelectedUsers(): void {
|
||||
Promise.all(this.selection.selected.map(value => {
|
||||
return this.userService.reactivateUser(value.id);
|
||||
})).then(() => {
|
||||
this.toast.showInfo('USER.TOAST.SELECTEDREACTIVATED', true);
|
||||
this.selection.clear();
|
||||
setTimeout(() => {
|
||||
this.refreshPage();
|
||||
}, 1000);
|
||||
}).catch(error => {
|
||||
this.toast.showError(error);
|
||||
});
|
||||
}
|
||||
|
||||
private async getData(limit: number, offset: number, type: Type, searchValue?: string): Promise<void> {
|
||||
this.loadingSubject.next(true);
|
||||
const query = new SearchQuery();
|
||||
const typeQuery = new TypeQuery();
|
||||
typeQuery.setType(type);
|
||||
query.setTypeQuery(typeQuery);
|
||||
|
||||
if (searchValue && this.userSearchKey !== undefined) {
|
||||
switch (this.userSearchKey) {
|
||||
case UserListSearchKey.DISPLAY_NAME:
|
||||
const dNQuery = new DisplayNameQuery();
|
||||
dNQuery.setDisplayName(searchValue);
|
||||
dNQuery.setMethod(TextQueryMethod.TEXT_QUERY_METHOD_CONTAINS_IGNORE_CASE);
|
||||
|
||||
query.setDisplayNameQuery(dNQuery);
|
||||
break;
|
||||
case UserListSearchKey.USER_NAME:
|
||||
const uNQuery = new UserNameQuery();
|
||||
uNQuery.setUserName(searchValue);
|
||||
uNQuery.setMethod(TextQueryMethod.TEXT_QUERY_METHOD_CONTAINS_IGNORE_CASE);
|
||||
|
||||
query.setUserNameQuery(uNQuery);
|
||||
break;
|
||||
case UserListSearchKey.FIRST_NAME:
|
||||
const fNQuery = new FirstNameQuery();
|
||||
fNQuery.setFirstName(searchValue);
|
||||
fNQuery.setMethod(TextQueryMethod.TEXT_QUERY_METHOD_CONTAINS_IGNORE_CASE);
|
||||
|
||||
query.setFirstNameQuery(fNQuery);
|
||||
break;
|
||||
case UserListSearchKey.FIRST_NAME:
|
||||
const lNQuery = new LastNameQuery();
|
||||
lNQuery.setLastName(searchValue);
|
||||
lNQuery.setMethod(TextQueryMethod.TEXT_QUERY_METHOD_CONTAINS_IGNORE_CASE);
|
||||
|
||||
query.setLastNameQuery(lNQuery);
|
||||
break;
|
||||
case UserListSearchKey.EMAIL:
|
||||
const eQuery = new EmailQuery();
|
||||
eQuery.setEmailAddress(searchValue);
|
||||
eQuery.setMethod(TextQueryMethod.TEXT_QUERY_METHOD_CONTAINS_IGNORE_CASE);
|
||||
|
||||
query.setEmailQuery(eQuery);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
this.userService.listUsers(limit, offset, [query]).then(resp => {
|
||||
if (resp.details?.totalResult) {
|
||||
this.totalResult = resp.details?.totalResult;
|
||||
}
|
||||
if (resp.details?.viewTimestamp) {
|
||||
this.viewTimestamp = resp.details?.viewTimestamp;
|
||||
}
|
||||
this.dataSource.data = resp.resultList;
|
||||
this.loadingSubject.next(false);
|
||||
}).catch(error => {
|
||||
this.toast.showError(error);
|
||||
this.loadingSubject.next(false);
|
||||
});
|
||||
}
|
||||
|
||||
public refreshPage(): void {
|
||||
this.getData(this.paginator.pageSize, this.paginator.pageIndex * this.paginator.pageSize, this.type);
|
||||
}
|
||||
|
||||
public applyFilter(event: Event): void {
|
||||
this.selection.clear();
|
||||
const filterValue = (event.target as HTMLInputElement).value;
|
||||
|
||||
this.getData(
|
||||
this.paginator.pageSize,
|
||||
this.paginator.pageIndex * this.paginator.pageSize,
|
||||
this.type,
|
||||
filterValue,
|
||||
);
|
||||
}
|
||||
|
||||
public setFilter(key: UserListSearchKey): void {
|
||||
ngOnInit(): void {
|
||||
this.route.queryParams.pipe(take(1)).subscribe(params => {
|
||||
this.getData(10, 0, this.type);
|
||||
if (params.deferredReload) {
|
||||
setTimeout(() => {
|
||||
if (this.filter) {
|
||||
(this.filter as any).nativeElement.focus();
|
||||
}
|
||||
}, 100);
|
||||
this.getData(10, 0, this.type);
|
||||
}, 2000);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
if (this.userSearchKey !== key) {
|
||||
this.userSearchKey = key;
|
||||
} else {
|
||||
this.userSearchKey = undefined;
|
||||
public isAllSelected(): boolean {
|
||||
const numSelected = this.selection.selected.length;
|
||||
const numRows = this.dataSource.data.length;
|
||||
return numSelected === numRows;
|
||||
}
|
||||
|
||||
public masterToggle(): void {
|
||||
this.isAllSelected() ?
|
||||
this.selection.clear() :
|
||||
this.dataSource.data.forEach(row => this.selection.select(row));
|
||||
}
|
||||
|
||||
|
||||
public changePage(event: PageEvent): void {
|
||||
this.selection.clear();
|
||||
this.getData(event.pageSize, event.pageIndex * event.pageSize, this.type);
|
||||
}
|
||||
|
||||
public deactivateSelectedUsers(): void {
|
||||
Promise.all(this.selection.selected.map(value => {
|
||||
return this.userService.deactivateUser(value.id);
|
||||
})).then(() => {
|
||||
this.toast.showInfo('USER.TOAST.SELECTEDDEACTIVATED', true);
|
||||
this.selection.clear();
|
||||
setTimeout(() => {
|
||||
this.refreshPage();
|
||||
}, 1000);
|
||||
}).catch(error => {
|
||||
this.toast.showError(error);
|
||||
});
|
||||
}
|
||||
|
||||
public reactivateSelectedUsers(): void {
|
||||
Promise.all(this.selection.selected.map(value => {
|
||||
return this.userService.reactivateUser(value.id);
|
||||
})).then(() => {
|
||||
this.toast.showInfo('USER.TOAST.SELECTEDREACTIVATED', true);
|
||||
this.selection.clear();
|
||||
setTimeout(() => {
|
||||
this.refreshPage();
|
||||
}, 1000);
|
||||
}).catch(error => {
|
||||
this.toast.showError(error);
|
||||
});
|
||||
}
|
||||
|
||||
private async getData(limit: number, offset: number, type: Type, searchValue?: string): Promise<void> {
|
||||
this.loadingSubject.next(true);
|
||||
const query = new SearchQuery();
|
||||
const typeQuery = new TypeQuery();
|
||||
typeQuery.setType(type);
|
||||
query.setTypeQuery(typeQuery);
|
||||
|
||||
if (searchValue && this.userSearchKey !== undefined) {
|
||||
switch (this.userSearchKey) {
|
||||
case UserListSearchKey.DISPLAY_NAME:
|
||||
const dNQuery = new DisplayNameQuery();
|
||||
dNQuery.setDisplayName(searchValue);
|
||||
dNQuery.setMethod(TextQueryMethod.TEXT_QUERY_METHOD_CONTAINS_IGNORE_CASE);
|
||||
|
||||
query.setDisplayNameQuery(dNQuery);
|
||||
break;
|
||||
case UserListSearchKey.USER_NAME:
|
||||
const uNQuery = new UserNameQuery();
|
||||
uNQuery.setUserName(searchValue);
|
||||
uNQuery.setMethod(TextQueryMethod.TEXT_QUERY_METHOD_CONTAINS_IGNORE_CASE);
|
||||
|
||||
query.setUserNameQuery(uNQuery);
|
||||
break;
|
||||
case UserListSearchKey.FIRST_NAME:
|
||||
const fNQuery = new FirstNameQuery();
|
||||
fNQuery.setFirstName(searchValue);
|
||||
fNQuery.setMethod(TextQueryMethod.TEXT_QUERY_METHOD_CONTAINS_IGNORE_CASE);
|
||||
|
||||
query.setFirstNameQuery(fNQuery);
|
||||
break;
|
||||
case UserListSearchKey.FIRST_NAME:
|
||||
const lNQuery = new LastNameQuery();
|
||||
lNQuery.setLastName(searchValue);
|
||||
lNQuery.setMethod(TextQueryMethod.TEXT_QUERY_METHOD_CONTAINS_IGNORE_CASE);
|
||||
|
||||
query.setLastNameQuery(lNQuery);
|
||||
break;
|
||||
case UserListSearchKey.EMAIL:
|
||||
const eQuery = new EmailQuery();
|
||||
eQuery.setEmailAddress(searchValue);
|
||||
eQuery.setMethod(TextQueryMethod.TEXT_QUERY_METHOD_CONTAINS_IGNORE_CASE);
|
||||
|
||||
query.setEmailQuery(eQuery);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
this.userService.listUsers(limit, offset, [query]).then(resp => {
|
||||
if (resp.details?.totalResult) {
|
||||
this.totalResult = resp.details?.totalResult;
|
||||
} else {
|
||||
this.totalResult = 0;
|
||||
}
|
||||
if (resp.details?.viewTimestamp) {
|
||||
this.viewTimestamp = resp.details?.viewTimestamp;
|
||||
}
|
||||
this.dataSource.data = resp.resultList;
|
||||
this.loadingSubject.next(false);
|
||||
}).catch(error => {
|
||||
this.toast.showError(error);
|
||||
this.loadingSubject.next(false);
|
||||
});
|
||||
}
|
||||
|
||||
public refreshPage(): void {
|
||||
this.getData(this.paginator.pageSize, this.paginator.pageIndex * this.paginator.pageSize, this.type);
|
||||
}
|
||||
|
||||
public applyFilter(event: Event): void {
|
||||
this.selection.clear();
|
||||
const filterValue = (event.target as HTMLInputElement).value;
|
||||
|
||||
this.getData(
|
||||
this.paginator.pageSize,
|
||||
this.paginator.pageIndex * this.paginator.pageSize,
|
||||
this.type,
|
||||
filterValue,
|
||||
);
|
||||
}
|
||||
|
||||
public setFilter(key: UserListSearchKey): void {
|
||||
setTimeout(() => {
|
||||
if (this.filter) {
|
||||
(this.filter as any).nativeElement.focus();
|
||||
}
|
||||
}, 100);
|
||||
|
||||
if (this.userSearchKey !== key) {
|
||||
this.userSearchKey = key;
|
||||
} else {
|
||||
this.userSearchKey = undefined;
|
||||
this.refreshPage();
|
||||
}
|
||||
}
|
||||
|
||||
public deleteUser(user: User.AsObject): void {
|
||||
const dialogRef = this.dialog.open(WarnDialogComponent, {
|
||||
data: {
|
||||
confirmKey: 'ACTIONS.DELETE',
|
||||
cancelKey: 'ACTIONS.CANCEL',
|
||||
titleKey: 'USER.DIALOG.DELETE_TITLE',
|
||||
descriptionKey: 'USER.DIALOG.DELETE_DESCRIPTION',
|
||||
},
|
||||
width: '400px',
|
||||
});
|
||||
|
||||
dialogRef.afterClosed().subscribe(resp => {
|
||||
if (resp) {
|
||||
this.userService.removeUser(user.id).then(() => {
|
||||
setTimeout(() => {
|
||||
this.refreshPage();
|
||||
}
|
||||
}
|
||||
|
||||
public deleteUser(user: User.AsObject): void {
|
||||
const dialogRef = this.dialog.open(WarnDialogComponent, {
|
||||
data: {
|
||||
confirmKey: 'ACTIONS.DELETE',
|
||||
cancelKey: 'ACTIONS.CANCEL',
|
||||
titleKey: 'USER.DIALOG.DELETE_TITLE',
|
||||
descriptionKey: 'USER.DIALOG.DELETE_DESCRIPTION',
|
||||
},
|
||||
width: '400px',
|
||||
}, 1000);
|
||||
this.toast.showInfo('USER.TOAST.DELETED', true);
|
||||
}).catch(error => {
|
||||
this.toast.showError(error);
|
||||
});
|
||||
|
||||
dialogRef.afterClosed().subscribe(resp => {
|
||||
if (resp) {
|
||||
this.userService.removeUser(user.id).then(() => {
|
||||
setTimeout(() => {
|
||||
this.refreshPage();
|
||||
}, 1000);
|
||||
this.toast.showInfo('USER.TOAST.DELETED', true);
|
||||
}).catch(error => {
|
||||
this.toast.showError(error);
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -1078,6 +1078,7 @@
|
||||
"TITLE": "OIDC-Konfiguration",
|
||||
"CLIENTID": "Client ID",
|
||||
"CLIENTSECRET": "Client Secret",
|
||||
"CLIENTSECRET_NOSECRET":"Bei ihrem gewählten Authentication Flow wird kein Secret benötigt und steht daher nicht zur Verfügung.",
|
||||
"CLIENTSECRET_DESCRIPTION": "Verwahre das Client Secret an einem sicheren Ort, da es nicht mehr angezeigt werden kann, sobald der Dialog geschlossen wird.",
|
||||
"REGENERATESECRET": "Client Secret neu generieren",
|
||||
"DEVMODE": "Entwicklermodus",
|
||||
|
@ -1079,6 +1079,7 @@
|
||||
"TITLE": "OIDC Configuration",
|
||||
"CLIENTID": "Client ID",
|
||||
"CLIENTSECRET": "Client Secret",
|
||||
"CLIENTSECRET_NOSECRET":"With your chosen authentication flow, no secret is required and is therefore not available.",
|
||||
"CLIENTSECRET_DESCRIPTION": "Keep your client secret at a safe place as it will disappear once the dialog is closed.",
|
||||
"REGENERATESECRET": "Regenerate Client Secret",
|
||||
"DEVMODE": "Development Mode",
|
||||
|
Loading…
Reference in New Issue
Block a user