From 65058ed17c3cef443817dafc9a01126be7f8a02b Mon Sep 17 00:00:00 2001 From: Max Peintner Date: Wed, 12 Aug 2020 08:47:53 +0200 Subject: [PATCH] feat(console): domain verification, create org, regexp route guards, change org, iam member (#573) * verification dialog, service * i18n, verification dialog * file saver * savefile * verify trigger * delete project, i18n * org create dialog * org-create-self * stylelint * fix signout redirect * rm unused dialog component, import * project i18n de * regexp roles * use regex to check permissions * border radius * change validation flow * update org member * iam member change * lint * rm unused css * Update console/src/assets/i18n/de.json Co-authored-by: Fabi <38692350+fgerschwiler@users.noreply.github.com> * Update console/src/assets/i18n/de.json Co-authored-by: Fabi <38692350+fgerschwiler@users.noreply.github.com> * change guard Co-authored-by: Fabi <38692350+fgerschwiler@users.noreply.github.com> --- console/package-lock.json | 10 + console/package.json | 2 + console/src/app/app.component.html | 6 +- console/src/app/app.module.ts | 2 + .../directives/has-role/has-role.directive.ts | 2 +- console/src/app/guards/role.guard.ts | 2 +- .../project-members.component.html | 2 +- .../iam-members/iam-members.component.html | 14 +- .../iam-members/iam-members.component.scss | 5 - .../iam-members/iam-members.component.spec.ts | 46 +-- .../iam/iam-members/iam-members.component.ts | 24 +- .../iam/iam-members/iam-members.module.ts | 6 + .../orgs/org-create/org-create.component.html | 301 +++++++++--------- .../orgs/org-create/org-create.component.ts | 42 ++- .../orgs/org-create/org-create.module.ts | 4 + .../domain-verification.component.html | 47 +++ .../domain-verification.component.scss | 41 +++ .../domain-verification.component.spec.ts | 25 ++ .../domain-verification.component.ts | 59 ++++ .../orgs/org-detail/org-detail.component.html | 5 +- .../orgs/org-detail/org-detail.component.scss | 14 + .../orgs/org-detail/org-detail.component.ts | 15 + .../org-members/org-members.component.html | 14 +- .../org-members/org-members.component.scss | 5 - .../orgs/org-members/org-members.component.ts | 30 +- .../orgs/org-members/org-members.module.ts | 6 + .../src/app/pages/orgs/orgs-routing.module.ts | 2 +- console/src/app/pages/orgs/orgs.module.ts | 5 +- .../apps/app-detail/app-detail.component.html | 3 +- .../owned-project-detail.component.html | 10 +- .../owned-project-detail.component.ts | 22 ++ .../owned-project-detail.module.ts | 2 + console/src/app/pages/validators.ts | 2 +- console/src/app/pipes/has-role.pipe.ts | 5 +- console/src/app/pipes/regexp-pipe.module.ts | 18 ++ console/src/app/pipes/regexp.pipe.ts | 10 + console/src/app/services/admin.service.ts | 15 + console/src/app/services/auth.service.ts | 22 +- console/src/app/services/org.service.ts | 54 ++++ console/src/app/services/project.service.ts | 13 +- console/src/assets/i18n/de.json | 82 ++--- console/src/assets/i18n/en.json | 18 +- 42 files changed, 757 insertions(+), 255 deletions(-) create mode 100644 console/src/app/pages/orgs/org-detail/domain-verification/domain-verification.component.html create mode 100644 console/src/app/pages/orgs/org-detail/domain-verification/domain-verification.component.scss create mode 100644 console/src/app/pages/orgs/org-detail/domain-verification/domain-verification.component.spec.ts create mode 100644 console/src/app/pages/orgs/org-detail/domain-verification/domain-verification.component.ts create mode 100644 console/src/app/pipes/regexp-pipe.module.ts create mode 100644 console/src/app/pipes/regexp.pipe.ts diff --git a/console/package-lock.json b/console/package-lock.json index 27b322af0f..369a79564b 100644 --- a/console/package-lock.json +++ b/console/package-lock.json @@ -2181,6 +2181,11 @@ "integrity": "sha512-rr+OQyAjxze7GgWrSaJwydHStIhHq2lvY3BOC2Mj7KnzI7XK0Uw1TOOdI9lDoajEbSWLiYgoo4f1R51erQfhPQ==", "dev": true }, + "@types/file-saver": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@types/file-saver/-/file-saver-2.0.1.tgz", + "integrity": "sha512-g1QUuhYVVAamfCifK7oB7G3aIl4BbOyzDOqVyUfEr4tfBKrXfeH+M+Tg7HKCXSrbzxYdhyCP7z9WbKo0R2hBCw==" + }, "@types/glob": { "version": "7.1.3", "resolved": "https://registry.npmjs.org/@types/glob/-/glob-7.1.3.tgz", @@ -6353,6 +6358,11 @@ "schema-utils": "^2.6.5" } }, + "file-saver": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/file-saver/-/file-saver-2.0.2.tgz", + "integrity": "sha512-Wz3c3XQ5xroCxd1G8b7yL0Ehkf0TC9oYC6buPFkNnU9EnaPlifeAFCyCh+iewXTyFRcg0a6j3J7FmJsIhlhBdw==" + }, "file-uri-to-path": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz", diff --git a/console/package.json b/console/package.json index c039385c97..3872c44061 100644 --- a/console/package.json +++ b/console/package.json @@ -24,11 +24,13 @@ "@angular/service-worker": "~10.0.2", "@ngx-translate/core": "^13.0.0", "@ngx-translate/http-loader": "^6.0.0", + "@types/file-saver": "^2.0.1", "@types/google-protobuf": "^3.7.2", "@types/uuid": "^8.0.1", "angularx-qrcode": "^10.0.6", "angular-oauth2-oidc": "^10.0.3", "cors": "^2.8.5", + "file-saver": "^2.0.2", "google-proto-files": "^2.2.0", "google-protobuf": "^3.12.4", "grpc": "^1.24.3", diff --git a/console/src/app/app.component.html b/console/src/app/app.component.html index c55a560649..755465b1bb 100644 --- a/console/src/app/app.component.html +++ b/console/src/app/app.component.html @@ -28,7 +28,7 @@ {{temporg?.name ? temporg.name : 'NO NAME'}} - + - - + + +

{{'ORG.PAGES.ORGDETAIL_TITLE' | translate}}

+
+
+ + {{ 'ORG_DETAIL.DETAIL.NAME' | translate }} + + + + {{ 'ORG_DETAIL.DETAIL.DOMAIN' | translate }} + + +
- - - - -

{{'ORG.PAGES.ORGDETAILUSER_TITLE' | translate}}

- -
- -
-

{{ 'USER.CREATE.NAMEANDEMAILSECTION' | translate }}

- - {{ 'USER.PROFILE.USERNAME' | translate }} - - - {{ 'USER.VALIDATION.REQUIRED' | translate }} - - - - {{ 'USER.PROFILE.EMAIL' | translate }} - - - {{ 'USER.VALIDATION.REQUIRED' | translate }} - - - - {{ 'USER.PROFILE.FIRSTNAME' | translate }} - - - {{ 'USER.VALIDATION.REQUIRED' | translate }} - - - - {{ 'USER.PROFILE.LASTNAME' | translate }} - - - {{ 'USER.VALIDATION.REQUIRED' | translate }} - - - - {{ 'USER.PROFILE.NICKNAME' | translate }} - - - {{ 'USER.VALIDATION.REQUIRED' | translate }} - - - -

{{ 'USER.CREATE.GENDERLANGSECTION' | translate }}

- - - {{ 'USER.PROFILE.GENDER' | translate }} - - - {{ 'GENDERS.'+gender | translate }} - - - - {{ 'USER.VALIDATION.REQUIRED' | translate }} - - - - {{ 'USER.PROFILE.PREFERRED_LANGUAGE' | translate }} - - - {{ 'LANGUAGES.'+language | translate }} - - - {{ 'USER.VALIDATION.REQUIRED' | translate }} - - - - - - {{'ORG.PAGES.USEPASSWORD' | translate}} - - -

{{ 'USER.CREATE.PASSWORDSECTION' | translate }}

- - - - - - - {{ 'USER.PASSWORD.NEW' | translate }} - - - +
+ +
+

{{ 'USER.CREATE.NAMEANDEMAILSECTION' | translate }}

+ + {{ 'USER.PROFILE.USERNAME' | translate }} + + {{ 'USER.VALIDATION.REQUIRED' | translate }} - - - {{ 'USER.PASSWORD.CONFIRM' | translate }} - - - + + {{ 'USER.PROFILE.EMAIL' | translate }} + + {{ 'USER.VALIDATION.REQUIRED' | translate }} - - {{ 'USER.PASSWORD.NOTEQUAL' | translate }} + + + {{ 'USER.PROFILE.FIRSTNAME' | translate }} + + + {{ 'USER.VALIDATION.REQUIRED' | translate }} - - + + {{ 'USER.PROFILE.LASTNAME' | translate }} + + + {{ 'USER.VALIDATION.REQUIRED' | translate }} + + + + {{ 'USER.PROFILE.NICKNAME' | translate }} + + + {{ 'USER.VALIDATION.REQUIRED' | translate }} + + + +

{{ 'USER.CREATE.GENDERLANGSECTION' | translate }}

+ + + {{ 'USER.PROFILE.GENDER' | translate }} + + + {{ 'GENDERS.'+gender | translate }} + + + + {{ 'USER.VALIDATION.REQUIRED' | translate }} + + + + {{ 'USER.PROFILE.PREFERRED_LANGUAGE' | translate }} + + + {{ 'LANGUAGES.'+language | translate }} + + + {{ 'USER.VALIDATION.REQUIRED' | translate }} + + + + + + {{'ORG.PAGES.USEPASSWORD' | translate}} + + +

{{ 'USER.CREATE.PASSWORDSECTION' | translate }}

+ + + + +
+ + {{ 'USER.PASSWORD.NEW' | translate }} + + + + {{ 'USER.VALIDATION.REQUIRED' | translate }} + + + + + {{ 'USER.PASSWORD.CONFIRM' | translate }} + + + + {{ 'USER.VALIDATION.REQUIRED' | translate }} + + + {{ 'USER.PASSWORD.NOTEQUAL' | translate }} + + +
+
+
+
+ + + +
+
-
- - - -
- +
+ + + +
+ +

{{'ORG.PAGES.ORGDETAIL_TITLE' | translate}}

+
+
+ + {{ 'ORG_DETAIL.DETAIL.NAME' | translate }} + + +
+ +
+ + +
+
+
- +
\ No newline at end of file diff --git a/console/src/app/pages/orgs/org-create/org-create.component.ts b/console/src/app/pages/orgs/org-create/org-create.component.ts index 1e958adf04..100be5e362 100644 --- a/console/src/app/pages/orgs/org-create/org-create.component.ts +++ b/console/src/app/pages/orgs/org-create/org-create.component.ts @@ -2,11 +2,14 @@ import { animate, style, transition, trigger } from '@angular/animations'; import { Location } from '@angular/common'; import { Component } from '@angular/core'; import { AbstractControl, FormBuilder, FormGroup, ValidatorFn, Validators } from '@angular/forms'; +import { MatSlideToggleChange } from '@angular/material/slide-toggle'; import { Router } from '@angular/router'; +import { take } from 'rxjs/operators'; import { lowerCaseValidator, numberValidator, symbolValidator, upperCaseValidator } from 'src/app/pages/validators'; import { CreateOrgRequest, CreateUserRequest, Gender, OrgSetUpResponse } from 'src/app/proto/generated/admin_pb'; import { PasswordComplexityPolicy } from 'src/app/proto/generated/auth_pb'; import { AdminService } from 'src/app/services/admin.service'; +import { AuthService } from 'src/app/services/auth.service'; import { OrgService } from 'src/app/services/org.service'; import { ToastService } from 'src/app/services/toast.service'; @@ -56,6 +59,8 @@ export class OrgCreateComponent { public policy!: PasswordComplexityPolicy.AsObject; public usePassword: boolean = false; + + public forSelf: boolean = true; constructor( private router: Router, private toast: ToastService, @@ -63,8 +68,13 @@ export class OrgCreateComponent { private _location: Location, private fb: FormBuilder, private orgService: OrgService, + private authService: AuthService, ) { - const validators: Validators[] = []; + this.authService.isAllowed(['iam.write']).pipe(take(1)).subscribe((allowed) => { + if (allowed) { + this.forSelf = false; + } + }); this.orgForm = this.fb.group({ name: ['', [Validators.required]], @@ -165,6 +175,36 @@ export class OrgCreateComponent { } } + public changeSelf(change: MatSlideToggleChange): void { + console.log(change.checked); + + if (change.checked) { + this.createSteps = 1; + + this.orgForm = this.fb.group({ + name: ['', [Validators.required]], + }); + } else { + this.createSteps = 2; + + this.orgForm = this.fb.group({ + name: ['', [Validators.required]], + domain: [''], + }); + } + } + + public createOrgForSelf(): void { + console.log('create for self'); + if (this.name && this.name.value) { + this.orgService.CreateOrg(this.name.value).then((org) => { + this.router.navigate(['orgs', org.toObject().id]); + }).catch(error => { + this.toast.showError(error); + }); + } + } + public get name(): AbstractControl | null { return this.orgForm.get('name'); } diff --git a/console/src/app/pages/orgs/org-create/org-create.module.ts b/console/src/app/pages/orgs/org-create/org-create.module.ts index 4087b69652..d000e4e5fc 100644 --- a/console/src/app/pages/orgs/org-create/org-create.module.ts +++ b/console/src/app/pages/orgs/org-create/org-create.module.ts @@ -7,7 +7,9 @@ import { MatFormFieldModule } from '@angular/material/form-field'; import { MatIconModule } from '@angular/material/icon'; import { MatInputModule } from '@angular/material/input'; import { MatSelectModule } from '@angular/material/select'; +import { MatSlideToggleModule } from '@angular/material/slide-toggle'; import { TranslateModule } from '@ngx-translate/core'; +import { HasRoleModule } from 'src/app/directives/has-role/has-role.module'; import { PasswordComplexityViewModule } from 'src/app/modules/password-complexity-view/password-complexity-view.module'; import { HasRolePipeModule } from 'src/app/pipes/has-role-pipe.module'; @@ -28,8 +30,10 @@ import { OrgCreateComponent } from './org-create.component'; MatSelectModule, HasRolePipeModule, TranslateModule, + HasRoleModule, MatCheckboxModule, PasswordComplexityViewModule, + MatSlideToggleModule, ], }) export class OrgCreateModule { } diff --git a/console/src/app/pages/orgs/org-detail/domain-verification/domain-verification.component.html b/console/src/app/pages/orgs/org-detail/domain-verification/domain-verification.component.html new file mode 100644 index 0000000000..7f886bc181 --- /dev/null +++ b/console/src/app/pages/orgs/org-detail/domain-verification/domain-verification.component.html @@ -0,0 +1,47 @@ +{{domain.domain}} {{'ORG.PAGES.ORGDOMAIN_TITLE' | translate}} +
+

{{ 'ORG.PAGES.ORGDOMAIN_VERIFICATION' | translate }}

+ +

{{ 'ORG.PAGES.ORGDOMAIN_VERIFICATION_VALIDATION_DESC' | translate }}

+ + +
+ +
+ +

{{ 'ORG.PAGES.ORGDOMAIN_VERIFICATION_NEWTOKEN_TITLE' | translate }}

+

{{ 'ORG.PAGES.ORGDOMAIN_VERIFICATION_NEWTOKEN_DESC' | translate }}

+ +
+ + +
+
+

HTTP TOKEN

+

{{http?.url}}.txt

+ +
+ +
+
+ +
+

DNS TOKEN

+
+

{{dns?.token}}

+ +
+

{{dns?.url}}

+
+
+
+ +
\ No newline at end of file diff --git a/console/src/app/pages/orgs/org-detail/domain-verification/domain-verification.component.scss b/console/src/app/pages/orgs/org-detail/domain-verification/domain-verification.component.scss new file mode 100644 index 0000000000..7252acecc9 --- /dev/null +++ b/console/src/app/pages/orgs/org-detail/domain-verification/domain-verification.component.scss @@ -0,0 +1,41 @@ +.btn-container { + display: flex; + margin: -.5rem; + + button { + margin: 1rem .5rem; + border-radius: .5rem; + display: block; + } +} + +.desc { + color: #8795a1; + font-size: .9rem; + + &.warn { + color: rgb(201, 51, 71); + } +} + +.entry { + margin: .5rem 0; +} + +.line { + display: flex; + align-items: center; +} + +.action { + display: flex; + justify-content: flex-end; + + .ok-button { + margin-left: .5rem; + } + + button { + border-radius: .5rem; + } +} diff --git a/console/src/app/pages/orgs/org-detail/domain-verification/domain-verification.component.spec.ts b/console/src/app/pages/orgs/org-detail/domain-verification/domain-verification.component.spec.ts new file mode 100644 index 0000000000..ddcd2912f0 --- /dev/null +++ b/console/src/app/pages/orgs/org-detail/domain-verification/domain-verification.component.spec.ts @@ -0,0 +1,25 @@ +import { async, ComponentFixture, TestBed } from '@angular/core/testing'; + +import { DomainVerificationComponent } from './domain-verification.component'; + +describe('DomainVerificationComponent', () => { + let component: DomainVerificationComponent; + let fixture: ComponentFixture; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + declarations: [DomainVerificationComponent], + }) + .compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(DomainVerificationComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/console/src/app/pages/orgs/org-detail/domain-verification/domain-verification.component.ts b/console/src/app/pages/orgs/org-detail/domain-verification/domain-verification.component.ts new file mode 100644 index 0000000000..fc4030187e --- /dev/null +++ b/console/src/app/pages/orgs/org-detail/domain-verification/domain-verification.component.ts @@ -0,0 +1,59 @@ +import { Component, Inject } from '@angular/core'; +import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog'; +import { saveAs } from 'file-saver'; +import { OrgDomainValidationResponse, OrgDomainValidationType, OrgDomainView } from 'src/app/proto/generated/management_pb'; +import { OrgService } from 'src/app/services/org.service'; +import { ToastService } from 'src/app/services/toast.service'; + +@Component({ + selector: 'app-domain-verification', + templateUrl: './domain-verification.component.html', + styleUrls: ['./domain-verification.component.scss'], +}) +export class DomainVerificationComponent { + public domain!: OrgDomainView.AsObject; + + public OrgDomainValidationType: any = OrgDomainValidationType; + + public http!: OrgDomainValidationResponse.AsObject; + public dns!: OrgDomainValidationResponse.AsObject; + public copied: string = ''; + + constructor( + private toast: ToastService, + public dialogRef: MatDialogRef, + @Inject(MAT_DIALOG_DATA) public data: any, + private orgService: OrgService, + ) { + this.domain = data.domain; + } + + async loadHttpToken(): Promise { + this.http = (await this.orgService.GenerateMyOrgDomainValidation( + this.domain.domain, + OrgDomainValidationType.ORGDOMAINVALIDATIONTYPE_HTTP)).toObject(); + } + + async loadDnsToken(): Promise { + this.dns = (await this.orgService.GenerateMyOrgDomainValidation( + this.domain.domain, + OrgDomainValidationType.ORGDOMAINVALIDATIONTYPE_DNS)).toObject(); + } + + public closeDialog(): void { + this.dialogRef.close(false); + } + + public validate(): void { + this.orgService.ValidateMyOrgDomain(this.domain.domain).then(() => { + this.dialogRef.close(false); + }).catch((error) => { + this.toast.showError(error); + }); + } + + public saveFile(): void { + const blob = new Blob([this.http.token], { type: 'text/plain;charset=utf-8' }); + saveAs(blob, this.http.token + '.txt'); + } +} diff --git a/console/src/app/pages/orgs/org-detail/org-detail.component.html b/console/src/app/pages/orgs/org-detail/org-detail.component.html index 50be20505a..341bcab32c 100644 --- a/console/src/app/pages/orgs/org-detail/org-detail.component.html +++ b/console/src/app/pages/orgs/org-detail/org-detail.component.html @@ -5,16 +5,17 @@
- {{domain.domain}} + {{domain.domain}} +

{{'ORG.PAGES.ORGDOMAIN_VERIFICATION' | translate}}

-
diff --git a/console/src/app/pages/orgs/org-detail/org-detail.component.scss b/console/src/app/pages/orgs/org-detail/org-detail.component.scss index 86f1727703..66bcc3c9ba 100644 --- a/console/src/app/pages/orgs/org-detail/org-detail.component.scss +++ b/console/src/app/pages/orgs/org-detail/org-detail.component.scss @@ -16,6 +16,11 @@ .title { font-size: 16px; margin-right: 1rem; + cursor: pointer; + + &:hover { + text-decoration: underline; + } } .verified, @@ -24,11 +29,20 @@ margin-right: 1rem; } + .verify-btn { + border-radius: .5rem; + font-size: 13px; + } + .fill-space { flex: 1; } } +.add-button { + border-radius: .5rem; +} + .new-desc { font-size: 14px; color: #818a8a; diff --git a/console/src/app/pages/orgs/org-detail/org-detail.component.ts b/console/src/app/pages/orgs/org-detail/org-detail.component.ts index 9fc98d086b..fa1ff4fdd8 100644 --- a/console/src/app/pages/orgs/org-detail/org-detail.component.ts +++ b/console/src/app/pages/orgs/org-detail/org-detail.component.ts @@ -23,6 +23,7 @@ import { OrgService } from 'src/app/services/org.service'; import { ToastService } from 'src/app/services/toast.service'; import { AddDomainDialogComponent } from './add-domain-dialog/add-domain-dialog.component'; +import { DomainVerificationComponent } from './domain-verification/domain-verification.component'; @Component({ @@ -182,4 +183,18 @@ export class OrgDetailComponent implements OnInit, OnDestroy { this.router.navigate(['org/members']); } } + + public verifyDomain(domain: OrgDomainView.AsObject): void { + const dialogRef = this.dialog.open(DomainVerificationComponent, { + data: { + domain: domain, + }, + }); + + dialogRef.afterClosed().subscribe(resp => { + if (resp) { + console.log(resp); + } + }); + } } diff --git a/console/src/app/pages/orgs/org-members/org-members.component.html b/console/src/app/pages/orgs/org-members/org-members.component.html index 08abac6b38..fac1d32a43 100644 --- a/console/src/app/pages/orgs/org-members/org-members.component.html +++ b/console/src/app/pages/orgs/org-members/org-members.component.html @@ -73,9 +73,17 @@ {{ 'PROJECT.MEMBER.ROLES' | translate }} - - - {{ 'ROLES.'+role | translate }} + + + {{ 'PROJECT.GRANT.TITLE' | translate }} + + + {{ 'ROLES.'+role | translate }} + + + diff --git a/console/src/app/pages/orgs/org-members/org-members.component.scss b/console/src/app/pages/orgs/org-members/org-members.component.scss index 23cd86f33e..cbf2c2bad9 100644 --- a/console/src/app/pages/orgs/org-members/org-members.component.scss +++ b/console/src/app/pages/orgs/org-members/org-members.component.scss @@ -73,11 +73,6 @@ width: 50px; max-width: 50px; } - - .role { - display: inline-block; - margin: .25rem; - } } } diff --git a/console/src/app/pages/orgs/org-members/org-members.component.ts b/console/src/app/pages/orgs/org-members/org-members.component.ts index 64cfb3b970..d025ae2ed1 100644 --- a/console/src/app/pages/orgs/org-members/org-members.component.ts +++ b/console/src/app/pages/orgs/org-members/org-members.component.ts @@ -2,10 +2,11 @@ import { SelectionModel } from '@angular/cdk/collections'; import { AfterViewInit, Component, ViewChild } from '@angular/core'; import { MatDialog } from '@angular/material/dialog'; import { MatPaginator } from '@angular/material/paginator'; +import { MatSelectChange } from '@angular/material/select'; import { MatTable } from '@angular/material/table'; import { tap } from 'rxjs/operators'; import { CreationType, MemberCreateDialogComponent } from 'src/app/modules/add-member-dialog/member-create-dialog.component'; -import { Org, OrgMemberView, ProjectMember, ProjectType, User } from 'src/app/proto/generated/management_pb'; +import { Org, OrgMember, OrgMemberView, ProjectMember, ProjectType, User } from 'src/app/proto/generated/management_pb'; import { OrgService } from 'src/app/services/org.service'; import { ToastService } from 'src/app/services/toast.service'; @@ -25,17 +26,23 @@ export class OrgMembersComponent implements AfterViewInit { public dataSource!: OrgMembersDataSource; public selection: SelectionModel = new SelectionModel(true, []); + public memberRoleOptions: string[] = []; + /** Columns displayed in the table. Columns IDs can be added, removed, or reordered. */ public displayedColumns: string[] = ['select', 'firstname', 'lastname', 'username', 'email', 'roles']; - constructor(private orgService: OrgService, + constructor( + private orgService: OrgService, private dialog: MatDialog, - private toast: ToastService) { + private toast: ToastService, + ) { this.orgService.GetMyOrg().then(org => { this.org = org.toObject(); this.dataSource = new OrgMembersDataSource(this.orgService); this.dataSource.loadMembers(0, 25); }); + + this.getRoleOptions(); } public ngAfterViewInit(): void { @@ -44,7 +51,24 @@ export class OrgMembersComponent implements AfterViewInit { tap(() => this.loadMembersPage()), ) .subscribe(); + } + public getRoleOptions(): void { + this.orgService.GetOrgMemberRoles().then(resp => { + this.memberRoleOptions = resp.toObject().rolesList; + }).catch(error => { + this.toast.showError(error); + }); + } + + updateRoles(member: OrgMemberView.AsObject, selectionChange: MatSelectChange): void { + console.log(member.userId, selectionChange.value); + this.orgService.ChangeMyOrgMember(member.userId, selectionChange.value) + .then((newmember: OrgMember) => { + this.toast.showInfo('ORG.TOAST.MEMBERCHANGED', true); + }).catch(error => { + this.toast.showError(error); + }); } private loadMembersPage(): void { diff --git a/console/src/app/pages/orgs/org-members/org-members.module.ts b/console/src/app/pages/orgs/org-members/org-members.module.ts index 6ca41b70d5..343ae6fa33 100644 --- a/console/src/app/pages/orgs/org-members/org-members.module.ts +++ b/console/src/app/pages/orgs/org-members/org-members.module.ts @@ -5,15 +5,18 @@ 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 { 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'; import { HasRoleModule } from 'src/app/directives/has-role/has-role.module'; import { DetailLayoutModule } from 'src/app/modules/detail-layout/detail-layout.module'; +import { HasRolePipeModule } from 'src/app/pipes/has-role-pipe.module'; import { OrgMembersRoutingModule } from './org-members-routing.module'; import { OrgMembersComponent } from './org-members.component'; @@ -39,6 +42,9 @@ import { OrgMembersComponent } from './org-members.component'; FormsModule, TranslateModule, DetailLayoutModule, + MatFormFieldModule, + MatSelectModule, + HasRolePipeModule, ], }) export class OrgMembersModule { } diff --git a/console/src/app/pages/orgs/orgs-routing.module.ts b/console/src/app/pages/orgs/orgs-routing.module.ts index 60f09eab4d..94d21e1e74 100644 --- a/console/src/app/pages/orgs/orgs-routing.module.ts +++ b/console/src/app/pages/orgs/orgs-routing.module.ts @@ -13,7 +13,7 @@ const routes: Routes = [ component: OrgCreateComponent, canActivate: [RoleGuard], data: { - roles: ['iam.write'], + roles: ['(org.create)?(iam.write)?'], }, loadChildren: () => import('./org-create/org-create.module').then(m => m.OrgCreateModule), }, diff --git a/console/src/app/pages/orgs/orgs.module.ts b/console/src/app/pages/orgs/orgs.module.ts index 7405feb6c1..c773e744b3 100644 --- a/console/src/app/pages/orgs/orgs.module.ts +++ b/console/src/app/pages/orgs/orgs.module.ts @@ -11,6 +11,7 @@ import { MatMenuModule } from '@angular/material/menu'; import { MatTabsModule } from '@angular/material/tabs'; import { MatTooltipModule } from '@angular/material/tooltip'; import { TranslateModule } from '@ngx-translate/core'; +import { CopyToClipboardModule } from 'src/app/directives/copy-to-clipboard/copy-to-clipboard.module'; import { HasRoleModule } from 'src/app/directives/has-role/has-role.module'; import { MemberCreateDialogModule } from 'src/app/modules/add-member-dialog/member-create-dialog.module'; import { CardModule } from 'src/app/modules/card/card.module'; @@ -21,13 +22,14 @@ import { WarnDialogModule } from 'src/app/modules/warn-dialog/warn-dialog.module import { ChangesModule } from '../../modules/changes/changes.module'; import { AddDomainDialogModule } from './org-detail/add-domain-dialog/add-domain-dialog.module'; +import { DomainVerificationComponent } from './org-detail/domain-verification/domain-verification.component'; import { OrgDetailComponent } from './org-detail/org-detail.component'; import { OrgGridComponent } from './org-grid/org-grid.component'; import { OrgsRoutingModule } from './orgs-routing.module'; import { PolicyGridComponent } from './policy-grid/policy-grid.component'; @NgModule({ - declarations: [OrgDetailComponent, OrgGridComponent, PolicyGridComponent], + declarations: [OrgDetailComponent, OrgGridComponent, PolicyGridComponent, DomainVerificationComponent], imports: [ CommonModule, OrgsRoutingModule, @@ -53,6 +55,7 @@ import { PolicyGridComponent } from './policy-grid/policy-grid.component'; TranslateModule, SharedModule, ContributorsModule, + CopyToClipboardModule, ], }) export class OrgsModule { } diff --git a/console/src/app/pages/projects/apps/app-detail/app-detail.component.html b/console/src/app/pages/projects/apps/app-detail/app-detail.component.html index d5fd1658cd..369c53cd30 100644 --- a/console/src/app/pages/projects/apps/app-detail/app-detail.component.html +++ b/console/src/app/pages/projects/apps/app-detail/app-detail.component.html @@ -32,7 +32,8 @@

Issuer: {{docs.issuer}}

-
diff --git a/console/src/app/pages/projects/owned-projects/owned-project-detail/owned-project-detail.component.html b/console/src/app/pages/projects/owned-projects/owned-project-detail/owned-project-detail.component.html index de6a45942b..16944fb5f0 100644 --- a/console/src/app/pages/projects/owned-projects/owned-project-detail/owned-project-detail.component.html +++ b/console/src/app/pages/projects/owned-projects/owned-project-detail/owned-project-detail.component.html @@ -6,12 +6,18 @@

{{ 'PROJECT.PAGES.TITLE' | translate }} {{project?.name}}

- + + + diff --git a/console/src/app/pages/projects/owned-projects/owned-project-detail/owned-project-detail.component.ts b/console/src/app/pages/projects/owned-projects/owned-project-detail/owned-project-detail.component.ts index 4941f20544..1841235323 100644 --- a/console/src/app/pages/projects/owned-projects/owned-project-detail/owned-project-detail.component.ts +++ b/console/src/app/pages/projects/owned-projects/owned-project-detail/owned-project-detail.component.ts @@ -166,6 +166,28 @@ export class OwnedProjectDetailComponent implements OnInit, OnDestroy { } } + public deleteProject(): void { + const dialogRef = this.dialog.open(WarnDialogComponent, { + data: { + confirmKey: 'ACTIONS.DELETE', + cancelKey: 'ACTIONS.CANCEL', + titleKey: 'PROJECT.PAGES.DIALOG.DELETE.TITLE', + descriptionKey: 'PROJECT.PAGES.DIALOG.DELETE.DESCRIPTION', + }, + width: '400px', + }); + dialogRef.afterClosed().subscribe(resp => { + if (resp) { + this.projectService.RemoveProject(this.projectId).then(() => { + this.toast.showInfo('PROJECT.TOAST.DELETED', true); + this.router.navigate(['/projects']); + }).catch(error => { + this.toast.showError(error); + }); + } + }); + } + public saveProject(): void { this.projectService.UpdateProject(this.project.projectId, this.project.name).then(() => { this.toast.showInfo('PROJECT.TOAST.UPDATED', true); diff --git a/console/src/app/pages/projects/owned-projects/owned-project-detail/owned-project-detail.module.ts b/console/src/app/pages/projects/owned-projects/owned-project-detail/owned-project-detail.module.ts index 600ee17eec..c18743ce3b 100644 --- a/console/src/app/pages/projects/owned-projects/owned-project-detail/owned-project-detail.module.ts +++ b/console/src/app/pages/projects/owned-projects/owned-project-detail/owned-project-detail.module.ts @@ -11,6 +11,7 @@ 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 { MatTooltipModule } from '@angular/material/tooltip'; import { TranslateModule } from '@ngx-translate/core'; import { HasRoleModule } from 'src/app/directives/has-role/has-role.module'; import { MemberCreateDialogModule } from 'src/app/modules/add-member-dialog/member-create-dialog.module'; @@ -50,6 +51,7 @@ import { ProjectGrantsComponent } from './project-grants/project-grants.componen MatIconModule, ContributorsModule, WarnDialogModule, + MatTooltipModule, ProjectRolesModule, HasRolePipeModule, UserGrantsModule, diff --git a/console/src/app/pages/validators.ts b/console/src/app/pages/validators.ts index e435620480..5083680dae 100644 --- a/console/src/app/pages/validators.ts +++ b/console/src/app/pages/validators.ts @@ -1,7 +1,7 @@ import { FormControl } from '@angular/forms'; export function symbolValidator(c: FormControl): any { - const REGEXP = /[^a-z0-9]/gi; + const REGEXP: RegExp = /[^a-z0-9]/gi; return REGEXP.test(c.value) ? null : { invalid: true, diff --git a/console/src/app/pipes/has-role.pipe.ts b/console/src/app/pipes/has-role.pipe.ts index d0c15e840c..543918e65c 100644 --- a/console/src/app/pipes/has-role.pipe.ts +++ b/console/src/app/pipes/has-role.pipe.ts @@ -7,10 +7,9 @@ import { AuthService } from '../services/auth.service'; name: 'hasRole', }) export class HasRolePipe implements PipeTransform { - constructor(private authService: AuthService) { } - public transform(values: string[], each: boolean = false): Observable { - return this.authService.isAllowed(values, each); + public transform(values: string[]): Observable { + return this.authService.isAllowed(values); } } diff --git a/console/src/app/pipes/regexp-pipe.module.ts b/console/src/app/pipes/regexp-pipe.module.ts new file mode 100644 index 0000000000..a0a59ac58d --- /dev/null +++ b/console/src/app/pipes/regexp-pipe.module.ts @@ -0,0 +1,18 @@ +import { CommonModule } from '@angular/common'; +import { NgModule } from '@angular/core'; + +import { RegexpPipe } from './regexp.pipe'; + + +@NgModule({ + declarations: [ + RegexpPipe, + ], + imports: [ + CommonModule, + ], + exports: [ + RegexpPipe, + ], +}) +export class RegExpPipeModule { } diff --git a/console/src/app/pipes/regexp.pipe.ts b/console/src/app/pipes/regexp.pipe.ts new file mode 100644 index 0000000000..5bb7f0962a --- /dev/null +++ b/console/src/app/pipes/regexp.pipe.ts @@ -0,0 +1,10 @@ +import { Pipe, PipeTransform } from '@angular/core'; + +@Pipe({ + name: 'regexp', +}) +export class RegexpPipe implements PipeTransform { + public transform(value: string): RegExp { + return new RegExp(value); + } +} diff --git a/console/src/app/services/admin.service.ts b/console/src/app/services/admin.service.ts index 7cdd2b879f..09a32c04ed 100644 --- a/console/src/app/services/admin.service.ts +++ b/console/src/app/services/admin.service.ts @@ -5,6 +5,7 @@ import { Metadata } from 'grpc-web'; import { AdminServicePromiseClient } from '../proto/generated/admin_grpc_web_pb'; import { AddIamMemberRequest, + ChangeIamMemberRequest, CreateOrgRequest, CreateUserRequest, IamMember, @@ -134,6 +135,20 @@ export class AdminService { ); } + public async ChangeIamMember( + userId: string, + rolesList: string[], + ): Promise { + const req = new ChangeIamMemberRequest(); + req.setUserId(userId); + req.setRolesList(rolesList); + + return await this.request( + c => c.changeIamMember, + req, + f => f, + ); + } public async GetOrgIamPolicy(orgId: string): Promise { const req = new OrgIamPolicyID(); diff --git a/console/src/app/services/auth.service.ts b/console/src/app/services/auth.service.ts index e7b38ed488..850aabcf1f 100644 --- a/console/src/app/services/auth.service.ts +++ b/console/src/app/services/auth.service.ts @@ -1,5 +1,4 @@ import { Injectable } from '@angular/core'; -import { Router } from '@angular/router'; import { AuthConfig, OAuthService } from 'angular-oauth2-oidc'; import { BehaviorSubject, from, merge, Observable, of, Subject } from 'rxjs'; import { catchError, filter, finalize, first, map, mergeMap, switchMap, take, timeout } from 'rxjs/operators'; @@ -31,7 +30,6 @@ export class AuthService { private userService: AuthUserService, private storage: StorageService, private statehandler: StatehandlerService, - private router: Router, ) { this.user = merge( of(this.oauthService.getAccessToken()).pipe( @@ -66,25 +64,28 @@ export class AuthService { first(), switchMap(() => from(this.userService.GetMyzitadelPermissions())), map(rolesResp => rolesResp.toObject().permissionsList), - ).subscribe(roles => this.zitadelPermissions.next(roles)); + ).subscribe(roles => { + console.log(roles); + this.zitadelPermissions.next(roles); + }); } - public isAllowed(roles: string[], each: boolean = false): Observable { + public isAllowed(roles: string[] | RegExp[]): Observable { if (roles && roles.length > 0) { return this.zitadelPermissions.pipe(switchMap(zroles => { - return of(this.hasRoles(zroles, roles, each)); + return of(this.hasRoles(zroles, roles)); })); } else { return of(false); } } - public hasRoles(userRoles: string[], requestedRoles: string[], each: boolean = false): boolean { - return each ? - requestedRoles.every(role => userRoles.includes(role)) : - requestedRoles.findIndex(role => { - return userRoles.findIndex(i => i.includes(role)) > -1; + public hasRoles(userRoles: string[], requestedRoles: string[] | RegExp[]): boolean { + return requestedRoles.findIndex((regexp: any) => { + return userRoles.findIndex(role => { + return (new RegExp(regexp)).test(role); }) > -1; + }) > -1; } public get authenticated(): boolean { @@ -129,7 +130,6 @@ export class AuthService { this.oauthService.logOut(); this._authenticated = false; this._authenticationChanged.next(false); - this.router.navigate(['/']); } public get activeOrgChanged(): Observable { diff --git a/console/src/app/services/org.service.ts b/console/src/app/services/org.service.ts index bc66eab250..ab8336194a 100644 --- a/console/src/app/services/org.service.ts +++ b/console/src/app/services/org.service.ts @@ -6,15 +6,21 @@ import { ManagementServicePromiseClient } from '../proto/generated/management_gr import { AddOrgDomainRequest, AddOrgMemberRequest, + ChangeOrgMemberRequest, Domain, Iam, Org, + OrgCreateRequest, OrgDomain, OrgDomainSearchQuery, OrgDomainSearchRequest, OrgDomainSearchResponse, + OrgDomainValidationRequest, + OrgDomainValidationResponse, + OrgDomainValidationType, OrgIamPolicy, OrgID, + OrgMember, OrgMemberRoles, OrgMemberSearchRequest, OrgMemberSearchResponse, @@ -34,6 +40,7 @@ import { ProjectGrantCreate, RemoveOrgDomainRequest, RemoveOrgMemberRequest, + ValidateOrgDomainRequest, } from '../proto/generated/management_pb'; import { GrpcBackendService } from './grpc-backend.service'; import { GrpcService, RequestFactory, ResponseMapper } from './grpc.service'; @@ -121,6 +128,31 @@ export class OrgService { ); } + public async GenerateMyOrgDomainValidation(domain: string, type: OrgDomainValidationType): + Promise { + const req: OrgDomainValidationRequest = new OrgDomainValidationRequest(); + req.setDomain(domain); + req.setType(type); + + return await this.request( + c => c.generateMyOrgDomainValidation, + req, + f => f, + ); + } + + public async ValidateMyOrgDomain(domain: string): + Promise { + const req: ValidateOrgDomainRequest = new ValidateOrgDomainRequest(); + req.setDomain(domain); + + return await this.request( + c => c.validateMyOrgDomain, + req, + f => f, + ); + } + public async SearchMyOrgMembers(limit: number, offset: number): Promise { const req = new OrgMemberSearchRequest(); req.setLimit(limit); @@ -142,6 +174,16 @@ export class OrgService { ); } + public async CreateOrg(name: string): Promise { + const req = new OrgCreateRequest(); + req.setName(name); + return await this.request( + c => c.createOrg, + req, + f => f, + ); + } + public async AddMyOrgMember(userId: string, rolesList: string[]): Promise { const req = new AddOrgMemberRequest(); req.setUserId(userId); @@ -155,6 +197,18 @@ export class OrgService { ); } + public async ChangeMyOrgMember(userId: string, rolesList: string[]): Promise { + const req = new ChangeOrgMemberRequest(); + req.setUserId(userId); + req.setRolesList(rolesList); + return await this.request( + c => c.changeMyOrgMember, + req, + f => f, + ); + } + + public async RemoveMyOrgMember(userId: string): Promise { const req = new RemoveOrgMemberRequest(); req.setUserId(userId); diff --git a/console/src/app/services/project.service.ts b/console/src/app/services/project.service.ts index 1e238101a8..f6cd47dfbe 100644 --- a/console/src/app/services/project.service.ts +++ b/console/src/app/services/project.service.ts @@ -10,6 +10,7 @@ import { ApplicationSearchRequest, ApplicationSearchResponse, ApplicationUpdate, + ApplicationView, GrantedProjectSearchRequest, OIDCApplicationCreate, OIDCConfig, @@ -488,7 +489,7 @@ export class ProjectService { ); } - public async GetApplicationById(projectId: string, applicationId: string): Promise { + public async GetApplicationById(projectId: string, applicationId: string): Promise { const req = new ApplicationID(); req.setProjectId(projectId); req.setId(applicationId); @@ -519,6 +520,16 @@ export class ProjectService { ); } + public async RemoveProject(id: string): Promise { + const req = new ProjectID(); + req.setId(id); + return await this.request( + c => c.removeProject, + req, + f => f, + ); + } + public async DeactivateProjectGrant(id: string, projectId: string): Promise { const req = new ProjectGrantID(); diff --git a/console/src/assets/i18n/de.json b/console/src/assets/i18n/de.json index 0d70c8c03c..65f30c0a52 100644 --- a/console/src/assets/i18n/de.json +++ b/console/src/assets/i18n/de.json @@ -56,7 +56,8 @@ "REACTIVATE":"Aktivieren", "DEACTIVATE":"Deaktivieren", "REFRESH":"Aktualisieren", - "LOGIN":"Login" + "LOGIN":"Login", + "EDIT":"Bearbeiten" }, "ERRORS": { "REQUIRED": "Bitte fülle alle benötigten Felder aus!", @@ -265,9 +266,12 @@ "CREATE":"Organisation erstellen", "ORGDETAIL_TITLE":"Gib den Namen und die Domain für die neue Organisation ein.", "ORGDOMAIN_TITLE":"Organisations Domain Verifikation", - "ORGDOMAIN_VERIFICATION":"Stelle deine Domain bereit und überprüfe deren Besitz indem du eine Bestätigungsdatei herunterladen und unter der unten angegebenen URL hochladen. Klicken zum Abschluss auf die Schaltfläche, um diese zu überprüfen.", + "ORGDOMAIN_VERIFICATION":"Überprüfen Sie den Besitz ihrer Domain indem Sie eine Bestätigungsdatei herunterladen und unter der angegebenen URL hochladen oder Sie sie mit einem DNS Eintrag verifizieren.", "ORGDOMAIN_VERIFICATION_SKIP":"Du kannst die Überprüfung vorerst überspringen und deine Organisation weiter erstellen. Um deine Organisation jedoch verwenden zu können, muss dieser Schritt abgeschlossen sein!", "ORGDETAILUSER_TITLE":"Organisationsbesitzer hinzufügen", + "ORGDOMAIN_VERIFICATION_VALIDATION_DESC":"Die Tokens werden regelmäßig überprüft, um sicherzustellen, dass sie weiterhin Besitzer der Domain sind.", + "ORGDOMAIN_VERIFICATION_NEWTOKEN_TITLE":"Neues Token anfordern", + "ORGDOMAIN_VERIFICATION_NEWTOKEN_DESC":"Wenn Sie ein neues Token anfordern wollen, klicken Sie auf die gewünschte Methode. Wenn Sie ein vorhandenes Token validieren möchten Klicken Sie auf Validieren.", "DOWNLOAD_FILE":"Datei download", "SELECTORGTOOLTIP":"Wähle diese Organisation", "PRIMARYDOMAIN":"Primäre Domain", @@ -350,7 +354,8 @@ "DOMAINADDED":"Domain hinzugefügt!", "DOMAINREMOVED":"Domain entfernt!", "MEMBERADDED":"Manager hinzugefügt!", - "MEMBERREMOVED":"Manager entfernt!" + "MEMBERREMOVED":"Manager entfernt!", + "MEMBERCHANGED":"Manager verändert!" } }, "ORG_DETAIL": { @@ -408,11 +413,15 @@ "DIALOG": { "REACTIVATE": { "TITLE":"Projekt reaktivieren", - "DESCRIPTION":"Wollen Sie das Project wirklich reaktivieren?" + "DESCRIPTION":"Wollen Sie das Projekt wirklich reaktivieren?" }, "DEACTIVATE": { "TITLE":"Projekt deaktivieren", - "DESCRIPTION":"Wollen Sie das Project wirklich deaktivieren?" + "DESCRIPTION":"Wollen Sie das Projekt wirklich deaktivieren?" + }, + "DELETE": { + "TITLE":"Projekt löschen", + "DESCRIPTION":"Wollen Sie das Projekt wirklich löschen?" } } }, @@ -479,7 +488,7 @@ "ROLENAMESLIST": "Rollen", "NOROLES":"Keine Rollen", "TOAST":{ - "PROJECTGRANTUSERGRANTADDED":"Project Berechtigung erstellt!", + "PROJECTGRANTUSERGRANTADDED":"Projekt Berechtigung erstellt!", "PROJECTGRANTADDED":"Projekt Berechtigung erstellt", "PROJECTGRANTCHANGED":"Projekt Berechtigung geändert!", "PROJECTGRANTMEMBERADDED":"Berechtigungsmanager hinzugefügt!", @@ -533,7 +542,8 @@ "REACTIVATED":"Reaktiviert!", "DEACTIVATED":"Deaktiviert!", "UPDATED":"Projekt gespeichert!", - "GRANTUPDATED":"Berechtigung verändert!" + "GRANTUPDATED":"Berechtigung verändert!", + "DELETED":"Projekt gelöscht!" } }, "APP": { @@ -624,44 +634,44 @@ "ROLES": { "ORG_OWNER": "Org. Owner", "ORG_MEMBER_VIEWER": "Org. Member Viewer", - "ORG_PROJECT_ROLE_VIEWER": "Org. Project Role Viewer", + "ORG_PROJECT_ROLE_VIEWER": "Org. Projekt Role Viewer", "ORG_EDITOR":"Org. Editor", "ORG_VIEWER":"Org. Viewer", "ORG_MEMBER_EDITOR":"Org.. Member Editor", - "ORG_PROJECT_CREATOR":"Org.. Project Creator", - "ORG_PROJECT_EDITOR":"Org.. Project Editor", - "ORG_PROJECT_VIEWER":"Org.. Project Viewer", - "ORG_PROJECT_MEMBER_EDITOR":"Org.. Project Member Editor", - "ORG_PROJECT_MEMBER_VIEWER":"Org.. Project Member Viewer", - "ORG_PROJECT_ROLE_EDITOR":"Org.. Project Role Editor", - "ORG_PROJECT_APP_EDITOR":"Org. Project App Editor", - "ORG_PROJECT_APP_VIEWER":"Org. Project App Viewer", - "ORG_PROJECT_GRANT_EDITOR":"Org. Project Grant Editor" , - "ORG_PROJECT_GRANT_VIEWER":"Org.Project Grant Viewer", - "ORG_PROJECT_GRANT_MEMBER_EDITOR":"Org.Project Grant Member Editor", - "ORG_PROJECT_GRANT_MEMBER_VIEWER":"Org.Project Grant Member Viewer", + "ORG_PROJECT_CREATOR":"Org.. Projekt Creator", + "ORG_PROJECT_EDITOR":"Org.. Projekt Editor", + "ORG_PROJECT_VIEWER":"Org.. Projekt Viewer", + "ORG_PROJECT_MEMBER_EDITOR":"Org.. Projekt Member Editor", + "ORG_PROJECT_MEMBER_VIEWER":"Org.. Projekt Member Viewer", + "ORG_PROJECT_ROLE_EDITOR":"Org.. Projekt Role Editor", + "ORG_PROJECT_APP_EDITOR":"Org. Projekt App Editor", + "ORG_PROJECT_APP_VIEWER":"Org. Projekt App Viewer", + "ORG_PROJECT_GRANT_EDITOR":"Org. Projekt Grant Editor" , + "ORG_PROJECT_GRANT_VIEWER":"Org.Projekt Grant Viewer", + "ORG_PROJECT_GRANT_MEMBER_EDITOR":"Org.Projekt Grant Member Editor", + "ORG_PROJECT_GRANT_MEMBER_VIEWER":"Org.Projekt Grant Member Viewer", "ORG_USER_EDITOR":"Org.User Editor", "ORG_USER_VIEWER":"Org. User Viewer", "ORG_USER_GRANT_EDITOR":"Org. User Grant Editor", "ORG_USER_GRANT_VIEWER":"Org. User Grant Viewer", "ORG_POLICY_EDITOR":"Org. Policy Editor", "ORG_POLICY_VIEWER":"Org. Policy Viewer", - "PROJECT_OWNER":"Project Owner", - "PROJECT_OWNER_VIEWER":"Project Owner Viewer", - "PROJECT_MEMBER_EDITOR":"Project Member Editor", - "PROJECT_APP_EDITOR":"Project App Editor", - "PROJECT_APP_VIEWER":"Project App Viewer", - "PROJECT_USER_GRANT_EDITOR":"Project User Grant Editor", - "PROJECT_USER_GRANT_VIEWER":"Project User Grant Viewer", - "PROJECT_ROLE_EDITOR": "Project Role Editor", - "PROJECT_MEMBER_VIEWER": "Project Member Viewer", - "PROJECT_GRANT_EDITOR":"Project Grant Editor", - "PROJECT_GRANT_VIEWER":"Project Grant Viewer", - "PROJECT_GRANT_MEMBER_EDITOR":"Project Grant Member Editor", - "PROJECT_GRANT_MEMBER_VIEWER":"Project Grant Member Viewer", - "PROJECT_GRANT_OWNER":"Project Grant Owner", - "PROJECT_GRANT_USER_GRANT_EDITOR":"Project Grant User Editor", - "PROJECT_GRANT_USER_GRANT_VIEWER":"Project Grant User Grant Viewer" + "PROJECT_OWNER":"Projekt Besitzer", + "PROJECT_OWNER_VIEWER":"Projekt Besitzer Viewer", + "PROJECT_MEMBER_EDITOR":"Projekt Manager Editor", + "PROJECT_APP_EDITOR":"Projekt App Editor", + "PROJECT_APP_VIEWER":"Projekt App Viewer", + "PROJECT_USER_GRANT_EDITOR":"Projekt User Grant Editor", + "PROJECT_USER_GRANT_VIEWER":"Projekt User Grant Viewer", + "PROJECT_ROLE_EDITOR": "Projekt Role Editor", + "PROJECT_MEMBER_VIEWER": "Projekt Member Viewer", + "PROJECT_GRANT_EDITOR":"Projekt Grant Editor", + "PROJECT_GRANT_VIEWER":"Projekt Grant Viewer", + "PROJECT_GRANT_MEMBER_EDITOR":"Projekt Grant Member Editor", + "PROJECT_GRANT_MEMBER_VIEWER":"Projekt Grant Member Viewer", + "PROJECT_GRANT_OWNER":"Projekt Grant Owner", + "PROJECT_GRANT_USER_GRANT_EDITOR":"Projekt Grant User Editor", + "PROJECT_GRANT_USER_GRANT_VIEWER":"Projekt Grant User Grant Viewer" }, "GRANTS": { "DELETE":"Grant löschen", diff --git a/console/src/assets/i18n/en.json b/console/src/assets/i18n/en.json index b1f23e64ed..e15acb6ccd 100644 --- a/console/src/assets/i18n/en.json +++ b/console/src/assets/i18n/en.json @@ -56,7 +56,8 @@ "REACTIVATE":"Reactivate", "DEACTIVATE":"Deactivate", "REFRESH":"Refresh", - "LOGIN":"Login" + "LOGIN":"Login", + "EDIT":"Edit" }, "ERRORS": { "REQUIRED": "Some required fields are missing!", @@ -265,9 +266,12 @@ "CREATE":"Create organisation", "ORGDETAIL_TITLE":"Enter the name and domain of your new organisation.", "ORGDOMAIN_TITLE":"Organisation domain ownership verification", - "ORGDOMAIN_VERIFICATION":"Provide your web domain and verify their ownership. You need to download a verification file and upload it at the provided URL listed below. To complete, click the button to verify.", + "ORGDOMAIN_VERIFICATION":"Verify ownership of your domain. You need to download a verification file and upload it at the provided URL listed below or place a TXT Record at the provided Url. To complete, click the button to verify.", "ORGDOMAIN_VERIFICATION_SKIP":"You can skip verification for now and continue to create your organisation, but in order to use your organisation this step has to be completed!", "ORGDETAILUSER_TITLE":"Configure Organisation Owner", + "ORGDOMAIN_VERIFICATION_VALIDATION_DESC":"The tokens are checked regularly to ensure you are still owner of the domain.", + "ORGDOMAIN_VERIFICATION_NEWTOKEN_TITLE":"Request new token", + "ORGDOMAIN_VERIFICATION_NEWTOKEN_DESC":"If you want to request a new token, select you preferred method, if you want to validate a persisting token, click on the button above.", "DOWNLOAD_FILE":"Download file", "SELECTORGTOOLTIP":"Select this organisation", "PRIMARYDOMAIN":"Primary Domain", @@ -350,7 +354,8 @@ "DOMAINADDED":"Added domain!", "DOMAINREMOVED":"Removed domain!", "MEMBERADDED":"Manager added!", - "MEMBERREMOVED":"Manager removed!" + "MEMBERREMOVED":"Manager removed!", + "MEMBERCHANGED":"Manager changed!" } }, "ORG_DETAIL": { @@ -413,6 +418,10 @@ "DEACTIVATE": { "TITLE":"Deactivate project", "DESCRIPTION":"Do you really want to deactivate your project?" + }, + "DELETE": { + "TITLE":"Projekt löschen", + "DESCRIPTION":"Wollen Sie das Project wirklich löschen?" } } }, @@ -533,7 +542,8 @@ "REACTIVATED":"Reactivated!", "DEACTIVATED":"Deactivated!", "UPDATED":"Project changed!", - "GRANTUPDATED":"Grant changed!" + "GRANTUPDATED":"Grant changed!", + "DELETED":"Deleted Project!" } }, "APP": {