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
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
125 changed files with 807 additions and 614 deletions

View File

@ -9381,9 +9381,9 @@
}
},
"lodash": {
"version": "4.17.15",
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz",
"integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A=="
"version": "4.17.19",
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.19.tgz",
"integrity": "sha512-JNvd8XER9GQX0v2qJgsaN/mzFCNA5BRe/j8JN9d+tWyGLSodKQHKFicdwNYzWwI3wjRnaKPsGj1XkBjx/F96DQ=="
},
"lodash.camelcase": {
"version": "4.3.0",
@ -10167,6 +10167,21 @@
"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": {
"version": "1.0.5",
"resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz",

View File

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

View File

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

View File

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

View File

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

View File

@ -134,10 +134,6 @@ export class AppComponent implements OnDestroy {
public orgLoading: boolean = false;
public showProjectSection: boolean = false;
public showOrgSection: boolean = false;
public showUserSection: boolean = false;
public iamreadwrite: boolean = false;
private authSub: 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.org = org;
this.loadPermissions();
});
this.authSub = this.authService.authenticationChanged.subscribe((authenticated) => {
if (authenticated) {
// this.userService.GetMyzitadelPermissions().pipe(take(1)).subscribe(perm => console.log(perm.toObject()));
this.loadPermissions();
this.authService.GetActiveOrg().then(org => {
this.org = org;
});
@ -235,13 +228,6 @@ export class AppComponent implements OnDestroy {
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 {
this.orgLoading = true;
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 { TranslateHttpLoader } from '@ngx-translate/http-loader';
import { AuthConfig, OAuthModule, OAuthStorage } from 'angular-oauth2-oidc';
import { QuicklinkModule } from 'ngx-quicklink';
import { environment } from '../environments/environment';
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 { AvatarModule } from './modules/avatar/avatar.module';
import { SignedoutComponent } from './pages/signedout/signedout.component';
import { HasRolePipeModule } from './pipes/has-role-pipe.module';
import { AuthUserService } from './services/auth-user.service';
import { AuthService } from './services/auth.service';
import { GrpcService } from './services/grpc.service';
@ -86,6 +88,7 @@ const authConfig: AuthConfig = {
deps: [HttpClient],
},
}),
QuicklinkModule,
AccountsCardModule,
HasRoleModule,
BrowserAnimationsModule,
@ -96,6 +99,7 @@ const authConfig: AuthConfig = {
MatSidenavModule,
MatCardModule,
OutsideClickModule,
HasRolePipeModule,
MatProgressBarModule,
MatToolbarModule,
MatMenuModule,

View File

@ -15,6 +15,6 @@ export class RoleGuard implements CanActivate {
route: ActivatedRouteSnapshot,
state: RouterStateSnapshot,
): 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.projectId = data.projectId;
console.log(this.creationType);
if (this.creationType === CreationType.PROJECT_GRANTED) {
this.projectService.GetProjectGrantMemberRoles().then(resp => {
this.memberRoleOptions = resp.toObject().rolesList;

View File

@ -3,7 +3,7 @@
<div *ngIf="title" class="row">
<h2 class="title">{{title}}</h2>
<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">
<mat-icon *ngIf="!expanded">keyboard_arrow_down</mat-icon>
<mat-icon *ngIf="expanded">keyboard_arrow_up</mat-icon>

View File

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

View File

@ -4,12 +4,13 @@ import { NgModule } from '@angular/core';
import { MatProgressSpinnerModule } from '@angular/material/progress-spinner';
import { TranslateModule } from '@ngx-translate/core';
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';
@NgModule({
declarations: [
ChangesComponent,
@ -19,8 +20,10 @@ import { ChangesComponent } from './changes.component';
ScrollableModule,
MatProgressSpinnerModule,
TranslateModule,
PipesModule,
HasRolePipeModule,
ScrollingModule,
LocalizedDatePipeModule,
TimestampToDatePipeModule,
],
exports: [
ChangesComponent,

View File

@ -5,6 +5,6 @@
<div class="meta" [ngClass]="{'hidden': hidden}">
<button (click)="hidden = !hidden" color="primary" class="hide" mat-icon-button><i
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>

View File

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

View File

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

View File

@ -98,7 +98,7 @@
<mat-form-field class="form-field" appearance="outline" *ngIf="project">
<mat-label>{{ 'PROJECT.GRANT.TITLE' | translate }}</mat-label>
<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)">
<mat-option *ngFor="let role of memberRoleOptions" [value]="role">
{{ 'ROLES.'+role | translate }}
@ -113,8 +113,9 @@
</tr>
</table>
<mat-paginator class="background-style" #paginator [pageSize]="50"
[pageSizeOptions]="[25, 50, 100, 250]">
<mat-paginator *ngIf="dataSource" class="background-style" #paginator [pageSize]="INITIALPAGESIZE"
[length]="dataSource.totalResult" [pageSizeOptions]="[25, 50, 100, 250]"
(page)="changePage($event)">
</mat-paginator>
</div>
</div>

View File

@ -1,7 +1,7 @@
import { SelectionModel } from '@angular/cdk/collections';
import { Component, ViewChild } from '@angular/core';
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 { MatTable } from '@angular/material/table';
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 { ProjectMembersDataSource } from './project-members-datasource';
@Component({
selector: 'app-project-members',
templateUrl: './project-members.component.html',
styleUrls: ['./project-members.component.scss'],
})
export class ProjectMembersComponent {
public INITIALPAGESIZE: number = 25;
public project!: ProjectView.AsObject | ProjectGrantView.AsObject;
public projectType: ProjectType = ProjectType.PROJECTTYPE_OWNED;
public disabled: boolean = false;
@ -50,15 +52,19 @@ export class ProjectMembersComponent {
this.project = project.toObject();
this.projectName = this.project.name;
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) {
console.log(params.projectid, params.grantid);
this.projectService.GetGrantedProjectByID(params.projectid, params.grantid).then(project => {
this.project = project.toObject();
this.projectName = this.project.projectName;
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) {
this.projectService.ChangeProjectMember(this.project.projectId, member.userId, selectionChange.value)
.then((newmember: ProjectMember) => {
this.toast.showInfo('Member changed');
this.toast.showInfo('PROJECT.TOAST.MEMBERCHANGED', true);
}).catch(error => {
this.toast.showError(error);
});
@ -157,10 +163,14 @@ export class ProjectMembersComponent {
this.projectService.ChangeProjectGrantMember(this.project.projectId,
this.grantId, member.userId, selectionChange.value)
.then((newmember: ProjectMember) => {
this.toast.showInfo('Member changed');
this.toast.showInfo('PROJECT.TOAST.MEMBERCHANGED', true);
}).catch(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 { TranslateModule } from '@ngx-translate/core';
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 { ProjectMembersComponent } from './project-members.component';
@ -42,7 +42,7 @@ import { ProjectMembersComponent } from './project-members.component';
MatProgressSpinnerModule,
FormsModule,
TranslateModule,
PipesModule,
HasRolePipeModule,
],
})
export class ProjectMembersModule { }

View File

@ -93,7 +93,7 @@ export class ProjectRolesComponent implements AfterViewInit, OnInit {
});
this.selection.clear();
}).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.next(this.dataSource.rolesSubject.value);
})
.catch(data => {
this.toast.showError(data.message);
.catch(error => {
this.toast.showError(error);
});
}

View File

@ -15,7 +15,8 @@ import { MatTooltipModule } from '@angular/material/tooltip';
import { RouterModule } from '@angular/router';
import { TranslateModule } from '@ngx-translate/core';
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 { ProjectRolesComponent } from './project-roles.component';
@ -39,9 +40,10 @@ import { ProjectRolesComponent } from './project-roles.component';
MatCheckboxModule,
RouterModule,
MatTooltipModule,
PipesModule,
HasRolePipeModule,
TranslateModule,
MatMenuModule,
TimestampToDatePipeModule,
],
exports: [
ProjectRolesComponent,

View File

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

View File

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

View File

@ -25,7 +25,6 @@
<mat-spinner diameter="50"></mat-spinner>
</div>
<table mat-table multiTemplateDataRows class="full-width-table" aria-label="Elements" [dataSource]="dataSource">
<ng-container matColumnDef="select">
<th class="selection" mat-header-cell *matHeaderCellDef>
<mat-checkbox color="primary" (change)="$event ? masterToggle() : null"
@ -53,7 +52,7 @@
<ng-container matColumnDef="org">
<th mat-header-cell *matHeaderCellDef> {{ 'PROJECT.GRANT.GRANTEDORGDOMAIN' | translate }} </th>
<td class="pointer" mat-cell *matCellDef="let grant">
{{grant.orgDomain}} {{grant.orgName}} </td>
{{grant.orgName}} </td>
</ng-container>
<ng-container matColumnDef="projectId">
@ -81,7 +80,8 @@
<ng-container *ngIf="context === UserGrantContext.USER">
<span class="no-roles"
*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 *ngIf="context === UserGrantContext.USER">
@ -105,7 +105,8 @@
<ng-container *ngIf="context === UserGrantContext.OWNED_PROJECT">
<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)"
matTooltip="{{'ACTIONS.CHANGE' | translate}}">
<i class="las la-edit"></i>
@ -141,6 +142,7 @@
</tr>
</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>
</div>

View File

@ -1,10 +1,10 @@
import { SelectionModel } from '@angular/cdk/collections';
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 { MatTable } from '@angular/material/table';
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 { ProjectService } from 'src/app/services/project.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'],
})
export class UserGrantsComponent implements OnInit, AfterViewInit {
// @Input() filterValue: string = '';
// @Input() filter: UserGrantSearchKey = UserGrantSearchKey.USERGRANTSEARCHKEY_USER_ID;
@Input() context: UserGrantContext = UserGrantContext.USER;
public grants: UserGrant.AsObject[] = [];
public grants: UserGrantView.AsObject[] = [];
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(MatTable) public table!: MatTable<ProjectGrant.AsObject>;
@ViewChild(MatTable) public table!: MatTable<UserGrantView.AsObject>;
@Input() allowCreate: boolean = false;
@Input() allowDelete: boolean = false;
@ -51,19 +49,13 @@ export class UserGrantsComponent implements OnInit, AfterViewInit {
private toast: ToastService,
) { }
public displayedColumns: string[] = ['select',
@Input() public displayedColumns: string[] = ['select',
'user',
'org',
'projectId', 'creationDate', 'changeDate', 'roleNamesList'];
public ngOnInit(): void {
console.log(this.context);
this.dataSource = new UserGrantsDataSource(this.userService);
const data = {
projectId: this.projectId,
grantId: this.grantId,
userId: this.userId,
};
switch (this.context) {
case UserGrantContext.OWNED_PROJECT:
@ -73,7 +65,7 @@ export class UserGrantsComponent implements OnInit, AfterViewInit {
}
break;
case UserGrantContext.GRANTED_PROJECT:
if (data && data.grantId) {
if (this.grantId) {
this.routerLink = ['/grant-create', 'project', this.projectId, 'grant', this.grantId];
this.getGrantRoleOptions(this.grantId, this.projectId);
}
@ -86,7 +78,11 @@ export class UserGrantsComponent implements OnInit, AfterViewInit {
default:
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 {
@ -122,8 +118,6 @@ export class UserGrantsComponent implements OnInit, AfterViewInit {
}
public getGrantRoleOptions(grantId: string, projectId: string): void {
console.log(grantId, projectId);
this.projectService.GetGrantedProjectByID(projectId, grantId).then(resp => {
this.loadedGrantId = projectId;
this.grantRoleOptions = resp.toObject().roleKeysList;
@ -133,7 +127,6 @@ export class UserGrantsComponent implements OnInit, AfterViewInit {
}
public getProjectRoleOptions(projectId: string): void {
console.log(projectId);
this.projectService.SearchProjectRoles(projectId, 100, 0).then(resp => {
this.loadedProjectId = projectId;
this.projectRoleOptions = resp.toObject().resultList;
@ -182,4 +175,12 @@ export class UserGrantsComponent implements OnInit, AfterViewInit {
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 { TranslateModule } from '@ngx-translate/core';
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 { UserGrantsComponent } from './user-grants.component';
@ -38,7 +39,8 @@ import { UserGrantsComponent } from './user-grants.component';
MatSelectModule,
MatFormFieldModule,
TranslateModule,
PipesModule,
HasRolePipeModule,
TimestampToDatePipeModule,
],
exports: [
UserGrantsComponent,

View File

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

View File

@ -4,6 +4,7 @@ import { MatButtonModule } from '@angular/material/button';
import { MatIconModule } from '@angular/material/icon';
import { TranslateModule } from '@ngx-translate/core';
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 { HomeComponent } from './home.component';
@ -19,6 +20,7 @@ import { HomeComponent } from './home.component';
HomeRoutingModule,
MatButtonModule,
TranslateModule,
SharedModule,
],
})
export class HomeModule { }

View File

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

View File

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

View File

@ -1,5 +1,7 @@
import { NgModule } from '@angular/core';
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';
@ -7,10 +9,18 @@ const routes: Routes = [
{
path: '',
component: IamComponent,
canActivate: [AuthGuard, RoleGuard],
data: {
roles: ['iam.read'],
},
},
{
path: 'members',
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">
<th mat-header-cell mat-sort-header *matHeaderCellDef> {{ 'IAM.VIEWS.SEQUENCE' | translate }} </th>
<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>
</ng-container>

View File

@ -35,13 +35,15 @@
table, mat-paginator {
width: 100%;
td, th {
padding: 0 1rem;
&:first-child {
padding-left: 0;
padding-right: 1rem;
}
&:last-child {
padding-right: 0;
}

View File

@ -21,7 +21,7 @@ export class IamViewsComponent {
@ViewChild(MatSort) public sort!: MatSort;
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);
public loading$: Observable<boolean> = this.loadingSubject.asObservable();
constructor(private adminService: AdminService) {

View File

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

View File

@ -1,5 +1,5 @@
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 { MatAutocompleteModule } from '@angular/material/autocomplete';
import { MatButtonModule } from '@angular/material/button';
@ -16,13 +16,17 @@ import { MatTabsModule } from '@angular/material/tabs';
import { MatTooltipModule } from '@angular/material/tooltip';
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 { 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 { IamRoutingModule } from './iam-routing.module';
import { IamComponent } from './iam.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,
IamRoutingModule,
ChangesModule,
CardModule,
MatAutocompleteModule,
MatChipsModule,
MatButtonModule,
@ -51,7 +56,9 @@ import { IamViewsComponent } from './iam-views/iam-views.component';
TranslateModule,
MatDialogModule,
IamContributorsModule,
LocalizedDatePipeModule,
TimestampToDatePipeModule,
SharedModule,
],
schemas: [NO_ERRORS_SCHEMA],
})
export class IamModule { }

View File

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

View File

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

View File

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

View File

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

View File

@ -8,7 +8,7 @@ import { MatIconModule } from '@angular/material/icon';
import { MatInputModule } from '@angular/material/input';
import { MatSelectModule } from '@angular/material/select';
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 { OrgCreateComponent } from './org-create.component';
@ -25,7 +25,7 @@ import { OrgCreateComponent } from './org-create.component';
MatButtonModule,
MatIconModule,
MatSelectModule,
PipesModule,
HasRolePipeModule,
TranslateModule,
MatCheckboxModule,
],

View File

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

View File

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

View File

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

View File

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

View File

@ -1,5 +1,5 @@
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 { MatButtonModule } from '@angular/material/button';
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 { CardModule } from 'src/app/modules/card/card.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 { ChangesModule } from '../../modules/changes/changes.module';
@ -49,8 +50,7 @@ import { PolicyGridComponent } from './policy-grid/policy-grid.component';
ChangesModule,
AddDomainDialogModule,
TranslateModule,
SharedModule,
],
exports: [],
schemas: [NO_ERRORS_SCHEMA],
})
export class OrgsModule { }

View File

@ -21,7 +21,7 @@
</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-label>{{ 'ORG.POLICY.DATA.DESCRIPTION' | translate }}</mat-label>
<input matInput name="description" ngDefaultControl [(ngModel)]="lockoutData.description"
@ -44,12 +44,12 @@
<span class="left-desc">{{'ORG.POLICY.DATA.SHOWLOCKOUTFAILURES' | translate}}</span>
<span class="fill-space"></span>
<mat-slide-toggle color="primary" name="showLockOutFailures" ngDefaultControl
[(ngModel)]="complexityData.showLockOutFailures">
[(ngModel)]="lockoutData.showLockOutFailures">
</mat-slide-toggle>
</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-label>{{ 'ORG.POLICY.DATA.DESCRIPTION' | translate }}</mat-label>
<input matInput name="description" ngDefaultControl [(ngModel)]="complexityData.description"
@ -98,7 +98,7 @@
</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-label>{{ 'ORG.POLICY.DATA.DESCRIPTION' | translate }}</mat-label>
<input matInput name="description" ngDefaultControl [(ngModel)]="ageData.description"
@ -133,7 +133,7 @@
</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-label>{{ 'ORG.POLICY.DATA.DESCRIPTION' | translate }}</mat-label>
<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 { BehaviorSubject, Subscription } from 'rxjs';
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 { OrgService } from 'src/app/services/org.service';
import { StorageService } from 'src/app/services/storage.service';
@ -39,31 +45,10 @@ export class PasswordPolicyComponent implements OnInit, OnDestroy {
public lockoutForm!: FormGroup;
public ageForm!: FormGroup;
public complexityData: any = {
minLength: 8,
description: '',
hasNumber: true,
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,
};
public complexityData!: PasswordComplexityPolicy.AsObject;
public lockoutData!: PasswordLockoutPolicy.AsObject;
public ageData!: PasswordAgePolicy.AsObject;
public iamData!: OrgIamPolicy.AsObject;
private sub: Subscription = new Subscription();
@ -102,19 +87,21 @@ export class PasswordPolicyComponent implements OnInit, OnDestroy {
if (this.componentAction === PolicyComponentAction.MODIFY) {
this.getData(params).then(data => {
switch (this.policyType) {
case PolicyComponentType.LOCKOUT:
this.lockoutData = data.toObject();
break;
case PolicyComponentType.AGE:
this.ageData = data.toObject();
break;
case PolicyComponentType.COMPLEXITY:
this.complexityData = data.toObject();
break;
case PolicyComponentType.IAM_POLICY:
this.iamData = data.toObject();
break;
if (data) {
switch (this.policyType) {
case PolicyComponentType.LOCKOUT:
this.lockoutData = data.toObject() as PasswordLockoutPolicy.AsObject;
break;
case PolicyComponentType.AGE:
this.ageData = data.toObject() as PasswordAgePolicy.AsObject;
break;
case PolicyComponentType.COMPLEXITY:
this.complexityData = data.toObject() as PasswordComplexityPolicy.AsObject;
break;
case PolicyComponentType.IAM_POLICY:
this.iamData = data.toObject() as OrgIamPolicy.AsObject;
break;
}
}
});
}
@ -128,7 +115,8 @@ export class PasswordPolicyComponent implements OnInit, OnDestroy {
this.sub.unsubscribe();
}
private async getData(params: any): Promise<any> {
private async getData(params: any):
Promise<PasswordLockoutPolicy | PasswordAgePolicy | PasswordComplexityPolicy | OrgIamPolicy | undefined> {
switch (params.policytype) {
case PolicyComponentType.LOCKOUT:
this.titleSub.next('ORG.POLICY.PWD_LOCKOUT.TITLE');
@ -270,8 +258,8 @@ export class PasswordPolicyComponent implements OnInit, OnDestroy {
if (orgId) {
this.adminService.CreateOrgIamPolicy(
orgId,
this.complexityData.description,
this.complexityData.userLoginMustBeDomain,
this.iamData.description,
this.iamData.userLoginMustBeDomain,
).then(() => {
this.router.navigate(['org']);
}).catch(error => {
@ -326,8 +314,8 @@ export class PasswordPolicyComponent implements OnInit, OnDestroy {
if (orgId) {
this.adminService.UpdateOrgIamPolicy(
orgId,
this.complexityData.description,
this.complexityData.userLoginMustBeDomain,
this.iamData.description,
this.iamData.userLoginMustBeDomain,
).then(() => {
this.router.navigate(['org']);
}).catch(error => {

View File

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

View File

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

View File

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

View File

@ -1,5 +1,5 @@
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 { MatButtonModule } from '@angular/material/button';
import { MatButtonToggleModule } from '@angular/material/button-toggle';
@ -53,6 +53,5 @@ import { AppsRoutingModule } from './apps-routing.module';
TranslateModule,
],
exports: [TranslateModule],
schemas: [CUSTOM_ELEMENTS_SCHEMA, NO_ERRORS_SCHEMA],
})
export class AppsModule { }

View File

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

View File

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

View File

@ -106,9 +106,9 @@ export class GrantedProjectListComponent implements OnInit, OnDestroy {
});
Promise.all(promises).then(() => {
this.toast.showInfo('Reactivated selected projects successfully');
this.toast.showInfo('PROJECT.TOAST.REACTIVATED', true);
}).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(() => {
this.toast.showInfo('Deactivated selected projects Successfully');
this.toast.showInfo('PROJECT.TOAST.DEACTIVATED', true);
}).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',
data: {
type: ProjectType.PROJECTTYPE_GRANTED,
roles: ['project.grant.member.read'],
},
loadChildren: () => import('src/app/modules/project-members/project-members.module')
.then(m => m.ProjectMembersModule),
@ -37,7 +38,10 @@ const routes: Routes = [
{
path: ':projectid/roles/create',
loadChildren: () => import('../project-role-create/project-role-create.module').then(m => m.ProjectRoleCreateModule),
canActivate: [RoleGuard],
data: {
roles: ['project.write'],
},
},
{
path: ':projectid/grants/create',

View File

@ -1,5 +1,5 @@
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 { MatButtonModule } from '@angular/material/button';
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 { ProjectContributorsModule } from 'src/app/modules/project-contributors/project-contributors.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 { 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 { 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 { GrantedProjectsRoutingModule } from './granted-projects-routing.module';
import { GrantedProjectsComponent } from './granted-projects.component';
@ -63,9 +65,10 @@ import { GrantedProjectsComponent } from './granted-projects.component';
CardModule,
MatTooltipModule,
MatSortModule,
PipesModule,
HasRolePipeModule,
TranslateModule,
TimestampToDatePipeModule,
SharedModule,
],
schemas: [NO_ERRORS_SCHEMA],
})
export class GrantedProjectsModule { }

View File

@ -1,20 +1,20 @@
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { ProjectApplicationGridComponent } from './project-application-grid.component';
import { ApplicationGridComponent } from './application-grid.component';
describe('AppGridComponent', () => {
let component: ProjectApplicationGridComponent;
let fixture: ComponentFixture<ProjectApplicationGridComponent>;
let component: ApplicationGridComponent;
let fixture: ComponentFixture<ApplicationGridComponent>;
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [ProjectApplicationGridComponent],
declarations: [ApplicationGridComponent],
})
.compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(ProjectApplicationGridComponent);
fixture = TestBed.createComponent(ApplicationGridComponent);
component = fixture.componentInstance;
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';
@Component({
selector: 'app-project-application-grid',
templateUrl: './project-application-grid.component.html',
styleUrls: ['./project-application-grid.component.scss'],
selector: 'app-application-grid',
templateUrl: './application-grid.component.html',
styleUrls: ['./application-grid.component.scss'],
})
export class ProjectApplicationGridComponent implements OnInit {
export class ApplicationGridComponent implements OnInit {
@Input() public projectId: string = '';
@Input() public disabled: boolean = false;
@Output() public changeView: EventEmitter<void> = new EventEmitter();

View File

@ -10,10 +10,6 @@
</ng-container>
</div>
<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']">
<a [disabled]="disabled" class="add-button" [routerLink]="[ '/projects', projectId, 'apps', 'create']"
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 { ToastService } from 'src/app/services/toast.service';
import { ProjectApplicationsDataSource } from './project-applications-datasource';
import { ProjectApplicationsDataSource } from './applications-datasource';
@Component({
selector: 'app-project-applications',
templateUrl: './project-applications.component.html',
styleUrls: ['./project-applications.component.scss'],
selector: 'app-applications',
templateUrl: './applications.component.html',
styleUrls: ['./applications.component.scss'],
})
export class ProjectApplicationsComponent implements AfterViewInit, OnInit {
export class ApplicationsComponent implements AfterViewInit, OnInit {
@Input() public projectId: string = '';
@Input() public disabled: boolean = false;
@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-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"
(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 }}">
<card-actions class="card-actions">
<div class="card-actions" card-actions>
<button mat-icon-button (click)="grid = true">
<i matTooltip="show grid view" class="las la-th-large"></i>
</button>
</card-actions>
<app-project-applications
[disabled]="project?.state !== ProjectState.PROJECTSTATE_ACTIVE || isZitadel"
[projectId]="projectId"></app-project-applications>
</div>
<app-applications [disabled]="project?.state !== ProjectState.PROJECTSTATE_ACTIVE || isZitadel"
[projectId]="projectId"></app-applications>
</app-card>
</ng-template>
@ -83,15 +82,15 @@
description="{{'GRANTS.PROJECT.DESCRIPTION' | translate }}">
<app-user-grants [context]="userGrantContext" [projectId]="projectId"
[disabled]="project?.state !== ProjectState.PROJECTSTATE_ACTIVE"
[allowCreate]="project?.state == ProjectState.PROJECTSTATE_ACTIVE && (['user.grant.write'] | hasRole)"
[allowDelete]="project?.state == ProjectState.PROJECTSTATE_ACTIVE && (['user.grant.delete'] | hasRole)">
[allowCreate]="project?.state == ProjectState.PROJECTSTATE_ACTIVE && (['user.grant.write'] | hasRole | async)"
[allowDelete]="project?.state == ProjectState.PROJECTSTATE_ACTIVE && (['user.grant.delete'] | hasRole | async)">
</app-user-grants>
</app-card>
</ng-template>
</ng-container>
</ng-container>
</div>
<metainfo class="side">
<div class="side" metainfo>
<div class="details">
<div class="row">
<span class="first">{{'PROJECT.STATE.TITLE' | translate}}:</span>
@ -111,5 +110,5 @@
<app-changes *ngIf="project" [changeType]="ChangeType.PROJECT" [id]="project.projectId"></app-changes>
</mat-tab>
</mat-tab-group>
</metainfo>
</div>
</app-meta-layout>

View File

@ -114,7 +114,7 @@ export class OwnedProjectDetailComponent implements OnInit, OnDestroy {
dialogRef.afterClosed().subscribe(resp => {
if (resp) {
this.projectService.ReactivateProject(this.projectId).then(() => {
this.toast.showInfo('Reactivated Project');
this.toast.showInfo('PROJECT.TOAST.REACTIVATED', true);
this.project.state = ProjectState.PROJECTSTATE_ACTIVE;
}).catch(error => {
this.toast.showError(error);
@ -135,7 +135,7 @@ export class OwnedProjectDetailComponent implements OnInit, OnDestroy {
dialogRef.afterClosed().subscribe(resp => {
if (resp) {
this.projectService.DeactivateProject(this.projectId).then(() => {
this.toast.showInfo('Deactivated Project');
this.toast.showInfo('PROJECT.TOAST.DEACTIVATED', true);
this.project.state = ProjectState.PROJECTSTATE_INACTIVE;
}).catch(error => {
this.toast.showError(error);
@ -147,9 +147,9 @@ export class OwnedProjectDetailComponent implements OnInit, OnDestroy {
public saveProject(): void {
this.projectService.UpdateProject(this.project.projectId, this.project.name).then(() => {
this.toast.showInfo('Project updated');
this.toast.showInfo('PROJECT.TOAST.UPDATED', true);
}).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([])),
finalize(() => this.loadingSubject.next(false)),
).subscribe(grants => {
console.log(grants);
this.grantsSubject.next(grants);
});
}

View File

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

View File

@ -1,5 +1,5 @@
<app-owned-project-grid *ngIf="grid" [loading]="loading$ | async" (changedView)="grid = false"
[items]="ownedProjectList" (newClicked)="addProject()">
[items]="ownedProjectList || []" (newClicked)="addProject()">
</app-owned-project-grid>
<div *ngIf="!grid" class="view-toggle">
@ -20,16 +20,6 @@
</ng-container>
</div>
<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']">
<a class="add-button" [routerLink]="[ '/projects', 'create']" color="primary" mat-raised-button>
<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(() => {
this.toast.showInfo('Reactivated selected projects successfully');
this.toast.showInfo('PROJECT.TOAST.REACTIVATED', true);
}).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(() => {
this.toast.showInfo('Deactivated selected projects Successfully');
this.toast.showInfo('PROJECT.TOAST.DEACTIVATED', true);
}).catch(error => {
this.toast.showInfo(error.message);
this.toast.showError(error);
});
}
}

View File

@ -1,10 +1,8 @@
import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';
import { AuthGuard } from 'src/app/guards/auth.guard';
import { RoleGuard } from 'src/app/guards/role.guard';
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';
const routes: Routes = [
@ -16,42 +14,60 @@ const routes: Routes = [
{
path: 'create',
loadChildren: () => import('../project-create/project-create.module').then(m => m.ProjectCreateModule),
canActivate: [AuthGuard, RoleGuard],
canActivate: [RoleGuard],
data: {
roles: ['project.write'],
},
},
{
path: ':id',
component: OwnedProjectDetailComponent,
data: { animation: 'HomePage' },
},
{
path: ':projectid/members',
data: {
type: ProjectType.PROJECTTYPE_OWNED,
animation: 'HomePage',
roles: ['project.read'],
},
loadChildren: () => import('src/app/modules/project-members/project-members.module')
.then(m => m.ProjectMembersModule),
canActivate: [RoleGuard],
loadChildren: () => import('./owned-project-detail/owned-project-detail.module')
.then(m => m.OwnedProjectDetailModule),
},
{
path: ':projectid/apps',
data: { animation: 'AddPage' },
loadChildren: () => import('src/app/pages/projects/apps/apps.module').then(m => m.AppsModule),
},
{
path: ':projectid/roles/create',
loadChildren: () => import('../project-role-create/project-role-create.module').then(m => m.ProjectRoleCreateModule),
},
{
path: ':projectid/grants/create',
loadChildren: () => import('../project-grant-create/project-grant-create.module')
.then(m => m.ProjectGrantCreateModule),
},
{
path: ':projectid/grant/:grantid',
loadChildren: () => import('./project-grant-detail/project-grant-detail.module')
.then(m => m.ProjectGrantDetailModule),
path: ':projectid',
children: [
{
path: 'members',
data: {
type: ProjectType.PROJECTTYPE_OWNED,
roles: ['project.member.read'],
},
canActivate: [RoleGuard],
loadChildren: () => import('src/app/modules/project-members/project-members.module')
.then(m => m.ProjectMembersModule),
},
{
path: 'apps',
data: {
animation: 'AddPage',
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 { NgModule, NO_ERRORS_SCHEMA } from '@angular/core';
import { NgModule } from '@angular/core';
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
import { MatButtonModule } from '@angular/material/button';
import { MatCheckboxModule } from '@angular/material/checkbox';
@ -10,47 +10,33 @@ import { MatInputModule } from '@angular/material/input';
import { MatPaginatorModule } from '@angular/material/paginator';
import { MatProgressBarModule } from '@angular/material/progress-bar';
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 { MatTabsModule } from '@angular/material/tabs';
import { MatTooltipModule } from '@angular/material/tooltip';
import { TranslateModule } from '@ngx-translate/core';
import { HasRoleModule } from 'src/app/directives/has-role/has-role.module';
import { AvatarModule } from 'src/app/modules/avatar/avatar.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 { SharedModule } from 'src/app/modules/shared/shared.module';
import { UserGrantsModule } from 'src/app/modules/user-grants/user-grants.module';
import { WarnDialogModule } from 'src/app/modules/warn-dialog/warn-dialog.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 { OwnedProjectDetailComponent } from './owned-project-detail/owned-project-detail.component';
import { OwnedProjectGridComponent } from './owned-project-grid/owned-project-grid.component';
import { OwnedProjectGridComponent } from './owned-project-list/owned-project-grid/owned-project-grid.component';
import { OwnedProjectListComponent } from './owned-project-list/owned-project-list.component';
import { OwnedProjectsRoutingModule } from './owned-projects-routing.module';
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({
declarations: [
OwnedProjectsComponent,
OwnedProjectListComponent,
OwnedProjectGridComponent,
OwnedProjectDetailComponent,
ProjectApplicationGridComponent,
ProjectApplicationsComponent,
ProjectGrantsComponent,
],
imports: [
CommonModule,
OwnedProjectsRoutingModule,
UserGrantsModule,
ProjectContributorsModule,
FormsModule,
ReactiveFormsModule,
TranslateModule,
@ -61,24 +47,18 @@ import { ProjectGrantsComponent } from './project-grants/project-grants.componen
MatPaginatorModule,
MatFormFieldModule,
MatInputModule,
ChangesModule,
MatChipsModule,
MatIconModule,
MatButtonModule,
WarnDialogModule,
MatProgressSpinnerModule,
MetaLayoutModule,
MatProgressBarModule,
ProjectRolesModule,
MatTabsModule,
MatCheckboxModule,
CardModule,
MatSelectModule,
MatTooltipModule,
MatSortModule,
PipesModule,
TranslateModule,
HasRolePipeModule,
TimestampToDatePipeModule,
SharedModule,
],
schemas: [NO_ERRORS_SCHEMA],
})
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 {
this.projectService.UpdateProjectGrant(this.grant.id, this.grant.projectId, selectionChange.value)
.then((newgrant: ProjectGrant) => {
this.toast.showInfo('Grant updated!');
this.toast.showInfo('PROJECT.TOAST.GRANTUPDATED');
}).catch(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 { MatPaginatorModule } from '@angular/material/paginator';
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 { MatTooltipModule } from '@angular/material/tooltip';
import { TranslateModule } from '@ngx-translate/core';
@ -36,8 +34,6 @@ import { ProjectGrantMembersModule } from './project-grant-members/project-grant
MatTableModule,
MatPaginatorModule,
MatFormFieldModule,
MatSelectModule,
MatSortModule,
MatTooltipModule,
ReactiveFormsModule,
MatProgressSpinnerModule,

View File

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

View File

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

View File

@ -13,7 +13,7 @@ import { MatTooltipModule } from '@angular/material/tooltip';
import { TranslateModule } from '@ngx-translate/core';
import { CardModule } from 'src/app/modules/card/card.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 { ProjectGrantCreateComponent } from './project-grant-create.component';
@ -33,7 +33,7 @@ import { ProjectGrantCreateComponent } from './project-grant-create.component';
ProjectRolesModule,
MatIconModule,
MatTooltipModule,
PipesModule,
HasRolePipeModule,
ReactiveFormsModule,
MatProgressSpinnerModule,
FormsModule,

View File

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

View File

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

View File

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

View File

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

View File

@ -1,5 +1,5 @@
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 { MatFormFieldModule } from '@angular/material/form-field';
import { MatIconModule } from '@angular/material/icon';
@ -10,6 +10,7 @@ import {
SearchProjectAutocompleteModule,
} 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 { SharedModule } from 'src/app/modules/shared/shared.module';
import { ProjectRolesModule } from '../../modules/project-roles/project-roles.module';
import { UserGrantCreateRoutingModule } from './user-grant-create-routing.module';
@ -31,9 +32,7 @@ import { UserGrantCreateComponent } from './user-grant-create.component';
SearchProjectAutocompleteModule,
SearchUserAutocompleteModule,
ProjectRolesModule,
],
schemas: [
CUSTOM_ELEMENTS_SCHEMA,
SharedModule,
],
})
export class UserGrantCreateModule { }

View File

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

View File

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

View File

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

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