mirror of
https://github.com/andwati/zitadel.git
synced 2026-11-05 13:52:15 +00:00
feat(console): granted project detail (#203)
* granted project detail * support for grantedProjects * getGrantedProjectGrantByIDs * fix grant members bindings * seperate granted from owned project detail * lint * dont show apps on granted projects
This commit is contained in:
+49
@@ -0,0 +1,49 @@
|
||||
<app-meta-layout>
|
||||
<div class="max-width-container">
|
||||
<div class="head" *ngIf="project?.id">
|
||||
<a [routerLink]="[ '/projects' ]" mat-icon-button>
|
||||
<mat-icon class="icon">arrow_back</mat-icon>
|
||||
</a>
|
||||
<h1>{{ 'PROJECT.PAGES.TITLE' | translate }} {{project?.name}}</h1>
|
||||
|
||||
<div class="full-width">
|
||||
<p class="desc">{{ 'PROJECT.PAGES.DESCRIPTION' | translate }}</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- <ng-template appHasRole [appHasRole]="['project.app.read:' + project?.id, 'project.app.read']">
|
||||
<app-project-application-grid *ngIf="grid" [disabled]="project?.state !== ProjectState.PROJECTSTATE_ACTIVE"
|
||||
(changeView)="grid = false" [projectId]="projectId"></app-project-application-grid>
|
||||
<app-card *ngIf="!grid" title="{{ 'PROJECT.APP.TITLE' | translate }}">
|
||||
<card-actions class="card-actions">
|
||||
<button mat-icon-button (click)="grid = true">
|
||||
<i matTooltip="show grid view" class="las la-th-large"></i>
|
||||
</button>
|
||||
</card-actions>
|
||||
<app-project-applications [disabled]="project?.state !== ProjectState.PROJECTSTATE_ACTIVE"
|
||||
[projectId]="projectId"></app-project-applications>
|
||||
</app-card>
|
||||
</ng-template> -->
|
||||
|
||||
<app-card>
|
||||
<app-project-grant-members *ngIf="project && project.id && project.grantId"
|
||||
[disabled]="project?.state !== ProjectState.PROJECTSTATE_ACTIVE" [project]="project">
|
||||
</app-project-grant-members>
|
||||
</app-card>
|
||||
</div>
|
||||
<metainfo class="side">
|
||||
<div class="details">
|
||||
<div class="row">
|
||||
<span class="first">{{'PROJECT.TYPE.TITLE' | translate}}:</span>
|
||||
<span class="second">{{'PROJECT.TYPE.'+ ProjectType.PROJECTTYPE_GRANTED | translate}}</span>
|
||||
</div>
|
||||
<div class="row">
|
||||
<span class="first">{{'PROJECT.STATE.TITLE' | translate}}:</span>
|
||||
<span *ngIf="project && project.state !== undefined"
|
||||
class="second">{{'PROJECT.STATE.'+project.state | translate}}</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<app-changes *ngIf="project" [changeType]="ChangeType.PROJECT" [id]="project.id"></app-changes>
|
||||
</metainfo>
|
||||
</app-meta-layout>
|
||||
+117
@@ -0,0 +1,117 @@
|
||||
.head {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
border-bottom: 1px solid #ffffff20;
|
||||
flex-wrap: wrap;
|
||||
margin-bottom: 1rem;
|
||||
|
||||
a {
|
||||
display: block;
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-size: 1.2rem;
|
||||
margin: 0 1rem;
|
||||
margin-left: 2rem;
|
||||
font-weight: normal;
|
||||
}
|
||||
|
||||
.full-width {
|
||||
padding-top: 1rem;
|
||||
width: 100%;
|
||||
display: block;
|
||||
|
||||
.icon-button {
|
||||
margin-right: 1rem;
|
||||
}
|
||||
|
||||
button {
|
||||
border-radius: .5rem;
|
||||
}
|
||||
|
||||
.desc {
|
||||
font-size: .9rem;
|
||||
color: #81868a;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.content {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
flex-wrap: wrap;
|
||||
margin: 0 -.5rem;
|
||||
|
||||
mat-form-field {
|
||||
flex: 1 1 33%;
|
||||
margin: 0 .5rem;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
.side {
|
||||
.details {
|
||||
margin-bottom: 1rem;
|
||||
border-bottom: 1px solid #81868a40;
|
||||
padding-bottom: 1rem;
|
||||
|
||||
.row {
|
||||
display: flex;
|
||||
margin-bottom: 0.5rem;
|
||||
align-items: center;
|
||||
|
||||
button {
|
||||
display: none;
|
||||
visibility: hidden;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
button {
|
||||
display: inline-block;
|
||||
visibility: visible;
|
||||
mat-icon {
|
||||
font-size: 1.2rem;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.first {
|
||||
flex: 1;
|
||||
font-size: 0.8rem;
|
||||
margin-right: 0.5rem;
|
||||
}
|
||||
|
||||
.fill-space {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.second {
|
||||
font-size: 0.8rem;
|
||||
text-overflow: ellipsis;
|
||||
overflow: hidden;
|
||||
margin-left: 1rem;
|
||||
}
|
||||
|
||||
a {
|
||||
&:hover {
|
||||
cursor: pointer;
|
||||
text-decoration: underline;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.side-section {
|
||||
color: #81868a;
|
||||
}
|
||||
}
|
||||
|
||||
.mat-tab-label {
|
||||
min-width: 100px !important;
|
||||
}
|
||||
|
||||
.flex-col {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
}
|
||||
+25
@@ -0,0 +1,25 @@
|
||||
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { GrantedProjectDetailComponent } from './granted-project-detail.component';
|
||||
|
||||
describe('GrantedProjectDetailComponent', () => {
|
||||
let component: GrantedProjectDetailComponent;
|
||||
let fixture: ComponentFixture<GrantedProjectDetailComponent>;
|
||||
|
||||
beforeEach(async(() => {
|
||||
TestBed.configureTestingModule({
|
||||
declarations: [GrantedProjectDetailComponent],
|
||||
})
|
||||
.compileComponents();
|
||||
}));
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(GrantedProjectDetailComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
||||
+104
@@ -0,0 +1,104 @@
|
||||
import { SelectionModel } from '@angular/cdk/collections';
|
||||
import { Location } from '@angular/common';
|
||||
import { Component, OnDestroy, OnInit } from '@angular/core';
|
||||
import { MatTableDataSource } from '@angular/material/table';
|
||||
import { ActivatedRoute, Params } from '@angular/router';
|
||||
import { TranslateService } from '@ngx-translate/core';
|
||||
import { from, Observable, of, Subscription } from 'rxjs';
|
||||
import { ChangeType } from 'src/app/modules/changes/changes.component';
|
||||
import {
|
||||
Application,
|
||||
ApplicationSearchResponse,
|
||||
GrantedProject,
|
||||
ProjectMember,
|
||||
ProjectMemberSearchResponse,
|
||||
ProjectRole,
|
||||
ProjectRoleSearchResponse,
|
||||
ProjectState,
|
||||
ProjectType,
|
||||
} from 'src/app/proto/generated/management_pb';
|
||||
import { GrpcService } from 'src/app/services/grpc.service';
|
||||
import { ProjectService } from 'src/app/services/project.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'],
|
||||
})
|
||||
export class GrantedProjectDetailComponent implements OnInit, OnDestroy {
|
||||
public projectId: string = '';
|
||||
public grantId: string = '';
|
||||
public project!: GrantedProject.AsObject;
|
||||
|
||||
public pageSizeRoles: number = 10;
|
||||
public roleDataSource: MatTableDataSource<ProjectRole.AsObject> = new MatTableDataSource<ProjectRole.AsObject>();
|
||||
public roleResult!: ProjectRoleSearchResponse.AsObject;
|
||||
public roleColumns: string[] = ['name', 'displayname', 'group', 'actions'];
|
||||
|
||||
public pageSizeMembers: number = 10;
|
||||
public projectDataSource: MatTableDataSource<ProjectMember.AsObject> = new MatTableDataSource<ProjectMember.AsObject>();
|
||||
public memberResult!: ProjectMemberSearchResponse.AsObject;
|
||||
public memberColumns: string[] = ['firstname', 'lastname', 'username', 'email', 'roles'];
|
||||
public selection: SelectionModel<ProjectMember.AsObject> = new SelectionModel<ProjectMember.AsObject>(true, []);
|
||||
|
||||
public pageSizeApps: number = 10;
|
||||
public appsDataSource: MatTableDataSource<Application.AsObject> = new MatTableDataSource<Application.AsObject>();
|
||||
public appsResult!: ApplicationSearchResponse.AsObject;
|
||||
public appsColumns: string[] = ['name'];
|
||||
|
||||
public ProjectState: any = ProjectState;
|
||||
public ProjectType: any = ProjectType;
|
||||
public ChangeType: any = ChangeType;
|
||||
|
||||
public grid: boolean = true;
|
||||
private subscription?: Subscription;
|
||||
public editstate: boolean = false;
|
||||
|
||||
public isZitadel$: Observable<boolean> = of(false);
|
||||
private zitadelsub: Subscription = new Subscription();
|
||||
|
||||
constructor(
|
||||
public translate: TranslateService,
|
||||
private route: ActivatedRoute,
|
||||
private toast: ToastService,
|
||||
private projectService: ProjectService,
|
||||
private _location: Location,
|
||||
private grpcService: GrpcService,
|
||||
) {
|
||||
}
|
||||
|
||||
public ngOnInit(): void {
|
||||
this.subscription = this.route.params.subscribe(params => this.getData(params));
|
||||
}
|
||||
|
||||
public ngOnDestroy(): void {
|
||||
this.subscription?.unsubscribe();
|
||||
this.zitadelsub.unsubscribe();
|
||||
}
|
||||
|
||||
private async getData({ id, grantId }: Params): Promise<void> {
|
||||
this.projectId = id;
|
||||
this.grantId = grantId;
|
||||
|
||||
if (this.projectId && this.grantId) {
|
||||
this.projectService.GetGrantedProjectGrantByID(this.projectId, this.grantId).then(proj => {
|
||||
this.project = proj.toObject();
|
||||
console.log(this.project);
|
||||
this.isZitadel$ = from(this.projectService.SearchApplications(this.project.id, 100, 0).then(appsResp => {
|
||||
const ret = appsResp.toObject().resultList
|
||||
.filter(app => app.oidcConfig?.clientId === this.grpcService.clientid).length > 0;
|
||||
return ret;
|
||||
}));
|
||||
}).catch(error => {
|
||||
this.toast.showError(error.message);
|
||||
});
|
||||
}
|
||||
|
||||
this.zitadelsub = this.isZitadel$.subscribe(isZita => console.log(`zitade: ${isZita}`));
|
||||
}
|
||||
|
||||
public navigateBack(): void {
|
||||
this._location.back();
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -42,7 +42,7 @@ export class ProjectContributorsComponent implements OnInit {
|
||||
private router: Router) { }
|
||||
|
||||
public ngOnInit(): void {
|
||||
console.log(this.project);
|
||||
console.log('project grant members');
|
||||
const promise: Promise<ProjectMemberSearchResponse> | undefined =
|
||||
this.projectType === ProjectType.PROJECTTYPE_OWNED ?
|
||||
this.projectService.SearchProjectMembers(this.project.id, 100, 0) :
|
||||
|
||||
@@ -35,7 +35,7 @@
|
||||
</div>
|
||||
|
||||
<!-- show only on owned projects-->
|
||||
<ng-container *ngIf="project && projectType == ProjectType.PROJECTTYPE_OWNED; else granteddetail">
|
||||
<ng-container *ngIf="project">
|
||||
<ng-template appHasRole [appHasRole]="['project.app.read:' + project.id, 'project.app.read']">
|
||||
<app-project-application-grid *ngIf="grid"
|
||||
[disabled]="project?.state !== ProjectState.PROJECTSTATE_ACTIVE" (changeView)="grid = false"
|
||||
@@ -71,20 +71,12 @@
|
||||
</ng-template>
|
||||
</ng-container>
|
||||
</ng-container>
|
||||
|
||||
<ng-template #granteddetail>
|
||||
<app-card>
|
||||
<app-project-grant-members *ngIf="project"
|
||||
[disabled]="project?.state !== ProjectState.PROJECTSTATE_ACTIVE" [project]="project">
|
||||
</app-project-grant-members>
|
||||
</app-card>
|
||||
</ng-template>
|
||||
</div>
|
||||
<metainfo class="side">
|
||||
<div class="details">
|
||||
<div class="row">
|
||||
<span class="first">{{'PROJECT.TYPE.TITLE' | translate}}:</span>
|
||||
<span class="second" *ngIf="projectType">{{'PROJECT.TYPE.'+ projectType | translate}}</span>
|
||||
<span class="second">{{'PROJECT.TYPE.'+ ProjectType.PROJECTTYPE_OWNED | translate}}</span>
|
||||
</div>
|
||||
<div class="row">
|
||||
<span class="first">{{'PROJECT.STATE.TITLE' | translate}}:</span>
|
||||
@@ -93,22 +85,16 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<ng-container *ngIf="projectType === ProjectType.PROJECTTYPE_OWNED; else grantedmeta">
|
||||
<mat-tab-group mat-stretch-tabs class="tab-group" disablePagination="true">
|
||||
<mat-tab label="Details">
|
||||
<app-project-contributors *ngIf="project"
|
||||
[disabled]="project?.state !== ProjectState.PROJECTSTATE_ACTIVE" [projectType]="projectType"
|
||||
[project]="project">
|
||||
</app-project-contributors>
|
||||
</mat-tab>
|
||||
<mat-tab label="{{ 'CHANGES.PROJECT.TITLE' | translate }}" class="flex-col">
|
||||
<app-changes *ngIf="project" [changeType]="ChangeType.PROJECT" [id]="project.id"></app-changes>
|
||||
</mat-tab>
|
||||
</mat-tab-group>
|
||||
</ng-container>
|
||||
|
||||
<ng-template #grantedmeta>
|
||||
<app-changes *ngIf="project" [changeType]="ChangeType.PROJECT" [id]="project.id"></app-changes>
|
||||
</ng-template>
|
||||
<mat-tab-group mat-stretch-tabs class="tab-group" disablePagination="true">
|
||||
<mat-tab label="Details">
|
||||
<app-project-contributors *ngIf="project"
|
||||
[disabled]="project?.state !== ProjectState.PROJECTSTATE_ACTIVE"
|
||||
[projectType]="ProjectType.PROJECTTYPE_OWNED" [project]="project">
|
||||
</app-project-contributors>
|
||||
</mat-tab>
|
||||
<mat-tab label="{{ 'CHANGES.PROJECT.TITLE' | translate }}" class="flex-col">
|
||||
<app-changes *ngIf="project" [changeType]="ChangeType.PROJECT" [id]="project.id"></app-changes>
|
||||
</mat-tab>
|
||||
</mat-tab-group>
|
||||
</metainfo>
|
||||
</app-meta-layout>
|
||||
@@ -9,6 +9,7 @@ import { ChangeType } from 'src/app/modules/changes/changes.component';
|
||||
import {
|
||||
Application,
|
||||
ApplicationSearchResponse,
|
||||
GrantedProject,
|
||||
Project,
|
||||
ProjectMember,
|
||||
ProjectMemberSearchResponse,
|
||||
@@ -29,9 +30,7 @@ import { ToastService } from 'src/app/services/toast.service';
|
||||
})
|
||||
export class ProjectDetailComponent implements OnInit, OnDestroy {
|
||||
public projectId: string = '';
|
||||
public grantId: string = '';
|
||||
public project!: Project.AsObject; // ProjectGrant.AsObject;
|
||||
public projectType: ProjectType = ProjectType.PROJECTTYPE_OWNED;
|
||||
public project!: Project.AsObject | GrantedProject.AsObject;
|
||||
|
||||
public pageSizeRoles: number = 10;
|
||||
public roleDataSource: MatTableDataSource<ProjectRole.AsObject> = new MatTableDataSource<ProjectRole.AsObject>();
|
||||
@@ -58,6 +57,7 @@ export class ProjectDetailComponent implements OnInit, OnDestroy {
|
||||
public editstate: boolean = false;
|
||||
|
||||
public isZitadel$: Observable<boolean> = of(false);
|
||||
private zitadelsub: Subscription = new Subscription();
|
||||
|
||||
constructor(
|
||||
public translate: TranslateService,
|
||||
@@ -75,43 +75,26 @@ export class ProjectDetailComponent implements OnInit, OnDestroy {
|
||||
|
||||
public ngOnDestroy(): void {
|
||||
this.subscription?.unsubscribe();
|
||||
this.zitadelsub.unsubscribe();
|
||||
}
|
||||
|
||||
private async getData({ id, grantId }: Params): Promise<void> {
|
||||
private async getData({ id }: Params): Promise<void> {
|
||||
this.projectId = id;
|
||||
this.grantId = grantId;
|
||||
|
||||
if (grantId) {
|
||||
this.projectType = ProjectType.PROJECTTYPE_GRANTED;
|
||||
// this.projectService.GetGrantedProjectGrantByID(id, this.grantId).then(proj => {
|
||||
// this.projectGrant = proj.toObject();
|
||||
// this.isZitadel$ = from(this.projectService.SearchApplications(this.project.id, 100, 0).then(appsResp => {
|
||||
// const ret = appsResp.toObject().resultList
|
||||
// .filter(app => app.oidcConfig?.clientId === this.grpcService.clientid).length > 0;
|
||||
// return ret;
|
||||
// })); // TODO: replace with prettier thing
|
||||
// }).catch(error => {
|
||||
// this.toast.showError(error.message);
|
||||
// });
|
||||
} else {
|
||||
this.projectType = ProjectType.PROJECTTYPE_OWNED;
|
||||
if (this.projectId) {
|
||||
this.projectService.GetProjectById(id).then(proj => {
|
||||
this.project = proj.toObject();
|
||||
// if (this.project.type !== ProjectType.PROJECTTYPE_SELF ||
|
||||
// this.project.state === ProjectState.PROJECTSTATE_INACTIVE ||
|
||||
// this.project.state === ProjectState.PROJECTSTATE_UNSPECIFIED) {
|
||||
// }
|
||||
|
||||
this.isZitadel$ = from(this.projectService.SearchApplications(this.project.id, 100, 0).then(appsResp => {
|
||||
const ret = appsResp.toObject().resultList
|
||||
.filter(app => app.oidcConfig?.clientId === this.grpcService.clientid).length > 0;
|
||||
return ret;
|
||||
})); // TODO: replace with prettier thing
|
||||
this.isZitadel$.subscribe(isZita => console.log(`zitade: ${isZita}`));
|
||||
}));
|
||||
}).catch(error => {
|
||||
this.toast.showError(error.message);
|
||||
});
|
||||
}
|
||||
|
||||
this.zitadelsub = this.isZitadel$.subscribe(isZita => console.log(`zitade: ${isZita}`));
|
||||
}
|
||||
|
||||
public changeState(newState: ProjectState): void {
|
||||
@@ -122,16 +105,12 @@ export class ProjectDetailComponent implements OnInit, OnDestroy {
|
||||
this.toast.showError(error.message);
|
||||
});
|
||||
} else if (newState === ProjectState.PROJECTSTATE_INACTIVE) {
|
||||
this.projectService.DeactivateProject(this.projectId).then(() => {
|
||||
this.toast.showInfo('Deactivated Project');
|
||||
}).catch(error => {
|
||||
this.toast.showError(error.message);
|
||||
});
|
||||
this.toast.showInfo('You cant update this project.');
|
||||
}
|
||||
}
|
||||
|
||||
public saveProject(): void {
|
||||
this.projectService.UpdateProject(this.project).then(() => {
|
||||
this.projectService.UpdateProject(this.project as Project.AsObject).then(() => {
|
||||
this.toast.showInfo('Project updated');
|
||||
}).catch(error => {
|
||||
this.toast.showInfo(error.message);
|
||||
|
||||
+15
-12
@@ -1,7 +1,7 @@
|
||||
import { DataSource } from '@angular/cdk/collections';
|
||||
import { BehaviorSubject, from, Observable, of } from 'rxjs';
|
||||
import { catchError, finalize, map } from 'rxjs/operators';
|
||||
import { GrantedProject, ProjectMember } from 'src/app/proto/generated/management_pb';
|
||||
import { ProjectMember } from 'src/app/proto/generated/management_pb';
|
||||
import { ProjectService } from 'src/app/services/project.service';
|
||||
|
||||
/**
|
||||
@@ -19,21 +19,24 @@ export class ProjectGrantMembersDataSource extends DataSource<ProjectMember.AsOb
|
||||
super();
|
||||
}
|
||||
|
||||
public loadMembers(project: GrantedProject.AsObject, pageIndex: number, pageSize: number, sortDirection?: string): void {
|
||||
public loadMembers(projectId: string, grantId: string, pageIndex: number,
|
||||
pageSize: number, sortDirection?: string): void {
|
||||
const offset = pageIndex * pageSize;
|
||||
|
||||
this.loadingSubject.next(true);
|
||||
|
||||
from(this.projectService.SearchProjectGrantMembers(project.id, project.grantId, pageSize, offset)).pipe(
|
||||
map(resp => {
|
||||
this.totalResult = resp.toObject().totalResult;
|
||||
return resp.toObject().resultList;
|
||||
}),
|
||||
catchError(() => of([])),
|
||||
finalize(() => this.loadingSubject.next(false)),
|
||||
).subscribe(members => {
|
||||
this.membersSubject.next(members);
|
||||
});
|
||||
from(this.projectService.SearchProjectGrantMembers(projectId,
|
||||
grantId, pageSize, offset)).pipe(
|
||||
map(resp => {
|
||||
this.totalResult = resp.toObject().totalResult;
|
||||
return resp.toObject().resultList;
|
||||
}),
|
||||
catchError(() => of([])),
|
||||
finalize(() => this.loadingSubject.next(false)),
|
||||
).subscribe(members => {
|
||||
console.log(members);
|
||||
this.membersSubject.next(members);
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
<h1>{{project?.name}} {{ 'PROJECT.MEMBER.TITLE' | translate }}</h1>
|
||||
<h1>{{ 'PROJECT.MEMBER.TITLE' | translate }}</h1>
|
||||
<p class="desc">{{ 'PROJECT.MEMBER.DESCRIPTION' | translate }}</p>
|
||||
|
||||
<div class="table-header-row">
|
||||
|
||||
+24
-21
@@ -3,9 +3,8 @@ import { AfterViewInit, Component, Input, OnInit, ViewChild } from '@angular/cor
|
||||
import { MatDialog } from '@angular/material/dialog';
|
||||
import { MatPaginator } from '@angular/material/paginator';
|
||||
import { MatTable } from '@angular/material/table';
|
||||
import { ActivatedRoute } from '@angular/router';
|
||||
import { tap } from 'rxjs/operators';
|
||||
import { GrantedProject, ProjectMember, User } from 'src/app/proto/generated/management_pb';
|
||||
import { ProjectMember, User } from 'src/app/proto/generated/management_pb';
|
||||
import { ProjectService } from 'src/app/services/project.service';
|
||||
import { ToastService } from 'src/app/services/toast.service';
|
||||
|
||||
@@ -21,7 +20,9 @@ import { ProjectGrantMembersDataSource } from './project-grant-members-datasourc
|
||||
styleUrls: ['./project-grant-members.component.scss'],
|
||||
})
|
||||
export class ProjectGrantMembersComponent implements AfterViewInit, OnInit {
|
||||
@Input() public project!: GrantedProject.AsObject;
|
||||
@Input() public projectId!: string;
|
||||
@Input() public grantId!: string;
|
||||
|
||||
public disabled: boolean = false;
|
||||
@ViewChild(MatPaginator) public paginator!: MatPaginator;
|
||||
@ViewChild(MatTable) public table!: MatTable<ProjectMember.AsObject>;
|
||||
@@ -34,12 +35,12 @@ export class ProjectGrantMembersComponent implements AfterViewInit, OnInit {
|
||||
constructor(private projectService: ProjectService,
|
||||
private dialog: MatDialog,
|
||||
private toast: ToastService,
|
||||
private route: ActivatedRoute) {
|
||||
) {
|
||||
}
|
||||
|
||||
public ngOnInit(): void {
|
||||
this.dataSource = new ProjectGrantMembersDataSource(this.projectService);
|
||||
this.dataSource.loadMembers(this.project, 0, 25, 'asc');
|
||||
this.dataSource.loadMembers(this.projectId, this.grantId, 0, 25, 'asc');
|
||||
}
|
||||
|
||||
public ngAfterViewInit(): void {
|
||||
@@ -48,33 +49,33 @@ export class ProjectGrantMembersComponent implements AfterViewInit, OnInit {
|
||||
tap(() => this.loadMembersPage()),
|
||||
)
|
||||
.subscribe();
|
||||
|
||||
}
|
||||
|
||||
private loadMembersPage(): void {
|
||||
this.dataSource.loadMembers(
|
||||
this.project,
|
||||
this.projectId,
|
||||
this.grantId,
|
||||
this.paginator.pageIndex,
|
||||
this.paginator.pageSize,
|
||||
);
|
||||
}
|
||||
|
||||
public removeProjectMemberSelection(): void {
|
||||
Promise.all(this.selection.selected.map(member => {
|
||||
return this.projectService.RemoveProjectMember(this.project.id, member.userId).then(() => {
|
||||
this.toast.showInfo('Removed successfully');
|
||||
}).catch(error => {
|
||||
this.toast.showError(error.message);
|
||||
});
|
||||
}));
|
||||
// Promise.all(this.selection.selected.map(member => {
|
||||
// return this.projectService.RemoveProjectMember(this.projectId, this.grantId, member.userId).then(() => {
|
||||
// this.toast.showInfo('Removed successfully');
|
||||
// }).catch(error => {
|
||||
// this.toast.showError(error.message);
|
||||
// });
|
||||
// }));
|
||||
}
|
||||
|
||||
public removeMember(member: ProjectMember.AsObject): void {
|
||||
this.projectService.RemoveProjectMember(this.project.id, member.userId).then(() => {
|
||||
this.toast.showInfo('Member removed successfully');
|
||||
}).catch(error => {
|
||||
this.toast.showError(error.message);
|
||||
});
|
||||
// this.projectService.RemoveProjectMember(this.grantedProject.id, member.userId).then(() => {
|
||||
// this.toast.showInfo('Member removed successfully');
|
||||
// }).catch(error => {
|
||||
// this.toast.showError(error.message);
|
||||
// });
|
||||
}
|
||||
|
||||
public isAllSelected(): boolean {
|
||||
@@ -93,19 +94,21 @@ export class ProjectGrantMembersComponent implements AfterViewInit, OnInit {
|
||||
const dialogRef = this.dialog.open(ProjectMemberCreateDialogComponent, {
|
||||
data: {
|
||||
creationType: CreationType.PROJECT_GRANTED,
|
||||
projectId: this.project.id,
|
||||
projectId: this.projectId,
|
||||
},
|
||||
width: '400px',
|
||||
});
|
||||
|
||||
dialogRef.afterClosed().subscribe(resp => {
|
||||
if (resp) {
|
||||
console.log(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.projectService.AddProjectMember(this.project.id, user.id, roles);
|
||||
return this.projectService.AddProjectGrantMember(this.projectId,
|
||||
this.grantId, user.id, roles);
|
||||
})).then(() => {
|
||||
this.toast.showError('members added');
|
||||
}).catch(error => {
|
||||
|
||||
@@ -48,19 +48,17 @@ export class ProjectGridComponent {
|
||||
public selectItem(item: GrantedProject.AsObject, event?: any): void {
|
||||
if (event && !event.target.classList.contains('mat-icon')) {
|
||||
if (item.grantId) {
|
||||
this.router.navigate([item.id, '/grant', `${item.grantId}`]);
|
||||
this.router.navigate(['projects', item.id, 'grant', `${item.grantId}`]);
|
||||
} else {
|
||||
this.router.navigate(['/projects', item.id]);
|
||||
}
|
||||
} else if (!event) {
|
||||
if (item.grantId) {
|
||||
this.router.navigate([item.id, '/grant', `${item.grantId}`]);
|
||||
this.router.navigate(['projects', item.id, 'grant', `${item.grantId}`]);
|
||||
} else {
|
||||
this.router.navigate(['/projects', item.id]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
public addItem(): void {
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { NgModule } from '@angular/core';
|
||||
import { RouterModule, Routes } from '@angular/router';
|
||||
|
||||
import { GrantedProjectDetailComponent } from './granted-project-detail/granted-project-detail.component';
|
||||
import { ProjectDetailComponent } from './project-detail/project-detail.component';
|
||||
import { ProjectListComponent } from './project-list/project-list.component';
|
||||
|
||||
@@ -16,7 +17,7 @@ const routes: Routes = [
|
||||
},
|
||||
{
|
||||
path: ':id/grant/:grantId',
|
||||
component: ProjectDetailComponent,
|
||||
component: GrantedProjectDetailComponent,
|
||||
data: { animation: 'HomePage' },
|
||||
},
|
||||
{
|
||||
|
||||
@@ -42,6 +42,7 @@ import { ProjectGrantsComponent } from './project-grants/project-grants.componen
|
||||
import { ProjectGridComponent } from './project-grid/project-grid.component';
|
||||
import { ProjectListComponent } from './project-list/project-list.component';
|
||||
import { ProjectsRoutingModule } from './projects-routing.module';
|
||||
import { GrantedProjectDetailComponent } from './granted-project-detail/granted-project-detail.component';
|
||||
|
||||
@NgModule({
|
||||
declarations: [
|
||||
@@ -54,6 +55,7 @@ import { ProjectsRoutingModule } from './projects-routing.module';
|
||||
ProjectGrantMembersComponent,
|
||||
ProjectGrantMembersCreateDialogComponent,
|
||||
ProjectContributorsComponent,
|
||||
GrantedProjectDetailComponent,
|
||||
],
|
||||
imports: [
|
||||
ProjectsRoutingModule,
|
||||
|
||||
Reference in New Issue
Block a user