fix(console): cleanup structure, role guard, paginated requests, cleanup policies, toast i18n, view timestamp, preloading strategy, maennchenfindings, fix passwordchange (#483)

* routes, move grid to list comopnent

* rename app list component, move to project sub

* add owned-project-detail child module

* seperate pipes

* set password validators only if needed

* create org initialize without pwd

* no caps

* self xss message

* fix user table

* fix project member paginator

* fix project members pagination, user grant pag

* move project grants, fix imports

* fix owned project detail imports

* use pipe and directives

* ng content bindings, rem custom schemas

* i18n, fix error toast parameter

* toast i18n

* side background

* fix: sequence, add timestamp

* audit

* fix metanav background

* org domain label

* cleanup policy component

* shorten user grant roles, mk cols visible as bind

* move user components, show otp only if available

* preload modules

* fix password change

* fix org create buttons

* class css
This commit is contained in:
Max Peintner
2020-07-16 15:13:36 +02:00
committed by GitHub
parent 2a3ecc0c6a
commit 4f3ccbfad0
125 changed files with 807 additions and 614 deletions

View File

@@ -9381,9 +9381,9 @@
} }
}, },
"lodash": { "lodash": {
"version": "4.17.15", "version": "4.17.19",
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz", "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.19.tgz",
"integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==" "integrity": "sha512-JNvd8XER9GQX0v2qJgsaN/mzFCNA5BRe/j8JN9d+tWyGLSodKQHKFicdwNYzWwI3wjRnaKPsGj1XkBjx/F96DQ=="
}, },
"lodash.camelcase": { "lodash.camelcase": {
"version": "4.3.0", "version": "4.3.0",
@@ -10167,6 +10167,21 @@
"tslib": "^2.0.0" "tslib": "^2.0.0"
} }
}, },
"ngx-quicklink": {
"version": "0.2.3",
"resolved": "https://registry.npmjs.org/ngx-quicklink/-/ngx-quicklink-0.2.3.tgz",
"integrity": "sha512-a7yxNKNdkuL87GWuPAknxYyo+jRm7KTjHN7Ni8ohNQrVfPzV3c6UV4QWg88Hxi0gJC4wF3vEG3uviDnj5wJRaw==",
"requires": {
"tslib": "^1.9.0"
},
"dependencies": {
"tslib": {
"version": "1.13.0",
"resolved": "https://registry.npmjs.org/tslib/-/tslib-1.13.0.tgz",
"integrity": "sha512-i/6DQjL8Xf3be4K/E6Wgpekn5Qasl1usyw++dAA35Ue5orEn65VIxOA+YvNNl9HV3qv70T7CNwjODHZrLwvd1Q=="
}
}
},
"nice-try": { "nice-try": {
"version": "1.0.5", "version": "1.0.5",
"resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz", "resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz",

View File

@@ -35,6 +35,7 @@
"grpc-web": "^1.2.0", "grpc-web": "^1.2.0",
"moment": "^2.27.0", "moment": "^2.27.0",
"ngx-moment": "^5.0.0", "ngx-moment": "^5.0.0",
"ngx-quicklink": "^0.2.3",
"prettier-stylelint": "^0.4.2", "prettier-stylelint": "^0.4.2",
"rxjs": "~6.6.0", "rxjs": "~6.6.0",
"ts-protoc-gen": "^0.12.0", "ts-protoc-gen": "^0.12.0",

View File

@@ -1,5 +1,6 @@
import { NgModule } from '@angular/core'; import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router'; import { RouterModule, Routes } from '@angular/router';
import { QuicklinkStrategy } from 'ngx-quicklink';
import { AuthGuard } from './guards/auth.guard'; import { AuthGuard } from './guards/auth.guard';
import { RoleGuard } from './guards/role.guard'; import { RoleGuard } from './guards/role.guard';
@@ -30,15 +31,30 @@ const routes: Routes = [
}, },
{ {
path: 'users', path: 'users',
loadChildren: () => import('./pages/users/users.module').then(m => m.UsersModule),
canActivate: [AuthGuard], canActivate: [AuthGuard],
children: [
{
path: 'all',
loadChildren: () => import('src/app/pages/users/user-list/user-list.module')
.then(m => m.UserListModule),
canActivate: [RoleGuard],
data: {
roles: ['user.read'],
},
},
{
path: '',
loadChildren: () => import('src/app/pages/users/user-detail/user-detail.module')
.then(m => m.UserDetailModule),
},
],
}, },
{ {
path: 'iam', path: 'iam',
loadChildren: () => import('./pages/iam/iam.module').then(m => m.IamModule), loadChildren: () => import('./pages/iam/iam.module').then(m => m.IamModule),
canActivate: [AuthGuard, RoleGuard], canActivate: [AuthGuard, RoleGuard],
data: { data: {
roles: ['iam.read'], roles: ['iam.read', 'iam.write'],
}, },
}, },
{ {
@@ -49,27 +65,30 @@ const routes: Routes = [
roles: ['org.read'], roles: ['org.read'],
}, },
}, },
{
path: 'grant-create/project/:projectid/grant/:grantid',
loadChildren: () => import('src/app/pages/user-grant-create/user-grant-create.module')
.then(m => m.UserGrantCreateModule),
},
{
path: 'grant-create/project/:projectid',
loadChildren: () => import('src/app/pages/user-grant-create/user-grant-create.module')
.then(m => m.UserGrantCreateModule),
},
{
path: 'grant-create/user/:userid',
loadChildren: () => import('src/app/pages/user-grant-create/user-grant-create.module')
.then(m => m.UserGrantCreateModule),
},
{ {
path: 'grant-create', path: 'grant-create',
loadChildren: () => import('src/app/pages/user-grant-create/user-grant-create.module') canActivate: [AuthGuard],
.then(m => m.UserGrantCreateModule), children: [
{
path: 'project/:projectid/grant/:grantid',
loadChildren: () => import('src/app/pages/user-grant-create/user-grant-create.module')
.then(m => m.UserGrantCreateModule),
canActivate: [RoleGuard],
data: {
roles: ['project.grant.user.grant.write'],
},
},
{
path: 'project/:projectid',
loadChildren: () => import('src/app/pages/user-grant-create/user-grant-create.module')
.then(m => m.UserGrantCreateModule),
canActivate: [RoleGuard],
data: {
roles: ['project.user.grant.write'],
},
},
],
}, },
{ {
path: 'signedout', path: 'signedout',
loadChildren: () => import('./pages/signedout/signedout.module').then(m => m.SignedoutModule), loadChildren: () => import('./pages/signedout/signedout.module').then(m => m.SignedoutModule),
@@ -81,7 +100,14 @@ const routes: Routes = [
]; ];
@NgModule({ @NgModule({
imports: [RouterModule.forRoot(routes)], imports: [
RouterModule.forRoot(
routes,
{
preloadingStrategy: QuicklinkStrategy,
},
),
],
exports: [RouterModule], exports: [RouterModule],
}) })
export class AppRoutingModule { } export class AppRoutingModule { }

View File

@@ -1,130 +1,130 @@
<ng-container *ngIf="(authService.user | async) || {} as user"> <ng-container *ngIf="(authService.user | async) || {} as user">
<mat-toolbar class="root-header"> <ng-container *ngIf="((['iam.read','iam.write'] | hasRole)) as iamuser$">
<button aria-label="Toggle sidenav" mat-icon-button (click)="drawer.toggle()"> <mat-toolbar class="root-header">
<mat-icon aria-label="Side nav toggle icon">menu</mat-icon> <button aria-label="Toggle sidenav" mat-icon-button (click)="drawer.toggle()">
</button> <mat-icon aria-label="Side nav toggle icon">menu</mat-icon>
<a *ngIf="(isHandset$ | async) == false" class="title" [routerLink]="['/']"> </button>
<img class="logo" alt="zitadel logo" *ngIf="componentCssClass == 'dark-theme'; else lighttheme" <a *ngIf="(isHandset$ | async) == false" class="title" [routerLink]="['/']">
src="../assets/images/zitadel-logo-oneline-darkdesign.svg" /> <img class="logo" alt="zitadel logo" *ngIf="componentCssClass == 'dark-theme'; else lighttheme"
<ng-template #lighttheme> src="../assets/images/zitadel-logo-oneline-darkdesign.svg" />
<img alt="zitadel logo" class="logo" src="../assets/images/zitadel-logo-oneline-lightdesign.svg" /> <ng-template #lighttheme>
</ng-template> <img alt="zitadel logo" class="logo" src="../assets/images/zitadel-logo-oneline-lightdesign.svg" />
</a> </ng-template>
</a>
<button (click)="loadOrgs()" *ngIf="profile?.id && org" mat-button <button (click)="loadOrgs()" *ngIf="profile?.id && org" mat-button
[matMenuTriggerFor]="menu">{{org?.name ? org.name : 'NO NAME'}} [matMenuTriggerFor]="menu">{{org?.name ? org.name : 'NO NAME'}}
<mat-icon> <mat-icon>
arrow_drop_down</mat-icon> arrow_drop_down</mat-icon>
</button>
<mat-menu #menu="matMenu">
<mat-progress-bar *ngIf="orgLoading" color="accent" mode="indeterminate"></mat-progress-bar>
<button class="show-all" mat-menu-item
[routerLink]="[ '/org/overview' ]">{{'MENU.SHOWORGS' | translate}}</button>
<button [ngClass]="{'active': temporg.id === org?.id}" [disabled]="!temporg.id" *ngFor="let temporg of orgs"
mat-menu-item (click)="setActiveOrg(temporg)">
{{temporg?.name ? temporg.name : 'NO NAME'}}
</button> </button>
<ng-template appHasRole [appHasRole]="['iam.write']"> <mat-menu #menu="matMenu">
<button mat-menu-item [routerLink]="[ '/org/create' ]"> <mat-progress-bar *ngIf="orgLoading" color="accent" mode="indeterminate"></mat-progress-bar>
<mat-icon class="avatar">add</mat-icon> <button class="show-all" mat-menu-item
{{'MENU.NEWORG' | translate}} [routerLink]="[ '/org/overview' ]">{{'MENU.SHOWORGS' | translate}}</button>
<button [ngClass]="{'active': temporg.id === org?.id}" [disabled]="!temporg.id"
*ngFor="let temporg of orgs" mat-menu-item (click)="setActiveOrg(temporg)">
{{temporg?.name ? temporg.name : 'NO NAME'}}
</button> </button>
</ng-template>
</mat-menu>
<span class="fill-space"></span>
<div (clickOutside)="closeAccountCard()" class="icon-container"> <ng-template appHasRole [appHasRole]="['iam.write']">
<app-avatar *ngIf="user && (user.displayName || (user.firstName && user.lastName))" <button mat-menu-item [routerLink]="[ '/org/create' ]">
class="avatar dontcloseonclick" (click)="showAccount = !showAccount" [active]="showAccount" <mat-icon class="avatar">add</mat-icon>
[name]="user.displayName ? user.displayName : (user.firstName + ' '+ user.lastName)" [size]="38"> {{'MENU.NEWORG' | translate}}
</app-avatar> </button>
<app-accounts-card @accounts class="a_card mat-elevation-z5" *ngIf="showAccount" </ng-template>
(close)="showAccount = false" [profile]="profile" [iamuser]="iamreadwrite"> </mat-menu>
</app-accounts-card> <span class="fill-space"></span>
</div>
</mat-toolbar>
<mat-drawer-container class="main-container"> <div (clickOutside)="closeAccountCard()" class="icon-container">
<mat-drawer #drawer class="side" [mode]="(isHandset$ | async) ? 'over' : 'side'" <app-avatar *ngIf="user && (user.displayName || (user.firstName && user.lastName))"
[opened]="!(isHandset$ | async)"> class="avatar dontcloseonclick" (click)="showAccount = !showAccount" [active]="showAccount"
<div class="side-column"> [name]="user.displayName ? user.displayName : (user.firstName + ' '+ user.lastName)" [size]="38">
<div class="list"> </app-avatar>
<ng-container *ngIf="authService.authenticationChanged | async"> <app-accounts-card @accounts class="a_card mat-elevation-z5" *ngIf="showAccount"
<a class="nav-item" [routerLinkActive]="['active']" [routerLinkActiveOptions]="{ exact: true }" (close)="showAccount = false" [profile]="profile" [iamuser]="iamuser$ | async">
[routerLink]="['/users/me']"> </app-accounts-card>
<i class="icon las la-user-circle"></i> </div>
<span class="label">{{ 'MENU.PERSONAL_INFO' | translate }}</span> </mat-toolbar>
</a>
</ng-container>
<ng-container *ngIf="iamreadwrite"> <mat-drawer-container class="main-container">
<div class="divider"> <mat-drawer #drawer class="sidenav" [mode]="(isHandset$ | async) ? 'over' : 'side'"
<div class="line"></div> [opened]="!(isHandset$ | async)">
</div> <div class="side-column">
<a class="nav-item" [routerLinkActive]="['active']" [routerLink]="[ '/iam']"> <div class="list">
<i class="icon las la-gem"></i> <ng-container *ngIf="authService.authenticationChanged | async">
<span class="label">{{'MENU.IAM' | translate}}</span> <a class="nav-item" [routerLinkActive]="['active']"
</a> [routerLinkActiveOptions]="{ exact: true }" [routerLink]="['/users/me']">
</ng-container> <i class="icon las la-user-circle"></i>
<span class="label">{{ 'MENU.PERSONAL_INFO' | translate }}</span>
</a>
</ng-container>
<ng-container *ngIf="showOrgSection"> <ng-container *ngIf="iamuser$ | async">
<a class="nav-item" [routerLinkActive]="['active']" [routerLink]="[ '/org']"> <div class="divider">
<i class="icon las la-archway"></i> <div class="line"></div>
<span class="label">{{org?.name ? org.name : 'MENU.ORGANIZATION' | translate}}</span> </div>
</a> <a class="nav-item" [routerLinkActive]="['active']" [routerLink]="[ '/iam']">
</ng-container> <i class="icon las la-gem"></i>
<span class="label">{{'MENU.IAM' | translate}}</span>
</a>
</ng-container>
<ng-container *ngIf="showProjectSection"> <ng-template appHasRole [appHasRole]="['org.read']">
<div class="divider"> <a class="nav-item" [routerLinkActive]="['active']" [routerLink]="[ '/org']">
<div class="line"></div> <i class="icon las la-archway"></i>
<span>{{'MENU.PROJECTSSECTION' | translate}}</span> <span class="label">{{org?.name ? org.name : 'MENU.ORGANIZATION' | translate}}</span>
<div class="line"></div> </a>
</div> </ng-template>
<a class="nav-item" [routerLinkActive]="['active']" [routerLink]="[ '/projects']"> <ng-template appHasRole [appHasRole]="['project.read']">
<i class="icon las la-layer-group"></i> <div class="divider">
<span class="label">{{org?.name ? org.name : 'MENU.ORGANIZATION' | translate}} <div class="line"></div>
{{ 'MENU.PROJECT' | translate }}</span> <span>{{'MENU.PROJECTSSECTION' | translate}}</span>
</a> <div class="line"></div>
</div>
<a class="nav-item" [routerLinkActive]="['active']" [routerLink]="[ '/granted-projects']"> <a class="nav-item" [routerLinkActive]="['active']" [routerLink]="[ '/projects']">
<i class="icon las la-layer-group"></i> <i class="icon las la-layer-group"></i>
<span class="label">{{ 'MENU.GRANTEDPROJECT' | translate }}</span> <span class="label">{{org?.name ? org.name : 'MENU.ORGANIZATION' | translate}}
</a> {{ 'MENU.PROJECT' | translate }}</span>
</ng-container> </a>
<ng-container *ngIf="showUserSection"> <a class="nav-item" [routerLinkActive]="['active']" [routerLink]="[ '/granted-projects']">
<div class="divider"> <i class="icon las la-layer-group"></i>
<div class="line"></div> <span class="label">{{ 'MENU.GRANTEDPROJECT' | translate }}</span>
<span class="label"> </a>
{{ 'MENU.USERSECTION' | translate }}</span> </ng-template>
<div class="line"></div>
</div>
<a class="nav-item" [routerLinkActive]="['active']" [routerLink]="[ '/users/all']" <ng-template appHasRole [appHasRole]="['user.read']">
[routerLinkActiveOptions]="{ exact: true }"> <div class="divider">
<i class="icon las la-users"></i> <div class="line"></div>
<span class="label">{{ 'MENU.USER' | translate }}</span> <span class="label">
</a> {{ 'MENU.USERSECTION' | translate }}</span>
</ng-container> <div class="line"></div>
</div>
<a class="nav-item" [routerLinkActive]="['active']" [routerLink]="[ '/users/all']"
[routerLinkActiveOptions]="{ exact: true }">
<i class="icon las la-users"></i>
<span class="label">{{ 'MENU.USER' | translate }}</span>
</a>
</ng-template>
<span class="fill-space"></span>
</div>
<span class="fill-space"></span> <span class="fill-space"></span>
</div> </div>
<span class="fill-space"></span> </mat-drawer>
</div> <mat-drawer-content class="content">
</mat-drawer> <div *ngIf="iamuser$ | async" class="admin-line" matTooltip="IAM Administrator">
<mat-drawer-content class="content">
<ng-template appHasRole [appHasRole]="['iam.write']">
<div class="admin-line" matTooltip="IAM Administrator">
<span>{{'MENU.IAMADMIN' | translate}}</span> <span>{{'MENU.IAMADMIN' | translate}}</span>
</div> </div>
</ng-template> <div class="router" [@routeAnimations]="prepareRoute(outlet)">
<div class="router" [@routeAnimations]="prepareRoute(outlet)"> <router-outlet #outlet="outlet"></router-outlet>
<router-outlet #outlet="outlet"></router-outlet> </div>
</div> </mat-drawer-content>
</mat-drawer-content> </mat-drawer-container>
</mat-drawer-container> </ng-container>
</ng-container> </ng-container>

View File

@@ -76,7 +76,7 @@
height: calc(100vh - 60px); height: calc(100vh - 60px);
width: 100%; width: 100%;
.side { .sidenav {
width: 300px; width: 300px;
border-right: none; border-right: none;

View File

@@ -134,10 +134,6 @@ export class AppComponent implements OnDestroy {
public orgLoading: boolean = false; public orgLoading: boolean = false;
public showProjectSection: boolean = false; public showProjectSection: boolean = false;
public showOrgSection: boolean = false;
public showUserSection: boolean = false;
public iamreadwrite: boolean = false;
private authSub: Subscription = new Subscription(); private authSub: Subscription = new Subscription();
private orgSub: Subscription = new Subscription(); private orgSub: Subscription = new Subscription();
@@ -207,13 +203,10 @@ export class AppComponent implements OnDestroy {
this.orgSub = this.authService.activeOrgChanged.subscribe(org => { this.orgSub = this.authService.activeOrgChanged.subscribe(org => {
this.org = org; this.org = org;
this.loadPermissions();
}); });
this.authSub = this.authService.authenticationChanged.subscribe((authenticated) => { this.authSub = this.authService.authenticationChanged.subscribe((authenticated) => {
if (authenticated) { if (authenticated) {
// this.userService.GetMyzitadelPermissions().pipe(take(1)).subscribe(perm => console.log(perm.toObject()));
this.loadPermissions();
this.authService.GetActiveOrg().then(org => { this.authService.GetActiveOrg().then(org => {
this.org = org; this.org = org;
}); });
@@ -235,13 +228,6 @@ export class AppComponent implements OnDestroy {
this.orgSub.unsubscribe(); this.orgSub.unsubscribe();
} }
public loadPermissions(): void {
this.userService.isAllowed(['iam.read', 'iam.write'], true).subscribe(allowed => this.iamreadwrite = allowed);
this.userService.isAllowed(['org.read']).subscribe(allowed => this.showOrgSection = allowed);
this.userService.isAllowed(['project.read']).subscribe(allowed => this.showProjectSection = allowed);
this.userService.isAllowed(['user.read']).subscribe(allowed => this.showUserSection = allowed);
}
public loadOrgs(): void { public loadOrgs(): void {
this.orgLoading = true; this.orgLoading = true;
this.userService.SearchMyProjectOrgs(10, 0).then(res => { this.userService.SearchMyProjectOrgs(10, 0).then(res => {

View File

@@ -18,6 +18,7 @@ import { ServiceWorkerModule } from '@angular/service-worker';
import { TranslateLoader, TranslateModule } from '@ngx-translate/core'; import { TranslateLoader, TranslateModule } from '@ngx-translate/core';
import { TranslateHttpLoader } from '@ngx-translate/http-loader'; import { TranslateHttpLoader } from '@ngx-translate/http-loader';
import { AuthConfig, OAuthModule, OAuthStorage } from 'angular-oauth2-oidc'; import { AuthConfig, OAuthModule, OAuthStorage } from 'angular-oauth2-oidc';
import { QuicklinkModule } from 'ngx-quicklink';
import { environment } from '../environments/environment'; import { environment } from '../environments/environment';
import { AppRoutingModule } from './app-routing.module'; import { AppRoutingModule } from './app-routing.module';
@@ -27,6 +28,7 @@ import { OutsideClickModule } from './directives/outside-click/outside-click.mod
import { AccountsCardModule } from './modules/accounts-card/accounts-card.module'; import { AccountsCardModule } from './modules/accounts-card/accounts-card.module';
import { AvatarModule } from './modules/avatar/avatar.module'; import { AvatarModule } from './modules/avatar/avatar.module';
import { SignedoutComponent } from './pages/signedout/signedout.component'; import { SignedoutComponent } from './pages/signedout/signedout.component';
import { HasRolePipeModule } from './pipes/has-role-pipe.module';
import { AuthUserService } from './services/auth-user.service'; import { AuthUserService } from './services/auth-user.service';
import { AuthService } from './services/auth.service'; import { AuthService } from './services/auth.service';
import { GrpcService } from './services/grpc.service'; import { GrpcService } from './services/grpc.service';
@@ -86,6 +88,7 @@ const authConfig: AuthConfig = {
deps: [HttpClient], deps: [HttpClient],
}, },
}), }),
QuicklinkModule,
AccountsCardModule, AccountsCardModule,
HasRoleModule, HasRoleModule,
BrowserAnimationsModule, BrowserAnimationsModule,
@@ -96,6 +99,7 @@ const authConfig: AuthConfig = {
MatSidenavModule, MatSidenavModule,
MatCardModule, MatCardModule,
OutsideClickModule, OutsideClickModule,
HasRolePipeModule,
MatProgressBarModule, MatProgressBarModule,
MatToolbarModule, MatToolbarModule,
MatMenuModule, MatMenuModule,

View File

@@ -15,6 +15,6 @@ export class RoleGuard implements CanActivate {
route: ActivatedRouteSnapshot, route: ActivatedRouteSnapshot,
state: RouterStateSnapshot, state: RouterStateSnapshot,
): Observable<boolean> { ): Observable<boolean> {
return this.userService.isAllowed(route.data['roles']); return this.userService.isAllowed(route.data['roles'], true);
} }
} }

View File

@@ -33,8 +33,6 @@ export class MemberCreateDialogComponent {
this.creationType = data.creationType; this.creationType = data.creationType;
this.projectId = data.projectId; this.projectId = data.projectId;
console.log(this.creationType);
if (this.creationType === CreationType.PROJECT_GRANTED) { if (this.creationType === CreationType.PROJECT_GRANTED) {
this.projectService.GetProjectGrantMemberRoles().then(resp => { this.projectService.GetProjectGrantMemberRoles().then(resp => {
this.memberRoleOptions = resp.toObject().rolesList; this.memberRoleOptions = resp.toObject().rolesList;

View File

@@ -3,7 +3,7 @@
<div *ngIf="title" class="row"> <div *ngIf="title" class="row">
<h2 class="title">{{title}}</h2> <h2 class="title">{{title}}</h2>
<span class="fill-space"></span> <span class="fill-space"></span>
<ng-content select="card-actions"></ng-content> <ng-content select="[card-actions]"></ng-content>
<button class="button" matTooltip="Expand or collapse" mat-icon-button (click)="expanded = !expanded"> <button class="button" matTooltip="Expand or collapse" mat-icon-button (click)="expanded = !expanded">
<mat-icon *ngIf="!expanded">keyboard_arrow_down</mat-icon> <mat-icon *ngIf="!expanded">keyboard_arrow_down</mat-icon>
<mat-icon *ngIf="expanded">keyboard_arrow_up</mat-icon> <mat-icon *ngIf="expanded">keyboard_arrow_up</mat-icon>

View File

@@ -119,7 +119,6 @@ export class ChangesComponent implements OnInit {
} }
}), }),
catchError(err => { catchError(err => {
console.error(err);
this._loading.next(false); this._loading.next(false);
this.bottom = true; this.bottom = true;
return of([]); return of([]);

View File

@@ -4,12 +4,13 @@ import { NgModule } from '@angular/core';
import { MatProgressSpinnerModule } from '@angular/material/progress-spinner'; import { MatProgressSpinnerModule } from '@angular/material/progress-spinner';
import { TranslateModule } from '@ngx-translate/core'; import { TranslateModule } from '@ngx-translate/core';
import { ScrollableModule } from 'src/app/directives/scrollable/scrollable.module'; import { ScrollableModule } from 'src/app/directives/scrollable/scrollable.module';
import { PipesModule } from 'src/app/pipes/pipes.module'; import { HasRolePipeModule } from 'src/app/pipes/has-role-pipe.module';
import { LocalizedDatePipeModule } from 'src/app/pipes/localized-date-pipe.module';
import { TimestampToDatePipeModule } from 'src/app/pipes/timestamp-to-date-pipe.module';
import { ChangesComponent } from './changes.component'; import { ChangesComponent } from './changes.component';
@NgModule({ @NgModule({
declarations: [ declarations: [
ChangesComponent, ChangesComponent,
@@ -19,8 +20,10 @@ import { ChangesComponent } from './changes.component';
ScrollableModule, ScrollableModule,
MatProgressSpinnerModule, MatProgressSpinnerModule,
TranslateModule, TranslateModule,
PipesModule, HasRolePipeModule,
ScrollingModule, ScrollingModule,
LocalizedDatePipeModule,
TimestampToDatePipeModule,
], ],
exports: [ exports: [
ChangesComponent, ChangesComponent,

View File

@@ -5,6 +5,6 @@
<div class="meta" [ngClass]="{'hidden': hidden}"> <div class="meta" [ngClass]="{'hidden': hidden}">
<button (click)="hidden = !hidden" color="primary" class="hide" mat-icon-button><i <button (click)="hidden = !hidden" color="primary" class="hide" mat-icon-button><i
class="las la-arrow-right"></i></button> class="las la-arrow-right"></i></button>
<ng-content class="meta-content" select="metainfo"></ng-content> <ng-content class="meta-content" select="[metainfo]"></ng-content>
</div> </div>
</div> </div>

View File

@@ -85,7 +85,7 @@ export class ProjectContributorsComponent implements OnInit {
case ProjectType.PROJECTTYPE_OWNED: case ProjectType.PROJECTTYPE_OWNED:
return this.projectService.AddProjectMember(this.project.projectId, user.id, roles) return this.projectService.AddProjectMember(this.project.projectId, user.id, roles)
.then(() => { .then(() => {
this.toast.showInfo('members added'); this.toast.showInfo('PROJECT.TOAST.MEMBERADDED', true);
}).catch(error => { }).catch(error => {
this.toast.showError(error); this.toast.showError(error);
}); });
@@ -96,7 +96,7 @@ export class ProjectContributorsComponent implements OnInit {
user.id, user.id,
roles, roles,
).then(() => { ).then(() => {
this.toast.showInfo('members added'); this.toast.showInfo('PROJECT.TOAST.MEMBERADDED', true);
}).catch(error => { }).catch(error => {
this.toast.showError(error); this.toast.showError(error);
}); });

View File

@@ -25,8 +25,7 @@ export class ProjectMembersDataSource extends DataSource<ProjectMember.AsObject>
const offset = pageIndex * pageSize; const offset = pageIndex * pageSize;
this.loadingSubject.next(true); this.loadingSubject.next(true);
console.log(grantId);
// TODO
const promise: Promise<ProjectMemberSearchResponse> | undefined = const promise: Promise<ProjectMemberSearchResponse> | undefined =
projectType === ProjectType.PROJECTTYPE_OWNED ? projectType === ProjectType.PROJECTTYPE_OWNED ?
this.projectService.SearchProjectMembers(projectId, pageSize, offset) : this.projectService.SearchProjectMembers(projectId, pageSize, offset) :

View File

@@ -98,7 +98,7 @@
<mat-form-field class="form-field" appearance="outline" *ngIf="project"> <mat-form-field class="form-field" appearance="outline" *ngIf="project">
<mat-label>{{ 'PROJECT.GRANT.TITLE' | translate }}</mat-label> <mat-label>{{ 'PROJECT.GRANT.TITLE' | translate }}</mat-label>
<mat-select [(ngModel)]="member.rolesList" multiple <mat-select [(ngModel)]="member.rolesList" multiple
[disabled]="(['project.member.write:'+project.projectId] | hasRole) == false" [disabled]="([('project.member.write:' + project.projectId)] | hasRole | async) == false"
(selectionChange)="updateRoles(member, $event)"> (selectionChange)="updateRoles(member, $event)">
<mat-option *ngFor="let role of memberRoleOptions" [value]="role"> <mat-option *ngFor="let role of memberRoleOptions" [value]="role">
{{ 'ROLES.'+role | translate }} {{ 'ROLES.'+role | translate }}
@@ -113,8 +113,9 @@
</tr> </tr>
</table> </table>
<mat-paginator class="background-style" #paginator [pageSize]="50" <mat-paginator *ngIf="dataSource" class="background-style" #paginator [pageSize]="INITIALPAGESIZE"
[pageSizeOptions]="[25, 50, 100, 250]"> [length]="dataSource.totalResult" [pageSizeOptions]="[25, 50, 100, 250]"
(page)="changePage($event)">
</mat-paginator> </mat-paginator>
</div> </div>
</div> </div>

View File

@@ -1,7 +1,7 @@
import { SelectionModel } from '@angular/cdk/collections'; import { SelectionModel } from '@angular/cdk/collections';
import { Component, ViewChild } from '@angular/core'; import { Component, ViewChild } from '@angular/core';
import { MatDialog } from '@angular/material/dialog'; import { MatDialog } from '@angular/material/dialog';
import { MatPaginator } from '@angular/material/paginator'; import { MatPaginator, PageEvent } from '@angular/material/paginator';
import { MatSelectChange } from '@angular/material/select'; import { MatSelectChange } from '@angular/material/select';
import { MatTable } from '@angular/material/table'; import { MatTable } from '@angular/material/table';
import { ActivatedRoute } from '@angular/router'; import { ActivatedRoute } from '@angular/router';
@@ -13,12 +13,14 @@ import { ToastService } from 'src/app/services/toast.service';
import { CreationType, MemberCreateDialogComponent } from '../add-member-dialog/member-create-dialog.component'; import { CreationType, MemberCreateDialogComponent } from '../add-member-dialog/member-create-dialog.component';
import { ProjectMembersDataSource } from './project-members-datasource'; import { ProjectMembersDataSource } from './project-members-datasource';
@Component({ @Component({
selector: 'app-project-members', selector: 'app-project-members',
templateUrl: './project-members.component.html', templateUrl: './project-members.component.html',
styleUrls: ['./project-members.component.scss'], styleUrls: ['./project-members.component.scss'],
}) })
export class ProjectMembersComponent { export class ProjectMembersComponent {
public INITIALPAGESIZE: number = 25;
public project!: ProjectView.AsObject | ProjectGrantView.AsObject; public project!: ProjectView.AsObject | ProjectGrantView.AsObject;
public projectType: ProjectType = ProjectType.PROJECTTYPE_OWNED; public projectType: ProjectType = ProjectType.PROJECTTYPE_OWNED;
public disabled: boolean = false; public disabled: boolean = false;
@@ -50,15 +52,19 @@ export class ProjectMembersComponent {
this.project = project.toObject(); this.project = project.toObject();
this.projectName = this.project.name; this.projectName = this.project.name;
this.dataSource = new ProjectMembersDataSource(this.projectService); this.dataSource = new ProjectMembersDataSource(this.projectService);
this.dataSource.loadMembers(this.project.projectId, this.projectType, 0, 25); this.dataSource.loadMembers(this.project.projectId, this.projectType, 0, this.INITIALPAGESIZE);
}); });
} else if (this.projectType === ProjectType.PROJECTTYPE_GRANTED) { } else if (this.projectType === ProjectType.PROJECTTYPE_GRANTED) {
console.log(params.projectid, params.grantid);
this.projectService.GetGrantedProjectByID(params.projectid, params.grantid).then(project => { this.projectService.GetGrantedProjectByID(params.projectid, params.grantid).then(project => {
this.project = project.toObject(); this.project = project.toObject();
this.projectName = this.project.projectName; this.projectName = this.project.projectName;
this.dataSource = new ProjectMembersDataSource(this.projectService); this.dataSource = new ProjectMembersDataSource(this.projectService);
this.dataSource.loadMembers(this.project.projectId, this.projectType, 0, 25, this.grantId); this.dataSource.loadMembers(this.project.projectId,
this.projectType,
0,
this.INITIALPAGESIZE,
this.grantId,
);
}); });
} }
}); });
@@ -149,7 +155,7 @@ export class ProjectMembersComponent {
if (this.projectType === ProjectType.PROJECTTYPE_OWNED) { if (this.projectType === ProjectType.PROJECTTYPE_OWNED) {
this.projectService.ChangeProjectMember(this.project.projectId, member.userId, selectionChange.value) this.projectService.ChangeProjectMember(this.project.projectId, member.userId, selectionChange.value)
.then((newmember: ProjectMember) => { .then((newmember: ProjectMember) => {
this.toast.showInfo('Member changed'); this.toast.showInfo('PROJECT.TOAST.MEMBERCHANGED', true);
}).catch(error => { }).catch(error => {
this.toast.showError(error); this.toast.showError(error);
}); });
@@ -157,10 +163,14 @@ export class ProjectMembersComponent {
this.projectService.ChangeProjectGrantMember(this.project.projectId, this.projectService.ChangeProjectGrantMember(this.project.projectId,
this.grantId, member.userId, selectionChange.value) this.grantId, member.userId, selectionChange.value)
.then((newmember: ProjectMember) => { .then((newmember: ProjectMember) => {
this.toast.showInfo('Member changed'); this.toast.showInfo('PROJECT.TOAST.MEMBERCHANGED', true);
}).catch(error => { }).catch(error => {
this.toast.showError(error); this.toast.showError(error);
}); });
} }
} }
public changePage(event: PageEvent): void {
this.dataSource.loadMembers(this.project.projectId, this.projectType, event.pageIndex, event.pageSize, this.grantId);
}
} }

View File

@@ -15,7 +15,7 @@ import { MatTableModule } from '@angular/material/table';
import { MatTooltipModule } from '@angular/material/tooltip'; import { MatTooltipModule } from '@angular/material/tooltip';
import { TranslateModule } from '@ngx-translate/core'; import { TranslateModule } from '@ngx-translate/core';
import { HasRoleModule } from 'src/app/directives/has-role/has-role.module'; import { HasRoleModule } from 'src/app/directives/has-role/has-role.module';
import { PipesModule } from 'src/app/pipes/pipes.module'; import { HasRolePipeModule } from 'src/app/pipes/has-role-pipe.module';
import { ProjectMembersRoutingModule } from './project-members-routing.module'; import { ProjectMembersRoutingModule } from './project-members-routing.module';
import { ProjectMembersComponent } from './project-members.component'; import { ProjectMembersComponent } from './project-members.component';
@@ -42,7 +42,7 @@ import { ProjectMembersComponent } from './project-members.component';
MatProgressSpinnerModule, MatProgressSpinnerModule,
FormsModule, FormsModule,
TranslateModule, TranslateModule,
PipesModule, HasRolePipeModule,
], ],
}) })
export class ProjectMembersModule { } export class ProjectMembersModule { }

View File

@@ -93,7 +93,7 @@ export class ProjectRolesComponent implements AfterViewInit, OnInit {
}); });
this.selection.clear(); this.selection.clear();
}).catch(error => { }).catch(error => {
this.toast.showError(error?.message || 'Error'); this.toast.showError(error);
}); });
} }
@@ -105,8 +105,8 @@ export class ProjectRolesComponent implements AfterViewInit, OnInit {
this.dataSource.rolesSubject.value.splice(index, 1); this.dataSource.rolesSubject.value.splice(index, 1);
this.dataSource.rolesSubject.next(this.dataSource.rolesSubject.value); this.dataSource.rolesSubject.next(this.dataSource.rolesSubject.value);
}) })
.catch(data => { .catch(error => {
this.toast.showError(data.message); this.toast.showError(error);
}); });
} }

