Skip to content

Commit 2b0e009

Browse files
feat: angular migration- groups
Signed-off-by: aditya.goyal <aditya.goyal@graviteesource.com> feat: admin can require user groups to be added in applications Signed-off-by: aditya.goyal <aditya.goyal@graviteesource.com> feat: resolved review comments Signed-off-by: aditya.goyal <aditya.goyal@graviteesource.com>
1 parent 7230c4c commit 2b0e009

File tree

60 files changed

+3734
-1783
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

60 files changed

+3734
-1783
lines changed

gravitee-apim-console-webui/src/app.module.ajs.ts

-9
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,6 @@ import PlatformLogsComponentAjs from './management/analytics/logs/platform-logs.
112112
import PlatformLogComponentAjs from './management/analytics/logs/platform-log.component.ajs';
113113

114114
import CategoryService from './services/category.service';
115-
import DialogAddGroupMemberController from './management/settings/groups/group/addMemberDialog.controller';
116115
import SubscriptionService from './services/subscription.service';
117116
import EmptyStateDirective from './components/emptystate/emptystate.directive';
118117
import TagService from './services/tag.service';
@@ -147,9 +146,6 @@ import { ApiAuditComponentAjs } from './management/api/audit/general/audit.compo
147146
import AuditComponent from './components/audit/audit.component';
148147
// Configuration
149148
import PortalSettingsService from './services/portalSettings.service';
150-
// Groups
151-
import GroupsComponentAjs from './management/settings/groups/groups.component.ajs';
152-
import GroupComponentAjs from './management/settings/groups/group/group.component.ajs';
153149
import GroupService from './services/group.service';
154150
// Dictionaries
155151
import DictionaryService from './services/dictionary.service';
@@ -227,7 +223,6 @@ import { ApiAlertsDashboardComponentAjs } from './management/api/analytics/alert
227223

