Skip to content

Commit 24b2b23

Browse files
authored
[ACS-9980] Add the option to provide custom user profile sections (#4859)
* [ACS-9980] Add the option to provide custom user profile sections * [ACS-9980] Cr fixes * [ACS-9980] Formatting fix
1 parent 2d8354b commit 24b2b23

File tree

12 files changed

+323
-161
lines changed

12 files changed

+323
-161
lines changed

extension.schema.json

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -743,6 +743,20 @@
743743
"type": "string"
744744
}
745745
}
746+
},
747+
"userProfileSection": {
748+
"type": "object",
749+
"required": ["id", "title"],
750+
"properties": {
751+
"id": {
752+
"description": "Unique identifier.",
753+
"type": "string"
754+
},
755+
"component": {
756+
"description": "Custom component id to display inside the section",
757+
"type": "string"
758+
}
759+
}
746760
}
747761
},
748762

@@ -1013,6 +1027,12 @@
10131027
"items": { "$ref": "#/definitions/badge" },
10141028
"minItems": 1
10151029
},
1030+
"userProfileSections": {
1031+
"description": "List of custom sections to display in the user profile component",
1032+
"type": "array",
1033+
"items": { "$ref": "#/definitions/userProfileSection" },
1034+
"minItems": 1
1035+
},
10161036
"search": {
10171037
"description": "aca search extension",
10181038
"type": "array",

projects/aca-content/assets/i18n/en.json

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -463,7 +463,12 @@
463463
"COLLAPSE_NAVIGATION": "Collapse navigation menu",
464464
"OPTIONS_SETTINGS": "Options and settings",
465465
"MY_PROFILE": "My profile",
466-
"EXPAND_NAVIGATION": "Expand navigation menu"
466+
"EXPAND_NAVIGATION": "Expand navigation menu",
467+
"EXPAND_SECTION": "Expand section",
468+
"COLLAPSE_SECTION": "Collapse section",
469+
"EDIT": "Edit",
470+
"CANCEL": "Cancel",
471+
"SAVE": "Save"
467472
},
468473
"FOLDER_INFO": {
469474
"ICON": "Folder Icon",

projects/aca-content/src/lib/aca-content.module.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -166,7 +166,8 @@ import { SaveSearchSidenavComponent } from './components/search/search-save/side
166166
'app.canShowLogout': rules.canShowLogout,
167167
'app.isContentServiceEnabled': rules.isContentServiceEnabled,
168168
'app.areTagsEnabled': rules.areTagsEnabled,
169-
'app.areCategoriesEnabled': rules.areCategoriesEnabled
169+
'app.areCategoriesEnabled': rules.areCategoriesEnabled,
170+
'app.isSSOEnabled': rules.isSSOEnabled
170171
}
171172
})
172173
]

projects/aca-content/src/lib/components/view-profile/view-profile.component.html

Lines changed: 176 additions & 78 deletions
Large diffs are not rendered by default.

projects/aca-content/src/lib/components/view-profile/view-profile.component.scss

Lines changed: 15 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ app-view-profile {
4343
}
4444

4545
.app-profile-general-icon {
46+
padding: 0 0.5rem 0 1rem;
4647
cursor: pointer;
4748
}
4849

