mirror of
https://github.com/zitadel/zitadel.git
synced 2025-02-28 20:17:23 +00:00
feat: show all available organizations when creating project grants (#6040)
* feat: show available orgs (project) grants * feat: add e2e for project grant * feat: add bulgarian missing translations * feat: update docs * fix: add @peintnermax suggested changes --------- Co-authored-by: Max Peintner <max@caos.ch>
This commit is contained in:
parent
e1b3cda98a
commit
7b44209bfd
@ -16,6 +16,7 @@
|
||||
color="primary"
|
||||
class="cnsl-action-button"
|
||||
mat-raised-button
|
||||
data-e2e="create-project-role-button"
|
||||
>
|
||||
<mat-icon data-e2e="add-new-role" class="icon">add</mat-icon>
|
||||
<span>{{ 'ACTIONS.NEW' | translate }}</span>
|
||||
|
@ -0,0 +1,32 @@
|
||||
<form>
|
||||
<cnsl-form-field class="full-width">
|
||||
<cnsl-label>{{ 'PROJECT.GRANT.CREATE.SEL_ORG_FORMFIELD' | translate }}</cnsl-label>
|
||||
<input
|
||||
cnslInput
|
||||
type="text"
|
||||
placeholder="Organization XY"
|
||||
#nameInput
|
||||
[formControl]="myControl"
|
||||
[matAutocomplete]="auto"
|
||||
data-e2e="add-org-input"
|
||||
/>
|
||||
|
||||
<mat-autocomplete #auto="matAutocomplete" (optionSelected)="selected($event)" [displayWith]="displayFn">
|
||||
<mat-option *ngIf="isLoading" class="is-loading">
|
||||
<mat-spinner diameter="30"></mat-spinner>
|
||||
</mat-option>
|
||||
<mat-option *ngFor="let org of filteredOrgs" [value]="org">
|
||||
<div class="org-option" data-e2e="org-option">
|
||||
<div class="org-option-column">
|
||||
<span>{{ org.name }}</span>
|
||||
<span class="fill-space"></span>
|
||||
<span class="smaller cnsl-secondary-text">{{ org.primaryDomain }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</mat-option>
|
||||
</mat-autocomplete>
|
||||
<span class="org-autocomplete-target-desc">
|
||||
{{ 'PROJECT.GRANT.CREATE.SEL_ORG_DESC' | translate }}
|
||||
</span>
|
||||
</cnsl-form-field>
|
||||
</form>
|
@ -0,0 +1,38 @@
|
||||
.full-width {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
input {
|
||||
max-width: 500px;
|
||||
}
|
||||
|
||||
.org-option {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
.org-option-column {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: flex-start;
|
||||
justify-content: center;
|
||||
width: 100%;
|
||||
|
||||
span {
|
||||
line-height: normal;
|
||||
}
|
||||
|
||||
.fill-space {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.smaller {
|
||||
font-size: 13px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.org-autocomplete-target-desc {
|
||||
font-size: 14px;
|
||||
display: block;
|
||||
margin-top: 0.5rem;
|
||||
}
|
@ -0,0 +1,24 @@
|
||||
import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';
|
||||
|
||||
import { SearchOrgAutocompleteComponent } from './search-org-autocomplete.component';
|
||||
|
||||
describe('SearchOrgComponent', () => {
|
||||
let component: SearchOrgAutocompleteComponent;
|
||||
let fixture: ComponentFixture<SearchOrgAutocompleteComponent>;
|
||||
|
||||
beforeEach(waitForAsync(() => {
|
||||
TestBed.configureTestingModule({
|
||||
declarations: [SearchOrgAutocompleteComponent],
|
||||
}).compileComponents();
|
||||
}));
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(SearchOrgAutocompleteComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
@ -0,0 +1,83 @@
|
||||
import { Component, EventEmitter, OnDestroy, OnInit, Output, ViewChild } from '@angular/core';
|
||||
import { UntypedFormControl } from '@angular/forms';
|
||||
import { MatAutocompleteSelectedEvent } from '@angular/material/autocomplete';
|
||||
import { MatLegacyAutocomplete as MatAutocomplete } from '@angular/material/legacy-autocomplete';
|
||||
import { debounceTime, from, map, Subject, switchMap, takeUntil, tap } from 'rxjs';
|
||||
import { TextQueryMethod } from 'src/app/proto/generated/zitadel/object_pb';
|
||||
import { Org, OrgNameQuery, OrgQuery, OrgState, OrgStateQuery } from 'src/app/proto/generated/zitadel/org_pb';
|
||||
import { AuthenticationService } from 'src/app/services/authentication.service';
|
||||
import { GrpcAuthService } from 'src/app/services/grpc-auth.service';
|
||||
|
||||
@Component({
|
||||
selector: 'cnsl-search-org-autocomplete',
|
||||
templateUrl: './search-org-autocomplete.component.html',
|
||||
styleUrls: ['./search-org-autocomplete.component.scss'],
|
||||
})
|
||||
export class SearchOrgAutocompleteComponent implements OnInit, OnDestroy {
|
||||
public selectable: boolean = true;
|
||||
public myControl: UntypedFormControl = new UntypedFormControl();
|
||||
public filteredOrgs: Array<Org.AsObject> = [];
|
||||
public isLoading: boolean = false;
|
||||
@ViewChild('auto') public matAutocomplete!: MatAutocomplete;
|
||||
@Output() public selectionChanged: EventEmitter<Org.AsObject> = new EventEmitter();
|
||||
|
||||
private unsubscribed$: Subject<void> = new Subject();
|
||||
constructor(public authService: AuthenticationService, private auth: GrpcAuthService) {
|
||||
this.myControl.valueChanges
|
||||
.pipe(
|
||||
takeUntil(this.unsubscribed$),
|
||||
debounceTime(200),
|
||||
tap(() => (this.isLoading = true)),
|
||||
switchMap((value) => {
|
||||
const stateQuery = new OrgQuery();
|
||||
const orgStateQuery = new OrgStateQuery();
|
||||
orgStateQuery.setState(OrgState.ORG_STATE_ACTIVE);
|
||||
stateQuery.setStateQuery(orgStateQuery);
|
||||
|
||||
let queries: OrgQuery[] = [stateQuery];
|
||||
|
||||
if (value) {
|
||||
const nameQuery = new OrgQuery();
|
||||
const orgNameQuery = new OrgNameQuery();
|
||||
orgNameQuery.setName(value);
|
||||
orgNameQuery.setMethod(TextQueryMethod.TEXT_QUERY_METHOD_CONTAINS_IGNORE_CASE);
|
||||
nameQuery.setNameQuery(orgNameQuery);
|
||||
queries = [stateQuery, nameQuery];
|
||||
}
|
||||
|
||||
return from(this.auth.listMyProjectOrgs(undefined, 0, queries)).pipe(
|
||||
map((resp) => {
|
||||
return resp.resultList.sort((left, right) => left.name.localeCompare(right.name));
|
||||
}),
|
||||
);
|
||||
}),
|
||||
)
|
||||
.subscribe((returnValue) => {
|
||||
this.isLoading = false;
|
||||
this.filteredOrgs = returnValue;
|
||||
});
|
||||
}
|
||||
|
||||
public ngOnInit(): void {
|
||||
const query = new OrgQuery();
|
||||
const orgStateQuery = new OrgStateQuery();
|
||||
orgStateQuery.setState(OrgState.ORG_STATE_ACTIVE);
|
||||
query.setStateQuery(orgStateQuery);
|
||||
|
||||
this.auth.listMyProjectOrgs(undefined, 0, [query]).then((orgs) => {
|
||||
this.filteredOrgs = orgs.resultList;
|
||||
});
|
||||
}
|
||||
|
||||
public ngOnDestroy(): void {
|
||||
this.unsubscribed$.next();
|
||||
}
|
||||
|
||||
public displayFn(org?: Org.AsObject): string {
|
||||
return org ? `${org.name}` : '';
|
||||
}
|
||||
|
||||
public selected(event: MatAutocompleteSelectedEvent): void {
|
||||
this.selectionChanged.emit(event.option.value);
|
||||
}
|
||||
}
|
@ -0,0 +1,32 @@
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { NgModule } from '@angular/core';
|
||||
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
|
||||
import { MatIconModule } from '@angular/material/icon';
|
||||
import { MatLegacyAutocompleteModule as MatAutocompleteModule } from '@angular/material/legacy-autocomplete';
|
||||
import { MatLegacyButtonModule as MatButtonModule } from '@angular/material/legacy-button';
|
||||
import { MatLegacyChipsModule as MatChipsModule } from '@angular/material/legacy-chips';
|
||||
import { MatLegacyProgressSpinnerModule as MatProgressSpinnerModule } from '@angular/material/legacy-progress-spinner';
|
||||
import { MatLegacySelectModule as MatSelectModule } from '@angular/material/legacy-select';
|
||||
import { TranslateModule } from '@ngx-translate/core';
|
||||
import { InputModule } from 'src/app/modules/input/input.module';
|
||||
|
||||
import { SearchOrgAutocompleteComponent } from './search-org-autocomplete.component';
|
||||
|
||||
@NgModule({
|
||||
declarations: [SearchOrgAutocompleteComponent],
|
||||
imports: [
|
||||
CommonModule,
|
||||
MatAutocompleteModule,
|
||||
MatChipsModule,
|
||||
MatButtonModule,
|
||||
InputModule,
|
||||
MatIconModule,
|
||||
ReactiveFormsModule,
|
||||
MatProgressSpinnerModule,
|
||||
FormsModule,
|
||||
TranslateModule,
|
||||
MatSelectModule,
|
||||
],
|
||||
exports: [SearchOrgAutocompleteComponent],
|
||||
})
|
||||
export class SearchOrgAutocompleteModule {}
|
@ -6,20 +6,8 @@
|
||||
>
|
||||
<ng-container *ngIf="currentCreateStep === 1">
|
||||
<h1>{{ 'PROJECT.GRANT.CREATE.SEL_ORG' | translate }}</h1>
|
||||
<p>{{ 'PROJECT.GRANT.CREATE.SEL_ORG_DESC' | translate }}</p>
|
||||
|
||||
<form (ngSubmit)="searchOrg(domain.value)">
|
||||
<cnsl-form-field class="org-domain">
|
||||
<cnsl-label>{{ 'PROJECT.GRANT.CREATE.SEL_ORG_FORMFIELD' | translate }}</cnsl-label>
|
||||
<input cnslInput #domain />
|
||||
</cnsl-form-field>
|
||||
|
||||
<button [disabled]="domain.value.length === 0" color="primary" type="submit" class="domain-button" mat-raised-button>
|
||||
{{ 'PROJECT.GRANT.CREATE.SEL_ORG_BUTTON' | translate }}
|
||||
</button>
|
||||
</form>
|
||||
|
||||
<span *ngIf="org"> {{ 'PROJECT.GRANT.CREATE.FOR_ORG' | translate }} {{ org.name }} </span>
|
||||
<cnsl-search-org-autocomplete class="block" (selectionChanged)="selectOrg($event)"> </cnsl-search-org-autocomplete>
|
||||
<span *ngIf="org"> {{ 'PROJECT.GRANT.CREATE.FOR_ORG' | translate }} {{ org.name }} - {{ org.primaryDomain }} </span>
|
||||
</ng-container>
|
||||
|
||||
<ng-container *ngIf="currentCreateStep === 2">
|
||||
@ -37,7 +25,15 @@
|
||||
|
||||
<div class="btn-container">
|
||||
<ng-container *ngIf="currentCreateStep === 1">
|
||||
<button [disabled]="!org" (click)="next()" color="primary" mat-raised-button class="big-button" cdkFocusInitial>
|
||||
<button
|
||||
[disabled]="!org"
|
||||
(click)="next()"
|
||||
color="primary"
|
||||
mat-raised-button
|
||||
class="big-button"
|
||||
cdkFocusInitial
|
||||
data-e2e="project-grant-continue"
|
||||
>
|
||||
{{ 'ACTIONS.CONTINUE' | translate }}
|
||||
</button>
|
||||
</ng-container>
|
||||
@ -46,7 +42,15 @@
|
||||
<button (click)="previous()" mat-stroked-button class="small-button">
|
||||
{{ 'ACTIONS.BACK' | translate }}
|
||||
</button>
|
||||
<button color="primary" [disabled]="!org" (click)="addGrant()" mat-raised-button class="big-button" cdkFocusInitial>
|
||||
<button
|
||||
color="primary"
|
||||
[disabled]="!org"
|
||||
(click)="addGrant()"
|
||||
mat-raised-button
|
||||
class="big-button"
|
||||
cdkFocusInitial
|
||||
data-e2e="save-project-grant-button"
|
||||
>
|
||||
{{ 'ACTIONS.SAVE' | translate }}
|
||||
</button>
|
||||
</ng-container>
|
||||
|
@ -88,6 +88,10 @@ export class ProjectGrantCreateComponent implements OnInit, OnDestroy {
|
||||
}
|
||||
}
|
||||
|
||||
public selectOrg(org: Org.AsObject): void {
|
||||
this.org = org;
|
||||
}
|
||||
|
||||
public selectRoles(roles: string[]): void {
|
||||
this.rolesKeyList = roles;
|
||||
}
|
||||
|
@ -15,6 +15,7 @@ import { InputModule } from 'src/app/modules/input/input.module';
|
||||
import { ProjectRolesTableModule } from 'src/app/modules/project-roles-table/project-roles-table.module';
|
||||
import { HasRolePipeModule } from 'src/app/pipes/has-role-pipe/has-role-pipe.module';
|
||||
|
||||
import { SearchOrgAutocompleteModule } from 'src/app/modules/search-org-autocomplete/search-org-autocomplete.module';
|
||||
import { ProjectGrantCreateRoutingModule } from './project-grant-create-routing.module';
|
||||
import { ProjectGrantCreateComponent } from './project-grant-create.component';
|
||||
|
||||
@ -38,6 +39,7 @@ import { ProjectGrantCreateComponent } from './project-grant-create.component';
|
||||
MatProgressSpinnerModule,
|
||||
FormsModule,
|
||||
TranslateModule,
|
||||
SearchOrgAutocompleteModule,
|
||||
],
|
||||
})
|
||||
export default class ProjectGrantCreateModule {}
|
||||
|
@ -17,6 +17,7 @@
|
||||
class="cnsl-action-button"
|
||||
mat-raised-button
|
||||
[routerLink]="['/projects', projectId, 'projectgrants', 'create']"
|
||||
data-e2e="create-project-grant-button"
|
||||
>
|
||||
<mat-icon class="icon">add</mat-icon>
|
||||
<span>{{ 'ACTIONS.NEW' | translate }}</span>
|
||||
|
@ -12,15 +12,15 @@
|
||||
<div class="newrole">
|
||||
<cnsl-form-field class="formfield">
|
||||
<cnsl-label>{{ 'PROJECT.ROLE.KEY' | translate }}</cnsl-label>
|
||||
<input cnslInput formControlName="key" />
|
||||
<input cnslInput formControlName="key" data-e2e="role-key-input" />
|
||||
</cnsl-form-field>
|
||||
<cnsl-form-field class="formfield">
|
||||
<cnsl-label>{{ 'PROJECT.ROLE.DISPLAY_NAME' | translate }}</cnsl-label>
|
||||
<input cnslInput formControlName="displayName" />
|
||||
<input cnslInput formControlName="displayName" data-e2e="role-display-name-input" />
|
||||
</cnsl-form-field>
|
||||
<cnsl-form-field class="formfield">
|
||||
<cnsl-label>{{ 'PROJECT.ROLE.GROUP' | translate }}</cnsl-label>
|
||||
<input cnslInput formControlName="group" />
|
||||
<input cnslInput formControlName="group" data-e2e="role-group-input" />
|
||||
</cnsl-form-field>
|
||||
</div>
|
||||
<button
|
||||
@ -36,7 +36,14 @@
|
||||
</ng-container>
|
||||
</div>
|
||||
|
||||
<button class="add-line-btn" color="primary" type="button" mat-stroked-button (click)="addEntry()">
|
||||
<button
|
||||
class="add-line-btn"
|
||||
color="primary"
|
||||
type="button"
|
||||
data-e2e="new-project-role-button"
|
||||
mat-stroked-button
|
||||
(click)="addEntry()"
|
||||
>
|
||||
{{ 'PROJECT.ROLE.ADDNEWLINE' | translate }}
|
||||
</button>
|
||||
|
||||
|
@ -1502,12 +1502,11 @@
|
||||
"SEL_PROJECT": "Търсене на проект",
|
||||
"SEL_ROLES": "Изберете ролите, които искате да бъдат добавени към субсидията",
|
||||
"SEL_USER": "Изберете потребители",
|
||||
"SEL_ORG": "Задайте домейна",
|
||||
"SEL_ORG_DESC": "Въведете пълния домейн, за да посочите организацията, която да предоставите.",
|
||||
"ORG_TITLE": "Организация",
|
||||
"SEL_ORG": "Търсете организация",
|
||||
"SEL_ORG_DESC": "Потърсете организацията за отпускане.",
|
||||
"ORG_DESCRIPTION": "На път сте да предоставите потребител за организацията {{name}}.",
|
||||
"ORG_DESCRIPTION_DESC": "Превключете контекста в заглавката по-горе, за да предоставите потребител за друга организация.",
|
||||
"SEL_ORG_FORMFIELD": "Пълен домейн",
|
||||
"SEL_ORG_FORMFIELD": "Организация",
|
||||
"SEL_ORG_BUTTON": "Организация на търсенето",
|
||||
"FOR_ORG": "Безвъзмездната помощ е създадена за:"
|
||||
},
|
||||
|
@ -1508,13 +1508,11 @@
|
||||
"SEL_ROLES": "Selektiere die gewünschten Rollen für das Erstellen der Berechtigung.",
|
||||
"SEL_PROJECT": "Suchen nach Projekt",
|
||||
"SEL_USER": "Benutzer auswählen",
|
||||
"SEL_ORG": "Suchen nach Domain",
|
||||
"SEL_ORG_DESC": "Gebe die vollständige Domain ein, um Resultate zu erhalten.",
|
||||
"ORG_TITLE": "Organisation",
|
||||
"SEL_ORG": "Durchsuchen Sie eine Organisation",
|
||||
"SEL_ORG_DESC": "Suchen Sie nach der zu gewährenden Organisation.",
|
||||
"ORG_DESCRIPTION": "Du bist im Begriff, einen Benutzer für die Organisation {{name}} zu berechtigen.",
|
||||
"ORG_DESCRIPTION_DESC": "Wechsle den Kontext, um die Organisation zu wechseln.",
|
||||
"SEL_ORG_FORMFIELD": "Vollständige Domain",
|
||||
"SEL_ORG_BUTTON": "Suche Organisation",
|
||||
"SEL_ORG_FORMFIELD": "Organisation",
|
||||
"FOR_ORG": "Die Berechtigung wird erstellt für:"
|
||||
},
|
||||
"DETAIL": {
|
||||
|
@ -1501,7 +1501,7 @@
|
||||
"GRANT": {
|
||||
"EMPTY": "No granted organization.",
|
||||
"TITLE": "Project Grants",
|
||||
"DESCRIPTION": "Allow an other organization to use your project.",
|
||||
"DESCRIPTION": "Allow another organization to use your project.",
|
||||
"EDITTITLE": "Edit roles",
|
||||
"CREATE": {
|
||||
"TITLE": "Create Organization Grant",
|
||||
@ -1509,13 +1509,11 @@
|
||||
"SEL_PROJECT": "Search for a project",
|
||||
"SEL_ROLES": "Select the roles you want to be added to the grant",
|
||||
"SEL_USER": "Select users",
|
||||
"SEL_ORG": "Set the domain",
|
||||
"SEL_ORG_DESC": "Enter the complete domain to specify the organization to grant.",
|
||||
"ORG_TITLE": "Organization",
|
||||
"SEL_ORG": "Search an organization",
|
||||
"SEL_ORG_DESC": "Search the organization to grant.",
|
||||
"ORG_DESCRIPTION": "You are about to grant a user for the organization {{name}}.",
|
||||
"ORG_DESCRIPTION_DESC": "Switch the context in the header above to grant a user for another organization.",
|
||||
"SEL_ORG_FORMFIELD": "Complete Domain",
|
||||
"SEL_ORG_BUTTON": "Search Organization",
|
||||
"SEL_ORG_FORMFIELD": "Organization",
|
||||
"FOR_ORG": "The grant is created for:"
|
||||
},
|
||||
"DETAIL": {
|
||||
|
@ -1509,13 +1509,11 @@
|
||||
"SEL_PROJECT": "Buscar un proyecto",
|
||||
"SEL_ROLES": "Selecciona los roles que quieres que se añadan a la concesión",
|
||||
"SEL_USER": "Seleccionar usuarios",
|
||||
"SEL_ORG": "Establecer el dominio",
|
||||
"SEL_ORG_DESC": "Introduce el dominio completo para especificar la organización concesionaria.",
|
||||
"ORG_TITLE": "Organización",
|
||||
"SEL_ORG": "Buscar una organización",
|
||||
"SEL_ORG_DESC": "Busca la organización concesionaria.",
|
||||
"ORG_DESCRIPTION": "Estás a punto de conceder acceso a un usuario para la organización {{name}}.",
|
||||
"ORG_DESCRIPTION_DESC": "Cambia el contexto en la cabecera superior para conceder acceso a un usuario para otra organización.",
|
||||
"SEL_ORG_FORMFIELD": "Completar dominio",
|
||||
"SEL_ORG_BUTTON": "Buscar organización",
|
||||
"SEL_ORG_FORMFIELD": "Organización",
|
||||
"FOR_ORG": "La concesión se creó para:"
|
||||
},
|
||||
"DETAIL": {
|
||||
|
@ -1508,13 +1508,11 @@
|
||||
"SEL_PROJECT": "Rechercher un projet",
|
||||
"SEL_ROLES": "Sélectionnez les rôles que vous souhaitez ajouter à l'autorisation.",
|
||||
"SEL_USER": "Sélectionnez les utilisateurs",
|
||||
"SEL_ORG": "Définir le domaine",
|
||||
"SEL_ORG_DESC": "Entrez le domaine complet pour spécifier l'organisation à accorder.",
|
||||
"ORG_TITLE": "Organisation",
|
||||
"SEL_ORG": "Rechercher une organisation",
|
||||
"SEL_ORG_DESC": "Rechercher l'organisme à accorder",
|
||||
"ORG_DESCRIPTION": "Vous êtes sur le point d'accorder un utilisateur pour l'organisation{{name}}.",
|
||||
"ORG_DESCRIPTION_DESC": "Changez le contexte dans l'en-tête ci-dessus pour accorder un utilisateur pour une autre organisation.",
|
||||
"SEL_ORG_FORMFIELD": "Domaine complet",
|
||||
"SEL_ORG_BUTTON": "Rechercher une organisation",
|
||||
"SEL_ORG_FORMFIELD": "Organisation",
|
||||
"FOR_ORG": "L'autorisation est créée pour"
|
||||
},
|
||||
"DETAIL": {
|
||||
|
@ -1508,13 +1508,11 @@
|
||||
"SEL_PROJECT": "Cerca un progetto",
|
||||
"SEL_ROLES": "Seleziona i ruoli che vuoi aggiungere",
|
||||
"SEL_USER": "Seleziona utenti",
|
||||
"SEL_ORG": "Impostare il dominio",
|
||||
"SEL_ORG_DESC": "Inserisci il dominio completo per specificare l'organizzazione da concedere.",
|
||||
"ORG_TITLE": "Organizzazione",
|
||||
"SEL_ORG": "Cerca un'organizzazione",
|
||||
"SEL_ORG_DESC": "Cerca l'organizzazione da concedere.",
|
||||
"ORG_DESCRIPTION": "Stai per concedere un utente per l'organizzazione {{name}}.",
|
||||
"ORG_DESCRIPTION_DESC": "Cambia il contesto nell'intestazione qui sopra per concedere un utente per un'altra organizzazione.",
|
||||
"SEL_ORG_FORMFIELD": "Dominio completo",
|
||||
"SEL_ORG_BUTTON": "Ricerca organizzazione",
|
||||
"SEL_ORG_FORMFIELD": "Organizzazione",
|
||||
"FOR_ORG": "Org grant \u00e8 creato per:"
|
||||
},
|
||||
"DETAIL": {
|
||||
|
@ -1504,13 +1504,11 @@
|
||||
"SEL_PROJECT": "プロジェクトを検索する",
|
||||
"SEL_ROLES": "許可するロールを選択する",
|
||||
"SEL_USER": "ユーザーを選択する",
|
||||
"SEL_ORG": "ドメインを設定する",
|
||||
"SEL_ORG_DESC": "完全なドメインを入力して、アクセスを許可する組織を指定する。",
|
||||
"ORG_TITLE": "組織",
|
||||
"SEL_ORG": "組織を検索する",
|
||||
"SEL_ORG_DESC": "付与する組織を検索する",
|
||||
"ORG_DESCRIPTION": "組織 {{name}} にユーザーをグラントします。",
|
||||
"ORG_DESCRIPTION_DESC": "上記のヘッダーのコンテキストを切り替えることで、別組織のユーザーにグラントできます。",
|
||||
"SEL_ORG_FORMFIELD": "完全なドメイン",
|
||||
"SEL_ORG_BUTTON": "組織を検索する",
|
||||
"SEL_ORG_FORMFIELD": "組織",
|
||||
"FOR_ORG": "グラントが以下に対して作成されます:"
|
||||
},
|
||||
"DETAIL": {
|
||||
|
@ -1508,13 +1508,11 @@
|
||||
"SEL_PROJECT": "Wyszukaj projekt",
|
||||
"SEL_ROLES": "Wybierz role, które mają zostać dodane do udzielenia ",
|
||||
"SEL_USER": "Wybierz użytkowników",
|
||||
"SEL_ORG": "Ustaw domenę",
|
||||
"SEL_ORG_DESC": "Wprowadź pełną domenę, aby określić organizację, której chcesz udzielić dostępu.",
|
||||
"ORG_TITLE": "Organizacja",
|
||||
"SEL_ORG": "Wyszukaj organizację",
|
||||
"SEL_ORG_DESC": "Wyszukaj organizację, której chcesz przyznać.",
|
||||
"ORG_DESCRIPTION": "Masz zamiar udzielić użytkownikowi dostęp dla organizacji {{name}}.",
|
||||
"ORG_DESCRIPTION_DESC": "Przełącz kontekst w nagłówku powyżej, aby udzielić użytkownikowi dostępu dla innej organizacji.",
|
||||
"SEL_ORG_FORMFIELD": "Pełna domena",
|
||||
"SEL_ORG_BUTTON": "Wyszukaj organizację",
|
||||
"SEL_ORG_FORMFIELD": "Organizacja",
|
||||
"FOR_ORG": "Dostęp udzielany:"
|
||||
},
|
||||
"DETAIL": {
|
||||
|
@ -1507,13 +1507,11 @@
|
||||
"SEL_PROJECT": "搜索项目",
|
||||
"SEL_ROLES": "选择要添加到授权中的角色",
|
||||
"SEL_USER": "选择一个或多个用户",
|
||||
"SEL_ORG": "选择一个组织",
|
||||
"SEL_ORG_DESC": "输入完整的域以指定要授予的组织。",
|
||||
"ORG_TITLE": "组织",
|
||||
"SEL_ORG": "搜索组织",
|
||||
"SEL_ORG_DESC": "搜索要授予的组织",
|
||||
"ORG_DESCRIPTION": "您即将授予组织 {{name}} 的用户。",
|
||||
"ORG_DESCRIPTION_DESC": "切换上面标题中的上下文以授予另一个组织的用户。",
|
||||
"SEL_ORG_FORMFIELD": "完整域名",
|
||||
"SEL_ORG_BUTTON": "搜索组织",
|
||||
"SEL_ORG_FORMFIELD": "组织",
|
||||
"FOR_ORG": "授予组织:"
|
||||
},
|
||||
"DETAIL": {
|
||||
|
@ -19,7 +19,11 @@ You would have to create roles for administration and your clients in this very
|
||||
|
||||
To create a project, navigate to your organization, then projects or directly via <https://{your_domain}.zitadel.cloud/ui/console/projects>, and then click the button to create a new project.
|
||||
|
||||
<img alt="Empty Project" src="/docs/img/console_projects_empty.png" width="270px" />
|
||||
<img
|
||||
alt="Empty Project"
|
||||
src="/docs/img/console_projects_empty.png"
|
||||
width="270px"
|
||||
/>
|
||||
|
||||
then enter your project name and continue.
|
||||
|
||||
@ -51,7 +55,7 @@ Organizations can then create authorizations for their users on their own. The p
|
||||
|
||||
<img src="/docs/img/guides/console/grantsmenu.png" alt="Grants" width="170px" />
|
||||
|
||||
2. Enter the domain of the organization you want to grant (go to the organization detail page if you can't remember it), hit the search button and continue.
|
||||
2. Search the organization you want to grant using the auto complete input and continue.
|
||||
3. Select some roles you would like to grant to the organization and confirm.
|
||||
4. You should now see the granted organization in the section **grants**.
|
||||
|
||||
|
@ -1,19 +1,23 @@
|
||||
import { Context } from 'support/commands';
|
||||
import { ensureProjectDoesntExist, ensureProjectExists } from '../../support/api/projects';
|
||||
import { ensureOrgExists } from 'support/api/orgs';
|
||||
|
||||
describe('projects', () => {
|
||||
beforeEach(() => {
|
||||
cy.context().as('ctx');
|
||||
});
|
||||
|
||||
const defaultOrg = 'e2eorgnewdefault';
|
||||
const testProjectNameCreate = 'e2eprojectcreate';
|
||||
const testProjectNameDelete = 'e2eprojectdelete';
|
||||
|
||||
describe('add project', () => {
|
||||
beforeEach(`ensure it doesn't exist already`, () => {
|
||||
cy.get<Context>('@ctx').then((ctx) => {
|
||||
ensureProjectDoesntExist(ctx.api, testProjectNameCreate);
|
||||
cy.visit(`/projects`);
|
||||
ensureOrgExists(ctx, defaultOrg).then(() => {
|
||||
ensureProjectDoesntExist(ctx.api, testProjectNameCreate);
|
||||
cy.visit(`/projects`);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@ -27,10 +31,49 @@ describe('projects', () => {
|
||||
it('should configure a project to assert roles on authentication');
|
||||
});
|
||||
|
||||
describe('create project grant', () => {
|
||||
const testRoleName = 'e2eroleundertestname';
|
||||
|
||||
beforeEach('ensure it exists', () => {
|
||||
cy.get<Context>('@ctx').then((ctx) => {
|
||||
ensureProjectExists(ctx.api, testProjectNameCreate).as('projectId');
|
||||
cy.get<number>('@projectId').then((projectId) => {
|
||||
cy.visit(`/projects/${projectId}`);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('should add a role', () => {
|
||||
cy.get('[data-e2e="sidenav-element-roles"]').click();
|
||||
cy.get('[data-e2e="add-new-role"]').click();
|
||||
cy.get('[formcontrolname="key"]').type(testRoleName);
|
||||
cy.get('[formcontrolname="displayName"]').type('e2eroleundertestdisplay');
|
||||
cy.get('[formcontrolname="group"]').type('e2eroleundertestgroup');
|
||||
cy.get('[data-e2e="save-button"]').click();
|
||||
cy.shouldConfirmSuccess();
|
||||
cy.contains('tr', testRoleName);
|
||||
});
|
||||
|
||||
it('should add a project grant', () => {
|
||||
const rowSelector = `tr:contains(${testRoleName})`;
|
||||
|
||||
cy.get('[data-e2e="sidenav-element-projectgrants"]').click();
|
||||
cy.get('[data-e2e="create-project-grant-button"]').click();
|
||||
cy.get('[data-e2e="add-org-input"]').type(defaultOrg);
|
||||
cy.get('mat-option').contains(defaultOrg).click();
|
||||
cy.get('button').should('be.enabled');
|
||||
cy.get('[data-e2e="project-grant-continue"]').first().click();
|
||||
cy.get(rowSelector).find('input').click({ force: true });
|
||||
cy.get('[data-e2e="save-project-grant-button"]').click();
|
||||
cy.contains('tr', defaultOrg);
|
||||
cy.contains('tr', testRoleName);
|
||||
});
|
||||
});
|
||||
|
||||
describe('edit project', () => {
|
||||
beforeEach('ensure it exists', () => {
|
||||
cy.get<Context>('@ctx').then((ctx) => {
|
||||
ensureProjectExists(ctx.api, testProjectNameDelete);
|
||||
ensureProjectExists(ctx.api, testProjectNameDelete).as('projectId');
|
||||
cy.visit(`/projects`);
|
||||
});
|
||||
});
|
||||
|
Loading…
x
Reference in New Issue
Block a user