mirror of
https://github.com/zitadel/zitadel.git
synced 2025-03-01 00:17:24 +00:00
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/grpc@1.24.2...grpc@1.24.3) Signed-off-by: dependabot[bot] <support@github.com> 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] <support@github.com> 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] <support@github.com> 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:
parent
e0fb19b4e9
commit
2d369fbcd3
1952
console/package-lock.json
generated
1952
console/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@ -14,53 +14,53 @@
|
||||
},
|
||||
"private": true,
|
||||
"dependencies": {
|
||||
"@angular/animations": "~9.1.0",
|
||||
"@angular/cdk": "~9.0.1",
|
||||
"@angular/common": "~9.1.0",
|
||||
"@angular/compiler": "~9.1.0",
|
||||
"@angular/core": "~9.1.0",
|
||||
"@angular/forms": "~9.1.0",
|
||||
"@angular/material": "^9.0.1",
|
||||
"@angular/platform-browser": "~9.1.0",
|
||||
"@angular/platform-browser-dynamic": "~9.1.0",
|
||||
"@angular/router": "~9.1.0",
|
||||
"@angular/service-worker": "~9.1.0",
|
||||
"@angular/animations": "~9.1.10",
|
||||
"@angular/cdk": "~9.2.4",
|
||||
"@angular/common": "~9.1.10",
|
||||
"@angular/compiler": "~9.1.10",
|
||||
"@angular/core": "~9.1.10",
|
||||
"@angular/forms": "~9.1.10",
|
||||
"@angular/material": "^9.2.4",
|
||||
"@angular/platform-browser": "~9.1.10",
|
||||
"@angular/platform-browser-dynamic": "~9.1.10",
|
||||
"@angular/router": "~9.1.10",
|
||||
"@angular/service-worker": "~9.1.10",
|
||||
"@ngx-translate/core": "^12.1.2",
|
||||
"@ngx-translate/http-loader": "^4.0.0",
|
||||
"@types/google-protobuf": "^3.7.2",
|
||||
"@types/uuid": "^8.0.0",
|
||||
"angular-oauth2-oidc": "^8.0.4",
|
||||
"angularx-qrcode": "^2.1.0",
|
||||
"angular-oauth2-oidc": "^9.2.2",
|
||||
"angularx-qrcode": "^2.3.4",
|
||||
"cors": "^2.8.5",
|
||||
"google-proto-files": "^1.1.1",
|
||||
"google-protobuf": "^3.12.0",
|
||||
"grpc": "^1.24.2",
|
||||
"google-proto-files": "^2.1.0",
|
||||
"google-protobuf": "^3.12.2",
|
||||
"grpc": "^1.24.3",
|
||||
"grpc-web": "^1.1.0",
|
||||
"hammerjs": "^2.0.8",
|
||||
"moment": "^2.24.0",
|
||||
"moment": "^2.26.0",
|
||||
"ngx-moment": "^3.5.0",
|
||||
"prettier-stylelint": "^0.4.2",
|
||||
"rxjs": "~6.5.5",
|
||||
"ts-protoc-gen": "^0.12.0",
|
||||
"tslib": "^1.13.0",
|
||||
"uuid": "^7.0.1",
|
||||
"tslib": "^2.0.0",
|
||||
"uuid": "^8.1.0",
|
||||
"zone.js": "~0.10.3"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@angular-devkit/build-angular": "~0.901.7",
|
||||
"@angular/cli": "~9.1.0",
|
||||
"@angular/compiler-cli": "~9.1.0",
|
||||
"@angular/language-service": "~9.1.9",
|
||||
"@angular/cli": "~9.1.7",
|
||||
"@angular/compiler-cli": "~9.1.10",
|
||||
"@angular/language-service": "~9.1.10",
|
||||
"@types/jasmine": "~3.5.10",
|
||||
"@types/jasminewd2": "~2.0.3",
|
||||
"@types/node": "^14.0.11",
|
||||
"codelyzer": "^5.1.2",
|
||||
"@types/node": "^14.0.13",
|
||||
"codelyzer": "^5.2.2",
|
||||
"jasmine-core": "~3.5.0",
|
||||
"karma": "^5.0.9",
|
||||
"jasmine-spec-reporter": "~5.0.2",
|
||||
"karma": "^5.0.9",
|
||||
"karma-chrome-launcher": "~3.1.0",
|
||||
"karma-coverage-istanbul-reporter": "~3.0.2",
|
||||
"karma-jasmine": "~3.1.1",
|
||||
"karma-coverage-istanbul-reporter": "~3.0.3",
|
||||
"karma-jasmine": "^3.3.1",
|
||||
"karma-jasmine-html-reporter": "^1.5.4",
|
||||
"prettier": "^2.0.5",
|
||||
"protractor": "^7.0.0",
|
||||
|
@ -39,10 +39,11 @@
|
||||
<div (clickOutside)="closeAccountCard()" class="icon-container">
|
||||
<div class="avatar-wrapper dontcloseonclick" (click)="showAccount = !showAccount">
|
||||
<div class="avatar-circle dontcloseonclick" [ngClass]="{'active': showAccount}">
|
||||
<img class="avatar dontcloseonclick" *ngIf="componentCssClass == 'dark-theme'; else lighttheme"
|
||||
src="../assets/images/account-circle-outline.png" />
|
||||
<i *ngIf="componentCssClass == 'dark-theme'; else lighttheme"
|
||||
class="avatar dontcloseonclick las la-user-circle"></i>
|
||||
|
||||
<ng-template #lighttheme>
|
||||
<img class="avatar dontcloseonclick" src="../assets/images/account-circle-outline-dark.png" />
|
||||
<i class="avatar las la-user-circle"></i>
|
||||
</ng-template>
|
||||
</div>
|
||||
</div>
|
||||
@ -58,31 +59,31 @@
|
||||
<div class="list">
|
||||
<a *ngIf="authService.authenticationChanged | async" class="nav-item" [routerLinkActive]="['active']"
|
||||
[routerLinkActiveOptions]="{ exact: true }" [routerLink]="['/user/me']">
|
||||
<mat-icon class="icon" svgIcon="mdi_account_circle_outline"></mat-icon>
|
||||
<i class="icon las la-user-circle"></i>
|
||||
<span class="label">{{ 'MENU.PERSONAL_INFO' | translate }}</span>
|
||||
</a>
|
||||
|
||||
<a *ngIf="showOrgSection && org?.id" class="nav-item" [routerLinkActive]="['active']"
|
||||
[routerLink]="[ '/orgs', org.id]">
|
||||
<mat-icon class="icon">business</mat-icon>
|
||||
<i class="icon las la-archway"></i>
|
||||
<span class="label">{{org?.name ? org.name : 'MENU.ORGANIZATION' | translate}}</span>
|
||||
</a>
|
||||
|
||||
<a *ngIf="showProjectSection" class="nav-item" [routerLinkActive]="['active']"
|
||||
[routerLink]="[ '/projects']">
|
||||
<mat-icon class="icon">folder_open</mat-icon>
|
||||
<i class="icon las la-layer-group"></i>
|
||||
<span class="label">{{ 'MENU.PROJECT' | translate }}</span>
|
||||
</a>
|
||||
|
||||
<a *ngIf="showUserSection" class="nav-item" [routerLinkActive]="['active']" [routerLink]="[ '/users']"
|
||||
[routerLinkActiveOptions]="{ exact: true }">
|
||||
<mat-icon class="icon">people_outline</mat-icon>
|
||||
<i class="icon las la-users"></i>
|
||||
<span class="label">{{ 'MENU.USER' | translate }}</span>
|
||||
</a>
|
||||
|
||||
<span class="fill-space"></span>
|
||||
<a class="nav-item" (click)="authService.signout()">
|
||||
<mat-icon class="icon" svgIcon="mdi_logout"></mat-icon>
|
||||
<i class="icon las la-sign-out-alt"></i>
|
||||
<span class="label">{{ 'MENU.LOGOUT' | translate }}</span>
|
||||
</a>
|
||||
|
||||
|
@ -54,33 +54,28 @@
|
||||
.avatar-wrapper {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
color: white;
|
||||
|
||||
.avatar-circle {
|
||||
height: 35px;
|
||||
width: 35px;
|
||||
height: 30px;
|
||||
width: 30px;
|
||||
font-size: 30px;
|
||||
background-color: transparent;
|
||||
border-radius: 50%;
|
||||
animation: background-color .2s ease-in;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
margin-left: .5rem;
|
||||
|
||||
.avatar {
|
||||
display: block;
|
||||
margin: auto auto;
|
||||
height: 30px;
|
||||
width: 30px;
|
||||
line-height: 35px;
|
||||
line-height: 30px;
|
||||
font-size: 30px;
|
||||
border-radius: 50%;
|
||||
text-align: center;
|
||||
fill: white;
|
||||
|
||||
* {
|
||||
fill: white;
|
||||
color: white;
|
||||
}
|
||||
}
|
||||
|
||||
&:hover, &.active {
|
||||
|
@ -170,11 +170,6 @@ export class AppComponent implements OnDestroy {
|
||||
this.domSanitizer.bypassSecurityTrustResourceUrl('assets/mdi/account-cancel-outline.svg'),
|
||||
);
|
||||
|
||||
this.matIconRegistry.addSvgIcon(
|
||||
'mdi_logout',
|
||||
this.domSanitizer.bypassSecurityTrustResourceUrl('assets/mdi/logout.svg'),
|
||||
);
|
||||
|
||||
this.matIconRegistry.addSvgIcon(
|
||||
'mdi_light_on',
|
||||
this.domSanitizer.bypassSecurityTrustResourceUrl('assets/mdi/lightbulb-on-outline.svg'),
|
||||
|
@ -19,7 +19,7 @@
|
||||
margin: 0;
|
||||
font-weight: 400;
|
||||
font-family: 'Rubik';
|
||||
font-size: 1.2rem;
|
||||
font-size: 18px;
|
||||
// margin-top: .3rem;
|
||||
}
|
||||
|
||||
|
@ -10,4 +10,5 @@
|
||||
<div class="sp-wrapper">
|
||||
<mat-spinner *ngIf="loading | async" diameter="25"></mat-spinner>
|
||||
</div>
|
||||
<span class="err-container" *ngIf="errorMessage">{{errorMessage}}</span>
|
||||
</div>
|
@ -2,7 +2,6 @@
|
||||
display: block;
|
||||
margin-bottom: 1rem;
|
||||
font-weight: 400;
|
||||
color: #81868a;
|
||||
margin-top: 1rem;
|
||||
}
|
||||
|
||||
@ -37,4 +36,9 @@
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.err-container {
|
||||
font-size: 14px;
|
||||
color: rgb(201,51,71);
|
||||
}
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
import { Component, Input, OnInit } from '@angular/core';
|
||||
import { Timestamp } from 'google-protobuf/google/protobuf/timestamp_pb';
|
||||
import { BehaviorSubject, from, Observable } from 'rxjs';
|
||||
import { scan, take, tap } from 'rxjs/operators';
|
||||
import { BehaviorSubject, from, Observable, of } from 'rxjs';
|
||||
import { catchError, scan, take, tap } from 'rxjs/operators';
|
||||
import { Change, Changes } from 'src/app/proto/generated/management_pb';
|
||||
import { MgmtUserService } from 'src/app/services/mgmt-user.service';
|
||||
|
||||
@ -19,6 +19,7 @@ export enum ChangeType {
|
||||
export class ChangesComponent implements OnInit {
|
||||
@Input() public changeType: ChangeType = ChangeType.USER;
|
||||
@Input() public id: string = '';
|
||||
public errorMessage: string = '';
|
||||
|
||||
// Source data
|
||||
private _done: BehaviorSubject<any> = new BehaviorSubject(false);
|
||||
@ -50,7 +51,6 @@ export class ChangesComponent implements OnInit {
|
||||
break;
|
||||
case ChangeType.ORG: first = this.mgmtUserService.OrgChanges(this.id, 10, 0);
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
this.mapAndUpdate(first);
|
||||
@ -100,6 +100,7 @@ export class ChangesComponent implements OnInit {
|
||||
// Map snapshot with doc ref (needed for cursor)
|
||||
return from(col).pipe(
|
||||
tap((res: Changes) => {
|
||||
console.log('more cahnge');
|
||||
let values = res.toObject().changesList;
|
||||
// If prepending, reverse the batch order
|
||||
values = false ? values.reverse() : values;
|
||||
@ -114,7 +115,14 @@ export class ChangesComponent implements OnInit {
|
||||
this._done.next(true);
|
||||
}
|
||||
}),
|
||||
take(1)).subscribe();
|
||||
catchError(err => {
|
||||
console.error(err);
|
||||
this._loading.next(false);
|
||||
this.errorMessage = err.message;
|
||||
return of([]);
|
||||
}),
|
||||
take(1),
|
||||
).subscribe();
|
||||
}
|
||||
|
||||
public dateFromTimestamp(date: Timestamp.AsObject): any {
|
||||
|
@ -31,6 +31,7 @@ export class ProjectRolesDataSource extends DataSource<ProjectRole.AsObject> {
|
||||
catchError(() => of([])),
|
||||
finalize(() => this.loadingSubject.next(false)),
|
||||
).subscribe(roles => {
|
||||
console.log(roles);
|
||||
this.rolesSubject.next(roles);
|
||||
});
|
||||
}
|
||||
|
@ -44,9 +44,9 @@
|
||||
</td>
|
||||
</ng-container>
|
||||
|
||||
<ng-container matColumnDef="name">
|
||||
<th mat-header-cell *matHeaderCellDef> {{ 'PROJECT.ROLE.NAME' | translate }} </th>
|
||||
<td mat-cell *matCellDef="let role"> {{role.name}} </td>
|
||||
<ng-container matColumnDef="key">
|
||||
<th mat-header-cell *matHeaderCellDef> {{ 'PROJECT.ROLE.KEY' | translate }} </th>
|
||||
<td mat-cell *matCellDef="let role"> {{role.key}} </td>
|
||||
</ng-container>
|
||||
|
||||
<ng-container matColumnDef="displayname">
|
||||
@ -63,6 +63,15 @@
|
||||
</td>
|
||||
</ng-container>
|
||||
|
||||
<ng-container matColumnDef="creationDate">
|
||||
<th mat-header-cell *matHeaderCellDef> {{ 'PROJECT.ROLE.CREATIONDATE' | translate }} </th>
|
||||
<td mat-cell *matCellDef="let role">
|
||||
<span>{{dateFromTimestamp(role.creationDate) | date: 'dd. MMM, HH:mm' }}</span>
|
||||
</td>
|
||||
</ng-container>
|
||||
|
||||
|
||||
|
||||
<tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
|
||||
<tr mat-row *matRowDef="let row; columns: displayedColumns;"></tr>
|
||||
</table>
|
||||
|
@ -2,6 +2,7 @@ import { SelectionModel } from '@angular/cdk/collections';
|
||||
import { AfterViewInit, Component, EventEmitter, Input, OnInit, Output, ViewChild } from '@angular/core';
|
||||
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 { ProjectRole } from 'src/app/proto/generated/management_pb';
|
||||
import { ProjectService } from 'src/app/services/project.service';
|
||||
@ -26,7 +27,7 @@ export class ProjectRolesComponent implements AfterViewInit, OnInit {
|
||||
@Output() public changedSelection: EventEmitter<Array<ProjectRole.AsObject>> = new EventEmitter();
|
||||
|
||||
/** Columns displayed in the table. Columns IDs can be added, removed, or reordered. */
|
||||
public displayedColumns: string[] = ['select', 'name', 'displayname', 'group'];
|
||||
public displayedColumns: string[] = ['select', 'key', 'displayname', 'group', 'creationDate'];
|
||||
|
||||
constructor(private projectService: ProjectService, private toast: ToastService) { }
|
||||
|
||||
@ -107,4 +108,9 @@ export class ProjectRolesComponent implements AfterViewInit, OnInit {
|
||||
this.toast.showError(data.message);
|
||||
});
|
||||
}
|
||||
|
||||
public dateFromTimestamp(date: Timestamp.AsObject): any {
|
||||
const ts: Date = new Date(date.seconds * 1000 + date.nanos / 1000);
|
||||
return ts;
|
||||
}
|
||||
}
|
||||
|
@ -12,7 +12,6 @@ import {
|
||||
SearchMethod,
|
||||
} from 'src/app/proto/generated/management_pb';
|
||||
import { ProjectService } from 'src/app/services/project.service';
|
||||
import { ToastService } from 'src/app/services/toast.service';
|
||||
|
||||
@Component({
|
||||
selector: 'app-search-project-autocomplete',
|
||||
@ -33,7 +32,7 @@ export class SearchProjectAutocompleteComponent {
|
||||
@ViewChild('auto') public matAutocomplete!: MatAutocomplete;
|
||||
@Input() public singleOutput: boolean = false;
|
||||
@Output() public selectionChanged: EventEmitter<Project.AsObject[] | Project.AsObject> = new EventEmitter();
|
||||
constructor(private projectService: ProjectService, private toast: ToastService) {
|
||||
constructor(private projectService: ProjectService) {
|
||||
this.myControl.valueChanges
|
||||
.pipe(
|
||||
debounceTime(200),
|
||||
|
@ -107,6 +107,7 @@ export class AppCreateComponent implements OnInit, OnDestroy {
|
||||
this.showSavedDialog(data.toObject());
|
||||
})
|
||||
.catch(data => {
|
||||
console.error(data);
|
||||
this.toast.showError(data.message);
|
||||
});
|
||||
}
|
||||
|
@ -8,16 +8,18 @@
|
||||
<p class="desc">{{ 'APP.PAGES.DESCRIPTION' | translate }}</p>
|
||||
</div>
|
||||
|
||||
<span *ngIf="errorMessage" class="err-container">{{errorMessage}}</span>
|
||||
|
||||
<app-card title="{{ 'APP.PAGES.DETAIL.TITLE' | translate }}" *ngIf="app">
|
||||
<form [formGroup]="appNameForm" (ngSubmit)="saveOIDCApp()">
|
||||
<div class="content">
|
||||
<mat-button-toggle-group formControlName="state" class="toggle" (change)="changeState($event)">
|
||||
<mat-button-toggle [value]="AppState.APPSTATE_INACTIVE" matTooltip="Deactivate Org">
|
||||
<mat-icon svgIcon="mdi_light_off"></mat-icon>
|
||||
<i class="las la-toggle-off"></i>
|
||||
{{'APP.PAGES.DETAIL.STATE.'+AppState.APPSTATE_INACTIVE | translate}}
|
||||
</mat-button-toggle>
|
||||
<mat-button-toggle [value]="AppState.APPSTATE_ACTIVE" matTooltip="Activate Org">
|
||||
<mat-icon svgIcon="mdi_light_on"></mat-icon>
|
||||
<i class="las la-toggle-on"></i>
|
||||
{{'APP.PAGES.DETAIL.STATE.'+AppState.APPSTATE_ACTIVE | translate}}
|
||||
</mat-button-toggle>
|
||||
</mat-button-toggle-group>
|
||||
|
@ -23,6 +23,11 @@
|
||||
}
|
||||
}
|
||||
|
||||
.err-container {
|
||||
color: rgb(201,51,71);
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.card-actions {
|
||||
button {
|
||||
border-radius: .5rem;
|
||||
@ -57,6 +62,10 @@
|
||||
margin-bottom: 1rem;
|
||||
margin-right: 1rem;
|
||||
border-radius: .5rem;
|
||||
|
||||
i {
|
||||
margin-right: 1rem;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -33,6 +33,7 @@ enum RedirectType {
|
||||
styleUrls: ['./app-detail.component.scss'],
|
||||
})
|
||||
export class AppDetailComponent implements OnInit, OnDestroy {
|
||||
public errorMessage: string = '';
|
||||
public selectable: boolean = false;
|
||||
public removable: boolean = true;
|
||||
public addOnBlur: boolean = true;
|
||||
@ -103,25 +104,31 @@ export class AppDetailComponent implements OnInit, OnDestroy {
|
||||
|
||||
private async getData({ projectid, id }: Params): Promise<void> {
|
||||
this.projectId = projectid;
|
||||
this.app = (await this.projectService.GetApplicationById(projectid, id)).toObject();
|
||||
this.appNameForm.patchValue(this.app);
|
||||
if (this.app.state !== AppState.APPSTATE_ACTIVE) {
|
||||
this.appNameForm.controls['name'].disable();
|
||||
this.appForm.disable();
|
||||
} else {
|
||||
this.appNameForm.controls['name'].enable();
|
||||
this.appForm.enable();
|
||||
this.clientId?.disable();
|
||||
}
|
||||
if (this.app.oidcConfig?.redirectUrisList) {
|
||||
this.redirectUrisList = this.app.oidcConfig.redirectUrisList;
|
||||
}
|
||||
if (this.app.oidcConfig?.postLogoutRedirectUrisList) {
|
||||
this.postLogoutRedirectUrisList = this.app.oidcConfig.postLogoutRedirectUrisList;
|
||||
}
|
||||
if (this.app.oidcConfig) {
|
||||
this.appForm.patchValue(this.app.oidcConfig);
|
||||
}
|
||||
this.projectService.GetApplicationById(projectid, id).then(app => {
|
||||
this.app = app.toObject();
|
||||
this.appNameForm.patchValue(this.app);
|
||||
if (this.app.state !== AppState.APPSTATE_ACTIVE) {
|
||||
this.appNameForm.controls['name'].disable();
|
||||
this.appForm.disable();
|
||||
} else {
|
||||
this.appNameForm.controls['name'].enable();
|
||||
this.appForm.enable();
|
||||
this.clientId?.disable();
|
||||
}
|
||||
if (this.app.oidcConfig?.redirectUrisList) {
|
||||
this.redirectUrisList = this.app.oidcConfig.redirectUrisList;
|
||||
}
|
||||
if (this.app.oidcConfig?.postLogoutRedirectUrisList) {
|
||||
this.postLogoutRedirectUrisList = this.app.oidcConfig.postLogoutRedirectUrisList;
|
||||
}
|
||||
if (this.app.oidcConfig) {
|
||||
this.appForm.patchValue(this.app.oidcConfig);
|
||||
}
|
||||
}).catch(error => {
|
||||
console.error(error);
|
||||
this.toast.showError(error.message);
|
||||
this.errorMessage = error.message;
|
||||
});
|
||||
}
|
||||
|
||||
public changeState(event: MatButtonToggleChange): void {
|
||||
|
@ -13,22 +13,20 @@
|
||||
<div class="container">
|
||||
<div matTooltip="{{'ORG.PAGES.SELECTORGTOOLTIP' | translate}}" class="item card"
|
||||
*ngFor="let org of orgList; index as i" (click)="selectOrg(org, $event)"
|
||||
[ngClass]="{ selected: selection.isSelected(org) }">
|
||||
[ngClass]="{ selected: selection.isSelected(org),active: activeOrg?.id === org?.id }">
|
||||
<!-- <mat-icon matTooltip="select org" (click)="selection.toggle(org)" class="selection-icon">
|
||||
check_circle</mat-icon> -->
|
||||
<div class="text-part">
|
||||
<span *ngIf="org?.changeDate" class="top">last modified on
|
||||
<!-- <span *ngIf="org?.changeDate" class="top">last modified on
|
||||
{{
|
||||
dateFromTimestamp(org.changeDate) | date: 'EEE dd. MMM, HH:mm'
|
||||
}}</span>
|
||||
}}</span> -->
|
||||
<span class="description">{{org.id}}</span>
|
||||
|
||||
<span class="name" *ngIf="org.name">{{ org.name }}</span>
|
||||
<span class="name" *ngIf="!org.name">No Name</span>
|
||||
|
||||
<span class="description">{{org.id}}</span>
|
||||
<span class="fill-space"></span>
|
||||
<div class="icons">
|
||||
<div class="current" *ngIf="activeOrg?.id === org?.id">
|
||||
<span>{{'ORG.PAGES.ACTIVE' | translate}}</span></div>
|
||||
</div>
|
||||
</div>
|
||||
<button [matMenuTriggerFor]="editMenu" class="edit-button" mat-icon-button>
|
||||
@ -37,12 +35,12 @@
|
||||
|
||||
<mat-menu #editMenu="matMenu">
|
||||
<ng-template matMenuContent>
|
||||
<button (click)="selectOrg(org)" mat-menu-item>
|
||||
<button (click)="routeToOrg(org)" mat-menu-item>
|
||||
{{'ACTIONS.VIEW' | translate}}
|
||||
</button>
|
||||
<button (click)="selection.toggle(org)" mat-menu-item>
|
||||
<!-- <button (click)="selection.toggle(org)" mat-menu-item>
|
||||
{{'ACTIONS.INFO' | translate}}
|
||||
</button>
|
||||
</button> -->
|
||||
</ng-template>
|
||||
</mat-menu>
|
||||
</div>
|
||||
|
@ -52,6 +52,10 @@ h1 {
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
&.active {
|
||||
border-color: #db4c69;
|
||||
}
|
||||
|
||||
.selection-icon {
|
||||
opacity: 0;
|
||||
position: absolute;
|
||||
@ -88,6 +92,7 @@ h1 {
|
||||
|
||||
.description {
|
||||
font-size: 0.8rem;
|
||||
margin-top: .5rem;
|
||||
}
|
||||
|
||||
.created {
|
||||
@ -120,6 +125,7 @@ h1 {
|
||||
|
||||
.current {
|
||||
height: 10px;
|
||||
font-size: 14px;
|
||||
width: 10px;
|
||||
border-radius: 50%;
|
||||
background-color: rgb(144,212,210);
|
||||
|
@ -42,10 +42,14 @@ export class OrgGridComponent {
|
||||
public selectOrg(item: Org.AsObject, event?: any): void {
|
||||
if (event && !event.target.classList.contains('mat-icon')) {
|
||||
this.authService.setActiveOrg(item);
|
||||
this.router.navigate(['/orgs', item.id]);
|
||||
this.routeToOrg(item);
|
||||
}
|
||||
}
|
||||
|
||||
public routeToOrg(item: Org.AsObject): void {
|
||||
this.router.navigate(['/orgs', item.id]);
|
||||
}
|
||||
|
||||
public dateFromTimestamp(date: Timestamp.AsObject): any {
|
||||
const ts: Date = new Date(date.seconds * 1000 + date.nanos / 1000);
|
||||
return ts;
|
||||
|
@ -31,6 +31,7 @@ export class OrgMembersDataSource extends DataSource<OrgMember.AsObject> {
|
||||
catchError(() => of([])),
|
||||
finalize(() => this.loadingSubject.next(false)),
|
||||
).subscribe(members => {
|
||||
console.log(members);
|
||||
this.membersSubject.next(members);
|
||||
});
|
||||
}
|
||||
|
@ -3,7 +3,7 @@
|
||||
<p class="top-desc">{{'ORG.POLICY.DESCRIPTION' | translate}}</p>
|
||||
|
||||
<div class="row-lyt">
|
||||
<div class="p-item card">
|
||||
<!-- <div class="p-item card">
|
||||
<div class="avatar">
|
||||
<mat-icon svgIcon="mdi_lock_reset"></mat-icon>
|
||||
</div>
|
||||
@ -38,7 +38,7 @@
|
||||
<button [disabled]="!agePolicy" [routerLink]="[ 'policy', PolicyComponentType.AGE ]"
|
||||
mat-raised-button>{{'ORG.POLICY.BTN_EDIT' | translate}}</button>
|
||||
</div>
|
||||
</div>
|
||||
</div> -->
|
||||
<div class="p-item card">
|
||||
<div class="avatar">
|
||||
<mat-icon svgIcon="mdi_textbox_password"></mat-icon>
|
||||
@ -70,7 +70,7 @@
|
||||
mat-raised-button>{{'ORG.POLICY.BTN_EDIT' | translate}}</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="p-item card">
|
||||
<!-- <div class="p-item card">
|
||||
<div class="avatar">
|
||||
<mat-icon svgIcon="mdi_lock_question"></mat-icon>
|
||||
</div>
|
||||
@ -98,5 +98,5 @@
|
||||
<button [disabled]="!lockoutPolicy" [routerLink]="[ 'policy', PolicyComponentType.LOCKOUT ]"
|
||||
mat-raised-button>{{'ORG.POLICY.BTN_EDIT' | translate}}</button>
|
||||
</div>
|
||||
</div>
|
||||
</div> -->
|
||||
</div>
|
@ -32,8 +32,8 @@ export class PolicyGridComponent implements OnInit {
|
||||
}
|
||||
|
||||
private getData(): void {
|
||||
this.orgService.GetPasswordLockoutPolicy().then(data => this.lockoutPolicy = data.toObject()).catch(error => { });
|
||||
this.orgService.GetPasswordAgePolicy().then(data => this.agePolicy = data.toObject()).catch(error => { });
|
||||
// this.orgService.GetPasswordLockoutPolicy().then(data => this.lockoutPolicy = data.toObject()).catch(error => { });
|
||||
// this.orgService.GetPasswordAgePolicy().then(data => this.agePolicy = data.toObject()).catch(error => { });
|
||||
this.orgService.GetPasswordComplexityPolicy().then(data => this.complexityPolicy = data.toObject())
|
||||
.catch(error => { });
|
||||
}
|
||||
|
@ -15,6 +15,11 @@
|
||||
<form @list (ngSubmit)="addRole()">
|
||||
<div @animate *ngFor="let formGroup of formArray.controls; index as i" class="content">
|
||||
<ng-container [formGroup]="formGroup">
|
||||
<mat-form-field appearance="outline" class="formfield">
|
||||
<mat-label>{{ 'PROJECT.ROLE.KEY' | translate }}</mat-label>
|
||||
<input matInput formControlName="key" />
|
||||
<!-- <mat-error *ngIf="name?.errors?.required">{{'ERRORS.REQUIRED' | translate}}</mat-error> -->
|
||||
</mat-form-field>
|
||||
<mat-form-field appearance="outline" class="formfield">
|
||||
<mat-label>{{ 'PROJECT.ROLE.NAME' | translate }}</mat-label>
|
||||
<input matInput formControlName="name" />
|
||||
|
@ -50,6 +50,7 @@ export class ProjectRoleCreateComponent implements OnInit, OnDestroy {
|
||||
private fb: FormBuilder,
|
||||
) {
|
||||
this.formGroup = new FormGroup({
|
||||
key: new FormControl(''),
|
||||
name: new FormControl(''),
|
||||
displayName: new FormControl(''),
|
||||
group: new FormControl('', [Validators.required]),
|
||||
|
@ -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,
|
||||
);
|
||||
|
@ -15,6 +15,7 @@ h1 {
|
||||
.col {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
.desc {
|
||||
font-size: .8rem;
|
||||
color: #81868a;
|
||||
@ -68,3 +69,7 @@ h1 {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
tr {
|
||||
outline: none;
|
||||
}
|
||||
|
@ -87,6 +87,7 @@
|
||||
},
|
||||
"DATA": {
|
||||
"STATE": "Status",
|
||||
"STATE0": "unbekannt",
|
||||
"STATE1": "aktiv",
|
||||
"STATE2": "inaktiv",
|
||||
"STATE3": "gelöscht",
|
||||
@ -325,6 +326,7 @@
|
||||
"NAME": "Name"
|
||||
},
|
||||
"ROLE": {
|
||||
"KEY":"Key",
|
||||
"TITLE": "Roles",
|
||||
"DESCRIPTION":"Definieren Sie Rollen, die Sie bei der Erstellung eines Projekt-Grants vergeben können",
|
||||
"NAME": "Name",
|
||||
@ -333,7 +335,8 @@
|
||||
"ACTIONS": "Aktion",
|
||||
"ADDTITLE": "Rolle erstellen",
|
||||
"ADDDESCRIPTION": "Geben Sie die Daten für die zu erstellende Rolle ein!",
|
||||
"DELETE":"Rolle löschen"
|
||||
"DELETE":"Rolle löschen",
|
||||
"CREATIONDATE":"Erstelldatum"
|
||||
},
|
||||
"TABLE": {
|
||||
"TOTAL": "Einträge gesamt:",
|
||||
@ -344,7 +347,7 @@
|
||||
"ORGNAME":"Org Name",
|
||||
"ORGDOMAIN":"Org Domain",
|
||||
"STATE":"Status",
|
||||
"Type":"Typ",
|
||||
"TYPE":"Typ",
|
||||
"CREATIONDATE":"Erstelldatum",
|
||||
"CHANGEDATE":"Letzte Änderung"
|
||||
}
|
||||
|
@ -87,6 +87,7 @@
|
||||
},
|
||||
"DATA": {
|
||||
"STATE": "Status",
|
||||
"STATE0": "unknown",
|
||||
"STATE1": "active",
|
||||
"STATE2": "inactive",
|
||||
"STATE3": "deleted",
|
||||
@ -325,6 +326,7 @@
|
||||
"NAME": "Name"
|
||||
},
|
||||
"ROLE": {
|
||||
"KEY":"Key",
|
||||
"TITLE": "Roles",
|
||||
"DESCRIPTION":"Define some roles which can be used to create project-grants",
|
||||
"NAME": "Name",
|
||||
@ -333,7 +335,8 @@
|
||||
"ACTIONS": "Actions",
|
||||
"ADDTITLE": "Create role",
|
||||
"ADDDESCRIPTION": "Enter the data for the new role!",
|
||||
"DELETE":"Delete Role"
|
||||
"DELETE":"Delete Role",
|
||||
"CREATIONDATE":"Created"
|
||||
},
|
||||
"TABLE": {
|
||||
"TOTAL": "Entries total:",
|
||||
@ -344,7 +347,7 @@
|
||||
"ORGNAME":"Org Name",
|
||||
"ORGDOMAIN":"Org Domain",
|
||||
"STATE":"Status",
|
||||
"Type":"Type",
|
||||
"TYPE":"Type",
|
||||
"CREATIONDATE":"Created At",
|
||||
"CHANGEDATE":"Last Modified"
|
||||
}
|
||||
|
@ -1 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="24" height="24" viewBox="0 0 24 24"><path d="M12,2A10,10 0 0,0 2,12A10,10 0 0,0 12,22A10,10 0 0,0 22,12A10,10 0 0,0 12,2M7.07,18.28C7.5,17.38 10.12,16.5 12,16.5C13.88,16.5 16.5,17.38 16.93,18.28C15.57,19.36 13.86,20 12,20C10.14,20 8.43,19.36 7.07,18.28M18.36,16.83C16.93,15.09 13.46,14.5 12,14.5C10.54,14.5 7.07,15.09 5.64,16.83C4.62,15.5 4,13.82 4,12C4,7.59 7.59,4 12,4C16.41,4 20,7.59 20,12C20,13.82 19.38,15.5 18.36,16.83M12,6C10.06,6 8.5,7.56 8.5,9.5C8.5,11.44 10.06,13 12,13C13.94,13 15.5,11.44 15.5,9.5C15.5,7.56 13.94,6 12,6M12,11A1.5,1.5 0 0,1 10.5,9.5A1.5,1.5 0 0,1 12,8A1.5,1.5 0 0,1 13.5,9.5A1.5,1.5 0 0,1 12,11Z" /></svg>
|
Before Width: | Height: | Size: 873 B |
@ -1 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="24" height="24" viewBox="0 0 24 24"><path d="M16,17V14H9V10H16V7L21,12L16,17M14,2A2,2 0 0,1 16,4V6H14V4H5V20H14V18H16V20A2,2 0 0,1 14,22H5A2,2 0 0,1 3,20V4A2,2 0 0,1 5,2H14Z" /></svg>
|
Before Width: | Height: | Size: 423 B |
@ -11,6 +11,8 @@
|
||||
<link href="https://fonts.googleapis.com/css?family=Roboto:300,400,500&display=swap" rel="stylesheet">
|
||||
<link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">
|
||||
<link href="https://fonts.googleapis.com/css?family=Rubik&display=swap" rel="stylesheet">
|
||||
<link rel="stylesheet"
|
||||
href="https://maxst.icons8.com/vue-static/landings/line-awesome/line-awesome/1.3.0/css/line-awesome.min.css">
|
||||
<link rel="manifest" href="manifest.webmanifest">
|
||||
<meta name="theme-color" content="#e6768b">
|
||||
</head>
|
||||
|
@ -207,3 +207,7 @@ body {
|
||||
border-radius: 0.5rem;
|
||||
background-color: #212224;
|
||||
}
|
||||
|
||||
i {
|
||||
font-size: 1.5rem;
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user