@@ -52,7 +53,16 @@ app-view-profile {
5253

5354
.app-profile-general {
5455
display: flex;
55-
padding-left: 1rem;
56+
align-items: center;
57+
width: 100%;
58+
59+
.app-general-edit {
60+
color: var(--adf-theme-foreground-text-color-054);
61+
}
62+
63+
.app-general-cancel-btn {
64+
color: var(--adf-metadata-action-button-clear-color);
65+
}
5666
}
5767

5868
.app-profile-general-bottom-radius {
@@ -62,48 +72,12 @@ app-view-profile {
6272

6373
.app-profile-general-section {
6474
display: flex;
65-
width: 60%;
66-
padding-top: 1rem;
67-
cursor: pointer;
68-
}
69-
70-
.app-general-title {
71-
margin-left: 0.6rem;
72-
margin-top: 4px;
73-
letter-spacing: 0.5px;
74-
}
75-
76-
.app-general-edit-btn {
77-
width: 60%;
78-
text-align: end;
79-
80-
.app-general-edit {
81-
background: var(--theme-grey-text-background-color);
82-
height: 30px;
83-
margin: 1rem;
84-
}
85-
86-
.app-general-cancel-btn {
87-
height: 30px;
88-
margin: 1rem;
89-
margin-left: 0.5rem;
90-
background-color: var(--theme-grey-text-background-color);
91-
padding-top: 0.25px;
92-
}
93-
94-
.app-general-save-btn {
95-
width: 75px;
96-
height: 30px;
97-
margin: 1rem;
98-
margin-left: 0.5rem;
99-
color: var(--theme-white-background);
100-
background-color: var(--theme-blue-button-color);
101-
font-weight: 600;
102-
}
75+
align-items: center;
76+
width: 100%;
10377
}
10478

10579
.app-divider {
106-
border-top-width: 2px;
80+
border-top-width: 1px;
10781
border-top-color: var(--theme-grey-background-color);
10882
padding-left: -1px;
10983
padding-right: 1px;
@@ -116,10 +90,6 @@ app-view-profile {
11690
box-shadow: 0 0 2px var(--theme-blue-button-color);
11791
}
11892

119-
.app-general-edit:hover {
120-
background: var(--theme-grey-hover-background-color);
121-
}
122-
12393
.app-general-dropdown-divider {
12494
border-top-color: var(--theme-grey-divider-color);
12595
}
@@ -183,7 +153,7 @@ app-view-profile {
183153
}
184154

185155
.app-profile-contact-row {
186-
margin: 2rem 0 5rem 2rem;
156+
margin: 2rem 0 0 2rem;
187157
width: 70%;
188158
border: 1px solid var(--theme-grey-background-color);
189159
border-radius: 1rem;

projects/aca-content/src/lib/components/view-profile/view-profile.component.spec.ts

Lines changed: 20 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -25,20 +25,21 @@
2525
import { TestBed, ComponentFixture } from '@angular/core/testing';
2626
import { ViewProfileComponent } from './view-profile.component';
2727
import { AppTestingModule } from '../../testing/app-testing.module';
28-
import { By } from '@angular/platform-browser';
2928
import { Router } from '@angular/router';
30-
import { BehaviorSubject, Subject } from 'rxjs';
31-
import { AppService } from '@alfresco/aca-shared';
29+
import { BehaviorSubject, of, Subject } from 'rxjs';
30+
import { AppExtensionService, AppService } from '@alfresco/aca-shared';
3231
import { UnitTestingUtils } from '@alfresco/adf-core';
3332
import { TestbedHarnessEnvironment } from '@angular/cdk/testing/testbed';
3433
import { HarnessLoader } from '@angular/cdk/testing';
34+
import { DynamicExtensionComponent } from '@alfresco/adf-extensions';
3535

3636
describe('ViewProfileComponent', () => {
3737
let fixture: ComponentFixture<ViewProfileComponent>;
3838
let component: ViewProfileComponent;
3939
let router: Router;
4040
let unitTestingUtils: UnitTestingUtils;
4141
let loader: HarnessLoader;
42+
let appExtensionService: AppExtensionService;
4243

4344
const appServiceMock = {
4445
toggleAppNavBar$: new Subject(),
@@ -61,6 +62,7 @@ describe('ViewProfileComponent', () => {
6162
router = TestBed.inject(Router);
6263
loader = TestbedHarnessEnvironment.loader(fixture);
6364
unitTestingUtils = new UnitTestingUtils(fixture.debugElement, loader);
65+
appExtensionService = TestBed.inject(AppExtensionService);
6466
router.initialNavigation();
6567
});
6668

@@ -71,7 +73,7 @@ describe('ViewProfileComponent', () => {
7173

7274
it('should toggle the appService toggleAppNavBar$ Subject', () => {
7375
spyOn(appServiceMock.toggleAppNavBar$, 'next');
74-
component.toggleClick();
76+
component.toggleNavigationMenu();
7577
expect(appServiceMock.toggleAppNavBar$.next).toHaveBeenCalled();
7678
});
7779

@@ -156,8 +158,7 @@ describe('ViewProfileComponent', () => {
156158
component.generalSectionDropdown = false;
157159
fixture.detectChanges();
158160

159-
const generalToggleIcon = fixture.debugElement.query(By.css('#toggle-general-dropdown'));
160-
generalToggleIcon.triggerEventHandler('click', null);
161+
unitTestingUtils.clickByCSS('#general-dropdown button');
161162

162163
expect(component.toggleGeneralDropdown).toHaveBeenCalled();
163164
expect(component.generalSectionButtonsToggle).toBe(true);
@@ -168,8 +169,7 @@ describe('ViewProfileComponent', () => {
168169
component.contactSectionDropdown = false;
169170
fixture.detectChanges();
170171

171-
const contactToggleIcon = fixture.debugElement.query(By.css('#toggle-contact-dropdown'));
172-
contactToggleIcon.triggerEventHandler('click', null);
172+
unitTestingUtils.clickByCSS('#contact-dropdown button');
173173

174174
expect(component.toggleContactDropdown).toHaveBeenCalled();
175175
expect(component.contactSectionButtonsToggle).toBe(true);
@@ -179,12 +179,10 @@ describe('ViewProfileComponent', () => {
179179
spyOn(component, 'toggleGeneralButtons').and.callThrough();
180180
fixture.detectChanges();
181181

182-
const generalEditButton = fixture.debugElement.query(By.css('#general-edit-button'));
183-
generalEditButton.triggerEventHandler('click', null);
182+
unitTestingUtils.clickByCSS('#general-dropdown .app-general-edit');
184183
fixture.detectChanges();
185184

186-
const generalCancelButton = fixture.debugElement.query(By.css('#general-cancel-button'));
187-
generalCancelButton.triggerEventHandler('click', null);
185+
unitTestingUtils.clickByCSS('#general-dropdown .app-general-cancel-btn');
188186

189187
expect(component.toggleGeneralButtons).toHaveBeenCalledTimes(2);
190188
});
@@ -193,12 +191,10 @@ describe('ViewProfileComponent', () => {
193191
spyOn(component, 'toggleContactButtons').and.callThrough();
194192
fixture.detectChanges();
195193

196-
const contactEditButton = fixture.debugElement.query(By.css('#contact-edit-button'));
197-
contactEditButton.triggerEventHandler('click', null);
194+
unitTestingUtils.clickByCSS('#contact-dropdown .app-general-edit');
198195
fixture.detectChanges();
199196

200-
const contactCancelButton = fixture.debugElement.query(By.css('#contact-cancel-button'));
201-
contactCancelButton.triggerEventHandler('click', null);
197+
unitTestingUtils.clickByCSS('#contact-dropdown .app-general-cancel-btn');
202198

203199
expect(component.toggleContactButtons).toHaveBeenCalledTimes(2);
204200
});
@@ -209,4 +205,12 @@ describe('ViewProfileComponent', () => {
209205

210206
expect(router.navigate).toHaveBeenCalledWith(['/personal-files'], { replaceUrl: true });
211207
});
208+
209+
it('should render additional user profile sections if provided', () => {
210+
spyOn(appExtensionService, 'getUserProfileSections').and.returnValue(of([{ id: 'test-section' }]));
211+
fixture.detectChanges();
212+
213+
expect(component.sections.length).toBe(1);
214+
expect(unitTestingUtils.getByDirective(DynamicExtensionComponent)).toBeDefined();
215+
});
212216
});

projects/aca-content/src/lib/components/view-profile/view-profile.component.ts

Lines changed: 24 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -27,18 +27,28 @@ import { PeopleApi, Person } from '@alfresco/js-api';
2727
import { Component, OnInit, ViewEncapsulation } from '@angular/core';
2828
import { FormControl, FormGroup, ReactiveFormsModule, Validators } from '@angular/forms';
2929
import { Router } from '@angular/router';
30-
import { Observable, throwError } from 'rxjs';
31-
import { AppService } from '@alfresco/aca-shared';
30+
import { Observable, take, throwError } from 'rxjs';
31+
import { AppExtensionService, AppService, UserProfileSection } from '@alfresco/aca-shared';
3232
import { CommonModule } from '@angular/common';
3333
import { MatButtonModule } from '@angular/material/button';
3434
import { MatIconModule } from '@angular/material/icon';
3535
import { TranslatePipe } from '@ngx-translate/core';
3636
import { MatDividerModule } from '@angular/material/divider';
3737
import { MatFormFieldModule } from '@angular/material/form-field';
3838
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
39+
import { DynamicExtensionComponent } from '@alfresco/adf-extensions';
3940

4041
@Component({
41-
imports: [CommonModule, TranslatePipe, ReactiveFormsModule, MatButtonModule, MatIconModule, MatDividerModule, MatFormFieldModule],
42+
imports: [
43+
CommonModule,
44+
TranslatePipe,
45+
ReactiveFormsModule,
46+
MatButtonModule,
47+
MatIconModule,
48+
MatDividerModule,
49+
MatFormFieldModule,
50+
DynamicExtensionComponent
51+
],
4252
selector: 'app-view-profile',
4353
templateUrl: './view-profile.component.html',
4454
styleUrls: ['./view-profile.component.scss'],
@@ -60,13 +70,15 @@ export class ViewProfileComponent implements OnInit {
6070
contactSectionDropdown = false;
6171
contactSectionButtonsToggle = true;
6272
appNavNarMode$: Observable<'collapsed' | 'expanded'>;
73+
sections: UserProfileSection[] = [];
6374

6475
constructor(
6576
private router: Router,
66-
apiService: AlfrescoApiService,
67-
private appService: AppService
77+
private readonly apiService: AlfrescoApiService,
78+
private readonly appService: AppService,
79+
private readonly extensionService: AppExtensionService
6880
) {
69-
this.peopleApi = new PeopleApi(apiService.getInstance());
81+
this.peopleApi = new PeopleApi(this.apiService.getInstance());
7082
this.appNavNarMode$ = appService.appNavNarMode$.pipe(takeUntilDestroyed());
7183
}
7284

@@ -81,9 +93,14 @@ export class ViewProfileComponent implements OnInit {
8193
.catch((error) => {
8294
throwError(error);
8395
});
96+
97+
this.extensionService
98+
.getUserProfileSections()
99+
.pipe(take(1))
100+
.subscribe((sections) => (this.sections = sections));
84101
}
85102

86-
toggleClick() {
103+
toggleNavigationMenu() {
87104
this.appService.toggleAppNavBar$.next();
88105
}
89106

@@ -112,10 +129,6 @@ export class ViewProfileComponent implements OnInit {
112129

113130
toggleGeneralDropdown() {
114131
this.generalSectionDropdown = !this.generalSectionDropdown;
115-
116-
if (!this.generalSectionDropdown) {
117-
this.generalSectionButtonsToggle = true;
118-
}
119132
}
120133

121134
toggleGeneralButtons() {
@@ -143,10 +156,6 @@ export class ViewProfileComponent implements OnInit {
143156

144157
toggleLoginDropdown() {
145158
this.loginSectionDropdown = !this.loginSectionDropdown;
146-
147-
if (!this.loginSectionDropdown) {
148-
this.loginSectionButtonsToggle = true;
149-
}
150159
}
151160

152161
toggleLoginButtons() {
@@ -161,10 +170,6 @@ export class ViewProfileComponent implements OnInit {
161170

162171
toggleContactDropdown() {
163172
this.contactSectionDropdown = !this.contactSectionDropdown;
164-
165-
if (!this.contactSectionDropdown) {
166-
this.contactSectionButtonsToggle = true;
167-
}
168173
}
169174

170175
toggleContactButtons() {

projects/aca-shared/rules/src/app.rules.spec.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1196,6 +1196,18 @@ describe('app.evaluators', () => {
11961196
expect(app.isSmartFolder(context)).toBeTrue();
11971197
});
11981198
});
1199+
1200+
describe('isSSOEnabled', () => {
1201+
it('should return true if sso is enabled', () => {
1202+
context.appConfig = { get: () => 'OAUTH' } as any;
1203+
expect(app.isSSOEnabled(context)).toBe(true);
1204+
});
1205+
1206+
it('should return false if sso is not enabled', () => {
1207+
context.appConfig = { get: () => 'basic' } as any;
1208+
expect(app.isSSOEnabled(context)).toBe(false);
1209+
});
1210+
});
11991211
});
12001212

12011213
describe('Versions compatibility', () => {

projects/aca-shared/rules/src/app.rules.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -560,3 +560,5 @@ export const canDisplayKnowledgeRetrievalButton = (context: AcaRuleContext): boo
560560
navigation.isRecentFiles(context) ||
561561
navigation.isFavorites(context) ||
562562
((navigation.isSearchResults(context) || navigation.isLibraryContent(context)) && !navigation.isLibraries(context)));
563+
564+
export const isSSOEnabled = (context: AcaRuleContext): boolean => context.appConfig.get('authType') === 'OAUTH';

projects/aca-shared/src/lib/models/types.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,3 +34,7 @@ export interface Badge extends Partial<Pick<ContentActionRef, 'component' | 'act
3434
icon: string;
3535
tooltip: string;
3636
}
37+
38+
export interface UserProfileSection extends Partial<Pick<ContentActionRef, 'component' | 'rules'>> {
39+
id: string;
40+
}

0 commit comments

Comments
 (0)