diff --git a/.github/workflows/pull-request.yml b/.github/workflows/pull-request.yml
index 3c23368e8..9e17bb15a 100644
--- a/.github/workflows/pull-request.yml
+++ b/.github/workflows/pull-request.yml
@@ -70,20 +70,13 @@ jobs:
unit-tests:
needs: [lint, build]
- name: "Unit tests: ${{ matrix.unit-tests.name }}"
+ name: "Unit tests"
runs-on: ubuntu-latest
- strategy:
- fail-fast: false
- matrix:
- unit-tests:
- - name: "aca-content"
- - name: "aca-shared"
steps:
- name: Checkout
uses: actions/checkout@v3
with:
fetch-depth: 0
-
- name: node
uses: actions/setup-node@v3
with:
diff --git a/app/src/app/app.component.html b/app/src/app/app.component.html
index 862e06c53..0680b43f9 100644
--- a/app/src/app/app.component.html
+++ b/app/src/app/app.component.html
@@ -1,2 +1 @@
-
{{ pageHeading | async | translate }}
diff --git a/app/src/app/app.components.ts b/app/src/app/app.components.ts
index 94d6e4003..9c6b90a6d 100644
--- a/app/src/app/app.components.ts
+++ b/app/src/app/app.components.ts
@@ -23,7 +23,7 @@
*/
import { Component, ViewEncapsulation } from '@angular/core';
-import { Observable, Subject } from 'rxjs';
+import { Subject } from 'rxjs';
import { AppService } from '@alfresco/aca-shared';
@Component({
@@ -34,10 +34,8 @@ import { AppService } from '@alfresco/aca-shared';
})
export class AppComponent {
onDestroy$: Subject = new Subject();
- pageHeading: Observable;
constructor(private appService: AppService) {
- this.pageHeading = this.appService.pageHeading$;
this.appService.init();
}
}
diff --git a/karma.conf.js b/karma.conf.js
index cfc277142..99002e4f8 100644
--- a/karma.conf.js
+++ b/karma.conf.js
@@ -58,7 +58,7 @@ module.exports = () => {
check: {
global: {
statements: 75,
- branches: 67,
+ branches: 65,
functions: 71,
lines: 74
}
diff --git a/projects/aca-content/src/lib/components/common/user-info/user-info.component.ts b/projects/aca-content/src/lib/components/common/user-info/user-info.component.ts
index 101c69a45..98d4a246a 100644
--- a/projects/aca-content/src/lib/components/common/user-info/user-info.component.ts
+++ b/projects/aca-content/src/lib/components/common/user-info/user-info.component.ts
@@ -27,8 +27,7 @@ import { CommonModule } from '@angular/common';
import { RouterModule } from '@angular/router';
import { MatMenuModule } from '@angular/material/menu';
import { TranslateModule } from '@ngx-translate/core';
-import { AppStore, getUserProfile } from '@alfresco/aca-shared/store';
-import { Store } from '@ngrx/store';
+import { UserProfileService } from '@alfresco/aca-shared';
@Component({
standalone: true,
@@ -39,6 +38,7 @@ import { Store } from '@ngrx/store';
encapsulation: ViewEncapsulation.None
})
export class UserInfoComponent {
- private store = inject>(Store);
- user$ = this.store.select(getUserProfile);
+ private userProfileService = inject(UserProfileService);
+
+ user$ = this.userProfileService.userProfile$;
}
diff --git a/projects/aca-content/src/lib/components/sidenav/user-menu/user-menu.component.ts b/projects/aca-content/src/lib/components/sidenav/user-menu/user-menu.component.ts
index 70f064a91..d01067113 100644
--- a/projects/aca-content/src/lib/components/sidenav/user-menu/user-menu.component.ts
+++ b/projects/aca-content/src/lib/components/sidenav/user-menu/user-menu.component.ts
@@ -28,9 +28,7 @@ import { CommonModule } from '@angular/common';
import { MatButtonModule } from '@angular/material/button';
import { TranslateModule } from '@ngx-translate/core';
import { MatMenuModule } from '@angular/material/menu';
-import { ToolbarMenuItemComponent } from '@alfresco/aca-shared';
-import { AppStore, getUserProfile } from '@alfresco/aca-shared/store';
-import { Store } from '@ngrx/store';
+import { ToolbarMenuItemComponent, UserProfileService } from '@alfresco/aca-shared';
@Component({
standalone: true,
@@ -42,8 +40,9 @@ import { Store } from '@ngrx/store';
host: { class: 'aca-user-menu' }
})
export class UserMenuComponent implements OnInit {
- private store = inject>(Store);
- user$ = this.store.select(getUserProfile);
+ private userProfileService = inject(UserProfileService);
+
+ user$ = this.userProfileService.userProfile$;
@Input()
actionRef: ContentActionRef;
diff --git a/projects/aca-content/src/lib/components/toolbar/toggle-join-library/toggle-join-library-button.component.ts b/projects/aca-content/src/lib/components/toolbar/toggle-join-library/toggle-join-library-button.component.ts
index 97f7ac0e8..220599163 100644
--- a/projects/aca-content/src/lib/components/toolbar/toggle-join-library/toggle-join-library-button.component.ts
+++ b/projects/aca-content/src/lib/components/toolbar/toggle-join-library/toggle-join-library-button.component.ts
@@ -22,17 +22,10 @@
* from Hyland Software. If not, see .
*/
-import {
- AppStore,
- SetSelectedNodesAction,
- SnackbarErrorAction,
- SnackbarInfoAction,
- getAppSelection,
- getUserProfile
-} from '@alfresco/aca-shared/store';
-import { AppHookService } from '@alfresco/aca-shared';
-import { ProfileState, SelectionState } from '@alfresco/adf-extensions';
-import { Component, ViewEncapsulation } from '@angular/core';
+import { AppStore, SetSelectedNodesAction, SnackbarErrorAction, SnackbarInfoAction, getAppSelection } from '@alfresco/aca-shared/store';
+import { AppHookService, UserProfileService } from '@alfresco/aca-shared';
+import { SelectionState } from '@alfresco/adf-extensions';
+import { Component, inject, ViewEncapsulation } from '@angular/core';
import { Store } from '@ngrx/store';
import { Observable } from 'rxjs';
import { LibraryMembershipDirective, LibraryMembershipErrorEvent, LibraryMembershipToggleEvent } from '@alfresco/adf-content-services';
@@ -64,12 +57,13 @@ import { MatIconModule } from '@angular/material/icon';
host: { class: 'app-toggle-join-library' }
})
export class ToggleJoinLibraryButtonComponent {
+ private userProfileService = inject(UserProfileService);
+
selection$: Observable;
- profile$: Observable;
+ profile$ = this.userProfileService.userProfile$;
constructor(private store: Store, private appHookService: AppHookService) {
this.selection$ = this.store.select(getAppSelection);
- this.profile$ = this.store.select(getUserProfile);
}
onToggleEvent(event: LibraryMembershipToggleEvent) {
diff --git a/projects/aca-content/src/lib/components/trashcan/trashcan.component.ts b/projects/aca-content/src/lib/components/trashcan/trashcan.component.ts
index d1b4cc7fb..31cdab994 100644
--- a/projects/aca-content/src/lib/components/trashcan/trashcan.component.ts
+++ b/projects/aca-content/src/lib/components/trashcan/trashcan.component.ts
@@ -22,10 +22,16 @@
* from Hyland Software. If not, see .
*/
-import { getUserProfile } from '@alfresco/aca-shared/store';
import { DocumentListPresetRef, DynamicColumnComponent } from '@alfresco/adf-extensions';
-import { Component, OnInit, ViewEncapsulation } from '@angular/core';
-import { ContextActionsDirective, PageComponent, PageLayoutComponent, PaginationDirective, ToolbarComponent } from '@alfresco/aca-shared';
+import { Component, inject, OnInit, ViewEncapsulation } from '@angular/core';
+import {
+ ContextActionsDirective,
+ PageComponent,
+ PageLayoutComponent,
+ PaginationDirective,
+ ToolbarComponent,
+ UserProfileService
+} from '@alfresco/aca-shared';
import { CommonModule } from '@angular/common';
import { TranslateModule } from '@ngx-translate/core';
import { DocumentListModule } from '@alfresco/adf-content-services';
@@ -52,7 +58,9 @@ import { DocumentListDirective } from '../../directives/document-list.directive'
encapsulation: ViewEncapsulation.None
})
export class TrashcanComponent extends PageComponent implements OnInit {
- user$ = this.store.select(getUserProfile);
+ private userProfileService = inject(UserProfileService);
+
+ user$ = this.userProfileService.userProfile$;
columns: DocumentListPresetRef[] = [];
ngOnInit() {
diff --git a/projects/aca-content/src/lib/store/reducers/app.reducer.ts b/projects/aca-content/src/lib/store/reducers/app.reducer.ts
index 73cf64ef7..192d8398d 100644
--- a/projects/aca-content/src/lib/store/reducers/app.reducer.ts
+++ b/projects/aca-content/src/lib/store/reducers/app.reducer.ts
@@ -92,32 +92,7 @@ export function appReducer(state: AppState = INITIAL_APP_STATE, action: Action):
}
function updateUser(state: AppState, action: SetUserProfileAction): AppState {
- const newState = { ...state };
- const user = action.payload.person;
- const groups = [...(action.payload.groups || [])];
-
- const id = user.id;
- const firstName = user.firstName || '';
- const lastName = user.lastName || '';
- const userName = `${firstName} ${lastName}`;
- const initials = [firstName[0], lastName[0]].join('');
- const email = user.email;
-
- const capabilities = user.capabilities;
- const isAdmin = capabilities ? capabilities.isAdmin : true;
-
- newState.user = {
- firstName,
- lastName,
- userName,
- initials,
- isAdmin,
- id,
- groups,
- email
- };
-
- return newState;
+ return { ...state, user: { ...action.payload } };
}
function updateCurrentFolder(state: AppState, action: SetCurrentFolderAction) {
diff --git a/projects/aca-shared/src/lib/services/app.service.spec.ts b/projects/aca-shared/src/lib/services/app.service.spec.ts
index acedcac91..b3be7a396 100644
--- a/projects/aca-shared/src/lib/services/app.service.spec.ts
+++ b/projects/aca-shared/src/lib/services/app.service.spec.ts
@@ -26,20 +26,19 @@ import { AppService } from './app.service';
import { TestBed } from '@angular/core/testing';
import {
AuthenticationService,
- AppConfigService,
AlfrescoApiService,
PageTitleService,
AlfrescoApiServiceMock,
TranslationMock,
TranslationService,
- UserPreferencesService
+ UserPreferencesService,
+ NotificationService
} from '@alfresco/adf-core';
import { BehaviorSubject, Observable, of, Subject } from 'rxjs';
import { HttpClientModule } from '@angular/common/http';
import {
DiscoveryApiService,
FileUploadErrorEvent,
- GroupService,
SearchQueryBuilderService,
SharedLinksApiService,
UploadService
@@ -53,25 +52,26 @@ import { MatDialogModule } from '@angular/material/dialog';
import { TranslateModule } from '@ngx-translate/core';
import { Store } from '@ngrx/store';
import { ContentApiService } from './content-api.service';
-import { SetRepositoryInfoAction, SetUserProfileAction, SnackbarErrorAction } from '@alfresco/aca-shared/store';
-import { AppSettingsService } from '@alfresco/aca-shared';
+import { AppSettingsService, UserProfileService } from '@alfresco/aca-shared';
+import { MatSnackBarModule } from '@angular/material/snack-bar';
describe('AppService', () => {
let service: AppService;
let auth: AuthenticationService;
- let appConfig: AppConfigService;
let searchQueryBuilderService: SearchQueryBuilderService;
let uploadService: UploadService;
let store: Store;
let sharedLinksApiService: SharedLinksApiService;
let contentApi: ContentApiService;
- let groupService: GroupService;
let preferencesService: UserPreferencesService;
let appSettingsService: AppSettingsService;
+ let userProfileService: UserProfileService;
+ let notificationService: NotificationService;
+ let loadUserProfileSpy: jasmine.Spy;
beforeEach(() => {
TestBed.configureTestingModule({
- imports: [CommonModule, HttpClientModule, TranslateModule.forRoot(), RouterTestingModule.withRoutes([]), MatDialogModule],
+ imports: [CommonModule, HttpClientModule, TranslateModule.forRoot(), RouterTestingModule.withRoutes([]), MatDialogModule, MatSnackBarModule],
providers: [
SearchQueryBuilderService,
provideMockStore({}),
@@ -118,31 +118,18 @@ describe('AppService', () => {
});
appSettingsService = TestBed.inject(AppSettingsService);
- appConfig = TestBed.inject(AppConfigService);
auth = TestBed.inject(AuthenticationService);
searchQueryBuilderService = TestBed.inject(SearchQueryBuilderService);
uploadService = TestBed.inject(UploadService);
store = TestBed.inject(Store);
sharedLinksApiService = TestBed.inject(SharedLinksApiService);
contentApi = TestBed.inject(ContentApiService);
- groupService = TestBed.inject(GroupService);
+ spyOn(contentApi, 'getRepositoryInformation').and.returnValue(of({} as any));
service = TestBed.inject(AppService);
preferencesService = TestBed.inject(UserPreferencesService);
- });
-
- it('should be ready if [withCredentials] mode is used', (done) => {
- appConfig.config = {
- auth: {
- withCredentials: true
- }
- };
-
- const instance = TestBed.inject(AppService);
- expect(instance.withCredentials).toBeTruthy();
-
- instance.ready$.subscribe(() => {
- done();
- });
+ userProfileService = TestBed.inject(UserProfileService);
+ loadUserProfileSpy = spyOn(userProfileService, 'loadUserProfile').and.returnValue(Promise.resolve({} as any));
+ notificationService = TestBed.inject(NotificationService);
});
it('should be ready after login', async () => {
@@ -170,45 +157,46 @@ describe('AppService', () => {
});
it('should raise notification on share link error', () => {
+ const showError = spyOn(notificationService, 'showError').and.stub();
spyOn(store, 'select').and.returnValue(of(''));
service.init();
- const dispatch = spyOn(store, 'dispatch');
sharedLinksApiService.error.next({ message: 'Error Message', statusCode: 1 });
- expect(dispatch).toHaveBeenCalledWith(new SnackbarErrorAction('Error Message'));
+ expect(showError).toHaveBeenCalledWith('Error Message');
});
it('should raise notification on upload error', async () => {
spyOn(store, 'select').and.returnValue(of(''));
service.init();
- const dispatch = spyOn(store, 'dispatch');
+
+ const showError = spyOn(notificationService, 'showError').and.stub();
uploadService.fileUploadError.next(new FileUploadErrorEvent(null, { status: 403 }));
- expect(dispatch).toHaveBeenCalledWith(new SnackbarErrorAction('APP.MESSAGES.UPLOAD.ERROR.403'));
- dispatch.calls.reset();
+ expect(showError).toHaveBeenCalledWith('APP.MESSAGES.UPLOAD.ERROR.403');
+ showError.calls.reset();
uploadService.fileUploadError.next(new FileUploadErrorEvent(null, { status: 404 }));
- expect(dispatch).toHaveBeenCalledWith(new SnackbarErrorAction('APP.MESSAGES.UPLOAD.ERROR.404'));
- dispatch.calls.reset();
+ expect(showError).toHaveBeenCalledWith('APP.MESSAGES.UPLOAD.ERROR.404');
+ showError.calls.reset();
uploadService.fileUploadError.next(new FileUploadErrorEvent(null, { status: 409 }));
- expect(dispatch).toHaveBeenCalledWith(new SnackbarErrorAction('APP.MESSAGES.UPLOAD.ERROR.CONFLICT'));
- dispatch.calls.reset();
+ expect(showError).toHaveBeenCalledWith('APP.MESSAGES.UPLOAD.ERROR.CONFLICT');
+ showError.calls.reset();
uploadService.fileUploadError.next(new FileUploadErrorEvent(null, { status: 500 }));
- expect(dispatch).toHaveBeenCalledWith(new SnackbarErrorAction('APP.MESSAGES.UPLOAD.ERROR.500'));
- dispatch.calls.reset();
+ expect(showError).toHaveBeenCalledWith('APP.MESSAGES.UPLOAD.ERROR.500');
+ showError.calls.reset();
uploadService.fileUploadError.next(new FileUploadErrorEvent(null, { status: 504 }));
- expect(dispatch).toHaveBeenCalledWith(new SnackbarErrorAction('APP.MESSAGES.UPLOAD.ERROR.504'));
- dispatch.calls.reset();
+ expect(showError).toHaveBeenCalledWith('APP.MESSAGES.UPLOAD.ERROR.504');
+ showError.calls.reset();
uploadService.fileUploadError.next(new FileUploadErrorEvent(null, { status: 403 }));
- expect(dispatch).toHaveBeenCalledWith(new SnackbarErrorAction('APP.MESSAGES.UPLOAD.ERROR.403'));
- dispatch.calls.reset();
+ expect(showError).toHaveBeenCalledWith('APP.MESSAGES.UPLOAD.ERROR.403');
+ showError.calls.reset();
uploadService.fileUploadError.next(new FileUploadErrorEvent(null, {}));
- expect(dispatch).toHaveBeenCalledWith(new SnackbarErrorAction('APP.MESSAGES.UPLOAD.ERROR.GENERIC'));
+ expect(showError).toHaveBeenCalledWith('APP.MESSAGES.UPLOAD.ERROR.GENERIC');
});
it('should load custom css', () => {
@@ -225,34 +213,19 @@ describe('AppService', () => {
});
it('should load repository status on login', () => {
- const repository: any = {};
- spyOn(contentApi, 'getRepositoryInformation').and.returnValue(of({ entry: { repository } }));
- spyOn(store, 'select').and.returnValue(of(''));
service.init();
-
- const dispatch = spyOn(store, 'dispatch');
auth.onLogin.next(true);
-
- expect(dispatch).toHaveBeenCalledWith(new SetRepositoryInfoAction(repository));
+ expect(contentApi.getRepositoryInformation).toHaveBeenCalled();
});
it('should load user profile on login', async () => {
const person: any = { id: 'person' };
- const group: any = { entry: {} };
- const groups: any[] = [group];
-
- spyOn(contentApi, 'getRepositoryInformation').and.returnValue(of({} as any));
- spyOn(groupService, 'listAllGroupMembershipsForPerson').and.returnValue(Promise.resolve(groups));
- spyOn(contentApi, 'getPerson').and.returnValue(of({ entry: person }));
-
+ loadUserProfileSpy.and.returnValue(Promise.resolve(person));
spyOn(store, 'select').and.returnValue(of(''));
service.init();
-
- const dispatch = spyOn(store, 'dispatch');
auth.onLogin.next(true);
- await expect(groupService.listAllGroupMembershipsForPerson).toHaveBeenCalled();
- await expect(dispatch).toHaveBeenCalledWith(new SetUserProfileAction({ person, groups: [group.entry] }));
+ expect(loadUserProfileSpy).toHaveBeenCalled();
});
});
diff --git a/projects/aca-shared/src/lib/services/app.service.ts b/projects/aca-shared/src/lib/services/app.service.ts
index f0a2238ff..b2eeecebd 100644
--- a/projects/aca-shared/src/lib/services/app.service.ts
+++ b/projects/aca-shared/src/lib/services/app.service.ts
@@ -22,39 +22,51 @@
* from Hyland Software. If not, see .
*/
-import { Injectable, OnDestroy } from '@angular/core';
-import { AuthenticationService, AppConfigService, AlfrescoApiService, PageTitleService, UserPreferencesService } from '@alfresco/adf-core';
+import { inject, Injectable, OnDestroy } from '@angular/core';
+import {
+ AuthenticationService,
+ AppConfigService,
+ AlfrescoApiService,
+ PageTitleService,
+ UserPreferencesService,
+ NotificationService
+} from '@alfresco/adf-core';
import { Observable, BehaviorSubject, Subject } from 'rxjs';
-import { GroupService, SearchQueryBuilderService, SharedLinksApiService, UploadService, FileUploadErrorEvent } from '@alfresco/adf-content-services';
+import { SearchQueryBuilderService, SharedLinksApiService, UploadService, FileUploadErrorEvent } from '@alfresco/adf-content-services';
import { OverlayContainer } from '@angular/cdk/overlay';
import { ActivatedRoute, ActivationEnd, NavigationStart, Router } from '@angular/router';
-import { filter, map, tap } from 'rxjs/operators';
+import { filter, map } from 'rxjs/operators';
import {
AppStore,
CloseModalDialogsAction,
SetCurrentUrlAction,
SetRepositoryInfoAction,
SetUserProfileAction,
- SnackbarErrorAction,
ResetSelectionAction
} from '@alfresco/aca-shared/store';
import { ContentApiService } from './content-api.service';
import { RouterExtensionService } from './router.extension.service';
import { Store } from '@ngrx/store';
-import { DiscoveryEntry, GroupEntry, Group } from '@alfresco/js-api';
+import { DiscoveryEntry } from '@alfresco/js-api';
import { AcaMobileAppSwitcherService } from './aca-mobile-app-switcher.service';
import { ShellAppService } from '@alfresco/adf-core/shell';
import { AppSettingsService } from './app-settings.service';
+import { UserProfileService } from './user-profile.service';
@Injectable({
providedIn: 'root'
})
// After moving shell to ADF to core, AppService will implement ShellAppService
export class AppService implements ShellAppService, OnDestroy {
+ private notificationService = inject(NotificationService);
private ready: BehaviorSubject;
ready$: Observable;
- pageHeading$: Observable;
+
+ private pageHeading = new BehaviorSubject('');
+ /** @deprecated page title is updated automatically */
+ pageHeading$ = this.pageHeading.asObservable();
+
appNavNarMode$: Subject<'collapsed' | 'expanded'> = new BehaviorSubject('expanded');
toggleAppNavBar$ = new Subject();
@@ -84,11 +96,11 @@ export class AppService implements ShellAppService, OnDestroy {
private routerExtensionService: RouterExtensionService,
private contentApi: ContentApiService,
private sharedLinksApiService: SharedLinksApiService,
- private groupService: GroupService,
private overlayContainer: OverlayContainer,
searchQueryBuilderService: SearchQueryBuilderService,
private acaMobileAppSwitcherService: AcaMobileAppSwitcherService,
- private appSettingsService: AppSettingsService
+ private appSettingsService: AppSettingsService,
+ private userProfileService: UserProfileService
) {
this.ready = new BehaviorSubject(this.authenticationService.isLoggedIn() || this.withCredentials);
this.ready$ = this.ready.asObservable();
@@ -104,11 +116,15 @@ export class AppService implements ShellAppService, OnDestroy {
acaMobileAppSwitcherService.closeDialog();
});
- this.pageHeading$ = this.router.events.pipe(
- filter((event) => event instanceof ActivationEnd && event.snapshot.children.length === 0),
- map((event: ActivationEnd) => event.snapshot?.data?.title ?? ''),
- tap((title) => this.pageTitle.setTitle(title))
- );
+ this.router.events
+ .pipe(
+ filter((event) => event instanceof ActivationEnd && event.snapshot.children.length === 0),
+ map((event: ActivationEnd) => event.snapshot?.data?.title ?? '')
+ )
+ .subscribe((title) => {
+ this.pageHeading.next(title);
+ this.pageTitle.setTitle(title);
+ });
}
ngOnDestroy(): void {
@@ -153,7 +169,7 @@ export class AppService implements ShellAppService, OnDestroy {
this.sharedLinksApiService.error.subscribe((err: { message: string }) => {
if (err?.message) {
- this.store.dispatch(new SnackbarErrorAction(err.message));
+ this.notificationService.showError(err.message);
}
});
@@ -184,17 +200,8 @@ export class AppService implements ShellAppService, OnDestroy {
}
private async loadUserProfile() {
- const groupsEntries: GroupEntry[] = await this.groupService.listAllGroupMembershipsForPerson('-me-', { maxItems: 250 });
-
- const groups: Group[] = [];
-
- if (groupsEntries) {
- groups.push(...groupsEntries.map((obj) => obj.entry));
- }
-
- this.contentApi.getPerson('-me-').subscribe((person) => {
- this.store.dispatch(new SetUserProfileAction({ person: person.entry, groups }));
- });
+ const profile = await this.userProfileService.loadUserProfile();
+ this.store.dispatch(new SetUserProfileAction(profile));
}
onFileUploadedError(error: FileUploadErrorEvent) {
@@ -220,7 +227,7 @@ export class AppService implements ShellAppService, OnDestroy {
message = 'APP.MESSAGES.UPLOAD.ERROR.504';
}
- this.store.dispatch(new SnackbarErrorAction(message));
+ this.notificationService.showError(message);
}
private loadCustomCss(): void {
diff --git a/projects/aca-shared/src/lib/services/user-profile.service.ts b/projects/aca-shared/src/lib/services/user-profile.service.ts
new file mode 100644
index 000000000..c36452cac
--- /dev/null
+++ b/projects/aca-shared/src/lib/services/user-profile.service.ts
@@ -0,0 +1,81 @@
+/*!
+ * Copyright © 2005-2024 Hyland Software, Inc. and its affiliates. All rights reserved.
+ *
+ * Alfresco Example Content Application
+ *
+ * This file is part of the Alfresco Example Content Application.
+ * If the software was purchased under a paid Alfresco license, the terms of
+ * the paid license agreement will prevail. Otherwise, the software is
+ * provided under the following open source license terms:
+ *
+ * The Alfresco Example Content Application is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * The Alfresco Example Content Application is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * from Hyland Software. If not, see .
+ */
+
+import { inject, Injectable } from '@angular/core';
+import { ProfileState } from '@alfresco/adf-extensions';
+import { GroupService } from '@alfresco/adf-content-services';
+import { BehaviorSubject } from 'rxjs';
+import { AlfrescoApiService } from '@alfresco/adf-core';
+import { PeopleApi } from '@alfresco/js-api';
+
+@Injectable({ providedIn: 'root' })
+export class UserProfileService {
+ private api = inject(AlfrescoApiService);
+ private groupService = inject(GroupService);
+
+ private get peopleApi(): PeopleApi {
+ return new PeopleApi(this.api.getInstance());
+ }
+
+ private userProfile = new BehaviorSubject(null);
+ userProfile$ = this.userProfile.asObservable();
+
+ /**
+ * Load user profile.
+ */
+ async loadUserProfile(): Promise {
+ const groupsEntries = await this.groupService.listAllGroupMembershipsForPerson('-me-', { maxItems: 250 });
+
+ const groups = [];
+ if (groupsEntries) {
+ groups.push(...groupsEntries.map((obj) => obj.entry));
+ }
+
+ const { entry: user } = await this.peopleApi.getPerson('-me-');
+
+ const id = user.id;
+ const firstName = user.firstName || '';
+ const lastName = user.lastName || '';
+ const userName = `${firstName} ${lastName}`;
+ const initials = [firstName[0], lastName[0]].join('');
+ const email = user.email;
+
+ const capabilities = user.capabilities;
+ const isAdmin = capabilities ? capabilities.isAdmin : true;
+
+ const profile: ProfileState = {
+ firstName,
+ lastName,
+ userName,
+ initials,
+ isAdmin,
+ id,
+ groups,
+ email
+ };
+
+ this.userProfile.next(profile);
+ return profile;
+ }
+}
diff --git a/projects/aca-shared/src/public-api.ts b/projects/aca-shared/src/public-api.ts
index fd2e7196c..6ac2a4926 100644
--- a/projects/aca-shared/src/public-api.ts
+++ b/projects/aca-shared/src/public-api.ts
@@ -57,6 +57,7 @@ export * from './lib/services/router.extension.service';
export * from './lib/services/app-hook.service';
export * from './lib/services/aca-file-auto-download.service';
export * from './lib/services/app-settings.service';
+export * from './lib/services/user-profile.service';
export * from './lib/utils/node.utils';
export * from './lib/testing/lib-testing-module';
diff --git a/projects/aca-shared/store/src/actions/app.actions.ts b/projects/aca-shared/store/src/actions/app.actions.ts
index 402216d4c..22cc211a9 100644
--- a/projects/aca-shared/store/src/actions/app.actions.ts
+++ b/projects/aca-shared/store/src/actions/app.actions.ts
@@ -23,8 +23,9 @@
*/
import { Action } from '@ngrx/store';
-import { Node, Person, Group, RepositoryInfo, VersionEntry } from '@alfresco/js-api';
+import { Node, RepositoryInfo, VersionEntry } from '@alfresco/js-api';
import { AppActionTypes } from './app-action-types';
+import { ProfileState } from '@alfresco/adf-extensions';
export class SetCurrentFolderAction implements Action {
readonly type = AppActionTypes.SetCurrentFolder;
@@ -47,7 +48,7 @@ export class SetCurrentUrlAction implements Action {
export class SetUserProfileAction implements Action {
readonly type = AppActionTypes.SetUserProfile;
- constructor(public payload: { person: Person; groups: Group[] }) {}
+ constructor(public payload: ProfileState) {}
}
export class ToggleInfoDrawerAction implements Action {
diff --git a/projects/aca-shared/store/src/selectors/app.selectors.ts b/projects/aca-shared/store/src/selectors/app.selectors.ts
index 3271dfabb..54639b422 100644
--- a/projects/aca-shared/store/src/selectors/app.selectors.ts
+++ b/projects/aca-shared/store/src/selectors/app.selectors.ts
@@ -28,6 +28,7 @@ import { createSelector } from '@ngrx/store';
const HXI_CONNECTOR = 'alfresco-hxinsight-connector-prediction-applier-extension';
export const selectApp = (state: AppStore) => state.app;
+/** @deprecated use `UserProfileService` instead */
export const getUserProfile = createSelector(selectApp, (state) => state.user);
export const getCurrentFolder = createSelector(selectApp, (state) => state.navigation.currentFolder);
export const getCurrentVersion = createSelector(selectApp, (state) => state.currentNodeVersion);