View File

@@ -15,7 +15,8 @@ import { MatTooltipModule } from '@angular/material/tooltip';
import { RouterModule } from '@angular/router'; import { RouterModule } from '@angular/router';
import { TranslateModule } from '@ngx-translate/core'; import { TranslateModule } from '@ngx-translate/core';
import { HasRoleModule } from 'src/app/directives/has-role/has-role.module'; import { HasRoleModule } from 'src/app/directives/has-role/has-role.module';
import { PipesModule } from 'src/app/pipes/pipes.module'; import { HasRolePipeModule } from 'src/app/pipes/has-role-pipe.module';
import { TimestampToDatePipeModule } from 'src/app/pipes/timestamp-to-date-pipe.module';
import { ProjectRoleDetailComponent } from './project-role-detail/project-role-detail.component'; import { ProjectRoleDetailComponent } from './project-role-detail/project-role-detail.component';
import { ProjectRolesComponent } from './project-roles.component'; import { ProjectRolesComponent } from './project-roles.component';
@@ -39,9 +40,10 @@ import { ProjectRolesComponent } from './project-roles.component';
MatCheckboxModule, MatCheckboxModule,
RouterModule, RouterModule,
MatTooltipModule, MatTooltipModule,
PipesModule, HasRolePipeModule,
TranslateModule, TranslateModule,
MatMenuModule, MatMenuModule,
TimestampToDatePipeModule,
], ],
exports: [ exports: [
ProjectRolesComponent, ProjectRolesComponent,

View File

@@ -1,13 +1,15 @@
import { CommonModule } from '@angular/common'; import { CommonModule } from '@angular/common';
import { NgModule } from '@angular/core'; import { NgModule } from '@angular/core';
import { QuicklinkModule } from 'ngx-quicklink';
import { UsersRoutingModule } from './users-routing.module';
@NgModule({ @NgModule({
declarations: [], declarations: [],
imports: [ imports: [
CommonModule, CommonModule,
UsersRoutingModule, QuicklinkModule,
],
exports: [
QuicklinkModule,
], ],
}) })
export class UsersModule { } export class SharedModule { }

View File

@@ -6,6 +6,7 @@ import {
UserGrantSearchKey, UserGrantSearchKey,
UserGrantSearchQuery, UserGrantSearchQuery,
UserGrantSearchResponse, UserGrantSearchResponse,
UserGrantView,
} from 'src/app/proto/generated/management_pb'; } from 'src/app/proto/generated/management_pb';
import { MgmtUserService } from 'src/app/services/mgmt-user.service'; import { MgmtUserService } from 'src/app/services/mgmt-user.service';
@@ -18,7 +19,7 @@ export enum UserGrantContext {
export class UserGrantsDataSource extends DataSource<UserGrant.AsObject> { export class UserGrantsDataSource extends DataSource<UserGrant.AsObject> {
public totalResult: number = 0; public totalResult: number = 0;
public grantsSubject: BehaviorSubject<UserGrant.AsObject[]> = new BehaviorSubject<UserGrant.AsObject[]>([]); public grantsSubject: BehaviorSubject<UserGrantView.AsObject[]> = new BehaviorSubject<UserGrantView.AsObject[]>([]);
private loadingSubject: BehaviorSubject<boolean> = new BehaviorSubject<boolean>(false); private loadingSubject: BehaviorSubject<boolean> = new BehaviorSubject<boolean>(false);
public loading$: Observable<boolean> = this.loadingSubject.asObservable(); public loading$: Observable<boolean> = this.loadingSubject.asObservable();
@@ -82,7 +83,6 @@ export class UserGrantsDataSource extends DataSource<UserGrant.AsObject> {
catchError(() => of([])), catchError(() => of([])),
finalize(() => this.loadingSubject.next(false)), finalize(() => this.loadingSubject.next(false)),
).subscribe(grants => { ).subscribe(grants => {
console.log(grants);
this.grantsSubject.next(grants); this.grantsSubject.next(grants);
}); });
} }
@@ -93,7 +93,7 @@ export class UserGrantsDataSource extends DataSource<UserGrant.AsObject> {
* the returned stream emits new items. * the returned stream emits new items.
* @returns A stream of the items to be rendered. * @returns A stream of the items to be rendered.
*/ */
public connect(): Observable<UserGrant.AsObject[]> { public connect(): Observable<UserGrantView.AsObject[]> {
return this.grantsSubject.asObservable(); return this.grantsSubject.asObservable();
} }

View File

@@ -25,7 +25,6 @@
<mat-spinner diameter="50"></mat-spinner> <mat-spinner diameter="50"></mat-spinner>
</div> </div>
<table mat-table multiTemplateDataRows class="full-width-table" aria-label="Elements" [dataSource]="dataSource"> <table mat-table multiTemplateDataRows class="full-width-table" aria-label="Elements" [dataSource]="dataSource">
<ng-container matColumnDef="select"> <ng-container matColumnDef="select">
<th class="selection" mat-header-cell *matHeaderCellDef> <th class="selection" mat-header-cell *matHeaderCellDef>
<mat-checkbox color="primary" (change)="$event ? masterToggle() : null" <mat-checkbox color="primary" (change)="$event ? masterToggle() : null"
@@ -53,7 +52,7 @@
<ng-container matColumnDef="org"> <ng-container matColumnDef="org">
<th mat-header-cell *matHeaderCellDef> {{ 'PROJECT.GRANT.GRANTEDORGDOMAIN' | translate }} </th> <th mat-header-cell *matHeaderCellDef> {{ 'PROJECT.GRANT.GRANTEDORGDOMAIN' | translate }} </th>
<td class="pointer" mat-cell *matCellDef="let grant"> <td class="pointer" mat-cell *matCellDef="let grant">
{{grant.orgDomain}} {{grant.orgName}} </td> {{grant.orgName}} </td>
</ng-container> </ng-container>
<ng-container matColumnDef="projectId"> <ng-container matColumnDef="projectId">
@@ -81,7 +80,8 @@
<ng-container *ngIf="context === UserGrantContext.USER"> <ng-container *ngIf="context === UserGrantContext.USER">
<span class="no-roles" <span class="no-roles"
*ngIf="grant.roleKeysList?.length === 0">{{'PROJECT.GRANT.NOROLES' | translate}}</span> *ngIf="grant.roleKeysList?.length === 0">{{'PROJECT.GRANT.NOROLES' | translate}}</span>
<span *ngFor="let role of grant.roleKeysList">{{role}}</span> <span
*ngFor="let role of grant.roleKeysList">{{ (role.length>8)? (role | slice:0:8)+'..':(role) }}</span>
</ng-container> </ng-container>
<!-- <ng-container *ngIf="context === UserGrantContext.USER"> <!-- <ng-container *ngIf="context === UserGrantContext.USER">
@@ -105,7 +105,8 @@
<ng-container *ngIf="context === UserGrantContext.OWNED_PROJECT"> <ng-container *ngIf="context === UserGrantContext.OWNED_PROJECT">
<ng-container *ngIf="loadedProjectId !== grant.projectId"> <ng-container *ngIf="loadedProjectId !== grant.projectId">
<span class="role app-label" *ngFor="let role of grant.roleKeysList">{{role}}</span> <span class="role app-label"
*ngFor="let role of grant.roleKeysList">{{ (role.length>6)? (role | slice:0:6)+'..':(role) }}</span>
<button mat-icon-button (click)="getProjectRoleOptions(grant.projectId)" <button mat-icon-button (click)="getProjectRoleOptions(grant.projectId)"
matTooltip="{{'ACTIONS.CHANGE' | translate}}"> matTooltip="{{'ACTIONS.CHANGE' | translate}}">
<i class="las la-edit"></i> <i class="las la-edit"></i>
@@ -141,6 +142,7 @@
</tr> </tr>
</table> </table>
<mat-paginator #paginator [length]="dataSource.totalResult" [pageSize]="50" [pageSizeOptions]="[25, 50, 100, 250]"> <mat-paginator #paginator [length]="dataSource.totalResult" [pageSize]="50" [length]="dataSource.totalResult"
[pageSizeOptions]="[2, 3, 25, 50, 100, 250]" (page)="changePage($event)">
</mat-paginator> </mat-paginator>
</div> </div>

View File

@@ -1,10 +1,10 @@
import { SelectionModel } from '@angular/cdk/collections'; import { SelectionModel } from '@angular/cdk/collections';
import { AfterViewInit, Component, Input, OnInit, ViewChild } from '@angular/core'; import { AfterViewInit, Component, Input, OnInit, ViewChild } from '@angular/core';
import { MatPaginator } from '@angular/material/paginator'; import { MatPaginator, PageEvent } from '@angular/material/paginator';
import { MatSelectChange } from '@angular/material/select'; import { MatSelectChange } from '@angular/material/select';
import { MatTable } from '@angular/material/table'; import { MatTable } from '@angular/material/table';
import { tap } from 'rxjs/operators'; import { tap } from 'rxjs/operators';
import { ProjectGrant, ProjectRoleView, UserGrant } from 'src/app/proto/generated/management_pb'; import { ProjectRoleView, UserGrant, UserGrantView } from 'src/app/proto/generated/management_pb';
import { MgmtUserService } from 'src/app/services/mgmt-user.service'; import { MgmtUserService } from 'src/app/services/mgmt-user.service';
import { ProjectService } from 'src/app/services/project.service'; import { ProjectService } from 'src/app/services/project.service';
import { ToastService } from 'src/app/services/toast.service'; import { ToastService } from 'src/app/services/toast.service';
@@ -17,15 +17,13 @@ import { UserGrantContext, UserGrantsDataSource } from './user-grants-datasource
styleUrls: ['./user-grants.component.scss'], styleUrls: ['./user-grants.component.scss'],
}) })
export class UserGrantsComponent implements OnInit, AfterViewInit { export class UserGrantsComponent implements OnInit, AfterViewInit {
// @Input() filterValue: string = '';
// @Input() filter: UserGrantSearchKey = UserGrantSearchKey.USERGRANTSEARCHKEY_USER_ID;
@Input() context: UserGrantContext = UserGrantContext.USER; @Input() context: UserGrantContext = UserGrantContext.USER;
public grants: UserGrant.AsObject[] = []; public grants: UserGrantView.AsObject[] = [];
public dataSource!: UserGrantsDataSource; public dataSource!: UserGrantsDataSource;
public selection: SelectionModel<UserGrant.AsObject> = new SelectionModel<UserGrant.AsObject>(true, []); public selection: SelectionModel<UserGrantView.AsObject> = new SelectionModel<UserGrantView.AsObject>(true, []);
@ViewChild(MatPaginator) public paginator!: MatPaginator; @ViewChild(MatPaginator) public paginator!: MatPaginator;
@ViewChild(MatTable) public table!: MatTable<ProjectGrant.AsObject>; @ViewChild(MatTable) public table!: MatTable<UserGrantView.AsObject>;
@Input() allowCreate: boolean = false; @Input() allowCreate: boolean = false;
@Input() allowDelete: boolean = false; @Input() allowDelete: boolean = false;
@@ -51,19 +49,13 @@ export class UserGrantsComponent implements OnInit, AfterViewInit {
private toast: ToastService, private toast: ToastService,
) { } ) { }
public displayedColumns: string[] = ['select', @Input() public displayedColumns: string[] = ['select',
'user', 'user',
'org', 'org',
'projectId', 'creationDate', 'changeDate', 'roleNamesList']; 'projectId', 'creationDate', 'changeDate', 'roleNamesList'];
public ngOnInit(): void { public ngOnInit(): void {
console.log(this.context);
this.dataSource = new UserGrantsDataSource(this.userService); this.dataSource = new UserGrantsDataSource(this.userService);
const data = {
projectId: this.projectId,
grantId: this.grantId,
userId: this.userId,
};
switch (this.context) { switch (this.context) {
case UserGrantContext.OWNED_PROJECT: case UserGrantContext.OWNED_PROJECT:
@@ -73,7 +65,7 @@ export class UserGrantsComponent implements OnInit, AfterViewInit {
} }
break; break;
case UserGrantContext.GRANTED_PROJECT: case UserGrantContext.GRANTED_PROJECT:
if (data && data.grantId) { if (this.grantId) {
this.routerLink = ['/grant-create', 'project', this.projectId, 'grant', this.grantId]; this.routerLink = ['/grant-create', 'project', this.projectId, 'grant', this.grantId];
this.getGrantRoleOptions(this.grantId, this.projectId); this.getGrantRoleOptions(this.grantId, this.projectId);
} }
@@ -86,7 +78,11 @@ export class UserGrantsComponent implements OnInit, AfterViewInit {
default: default:
this.routerLink = ['/grant-create']; this.routerLink = ['/grant-create'];
} }
this.dataSource.loadGrants(this.context, 0, 25, data); this.dataSource.loadGrants(this.context, 0, 25, {
projectId: this.projectId,
grantId: this.grantId,
userId: this.userId,
});
} }
public ngAfterViewInit(): void { public ngAfterViewInit(): void {
@@ -122,8 +118,6 @@ export class UserGrantsComponent implements OnInit, AfterViewInit {
} }
public getGrantRoleOptions(grantId: string, projectId: string): void { public getGrantRoleOptions(grantId: string, projectId: string): void {
console.log(grantId, projectId);
this.projectService.GetGrantedProjectByID(projectId, grantId).then(resp => { this.projectService.GetGrantedProjectByID(projectId, grantId).then(resp => {
this.loadedGrantId = projectId; this.loadedGrantId = projectId;
this.grantRoleOptions = resp.toObject().roleKeysList; this.grantRoleOptions = resp.toObject().roleKeysList;
@@ -133,7 +127,6 @@ export class UserGrantsComponent implements OnInit, AfterViewInit {
} }
public getProjectRoleOptions(projectId: string): void { public getProjectRoleOptions(projectId: string): void {
console.log(projectId);
this.projectService.SearchProjectRoles(projectId, 100, 0).then(resp => { this.projectService.SearchProjectRoles(projectId, 100, 0).then(resp => {
this.loadedProjectId = projectId; this.loadedProjectId = projectId;
this.projectRoleOptions = resp.toObject().resultList; this.projectRoleOptions = resp.toObject().resultList;
@@ -182,4 +175,12 @@ export class UserGrantsComponent implements OnInit, AfterViewInit {
this.toast.showError(error); this.toast.showError(error);
}); });
} }
public changePage(event: PageEvent): void {
this.dataSource.loadGrants(this.context, event.pageIndex, event.pageSize, {
projectId: this.projectId,
grantId: this.grantId,
userId: this.userId,
});
}
} }

View File

@@ -13,7 +13,8 @@ import { MatTooltipModule } from '@angular/material/tooltip';
import { RouterModule } from '@angular/router'; import { RouterModule } from '@angular/router';
import { TranslateModule } from '@ngx-translate/core'; import { TranslateModule } from '@ngx-translate/core';
import { HasRoleModule } from 'src/app/directives/has-role/has-role.module'; import { HasRoleModule } from 'src/app/directives/has-role/has-role.module';
import { PipesModule } from 'src/app/pipes/pipes.module'; import { HasRolePipeModule } from 'src/app/pipes/has-role-pipe.module';
import { TimestampToDatePipeModule } from 'src/app/pipes/timestamp-to-date-pipe.module';
import { AvatarModule } from '../avatar/avatar.module'; import { AvatarModule } from '../avatar/avatar.module';
import { UserGrantsComponent } from './user-grants.component'; import { UserGrantsComponent } from './user-grants.component';
@@ -38,7 +39,8 @@ import { UserGrantsComponent } from './user-grants.component';
MatSelectModule, MatSelectModule,
MatFormFieldModule, MatFormFieldModule,
TranslateModule, TranslateModule,
PipesModule, HasRolePipeModule,
TimestampToDatePipeModule,
], ],
exports: [ exports: [
UserGrantsComponent, UserGrantsComponent,

View File

@@ -18,7 +18,7 @@
</div> </div>
<span class="fill-space"></span> <span class="fill-space"></span>
<div class="footer"> <div class="footer">
<a color="accent" mat-button [routerLink]="['/iam']">{{'HOME.IAM_BUTTON' | translate}}</a> <a color="primary" mat-button [routerLink]="['/iam']">{{'HOME.IAM_BUTTON' | translate}}</a>
</div> </div>
</div> </div>
</ng-template> </ng-template>
@@ -31,7 +31,7 @@
</div> </div>
<span class="fill-space"></span> <span class="fill-space"></span>
<div class="footer"> <div class="footer">
<a color="accent" mat-button <a color="primary" mat-button
[routerLink]="['/users/me']">{{'HOME.SECURITYANDPRIVACY_BUTTON' | translate}}</a> [routerLink]="['/users/me']">{{'HOME.SECURITYANDPRIVACY_BUTTON' | translate}}</a>
</div> </div>
</div> </div>
@@ -46,7 +46,8 @@
</div> </div>
<span class="fill-space"></span> <span class="fill-space"></span>
<div class="footer"> <div class="footer">
<a color="accent" mat-button [routerLink]="['/projects']">{{'HOME.PROJECTS_BUTTON' | translate}}</a> <a color="primary" mat-button
[routerLink]="['/projects']">{{'HOME.PROJECTS_BUTTON' | translate}}</a>
</div> </div>
</div> </div>
</ng-template> </ng-template>
@@ -60,7 +61,7 @@
</div> </div>
<span class="fill-space"></span> <span class="fill-space"></span>
<div class="footer"> <div class="footer">
<a color="accent" mat-button [routerLink]="['/org']">{{'HOME.PROTECTION_BUTTON' | translate}}</a> <a color="primary" mat-button [routerLink]="['/org']">{{'HOME.PROTECTION_BUTTON' | translate}}</a>
</div> </div>
</div> </div>
</ng-template> </ng-template>
@@ -75,7 +76,7 @@
</div> </div>
<span class="fill-space"></span> <span class="fill-space"></span>
<div class="footer"> <div class="footer">
<a color="accent" mat-button [routerLink]="['/users/me']">{{'HOME.USERS_BUTTON' | translate}}</a> <a color="primary" mat-button [routerLink]="['/users/me']">{{'HOME.USERS_BUTTON' | translate}}</a>
</div> </div>
</div> </div>
</ng-template> </ng-template>

View File

@@ -4,6 +4,7 @@ import { MatButtonModule } from '@angular/material/button';
import { MatIconModule } from '@angular/material/icon'; import { MatIconModule } from '@angular/material/icon';
import { TranslateModule } from '@ngx-translate/core'; import { TranslateModule } from '@ngx-translate/core';
import { HasRoleModule } from 'src/app/directives/has-role/has-role.module'; import { HasRoleModule } from 'src/app/directives/has-role/has-role.module';
import { SharedModule } from 'src/app/modules/shared/shared.module';
import { HomeRoutingModule } from './home-routing.module'; import { HomeRoutingModule } from './home-routing.module';
import { HomeComponent } from './home.component'; import { HomeComponent } from './home.component';
@@ -19,6 +20,7 @@ import { HomeComponent } from './home.component';
HomeRoutingModule, HomeRoutingModule,
MatButtonModule, MatButtonModule,
TranslateModule, TranslateModule,
SharedModule,
], ],
}) })
export class HomeModule { } export class HomeModule { }