228224
import { markedHighlight } from 'marked-highlight';
229225
import { downgradeInjectable } from '@angular/upgrade/static';
230-
import DialogTransferOwnershipController from './management/settings/groups/group/transferOwnershipDialog.controller';
231226
import ApiKeysComponent from './management/application/components/api-key/api-keys.component';
232227
import ApiKeysController from './management/application/components/api-key/api-keys.controller';
233228
import { IfMatchEtagInterceptor } from './shared/interceptors/if-match-etag.interceptor';
@@ -436,10 +431,6 @@ graviteeManagementModule.component('analyticsDashboardComponentAjs', AnalyticsDa
436431
graviteeManagementModule.component('gvAlertDashboard', AlertsDashboardComponent);
437432
graviteeManagementModule.component('alertsActivityComponentAjs', AlertsActivityComponentAjs);
438433
graviteeManagementModule.component('apiAlertsDashboardComponentAjs', ApiAlertsDashboardComponentAjs);
439-
graviteeManagementModule.component('settingsGroupsAjs', GroupsComponentAjs);
440-
graviteeManagementModule.component('settingsGroupEditAjs', GroupComponentAjs);
441-
graviteeManagementModule.controller('DialogAddGroupMemberController', DialogAddGroupMemberController);
442-
graviteeManagementModule.controller('DialogTransferOwnershipController', DialogTransferOwnershipController);
443434
graviteeManagementModule.controller('FileChooserDialogController', FileChooserDialogController);
444435
graviteeManagementModule.controller('DialogConfirmController', DialogConfirmController);
445436
graviteeManagementModule.controller('DialogConfirmAndValidateController', DialogConfirmAndValidateController);

gravitee-apim-console-webui/src/entities/application/CreateApplication.ts

+1
Original file line numberDiff line numberDiff line change
@@ -22,4 +22,5 @@ export interface CreateApplication {
2222
domain?: string;
2323
type?: string;
2424
settings?: ApplicationSettings;
25+
groups?: string[];
2526
}

gravitee-apim-console-webui/src/entities/consoleSettings.ts

+5
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ export interface ConsoleSettings {
3333
trialInstance?: ConsoleSettingsTrialInstance;
3434
federation?: ConsoleSettingsFederation;
3535
cloudHosted?: ConsoleSettingsCloudHosted;
36+
userGroup?: ConsoleSettingsUserGroup;
3637
}
3738

3839
export interface ConsoleSettingsEmail {
@@ -187,3 +188,7 @@ export interface ConsoleSettingsFederation {
187188
export interface ConsoleSettingsCloudHosted {
188189
enabled?: boolean;
189190
}
191+
192+
interface ConsoleSettingsUserGroup {
193+
required: { enabled: boolean };
194+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
/*
2+
* Copyright (C) 2015 The Gravitee team (http://gravitee.io)
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
export interface Invitation {
18+
id?: string;
19+
reference_type?: string;
20+
reference_id: string;
21+
email: string;
22+
api_role?: string;
23+
application_role?: string;
24+
}

gravitee-apim-console-webui/src/index.scss

-1
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,6 @@
4242
@import 'management/api/api';
4343
@import 'management/analytics';
4444
@import 'management/settings/portal-theme/portal-theme';
45-
@import 'management/settings/groups/group/group';
4645
@import 'management/datatable';
4746
@import 'management/forms';
4847
@import 'management/stepper';

gravitee-apim-console-webui/src/management/application/creation/application-creation.component.spec.ts

+4
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,7 @@ describe('ApplicationCreationComponent', () => {
6868
name: 'name',
6969
description: 'description',
7070
domain: 'domain',
71+
groups: [],
7172
settings: {
7273
app: {
7374
client_id: 'appClientId',
@@ -97,6 +98,7 @@ describe('ApplicationCreationComponent', () => {
9798
name: 'name',
9899
description: 'description',
99100
domain: 'domain',
101+
groups: [],
100102
settings: {
101103
oauth: {
102104
additional_client_metadata: {},
@@ -128,6 +130,7 @@ describe('ApplicationCreationComponent', () => {
128130
name: 'name',
129131
description: 'description',
130132
domain: 'domain',
133+
groups: [],
131134
settings: {
132135
oauth: {
133136
additional_client_metadata: {},
@@ -166,6 +169,7 @@ describe('ApplicationCreationComponent', () => {
166169
name: 'name',
167170
description: 'description',
168171
domain: 'domain',
172+
groups: [],
169173
settings: {
170174
app: {
171175
client_id: 'appClientId',

gravitee-apim-console-webui/src/management/application/creation/application-creation.component.ts

+24-2
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
*/
1616

1717
import { CommonModule } from '@angular/common';
18-
import { Component, ChangeDetectionStrategy, DestroyRef, inject } from '@angular/core';
18+
import { ChangeDetectionStrategy, Component, DestroyRef, inject, OnInit } from '@angular/core';
1919
import { MatCardModule } from '@angular/material/card';
2020
import { map, tap } from 'rxjs/operators';
2121
import { FormControl, FormGroup, ReactiveFormsModule, Validators } from '@angular/forms';
@@ -30,6 +30,7 @@ import { ApplicationTypesService } from '../../../services-ngx/application-types
3030
import { ApplicationService } from '../../../services-ngx/application.service';
3131
import { SnackBarService } from '../../../services-ngx/snack-bar.service';
3232
import { toDictionary } from '../../../util/gio-form-header.util';
33+
import { ConsoleSettingsService } from '../../../services-ngx/console-settings.service';
3334

3435
const TYPES_INFOS = {
3536
SIMPLE: {
@@ -67,7 +68,7 @@ const TYPES_INFOS = {
6768
styleUrls: ['./application-creation.component.scss'],
6869
templateUrl: './application-creation.component.html',
6970
})
70-
export class ApplicationCreationComponent {
71+
export class ApplicationCreationComponent implements OnInit {
7172
private destroyRef = inject(DestroyRef);
7273
private isCreating = false;
7374

@@ -84,6 +85,7 @@ export class ApplicationCreationComponent {
8485
oauthGrantTypes: new FormControl(),
8586
oauthRedirectUris: new FormControl([]),
8687
additionalClientMetadata: new FormControl([]),
88+
groups: new FormControl([]),
8789
});
8890

8991
public applicationTypes$ = this.applicationTypesService.getEnabledApplicationTypes().pipe(
@@ -111,8 +113,13 @@ export class ApplicationCreationComponent {
111113
private readonly snackBarService: SnackBarService,
112114
private readonly activatedRoute: ActivatedRoute,
113115
private readonly router: Router,
116+
private readonly settingsService: ConsoleSettingsService,
114117
) {}
115118

119+
ngOnInit(): void {
120+
this.setUserGroupRequiredValidator();
121+
}
122+
116123
onSubmit() {
117124
if (this.applicationFormGroup.invalid || this.isCreating === true) {
118125
return;
@@ -125,6 +132,7 @@ export class ApplicationCreationComponent {
125132
name: applicationPayload.name,
126133
description: applicationPayload.description,
127134
domain: applicationPayload.domain,
135+
groups: applicationPayload.groups,
128136
settings: {
129137
...(applicationPayload.type === 'SIMPLE'
130138
? {
@@ -158,4 +166,18 @@ export class ApplicationCreationComponent {
158166
},
159167
});
160168
}
169+
170+
private setUserGroupRequiredValidator() {
171+
this.settingsService
172+
.get()
173+
.pipe(
174+
tap((consoleSettings) => {
175+
if (consoleSettings.userGroup.required.enabled) {
176+
this.applicationFormGroup.controls.groups?.setValidators(Validators.required);
177+
}
178+
}),
179+
takeUntilDestroyed(this.destroyRef),
180+
)
181+
.subscribe();
182+
}
161183
}

gravitee-apim-console-webui/src/management/application/creation/components/application-creation-form.component.html

+10
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,16 @@
5050
<mat-label>Domain</mat-label>
5151
</mat-form-field>
5252

53+
<mat-form-field>
54+
<mat-label>Select Groups</mat-label>
55+
<mat-hint>Select user groups to add to the application</mat-hint>
56+
<mat-select formControlName="groups" multiple>
57+
@for (group of groupsList | async; track group) {
58+
<mat-option [value]="group.id">{{ group.name }}</mat-option>
59+
}
60+
</mat-select>
61+
</mat-form-field>
62+
5363
<h3 class="form__securityTitle">Security</h3>
5464
@if (applicationTypes.length === 0) {
5565
<gio-banner-warning>No application type available, please check Client Registration configuration.</gio-banner-warning>

gravitee-apim-console-webui/src/management/application/creation/components/application-creation-form.component.ts

+23-5
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
* limitations under the License.
1515
*/
1616
import { CommonModule } from '@angular/common';
17-
import { Component, OnInit, inject, DestroyRef, Input } from '@angular/core';
17+
import { Component, DestroyRef, inject, Input, OnInit } from '@angular/core';
1818
import { FormControl, FormGroup, ReactiveFormsModule, Validators } from '@angular/forms';
1919
import { MatFormFieldModule } from '@angular/material/form-field';
2020
import { MatInputModule } from '@angular/material/input';
@@ -28,11 +28,14 @@ import {
2828
Header,
2929
} from '@gravitee/ui-particles-angular';
3030
import { MatRadioModule } from '@angular/material/radio';
31-
import { filter, map, share, startWith, tap } from 'rxjs/operators';
31+
import { filter, map, share, startWith, switchMap, tap } from 'rxjs/operators';
3232
import { MatSelectModule } from '@angular/material/select';
33-
import { Observable } from 'rxjs';
33+
import { BehaviorSubject, Observable, of } from 'rxjs';
34+
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
3435

3536
import { ApplicationType } from '../../../../entities/application-type/ApplicationType';
37+
import { GroupService } from '../../../../services-ngx/group.service';
38+
import { Group } from '../../../../entities/group/group';
3639

3740
export type ApplicationForm = {
3841
name: FormControl<string>;
@@ -48,6 +51,7 @@ export type ApplicationForm = {
4851
oauthRedirectUris: FormControl<string[]>;
4952

5053
additionalClientMetadata: FormControl<Header[]>;
54+
groups: FormControl<string[]>;
5155
};
5256

5357
export type ApplicationCreationFormApplicationType = ApplicationType & {
@@ -77,8 +81,6 @@ export type ApplicationCreationFormApplicationType = ApplicationType & {
7781
templateUrl: './application-creation-form.component.html',
7882
})
7983
export class ApplicationCreationFormComponent implements OnInit {
80-
private destroyRef = inject(DestroyRef);
81-
8284
@Input({ required: true })
8385
public applicationTypes: ApplicationCreationFormApplicationType[];
8486

@@ -92,8 +94,16 @@ export class ApplicationCreationFormComponent implements OnInit {
9294
allowedGrantTypesVM: { value: string; label: string; disabled: boolean }[];
9395
}
9496
>;
97+
groupsList: Observable<Group[]> = of([]);
98+
99+
private refreshGroups = new BehaviorSubject<Group[]>([]);
100+
private destroyRef: DestroyRef = inject(DestroyRef);
101+
102+
constructor(private readonly groupService: GroupService) {}
95103

96104
ngOnInit() {
105+
this.initializeGroups();
106+
97107
this.applicationType$ = this.applicationFormGroup.get('type').valueChanges.pipe(
98108
startWith(this.applicationFormGroup.get('type').value),
99109
filter((typeSelected) => !!typeSelected),
@@ -133,4 +143,12 @@ export class ApplicationCreationFormComponent implements OnInit {
133143
share(),
134144
);
135145
}
146+
147+
private initializeGroups() {
148+
this.groupsList = this.refreshGroups.pipe(
149+
switchMap((_) => this.groupService.list()),
150+
map((_) => _.sort((a, b) => a.name.localeCompare(b.name))),
151+
takeUntilDestroyed(this.destroyRef),
152+
);
153+
}
136154
}

gravitee-apim-console-webui/src/management/settings/groups/_groups.scss

-3
This file was deleted.

gravitee-apim-console-webui/src/management/settings/groups/group/_group.scss

-23
This file was deleted.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
<!--
2+
3+
Copyright (C) 2015 The Gravitee team (http://gravitee.io)
4+
5+
Licensed under the Apache License, Version 2.0 (the "License");
6+
you may not use this file except in compliance with the License.
7+
You may obtain a copy of the License at
8+
9+
http://www.apache.org/licenses/LICENSE-2.0
10+
11+
Unless required by applicable law or agreed to in writing, software
12+
distributed under the License is distributed on an "AS IS" BASIS,
13+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
See the License for the specific language governing permissions and
15+
limitations under the License.
16+
17+
-->
18+
<h2 mat-dialog-title>Add Members</h2>
19+
<mat-dialog-content>
20+
<form [formGroup]="addMemberForm" class="add-member__form">
21+
<mat-form-field aria-hidden="false" aria-label="Select default API role">
22+
<mat-label>Default API Role</mat-label>
23+
<mat-select formControlName="defaultAPIRole" (selectionChange)="onAPIRoleChange()">
24+
@for (role of defaultAPIRoles; track role.id) {
25+
<mat-option [value]="role.name" [disabled]="disabledAPIRoles().has(role.id)">{{ role.name }}</mat-option>
26+
}
27+
</mat-select>
28+
</mat-form-field>
29+
30+
<mat-form-field aria-hidden="false" aria-label="Select default application role">
31+
<mat-label>Default Application Role</mat-label>
32+
<mat-select formControlName="defaultApplicationRole">
33+
@for (role of defaultApplicationRoles; track role.id) {
34+
<mat-option [value]="role.name" [disabled]="role.system">{{ role.name }}</mat-option>
35+
}
36+
</mat-select>
37+
</mat-form-field>
38+
39+
<mat-form-field aria-hidden="false" aria-label="Select default integration role">
40+
<mat-label>Default Integration Role</mat-label>
41+
<mat-select formControlName="defaultIntegrationRole">
42+
@for (role of defaultIntegrationRoles; track role.id) {
43+
<mat-option [value]="role.name" [disabled]="role.system">{{ role.name }}</mat-option>
44+
}
45+
</mat-select>
46+
</mat-form-field>
47+
48+
<mat-form-field appearance="outline">
49+
<mat-label>Search Users</mat-label>
50+
<input aria-label="Search users" matInput formControlName="searchTerm" [matAutocomplete]="auto" />
51+
<mat-autocomplete #auto="matAutocomplete" (optionSelected)="selectUser($event)">
52+
@for (user of filteredUsers$ | async; track user.id) {
53+
<mat-option [value]="user">
54+
{{ user.displayName }}
55+
</mat-option>
56+
}
57+
</mat-autocomplete>
58+
<mat-hint>Search users to add to the group</mat-hint>
59+
</mat-form-field>
60+
61+
<mat-chip-set>
62+
@for (user of selectedUsers; track user.id) {
63+
<mat-chip [removable]="true" (removed)="deselectUser(user)">
64+
{{ user.displayName }}
65+
<mat-icon matChipRemove>cancel</mat-icon>
66+
</mat-chip>
67+
}
68+
</mat-chip-set>
69+
</form>
70+
</mat-dialog-content>
71+
72+
<mat-dialog-actions align="end">
73+
<button mat-raised-button color="primary" [disabled]="disableSubmit()" (click)="submit()">Add Users</button>
74+
<button mat-raised-button mat-dialog-close>Cancel</button>
75+
</mat-dialog-actions>

0 commit comments

Comments
 (0)