fix(console): refactoring (#197)

* return error from changes

* project member context, org-policies, state

* project type seperation

* chore(deps): bump grpc from 1.24.2 to 1.24.3 in /console (#183)

Bumps [grpc](https://github.com/grpc/grpc-node) from 1.24.2 to 1.24.3.
- [Release notes](https://github.com/grpc/grpc-node/releases)
- [Commits](https://github.com/grpc/grpc-node/compare/[email protected]@1.24.3)

Signed-off-by: dependabot[bot] <[email protected]>

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

* chore(deps): bump google-proto-files from 1.1.2 to 2.1.0 in /console (#176)

Bumps [google-proto-files](https://github.com/googleapis/nodejs-proto-files) from 1.1.2 to 2.1.0.
- [Release notes](https://github.com/googleapis/nodejs-proto-files/releases)
- [Changelog](https://github.com/googleapis/nodejs-proto-files/blob/master/CHANGELOG.md)
- [Commits](https://github.com/googleapis/nodejs-proto-files/compare/v1.1.2...v2.1.0)

Signed-off-by: dependabot[bot] <[email protected]>

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

* chore(deps-dev): bump karma-coverage-istanbul-reporter in /console (#169)

Bumps [karma-coverage-istanbul-reporter](https://github.com/mattlewis92/karma-coverage-istanbul-reporter) from 3.0.2 to 3.0.3.
- [Release notes](https://github.com/mattlewis92/karma-coverage-istanbul-reporter/releases)
- [Changelog](https://github.com/mattlewis92/karma-coverage-istanbul-reporter/blob/master/CHANGELOG.md)
- [Commits](https://github.com/mattlewis92/karma-coverage-istanbul-reporter/compare/v3.0.2...v3.0.3)

Signed-off-by: dependabot[bot] <[email protected]>

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

* update packages

* update deps

* lint

* replace assets

* add key, creationdate for roles

* project grant members

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
This commit is contained in:
Max Peintner
2020-06-10 12:59:12 +02:00
committed by GitHub
co-authored by dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
parent e0fb19b4e9
commit 2d369fbcd3
51 changed files with 1051 additions and 1376 deletions
@@ -2,7 +2,7 @@
<h3>{{'APP.LIST' | translate}}</h3>
<span class="fill-space"></span>
<button mat-icon-button (click)="closeView()">
<mat-icon matTooltip="show list view">list</mat-icon>
<i class="show list view las la-th-list"></i>
</button>
</div>
<div class="app-container">
@@ -18,6 +18,7 @@
padding-bottom: 2rem;
.app-wrap {
outline: none;
display: flex;
flex-direction: column;
align-items: center;
@@ -73,4 +73,8 @@
.pointer {
outline: none;
cursor: pointer;
}
}
tr {
outline: none;
}
@@ -5,15 +5,15 @@
<div class="img-list">
<ng-container *ngIf="totalResult < 10; else compact">
<ng-container *ngFor="let member of membersSubject | async">
<img (click)="showDetail()" *ngIf="member.imageURL; else render" class="avatar-img"
<!-- <img (click)="showDetail()" *ngIf="member.imageURL; else render" class="avatar-img"
[src]="member.imageURL" matTooltip="{{ member.email }} | {{member.rolesList?.join(' ')}}"
alt="editor avatar" />
<ng-template #render>
<div (click)="showDetail()" class="avatar-circle"
matTooltip="{{ member.email }} | {{member.rolesList?.join(' ')}}">
<mat-icon>face</mat-icon>
</div>
</ng-template>
<ng-template #render> -->
<div (click)="showDetail()" class="avatar-circle"
matTooltip="{{ member.email }} | {{member.rolesList?.join(' ')}}">
<mat-icon>face</mat-icon>
</div>
<!-- </ng-template> -->
</ng-container>
</ng-container>
<ng-template #compact>
@@ -22,7 +22,7 @@
</div>
</ng-template>
<button class="add-img" (click)="openAddMember()"
[disabled]="project?.state !== ProjectState.ACTIVE_PROJECT" mat-icon-button
[disabled]="project?.state !== ProjectState.PROJECTSTATE_ACTIVE" mat-icon-button
aria-label="Edit contributors">
<mat-icon>add</mat-icon>
</button>
@@ -5,7 +5,6 @@
display: block;
margin-bottom: 1rem;
font-weight: 400;
color: #81868a;
}
.sub-header {
@@ -6,8 +6,8 @@ import { catchError, finalize, map } from 'rxjs/operators';
import { User } from 'src/app/proto/generated/auth_pb';
import {
GrantedProject,
ProjectMember,
ProjectMemberSearchResponse,
ProjectMemberView,
ProjectState,
ProjectType,
} from 'src/app/proto/generated/management_pb';
@@ -26,10 +26,13 @@ import {
})
export class ProjectContributorsComponent implements OnInit {
@Input() public project!: GrantedProject.AsObject;
@Input() public projectType!: ProjectType;
@Input() public disabled: boolean = false;
public totalResult: number = 0;
public membersSubject: BehaviorSubject<ProjectMember.AsObject[]> = new BehaviorSubject<ProjectMember.AsObject[]>([]);
public membersSubject: BehaviorSubject<ProjectMemberView.AsObject[]>
= new BehaviorSubject<ProjectMemberView.AsObject[]>([]);
public ProjectState: any = ProjectState;
private loadingSubject: BehaviorSubject<boolean> = new BehaviorSubject<boolean>(false);
@@ -39,10 +42,11 @@ export class ProjectContributorsComponent implements OnInit {
private router: Router) { }
public ngOnInit(): void {
console.log(this.project);
const promise: Promise<ProjectMemberSearchResponse> | undefined =
this.project.type === ProjectType.PROJECTTYPE_OWNED ?
this.projectType === ProjectType.PROJECTTYPE_OWNED ?
this.projectService.SearchProjectMembers(this.project.id, 100, 0) :
this.project.type === ProjectType.PROJECTTYPE_GRANTED ?
this.projectType === ProjectType.PROJECTTYPE_GRANTED ?
this.projectService.SearchProjectGrantMembers(this.project.id, this.project.grantId, 100, 0) : undefined;
if (promise) {
from(promise).pipe(
@@ -43,7 +43,7 @@
<app-card *ngIf="!grid" title="{{ 'PROJECT.APP.TITLE' | translate }}">
<card-actions class="card-actions">
<button mat-icon-button (click)="grid = true">
<mat-icon matTooltip="show grid view">grid_on</mat-icon>
<i matTooltip="show grid view" class="las la-th-large"></i>
</button>
</card-actions>
<app-project-applications [disabled]="project?.state !== ProjectState.PROJECTSTATE_ACTIVE"
@@ -81,7 +81,6 @@
</ng-template>
</div>
<metainfo class="side">
<div class="details">
<div class="row">
<span class="first">{{'PROJECT.TYPE.TITLE' | translate}}:</span>
@@ -98,7 +97,8 @@
<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" [project]="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">
@@ -82,6 +82,7 @@ export class ProjectDetailComponent implements OnInit, OnDestroy {
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 => {
@@ -93,6 +94,7 @@ export class ProjectDetailComponent implements OnInit, OnDestroy {
// this.toast.showError(error.message);
// });
} else {
this.projectType = ProjectType.PROJECTTYPE_OWNED;
this.projectService.GetProjectById(id).then(proj => {
this.project = proj.toObject();
// if (this.project.type !== ProjectType.PROJECTTYPE_SELF ||
@@ -105,6 +107,7 @@ export class ProjectDetailComponent implements OnInit, OnDestroy {
.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);
});
@@ -7,7 +7,7 @@
</app-search-user-autocomplete>
<mat-form-field class="full-width">
<mat-label>{{ 'APP.OIDC.RESPONSE' | translate }}</mat-label>
<mat-label>{{ 'PROJECT.MEMBER.ROLES' | translate }}</mat-label>
<mat-select [(ngModel)]="roleKeyList" multiple>
<mat-option *ngFor="let key of data.roleKeysList" [value]="key">
{{ key }}
@@ -87,13 +87,15 @@
<span class="mem-title">Members</span>
<ng-template appHasRole
[appHasRole]="['project.grant.member.write:' + projectId, 'project.grant.member.write']">
<button [disabled]="disabled" mat-icon-button
<button [disabled]="disabled || element?.roleKeysList?.length === 0"
matTooltip="disabled or no roles defined" mat-icon-button
(click)="addProjectGrantMember(element)">
<mat-icon>add</mat-icon>
</button>
</ng-template>
</div>
<div class="mem-description">
<div class="mem-description"
*ngIf="selectedGrantMembers && selectedGrantMembers.length > 0">
<span *ngFor="let mem of selectedGrantMembers">{{mem.firstName}} {{mem.lastName}}
{{mem.email}} |
<span *ngFor="let role of mem.rolesList">{{role}} </span></span>
@@ -6,7 +6,7 @@ import { MatPaginator } from '@angular/material/paginator';
import { MatTable } from '@angular/material/table';
import { Timestamp } from 'google-protobuf/google/protobuf/timestamp_pb';
import { tap } from 'rxjs/operators';
import { ProjectGrant, ProjectGrantMember } from 'src/app/proto/generated/management_pb';
import { ProjectGrant, ProjectMemberView } from 'src/app/proto/generated/management_pb';
import { ProjectService } from 'src/app/services/project.service';
import { ToastService } from 'src/app/services/toast.service';
@@ -36,7 +36,7 @@ export class ProjectGrantsComponent implements OnInit, AfterViewInit {
public dataSource!: ProjectGrantsDataSource;
public selection: SelectionModel<ProjectGrant.AsObject> = new SelectionModel<ProjectGrant.AsObject>(true, []);
public expandedElement: ProjectGrant.AsObject | null = null;
public selectedGrantMembers: ProjectGrantMember.AsObject[] = [];
public selectedGrantMembers: ProjectMemberView.AsObject[] = [];
/** Columns displayed in the table. Columns IDs can be added, removed, or reordered. */
public displayedColumns: string[] = ['select', 'grantedOrgName', 'grantedOrgDomain', 'creationDate', 'changeDate', 'roleNamesList'];
@@ -97,6 +97,13 @@ export class ProjectGrantsComponent implements OnInit, AfterViewInit {
width: '400px',
});
console.log({
orgId: grant.grantedOrgId,
grantId: grant.id,
projectId: grant.projectId,
roleKeysList: grant.roleKeysList,
});
dialogRef.afterClosed().subscribe((dataToAdd: ProjectGrantMembersCreateDialogExportType) => {
if (dataToAdd) {
dataToAdd.userIds.forEach(userid => {
@@ -3,23 +3,23 @@
<ng-template appHasRole [appHasRole]="['project.write']">
<button (click)="deactivateProjects(selection.selected)" @animate
matTooltip="{{'PROJECT.TABLE.DEACTIVATE' | translate}}" class="left-button" mat-icon-button>
<mat-icon svgIcon="mdi_light_off"></mat-icon>
<i class="las la-toggle-off"></i>
</button>
<button @animate (click)="reactivateProjects(selection.selected)" class="left-button"
matTooltip="{{'PROJECT.TABLE.ACTIVATE' | translate}}" mat-icon-button>
<mat-icon svgIcon="mdi_light_on"></mat-icon>
<i class="las la-toggle-on"></i>
</button>
</ng-template>
</div>
<button [disabled]="selection.selected.length > 0" (click)="changedView.emit(true)" mat-icon-button>
<mat-icon matTooltip="show list view">list</mat-icon>
<i class="show list view las la-th-list"></i>
</button>
</div>
<div class="container">
<mat-progress-bar *ngIf="loading" class="spinner" color="accent" mode="indeterminate"></mat-progress-bar>
<div class="item card" *ngFor="let item of items; index as i" (click)="selectItem(item, $event)"
[ngClass]="{ selected: selection.isSelected(item), inactive: item.state !== ProjectState.ACTIVE_PROJECT}">
[ngClass]="{ selected: selection.isSelected(item), inactive: item.state !== ProjectState.PROJECTSTATE_ACTIVE}">
<mat-icon matTooltip="select item" (click)="selection.toggle(item)" class="selection-icon">
check_circle</mat-icon>
<div class="text-part">
@@ -29,8 +29,8 @@
}}</span>
<span class="name" *ngIf="item.name">{{ item.name }}</span>
<span class="description" *ngIf="item.state">{{'PROJECT.STATE.'+item.state | translate}}</span>
<!-- <span class="description" *ngIf="item.type">{{'PROJECT.TYPE.TITLE' | translate}}:
{{'PROJECT.TYPE.'+item.type | translate}}</span> -->
<span class="description" *ngIf="item.type !== undefined">{{'PROJECT.TYPE.TITLE' | translate}}:
{{'PROJECT.TYPE.'+item.type | translate}}</span>
<span *ngIf="item.changeDate" class="created">created on
{{
dateFromTimestamp(item.creationDate) | date: 'EEE dd. MMM, HH:mm'
@@ -52,8 +52,6 @@
<button (click)="selection.toggle(item)" mat-menu-item>
{{'ACTIONS.INFO' | translate}}
</button>
<button (click)="deleteProject(item)" mat-menu-item> {{'ACTIONS.DELETE' | translate}}</button>
</ng-template>
</mat-menu>
</div>
@@ -53,6 +53,10 @@
top: -12px;
left: -12px;
user-select: none;
&:hover {
color: white;
}
}
img {
@@ -121,6 +125,10 @@
color: #81868a;
}
}
span {
margin: 2px 0;
}
}
.edit-button {
@@ -32,12 +32,12 @@ import { ToastService } from 'src/app/services/toast.service';
],
})
export class ProjectGridComponent {
@Input() items: Array<Project.AsObject> = [];
@Input() items: Array<GrantedProject.AsObject> = [];
@Output() newClicked: EventEmitter<boolean> = new EventEmitter();
@Output() changedView: EventEmitter<boolean> = new EventEmitter();
@Input() loading: boolean = false;
public selection: SelectionModel<Project.AsObject> = new SelectionModel<Project.AsObject>(true, []);
public selection: SelectionModel<GrantedProject.AsObject> = new SelectionModel<GrantedProject.AsObject>(true, []);
public selectedIndex: number = -1;
public showNewProject: boolean = false;
@@ -48,41 +48,25 @@ 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(['/project-grant', `${item.id}:${item.grantId}`]);
this.router.navigate([item.id, '/grant', `${item.grantId}`]);
} else {
this.router.navigate(['/projects', item.id]);
}
} else if (!event) {
this.router.navigate(['/projects', item.id]);
if (item.grantId) {
this.router.navigate([item.id, '/grant', `${item.grantId}`]);
} else {
this.router.navigate(['/projects', item.id]);
}
}
}
public addItem(): void {
this.newClicked.emit(true);
}
public deleteProjects(selected: Project.AsObject[]): void {
// TODO: implement service
// Promise.all([selected.map(proj => {
// return this.projectService.DeleteProject(proj.id);
// })]).then(() => {
// this.toast.showInfo('Successful deleted all projects');
// }).catch(error => {
// this.toast.showError(error.message);
// });
}
public deleteProject(proj: Project.AsObject): void {
// TODO: implement service
// this.projectService.DeleteProject(proj.id).then(() => {
// this.toast.showInfo('Successful deleted Project');
// }).catch(error => {
// this.toast.showError(error.message);
// });
}
public dateFromTimestamp(date: Timestamp.AsObject): any {
const ts: Date = new Date(date.seconds * 1000 + date.nanos / 1000);
return ts;
@@ -8,7 +8,7 @@
<div *ngIf="!grid" class="view-toggle">
<button (click)="grid = true" mat-icon-button>
<mat-icon matTooltip="show grid view">grid_on</mat-icon>
<i matTooltip="show grid view" class="las la-th-large"></i>
</button>
</div>
<div *ngIf="!grid && projectList">
@@ -83,7 +83,7 @@
<ng-container matColumnDef="type">
<th mat-header-cell *matHeaderCellDef> {{ 'PROJECT.TABLE.TYPE' | translate }} </th>
<td mat-cell *matCellDef="let project">
<span *ngIf="project.type">{{'PROJECT.TYPE.'+project.type | translate}}</span>
<span *ngIf="project.type !== undefined">{{'PROJECT.TYPE.'+project.type | translate}}</span>
</td>
</ng-container>
@@ -100,4 +100,8 @@ h1 {
max-width: 50px;
}
}
}
tr {
outline: none;
}
@@ -1,6 +1,6 @@
import { animate, animateChild, query, stagger, style, transition, trigger } from '@angular/animations';
import { SelectionModel } from '@angular/cdk/collections';
import { Component, OnInit } from '@angular/core';
import { Component, OnDestroy, OnInit } from '@angular/core';
import { PageEvent } from '@angular/material/paginator';
import { MatTableDataSource } from '@angular/material/table';
import { ActivatedRoute, Router } from '@angular/router';
@@ -35,7 +35,7 @@ import { ToastService } from 'src/app/services/toast.service';
]),
],
})
export class ProjectListComponent implements OnInit {
export class ProjectListComponent implements OnInit, OnDestroy {
public totalResult: number = 0;
public dataSource: MatTableDataSource<GrantedProject.AsObject> = new MatTableDataSource<GrantedProject.AsObject>();
public projectList: GrantedProject.AsObject[] = [];
@@ -58,6 +58,10 @@ export class ProjectListComponent implements OnInit {
this.subscription = this.route.params.subscribe(() => this.getData(10, 0));
}
public ngOnDestroy(): void {
this.subscription?.unsubscribe();
}
public isAllSelected(): boolean {
const numSelected = this.selection.selected.length;
const numRows = this.dataSource.data.length;
@@ -1,6 +1,7 @@
import { DataSource } from '@angular/cdk/collections';
import { BehaviorSubject, Observable } from 'rxjs';
import { Project, ProjectMember } from 'src/app/proto/generated/management_pb';
import { BehaviorSubject, from, Observable, of } from 'rxjs';
import { catchError, finalize, map } from 'rxjs/operators';
import { Project, ProjectMember, ProjectMemberSearchResponse, ProjectType } from 'src/app/proto/generated/management_pb';
import { ProjectService } from 'src/app/services/project.service';
/**
@@ -18,29 +19,32 @@ export class ProjectMembersDataSource extends DataSource<ProjectMember.AsObject>
super();
}
public loadMembers(project: Project.AsObject, pageIndex: number, pageSize: number, sortDirection?: string): void {
public loadMembers(project: Project.AsObject,
projectType: ProjectType,
pageIndex: number, pageSize: number, grantId?: string, sortDirection?: string): void {
const offset = pageIndex * pageSize;
this.loadingSubject.next(true);
// TODO
// const promise: Promise<ProjectMemberSearchResponse> | undefined =
// project.type === ProjectType.PROJECTTYPE_OWNED ?
// this.projectService.SearchProjectMembers(project.id, pageSize, offset) :
// project.type === ProjectType.PROJECTTYPE_GRANTED ?
// this.projectService.SearchProjectGrantMembers(project.id,
// project.grantId, pageSize, offset) : undefined;
// if (promise) {
// from(promise).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);
// });
// }
const promise: Promise<ProjectMemberSearchResponse> | undefined =
projectType === ProjectType.PROJECTTYPE_OWNED ?
this.projectService.SearchProjectMembers(project.id, pageSize, offset) :
projectType === ProjectType.PROJECTTYPE_GRANTED && grantId ?
this.projectService.SearchProjectGrantMembers(project.id,
grantId, pageSize, offset) : undefined;
if (promise) {
from(promise).pipe(
map(resp => {
this.totalResult = resp.toObject().totalResult;
console.log(this.totalResult);
return resp.toObject().resultList;
}),
catchError(() => of([])),
finalize(() => this.loadingSubject.next(false)),
).subscribe(members => {
this.membersSubject.next(members);
});
}
}
@@ -1,11 +1,10 @@
import { SelectionModel } from '@angular/cdk/collections';
import { AfterViewInit, Component, ViewChild } from '@angular/core';
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 { Project, ProjectMember } from 'src/app/proto/generated/management_pb';
import { Project, ProjectMember, ProjectType } from 'src/app/proto/generated/management_pb';
import { ProjectService } from 'src/app/services/project.service';
import { ToastService } from 'src/app/services/toast.service';
@@ -18,6 +17,7 @@ import { ProjectMembersDataSource } from './project-members-datasource';
})
export class ProjectMembersComponent implements AfterViewInit {
public project!: Project.AsObject;
public projectType: ProjectType = ProjectType.PROJECTTYPE_OWNED;
public disabled: boolean = false;
@ViewChild(MatPaginator) public paginator!: MatPaginator;
@ViewChild(MatTable) public table!: MatTable<ProjectMember.AsObject>;
@@ -28,14 +28,14 @@ export class ProjectMembersComponent implements AfterViewInit {
public displayedColumns: string[] = ['select', 'firstname', 'lastname', 'username', 'email', 'roles'];
constructor(private projectService: ProjectService,
private dialog: MatDialog,
private toast: ToastService,
private route: ActivatedRoute) {
this.route.params.subscribe(params => {
this.projectService.GetProjectById(params.projectid).then(project => {
this.project = project.toObject();
console.log(this.project);
this.dataSource = new ProjectMembersDataSource(this.projectService);
this.dataSource.loadMembers(this.project, 0, 25, 'asc');
this.dataSource.loadMembers(this.project, this.projectType, 0, 25, 'asc');
});
});
}
@@ -52,6 +52,7 @@ export class ProjectMembersComponent implements AfterViewInit {
private loadMembersPage(): void {
this.dataSource.loadMembers(
this.project,
this.projectType,
this.paginator.pageIndex,
this.paginator.pageSize,
);