diff --git a/console/src/app/app-routing.module.ts b/console/src/app/app-routing.module.ts index 77b867b51b..a7ec050286 100644 --- a/console/src/app/app-routing.module.ts +++ b/console/src/app/app-routing.module.ts @@ -55,11 +55,28 @@ 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), }, + { path: 'signedout', loadChildren: () => import('./pages/signedout/signedout.module').then(m => m.SignedoutModule), diff --git a/console/src/app/app.module.ts b/console/src/app/app.module.ts index 1d49a5a55d..c27d11e188 100644 --- a/console/src/app/app.module.ts +++ b/console/src/app/app.module.ts @@ -103,7 +103,7 @@ export let authConfig = { MatMenuModule, MatSnackBarModule, AvatarModule, - ServiceWorkerModule.register('ngsw-worker.js', { enabled: environment.production }), + ServiceWorkerModule.register('ngsw-config.json', { enabled: environment.production }), ], providers: [ ThemeService, diff --git a/console/src/app/modules/accounts-card/accounts-card.component.html b/console/src/app/modules/accounts-card/accounts-card.component.html index 6d8b93598e..8ec771c0dd 100644 --- a/console/src/app/modules/accounts-card/accounts-card.component.html +++ b/console/src/app/modules/accounts-card/accounts-card.component.html @@ -11,8 +11,8 @@
- +
diff --git a/console/src/app/modules/accounts-card/accounts-card.component.ts b/console/src/app/modules/accounts-card/accounts-card.component.ts index d7860efce9..b8a15ea6c5 100644 --- a/console/src/app/modules/accounts-card/accounts-card.component.ts +++ b/console/src/app/modules/accounts-card/accounts-card.component.ts @@ -17,10 +17,7 @@ export class AccountsCardComponent implements OnInit { @Output() public close: EventEmitter = new EventEmitter(); public users: UserSessionView.AsObject[] = []; public loadingUsers: boolean = false; - constructor(public authService: AuthService, private router: Router, private userService: AuthUserService) { } - - public ngOnInit(): void { - this.loadingUsers = true; + constructor(public authService: AuthService, private router: Router, private userService: AuthUserService) { this.userService.getMyUserSessions().then(sessions => { this.users = sessions.toObject().userSessionsList; @@ -33,6 +30,10 @@ export class AccountsCardComponent implements OnInit { }); } + public ngOnInit(): void { + this.loadingUsers = true; + } + public editUserProfile(): void { this.router.navigate(['user/me']); this.close.emit(); diff --git a/console/src/app/modules/changes/changes.component.ts b/console/src/app/modules/changes/changes.component.ts index 55d503df4c..406dbc69e4 100644 --- a/console/src/app/modules/changes/changes.component.ts +++ b/console/src/app/modules/changes/changes.component.ts @@ -23,12 +23,10 @@ export class ChangesComponent implements OnInit { @Input() public sortDirectionAsc: boolean = true; public bottom: boolean = false; - // Source data private _done: BehaviorSubject = new BehaviorSubject(false); private _loading: BehaviorSubject = new BehaviorSubject(false); private _data: BehaviorSubject = new BehaviorSubject([]); - // Observable data loading: Observable = this._loading.asObservable(); public data!: Observable; public changes!: Changes.AsObject; diff --git a/console/src/app/modules/meta-layout/meta-layout.component.ts b/console/src/app/modules/meta-layout/meta-layout.component.ts index f6a6bf710f..f96b778b75 100644 --- a/console/src/app/modules/meta-layout/meta-layout.component.ts +++ b/console/src/app/modules/meta-layout/meta-layout.component.ts @@ -19,6 +19,4 @@ export class MetaLayoutComponent { .pipe(map(result => { return result.matches; })); - - } diff --git a/console/src/app/modules/project-contributors/project-contributors.component.html b/console/src/app/modules/project-contributors/project-contributors.component.html index a33ea92402..e4934c6d4d 100644 --- a/console/src/app/modules/project-contributors/project-contributors.component.html +++ b/console/src/app/modules/project-contributors/project-contributors.component.html @@ -7,10 +7,8 @@
- diff --git a/console/src/app/modules/project-contributors/project-contributors.component.scss b/console/src/app/modules/project-contributors/project-contributors.component.scss index 79b450fb88..75a5859de1 100644 --- a/console/src/app/modules/project-contributors/project-contributors.component.scss +++ b/console/src/app/modules/project-contributors/project-contributors.component.scss @@ -30,11 +30,16 @@ align-items: center; .avatar-circle { - float: left; - margin: 0 8px 0 -15px; - height: 32px; - width: 32px; - border-radius: 50%; + float: left; + margin: 0 8px 0 -15px; + height: 32px; + width: 32px; + border-radius: 50%; + &:not(:first-child) { + -webkit-box-shadow: -9px 0px 20px -6px rgba(0,0,0,0.75); + -moz-box-shadow: -9px 0px 20px -6px rgba(0,0,0,0.75); + box-shadow: -9px 0px 20px -6px rgba(0,0,0,0.75); + } } .add-img { diff --git a/console/src/app/modules/project-members/project-members.component.ts b/console/src/app/modules/project-members/project-members.component.ts index 55cb6a9d26..efc10295de 100644 --- a/console/src/app/modules/project-members/project-members.component.ts +++ b/console/src/app/modules/project-members/project-members.component.ts @@ -38,7 +38,6 @@ export class ProjectMembersComponent implements AfterViewInit { private route: ActivatedRoute) { this.route.data.pipe(take(1)).subscribe(data => { this.projectType = data.type; - console.log(data); this.getRoleOptions(); @@ -156,6 +155,5 @@ export class ProjectMembersComponent implements AfterViewInit { }).catch(error => { this.toast.showError(error.message); }); - } } diff --git a/console/src/app/modules/project-roles/project-roles.module.ts b/console/src/app/modules/project-roles/project-roles.module.ts index 36914707ec..b1de8f3416 100644 --- a/console/src/app/modules/project-roles/project-roles.module.ts +++ b/console/src/app/modules/project-roles/project-roles.module.ts @@ -3,6 +3,7 @@ import { NgModule } from '@angular/core'; import { FormsModule, ReactiveFormsModule } from '@angular/forms'; import { MatButtonModule } from '@angular/material/button'; import { MatCheckboxModule } from '@angular/material/checkbox'; +import { MatDialogModule } from '@angular/material/dialog'; import { MatFormFieldModule } from '@angular/material/form-field'; import { MatIconModule } from '@angular/material/icon'; import { MatInputModule } from '@angular/material/input'; @@ -28,6 +29,7 @@ import { ProjectRolesComponent } from './project-roles.component'; HasRoleModule, MatTableModule, MatPaginatorModule, + MatDialogModule, MatFormFieldModule, FormsModule, ReactiveFormsModule, diff --git a/console/src/app/modules/user-grants/user-grants-datasource.ts b/console/src/app/modules/user-grants/user-grants-datasource.ts index 3cea1f8e73..9a88fe96a1 100644 --- a/console/src/app/modules/user-grants/user-grants-datasource.ts +++ b/console/src/app/modules/user-grants/user-grants-datasource.ts @@ -1,9 +1,21 @@ import { DataSource } from '@angular/cdk/collections'; import { BehaviorSubject, from, Observable, of } from 'rxjs'; import { catchError, finalize, map } from 'rxjs/operators'; -import { UserGrant, UserGrantSearchKey, UserGrantSearchQuery } from 'src/app/proto/generated/management_pb'; +import { + UserGrant, + UserGrantSearchKey, + UserGrantSearchQuery, + UserGrantSearchResponse, +} from 'src/app/proto/generated/management_pb'; import { MgmtUserService } from 'src/app/services/mgmt-user.service'; +export enum UserGrantContext { + // AUTHUSER = 'authuser', + USER = 'user', + OWNED_PROJECT = 'owned', + GRANTED_PROJECT = 'granted', +} + export class UserGrantsDataSource extends DataSource { public totalResult: number = 0; public grantsSubject: BehaviorSubject = new BehaviorSubject([]); @@ -14,17 +26,54 @@ export class UserGrantsDataSource extends DataSource { super(); } - public loadGrants(filter: UserGrantSearchKey, userId: string, pageIndex: number, pageSize: number): void { + public loadGrants( + context: UserGrantContext, + pageIndex: number, + pageSize: number, + data: { + projectId?: string; + grantId?: string; + userId?: string; + }, + queries?: UserGrantSearchQuery[], + ): void { const offset = pageIndex * pageSize; this.loadingSubject.next(true); - const query = new UserGrantSearchQuery(); - query.setKey(filter); - query.setValue(userId); + switch (context) { + case UserGrantContext.USER: + if (data && data.userId) { + const userfilter = new UserGrantSearchQuery(); + userfilter.setKey(UserGrantSearchKey.USERGRANTSEARCHKEY_USER_ID); + userfilter.setValue(data.userId); + if (queries) { + queries.push(userfilter); + } else { + queries = [userfilter]; + } - const queries: UserGrantSearchQuery[] = [query]; - from(this.userService.SearchUserGrants(10, 0, queries)).pipe( + const promise = this.userService.SearchUserGrants(10, 0, queries); + this.loadResponse(promise); + } + break; + case UserGrantContext.OWNED_PROJECT: + if (data && data.projectId) { + const promise1 = this.userService.SearchProjectUserGrants(data.projectId, 10, 0, queries); + this.loadResponse(promise1); + } + break; + case UserGrantContext.GRANTED_PROJECT: + if (data && data.grantId) { + const promise2 = this.userService.SearchProjectGrantUserGrants(data.grantId, 10, 0, queries); + this.loadResponse(promise2); + } + break; + } + } + + private loadResponse(promise: Promise): void { + from(promise).pipe( map(resp => { this.totalResult = resp.toObject().totalResult; console.log(resp.toObject().resultList); diff --git a/console/src/app/modules/user-grants/user-grants.component.html b/console/src/app/modules/user-grants/user-grants.component.html index 6aefd7006c..f3aa5212f0 100644 --- a/console/src/app/modules/user-grants/user-grants.component.html +++ b/console/src/app/modules/user-grants/user-grants.component.html @@ -11,11 +11,11 @@
+ mat-raised-button [routerLink]="routerLink"> add{{ 'GRANTS.ADD_BTN' | translate }}
@@ -86,7 +86,7 @@ - + {{ 'PROJECT.GRANT.TITLE' | translate }} diff --git a/console/src/app/modules/user-grants/user-grants.component.ts b/console/src/app/modules/user-grants/user-grants.component.ts index 02b933a308..a46a202478 100644 --- a/console/src/app/modules/user-grants/user-grants.component.ts +++ b/console/src/app/modules/user-grants/user-grants.component.ts @@ -4,12 +4,12 @@ import { MatPaginator } 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, UserGrantSearchKey } from 'src/app/proto/generated/management_pb'; +import { ProjectGrant, ProjectRoleView, UserGrant } 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'; -import { UserGrantsDataSource } from './user-grants-datasource'; +import { UserGrantContext, UserGrantsDataSource } from './user-grants-datasource'; @Component({ selector: 'app-user-grants', @@ -17,8 +17,9 @@ import { 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() filterValue: string = ''; + // @Input() filter: UserGrantSearchKey = UserGrantSearchKey.USERGRANTSEARCHKEY_USER_ID; + @Input() context: UserGrantContext = UserGrantContext.USER; public grants: UserGrant.AsObject[] = []; public dataSource!: UserGrantsDataSource; @@ -29,7 +30,12 @@ export class UserGrantsComponent implements OnInit, AfterViewInit { @Input() allowCreate: boolean = false; @Input() allowDelete: boolean = false; + @Input() userId: string = ''; + @Input() projectId: string = ''; + @Input() grantId: string = ''; + public roleOptions: ProjectRoleView.AsObject[] = []; + public routerLink: any = ['']; constructor( private userService: MgmtUserService, @@ -44,11 +50,35 @@ export class UserGrantsComponent implements OnInit, AfterViewInit { public ngOnInit(): void { this.dataSource = new UserGrantsDataSource(this.userService); - this.dataSource.loadGrants(this.filter, this.filterValue, 0, 25); + const data = { + projectId: this.projectId, + grantId: this.grantId, + userId: this.userId, + }; + console.log(this.context); - if (this.filter === UserGrantSearchKey.USERGRANTSEARCHKEY_PROJECT_ID) { - this.getRoleOptions(this.filterValue); + switch (this.context) { + case UserGrantContext.OWNED_PROJECT: + if (this.projectId) { + this.getRoleOptions(this.projectId); + this.routerLink = ['/grant-create', 'project', this.projectId]; + } + break; + case UserGrantContext.GRANTED_PROJECT: + if (data && data.grantId) { + this.routerLink = ['/grant-create', 'project', this.projectId, 'grant', this.grantId]; + } + break; + case UserGrantContext.USER: + if (this.userId) { + this.routerLink = ['/grant-create', 'user', this.userId]; + } + break; + default: + this.routerLink = ['/grant-create']; } + console.log(data); + this.dataSource.loadGrants(this.context, 0, 25, data); } public ngAfterViewInit(): void { @@ -61,10 +91,13 @@ export class UserGrantsComponent implements OnInit, AfterViewInit { private loadGrantsPage(): void { this.dataSource.loadGrants( - this.filter, - this.filterValue, + this.context, this.paginator.pageIndex, this.paginator.pageSize, + { + projectId: this.projectId, + grantId: this.grantId, + }, ); } @@ -81,7 +114,7 @@ export class UserGrantsComponent implements OnInit, AfterViewInit { } public loadRoleOptions(projectId: string): void { - if (this.filter === UserGrantSearchKey.USERGRANTSEARCHKEY_USER_ID) { + if (this.context === UserGrantContext.USER) { this.getRoleOptions(projectId); } } @@ -103,4 +136,13 @@ export class UserGrantsComponent implements OnInit, AfterViewInit { this.toast.showError(error.message); }); } + + deleteGrantSelection(): void { + this.userService.BulkRemoveUserGrant(this.selection.selected.map(grant => grant.id)).then(() => { + this.toast.showInfo('Grants deleted'); + this.loadGrantsPage(); + }).catch(error => { + this.toast.showError(error.message); + }); + } } diff --git a/console/src/app/pages/granted-projects/granted-project-detail/granted-project-detail.component.html b/console/src/app/pages/granted-projects/granted-project-detail/granted-project-detail.component.html index d3b415705c..ff813d2b05 100644 --- a/console/src/app/pages/granted-projects/granted-project-detail/granted-project-detail.component.html +++ b/console/src/app/pages/granted-projects/granted-project-detail/granted-project-detail.component.html @@ -15,7 +15,7 @@ - diff --git a/console/src/app/pages/granted-projects/granted-project-detail/granted-project-detail.component.ts b/console/src/app/pages/granted-projects/granted-project-detail/granted-project-detail.component.ts index 64135bff17..ab19803a3c 100644 --- a/console/src/app/pages/granted-projects/granted-project-detail/granted-project-detail.component.ts +++ b/console/src/app/pages/granted-projects/granted-project-detail/granted-project-detail.component.ts @@ -6,6 +6,7 @@ import { ActivatedRoute, Params } from '@angular/router'; import { TranslateService } from '@ngx-translate/core'; import { Subscription } from 'rxjs'; import { ChangeType } from 'src/app/modules/changes/changes.component'; +import { UserGrantContext } from 'src/app/modules/user-grants/user-grants-datasource'; import { Application, ApplicationSearchResponse, @@ -58,6 +59,7 @@ export class GrantedProjectDetailComponent implements OnInit, OnDestroy { public isZitadel: boolean = false; + public userGrantContext: UserGrantContext = UserGrantContext.GRANTED_PROJECT; public userGrantSearchKey: UserGrantSearchKey = UserGrantSearchKey.USERGRANTSEARCHKEY_PROJECT_ID; constructor( diff --git a/console/src/app/pages/granted-projects/granted-projects.module.ts b/console/src/app/pages/granted-projects/granted-projects.module.ts index 89feee4bc5..1d1b62285a 100644 --- a/console/src/app/pages/granted-projects/granted-projects.module.ts +++ b/console/src/app/pages/granted-projects/granted-projects.module.ts @@ -3,10 +3,7 @@ import { HttpClient } from '@angular/common/http'; import { NgModule, NO_ERRORS_SCHEMA } from '@angular/core'; import { FormsModule, ReactiveFormsModule } from '@angular/forms'; import { MatButtonModule } from '@angular/material/button'; -import { MatButtonToggleModule } from '@angular/material/button-toggle'; import { MatCheckboxModule } from '@angular/material/checkbox'; -import { MatChipsModule } from '@angular/material/chips'; -import { MatDialogModule } from '@angular/material/dialog'; import { MatFormFieldModule } from '@angular/material/form-field'; import { MatIconModule } from '@angular/material/icon'; import { MatInputModule } from '@angular/material/input'; @@ -29,10 +26,7 @@ import { ChangesModule } from '../../modules/changes/changes.module'; import { MetaLayoutModule } from '../../modules/meta-layout/meta-layout.module'; import { ProjectContributorsModule } from '../../modules/project-contributors/project-contributors.module'; import { ProjectRolesModule } from '../../modules/project-roles/project-roles.module'; -import { SearchUserAutocompleteModule } from '../../modules/search-user-autocomplete/search-user-autocomplete.module'; import { PipesModule } from '../../pipes/pipes.module'; -import { OrgContributorsModule } from '../orgs/org-contributors/org-contributors.module'; -import { UserListModule } from '../user-list/user-list.module'; import { GrantedProjectDetailComponent } from './granted-project-detail/granted-project-detail.component'; import { GrantedProjectGridComponent } from './granted-project-grid/granted-project-grid.component'; import { GrantedProjectListComponent } from './granted-project-list/granted-project-list.component'; @@ -57,29 +51,23 @@ import { GrantedProjectsComponent } from './granted-projects.component'; HasRoleModule, MatTableModule, MatPaginatorModule, + MatMenuModule, MatFormFieldModule, MatInputModule, ChangesModule, - UserListModule, - MatMenuModule, - MatChipsModule, MatIconModule, MatSelectModule, MatButtonModule, MatProgressSpinnerModule, MetaLayoutModule, MatProgressBarModule, - MatDialogModule, - MatButtonToggleModule, MatTabsModule, ProjectRolesModule, - SearchUserAutocompleteModule, MatCheckboxModule, CardModule, MatTooltipModule, MatSortModule, PipesModule, - OrgContributorsModule, TranslateModule.forChild({ loader: { provide: TranslateLoader, diff --git a/console/src/app/pages/iam/iam-contributors/iam-contributors.component.scss b/console/src/app/pages/iam/iam-contributors/iam-contributors.component.scss index 1d9b82ea22..b9ecafc16d 100644 --- a/console/src/app/pages/iam/iam-contributors/iam-contributors.component.scss +++ b/console/src/app/pages/iam/iam-contributors/iam-contributors.component.scss @@ -30,11 +30,16 @@ align-items: center; .avatar-img, .avatar-circle { - float: left; - margin: 0 8px 0 -15px; - height: 32px; - width: 32px; - border-radius: 50%; + float: left; + margin: 0 8px 0 -15px; + height: 32px; + width: 32px; + border-radius: 50%; + &:not(:first-child) { + -webkit-box-shadow: -9px 0px 20px -6px rgba(0,0,0,0.75); + -moz-box-shadow: -9px 0px 20px -6px rgba(0,0,0,0.75); + box-shadow: -9px 0px 20px -6px rgba(0,0,0,0.75); + } } .add-img { diff --git a/console/src/app/pages/iam/iam-views/iam-views.component.ts b/console/src/app/pages/iam/iam-views/iam-views.component.ts index 1455838ffd..c2de7220f8 100644 --- a/console/src/app/pages/iam/iam-views/iam-views.component.ts +++ b/console/src/app/pages/iam/iam-views/iam-views.component.ts @@ -39,6 +39,7 @@ export class IamViewsComponent { ).subscribe(views => { this.dataSource = new MatTableDataSource(views); this.dataSource.paginator = this.paginator; + this.dataSource.sort = this.sort; }); } diff --git a/console/src/app/pages/iam/iam.component.html b/console/src/app/pages/iam/iam.component.html index 43a267cd66..b8e7ccd6e5 100644 --- a/console/src/app/pages/iam/iam.component.html +++ b/console/src/app/pages/iam/iam.component.html @@ -9,17 +9,7 @@
- - - - \ No newline at end of file diff --git a/console/src/app/pages/iam/iam.component.ts b/console/src/app/pages/iam/iam.component.ts index 89c311c823..3e5d5a7a37 100644 --- a/console/src/app/pages/iam/iam.component.ts +++ b/console/src/app/pages/iam/iam.component.ts @@ -1,17 +1,9 @@ -import { Component, OnInit } from '@angular/core'; +import { Component } from '@angular/core'; @Component({ selector: 'app-iam', templateUrl: './iam.component.html', styleUrls: ['./iam.component.scss'], }) -export class IamComponent implements OnInit { - - constructor() { - - } - - ngOnInit(): void { - } - +export class IamComponent { } diff --git a/console/src/app/pages/orgs/org-contributors/org-contributors.component.scss b/console/src/app/pages/orgs/org-contributors/org-contributors.component.scss index 1d9b82ea22..2b3edbf6ad 100644 --- a/console/src/app/pages/orgs/org-contributors/org-contributors.component.scss +++ b/console/src/app/pages/orgs/org-contributors/org-contributors.component.scss @@ -35,6 +35,11 @@ height: 32px; width: 32px; border-radius: 50%; + &:not(:first-child) { + -webkit-box-shadow: -9px 0px 20px -6px rgba(0,0,0,0.75); + -moz-box-shadow: -9px 0px 20px -6px rgba(0,0,0,0.75); + box-shadow: -9px 0px 20px -6px rgba(0,0,0,0.75); + } } .add-img { diff --git a/console/src/app/pages/owned-projects/owned-project-detail/owned-project-detail.component.html b/console/src/app/pages/owned-projects/owned-project-detail/owned-project-detail.component.html index ed4cfab060..e8b257015b 100644 --- a/console/src/app/pages/owned-projects/owned-project-detail/owned-project-detail.component.html +++ b/console/src/app/pages/owned-projects/owned-project-detail/owned-project-detail.component.html @@ -78,7 +78,7 @@ - diff --git a/console/src/app/pages/owned-projects/owned-project-detail/owned-project-detail.component.ts b/console/src/app/pages/owned-projects/owned-project-detail/owned-project-detail.component.ts index 6cc617aedf..2a73e9a77d 100644 --- a/console/src/app/pages/owned-projects/owned-project-detail/owned-project-detail.component.ts +++ b/console/src/app/pages/owned-projects/owned-project-detail/owned-project-detail.component.ts @@ -6,6 +6,7 @@ import { ActivatedRoute, Params } from '@angular/router'; import { TranslateService } from '@ngx-translate/core'; import { Subscription } from 'rxjs'; import { ChangeType } from 'src/app/modules/changes/changes.component'; +import { UserGrantContext } from 'src/app/modules/user-grants/user-grants-datasource'; import { Application, ApplicationSearchResponse, @@ -59,6 +60,7 @@ export class OwnedProjectDetailComponent implements OnInit, OnDestroy { public isZitadel: boolean = false; public userGrantSearchKey: UserGrantSearchKey = UserGrantSearchKey.USERGRANTSEARCHKEY_PROJECT_ID; + public userGrantContext: UserGrantContext = UserGrantContext.OWNED_PROJECT; constructor( public translate: TranslateService, diff --git a/console/src/app/pages/owned-projects/owned-projects.component.spec.ts b/console/src/app/pages/owned-projects/owned-projects.component.spec.ts index a33e1cc85a..6b6dfb2dca 100644 --- a/console/src/app/pages/owned-projects/owned-projects.component.spec.ts +++ b/console/src/app/pages/owned-projects/owned-projects.component.spec.ts @@ -1,20 +1,20 @@ import { async, ComponentFixture, TestBed } from '@angular/core/testing'; -import { ProjectsComponent } from './projects.component'; +import { OwnedProjectsComponent } from './owned-projects.component'; -describe('ProjectsComponent', () => { - let component: ProjectsComponent; - let fixture: ComponentFixture; +describe('OwnedProjectComponent', () => { + let component: OwnedProjectsComponent; + let fixture: ComponentFixture; beforeEach(async(() => { TestBed.configureTestingModule({ - declarations: [ProjectsComponent], + declarations: [OwnedProjectsComponent], }) .compileComponents(); })); beforeEach(() => { - fixture = TestBed.createComponent(ProjectsComponent); + fixture = TestBed.createComponent(OwnedProjectsComponent); component = fixture.componentInstance; fixture.detectChanges(); }); diff --git a/console/src/app/pages/owned-projects/owned-projects.module.ts b/console/src/app/pages/owned-projects/owned-projects.module.ts index c658f1b141..1e7d69a1e6 100644 --- a/console/src/app/pages/owned-projects/owned-projects.module.ts +++ b/console/src/app/pages/owned-projects/owned-projects.module.ts @@ -3,10 +3,8 @@ import { HttpClient } from '@angular/common/http'; import { NgModule, NO_ERRORS_SCHEMA } from '@angular/core'; import { FormsModule, ReactiveFormsModule } from '@angular/forms'; import { MatButtonModule } from '@angular/material/button'; -import { MatButtonToggleModule } from '@angular/material/button-toggle'; import { MatCheckboxModule } from '@angular/material/checkbox'; import { MatChipsModule } from '@angular/material/chips'; -import { MatDialogModule } from '@angular/material/dialog'; import { MatFormFieldModule } from '@angular/material/form-field'; import { MatIconModule } from '@angular/material/icon'; import { MatInputModule } from '@angular/material/input'; @@ -14,14 +12,13 @@ import { MatMenuModule } from '@angular/material/menu'; 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 { TranslateLoader, TranslateModule } from '@ngx-translate/core'; import { AvatarModule } from 'src/app/modules/avatar/avatar.module'; -import { ProjectGrantMembersModule } from 'src/app/modules/project-grant-members/project-grant-members.module'; +import { ProjectRolesModule } from 'src/app/modules/project-roles/project-roles.module'; import { UserGrantsModule } from 'src/app/modules/user-grants/user-grants.module'; import { HttpLoaderFactory } from '../../app.module'; @@ -30,10 +27,7 @@ import { CardModule } from '../../modules/card/card.module'; import { ChangesModule } from '../../modules/changes/changes.module'; import { MetaLayoutModule } from '../../modules/meta-layout/meta-layout.module'; import { ProjectContributorsModule } from '../../modules/project-contributors/project-contributors.module'; -import { ProjectRolesModule } from '../../modules/project-roles/project-roles.module'; -import { SearchUserAutocompleteModule } from '../../modules/search-user-autocomplete/search-user-autocomplete.module'; import { PipesModule } from '../../pipes/pipes.module'; -import { OrgContributorsModule } from '../orgs/org-contributors/org-contributors.module'; import { UserListModule } from '../user-list/user-list.module'; import { OwnedProjectDetailComponent } from './owned-project-detail/owned-project-detail.component'; import { OwnedProjectGridComponent } from './owned-project-grid/owned-project-grid.component'; @@ -59,7 +53,6 @@ import { ProjectGrantsComponent } from './project-grants/project-grants.componen OwnedProjectsRoutingModule, UserGrantsModule, ProjectContributorsModule, - ProjectGrantMembersModule, FormsModule, TranslateModule, AvatarModule, @@ -74,22 +67,17 @@ import { ProjectGrantsComponent } from './project-grants/project-grants.componen MatMenuModule, MatChipsModule, MatIconModule, - MatSelectModule, MatButtonModule, MatProgressSpinnerModule, MetaLayoutModule, MatProgressBarModule, - MatDialogModule, - MatButtonToggleModule, - MatTabsModule, ProjectRolesModule, - SearchUserAutocompleteModule, + MatTabsModule, MatCheckboxModule, CardModule, MatTooltipModule, MatSortModule, PipesModule, - OrgContributorsModule, TranslateModule.forChild({ loader: { provide: TranslateLoader, diff --git a/console/src/app/pages/owned-projects/project-grant-detail/project-grant-detail.module.ts b/console/src/app/pages/owned-projects/project-grant-detail/project-grant-detail.module.ts index ac10171f11..ea075c7b35 100644 --- a/console/src/app/pages/owned-projects/project-grant-detail/project-grant-detail.module.ts +++ b/console/src/app/pages/owned-projects/project-grant-detail/project-grant-detail.module.ts @@ -13,10 +13,10 @@ 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 { ProjectGrantMembersModule } from 'src/app/modules/project-grant-members/project-grant-members.module'; import { ProjectGrantDetailRoutingModule } from './project-grant-detail-routing.module'; import { ProjectGrantDetailComponent } from './project-grant-detail.component'; +import { ProjectGrantMembersModule } from './project-grant-members/project-grant-members.module'; @NgModule({ diff --git a/console/src/app/modules/project-grant-members/project-grant-members-create-dialog/project-grant-members-create-dialog.component.html b/console/src/app/pages/owned-projects/project-grant-detail/project-grant-members/project-grant-members-create-dialog/project-grant-members-create-dialog.component.html similarity index 100% rename from console/src/app/modules/project-grant-members/project-grant-members-create-dialog/project-grant-members-create-dialog.component.html rename to console/src/app/pages/owned-projects/project-grant-detail/project-grant-members/project-grant-members-create-dialog/project-grant-members-create-dialog.component.html diff --git a/console/src/app/modules/project-grant-members/project-grant-members-create-dialog/project-grant-members-create-dialog.component.scss b/console/src/app/pages/owned-projects/project-grant-detail/project-grant-members/project-grant-members-create-dialog/project-grant-members-create-dialog.component.scss similarity index 100% rename from console/src/app/modules/project-grant-members/project-grant-members-create-dialog/project-grant-members-create-dialog.component.scss rename to console/src/app/pages/owned-projects/project-grant-detail/project-grant-members/project-grant-members-create-dialog/project-grant-members-create-dialog.component.scss diff --git a/console/src/app/modules/project-grant-members/project-grant-members-create-dialog/project-grant-members-create-dialog.component.spec.ts b/console/src/app/pages/owned-projects/project-grant-detail/project-grant-members/project-grant-members-create-dialog/project-grant-members-create-dialog.component.spec.ts similarity index 100% rename from console/src/app/modules/project-grant-members/project-grant-members-create-dialog/project-grant-members-create-dialog.component.spec.ts rename to console/src/app/pages/owned-projects/project-grant-detail/project-grant-members/project-grant-members-create-dialog/project-grant-members-create-dialog.component.spec.ts diff --git a/console/src/app/modules/project-grant-members/project-grant-members-create-dialog/project-grant-members-create-dialog.component.ts b/console/src/app/pages/owned-projects/project-grant-detail/project-grant-members/project-grant-members-create-dialog/project-grant-members-create-dialog.component.ts similarity index 100% rename from console/src/app/modules/project-grant-members/project-grant-members-create-dialog/project-grant-members-create-dialog.component.ts rename to console/src/app/pages/owned-projects/project-grant-detail/project-grant-members/project-grant-members-create-dialog/project-grant-members-create-dialog.component.ts diff --git a/console/src/app/pages/owned-projects/project-grant-detail/project-grant-members/project-grant-members-create-dialog/project-grant-members-create-dialog.module.ts b/console/src/app/pages/owned-projects/project-grant-detail/project-grant-members/project-grant-members-create-dialog/project-grant-members-create-dialog.module.ts new file mode 100644 index 0000000000..c39fcbb047 --- /dev/null +++ b/console/src/app/pages/owned-projects/project-grant-detail/project-grant-members/project-grant-members-create-dialog/project-grant-members-create-dialog.module.ts @@ -0,0 +1,30 @@ +import { CommonModule } from '@angular/common'; +import { NgModule } from '@angular/core'; +import { FormsModule } from '@angular/forms'; +import { MatButtonModule } from '@angular/material/button'; +import { MatDialogModule } from '@angular/material/dialog'; +import { MatFormFieldModule } from '@angular/material/form-field'; +import { MatSelectModule } from '@angular/material/select'; +import { TranslateModule } from '@ngx-translate/core'; +import { SearchUserAutocompleteModule } from 'src/app/modules/search-user-autocomplete/search-user-autocomplete.module'; + +import { ProjectGrantMembersCreateDialogComponent } from './project-grant-members-create-dialog.component'; + +@NgModule({ + declarations: [ProjectGrantMembersCreateDialogComponent], + imports: [ + CommonModule, + FormsModule, + MatDialogModule, + MatButtonModule, + TranslateModule, + MatSelectModule, + MatFormFieldModule, + SearchUserAutocompleteModule, + ], + entryComponents: [ + ProjectGrantMembersCreateDialogComponent, + ], +}) +export class ProjectGrantMembersCreateDialogModule { } + diff --git a/console/src/app/modules/project-grant-members/project-grant-members-datasource.ts b/console/src/app/pages/owned-projects/project-grant-detail/project-grant-members/project-grant-members-datasource.ts similarity index 94% rename from console/src/app/modules/project-grant-members/project-grant-members-datasource.ts rename to console/src/app/pages/owned-projects/project-grant-detail/project-grant-members/project-grant-members-datasource.ts index 926826b9d7..6c8228f14f 100644 --- a/console/src/app/modules/project-grant-members/project-grant-members-datasource.ts +++ b/console/src/app/pages/owned-projects/project-grant-detail/project-grant-members/project-grant-members-datasource.ts @@ -19,8 +19,8 @@ export class ProjectGrantMembersDataSource extends DataSource {{ 'PROJECT.MEMBER.ROLES' | translate }} - - - {{ 'ROLES.'+role | translate }} - - - - - - - - - - - + + + {{ 'PROJECT.GRANT.TITLE' | translate }} + + + {{ 'ROLES.'+role | translate }} + + + diff --git a/console/src/app/modules/project-grant-members/project-grant-members.component.scss b/console/src/app/pages/owned-projects/project-grant-detail/project-grant-members/project-grant-members.component.scss similarity index 100% rename from console/src/app/modules/project-grant-members/project-grant-members.component.scss rename to console/src/app/pages/owned-projects/project-grant-detail/project-grant-members/project-grant-members.component.scss diff --git a/console/src/app/modules/project-grant-members/project-grant-members.component.spec.ts b/console/src/app/pages/owned-projects/project-grant-detail/project-grant-members/project-grant-members.component.spec.ts similarity index 100% rename from console/src/app/modules/project-grant-members/project-grant-members.component.spec.ts rename to console/src/app/pages/owned-projects/project-grant-detail/project-grant-members/project-grant-members.component.spec.ts diff --git a/console/src/app/modules/project-grant-members/project-grant-members.component.ts b/console/src/app/pages/owned-projects/project-grant-detail/project-grant-members/project-grant-members.component.ts similarity index 75% rename from console/src/app/modules/project-grant-members/project-grant-members.component.ts rename to console/src/app/pages/owned-projects/project-grant-detail/project-grant-members/project-grant-members.component.ts index 9b30e170e7..f91cb961c3 100644 --- a/console/src/app/modules/project-grant-members/project-grant-members.component.ts +++ b/console/src/app/pages/owned-projects/project-grant-detail/project-grant-members/project-grant-members.component.ts @@ -2,6 +2,7 @@ import { SelectionModel } from '@angular/cdk/collections'; import { AfterViewInit, Component, Input, OnInit, ViewChild } from '@angular/core'; import { MatDialog } from '@angular/material/dialog'; import { MatPaginator } from '@angular/material/paginator'; +import { MatSelectChange } from '@angular/material/select'; import { MatTable } from '@angular/material/table'; import { tap } from 'rxjs/operators'; import { ProjectMember, ProjectType } from 'src/app/proto/generated/management_pb'; @@ -35,17 +36,19 @@ export class ProjectGrantMembersComponent implements AfterViewInit, OnInit { public displayedColumns: string[] = ['select', 'firstname', 'lastname', 'username', 'email', 'roles']; public ProjectType: any = ProjectType; + public memberRoleOptions: string[] = []; constructor( private projectService: ProjectService, private dialog: MatDialog, private toast: ToastService, - ) { } + ) { + this.dataSource = new ProjectGrantMembersDataSource(this.projectService); + this.getRoleOptions(); + } public ngOnInit(): void { - this.dataSource = new ProjectGrantMembersDataSource(this.projectService); - console.log(this.projectId); - this.dataSource.loadMembers(this.projectId, this.grantId, 0, 25, 'asc'); + this.dataSource.loadGrantMembers(this.projectId, this.grantId, 0, 25); } public ngAfterViewInit(): void { @@ -56,14 +59,32 @@ export class ProjectGrantMembersComponent implements AfterViewInit, OnInit { .subscribe(); } + public getRoleOptions(): void { + if (this.type === ProjectType.PROJECTTYPE_GRANTED) { + this.projectService.GetProjectGrantMemberRoles().then(resp => { + this.memberRoleOptions = resp.toObject().rolesList; + console.log(this.memberRoleOptions); + }).catch(error => { + this.toast.showError(error.message); + }); + } else if (this.type === ProjectType.PROJECTTYPE_OWNED) { + this.projectService.GetProjectMemberRoles().then(resp => { + this.memberRoleOptions = resp.toObject().rolesList; + }).catch(error => { + this.toast.showError(error.message); + }); + } + } + private loadMembersPage(): void { - this.dataSource.loadMembers( + this.dataSource.loadGrantMembers( this.projectId, this.grantId, this.paginator.pageIndex, this.paginator.pageSize, ); } + public removeProjectMemberSelection(): void { Promise.all(this.selection.selected.map(member => { return this.projectService.RemoveProjectGrantMember(this.projectId, this.grantId, member.userId).then(() => { @@ -124,4 +145,15 @@ export class ProjectGrantMembersComponent implements AfterViewInit, OnInit { } }); } + + updateRoles(member: ProjectMember.AsObject, selectionChange: MatSelectChange): void { + console.log(this.projectId, this.grantId, member.userId, selectionChange.value); + this.projectService.ChangeProjectGrantMember(this.projectId, this.grantId, member.userId, selectionChange.value) + .then((newmember: ProjectMember) => { + console.log(newmember.toObject()); + this.toast.showInfo('Member updated!'); + }).catch(error => { + this.toast.showError(error.message); + }); + } } diff --git a/console/src/app/modules/project-grant-members/project-grant-members.module.ts b/console/src/app/pages/owned-projects/project-grant-detail/project-grant-members/project-grant-members.module.ts similarity index 77% rename from console/src/app/modules/project-grant-members/project-grant-members.module.ts rename to console/src/app/pages/owned-projects/project-grant-detail/project-grant-members/project-grant-members.module.ts index 6d1675d823..d8c3eff0e4 100644 --- a/console/src/app/modules/project-grant-members/project-grant-members.module.ts +++ b/console/src/app/pages/owned-projects/project-grant-detail/project-grant-members/project-grant-members.module.ts @@ -1,15 +1,12 @@ import { CommonModule } from '@angular/common'; import { NgModule } from '@angular/core'; import { FormsModule, ReactiveFormsModule } from '@angular/forms'; -import { MatAutocompleteModule } from '@angular/material/autocomplete'; import { MatButtonModule } from '@angular/material/button'; import { MatCheckboxModule } from '@angular/material/checkbox'; -import { MatChipsModule } from '@angular/material/chips'; import { MatDialogModule } from '@angular/material/dialog'; import { MatFormFieldModule } from '@angular/material/form-field'; import { MatIconModule } from '@angular/material/icon'; import { MatInputModule } from '@angular/material/input'; -import { MatMenuModule } from '@angular/material/menu'; import { MatPaginatorModule } from '@angular/material/paginator'; import { MatProgressSpinnerModule } from '@angular/material/progress-spinner'; import { MatSelectModule } from '@angular/material/select'; @@ -19,22 +16,19 @@ 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 { SearchUserAutocompleteModule } from 'src/app/modules/search-user-autocomplete/search-user-autocomplete.module'; -import { SearchUserAutocompleteModule } from '../search-user-autocomplete/search-user-autocomplete.module'; import { - ProjectGrantMembersCreateDialogComponent, -} from './project-grant-members-create-dialog/project-grant-members-create-dialog.component'; + ProjectGrantMembersCreateDialogModule, +} from './project-grant-members-create-dialog/project-grant-members-create-dialog.module'; import { ProjectGrantMembersComponent } from './project-grant-members.component'; @NgModule({ - declarations: [ProjectGrantMembersComponent, ProjectGrantMembersCreateDialogComponent], + declarations: [ProjectGrantMembersComponent], imports: [ CommonModule, - MatAutocompleteModule, HasRoleModule, RouterModule, - MatChipsModule, - MatMenuModule, MatButtonModule, MatCheckboxModule, MatIconModule, @@ -43,6 +37,7 @@ import { ProjectGrantMembersComponent } from './project-grant-members.component' MatSelectModule, MatTableModule, SearchUserAutocompleteModule, + ProjectGrantMembersCreateDialogModule, MatPaginatorModule, MatSortModule, MatTooltipModule, diff --git a/console/src/app/pages/owned-projects/project-grants/project-grants.component.ts b/console/src/app/pages/owned-projects/project-grants/project-grants.component.ts index 4211413a9a..abd7436514 100644 --- a/console/src/app/pages/owned-projects/project-grants/project-grants.component.ts +++ b/console/src/app/pages/owned-projects/project-grants/project-grants.component.ts @@ -5,10 +5,6 @@ import { MatDialog } from '@angular/material/dialog'; import { MatPaginator } from '@angular/material/paginator'; import { MatTable } from '@angular/material/table'; import { tap } from 'rxjs/operators'; -import { - ProjectGrantMembersCreateDialogComponent, - ProjectGrantMembersCreateDialogExportType, -} from 'src/app/modules/project-grant-members/project-grant-members-create-dialog/project-grant-members-create-dialog.component'; import { ProjectGrant, ProjectMemberView } from 'src/app/proto/generated/management_pb'; import { ProjectService } from 'src/app/services/project.service'; import { ToastService } from 'src/app/services/toast.service'; @@ -75,35 +71,4 @@ export class ProjectGrantsComponent implements OnInit, AfterViewInit { this.selection.clear() : this.dataSource.grantsSubject.value.forEach(row => this.selection.select(row)); } - - public async addProjectGrantMember(grant: ProjectGrant.AsObject): Promise { - const keysList = (await this.projectService.GetProjectGrantMemberRoles()).toObject(); - console.log(keysList); - - const dialogRef = this.dialog.open(ProjectGrantMembersCreateDialogComponent, { - data: { - roleKeysList: keysList.rolesList, - }, - width: '400px', - }); - - dialogRef.afterClosed().subscribe((dataToAdd: ProjectGrantMembersCreateDialogExportType) => { - console.log(dataToAdd); - if (dataToAdd) { - dataToAdd.userIds.forEach((userid: string) => { - this.projectService.AddProjectGrantMember( - this.projectId, - grant.id, - userid, - dataToAdd.rolesKeyList, - ).then(() => { - this.toast.showInfo('Project Grant Member successfully added!'); - }).catch(error => { - this.toast.showError(error.message); - }); - }); - - } - }); - } } diff --git a/console/src/app/pages/user-detail/auth-user-detail/auth-user-detail.component.html b/console/src/app/pages/user-detail/auth-user-detail/auth-user-detail.component.html index 1da19c8920..e2fd6e596a 100644 --- a/console/src/app/pages/user-detail/auth-user-detail/auth-user-detail.component.html +++ b/console/src/app/pages/user-detail/auth-user-detail/auth-user-detail.component.html @@ -33,80 +33,20 @@ - -
-
- - {{ 'USER.PASSWORD.OLD' | translate }} - - {{ 'USER.PASSWORD.REQUIRED' | translate }} - - - - {{ 'USER.PASSWORD.NEW' | translate }} - - - - {{ 'USER.VALIDATION.REQUIRED' | translate }} - - - {{ 'USER.VALIDATION.SYMBOLERROR' | translate }} - - - {{ 'USER.VALIDATION.NUMBERERROR' | translate }} - - - {{ 'USER.VALIDATION.UPPERCASEMISSING' | translate }} - - - {{ 'USER.VALIDATION.LOWERCASEMISSING' | translate }} - - - {{ 'USER.VALIDATION.MINLENGTH' | translate:newPassword?.errors?.minlength }} - - - - - {{ 'USER.PASSWORD.CONFIRM' | translate }} - - - - {{ 'USER.VALIDATION.REQUIRED' | translate }} - - - {{ 'USER.VALIDATION.SYMBOLERROR' | translate }} - - - {{ 'USER.VALIDATION.NUMBERERROR' | translate }} - - - {{ 'USER.PASSWORD.NOTEQUAL' | translate }} - - - {{ 'USER.VALIDATION.UPPERCASEMISSING' | translate }} - - - {{ 'USER.VALIDATION.LOWERCASEMISSING' | translate }} - - - {{ 'USER.VALIDATION.MINLENGTH' | translate:confirmPassword?.errors?.minlength }} - - -
-
- -
-
-
-
+
+ {{ 'USER.PROFILE.PASSWORD' | translate }} + + ********* + +
+
{{ 'USER.EMAIL' | translate }} @@ -166,9 +106,6 @@ -
@@ -188,36 +125,6 @@ - -
diff --git a/console/src/app/pages/user-detail/auth-user-detail/auth-user-detail.component.scss b/console/src/app/pages/user-detail/auth-user-detail/auth-user-detail.component.scss index cda88ccdac..4464061363 100644 --- a/console/src/app/pages/user-detail/auth-user-detail/auth-user-detail.component.scss +++ b/console/src/app/pages/user-detail/auth-user-detail/auth-user-detail.component.scss @@ -94,7 +94,7 @@ h1 { flex-wrap: wrap; .label, .name { - margin-right: 1rem; + margin-right: 1rem; } .actions { @@ -107,7 +107,7 @@ h1 { .label { flex: 1; font-size: .9rem; - color: #818a8a; + color: #8795a1; } mat-icon { @@ -150,6 +150,20 @@ h1 { .theme-card { max-width: 300px; } + + .pwd-row { + display: flex; + align-items: center; + + span { + flex: 1; + } + + .title { + color: #8795a1; + font-size: 0.9rem; + } + } } .side { diff --git a/console/src/app/pages/user-detail/auth-user-detail/auth-user-detail.component.ts b/console/src/app/pages/user-detail/auth-user-detail/auth-user-detail.component.ts index 5e8c1a691b..418b68ee26 100644 --- a/console/src/app/pages/user-detail/auth-user-detail/auth-user-detail.component.ts +++ b/console/src/app/pages/user-detail/auth-user-detail/auth-user-detail.component.ts @@ -1,17 +1,15 @@ import { Component, OnDestroy } from '@angular/core'; -import { AbstractControl, FormBuilder, FormGroup, Validators } from '@angular/forms'; +import { AbstractControl, FormBuilder } from '@angular/forms'; import { MatDialog } from '@angular/material/dialog'; import { TranslateService } from '@ngx-translate/core'; import { Subscription } from 'rxjs'; import { ChangeType } from 'src/app/modules/changes/changes.component'; import { Gender, UserAddress, UserEmail, UserPhone, UserProfile, UserView } from 'src/app/proto/generated/auth_pb'; -import { PasswordComplexityPolicy } from 'src/app/proto/generated/management_pb'; import { AuthUserService } from 'src/app/services/auth-user.service'; import { OrgService } from 'src/app/services/org.service'; import { ToastService } from 'src/app/services/toast.service'; import { CodeDialogComponent } from '../code-dialog/code-dialog.component'; -import { lowerCaseValidator, numberValidator, symbolValidator, upperCaseValidator } from '../validators'; function passwordConfirmValidator(c: AbstractControl): any { if (!c.parent || !c) { @@ -44,7 +42,6 @@ export class AuthUserDetailComponent implements OnDestroy { public genders: Gender[] = [Gender.GENDER_MALE, Gender.GENDER_FEMALE, Gender.GENDER_DIVERSE]; public languages: string[] = ['de', 'en']; - public passwordForm!: FormGroup; private subscription: Subscription = new Subscription(); public emailEditState: boolean = false; @@ -52,7 +49,6 @@ export class AuthUserDetailComponent implements OnDestroy { public loading: boolean = false; - public policy!: PasswordComplexityPolicy.AsObject; public copied: string = ''; public ChangeType: any = ChangeType; @@ -66,40 +62,6 @@ export class AuthUserDetailComponent implements OnDestroy { private dialog: MatDialog, private orgService: OrgService, ) { - const validators: Validators[] = [Validators.required]; - this.orgService.GetPasswordComplexityPolicy().then(data => { - this.policy = data.toObject(); - if (this.policy.minLength) { - validators.push(Validators.minLength(this.policy.minLength)); - } - if (this.policy.hasLowercase) { - validators.push(lowerCaseValidator); - } - if (this.policy.hasUppercase) { - validators.push(upperCaseValidator); - } - if (this.policy.hasNumber) { - validators.push(numberValidator); - } - if (this.policy.hasSymbol) { - validators.push(symbolValidator); - } - - this.passwordForm = this.fb.group({ - currentPassword: ['', []], - newPassword: ['', validators], - confirmPassword: ['', [...validators, passwordConfirmValidator]], - }); - }).catch(error => { - this.toast.showError(error.message); - console.error(error.message); - this.passwordForm = this.fb.group({ - currentPassword: ['', []], - newPassword: ['', validators], - confirmPassword: ['', [...validators, passwordConfirmValidator]], - }); - }); - this.loading = true; this.getData().then(() => { this.loading = false; @@ -136,19 +98,6 @@ export class AuthUserDetailComponent implements OnDestroy { }); } - public setPassword(): void { - if (this.passwordForm.valid && this.currentPassword && - this.currentPassword.value && - this.newPassword && this.newPassword.value && this.newPassword.valid) { - this.userService - .ChangeMyPassword(this.currentPassword.value, this.newPassword.value).then((data: any) => { - this.toast.showInfo('Password Set'); - }).catch(data => { - this.toast.showError(data.message); - }); - } - } - public saveEmail(): void { this.emailEditState = false; @@ -163,11 +112,6 @@ export class AuthUserDetailComponent implements OnDestroy { }); } - public deletePhone(): void { - this.user.phone = ''; - this.savePhone(); - } - public enterCode(): void { const dialogRef = this.dialog.open(CodeDialogComponent, { data: { @@ -220,16 +164,6 @@ export class AuthUserDetailComponent implements OnDestroy { }); } - public get currentPassword(): AbstractControl | null { - return this.passwordForm.get('currentPassword'); - } - public get newPassword(): AbstractControl | null { - return this.passwordForm.get('newPassword'); - } - public get confirmPassword(): AbstractControl | null { - return this.passwordForm.get('confirmPassword'); - } - private async getData(): Promise { this.userService.GetMyUser().then(user => { this.user = user.toObject(); diff --git a/console/src/app/pages/user-detail/password/password.component.html b/console/src/app/pages/user-detail/password/password.component.html new file mode 100644 index 0000000000..625212b6ff --- /dev/null +++ b/console/src/app/pages/user-detail/password/password.component.html @@ -0,0 +1,151 @@ +
+
+ +
+
+

{{ 'USER.PASSWORD.TITLE' | translate }}

+

{{ 'USER.PASSWORD.DESCRIPTION' | translate }}

+
+ + +
+
+ + {{ 'USER.PASSWORD.NEW' | translate }} + + + + {{ 'USER.VALIDATION.REQUIRED' | translate }} + + + {{ 'USER.VALIDATION.SYMBOLERROR' | translate }} + + + {{ 'USER.VALIDATION.NUMBERERROR' | translate }} + + + {{ 'USER.VALIDATION.UPPERCASEMISSING' | translate }} + + + {{ 'USER.VALIDATION.LOWERCASEMISSING' | translate }} + + + {{ 'USER.VALIDATION.MINLENGTH' | translate:password?.errors?.minlength }} + + + + {{ 'USER.PASSWORD.CONFIRM' | translate }} + + + + {{ 'USER.VALIDATION.REQUIRED' | translate }} + + + {{ 'USER.VALIDATION.SYMBOLERROR' | translate }} + + + {{ 'USER.VALIDATION.NUMBERERROR' | translate }} + + + {{ 'USER.PASSWORD.NOTEQUAL' | translate }} + + + {{ 'USER.VALIDATION.UPPERCASEMISSING' | translate }} + + + {{ 'USER.VALIDATION.LOWERCASEMISSING' | translate }} + + + {{ 'USER.VALIDATION.MINLENGTH' | translate:confirmPassword?.errors?.minlength }} + + +
+
+ +
+
+
+ + +
+
+ + {{ 'USER.PASSWORD.OLD' | translate }} + + + {{ 'USER.PASSWORD.REQUIRED' | translate }} + + + + {{ 'USER.PASSWORD.NEW' | translate }} + + + + {{ 'USER.VALIDATION.REQUIRED' | translate }} + + + {{ 'USER.VALIDATION.SYMBOLERROR' | translate }} + + + {{ 'USER.VALIDATION.NUMBERERROR' | translate }} + + + {{ 'USER.VALIDATION.UPPERCASEMISSING' | translate }} + + + {{ 'USER.VALIDATION.LOWERCASEMISSING' | translate }} + + + {{ 'USER.VALIDATION.MINLENGTH' | translate:newPassword?.errors?.minlength }} + + + + + {{ 'USER.PASSWORD.CONFIRM' | translate }} + + + + {{ 'USER.VALIDATION.REQUIRED' | translate }} + + + {{ 'USER.VALIDATION.SYMBOLERROR' | translate }} + + + {{ 'USER.VALIDATION.NUMBERERROR' | translate }} + + + {{ 'USER.PASSWORD.NOTEQUAL' | translate }} + + + {{ 'USER.VALIDATION.UPPERCASEMISSING' | translate }} + + + {{ 'USER.VALIDATION.LOWERCASEMISSING' | translate }} + + + {{ 'USER.VALIDATION.MINLENGTH' | translate:confirmPassword?.errors?.minlength }} + + +
+ +
+
+ +
+
+
\ No newline at end of file diff --git a/console/src/app/pages/user-detail/password/password.component.scss b/console/src/app/pages/user-detail/password/password.component.scss new file mode 100644 index 0000000000..b81fae7b54 --- /dev/null +++ b/console/src/app/pages/user-detail/password/password.component.scss @@ -0,0 +1,66 @@ +.container { + display: flex; + padding-bottom: 3rem; + + .left { + width: 100px; + display: flex; + padding: 1rem; + justify-content: center; + + a { + margin-top: .2rem; + } + } + + .right { + flex: 1; + padding-top: 1rem; + + .head { + display: flex; + align-items: center; + border-bottom: 1px solid #ffffff20; + margin-bottom: 2rem; + flex-wrap: wrap; + + a { + display: block; + } + + h1 { + font-size: 2rem; + margin-top: 0.2rem; + } + + .desc { + width: 100%; + display: block; + font-size: .9rem; + color: #8795a1; + } + } + } +} + +.content { + display: flex; + flex-direction: row; + flex-wrap: wrap; + margin: 0 -.5rem; + + mat-form-field { + margin: 0 .5rem; + } + + &.center { + align-items: center; + } +} + +.submit-button { + margin-top: 100px; + display: block; + padding: 0.5rem 4rem; + border-radius: 0.5rem; +} \ No newline at end of file diff --git a/console/src/app/pages/user-detail/password/password.component.spec.ts b/console/src/app/pages/user-detail/password/password.component.spec.ts new file mode 100644 index 0000000000..7f3799a94b --- /dev/null +++ b/console/src/app/pages/user-detail/password/password.component.spec.ts @@ -0,0 +1,25 @@ +import { async, ComponentFixture, TestBed } from '@angular/core/testing'; + +import { PasswordComponent } from './password.component'; + +describe('PasswordComponent', () => { + let component: PasswordComponent; + let fixture: ComponentFixture; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + declarations: [PasswordComponent], + }) + .compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(PasswordComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/console/src/app/pages/user-detail/password/password.component.ts b/console/src/app/pages/user-detail/password/password.component.ts new file mode 100644 index 0000000000..3beb6ab247 --- /dev/null +++ b/console/src/app/pages/user-detail/password/password.component.ts @@ -0,0 +1,137 @@ +import { Component, OnInit } from '@angular/core'; +import { AbstractControl, FormBuilder, FormGroup, Validators } from '@angular/forms'; +import { ActivatedRoute } from '@angular/router'; +import { PasswordComplexityPolicy } from 'src/app/proto/generated/management_pb'; +import { AuthUserService } from 'src/app/services/auth-user.service'; +import { MgmtUserService } from 'src/app/services/mgmt-user.service'; +import { OrgService } from 'src/app/services/org.service'; +import { ToastService } from 'src/app/services/toast.service'; + +import { lowerCaseValidator, numberValidator, symbolValidator, upperCaseValidator } from '../validators'; + +function passwordConfirmValidator(c: AbstractControl): any { + if (!c.parent || !c) { + return; + } + const pwd = c.parent.get('password'); + const cpwd = c.parent.get('confirmPassword'); + + if (!pwd || !cpwd) { + return; + } + if (pwd.value !== cpwd.value) { + return { invalid: true, notequal: 'Password is not equal' }; + } +} + +@Component({ + selector: 'app-password', + templateUrl: './password.component.html', + styleUrls: ['./password.component.scss'], +}) +export class PasswordComponent implements OnInit { + userId: string = ''; + + public policy!: PasswordComplexityPolicy.AsObject; + public passwordForm!: FormGroup; + + constructor( + private orgService: OrgService, + activatedRoute: ActivatedRoute, + private fb: FormBuilder, + private userService: AuthUserService, + private mgmtUserService: MgmtUserService, + private toast: ToastService, + ) { + + activatedRoute.params.subscribe(data => { + const { id } = data; + if (id) { + this.userId = id; + } + + const validators: Validators[] = [Validators.required]; + this.orgService.GetPasswordComplexityPolicy().then(complexity => { + this.policy = complexity.toObject(); + if (this.policy.minLength) { + validators.push(Validators.minLength(this.policy.minLength)); + } + if (this.policy.hasLowercase) { + validators.push(lowerCaseValidator); + } + if (this.policy.hasUppercase) { + validators.push(upperCaseValidator); + } + if (this.policy.hasNumber) { + validators.push(numberValidator); + } + if (this.policy.hasSymbol) { + validators.push(symbolValidator); + } + + this.setupForm(validators); + }).catch(error => { + this.setupForm(validators); + }); + }); + } + + ngOnInit(): void { + } + + setupForm(validators: Validators[]): void { + if (this.userId) { + this.passwordForm = this.fb.group({ + password: ['', validators], + confirmPassword: ['', [...validators, passwordConfirmValidator]], + }); + } else { + this.passwordForm = this.fb.group({ + currentPassword: ['', validators], + newPassword: ['', validators], + confirmPassword: ['', [...validators, passwordConfirmValidator]], + }); + } + } + + public setInitialPassword(userId: string): void { + if (this.passwordForm.valid && this.password && this.password.value) { + this.mgmtUserService.SetInitialPassword(userId, this.password.value).then((data: any) => { + this.toast.showInfo('Set initial Password'); + window.history.back(); + }).catch(data => { + this.toast.showError(data.message); + }); + } + } + + public setPassword(): void { + if (this.passwordForm.valid && this.currentPassword && + this.currentPassword.value && + this.newPassword && this.newPassword.value && this.newPassword.valid) { + this.userService + .ChangeMyPassword(this.currentPassword.value, this.newPassword.value).then((data: any) => { + this.toast.showInfo('Password Set'); + window.history.back(); + }).catch(data => { + this.toast.showError(data.message); + }); + } + } + + public get password(): AbstractControl | null { + return this.passwordForm.get('password'); + } + + public get newPassword(): AbstractControl | null { + return this.passwordForm.get('newPassword'); + } + + public get currentPassword(): AbstractControl | null { + return this.passwordForm.get('newPassword'); + } + + public get confirmPassword(): AbstractControl | null { + return this.passwordForm.get('confirmPassword'); + } +} diff --git a/console/src/app/pages/user-detail/user-detail-routing.module.ts b/console/src/app/pages/user-detail/user-detail-routing.module.ts index 2b5fe61abd..d74d40c6c9 100644 --- a/console/src/app/pages/user-detail/user-detail-routing.module.ts +++ b/console/src/app/pages/user-detail/user-detail-routing.module.ts @@ -3,6 +3,7 @@ import { RouterModule, Routes } from '@angular/router'; import { RoleGuard } from 'src/app/guards/role.guard'; import { AuthUserDetailComponent } from './auth-user-detail/auth-user-detail.component'; +import { PasswordComponent } from './password/password.component'; import { UserDetailComponent } from './user-detail/user-detail.component'; const routes: Routes = [ @@ -10,6 +11,10 @@ const routes: Routes = [ path: 'me', component: AuthUserDetailComponent, }, + { + path: 'me/password', + component: PasswordComponent, + }, { path: ':id', component: UserDetailComponent, @@ -18,6 +23,14 @@ const routes: Routes = [ roles: ['user.read'], }, }, + { + path: ':id/password', + component: PasswordComponent, + canActivate: [RoleGuard], + data: { + roles: ['user.write'], + }, + }, ]; @NgModule({ diff --git a/console/src/app/pages/user-detail/user-detail.module.ts b/console/src/app/pages/user-detail/user-detail.module.ts index 272757bf9b..d356cb4899 100644 --- a/console/src/app/pages/user-detail/user-detail.module.ts +++ b/console/src/app/pages/user-detail/user-detail.module.ts @@ -28,6 +28,7 @@ import { ThemeSettingComponent } from './theme-setting/theme-setting.component'; import { UserDetailRoutingModule } from './user-detail-routing.module'; import { UserDetailComponent } from './user-detail/user-detail.component'; import { UserMfaComponent } from './user-mfa/user-mfa.component'; +import { PasswordComponent } from './password/password.component'; @NgModule({ declarations: [ @@ -37,6 +38,7 @@ import { UserMfaComponent } from './user-mfa/user-mfa.component'; AuthUserMfaComponent, UserMfaComponent, ThemeSettingComponent, + PasswordComponent, ], imports: [ UserDetailRoutingModule, diff --git a/console/src/app/pages/user-detail/user-detail/user-detail.component.html b/console/src/app/pages/user-detail/user-detail/user-detail.component.html index 73881402cf..eef0fccae1 100644 --- a/console/src/app/pages/user-detail/user-detail/user-detail.component.html +++ b/console/src/app/pages/user-detail/user-detail/user-detail.component.html @@ -24,76 +24,22 @@
- - - - -
-
- - {{ 'USER.PASSWORD.NEW' | translate }} - - - - {{ 'USER.VALIDATION.REQUIRED' | translate }} - - - {{ 'USER.VALIDATION.SYMBOLERROR' | translate }} - - - {{ 'USER.VALIDATION.NUMBERERROR' | translate }} - - - {{ 'USER.VALIDATION.UPPERCASEMISSING' | translate }} - - - {{ 'USER.VALIDATION.LOWERCASEMISSING' | translate }} - - - {{ 'USER.VALIDATION.MINLENGTH' | translate:password?.errors?.minlength }} - - - - {{ 'USER.PASSWORD.CONFIRM' | translate }} - - - - {{ 'USER.VALIDATION.REQUIRED' | translate }} - - - {{ 'USER.VALIDATION.SYMBOLERROR' | translate }} - - - {{ 'USER.VALIDATION.NUMBERERROR' | translate }} - - - {{ 'USER.PASSWORD.NOTEQUAL' | translate }} - - - {{ 'USER.VALIDATION.UPPERCASEMISSING' | translate }} - - - {{ 'USER.VALIDATION.LOWERCASEMISSING' | translate }} - - - {{ 'USER.VALIDATION.MINLENGTH' | translate:confirmPassword?.errors?.minlength }} - - -
-
- -
-
-
-
+
+ {{ 'USER.PROFILE.PASSWORD' | translate }} + + ********* +
+ + + chevron_right + +
+
{{ 'USER.EMAIL' | translate }} @@ -142,7 +88,6 @@ highlight_off - {{'USER.LOGINMETHODS.RESENDCODE' | translate}} @@ -152,9 +97,6 @@ -
@@ -177,7 +119,7 @@ -
diff --git a/console/src/app/pages/user-detail/user-detail/user-detail.component.scss b/console/src/app/pages/user-detail/user-detail/user-detail.component.scss index e8d8069058..647662d210 100644 --- a/console/src/app/pages/user-detail/user-detail/user-detail.component.scss +++ b/console/src/app/pages/user-detail/user-detail/user-detail.component.scss @@ -9,7 +9,7 @@ } h1 { - font-size: 1.2rem; + font-size: 2rem; margin: 0 1rem; margin-left: 2rem; font-weight: normal; @@ -82,6 +82,10 @@ display: flex; justify-content: flex-end; align-items: center; + + .notify-change-pwd { + border-radius: .5rem; + } } .label { diff --git a/console/src/app/pages/user-detail/user-detail/user-detail.component.ts b/console/src/app/pages/user-detail/user-detail/user-detail.component.ts index 71fe7bca38..7440b9f41c 100644 --- a/console/src/app/pages/user-detail/user-detail/user-detail.component.ts +++ b/console/src/app/pages/user-detail/user-detail/user-detail.component.ts @@ -1,7 +1,5 @@ import { Location } from '@angular/common'; import { Component, OnDestroy, OnInit } from '@angular/core'; -import { AbstractControl, FormBuilder, FormGroup, Validators } from '@angular/forms'; -import { MatDialog } from '@angular/material/dialog'; import { ActivatedRoute, Params } from '@angular/router'; import { TranslateService } from '@ngx-translate/core'; import { Subscription } from 'rxjs'; @@ -9,7 +7,6 @@ import { ChangeType } from 'src/app/modules/changes/changes.component'; import { Gender, NotificationType, - PasswordComplexityPolicy, UserEmail, UserPhone, UserProfile, @@ -18,27 +15,8 @@ import { } from 'src/app/proto/generated/management_pb'; import { AuthUserService } from 'src/app/services/auth-user.service'; import { MgmtUserService } from 'src/app/services/mgmt-user.service'; -import { OrgService } from 'src/app/services/org.service'; import { ToastService } from 'src/app/services/toast.service'; -import { CodeDialogComponent } from '../code-dialog/code-dialog.component'; -import { lowerCaseValidator, numberValidator, symbolValidator, upperCaseValidator } from '../validators'; - -function passwordConfirmValidator(c: AbstractControl): any { - if (!c.parent || !c) { - return; - } - const pwd = c.parent.get('password'); - const cpwd = c.parent.get('confirmPassword'); - - if (!pwd || !cpwd) { - return; - } - if (pwd.value !== cpwd.value) { - return { invalid: true, notequal: 'Password is not equal' }; - } -} - @Component({ selector: 'app-user-detail', templateUrl: './user-detail.component.html', @@ -46,13 +24,9 @@ function passwordConfirmValidator(c: AbstractControl): any { }) export class UserDetailComponent implements OnInit, OnDestroy { public user!: UserView.AsObject; - // public address: UserAddress.AsObject = { id: '' } as any; public genders: Gender[] = [Gender.GENDER_MALE, Gender.GENDER_FEMALE, Gender.GENDER_DIVERSE]; public languages: string[] = ['de', 'en']; - public passwordForm!: FormGroup; - // public addressForm!: FormGroup; - public isMgmt: boolean = false; private subscription: Subscription = new Subscription(); public emailEditState: boolean = false; @@ -62,49 +36,14 @@ export class UserDetailComponent implements OnInit, OnDestroy { public loading: boolean = false; public UserState: any = UserState; - public policy!: PasswordComplexityPolicy.AsObject; constructor( public translate: TranslateService, private route: ActivatedRoute, private toast: ToastService, private mgmtUserService: MgmtUserService, - private fb: FormBuilder, private _location: Location, - private dialog: MatDialog, - private orgService: OrgService, public authUserService: AuthUserService, - ) { - const validators: Validators[] = [Validators.required]; - - this.orgService.GetPasswordComplexityPolicy().then(data => { - this.policy = data.toObject(); - if (this.policy.minLength) { - validators.push(Validators.minLength(this.policy.minLength)); - } - if (this.policy.hasLowercase) { - validators.push(lowerCaseValidator); - } - if (this.policy.hasUppercase) { - validators.push(upperCaseValidator); - } - if (this.policy.hasNumber) { - validators.push(numberValidator); - } - if (this.policy.hasSymbol) { - validators.push(symbolValidator); - } - - this.passwordForm = this.fb.group({ - password: ['', validators], - confirmPassword: ['', [...validators, passwordConfirmValidator]], - }); - }).catch(error => { - this.passwordForm = this.fb.group({ - password: ['', []], - confirmPassword: ['', [passwordConfirmValidator]], - }); - }); - } + ) { } public ngOnInit(): void { this.subscription = this.route.params.subscribe(params => { @@ -121,25 +60,6 @@ export class UserDetailComponent implements OnInit, OnDestroy { this.subscription.unsubscribe(); } - public deletePhone(): void { - this.user.phone = ''; - this.savePhone(); - } - - public enterCode(): void { - const dialogRef = this.dialog.open(CodeDialogComponent, { - data: { - number: this.user.phone, - }, - }); - - dialogRef.afterClosed().subscribe(code => { - if (code) { - this.toast.showInfo('TODO: implement service'); - } - }); - } - public saveProfile(profileData: UserProfile.AsObject): void { this.user.firstName = profileData.firstName; this.user.lastName = profileData.lastName; @@ -180,27 +100,6 @@ export class UserDetailComponent implements OnInit, OnDestroy { }); } - public setInitialPassword(): void { - if (this.passwordForm.valid && this.password && this.password.value) { - this.mgmtUserService.SetInitialPassword(this.user.id, this.password.value).then((data: any) => { - this.toast.showInfo('Set initial Password'); - this.user.email = data.toObject(); - }).catch(data => { - this.toast.showError(data.message); - }); - } - } - - public sendSetPasswordNotification(): void { - this.mgmtUserService.SendSetPasswordNotification(this.user.id, NotificationType.NOTIFICATIONTYPE_EMAIL) - .then((data: any) => { - this.toast.showInfo('Set initial Password'); - this.user.email = data.toObject(); - }).catch(data => { - this.toast.showError(data.message); - }); - } - public saveEmail(): void { this.emailEditState = false; this.mgmtUserService @@ -227,13 +126,6 @@ export class UserDetailComponent implements OnInit, OnDestroy { this._location.back(); } - public get password(): AbstractControl | null { - return this.passwordForm.get('password'); - } - public get confirmPassword(): AbstractControl | null { - return this.passwordForm.get('confirmPassword'); - } - private async getData({ id }: Params): Promise { this.isMgmt = true; this.mgmtUserService.GetUserByID(id).then(user => { @@ -242,4 +134,13 @@ export class UserDetailComponent implements OnInit, OnDestroy { console.error(err); }); } + + public sendSetPasswordNotification(): void { + this.mgmtUserService.SendSetPasswordNotification(this.user.id, NotificationType.NOTIFICATIONTYPE_EMAIL) + .then(() => { + this.toast.showInfo('Set initial Password'); + }).catch(data => { + this.toast.showError(data.message); + }); + } } diff --git a/console/src/app/pages/user-grant-create/user-grant-create.component.html b/console/src/app/pages/user-grant-create/user-grant-create.component.html index 4be2af7fef..52d05fbdc0 100644 --- a/console/src/app/pages/user-grant-create/user-grant-create.component.html +++ b/console/src/app/pages/user-grant-create/user-grant-create.component.html @@ -16,7 +16,7 @@ {{'PROJECT.GRANT.CREATE.ORG_DESCRIPTION_DESC' | translate}}

- +

{{'PROJECT.GRANT.CREATE.SEL_PROJECT' | translate}}

- +

{{'PROJECT.GRANT.CREATE.SEL_USER' | translate}}

@@ -43,7 +44,7 @@
diff --git a/console/src/app/pages/user-grant-create/user-grant-create.component.ts b/console/src/app/pages/user-grant-create/user-grant-create.component.ts index f2626bcac0..1d05024f43 100644 --- a/console/src/app/pages/user-grant-create/user-grant-create.component.ts +++ b/console/src/app/pages/user-grant-create/user-grant-create.component.ts @@ -2,15 +2,9 @@ import { Location } from '@angular/common'; import { Component, OnDestroy } from '@angular/core'; import { ActivatedRoute, Params } from '@angular/router'; import { Subscription } from 'rxjs'; +import { UserGrantContext } from 'src/app/modules/user-grants/user-grants-datasource'; import { Org } from 'src/app/proto/generated/auth_pb'; -import { - ProjectGrantView, - ProjectRole, - ProjectView, - User, - UserGrant, - UserGrantSearchKey, -} from 'src/app/proto/generated/management_pb'; +import { ProjectGrantView, ProjectRole, ProjectView, User, UserGrant } from 'src/app/proto/generated/management_pb'; import { AuthService } from 'src/app/services/auth.service'; import { MgmtUserService } from 'src/app/services/mgmt-user.service'; import { ToastService } from 'src/app/services/toast.service'; @@ -21,6 +15,8 @@ import { ToastService } from 'src/app/services/toast.service'; styleUrls: ['./user-grant-create.component.scss'], }) export class UserGrantCreateComponent implements OnDestroy { + public context!: UserGrantContext; + public org!: Org.AsObject; public userId: string = ''; public projectId: string = ''; @@ -30,12 +26,11 @@ export class UserGrantCreateComponent implements OnDestroy { public STEPS: number = 2; // project, roles public currentCreateStep: number = 1; - public filter!: UserGrantSearchKey; public filterValue: string = ''; private subscription: Subscription = new Subscription(); - public UserGrantSearchKey: any = UserGrantSearchKey; + public UserGrantContext: any = UserGrantContext; constructor( private authService: AuthService, private userService: MgmtUserService, @@ -45,18 +40,20 @@ export class UserGrantCreateComponent implements OnDestroy { ) { this.subscription = this.route.params.subscribe((params: Params) => { console.log(params); - const { filter, filterValue } = params; - this.filter = filter; - switch (filter) { - case (`${UserGrantSearchKey.USERGRANTSEARCHKEY_PROJECT_ID}`): - this.projectId = filterValue; - break; - case (`${UserGrantSearchKey.USERGRANTSEARCHKEY_USER_ID}`): - this.userId = filterValue; - break; - } + const { context, projectid, grantid, userid } = params; + this.context = context; - console.log(this.projectId, this.userId); + this.projectId = projectid; + this.grantId = grantid; + this.userId = userid; + + 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; + } }); this.authService.GetActiveOrg().then(org => { @@ -69,15 +66,48 @@ export class UserGrantCreateComponent implements OnDestroy { } public addGrant(): void { - this.userService.CreateUserGrant( - this.projectId, - this.userId, - this.rolesList, - ).then((data: UserGrant) => { - this.close(); - }).catch(error => { - this.toast.showError(error.message); - }); + 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.message); + }); + 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.close(); + }).catch(error => { + this.toast.showError(error.message); + }); + break; + case UserGrantContext.GRANTED_PROJECT: + this.userService.CreateProjectGrantUserGrant( + this.org.id, + this.projectId, + this.grantId, + this.userId, + this.rolesList, + ).then((data: UserGrant) => { + this.toast.showInfo('Project Grant User Grant added'); + this.close(); + }).catch(error => { + this.toast.showError(error.message); + }); + break; + + } + } public selectProject(project: ProjectView.AsObject | ProjectGrantView.AsObject | any): void { diff --git a/console/src/app/services/mgmt-user.service.ts b/console/src/app/services/mgmt-user.service.ts index c9d48b2a17..fc121d6c77 100644 --- a/console/src/app/services/mgmt-user.service.ts +++ b/console/src/app/services/mgmt-user.service.ts @@ -15,10 +15,12 @@ import { ProjectGrantMemberSearchQuery, ProjectGrantMemberSearchRequest, ProjectGrantMemberSearchResponse, + ProjectGrantUserGrantCreate, ProjectGrantUserGrantID, ProjectGrantUserGrantSearchRequest, ProjectGrantUserGrantUpdate, ProjectRoleAdd, + ProjectUserGrantSearchRequest, SetPasswordNotificationRequest, UpdateUserAddressRequest, UpdateUserEmailRequest, @@ -30,6 +32,7 @@ import { UserGrant, UserGrantCreate, UserGrantID, + UserGrantRemoveBulk, UserGrantSearchQuery, UserGrantSearchRequest, UserGrantSearchResponse, @@ -221,6 +224,44 @@ export class MgmtUserService { ); } + public async CreateProjectUserGrant( + projectId: string, + userId: string, + roleNamesList: string[], + ): Promise { + const req = new UserGrantCreate(); + req.setProjectId(projectId); + req.setUserId(userId); + req.setRoleKeysList(roleNamesList); + + return await this.request( + c => c.createProjectUserGrant, + req, + f => f, + ); + } + + public async CreateProjectGrantUserGrant( + orgId: string, + projectId: string, + grantId: string, + userId: string, + roleNamesList: string[], + ): Promise { + const req = new ProjectGrantUserGrantCreate(); + req.setOrgId(orgId); + req.setProjectId(projectId); + req.setProjectGrantId(grantId); + req.setUserId(userId); + req.setRoleKeysList(roleNamesList); + + return await this.request( + c => c.createProjectGrantUserGrant, + req, + f => f, + ); + } + public async ReactivateUser(id: string): Promise { const req = new UserID(); req.setId(id); @@ -355,6 +396,8 @@ export class MgmtUserService { ); } + // USER GRANTS + public async SearchUserGrants( limit: number, offset: number, @@ -373,13 +416,34 @@ export class MgmtUserService { ); } + public async SearchProjectUserGrants( + projectId: string, + limit: number, + offset: number, + queryList?: UserGrantSearchQuery[], + ): Promise { + const req = new ProjectUserGrantSearchRequest(); + req.setProjectId(projectId); + req.setLimit(limit); + req.setOffset(offset); + if (queryList) { + req.setQueriesList(queryList); + } + return await this.request( + c => c.searchProjectUserGrants, + req, + f => f, + ); + } - public async searchProjectGrantUserGrants( + public async SearchProjectGrantUserGrants( + projectGrantId: string, limit: number, offset: number, queryList?: UserGrantSearchQuery[], ): Promise { const req = new ProjectGrantUserGrantSearchRequest(); + req.setProjectGrantId(projectGrantId); req.setLimit(limit); req.setOffset(offset); if (queryList) { @@ -460,6 +524,36 @@ export class MgmtUserService { ); } + public async RemoveUserGrant( + id: string, + userId: string, + ): Promise { + const req = new UserGrantID(); + req.setId(id); + req.setUserId(userId); + + return await this.request( + c => c.removeUserGrant, + req, + f => f, + ); + } + + public async BulkRemoveUserGrant( + idsList: string[], + ): Promise { + const req = new UserGrantRemoveBulk(); + req.setIdsList(idsList); + + return await this.request( + c => c.bulkRemoveUserGrant, + req, + f => f, + ); + } + + // + public async ApplicationChanges(id: string, limit: number, offset: number): Promise { const req = new ChangeRequest(); req.setId(id); diff --git a/console/src/app/services/project.service.ts b/console/src/app/services/project.service.ts index ec14ae56be..a5998341e4 100644 --- a/console/src/app/services/project.service.ts +++ b/console/src/app/services/project.service.ts @@ -19,7 +19,9 @@ import { ProjectGrant, ProjectGrantCreate, ProjectGrantID, + ProjectGrantMember, ProjectGrantMemberAdd, + ProjectGrantMemberChange, ProjectGrantMemberRemove, ProjectGrantMemberRoles, ProjectGrantMemberSearchQuery, @@ -246,6 +248,24 @@ export class ProjectService { ); } + public async ChangeProjectGrantMember( + projectId: string, + grantId: string, + userId: string, + rolesList: string[], + ): Promise { + const req = new ProjectGrantMemberChange(); + req.setProjectId(projectId); + req.setGrantId(grantId); + req.setUserId(userId); + req.setRolesList(rolesList); + return await this.request( + c => c.changeProjectGrantMember, + req, + f => f, + ); + } + public async SearchProjectGrantMembers( projectId: string, grantId: string, diff --git a/console/src/assets/i18n/de.json b/console/src/assets/i18n/de.json index ed9bdf0c7e..ce74e738e9 100644 --- a/console/src/assets/i18n/de.json +++ b/console/src/assets/i18n/de.json @@ -3,7 +3,7 @@ "HOME": { "TITLE": "zitadel", "SECURITYANDPRIVACY": "Datenschutz und Personalisierung", - "SECURITYANDPRIVACY_DESC": "Sie können die Daten in Ihrem Caos-Konto sehen und auswählen, welche Aktivitäten gespeichert werden, um Caos für sich zu personalisieren", + "SECURITYANDPRIVACY_DESC": "Sie können die Daten in Ihrem Zitadel Konto sehen und auswählen, welche Aktivitäten gespeichert werden, um Zitadel für sich zu personalisieren", "SECURITYANDPRIVACY_BUTTON": "Daten verwalten und personalisieren", "PROTECTION": "Organisationsrichtlinien", "PROTECTION_DESC": "Verwalten Sie Ihre Organisationsrichtlinien. Entdecken Sie einige vorgefertigte Lösungen, die Ihnen Zeit sparen und Sicherheit gewährleisten.", @@ -52,7 +52,7 @@ }, "USER": { "TITLE": "Persönliche Informationen", - "DESCRIPTION": "Hier können Sie Ihre Daten sowie die Datenschutz- und Sicherheitseinstellungen verwalten, um Caos optimal an Ihre Bedürfnisse anzupassen", + "DESCRIPTION": "Hier können Sie Ihre Daten sowie die Datenschutz- und Sicherheitseinstellungen verwalten, um Zitadel optimal an Ihre Bedürfnisse anzupassen", "PAGES": { "LIST": "Benutzer", "TITLE": "Benutzer", @@ -112,18 +112,19 @@ "TITLE": "Profil", "EMAIL": "Email", "PHONE": "Phonenumber", - "DESCRIPTION": "Hier können Sie Ihre Daten sowie die Datenschutz- und Sicherheitseinstellungen verwalten, um Caos optimal an Ihre Bedürfnisse anzupassen", + "DESCRIPTION": "Hier können Sie Ihre Daten sowie die Datenschutz- und Sicherheitseinstellungen verwalten, um Zitadel optimal an Ihre Bedürfnisse anzupassen", "USERNAME": "Benutzername", "FIRSTNAME": "Vorname", "LASTNAME": "Nachname", "NICKNAME": "Spitzname", "DISPLAYNAME": "Anzeigename", "PREFERRED_LANGUAGE": "Sprache", - "GENDER": "Geschlecht" + "GENDER": "Geschlecht", + "PASSWORD":"Passwort" }, "PASSWORD": { "TITLE": "Passwort", - "DESCRIPTION": "Das Password muss aus mindestens 8 Zeichen bestehen und einen Grossbuchstaben, ein Sonderzeichen und eine Zahl enthalten. Die maximale Anzahl an Zeichen ist 72!", + "DESCRIPTION": "Beachten Sie, dass das Password der von Ihrer Organisation definierten Richtlinie entsprechen muss.", "OLD": "Aktuelles Passwort", "NEW": "Neues Passwort", "CONFIRM": "Neues Passwort Wiederholung", diff --git a/console/src/assets/i18n/en.json b/console/src/assets/i18n/en.json index e6e63bada6..196fa4bcf6 100644 --- a/console/src/assets/i18n/en.json +++ b/console/src/assets/i18n/en.json @@ -3,7 +3,7 @@ "HOME": { "TITLE": "zitadel", "SECURITYANDPRIVACY": "Data protection and personalization", - "SECURITYANDPRIVACY_DESC": "You can view the data in your Caos account and choose which activities are saved in order to personalize Caos for you", + "SECURITYANDPRIVACY_DESC": "You can view the data in your Zitadel account and choose which activities are saved in order to personalize Zitadel for you", "SECURITYANDPRIVACY_BUTTON": "Personalize data", "PROTECTION": "Organizational Policies", "PROTECTION_DESC": "Manage your organizational guidelines. Explore some pre-packaged solutions that save you time and ensure security.", @@ -112,18 +112,19 @@ "TITLE": "Profile", "EMAIL": "Email", "PHONE": "Phonenumber", - "DESCRIPTION": "Here you can manage your data as well as data protection and security settings in order to optimally adapt Caos to your needs", + "DESCRIPTION": "Here you can manage your data as well as data protection and security settings in order to optimally adapt Zitadel to your needs", "USERNAME": "Username", "FIRSTNAME": "Firstname", "LASTNAME": "Lastname", "NICKNAME": "Nickname", "DISPLAYNAME": "Displayname", "PREFERRED_LANGUAGE": "Language", - "GENDER": "Gender" + "GENDER": "Gender", + "PASSWORD":"Password" }, "PASSWORD": { "TITLE": "Password", - "DESCRIPTION": "The password must consist of at least 8 characters and contain a capital letter, a special character and a number. The maximum length is 72.", + "DESCRIPTION": "Note that the possword must correspond to the policy your organization has set.", "OLD": "Current Password", "NEW": "New Password", "CONFIRM": "Password Confirmation", @@ -137,7 +138,7 @@ "EMAIL": "Email", "PHONE": "Phonenumber", "LOGINMETHODS": { - "TITLE": "Methods to check your identity", + "TITLE": "Methods to access your identity", "DESCRIPTION": "This allows us to confirm your identity when you register or to contact you if suspicious activity is detected in your account", "EMAIL": { "TITLE": "Email",