diff --git a/projects/aca-content/src/lib/aca-content.module.ts b/projects/aca-content/src/lib/aca-content.module.ts index 6f944e248..977798d26 100644 --- a/projects/aca-content/src/lib/aca-content.module.ts +++ b/projects/aca-content/src/lib/aca-content.module.ts @@ -113,7 +113,6 @@ import { ViewNodeComponent } from './components/toolbar/view-node/view-node.comp import { CONTENT_ROUTES } from './aca-content.routes'; import { RouterModule } from '@angular/router'; import { UploadFilesDialogComponent } from './components/upload-files-dialog/upload-files-dialog.component'; -import { AppLayoutComponent } from './components/layout/app-layout/app-layout.component'; import { AppTrashcanModule } from './components/trashcan/trashcan.module'; import { AppSharedLinkViewModule } from './components/shared-link-view/shared-link-view.module'; import { AcaFolderRulesModule } from '@alfresco/aca-folder-rules'; @@ -122,6 +121,7 @@ import { UserInfoComponent } from './components/common/user-info/user-info.compo import { AppHeaderActionsModule } from './components/header-actions/header-actions.module'; import { SidenavComponent } from './components/sidenav/sidenav.component'; import { ContentManagementService } from './services/content-management.service'; +import { ShellLayoutComponent } from '@alfresco/adf-core/shell'; registerLocaleData(localeFr); registerLocaleData(localeDe); @@ -207,7 +207,7 @@ export class ContentServiceExtensionModule { }); extensions.setComponents({ - 'app.layout.main': AppLayoutComponent, + 'app.layout.main': ShellLayoutComponent, // This allows providing custom application header, disabled for ACA the time being // 'app.layout.header': AppHeaderComponent, 'app.layout.sidenav': SidenavComponent, diff --git a/projects/aca-content/src/lib/aca-content.routes.ts b/projects/aca-content/src/lib/aca-content.routes.ts index c4b5441c3..f09153a5e 100644 --- a/projects/aca-content/src/lib/aca-content.routes.ts +++ b/projects/aca-content/src/lib/aca-content.routes.ts @@ -23,7 +23,6 @@ * along with Alfresco. If not, see . */ -import { AppLayoutComponent } from './components/layout/app-layout/app-layout.component'; import { FilesComponent } from './components/files/files.component'; import { LibrariesComponent } from './components/libraries/libraries.component'; import { FavoriteLibrariesComponent } from './components/favorite-libraries/favorite-libraries.component'; @@ -41,6 +40,7 @@ import { ViewProfileRuleGuard } from './components/view-profile/view-profile.gua import { Route } from '@angular/router'; import { SharedLinkViewComponent } from './components/shared-link-view/shared-link-view.component'; import { TrashcanComponent } from './components/trashcan/trashcan.component'; +import { ShellLayoutComponent } from '@alfresco/adf-core/shell'; export const CONTENT_ROUTES: ExtensionRoute[] = [ { @@ -57,7 +57,7 @@ export const CONTENT_ROUTES: ExtensionRoute[] = [ }, { path: 'view', - component: AppLayoutComponent, + component: ShellLayoutComponent, children: [ { path: ':nodeId', diff --git a/projects/aca-content/src/lib/components/layout/app-layout/app-layout.component.html b/projects/aca-content/src/lib/components/layout/app-layout/app-layout.component.html deleted file mode 100644 index 663393ce6..000000000 --- a/projects/aca-content/src/lib/components/layout/app-layout/app-layout.component.html +++ /dev/null @@ -1,32 +0,0 @@ - - - - - - - - - - - - - - - - - - - - diff --git a/projects/aca-content/src/lib/components/layout/app-layout/app-layout.component.scss b/projects/aca-content/src/lib/components/layout/app-layout/app-layout.component.scss deleted file mode 100644 index 9f026feab..000000000 --- a/projects/aca-content/src/lib/components/layout/app-layout/app-layout.component.scss +++ /dev/null @@ -1,34 +0,0 @@ -.app-layout { - display: flex; - flex-direction: column; - flex: 1; - height: 100%; - overflow: hidden; - min-height: 0; - - router-outlet[name='viewer'] + * { - width: 100%; - height: 100%; - z-index: 999; - position: absolute; - top: 0; - right: 0; - background-color: white; - } - - adf-file-uploading-dialog { - z-index: 1000; - } -} - -@media screen and (max-width: 599px) { - .adf-app-title { - display: none; - } -} - -@media screen and (max-width: 719px) { - .adf-app-logo { - display: none; - } -} diff --git a/projects/aca-content/src/lib/components/layout/app-layout/app-layout.component.spec.ts b/projects/aca-content/src/lib/components/layout/app-layout/app-layout.component.spec.ts deleted file mode 100644 index aece3d063..000000000 --- a/projects/aca-content/src/lib/components/layout/app-layout/app-layout.component.spec.ts +++ /dev/null @@ -1,220 +0,0 @@ -/*! - * @license - * Alfresco Example Content Application - * - * Copyright (C) 2005 - 2020 Alfresco Software Limited - * - * 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 - * along with Alfresco. If not, see . - */ - -import { NO_ERRORS_SCHEMA } from '@angular/core'; -import { TestBed, ComponentFixture } from '@angular/core/testing'; -import { AppConfigService, FileModel, UploadService, UserPreferencesService } from '@alfresco/adf-core'; -import { AppLayoutComponent } from './app-layout.component'; -import { AppTestingModule } from '../../../testing/app-testing.module'; -import { Store } from '@ngrx/store'; -import { AppStore, SetSelectedNodesAction, ResetSelectionAction } from '@alfresco/aca-shared/store'; -import { Router, NavigationStart } from '@angular/router'; -import { of, Subject } from 'rxjs'; -import { By } from '@angular/platform-browser'; - -class MockRouter { - private url = 'some-url'; - private subject = new Subject(); - events = this.subject.asObservable(); - routerState = { snapshot: { url: this.url } }; - - navigateByUrl(url: string) { - const navigationStart = new NavigationStart(0, url); - this.subject.next(navigationStart); - } -} - -describe('AppLayoutComponent', () => { - let fixture: ComponentFixture; - let component: AppLayoutComponent; - let appConfig: AppConfigService; - let userPreference: UserPreferencesService; - let store: Store; - let router: Router; - let uploadService: UploadService; - let fakeFileList: FileModel[]; - - beforeEach(() => { - TestBed.configureTestingModule({ - imports: [AppTestingModule], - providers: [ - Store, - { - provide: Router, - useClass: MockRouter - } - ], - declarations: [AppLayoutComponent], - schemas: [NO_ERRORS_SCHEMA] - }); - - fixture = TestBed.createComponent(AppLayoutComponent); - component = fixture.componentInstance; - appConfig = TestBed.inject(AppConfigService); - store = TestBed.inject(Store); - router = TestBed.inject(Router); - userPreference = TestBed.inject(UserPreferencesService); - - fakeFileList = [new FileModel(new File([], 'fakeFile'))]; - - uploadService = TestBed.inject(UploadService); - }); - - beforeEach(() => { - appConfig.config.languages = []; - appConfig.config.locale = 'en'; - }); - - describe('sidenav state', () => { - it('should get state from configuration', () => { - appConfig.config.sideNav = { - expandedSidenav: false, - preserveState: false - }; - - fixture.detectChanges(); - - expect(component.expandedSidenav).toBe(false); - }); - - it('should resolve state to true is no configuration', () => { - appConfig.config.sidenav = {}; - - fixture.detectChanges(); - - expect(component.expandedSidenav).toBe(true); - }); - - it('should get state from user settings as true', () => { - appConfig.config.sideNav = { - expandedSidenav: false, - preserveState: true - }; - - spyOn(userPreference, 'get').and.callFake((key) => { - if (key === 'expandedSidenav') { - return 'true'; - } - return 'false'; - }); - - fixture.detectChanges(); - - expect(component.expandedSidenav).toBe(true); - }); - - it('should get state from user settings as false', () => { - appConfig.config.sidenav = { - expandedSidenav: false, - preserveState: true - }; - - spyOn(userPreference, 'get').and.callFake((key) => { - if (key === 'expandedSidenav') { - return 'false'; - } - return 'true'; - }); - - fixture.detectChanges(); - - expect(component.expandedSidenav).toBe(false); - }); - }); - - it('should reset selection before navigation', () => { - const selection: any[] = [{ entry: { id: 'nodeId', name: 'name' } }]; - spyOn(store, 'dispatch').and.stub(); - fixture.detectChanges(); - store.dispatch(new SetSelectedNodesAction(selection)); - router.navigateByUrl('somewhere/over/the/rainbow'); - fixture.detectChanges(); - - expect(store.dispatch['calls'].mostRecent().args).toEqual([new ResetSelectionAction()]); - }); - - it('should close menu on mobile screen size', () => { - component.minimizeSidenav = false; - component.layout.container = { - isMobileScreenSize: true, - toggleMenu: () => {} - }; - - spyOn(component.layout.container, 'toggleMenu'); - fixture.detectChanges(); - - component.hideMenu({ preventDefault: () => {} } as any); - - expect(component.layout.container.toggleMenu).toHaveBeenCalled(); - }); - - it('should close menu on mobile screen size also when minimizeSidenav true', () => { - fixture.detectChanges(); - component.minimizeSidenav = true; - component.layout.container = { - isMobileScreenSize: true, - toggleMenu: () => {} - }; - - spyOn(component.layout.container, 'toggleMenu'); - fixture.detectChanges(); - - component.hideMenu({ preventDefault: () => {} } as any); - - expect(component.layout.container.toggleMenu).toHaveBeenCalled(); - }); - - describe('File Uploading Dialog', () => { - it('should the uploading file dialog be visible on the left when the showFileUploadingDialog is true', async () => { - fixture.detectChanges(); - await fixture.whenStable(); - - uploadService.addToQueue(...fakeFileList); - fixture.detectChanges(); - await fixture.whenStable(); - - const fileUploadingDialog = fixture.debugElement.query(By.css('adf-file-uploading-dialog')); - - expect(fileUploadingDialog.attributes['position']).toEqual('left'); - expect(component.showFileUploadingDialog).toEqual(true); - expect(fileUploadingDialog).not.toEqual(null); - }); - - it('should the uploading file dialog not be visible when the showFileUploadingDialog is false', async () => { - spyOn(store, 'select').and.returnValue(of(false)); - fixture.detectChanges(); - await fixture.whenStable(); - - uploadService.addToQueue(...fakeFileList); - fixture.detectChanges(); - await fixture.whenStable(); - - const fileUploadingDialog = fixture.debugElement.query(By.css('adf-file-uploading-dialog')); - - expect(component.showFileUploadingDialog).toEqual(false); - expect(fileUploadingDialog).toEqual(null); - }); - }); -}); diff --git a/projects/aca-content/src/lib/components/layout/app-layout/app-layout.component.ts b/projects/aca-content/src/lib/components/layout/app-layout/app-layout.component.ts deleted file mode 100644 index 6193c7f2a..000000000 --- a/projects/aca-content/src/lib/components/layout/app-layout/app-layout.component.ts +++ /dev/null @@ -1,177 +0,0 @@ -/*! - * @license - * Alfresco Example Content Application - * - * Copyright (C) 2005 - 2020 Alfresco Software Limited - * - * 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 - * along with Alfresco. If not, see . - */ - -import { AppConfigService, SidenavLayoutComponent, UserPreferencesService } from '@alfresco/adf-core'; -import { Component, OnDestroy, OnInit, ViewChild, ViewEncapsulation } from '@angular/core'; -import { NavigationEnd, Router, NavigationStart } from '@angular/router'; -import { Store } from '@ngrx/store'; -import { Subject, Observable } from 'rxjs'; -import { filter, takeUntil, map, withLatestFrom, delay } from 'rxjs/operators'; -import { NodePermissionService } from '@alfresco/aca-shared'; -import { BreakpointObserver } from '@angular/cdk/layout'; -import { AppStore, getCurrentFolder, getFileUploadingDialog, ResetSelectionAction } from '@alfresco/aca-shared/store'; -import { Directionality } from '@angular/cdk/bidi'; - -@Component({ - selector: 'app-layout', - templateUrl: './app-layout.component.html', - styleUrls: ['./app-layout.component.scss'], - encapsulation: ViewEncapsulation.None, - host: { class: 'app-layout' } -}) -export class AppLayoutComponent implements OnInit, OnDestroy { - @ViewChild('layout', { static: true }) - layout: SidenavLayoutComponent; - - onDestroy$: Subject = new Subject(); - isSmallScreen$: Observable; - - expandedSidenav: boolean; - currentFolderId: string; - canUpload = false; - - minimizeSidenav = false; - hideSidenav = false; - direction: Directionality; - - showFileUploadingDialog: boolean; - - private minimizeConditions: string[] = ['search']; - private hideConditions: string[] = ['/preview/']; - - constructor( - protected store: Store, - private permission: NodePermissionService, - private router: Router, - private userPreferenceService: UserPreferencesService, - private appConfigService: AppConfigService, - private breakpointObserver: BreakpointObserver - ) {} - - ngOnInit() { - this.isSmallScreen$ = this.breakpointObserver.observe(['(max-width: 600px)']).pipe(map((result) => result.matches)); - - this.hideSidenav = this.hideConditions.some((el) => this.router.routerState.snapshot.url.includes(el)); - - this.minimizeSidenav = this.minimizeConditions.some((el) => this.router.routerState.snapshot.url.includes(el)); - - if (!this.minimizeSidenav) { - this.expandedSidenav = this.getSidenavState(); - } else { - this.expandedSidenav = false; - } - - this.store - .select(getCurrentFolder) - .pipe(takeUntil(this.onDestroy$)) - .subscribe((node) => { - this.currentFolderId = node ? node.id : null; - this.canUpload = node && this.permission.check(node, ['create']); - }); - - this.router.events - .pipe( - withLatestFrom(this.isSmallScreen$), - filter(([event, isSmallScreen]) => isSmallScreen && event instanceof NavigationEnd), - takeUntil(this.onDestroy$) - ) - .subscribe(() => { - this.layout.container.sidenav.close(); - }); - - this.router.events - .pipe( - filter((event) => event instanceof NavigationEnd), - takeUntil(this.onDestroy$) - ) - .subscribe((event: NavigationEnd) => { - this.minimizeSidenav = this.minimizeConditions.some((el) => event.urlAfterRedirects.includes(el)); - this.hideSidenav = this.hideConditions.some((el) => event.urlAfterRedirects.includes(el)); - - this.updateState(); - }); - - this.router.events - .pipe( - filter((event) => event instanceof NavigationStart), - takeUntil(this.onDestroy$) - ) - .subscribe(() => { - this.store.dispatch(new ResetSelectionAction()); - }); - - this.store - .select(getFileUploadingDialog) - .pipe(delay(0), takeUntil(this.onDestroy$)) - .subscribe((fileUploadingDialog: boolean) => { - this.showFileUploadingDialog = fileUploadingDialog; - }); - } - - ngOnDestroy() { - this.onDestroy$.next(true); - this.onDestroy$.complete(); - } - - hideMenu(event: Event) { - if (this.layout.container.isMobileScreenSize) { - event.preventDefault(); - this.layout.container.toggleMenu(); - } - } - - private updateState() { - if (this.minimizeSidenav && !this.layout.isMenuMinimized) { - this.layout.isMenuMinimized = true; - if (!this.layout.container.isMobileScreenSize) { - this.layout.container.toggleMenu(); - } - } - - if (!this.minimizeSidenav) { - if (this.getSidenavState() && this.layout.isMenuMinimized) { - this.layout.isMenuMinimized = false; - this.layout.container.toggleMenu(); - } - } - } - - onExpanded(state: boolean) { - if (!this.minimizeSidenav && this.appConfigService.get('sideNav.preserveState')) { - this.userPreferenceService.set('expandedSidenav', state); - } - } - - private getSidenavState(): boolean { - const expand = this.appConfigService.get('sideNav.expandedSidenav', true); - const preserveState = this.appConfigService.get('sideNav.preserveState', true); - - if (preserveState) { - return this.userPreferenceService.get('expandedSidenav', expand.toString()) === 'true'; - } - - return expand; - } -} diff --git a/projects/aca-content/src/lib/components/layout/layout.module.ts b/projects/aca-content/src/lib/components/layout/layout.module.ts index 0b93e4646..dab9c1e61 100644 --- a/projects/aca-content/src/lib/components/layout/layout.module.ts +++ b/projects/aca-content/src/lib/components/layout/layout.module.ts @@ -27,7 +27,6 @@ import { NgModule } from '@angular/core'; import { CommonModule } from '@angular/common'; import { CoreModule } from '@alfresco/adf-core'; import { SHELL_NAVBAR_MIN_WIDTH } from '@alfresco/adf-core/shell'; -import { AppLayoutComponent } from './app-layout/app-layout.component'; import { ContentModule } from '@alfresco/adf-content-services'; import { RouterModule } from '@angular/router'; import { AppSidenavModule } from '../sidenav/sidenav.module'; @@ -48,8 +47,7 @@ import { PageLayoutModule } from '@alfresco/aca-shared'; HttpClientModule, PageLayoutModule ], - declarations: [AppLayoutComponent], - exports: [AppLayoutComponent, PageLayoutModule], + exports: [PageLayoutModule], providers: [{ provide: SHELL_NAVBAR_MIN_WIDTH, useValue: 0 }] }) export class AppLayoutModule {}