View File

@@ -74,7 +74,7 @@ export class IamContributorsComponent implements OnInit {
Promise.all(users.map(user => { Promise.all(users.map(user => {
return this.adminService.AddIamMember(user.id, roles); return this.adminService.AddIamMember(user.id, roles);
})).then(() => { })).then(() => {
this.toast.showError('members added'); this.toast.showInfo('IAM.TOAST.MEMBERADDED');
}).catch(error => { }).catch(error => {
this.toast.showError(error); this.toast.showError(error);
}); });

View File

@@ -53,7 +53,7 @@ export class IamMembersComponent implements AfterViewInit {
public removeProjectMemberSelection(): void { public removeProjectMemberSelection(): void {
Promise.all(this.selection.selected.map(member => { Promise.all(this.selection.selected.map(member => {
return this.adminService.RemoveIamMember(member.userId).then(() => { return this.adminService.RemoveIamMember(member.userId).then(() => {
this.toast.showInfo('Removed successfully'); this.toast.showInfo('IAM.TOAST.MEMBERREMOVED', true);
}).catch(error => { }).catch(error => {
this.toast.showError(error); this.toast.showError(error);
}); });
@@ -62,7 +62,7 @@ export class IamMembersComponent implements AfterViewInit {
public removeMember(member: ProjectMember.AsObject): void { public removeMember(member: ProjectMember.AsObject): void {
this.adminService.RemoveIamMember(member.userId).then(() => { this.adminService.RemoveIamMember(member.userId).then(() => {
this.toast.showInfo('Member removed successfully'); this.toast.showInfo('IAM.TOAST.MEMBERREMOVED', true);
}).catch(error => { }).catch(error => {
this.toast.showError(error); this.toast.showError(error);
}); });
@@ -97,7 +97,7 @@ export class IamMembersComponent implements AfterViewInit {
Promise.all(users.map(user => { Promise.all(users.map(user => {
return this.adminService.AddIamMember(user.id, roles); return this.adminService.AddIamMember(user.id, roles);
})).then(() => { })).then(() => {
this.toast.showError('members added'); this.toast.showInfo('IAM.TOAST.MEMBERADDED', true);
}).catch(error => { }).catch(error => {
this.toast.showError(error); this.toast.showError(error);
}); });

View File

@@ -1,5 +1,7 @@
import { NgModule } from '@angular/core'; import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router'; import { RouterModule, Routes } from '@angular/router';
import { AuthGuard } from 'src/app/guards/auth.guard';
import { RoleGuard } from 'src/app/guards/role.guard';
import { IamComponent } from './iam.component'; import { IamComponent } from './iam.component';
@@ -7,10 +9,18 @@ const routes: Routes = [
{ {
path: '', path: '',
component: IamComponent, component: IamComponent,
canActivate: [AuthGuard, RoleGuard],
data: {
roles: ['iam.read'],
},
}, },
{ {
path: 'members', path: 'members',
loadChildren: () => import('./iam-members/iam-members.module').then(m => m.IamMembersModule), loadChildren: () => import('./iam-members/iam-members.module').then(m => m.IamMembersModule),
canActivate: [AuthGuard, RoleGuard],
data: {
roles: ['iam.member.read'],
},
}, },
]; ];

View File

@@ -26,7 +26,14 @@
<ng-container matColumnDef="sequence"> <ng-container matColumnDef="sequence">
<th mat-header-cell mat-sort-header *matHeaderCellDef> {{ 'IAM.VIEWS.SEQUENCE' | translate }} </th> <th mat-header-cell mat-sort-header *matHeaderCellDef> {{ 'IAM.VIEWS.SEQUENCE' | translate }} </th>
<td mat-cell *matCellDef="let role"> <td mat-cell *matCellDef="let role">
<span class="role app-label">{{role.sequence}}</span> <span class="role app-label">{{role?.processedSequence}}</span>
</td>
</ng-container>
<ng-container matColumnDef="timestamp">
<th mat-header-cell mat-sort-header *matHeaderCellDef> {{ 'IAM.VIEWS.SEQUENCE' | translate }} </th>
<td mat-cell *matCellDef="let role">
<span>{{role?.viewTimestamp | timestampToDate | localizedDate: 'EEE dd. MMM, HH:mm' }}</span>
</td> </td>
</ng-container> </ng-container>

View File

@@ -37,6 +37,8 @@
width: 100%; width: 100%;
td, th { td, th {
padding: 0 1rem;
&:first-child { &:first-child {
padding-left: 0; padding-left: 0;
padding-right: 1rem; padding-right: 1rem;

View File

@@ -21,7 +21,7 @@ export class IamViewsComponent {
@ViewChild(MatSort) public sort!: MatSort; @ViewChild(MatSort) public sort!: MatSort;
public dataSource!: MatTableDataSource<View.AsObject>; public dataSource!: MatTableDataSource<View.AsObject>;
public displayedColumns: string[] = ['viewName', 'database', 'sequence', 'actions']; public displayedColumns: string[] = ['viewName', 'database', 'sequence', 'timestamp', 'actions'];
private loadingSubject: BehaviorSubject<boolean> = new BehaviorSubject<boolean>(false); private loadingSubject: BehaviorSubject<boolean> = new BehaviorSubject<boolean>(false);
public loading$: Observable<boolean> = this.loadingSubject.asObservable(); public loading$: Observable<boolean> = this.loadingSubject.asObservable();
constructor(private adminService: AdminService) { constructor(private adminService: AdminService) {

View File

@@ -8,8 +8,8 @@
</app-card> </app-card>
</div> </div>
<metainfo class="side"> <div class="side" metainfo>
<app-iam-contributors> <app-iam-contributors>
</app-iam-contributors> </app-iam-contributors>
</metainfo> </div>
</app-meta-layout> </app-meta-layout>

View File

@@ -1,5 +1,5 @@
import { CommonModule } from '@angular/common'; import { CommonModule } from '@angular/common';
import { NgModule, NO_ERRORS_SCHEMA } from '@angular/core'; import { NgModule } from '@angular/core';
import { FormsModule, ReactiveFormsModule } from '@angular/forms'; import { FormsModule, ReactiveFormsModule } from '@angular/forms';
import { MatAutocompleteModule } from '@angular/material/autocomplete'; import { MatAutocompleteModule } from '@angular/material/autocomplete';
import { MatButtonModule } from '@angular/material/button'; import { MatButtonModule } from '@angular/material/button';
@@ -16,13 +16,17 @@ import { MatTabsModule } from '@angular/material/tabs';
import { MatTooltipModule } from '@angular/material/tooltip'; import { MatTooltipModule } from '@angular/material/tooltip';
import { TranslateModule } from '@ngx-translate/core'; import { TranslateModule } from '@ngx-translate/core';
import { HasRoleModule } from 'src/app/directives/has-role/has-role.module'; import { HasRoleModule } from 'src/app/directives/has-role/has-role.module';
import { CardModule } from 'src/app/modules/card/card.module';
import { ChangesModule } from 'src/app/modules/changes/changes.module'; import { ChangesModule } from 'src/app/modules/changes/changes.module';
import { MetaLayoutModule } from 'src/app/modules/meta-layout/meta-layout.module'; import { MetaLayoutModule } from 'src/app/modules/meta-layout/meta-layout.module';
import { SharedModule } from 'src/app/modules/shared/shared.module';
import { LocalizedDatePipeModule } from 'src/app/pipes/localized-date-pipe.module';
import { TimestampToDatePipeModule } from 'src/app/pipes/timestamp-to-date-pipe.module';
import { IamContributorsModule } from './iam-contributors/iam-contributors.module'; import { IamContributorsModule } from './iam-contributors/iam-contributors.module';
import { IamRoutingModule } from './iam-routing.module'; import { IamRoutingModule } from './iam-routing.module';
import { IamComponent } from './iam.component';
import { IamViewsComponent } from './iam-views/iam-views.component'; import { IamViewsComponent } from './iam-views/iam-views.component';
import { IamComponent } from './iam.component';
@@ -32,6 +36,7 @@ import { IamViewsComponent } from './iam-views/iam-views.component';
CommonModule, CommonModule,
IamRoutingModule, IamRoutingModule,
ChangesModule, ChangesModule,
CardModule,
MatAutocompleteModule, MatAutocompleteModule,
MatChipsModule, MatChipsModule,
MatButtonModule, MatButtonModule,
@@ -51,7 +56,9 @@ import { IamViewsComponent } from './iam-views/iam-views.component';
TranslateModule, TranslateModule,
MatDialogModule, MatDialogModule,
IamContributorsModule, IamContributorsModule,
LocalizedDatePipeModule,
TimestampToDatePipeModule,
SharedModule,
], ],
schemas: [NO_ERRORS_SCHEMA],
}) })
export class IamModule { } export class IamModule { }

View File

@@ -75,7 +75,7 @@ export class OrgContributorsComponent implements OnInit {
Promise.all(users.map(user => { Promise.all(users.map(user => {
return this.orgService.AddMyOrgMember(user.id, roles); return this.orgService.AddMyOrgMember(user.id, roles);
})).then(() => { })).then(() => {
this.toast.showError('members added'); this.toast.showInfo('ORG.TOAST.MEMBERADDED', true);
}).catch(error => { }).catch(error => {
this.toast.showError(error); this.toast.showError(error);
}); });

View File

@@ -22,10 +22,13 @@
</mat-form-field> </mat-form-field>
</div> </div>
<button [disabled]="orgForm.invalid" color="primary" mat-raised-button class="continue-button" <div class="btn-container">
cdkFocusInitial type="submit"> <span class="fill-space"></span>
{{'CONTINUE' | translate}} <button [disabled]="orgForm.invalid" color="primary" mat-raised-button class="big-button"
</button> cdkFocusInitial type="submit">
{{'CONTINUE' | translate}}
</button>
</div>
</form> </form>
<!-- <div *ngIf="name?.touched" @openClose> <!-- <div *ngIf="name?.touched" @openClose>
@@ -174,7 +177,10 @@
</ng-container> </ng-container>
</div> </div>
<div class="btn-container"> <div class="btn-container">
<button color="primary" class="continue-button" [disabled]="orgForm.invalid || userForm.invalid" <button color="primary" class="small-button" type="button" (click)="previous()"
mat-stroked-button>{{ 'ACTIONS.BACK' | translate }}</button>
<span class="fill-space"></span>
<button color="primary" class="big-button" [disabled]="orgForm.invalid || userForm.invalid"
type="submit" mat-raised-button>{{ 'ACTIONS.FINISH' | translate }}</button> type="submit" mat-raised-button>{{ 'ACTIONS.FINISH' | translate }}</button>
</div> </div>
</form> </form>

View File

@@ -74,7 +74,7 @@ h1 {
.btn-container { .btn-container {
display: flex; display: flex;
justify-content: flex-end; justify-content: flex-end;
button { .continue-button {
margin-top: 3rem; margin-top: 3rem;
display: block; display: block;
padding: 0.5rem 4rem; padding: 0.5rem 4rem;
@@ -125,19 +125,23 @@ h1 {
.btn-container { .btn-container {
display: flex; display: flex;
margin: 0 -.5rem; align-items: center;
button {
border-radius: .5rem;
margin: 0 .5rem;
}
}
.continue-button {
margin-top: 3rem; margin-top: 3rem;
display: block;
padding: 0.5rem 4rem; .small-button {
border-radius: 0.5rem; display: block;
border-radius: 0.5rem;
}
.fill-space {
flex: 1;
}
.big-button {
display: block;
padding: 0.5rem 4rem;
border-radius: 0.5rem;
}
} }
mat-checkbox { mat-checkbox {

View File

@@ -96,8 +96,8 @@ export class OrgCreateComponent {
.then((data: OrgSetUpResponse) => { .then((data: OrgSetUpResponse) => {
this.router.navigate(['orgs', data.toObject().org?.id]); this.router.navigate(['orgs', data.toObject().org?.id]);
}) })
.catch(data => { .catch(error => {
this.toast.showError(data.message); this.toast.showError(error);
}); });
} }

View File

@@ -8,7 +8,7 @@ import { MatIconModule } from '@angular/material/icon';
import { MatInputModule } from '@angular/material/input'; import { MatInputModule } from '@angular/material/input';
import { MatSelectModule } from '@angular/material/select'; import { MatSelectModule } from '@angular/material/select';
import { TranslateModule } from '@ngx-translate/core'; import { TranslateModule } from '@ngx-translate/core';
import { PipesModule } from 'src/app/pipes/pipes.module'; import { HasRolePipeModule } from 'src/app/pipes/has-role-pipe.module';
import { OrgCreateRoutingModule } from './org-create-routing.module'; import { OrgCreateRoutingModule } from './org-create-routing.module';
import { OrgCreateComponent } from './org-create.component'; import { OrgCreateComponent } from './org-create.component';
@@ -25,7 +25,7 @@ import { OrgCreateComponent } from './org-create.component';
MatButtonModule, MatButtonModule,
MatIconModule, MatIconModule,
MatSelectModule, MatSelectModule,
PipesModule, HasRolePipeModule,
TranslateModule, TranslateModule,
MatCheckboxModule, MatCheckboxModule,
], ],

View File

@@ -2,8 +2,8 @@
<div mat-dialog-content> <div mat-dialog-content>
<p class="desc"> {{'ORG.DOMAINS.ADD.DESCRIPTION' | translate}}</p> <p class="desc"> {{'ORG.DOMAINS.ADD.DESCRIPTION' | translate}}</p>
<mat-form-field label="Access Code" required="true"> <mat-form-field label="Domain" required="true">
<mat-label>Code</mat-label> <mat-label>Domain</mat-label>
<input matInput [(ngModel)]="newdomain" /> <input matInput [(ngModel)]="newdomain" />
</mat-form-field> </mat-form-field>
</div> </div>

View File

@@ -24,7 +24,7 @@
</ng-template> </ng-template>
</div> </div>
<metainfo class="side"> <div class="side" metainfo>
<div class="details"> <div class="details">
<div class="row"> <div class="row">
<span class="first">{{'ORG.PAGES.PRIMARYDOMAIN' | translate}}</span> <span class="first">{{'ORG.PAGES.PRIMARYDOMAIN' | translate}}</span>
@@ -46,5 +46,5 @@
<app-changes *ngIf="org" [changeType]="ChangeType.ORG" [id]="org.id"></app-changes> <app-changes *ngIf="org" [changeType]="ChangeType.ORG" [id]="org.id"></app-changes>
</mat-tab> </mat-tab>
</mat-tab-group> </mat-tab-group>
</metainfo> </div>
</app-meta-layout> </app-meta-layout>

View File

@@ -91,13 +91,11 @@ export class OrgGridComponent {
private getData(limit: number, offset: number): void { private getData(limit: number, offset: number): void {
this.userService.SearchMyProjectOrgs(limit, offset).then(res => { this.userService.SearchMyProjectOrgs(limit, offset).then(res => {
this.orgList = res.toObject().resultList; this.orgList = res.toObject().resultList;
console.log(this.orgList);
this.notPinned = Object.assign([], this.orgList); this.notPinned = Object.assign([], this.orgList);
this.reorganizeItems(); this.reorganizeItems();
this.loading = false; this.loading = false;
}).catch(error => { }).catch(error => {
console.error(error);
this.toast.showError(error); this.toast.showError(error);
this.loading = false; this.loading = false;
}); });

View File

@@ -57,7 +57,7 @@ export class OrgMembersComponent implements AfterViewInit {
public removeProjectMemberSelection(): void { public removeProjectMemberSelection(): void {
Promise.all(this.selection.selected.map(member => { Promise.all(this.selection.selected.map(member => {
return this.orgService.RemoveMyOrgMember(member.userId).then(() => { return this.orgService.RemoveMyOrgMember(member.userId).then(() => {
this.toast.showInfo('Removed successfully'); this.toast.showInfo('ORG.TOAST.MEMBERREMOVED', true);
}).catch(error => { }).catch(error => {
this.toast.showError(error); this.toast.showError(error);
}); });
@@ -66,7 +66,7 @@ export class OrgMembersComponent implements AfterViewInit {
public removeMember(member: ProjectMember.AsObject): void { public removeMember(member: ProjectMember.AsObject): void {
this.orgService.RemoveMyOrgMember(member.userId).then(() => { this.orgService.RemoveMyOrgMember(member.userId).then(() => {
this.toast.showInfo('Member removed successfully'); this.toast.showInfo('ORG.TOAST.MEMBERREMOVED', true);
}).catch(error => { }).catch(error => {
this.toast.showError(error); this.toast.showError(error);
}); });
@@ -101,7 +101,7 @@ export class OrgMembersComponent implements AfterViewInit {
Promise.all(users.map(user => { Promise.all(users.map(user => {
return this.orgService.AddMyOrgMember(user.id, roles); return this.orgService.AddMyOrgMember(user.id, roles);
})).then(() => { })).then(() => {
this.toast.showError('members added'); this.toast.showInfo('ORG.TOAST.MEMBERADDED', true);
}).catch(error => { }).catch(error => {
this.toast.showError(error); this.toast.showError(error);
}); });

View File

@@ -1,5 +1,5 @@
import { CommonModule } from '@angular/common'; import { CommonModule } from '@angular/common';
import { NgModule, NO_ERRORS_SCHEMA } from '@angular/core'; import { NgModule } from '@angular/core';
import { FormsModule, ReactiveFormsModule } from '@angular/forms'; import { FormsModule, ReactiveFormsModule } from '@angular/forms';
import { MatButtonModule } from '@angular/material/button'; import { MatButtonModule } from '@angular/material/button';
import { MatButtonToggleModule } from '@angular/material/button-toggle'; import { MatButtonToggleModule } from '@angular/material/button-toggle';
@@ -14,6 +14,7 @@ import { TranslateModule } from '@ngx-translate/core';
import { HasRoleModule } from 'src/app/directives/has-role/has-role.module'; import { HasRoleModule } from 'src/app/directives/has-role/has-role.module';
import { CardModule } from 'src/app/modules/card/card.module'; import { CardModule } from 'src/app/modules/card/card.module';
import { MetaLayoutModule } from 'src/app/modules/meta-layout/meta-layout.module'; import { MetaLayoutModule } from 'src/app/modules/meta-layout/meta-layout.module';
import { SharedModule } from 'src/app/modules/shared/shared.module';
import { WarnDialogModule } from 'src/app/modules/warn-dialog/warn-dialog.module'; import { WarnDialogModule } from 'src/app/modules/warn-dialog/warn-dialog.module';
import { ChangesModule } from '../../modules/changes/changes.module'; import { ChangesModule } from '../../modules/changes/changes.module';
@@ -49,8 +50,7 @@ import { PolicyGridComponent } from './policy-grid/policy-grid.component';
ChangesModule, ChangesModule,
AddDomainDialogModule, AddDomainDialogModule,
TranslateModule, TranslateModule,
SharedModule,
], ],
exports: [],
schemas: [NO_ERRORS_SCHEMA],
}) })
export class OrgsModule { } export class OrgsModule { }

View File

@@ -21,7 +21,7 @@
</div> </div>
<div> <div>
<div class="content" *ngIf="policyType === PolicyComponentType?.LOCKOUT"> <div class="content" *ngIf="policyType === PolicyComponentType?.LOCKOUT && lockoutData">
<mat-form-field class="description-formfield" appearance="outline"> <mat-form-field class="description-formfield" appearance="outline">
<mat-label>{{ 'ORG.POLICY.DATA.DESCRIPTION' | translate }}</mat-label> <mat-label>{{ 'ORG.POLICY.DATA.DESCRIPTION' | translate }}</mat-label>
<input matInput name="description" ngDefaultControl [(ngModel)]="lockoutData.description" <input matInput name="description" ngDefaultControl [(ngModel)]="lockoutData.description"
@@ -44,12 +44,12 @@
<span class="left-desc">{{'ORG.POLICY.DATA.SHOWLOCKOUTFAILURES' | translate}}</span> <span class="left-desc">{{'ORG.POLICY.DATA.SHOWLOCKOUTFAILURES' | translate}}</span>
<span class="fill-space"></span> <span class="fill-space"></span>
<mat-slide-toggle color="primary" name="showLockOutFailures" ngDefaultControl <mat-slide-toggle color="primary" name="showLockOutFailures" ngDefaultControl
[(ngModel)]="complexityData.showLockOutFailures"> [(ngModel)]="lockoutData.showLockOutFailures">
</mat-slide-toggle> </mat-slide-toggle>
</div> </div>
</div> </div>
<div *ngIf="policyType === PolicyComponentType?.COMPLEXITY" class="content"> <div *ngIf="policyType === PolicyComponentType?.COMPLEXITY && complexityData" class="content">
<mat-form-field class="description-formfield" appearance="outline"> <mat-form-field class="description-formfield" appearance="outline">
<mat-label>{{ 'ORG.POLICY.DATA.DESCRIPTION' | translate }}</mat-label> <mat-label>{{ 'ORG.POLICY.DATA.DESCRIPTION' | translate }}</mat-label>
<input matInput name="description" ngDefaultControl [(ngModel)]="complexityData.description" <input matInput name="description" ngDefaultControl [(ngModel)]="complexityData.description"
@@ -98,7 +98,7 @@
</div> </div>
</div> </div>
<div class="content" *ngIf="policyType === PolicyComponentType?.AGE"> <div class="content" *ngIf="policyType === PolicyComponentType?.AGE && ageData">
<mat-form-field class="description-formfield" appearance="outline"> <mat-form-field class="description-formfield" appearance="outline">
<mat-label>{{ 'ORG.POLICY.DATA.DESCRIPTION' | translate }}</mat-label> <mat-label>{{ 'ORG.POLICY.DATA.DESCRIPTION' | translate }}</mat-label>
<input matInput name="description" ngDefaultControl [(ngModel)]="ageData.description" <input matInput name="description" ngDefaultControl [(ngModel)]="ageData.description"
@@ -133,7 +133,7 @@
</div> </div>
</div> </div>
<div class="content" *ngIf="policyType === PolicyComponentType?.IAM_POLICY"> <div class="content" *ngIf="policyType === PolicyComponentType?.IAM_POLICY && iamData">
<mat-form-field class="description-formfield" appearance="outline"> <mat-form-field class="description-formfield" appearance="outline">
<mat-label>{{ 'ORG.POLICY.DATA.DESCRIPTION' | translate }}</mat-label> <mat-label>{{ 'ORG.POLICY.DATA.DESCRIPTION' | translate }}</mat-label>
<input matInput name="description" ngDefaultControl [(ngModel)]="iamData.description" <input matInput name="description" ngDefaultControl [(ngModel)]="iamData.description"

View File

@@ -3,6 +3,12 @@ import { FormGroup } from '@angular/forms';
import { ActivatedRoute, Router } from '@angular/router'; import { ActivatedRoute, Router } from '@angular/router';
import { BehaviorSubject, Subscription } from 'rxjs'; import { BehaviorSubject, Subscription } from 'rxjs';
import { switchMap } from 'rxjs/operators'; import { switchMap } from 'rxjs/operators';
import {
OrgIamPolicy,
PasswordAgePolicy,
PasswordComplexityPolicy,
PasswordLockoutPolicy,
} from 'src/app/proto/generated/management_pb';
import { AdminService } from 'src/app/services/admin.service'; import { AdminService } from 'src/app/services/admin.service';
import { OrgService } from 'src/app/services/org.service'; import { OrgService } from 'src/app/services/org.service';
import { StorageService } from 'src/app/services/storage.service'; import { StorageService } from 'src/app/services/storage.service';
@@ -39,31 +45,10 @@ export class PasswordPolicyComponent implements OnInit, OnDestroy {
public lockoutForm!: FormGroup; public lockoutForm!: FormGroup;
public ageForm!: FormGroup; public ageForm!: FormGroup;
public complexityData: any = { public complexityData!: PasswordComplexityPolicy.AsObject;
minLength: 8, public lockoutData!: PasswordLockoutPolicy.AsObject;
description: '', public ageData!: PasswordAgePolicy.AsObject;
hasNumber: true, public iamData!: OrgIamPolicy.AsObject;
hasSymbol: true,
hasLowercase: true,
hasUppercase: true,
};
public lockoutData: any = {
description: '',
maxAttempts: 5,
showLockOutFailures: true,
};
public ageData: any = {
description: '',
expireWarnDays: 80,
maxAgeDays: 90,
};
public iamData: any = {
description: '',
userLoginMustBeDomain: false,
};
private sub: Subscription = new Subscription(); private sub: Subscription = new Subscription();
@@ -102,19 +87,21 @@ export class PasswordPolicyComponent implements OnInit, OnDestroy {
if (this.componentAction === PolicyComponentAction.MODIFY) { if (this.componentAction === PolicyComponentAction.MODIFY) {
this.getData(params).then(data => { this.getData(params).then(data => {
switch (this.policyType) { if (data) {
case PolicyComponentType.LOCKOUT: switch (this.policyType) {
this.lockoutData = data.toObject(); case PolicyComponentType.LOCKOUT:
break; this.lockoutData = data.toObject() as PasswordLockoutPolicy.AsObject;
case PolicyComponentType.AGE: break;
this.ageData = data.toObject(); case PolicyComponentType.AGE:
break; this.ageData = data.toObject() as PasswordAgePolicy.AsObject;
case PolicyComponentType.COMPLEXITY: break;
this.complexityData = data.toObject(); case PolicyComponentType.COMPLEXITY:
break; this.complexityData = data.toObject() as PasswordComplexityPolicy.AsObject;
case PolicyComponentType.IAM_POLICY: break;
this.iamData = data.toObject(); case PolicyComponentType.IAM_POLICY:
break; this.iamData = data.toObject() as OrgIamPolicy.AsObject;
break;
}
} }
}); });
} }
@@ -128,7 +115,8 @@ export class PasswordPolicyComponent implements OnInit, OnDestroy {
this.sub.unsubscribe(); this.sub.unsubscribe();
} }
private async getData(params: any): Promise<any> { private async getData(params: any):
Promise<PasswordLockoutPolicy | PasswordAgePolicy | PasswordComplexityPolicy | OrgIamPolicy | undefined> {
switch (params.policytype) { switch (params.policytype) {
case PolicyComponentType.LOCKOUT: case PolicyComponentType.LOCKOUT:
this.titleSub.next('ORG.POLICY.PWD_LOCKOUT.TITLE'); this.titleSub.next('ORG.POLICY.PWD_LOCKOUT.TITLE');
@@ -270,8 +258,8 @@ export class PasswordPolicyComponent implements OnInit, OnDestroy {
if (orgId) { if (orgId) {
this.adminService.CreateOrgIamPolicy( this.adminService.CreateOrgIamPolicy(
orgId, orgId,
this.complexityData.description, this.iamData.description,
this.complexityData.userLoginMustBeDomain, this.iamData.userLoginMustBeDomain,
).then(() => { ).then(() => {
this.router.navigate(['org']); this.router.navigate(['org']);
}).catch(error => { }).catch(error => {
@@ -326,8 +314,8 @@ export class PasswordPolicyComponent implements OnInit, OnDestroy {
if (orgId) { if (orgId) {
this.adminService.UpdateOrgIamPolicy( this.adminService.UpdateOrgIamPolicy(
orgId, orgId,
this.complexityData.description, this.iamData.description,
this.complexityData.userLoginMustBeDomain, this.iamData.userLoginMustBeDomain,
).then(() => { ).then(() => {
this.router.navigate(['org']); this.router.navigate(['org']);
}).catch(error => { }).catch(error => {

View File

@@ -104,9 +104,8 @@ export class AppCreateComponent implements OnInit, OnDestroy {
.then((data: Application) => { .then((data: Application) => {
this.showSavedDialog(data.toObject()); this.showSavedDialog(data.toObject());
}) })
.catch(data => { .catch(error => {
console.error(data); this.toast.showError(error);
this.toast.showError(data.message);
}); });
} }

View File

@@ -36,10 +36,10 @@
</app-card> </app-card>
<app-card title="{{ 'APP.OIDC.TITLE' | translate }}" *ngIf="app && app.oidcConfig"> <app-card title="{{ 'APP.OIDC.TITLE' | translate }}" *ngIf="app && app.oidcConfig">
<card-actions class="card-actions"> <div class="card-actions" card-actions>
<button mat-stroked-button <button mat-stroked-button
(click)="regenerateOIDCClientSecret()">{{'APP.OIDC.REGENERATESECRET' | translate}}</button> (click)="regenerateOIDCClientSecret()">{{'APP.OIDC.REGENERATESECRET' | translate}}</button>
</card-actions> </div>
<form *ngIf="appForm" [formGroup]="appForm" (ngSubmit)="saveOIDCApp()"> <form *ngIf="appForm" [formGroup]="appForm" (ngSubmit)="saveOIDCApp()">
<div class="content"> <div class="content">
<mat-form-field appearance="outline"> <mat-form-field appearance="outline">

View File

@@ -17,7 +17,6 @@ import {
OIDCGrantType, OIDCGrantType,
OIDCResponseType, OIDCResponseType,
} from 'src/app/proto/generated/management_pb'; } from 'src/app/proto/generated/management_pb';
import { GrpcService } from 'src/app/services/grpc.service';
import { OrgService } from 'src/app/services/org.service'; import { OrgService } from 'src/app/services/org.service';
import { ProjectService } from 'src/app/services/project.service'; import { ProjectService } from 'src/app/services/project.service';
import { ToastService } from 'src/app/services/toast.service'; import { ToastService } from 'src/app/services/toast.service';
@@ -84,7 +83,6 @@ export class AppDetailComponent implements OnInit, OnDestroy {
private fb: FormBuilder, private fb: FormBuilder,
private _location: Location, private _location: Location,
private dialog: MatDialog, private dialog: MatDialog,
private grpcService: GrpcService,
private orgService: OrgService, private orgService: OrgService,
) { ) {
this.appNameForm = this.fb.group({ this.appNameForm = this.fb.group({
@@ -224,8 +222,8 @@ export class AppDetailComponent implements OnInit, OnDestroy {
.then((data: OIDCConfig) => { .then((data: OIDCConfig) => {
this.toast.showInfo('APP.TOAST.OIDCUPDATED', true); this.toast.showInfo('APP.TOAST.OIDCUPDATED', true);
}) })
.catch(data => { .catch(error => {
this.toast.showError(data.message); this.toast.showError(error);
}); });
} }
} }

View File

@@ -1,5 +1,5 @@
import { CommonModule } from '@angular/common'; import { CommonModule } from '@angular/common';
import { CUSTOM_ELEMENTS_SCHEMA, NgModule, NO_ERRORS_SCHEMA } from '@angular/core'; import { NgModule } from '@angular/core';
import { FormsModule, ReactiveFormsModule } from '@angular/forms'; import { FormsModule, ReactiveFormsModule } from '@angular/forms';
import { MatButtonModule } from '@angular/material/button'; import { MatButtonModule } from '@angular/material/button';
import { MatButtonToggleModule } from '@angular/material/button-toggle'; import { MatButtonToggleModule } from '@angular/material/button-toggle';
@@ -53,6 +53,5 @@ import { AppsRoutingModule } from './apps-routing.module';
TranslateModule, TranslateModule,
], ],
exports: [TranslateModule], exports: [TranslateModule],
schemas: [CUSTOM_ELEMENTS_SCHEMA, NO_ERRORS_SCHEMA],
}) })
export class AppsModule { } export class AppsModule { }

View File

@@ -12,17 +12,18 @@
</div> </div>
</div> </div>
<!-- <ng-template appHasRole [appHasRole]="['project.grant.user.grant.read']"> --> <ng-template appHasRole [appHasRole]="['project.grant.user.grant.read']">
<app-card *ngIf="project?.projectId" title="{{ 'GRANTS.PROJECT.TITLE' | translate }}" <app-card *ngIf="project?.projectId" title="{{ 'GRANTS.PROJECT.TITLE' | translate }}"
description="{{'GRANTS.PROJECT.DESCRIPTION' | translate }}"> description="{{'GRANTS.PROJECT.DESCRIPTION' | translate }}">
<app-user-grants [context]="userGrantContext" [projectId]="projectId" [grantId]="grantId" <app-user-grants [context]="userGrantContext" [projectId]="projectId" [grantId]="grantId"
[allowCreate]="['project.grant.user.grant.write'] | hasRole" [displayedColumns]="['select', 'projectId', 'creationDate', 'changeDate', 'roleNamesList']"
[allowDelete]="['project.grant.user.grant.delete'] | hasRole"> [allowCreate]="['project.grant.user.grant.write'] | hasRole | async"
</app-user-grants> [allowDelete]="['project.grant.user.grant.delete'] | hasRole | async">
</app-card> </app-user-grants>
<!-- </ng-template> --> </app-card>
</ng-template>
</div> </div>
<metainfo class="side"> <div class="side" metainfo>
<div class="details"> <div class="details">
<div class="row"> <div class="row">
<span class="first">{{'PROJECT.STATE.TITLE' | translate}}:</span> <span class="first">{{'PROJECT.STATE.TITLE' | translate}}:</span>
@@ -42,5 +43,5 @@
<app-changes *ngIf="project" [changeType]="ChangeType.PROJECT" [id]="project.id"></app-changes> <app-changes *ngIf="project" [changeType]="ChangeType.PROJECT" [id]="project.id"></app-changes>
</mat-tab> </mat-tab>
</mat-tab-group> </mat-tab-group>
</metainfo> </div>
</app-meta-layout> </app-meta-layout>

View File

@@ -91,7 +91,6 @@ export class GrantedProjectDetailComponent implements OnInit, OnDestroy {
if (this.projectId && this.grantId) { if (this.projectId && this.grantId) {
this.projectService.GetGrantedProjectByID(this.projectId, this.grantId).then(proj => { this.projectService.GetGrantedProjectByID(this.projectId, this.grantId).then(proj => {
this.project = proj.toObject(); this.project = proj.toObject();
console.log('granted-project', this.project);
}).catch(error => { }).catch(error => {
this.toast.showError(error); this.toast.showError(error);
}); });

View File

@@ -106,9 +106,9 @@ export class GrantedProjectListComponent implements OnInit, OnDestroy {
}); });
Promise.all(promises).then(() => { Promise.all(promises).then(() => {
this.toast.showInfo('Reactivated selected projects successfully'); this.toast.showInfo('PROJECT.TOAST.REACTIVATED', true);
}).catch(error => { }).catch(error => {
this.toast.showInfo(error.message); this.toast.showError(error);
}); });
} }
@@ -119,9 +119,9 @@ export class GrantedProjectListComponent implements OnInit, OnDestroy {
}); });
Promise.all(promises).then(() => { Promise.all(promises).then(() => {
this.toast.showInfo('Deactivated selected projects Successfully'); this.toast.showInfo('PROJECT.TOAST.DEACTIVATED', true);
}).catch(error => { }).catch(error => {
this.toast.showInfo(error.message); this.toast.showError(error);
}); });
} }
} }

View File

@@ -25,6 +25,7 @@ const routes: Routes = [
path: ':projectid/grant/:grantid/members', path: ':projectid/grant/:grantid/members',
data: { data: {
type: ProjectType.PROJECTTYPE_GRANTED, type: ProjectType.PROJECTTYPE_GRANTED,
roles: ['project.grant.member.read'],
}, },
loadChildren: () => import('src/app/modules/project-members/project-members.module') loadChildren: () => import('src/app/modules/project-members/project-members.module')
.then(m => m.ProjectMembersModule), .then(m => m.ProjectMembersModule),
@@ -37,7 +38,10 @@ const routes: Routes = [
{ {
path: ':projectid/roles/create', path: ':projectid/roles/create',
loadChildren: () => import('../project-role-create/project-role-create.module').then(m => m.ProjectRoleCreateModule), loadChildren: () => import('../project-role-create/project-role-create.module').then(m => m.ProjectRoleCreateModule),
canActivate: [RoleGuard],
data: {
roles: ['project.write'],
},
}, },
{ {
path: ':projectid/grants/create', path: ':projectid/grants/create',

View File

@@ -1,5 +1,5 @@
import { CommonModule } from '@angular/common'; import { CommonModule } from '@angular/common';
import { NgModule, NO_ERRORS_SCHEMA } from '@angular/core'; import { NgModule } from '@angular/core';
import { FormsModule, ReactiveFormsModule } from '@angular/forms'; import { FormsModule, ReactiveFormsModule } from '@angular/forms';
import { MatButtonModule } from '@angular/material/button'; import { MatButtonModule } from '@angular/material/button';
import { MatCheckboxModule } from '@angular/material/checkbox'; import { MatCheckboxModule } from '@angular/material/checkbox';
@@ -21,11 +21,13 @@ import { ChangesModule } from 'src/app/modules/changes/changes.module';
import { MetaLayoutModule } from 'src/app/modules/meta-layout/meta-layout.module'; import { MetaLayoutModule } from 'src/app/modules/meta-layout/meta-layout.module';
import { ProjectContributorsModule } from 'src/app/modules/project-contributors/project-contributors.module'; import { ProjectContributorsModule } from 'src/app/modules/project-contributors/project-contributors.module';
import { ProjectRolesModule } from 'src/app/modules/project-roles/project-roles.module'; import { ProjectRolesModule } from 'src/app/modules/project-roles/project-roles.module';
import { SharedModule } from 'src/app/modules/shared/shared.module';
import { UserGrantsModule } from 'src/app/modules/user-grants/user-grants.module'; import { UserGrantsModule } from 'src/app/modules/user-grants/user-grants.module';
import { PipesModule } from 'src/app/pipes/pipes.module'; import { HasRolePipeModule } from 'src/app/pipes/has-role-pipe.module';
import { TimestampToDatePipeModule } from 'src/app/pipes/timestamp-to-date-pipe.module';
import { GrantedProjectDetailComponent } from './granted-project-detail/granted-project-detail.component'; import { GrantedProjectDetailComponent } from './granted-project-detail/granted-project-detail.component';
import { GrantedProjectGridComponent } from './granted-project-grid/granted-project-grid.component'; import { GrantedProjectGridComponent } from './granted-project-list/granted-project-grid/granted-project-grid.component';
import { GrantedProjectListComponent } from './granted-project-list/granted-project-list.component'; import { GrantedProjectListComponent } from './granted-project-list/granted-project-list.component';
import { GrantedProjectsRoutingModule } from './granted-projects-routing.module'; import { GrantedProjectsRoutingModule } from './granted-projects-routing.module';
import { GrantedProjectsComponent } from './granted-projects.component'; import { GrantedProjectsComponent } from './granted-projects.component';
@@ -63,9 +65,10 @@ import { GrantedProjectsComponent } from './granted-projects.component';
CardModule, CardModule,
MatTooltipModule, MatTooltipModule,
MatSortModule, MatSortModule,
PipesModule, HasRolePipeModule,
TranslateModule, TranslateModule,
TimestampToDatePipeModule,
SharedModule,
], ],
schemas: [NO_ERRORS_SCHEMA],
}) })
export class GrantedProjectsModule { } export class GrantedProjectsModule { }

View File

@@ -1,20 +1,20 @@
import { async, ComponentFixture, TestBed } from '@angular/core/testing'; import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { ProjectApplicationGridComponent } from './project-application-grid.component'; import { ApplicationGridComponent } from './application-grid.component';
describe('AppGridComponent', () => { describe('AppGridComponent', () => {
let component: ProjectApplicationGridComponent; let component: ApplicationGridComponent;
let fixture: ComponentFixture<ProjectApplicationGridComponent>; let fixture: ComponentFixture<ApplicationGridComponent>;
beforeEach(async(() => { beforeEach(async(() => {
TestBed.configureTestingModule({ TestBed.configureTestingModule({
declarations: [ProjectApplicationGridComponent], declarations: [ApplicationGridComponent],
}) })
.compileComponents(); .compileComponents();
})); }));
beforeEach(() => { beforeEach(() => {
fixture = TestBed.createComponent(ProjectApplicationGridComponent); fixture = TestBed.createComponent(ApplicationGridComponent);
component = fixture.componentInstance; component = fixture.componentInstance;
fixture.detectChanges(); fixture.detectChanges();
}); });

View File

@@ -5,11 +5,11 @@ import { Application } from 'src/app/proto/generated/management_pb';
import { ProjectService } from 'src/app/services/project.service'; import { ProjectService } from 'src/app/services/project.service';
@Component({ @Component({
selector: 'app-project-application-grid', selector: 'app-application-grid',
templateUrl: './project-application-grid.component.html', templateUrl: './application-grid.component.html',
styleUrls: ['./project-application-grid.component.scss'], styleUrls: ['./application-grid.component.scss'],
}) })
export class ProjectApplicationGridComponent implements OnInit { export class ApplicationGridComponent implements OnInit {
@Input() public projectId: string = ''; @Input() public projectId: string = '';
@Input() public disabled: boolean = false; @Input() public disabled: boolean = false;
@Output() public changeView: EventEmitter<void> = new EventEmitter(); @Output() public changeView: EventEmitter<void> = new EventEmitter();

View File

@@ -10,10 +10,6 @@
</ng-container> </ng-container>
</div> </div>
<span class="fill-space"></span> <span class="fill-space"></span>
<!-- <button [disabled]="disabled" matTooltip="{{'ORG_DETAIL.TABLE.DELETE' | translate}}" class="icon-button"
mat-icon-button *ngIf="selection.hasValue()">
<i class="las la-trash"></i>
</button> -->
<ng-template appHasRole [appHasRole]="['project.app.write']"> <ng-template appHasRole [appHasRole]="['project.app.write']">
<a [disabled]="disabled" class="add-button" [routerLink]="[ '/projects', projectId, 'apps', 'create']" <a [disabled]="disabled" class="add-button" [routerLink]="[ '/projects', projectId, 'apps', 'create']"
color="primary" mat-raised-button> color="primary" mat-raised-button>

View File

@@ -0,0 +1,34 @@
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { MatPaginatorModule } from '@angular/material/paginator';
import { MatSortModule } from '@angular/material/sort';
import { MatTableModule } from '@angular/material/table';
import { NoopAnimationsModule } from '@angular/platform-browser/animations';
import { ApplicationsComponent } from './applications.component';
describe('ProjectApplicationsComponent', () => {
let component: ApplicationsComponent;
let fixture: ComponentFixture<ApplicationsComponent>;
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [ApplicationsComponent],
imports: [
NoopAnimationsModule,
MatPaginatorModule,
MatSortModule,
MatTableModule,
],
}).compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(ApplicationsComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should compile', () => {
expect(component).toBeTruthy();
});
});

View File

@@ -9,15 +9,15 @@ import { Application } from 'src/app/proto/generated/management_pb';
import { ProjectService } from 'src/app/services/project.service'; import { ProjectService } from 'src/app/services/project.service';
import { ToastService } from 'src/app/services/toast.service'; import { ToastService } from 'src/app/services/toast.service';
import { ProjectApplicationsDataSource } from './project-applications-datasource'; import { ProjectApplicationsDataSource } from './applications-datasource';
@Component({ @Component({
selector: 'app-project-applications', selector: 'app-applications',
templateUrl: './project-applications.component.html', templateUrl: './applications.component.html',
styleUrls: ['./project-applications.component.scss'], styleUrls: ['./applications.component.scss'],
}) })
export class ProjectApplicationsComponent implements AfterViewInit, OnInit { export class ApplicationsComponent implements AfterViewInit, OnInit {
@Input() public projectId: string = ''; @Input() public projectId: string = '';
@Input() public disabled: boolean = false; @Input() public disabled: boolean = false;
@ViewChild(MatPaginator) public paginator!: MatPaginator; @ViewChild(MatPaginator) public paginator!: MatPaginator;

View File

@@ -0,0 +1,23 @@
import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';
import { RoleGuard } from 'src/app/guards/role.guard';
import { OwnedProjectDetailComponent } from './owned-project-detail.component';
const routes: Routes = [
{
path: '',
component: OwnedProjectDetailComponent,
data: {
animation: 'HomePage',
roles: ['project.read'],
},
canActivate: [RoleGuard],
},
];
@NgModule({
imports: [RouterModule.forChild(routes)],
exports: [RouterModule],
})
export class OwnedProjectDetailRoutingModule { }

View File

@@ -43,18 +43,17 @@
<ng-container *ngIf="project"> <ng-container *ngIf="project">
<ng-template appHasRole [appHasRole]="['project.app.read:' + project.projectId, 'project.app.read']"> <ng-template appHasRole [appHasRole]="['project.app.read:' + project.projectId, 'project.app.read']">
<app-project-application-grid *ngIf="grid" <app-application-grid *ngIf="grid"
[disabled]="project?.state !== ProjectState.PROJECTSTATE_ACTIVE || isZitadel" [disabled]="project?.state !== ProjectState.PROJECTSTATE_ACTIVE || isZitadel"
(changeView)="grid = false" [projectId]="projectId"></app-project-application-grid> (changeView)="grid = false" [projectId]="projectId"></app-application-grid>
<app-card *ngIf="!grid" title="{{ 'PROJECT.APP.TITLE' | translate }}"> <app-card *ngIf="!grid" title="{{ 'PROJECT.APP.TITLE' | translate }}">
<card-actions class="card-actions"> <div class="card-actions" card-actions>
<button mat-icon-button (click)="grid = true"> <button mat-icon-button (click)="grid = true">
<i matTooltip="show grid view" class="las la-th-large"></i> <i matTooltip="show grid view" class="las la-th-large"></i>
</button> </button>
</card-actions> </div>
<app-project-applications <app-applications [disabled]="project?.state !== ProjectState.PROJECTSTATE_ACTIVE || isZitadel"
[disabled]="project?.state !== ProjectState.PROJECTSTATE_ACTIVE || isZitadel" [projectId]="projectId"></app-applications>
[projectId]="projectId"></app-project-applications>
</app-card> </app-card>
</ng-template> </ng-template>
@@ -83,15 +82,15 @@
description="{{'GRANTS.PROJECT.DESCRIPTION' | translate }}"> description="{{'GRANTS.PROJECT.DESCRIPTION' | translate }}">
<app-user-grants [context]="userGrantContext" [projectId]="projectId" <app-user-grants [context]="userGrantContext" [projectId]="projectId"
[disabled]="project?.state !== ProjectState.PROJECTSTATE_ACTIVE" [disabled]="project?.state !== ProjectState.PROJECTSTATE_ACTIVE"
[allowCreate]="project?.state == ProjectState.PROJECTSTATE_ACTIVE && (['user.grant.write'] | hasRole)" [allowCreate]="project?.state == ProjectState.PROJECTSTATE_ACTIVE && (['user.grant.write'] | hasRole | async)"
[allowDelete]="project?.state == ProjectState.PROJECTSTATE_ACTIVE && (['user.grant.delete'] | hasRole)"> [allowDelete]="project?.state == ProjectState.PROJECTSTATE_ACTIVE && (['user.grant.delete'] | hasRole | async)">
</app-user-grants> </app-user-grants>
</app-card> </app-card>
</ng-template> </ng-template>
</ng-container> </ng-container>
</ng-container> </ng-container>
</div> </div>
<metainfo class="side"> <div class="side" metainfo>
<div class="details"> <div class="details">
<div class="row"> <div class="row">
<span class="first">{{'PROJECT.STATE.TITLE' | translate}}:</span> <span class="first">{{'PROJECT.STATE.TITLE' | translate}}:</span>
@@ -111,5 +110,5 @@
<app-changes *ngIf="project" [changeType]="ChangeType.PROJECT" [id]="project.projectId"></app-changes> <app-changes *ngIf="project" [changeType]="ChangeType.PROJECT" [id]="project.projectId"></app-changes>
</mat-tab> </mat-tab>
</mat-tab-group> </mat-tab-group>
</metainfo> </div>
</app-meta-layout> </app-meta-layout>

View File

@@ -114,7 +114,7 @@ export class OwnedProjectDetailComponent implements OnInit, OnDestroy {
dialogRef.afterClosed().subscribe(resp => { dialogRef.afterClosed().subscribe(resp => {
if (resp) { if (resp) {
this.projectService.ReactivateProject(this.projectId).then(() => { this.projectService.ReactivateProject(this.projectId).then(() => {
this.toast.showInfo('Reactivated Project'); this.toast.showInfo('PROJECT.TOAST.REACTIVATED', true);
this.project.state = ProjectState.PROJECTSTATE_ACTIVE; this.project.state = ProjectState.PROJECTSTATE_ACTIVE;
}).catch(error => { }).catch(error => {
this.toast.showError(error); this.toast.showError(error);
@@ -135,7 +135,7 @@ export class OwnedProjectDetailComponent implements OnInit, OnDestroy {
dialogRef.afterClosed().subscribe(resp => { dialogRef.afterClosed().subscribe(resp => {
if (resp) { if (resp) {
this.projectService.DeactivateProject(this.projectId).then(() => { this.projectService.DeactivateProject(this.projectId).then(() => {
this.toast.showInfo('Deactivated Project'); this.toast.showInfo('PROJECT.TOAST.DEACTIVATED', true);
this.project.state = ProjectState.PROJECTSTATE_INACTIVE; this.project.state = ProjectState.PROJECTSTATE_INACTIVE;
}).catch(error => { }).catch(error => {
this.toast.showError(error); this.toast.showError(error);
@@ -147,9 +147,9 @@ export class OwnedProjectDetailComponent implements OnInit, OnDestroy {
public saveProject(): void { public saveProject(): void {
this.projectService.UpdateProject(this.project.projectId, this.project.name).then(() => { this.projectService.UpdateProject(this.project.projectId, this.project.name).then(() => {
this.toast.showInfo('Project updated'); this.toast.showInfo('PROJECT.TOAST.UPDATED', true);
}).catch(error => { }).catch(error => {
this.toast.showInfo(error.message); this.toast.showError(error);
}); });
} }

View File

@@ -0,0 +1,64 @@
import { CommonModule } from '@angular/common';
import { NgModule } from '@angular/core';
import { FormsModule } from '@angular/forms';
import { MatButtonModule } from '@angular/material/button';
import { MatCheckboxModule } from '@angular/material/checkbox';
import { MatFormFieldModule } from '@angular/material/form-field';
import { MatIconModule } from '@angular/material/icon';
import { MatPaginatorModule } from '@angular/material/paginator';
import { MatProgressSpinnerModule } from '@angular/material/progress-spinner';
import { MatSelectModule } from '@angular/material/select';
import { MatTableModule } from '@angular/material/table';
import { MatTabsModule } from '@angular/material/tabs';
import { TranslateModule } from '@ngx-translate/core';
import { HasRoleModule } from 'src/app/directives/has-role/has-role.module';
import { CardModule } from 'src/app/modules/card/card.module';
import { ChangesModule } from 'src/app/modules/changes/changes.module';
import { MetaLayoutModule } from 'src/app/modules/meta-layout/meta-layout.module';
import { ProjectContributorsModule } from 'src/app/modules/project-contributors/project-contributors.module';
import { ProjectRolesModule } from 'src/app/modules/project-roles/project-roles.module';
import { UserGrantsModule } from 'src/app/modules/user-grants/user-grants.module';
import { WarnDialogModule } from 'src/app/modules/warn-dialog/warn-dialog.module';
import { HasRolePipeModule } from 'src/app/pipes/has-role-pipe.module';
import { TimestampToDatePipeModule } from 'src/app/pipes/timestamp-to-date-pipe.module';
import { ApplicationGridComponent } from './application-grid/application-grid.component';
import { ApplicationsComponent } from './applications/applications.component';
import { OwnedProjectDetailRoutingModule } from './owned-project-detail-routing.module';
import { OwnedProjectDetailComponent } from './owned-project-detail.component';
import { ProjectGrantsComponent } from './project-grants/project-grants.component';
@NgModule({
declarations: [
OwnedProjectDetailComponent,
ApplicationGridComponent,
ApplicationsComponent,
ProjectGrantsComponent,
],
imports: [
CommonModule,
FormsModule,
OwnedProjectDetailRoutingModule,
TranslateModule,
HasRoleModule,
MatTabsModule,
MatButtonModule,
MatIconModule,
ProjectContributorsModule,
WarnDialogModule,
ProjectRolesModule,
HasRolePipeModule,
UserGrantsModule,
TimestampToDatePipeModule,
MatTableModule,
MatFormFieldModule,
CardModule,
MatPaginatorModule,
MatCheckboxModule,
MatSelectModule,
MatProgressSpinnerModule,
ChangesModule,
MetaLayoutModule,
],
})
export class OwnedProjectDetailModule { }

View File

@@ -29,7 +29,6 @@ export class ProjectGrantsDataSource extends DataSource<ProjectGrant.AsObject> {
catchError(() => of([])), catchError(() => of([])),
finalize(() => this.loadingSubject.next(false)), finalize(() => this.loadingSubject.next(false)),
).subscribe(grants => { ).subscribe(grants => {
console.log(grants);
this.grantsSubject.next(grants); this.grantsSubject.next(grants);
}); });
} }

View File

@@ -75,14 +75,13 @@ export class ProjectGrantsComponent implements OnInit, AfterViewInit {
public getRoleOptions(projectId: string): void { public getRoleOptions(projectId: string): void {
this.projectService.SearchProjectRoles(projectId, 100, 0).then(resp => { this.projectService.SearchProjectRoles(projectId, 100, 0).then(resp => {
this.memberRoleOptions = resp.toObject().resultList; this.memberRoleOptions = resp.toObject().resultList;
console.log(resp.toObject());
}); });
} }
updateRoles(grant: ProjectGrant.AsObject, selectionChange: MatSelectChange): void { updateRoles(grant: ProjectGrant.AsObject, selectionChange: MatSelectChange): void {
this.projectService.UpdateProjectGrant(grant.id, grant.projectId, selectionChange.value) this.projectService.UpdateProjectGrant(grant.id, grant.projectId, selectionChange.value)
.then((newgrant: ProjectGrant) => { .then((newgrant: ProjectGrant) => {
this.toast.showInfo('Grant updated!'); this.toast.showInfo('PROJECT.GRANT.TOAST.PROJECTGRANTCHANGED', true);
}).catch(error => { }).catch(error => {
this.toast.showError(error); this.toast.showError(error);
}); });

View File

@@ -1,5 +1,5 @@
<app-owned-project-grid *ngIf="grid" [loading]="loading$ | async" (changedView)="grid = false" <app-owned-project-grid *ngIf="grid" [loading]="loading$ | async" (changedView)="grid = false"
[items]="ownedProjectList" (newClicked)="addProject()"> [items]="ownedProjectList || []" (newClicked)="addProject()">
</app-owned-project-grid> </app-owned-project-grid>
<div *ngIf="!grid" class="view-toggle"> <div *ngIf="!grid" class="view-toggle">
@@ -20,16 +20,6 @@
</ng-container> </ng-container>
</div> </div>
<span class="fill-space"></span> <span class="fill-space"></span>
<div @list class="action-btns" *ngIf="selection.hasValue()">
<button @animate (click)="deactivateSelectedProjects()"
matTooltip="{{'PROJECT.TABLE.DEACTIVATE' | translate}}" class="icon-button" mat-icon-button>
<mat-icon svgIcon="mdi_light_off"></mat-icon>
</button>
<button @animate (click)="reactivateSelectedProjects()"
matTooltip="{{'PROJECT.TABLE.ACTIVATE' | translate}}" class="icon-button" mat-icon-button>
<mat-icon svgIcon="mdi_light_on"></mat-icon>
</button>
</div>
<ng-template appHasRole [appHasRole]="['project.write']"> <ng-template appHasRole [appHasRole]="['project.write']">
<a class="add-button" [routerLink]="[ '/projects', 'create']" color="primary" mat-raised-button> <a class="add-button" [routerLink]="[ '/projects', 'create']" color="primary" mat-raised-button>
<mat-icon class="icon">add</mat-icon>{{ 'ACTIONS.NEW' | translate }} <mat-icon class="icon">add</mat-icon>{{ 'ACTIONS.NEW' | translate }}

View File

@@ -108,9 +108,9 @@ export class OwnedProjectListComponent implements OnInit, OnDestroy {
}); });
Promise.all(promises).then(() => { Promise.all(promises).then(() => {
this.toast.showInfo('Reactivated selected projects successfully'); this.toast.showInfo('PROJECT.TOAST.REACTIVATED', true);
}).catch(error => { }).catch(error => {
this.toast.showInfo(error.message); this.toast.showError(error);
}); });
} }
@@ -121,9 +121,9 @@ export class OwnedProjectListComponent implements OnInit, OnDestroy {
}); });
Promise.all(promises).then(() => { Promise.all(promises).then(() => {
this.toast.showInfo('Deactivated selected projects Successfully'); this.toast.showInfo('PROJECT.TOAST.DEACTIVATED', true);
}).catch(error => { }).catch(error => {
this.toast.showInfo(error.message); this.toast.showError(error);
}); });
} }
} }

View File

@@ -1,10 +1,8 @@
import { NgModule } from '@angular/core'; import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router'; import { RouterModule, Routes } from '@angular/router';
import { AuthGuard } from 'src/app/guards/auth.guard';
import { RoleGuard } from 'src/app/guards/role.guard'; import { RoleGuard } from 'src/app/guards/role.guard';
import { ProjectType } from 'src/app/proto/generated/management_pb'; import { ProjectType } from 'src/app/proto/generated/management_pb';
import { OwnedProjectDetailComponent } from './owned-project-detail/owned-project-detail.component';
import { OwnedProjectsComponent } from './owned-projects.component'; import { OwnedProjectsComponent } from './owned-projects.component';
const routes: Routes = [ const routes: Routes = [
@@ -16,42 +14,60 @@ const routes: Routes = [
{ {
path: 'create', path: 'create',
loadChildren: () => import('../project-create/project-create.module').then(m => m.ProjectCreateModule), loadChildren: () => import('../project-create/project-create.module').then(m => m.ProjectCreateModule),
canActivate: [AuthGuard, RoleGuard], canActivate: [RoleGuard],
data: { data: {
roles: ['project.write'], roles: ['project.write'],
}, },
}, },
{ {
path: ':id', path: ':id',
component: OwnedProjectDetailComponent,
data: { animation: 'HomePage' },
},
{
path: ':projectid/members',
data: { data: {
type: ProjectType.PROJECTTYPE_OWNED, animation: 'HomePage',
roles: ['project.read'],
}, },
loadChildren: () => import('src/app/modules/project-members/project-members.module') canActivate: [RoleGuard],
.then(m => m.ProjectMembersModule), loadChildren: () => import('./owned-project-detail/owned-project-detail.module')
.then(m => m.OwnedProjectDetailModule),
}, },
{ {
path: ':projectid/apps', path: ':projectid',
data: { animation: 'AddPage' }, children: [
loadChildren: () => import('src/app/pages/projects/apps/apps.module').then(m => m.AppsModule), {
}, path: 'members',
{ data: {
path: ':projectid/roles/create', type: ProjectType.PROJECTTYPE_OWNED,
loadChildren: () => import('../project-role-create/project-role-create.module').then(m => m.ProjectRoleCreateModule), roles: ['project.member.read'],
}, },
{ canActivate: [RoleGuard],
path: ':projectid/grants/create', loadChildren: () => import('src/app/modules/project-members/project-members.module')
loadChildren: () => import('../project-grant-create/project-grant-create.module') .then(m => m.ProjectMembersModule),
.then(m => m.ProjectGrantCreateModule), },
}, {
{ path: 'apps',
path: ':projectid/grant/:grantid', data: {
loadChildren: () => import('./project-grant-detail/project-grant-detail.module') animation: 'AddPage',
.then(m => m.ProjectGrantDetailModule), roles: ['project.app.read'],
},
canActivate: [RoleGuard],
loadChildren: () => import('src/app/pages/projects/apps/apps.module')
.then(m => m.AppsModule),
},
{
path: 'roles/create',
loadChildren: () => import('../project-role-create/project-role-create.module')
.then(m => m.ProjectRoleCreateModule),
},
{
path: 'grants/create',
loadChildren: () => import('../project-grant-create/project-grant-create.module')
.then(m => m.ProjectGrantCreateModule),
},
{
path: 'grant/:grantid',
loadChildren: () => import('./project-grant-detail/project-grant-detail.module')
.then(m => m.ProjectGrantDetailModule),
},
],
}, },
]; ];

View File

@@ -1,5 +1,5 @@
import { CommonModule } from '@angular/common'; import { CommonModule } from '@angular/common';
import { NgModule, NO_ERRORS_SCHEMA } from '@angular/core'; import { NgModule } from '@angular/core';
import { FormsModule, ReactiveFormsModule } from '@angular/forms'; import { FormsModule, ReactiveFormsModule } from '@angular/forms';
import { MatButtonModule } from '@angular/material/button'; import { MatButtonModule } from '@angular/material/button';
import { MatCheckboxModule } from '@angular/material/checkbox'; import { MatCheckboxModule } from '@angular/material/checkbox';
@@ -10,47 +10,33 @@ import { MatInputModule } from '@angular/material/input';
import { MatPaginatorModule } from '@angular/material/paginator'; import { MatPaginatorModule } from '@angular/material/paginator';
import { MatProgressBarModule } from '@angular/material/progress-bar'; import { MatProgressBarModule } from '@angular/material/progress-bar';
import { MatProgressSpinnerModule } from '@angular/material/progress-spinner'; import { MatProgressSpinnerModule } from '@angular/material/progress-spinner';
import { MatSelectModule } from '@angular/material/select';
import { MatSortModule } from '@angular/material/sort'; import { MatSortModule } from '@angular/material/sort';
import { MatTableModule } from '@angular/material/table'; import { MatTableModule } from '@angular/material/table';
import { MatTabsModule } from '@angular/material/tabs';
import { MatTooltipModule } from '@angular/material/tooltip'; import { MatTooltipModule } from '@angular/material/tooltip';
import { TranslateModule } from '@ngx-translate/core'; import { TranslateModule } from '@ngx-translate/core';
import { HasRoleModule } from 'src/app/directives/has-role/has-role.module'; import { HasRoleModule } from 'src/app/directives/has-role/has-role.module';
import { AvatarModule } from 'src/app/modules/avatar/avatar.module'; import { AvatarModule } from 'src/app/modules/avatar/avatar.module';
import { CardModule } from 'src/app/modules/card/card.module'; import { CardModule } from 'src/app/modules/card/card.module';
import { ChangesModule } from 'src/app/modules/changes/changes.module'; import { SharedModule } from 'src/app/modules/shared/shared.module';
import { MetaLayoutModule } from 'src/app/modules/meta-layout/meta-layout.module';
import { ProjectContributorsModule } from 'src/app/modules/project-contributors/project-contributors.module';
import { ProjectRolesModule } from 'src/app/modules/project-roles/project-roles.module';
import { UserGrantsModule } from 'src/app/modules/user-grants/user-grants.module'; import { UserGrantsModule } from 'src/app/modules/user-grants/user-grants.module';
import { WarnDialogModule } from 'src/app/modules/warn-dialog/warn-dialog.module'; import { HasRolePipeModule } from 'src/app/pipes/has-role-pipe.module';
import { PipesModule } from 'src/app/pipes/pipes.module'; import { TimestampToDatePipeModule } from 'src/app/pipes/timestamp-to-date-pipe.module';
import { OwnedProjectDetailComponent } from './owned-project-detail/owned-project-detail.component'; import { OwnedProjectGridComponent } from './owned-project-list/owned-project-grid/owned-project-grid.component';
import { OwnedProjectGridComponent } from './owned-project-grid/owned-project-grid.component';
import { OwnedProjectListComponent } from './owned-project-list/owned-project-list.component'; import { OwnedProjectListComponent } from './owned-project-list/owned-project-list.component';
import { OwnedProjectsRoutingModule } from './owned-projects-routing.module'; import { OwnedProjectsRoutingModule } from './owned-projects-routing.module';
import { OwnedProjectsComponent } from './owned-projects.component'; import { OwnedProjectsComponent } from './owned-projects.component';
import { ProjectApplicationGridComponent } from './project-application-grid/project-application-grid.component';
import { ProjectApplicationsComponent } from './project-applications/project-applications.component';
import { ProjectGrantsComponent } from './project-grants/project-grants.component';
@NgModule({ @NgModule({
declarations: [ declarations: [
OwnedProjectsComponent, OwnedProjectsComponent,
OwnedProjectListComponent, OwnedProjectListComponent,
OwnedProjectGridComponent, OwnedProjectGridComponent,
OwnedProjectDetailComponent,
ProjectApplicationGridComponent,
ProjectApplicationsComponent,
ProjectGrantsComponent,
], ],
imports: [ imports: [
CommonModule, CommonModule,
OwnedProjectsRoutingModule, OwnedProjectsRoutingModule,
UserGrantsModule, UserGrantsModule,
ProjectContributorsModule,
FormsModule, FormsModule,
ReactiveFormsModule, ReactiveFormsModule,
TranslateModule, TranslateModule,
@@ -61,24 +47,18 @@ import { ProjectGrantsComponent } from './project-grants/project-grants.componen
MatPaginatorModule, MatPaginatorModule,
MatFormFieldModule, MatFormFieldModule,
MatInputModule, MatInputModule,
ChangesModule,
MatChipsModule, MatChipsModule,
MatIconModule, MatIconModule,
MatButtonModule, MatButtonModule,
WarnDialogModule,
MatProgressSpinnerModule, MatProgressSpinnerModule,
MetaLayoutModule,
MatProgressBarModule, MatProgressBarModule,
ProjectRolesModule,
MatTabsModule,
MatCheckboxModule, MatCheckboxModule,
CardModule, CardModule,
MatSelectModule,
MatTooltipModule, MatTooltipModule,
MatSortModule, MatSortModule,
PipesModule, HasRolePipeModule,
TranslateModule, TimestampToDatePipeModule,
SharedModule,
], ],
schemas: [NO_ERRORS_SCHEMA],
}) })
export class OwnedProjectsModule { } export class OwnedProjectsModule { }

View File

@@ -1,34 +0,0 @@
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { MatPaginatorModule } from '@angular/material/paginator';
import { MatSortModule } from '@angular/material/sort';
import { MatTableModule } from '@angular/material/table';
import { NoopAnimationsModule } from '@angular/platform-browser/animations';
import { ProjectApplicationsComponent } from './project-applications.component';
describe('ProjectApplicationsComponent', () => {
let component: ProjectApplicationsComponent;
let fixture: ComponentFixture<ProjectApplicationsComponent>;
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [ProjectApplicationsComponent],
imports: [
NoopAnimationsModule,
MatPaginatorModule,
MatSortModule,
MatTableModule,
],
}).compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(ProjectApplicationsComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should compile', () => {
expect(component).toBeTruthy();
});
});

View File

@@ -80,7 +80,7 @@ export class ProjectGrantDetailComponent {
updateRoles(selectionChange: MatSelectChange): void { updateRoles(selectionChange: MatSelectChange): void {
this.projectService.UpdateProjectGrant(this.grant.id, this.grant.projectId, selectionChange.value) this.projectService.UpdateProjectGrant(this.grant.id, this.grant.projectId, selectionChange.value)
.then((newgrant: ProjectGrant) => { .then((newgrant: ProjectGrant) => {
this.toast.showInfo('Grant updated!'); this.toast.showInfo('PROJECT.TOAST.GRANTUPDATED');
}).catch(error => { }).catch(error => {
this.toast.showError(error); this.toast.showError(error);
}); });

View File

@@ -9,8 +9,6 @@ import { MatFormFieldModule } from '@angular/material/form-field';
import { MatIconModule } from '@angular/material/icon'; import { MatIconModule } from '@angular/material/icon';
import { MatPaginatorModule } from '@angular/material/paginator'; import { MatPaginatorModule } from '@angular/material/paginator';
import { MatProgressSpinnerModule } from '@angular/material/progress-spinner'; import { MatProgressSpinnerModule } from '@angular/material/progress-spinner';
import { MatSelectModule } from '@angular/material/select';
import { MatSortModule } from '@angular/material/sort';
import { MatTableModule } from '@angular/material/table'; import { MatTableModule } from '@angular/material/table';
import { MatTooltipModule } from '@angular/material/tooltip'; import { MatTooltipModule } from '@angular/material/tooltip';
import { TranslateModule } from '@ngx-translate/core'; import { TranslateModule } from '@ngx-translate/core';
@@ -36,8 +34,6 @@ import { ProjectGrantMembersModule } from './project-grant-members/project-grant
MatTableModule, MatTableModule,
MatPaginatorModule, MatPaginatorModule,
MatFormFieldModule, MatFormFieldModule,
MatSelectModule,
MatSortModule,
MatTooltipModule, MatTooltipModule,
ReactiveFormsModule, ReactiveFormsModule,
MatProgressSpinnerModule, MatProgressSpinnerModule,

View File

@@ -87,7 +87,7 @@ export class ProjectGrantMembersComponent implements AfterViewInit, OnInit {
public removeProjectMemberSelection(): void { public removeProjectMemberSelection(): void {
Promise.all(this.selection.selected.map(member => { Promise.all(this.selection.selected.map(member => {
return this.projectService.RemoveProjectGrantMember(this.projectId, this.grantId, member.userId).then(() => { return this.projectService.RemoveProjectGrantMember(this.projectId, this.grantId, member.userId).then(() => {
this.toast.showInfo('Removed successfully'); this.toast.showInfo('PROJECT.GRANT.TOAST.PROJECTGRANTMEMBERREMOVED', true);
}).catch(error => { }).catch(error => {
this.toast.showError(error); this.toast.showError(error);
}); });
@@ -96,7 +96,7 @@ export class ProjectGrantMembersComponent implements AfterViewInit, OnInit {
public removeMember(member: ProjectMember.AsObject): void { public removeMember(member: ProjectMember.AsObject): void {
this.projectService.RemoveProjectGrantMember(this.projectId, this.grantId, member.userId).then(() => { this.projectService.RemoveProjectGrantMember(this.projectId, this.grantId, member.userId).then(() => {
this.toast.showInfo('Member removed successfully'); this.toast.showInfo('PROJECT.GRANT.TOAST.PROJECTGRANTMEMBERREMOVED', true);
}).catch(error => { }).catch(error => {
this.toast.showError(error); this.toast.showError(error);
}); });
@@ -134,8 +134,7 @@ export class ProjectGrantMembersComponent implements AfterViewInit, OnInit {
dataToAdd.rolesKeyList, dataToAdd.rolesKeyList,
); );
})).then(() => { })).then(() => {
console.log('this'); this.toast.showInfo('PROJECT.GRANT.TOAST.PROJECTGRANTMEMBERADDED', true);
this.toast.showInfo('Project Grant Member successfully added!');
}).catch(error => { }).catch(error => {
this.toast.showError(error); this.toast.showError(error);
}); });
@@ -146,7 +145,7 @@ export class ProjectGrantMembersComponent implements AfterViewInit, OnInit {
updateRoles(member: ProjectMember.AsObject, selectionChange: MatSelectChange): void { updateRoles(member: ProjectMember.AsObject, selectionChange: MatSelectChange): void {
this.projectService.ChangeProjectGrantMember(this.projectId, this.grantId, member.userId, selectionChange.value) this.projectService.ChangeProjectGrantMember(this.projectId, this.grantId, member.userId, selectionChange.value)
.then((newmember: ProjectMember) => { .then((newmember: ProjectMember) => {
this.toast.showInfo('Member updated!'); this.toast.showInfo('PROJECT.GRANT.TOAST.PROJECTGRANTMEMBERCHANGED', true);
}).catch(error => { }).catch(error => {
this.toast.showError(error); this.toast.showError(error);
}); });

View File

@@ -30,8 +30,8 @@ export class ProjectCreateComponent implements OnInit {
.then((data: Project) => { .then((data: Project) => {
this.router.navigate(['projects', data.getId()]); this.router.navigate(['projects', data.getId()]);
}) })
.catch(data => { .catch(error => {
this.toast.showError(data.message); this.toast.showError(error);
}); });
} }

View File

@@ -13,7 +13,7 @@ import { MatTooltipModule } from '@angular/material/tooltip';
import { TranslateModule } from '@ngx-translate/core'; import { TranslateModule } from '@ngx-translate/core';
import { CardModule } from 'src/app/modules/card/card.module'; import { CardModule } from 'src/app/modules/card/card.module';
import { ProjectRolesModule } from 'src/app/modules/project-roles/project-roles.module'; import { ProjectRolesModule } from 'src/app/modules/project-roles/project-roles.module';
import { PipesModule } from 'src/app/pipes/pipes.module'; import { HasRolePipeModule } from 'src/app/pipes/has-role-pipe.module';
import { ProjectGrantCreateRoutingModule } from './project-grant-create-routing.module'; import { ProjectGrantCreateRoutingModule } from './project-grant-create-routing.module';
import { ProjectGrantCreateComponent } from './project-grant-create.component'; import { ProjectGrantCreateComponent } from './project-grant-create.component';
@@ -33,7 +33,7 @@ import { ProjectGrantCreateComponent } from './project-grant-create.component';
ProjectRolesModule, ProjectRolesModule,
MatIconModule, MatIconModule,
MatTooltipModule, MatTooltipModule,
PipesModule, HasRolePipeModule,
ReactiveFormsModule, ReactiveFormsModule,
MatProgressSpinnerModule, MatProgressSpinnerModule,
FormsModule, FormsModule,

View File

@@ -9,8 +9,8 @@
</div> </div>
<h1>{{'PROJECT.ROLE.ADDDESCRIPTION' | translate}}</h1> <h1>{{'PROJECT.ROLE.ADDDESCRIPTION' | translate}}</h1>
<button class="add-line-btn" color="primary" mat-stroked-button (click)="addEntry()"> <button class="add-line-btn" color="primary" type="button" mat-stroked-button (click)="addEntry()">
Add another role {{'PROJECT.ROLE.ADDNEWLINE' | translate}}
</button> </button>
<form @list (ngSubmit)="addRole()"> <form @list (ngSubmit)="addRole()">
<div @animate *ngFor="let formGroup of formArray.controls; index as i" class="content"> <div @animate *ngFor="let formGroup of formArray.controls; index as i" class="content">
@@ -18,8 +18,6 @@
<mat-form-field appearance="outline" class="formfield"> <mat-form-field appearance="outline" class="formfield">
<mat-label>{{ 'PROJECT.ROLE.KEY' | translate }}</mat-label> <mat-label>{{ 'PROJECT.ROLE.KEY' | translate }}</mat-label>
<input matInput formControlName="key" /> <input matInput formControlName="key" />
<!-- <mat-error *ngIf="formGroup.get('key')?.errors?.required">{{'ERRORS.REQUIRED' | translate}}
</mat-error> -->
</mat-form-field> </mat-form-field>
<mat-form-field appearance="outline" class="formfield"> <mat-form-field appearance="outline" class="formfield">
<mat-label>{{ 'PROJECT.ROLE.DISPLAY_NAME' | translate }}</mat-label> <mat-label>{{ 'PROJECT.ROLE.DISPLAY_NAME' | translate }}</mat-label>
@@ -29,15 +27,14 @@
<mat-label>{{ 'PROJECT.ROLE.GROUP' | translate }}</mat-label> <mat-label>{{ 'PROJECT.ROLE.GROUP' | translate }}</mat-label>
<input matInput formControlName="group" /> <input matInput formControlName="group" />
</mat-form-field> </mat-form-field>
<button mat-icon-button (click)="removeEntry(i)" color="warn" <button mat-icon-button (click)="removeEntry(i)" type="button" color="warn"
matTooltip="{{ 'ACTIONS.REMOVE' | translate }}"> matTooltip="{{ 'ACTIONS.REMOVE' | translate }}">
<i class="las la-trash"></i> <i class="las la-trash"></i>
</button> </button>
</ng-container> </ng-container>
</div> </div>
<button color="primary" mat-raised-button class="continue-button" [disabled]="formArray.invalid" cdkFocusInitial <button color="primary" mat-raised-button class="continue-button" [disabled]="formArray.invalid" type="submit">
type="submit">
{{ 'ACTIONS.SAVE' | translate }} {{ 'ACTIONS.SAVE' | translate }}
</button> </button>
</form> </form>

View File

@@ -84,6 +84,7 @@ export class ProjectRoleCreateComponent implements OnInit, OnDestroy {
} }
public addRole(): void { public addRole(): void {
console.log(this.formArray.value);
const rolesToAdd: ProjectRoleAdd[] = this.formArray.value.map((element: any) => { const rolesToAdd: ProjectRoleAdd[] = this.formArray.value.map((element: any) => {
const role = new ProjectRoleAdd(); const role = new ProjectRoleAdd();
role.setKey(element.key); role.setKey(element.key);

View File

@@ -1,5 +1,6 @@
import { CommonModule } from '@angular/common'; import { CommonModule } from '@angular/common';
import { NgModule } from '@angular/core'; import { NgModule } from '@angular/core';
import { SharedModule } from 'src/app/modules/shared/shared.module';
import { SignedoutRoutingModule } from './signedout-routing.module'; import { SignedoutRoutingModule } from './signedout-routing.module';
@@ -8,6 +9,7 @@ import { SignedoutRoutingModule } from './signedout-routing.module';
imports: [ imports: [
CommonModule, CommonModule,
SignedoutRoutingModule, SignedoutRoutingModule,
SharedModule,
], ],
}) })
export class SignedoutModule { } export class SignedoutModule { }

View File

@@ -50,19 +50,11 @@ export class UserGrantCreateComponent implements OnDestroy {
this.grantId = grantid; this.grantId = grantid;
this.userId = userid; this.userId = userid;
console.log('usergrantcreate');
// if (this.userId) {
// this.context = UserGrantContext.USER;
// } else
if (this.projectId && !this.grantId) { if (this.projectId && !this.grantId) {
this.context = UserGrantContext.OWNED_PROJECT; this.context = UserGrantContext.OWNED_PROJECT;
} else if (this.projectId && this.grantId) { } else if (this.projectId && this.grantId) {
this.context = UserGrantContext.GRANTED_PROJECT; this.context = UserGrantContext.GRANTED_PROJECT;
console.log(this.grantId, this.projectId);
this.projectService.GetGrantedProjectByID(this.projectId, this.grantId).then(resp => { this.projectService.GetGrantedProjectByID(this.projectId, this.grantId).then(resp => {
console.log(resp.toObject());
this.grantRolesKeyList = resp.toObject().roleKeysList; this.grantRolesKeyList = resp.toObject().roleKeysList;
}).catch(error => { }).catch(error => {
this.toast.showError(error); this.toast.showError(error);
@@ -81,25 +73,13 @@ export class UserGrantCreateComponent implements OnDestroy {
public addGrant(): void { public addGrant(): void {
switch (this.context) { switch (this.context) {
// case UserGrantContext.USER:
// this.userService.CreateUserGrant(
// this.projectId,
// this.userId,
// this.rolesList,
// ).then((data: UserGrant) => {
// this.toast.showInfo('User Grant added');
// this.close();
// }).catch(error => {
// this.toast.showError(error);
// });
// break;
case UserGrantContext.OWNED_PROJECT: case UserGrantContext.OWNED_PROJECT:
this.userService.CreateProjectUserGrant( this.userService.CreateProjectUserGrant(
this.projectId, this.projectId,
this.userId, this.userId,
this.rolesList, this.rolesList,
).then((data: UserGrant) => { ).then((data: UserGrant) => {
this.toast.showInfo('Project User Grant added'); this.toast.showInfo('PROJECT.GRANT.TOAST.PROJECTGRANTADDED', true);
this.close(); this.close();
}).catch(error => { }).catch(error => {
this.toast.showError(error); this.toast.showError(error);
@@ -113,13 +93,12 @@ export class UserGrantCreateComponent implements OnDestroy {
this.userId, this.userId,
this.rolesList, this.rolesList,
).then((data: UserGrant) => { ).then((data: UserGrant) => {
this.toast.showInfo('Project Grant User Grant added'); this.toast.showInfo('PROJECT.GRANT.TOAST.PROJECTGRANTUSERGRANTADDED', true);
this.close(); this.close();
}).catch(error => { }).catch(error => {
this.toast.showError(error); this.toast.showError(error);
}); });
break; break;
} }
} }

View File

@@ -1,5 +1,5 @@
import { CommonModule } from '@angular/common'; import { CommonModule } from '@angular/common';
import { CUSTOM_ELEMENTS_SCHEMA, NgModule } from '@angular/core'; import { NgModule } from '@angular/core';
import { MatButtonModule } from '@angular/material/button'; import { MatButtonModule } from '@angular/material/button';
import { MatFormFieldModule } from '@angular/material/form-field'; import { MatFormFieldModule } from '@angular/material/form-field';
import { MatIconModule } from '@angular/material/icon'; import { MatIconModule } from '@angular/material/icon';
@@ -10,6 +10,7 @@ import {
SearchProjectAutocompleteModule, SearchProjectAutocompleteModule,
} from 'src/app/modules/search-project-autocomplete/search-project-autocomplete.module'; } from 'src/app/modules/search-project-autocomplete/search-project-autocomplete.module';
import { SearchUserAutocompleteModule } from 'src/app/modules/search-user-autocomplete/search-user-autocomplete.module'; import { SearchUserAutocompleteModule } from 'src/app/modules/search-user-autocomplete/search-user-autocomplete.module';
import { SharedModule } from 'src/app/modules/shared/shared.module';
import { ProjectRolesModule } from '../../modules/project-roles/project-roles.module'; import { ProjectRolesModule } from '../../modules/project-roles/project-roles.module';
import { UserGrantCreateRoutingModule } from './user-grant-create-routing.module'; import { UserGrantCreateRoutingModule } from './user-grant-create-routing.module';
@@ -31,9 +32,7 @@ import { UserGrantCreateComponent } from './user-grant-create.component';
SearchProjectAutocompleteModule, SearchProjectAutocompleteModule,
SearchUserAutocompleteModule, SearchUserAutocompleteModule,
ProjectRolesModule, ProjectRolesModule,
], SharedModule,
schemas: [
CUSTOM_ELEMENTS_SCHEMA,
], ],
}) })
export class UserGrantCreateModule { } export class UserGrantCreateModule { }

View File

@@ -89,8 +89,8 @@ export class UserCreateComponent implements OnDestroy {
this.toast.showInfo('USER.TOAST.CREATED', true); this.toast.showInfo('USER.TOAST.CREATED', true);
this.router.navigate(['users', data.getId()]); this.router.navigate(['users', data.getId()]);
}) })
.catch(data => { .catch(error => {
this.toast.showError(data.message); this.toast.showError(error);
}); });
} }

View File

@@ -129,7 +129,7 @@
<app-auth-user-mfa *ngIf="user"></app-auth-user-mfa> <app-auth-user-mfa *ngIf="user"></app-auth-user-mfa>
</div> </div>
<metainfo *ngIf="user" class="side"> <div *ngIf="user" class="side" metainfo>
<div class="details"> <div class="details">
<div class="row" *ngIf="user?.preferredLoginName"> <div class="row" *ngIf="user?.preferredLoginName">
<span class="first">Preferred Loginname:</span> <span class="first">Preferred Loginname:</span>
@@ -138,5 +138,5 @@
</div> </div>
<app-changes [changeType]="ChangeType.MYUSER" [id]="user.id"></app-changes> <app-changes [changeType]="ChangeType.MYUSER" [id]="user.id"></app-changes>
</metainfo> </div>
</app-meta-layout> </app-meta-layout>

View File

@@ -69,8 +69,8 @@ export class AuthUserDetailComponent implements OnDestroy {
this.toast.showInfo('USER.TOAST.SAVED', true); this.toast.showInfo('USER.TOAST.SAVED', true);
this.user = Object.assign(this.user, data.toObject()); this.user = Object.assign(this.user, data.toObject());
}) })
.catch(data => { .catch(error => {
this.toast.showError(data.message); this.toast.showError(error);
}); });
} }
@@ -144,8 +144,8 @@ export class AuthUserDetailComponent implements OnDestroy {
this.toast.showInfo('USER.TOAST.PHONESAVED', true); this.toast.showInfo('USER.TOAST.PHONESAVED', true);
this.user.phone = data.toObject().phone; this.user.phone = data.toObject().phone;
this.phoneEditState = false; this.phoneEditState = false;
}).catch(data => { }).catch(error => {
this.toast.showError(data); this.toast.showError(error);
this.phoneEditState = false; this.phoneEditState = false;
}); });
} }
@@ -153,8 +153,8 @@ export class AuthUserDetailComponent implements OnDestroy {
private async getData(): Promise<void> { private async getData(): Promise<void> {
this.userService.GetMyUser().then(user => { this.userService.GetMyUser().then(user => {
this.user = user.toObject(); this.user = user.toObject();
}).catch(err => { }).catch(error => {
this.toast.showError(err); this.toast.showError(error);
}); });
} }

Some files were not shown because too many files have changed in this diff Show More