[ACS-3742] Layout changes for workspace (#2980)

* Layout changes for workspace sidemenu

* added header and search layout changes

* implemented review comments and removed process related code

* Added expand and collapse functionality

* Modified the paths

* linting fixes

* use standard material settings icon

* use only specific modules needed for page layout

* use standard "menu" icon for now

* use standard avatar icon for now

* cleanup user profile menu item

* cleanup About component layout

* remove hardcoded settings route

* deprecate "headerImagePath"

* deprecate "headerTextColor" customisation

* deprecate "headerColor" customisation

* proper toggle of the side menu

* proper sidebar header implementation

* user profile basic cleanup

* minor fixes

* cleanup buttons

* remove old app layout and use ADF one

* remove old header component

* cleanup old layout module

* fix unit tests

* cleanup unit tests

* cleanup header actions module

* deprecate unused main-action component

* cleanup styles

* restore removed method

* cleanup search results toolbar

* restore expand menu functionality

* cleanup code, back buttons for about and profile

* restore original code

* proper collapse button

* remove unused i18n key

* styles cleanup

* cleanup sidebar

* cleanup user profile

* add safety checks for focus after close

* layout fixes

* update view profile unit tests

* code cleanup after reviews

* cleanup header actions

* fix menu population, user info

* improved upload and create actions

* remove useless tests

* fix folder rules tests

* search button workaround

* e2e: remove wait

* add create/upload tooltips

* e2e fix

* e2e fix

* e2e fix

* e2e fix

* e2e fix

* e2e fix

* e2e fix

* e2e fix

* e2e fix

* e2e fix

* e2e fix

* e2e fix

* try fix e2e

* update e2e extension configs

* try fix e2e

* try fix e2e

* fix eslint config

* try fix e2e

* move search button to extensions

* move upload and create to extensions

* remove header actions as no longer needed

* cleanup

* e2e fixes and cleanup for unwanted files

* linting fixes

* linting fixes

* added button type to support text buttons

* linting fixes

* added more unit tests to achieve code coverage requirement

* fixing code covergae for aca-content

* fixed code coverage for aca-shared

* linting fixes

* linting fixes

* cleanup

* version fix

---------

Co-authored-by: SheenaMalhotra182 <sheena.malhotra@globallogic.com>
Co-authored-by: Denys Vuika <denys.vuika@gmail.com>
Co-authored-by: SheenaMalhotra182 <sheena.malhotra@contractors.onbase.com>
This commit is contained in:
Yasa-Nataliya
2023-04-20 16:48:24 +05:30
committed by GitHub
parent d042b80386
commit 6fac964d94
140 changed files with 1663 additions and 2177 deletions

View File

@@ -27,9 +27,6 @@
<mat-panel-title>
<div class="item">
<button
[ngClass]="{
'action-button--active': acaExpansionPanel.hasActiveLinks()
}"
[attr.aria-label]="item.title | translate"
[id]="item.id"
[attr.title]="item.description | translate"

View File

@@ -0,0 +1,20 @@
<div class="sidenav-header">
<div class="sidenav-header-title">
<div class="sidenav-header-title-logo"
(click)="toggleNavBar.emit()"
(keypress)="toggleNavBar.emit()">
<img
src="{{ logo$ | async }}"
title="{{'APP.TOOLTIPS.COLLAPSE_NAVIGATION' | translate}}"
alt="{{ 'CORE.HEADER.LOGO_ARIA' | translate }}" />
</div>
<div class="sidenav-header-title-text" [routerLink]="landingPage">
{{ appName$ | async | translate }}
</div>
<ng-container *ngFor="let actionRef of actions; trackBy: trackByActionId">
<aca-toolbar-action [actionRef]="actionRef"></aca-toolbar-action>
</ng-container>
</div>
</div>

View File

@@ -0,0 +1,74 @@
/*!
* Copyright © 2005-2023 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 <http://www.gnu.org/licenses/>.
*/
import { Component, EventEmitter, OnDestroy, OnInit, Output, ViewEncapsulation } from '@angular/core';
import { Store } from '@ngrx/store';
import { Observable, Subject } from 'rxjs';
import { AppStore, getAppName, getLogoPath } from '@alfresco/aca-shared/store';
import { AppConfigService } from '@alfresco/adf-core';
import { ContentActionRef } from '@alfresco/adf-extensions';
import { AppExtensionService } from '@alfresco/aca-shared';
import { takeUntil } from 'rxjs/operators';
@Component({
selector: 'app-sidenav-header',
templateUrl: `./sidenav-header.component.html`,
encapsulation: ViewEncapsulation.None,
host: { class: 'app-sidenav-header' }
})
export class SidenavHeaderComponent implements OnInit, OnDestroy {
private onDestroy$ = new Subject<boolean>();
appName$: Observable<string>;
logo$: Observable<string>;
landingPage: string;
actions: Array<ContentActionRef> = [];
@Output()
toggleNavBar = new EventEmitter();
constructor(public store: Store<AppStore>, private appConfigService: AppConfigService, private appExtensions: AppExtensionService) {
this.appName$ = store.select(getAppName);
this.logo$ = store.select(getLogoPath);
this.landingPage = this.appConfigService.get('landingPage', '/personal-files');
}
ngOnInit() {
this.appExtensions
.getHeaderActions()
.pipe(takeUntil(this.onDestroy$))
.subscribe((actions) => {
this.actions = actions;
});
}
ngOnDestroy() {
this.onDestroy$.next(true);
this.onDestroy$.complete();
}
trackByActionId(_: number, action: ContentActionRef) {
return action.id;
}
}

View File

@@ -1,3 +0,0 @@
<app-sidenav
[mode]="data.mode"
></app-sidenav>

View File

@@ -1,36 +1,16 @@
<div class="sidenav">
<ng-container [ngSwitch]="mode">
<div class="section action-menu" [ngClass]="'section--' + mode">
<app-main-action [expanded]="mode === 'expanded'"></app-main-action>
<app-create-menu [expanded]="mode === 'expanded'"></app-create-menu>
</div>
<app-sidenav-header (toggleNavBar)="toggleClick()"></app-sidenav-header>
<div class="section-sub-actions">
<div *ngFor="let group of groups; trackBy: trackByGroupId" class="section" [ngClass]="'section--' + mode">
<ng-container *ngSwitchCase="'expanded'">
<div *ngFor="let group of groups; trackBy: trackByGroupId" class="section">
<mat-list-item *ngFor="let item of group.items; trackBy: trackByLinkId">
<ng-container *ngIf="!item.component">
<app-expand-menu [item]="item"></app-expand-menu>
</ng-container>
<ng-container *ngIf="item.component">
<adf-dynamic-component [data]="{ item: item, state: 'expanded' }" [id]="item.component"></adf-dynamic-component>
</ng-container>
</mat-list-item>
</ng-container>
<ng-container *ngSwitchCase="'collapsed'">
<div class="list-item" *ngFor="let item of group.items; trackBy: trackByLinkId">
<ng-container *ngIf="!item.component">
<app-button-menu [item]="item"></app-button-menu>
</ng-container>
<ng-container *ngIf="item.component">
<adf-dynamic-component [data]="{ item: item, state: 'collapsed' }" [id]="item.component"> </adf-dynamic-component>
</ng-container>
</div>
</ng-container>
</div>
</div>
</ng-container>
</div>

View File

@@ -1,151 +1,129 @@
.app-sidenav {
display: flex;
flex: 1;
flex-direction: column;
height: 100%;
overflow-y: hidden;
}
.sidenav {
display: flex;
flex: 1;
flex-direction: column;
height: 100%;
background-color: var(--theme-background-color);
overflow-y: hidden;
background: var(--theme-sidenav-background-color);
.action-menu {
display: flex;
flex-direction: column;
justify-content: center;
align-items: stretch;
}
&-header {
padding: 32px 0;
.section.action-menu {
padding: 8px 14px;
position: sticky;
}
&-title {
display: flex;
flex-direction: row;
align-items: center;
height: 32px;
padding: 0 24px;
.section-sub-actions {
overflow-y: auto;
}
&-logo {
img {
cursor: pointer;
height: 28px;
vertical-align: middle;
}
}
.section {
padding: 8px 6px;
border-bottom: 1px solid var(--theme-divider-color);
&-text {
flex: 1;
color: var(--theme-selected-text-color);
padding-left: 32px;
letter-spacing: 0.25px;
font-style: normal;
font-weight: 400;
font-size: var(--theme-body-1-font-size);
cursor: pointer;
}
}
}
.section:last-child {
border-bottom: 0;
}
.section--collapsed {
display: flex;
flex-direction: column;
align-items: center;
}
.section-sub-actions {
overflow-y: auto;
.list-item {
padding: 12px 0;
display: flex;
align-items: center;
height: 24px;
}
.mat-expansion-panel {
width: 100%;
background-color: unset;
box-shadow: none;
border-radius: 0;
.menu {
display: flex;
flex: 1;
flex-direction: row;
}
&-header {
height: 32px;
padding: 0 32px 0 0;
display: flex;
align-items: center;
border: none;
}
&-header:hover {
background: var(--theme-hover-background-color);
}
.full-width {
display: flex;
width: 100%;
}
&-header-title {
display: flex;
flex-direction: row;
align-items: center;
}
.action-button--active {
color: var(--theme-primary-color) !important;
}
&-body {
padding: 0 0 16px;
font-size: var(--theme-body-1-font-size);
.action-button {
color: var(--theme-text-color);
}
.mat-button {
line-height: 32px;
}
}
.action-button .action-button__label {
margin: 0 8px !important;
}
.mat-expansion-indicator {
display: flex;
align-content: center;
}
.item {
padding: 12px 0;
flex-direction: row;
display: flex;
align-items: center;
text-decoration: none;
height: 24px;
width: 100%;
user-select: none;
}
.mat-expansion-indicator::after {
transform: rotate(226deg);
}
}
.app-item,
.app-item .item {
display: flex;
flex: 1;
flex-direction: row;
}
.item {
flex-direction: row;
display: flex;
align-items: center;
text-decoration: none;
width: 100%;
user-select: none;
.item:hover .action-button__label {
color: var(--theme-primary-color);
}
&:hover .action-button__label {
color: var(--theme-selected-text-color);
}
}
.mat-expansion-panel-header {
padding: 0 8px 0 0 !important;
display: flex;
align-items: center;
font-size: 14px !important;
}
.action-button {
color: var(--theme-action-button-text-color);
height: 32px;
padding: 0 24px;
border-radius: 0;
}
.mat-expansion-panel {
width: 100%;
background-color: unset;
box-shadow: none !important;
}
.full-width {
display: flex;
width: 100%;
}
.mat-expansion-panel:not(.mat-expanded) .mat-expansion-panel-header:not([aria-disabled='true']):hover {
background: none !important;
}
.action-button--active {
color: var(--theme-selected-text-color) !important;
background: var(--theme-selected-background-color);
}
.mat-expansion-indicator {
display: flex;
align-content: center;
}
.mat-expansion-panel-body {
padding-bottom: 0;
}
.mat-expansion-panel-header-title {
display: flex;
flex-direction: row;
align-items: center;
}
}
.aca-menu-panel {
.action-button--active {
color: var(--theme-accent-color) !important;
}
.action-button {
color: var(--theme-primary-color);
}
.action-button:hover {
color: var(--theme-accent-color);
}
}
[dir='rtl'] .sidenav {
/* stylelint-disable-next-line no-descending-specificity */
.mat-expansion-panel-header {
padding: 0 0 0 8px !important;
.action-panel-header {
color: var(--theme-action-button-text-color);
padding: 0 24px;
&__label {
font-size: var(--theme-caption-font-size);
}
}
}
}

View File

@@ -26,7 +26,8 @@ import { NO_ERRORS_SCHEMA } from '@angular/core';
import { TestBed, ComponentFixture } from '@angular/core/testing';
import { SidenavComponent } from './sidenav.component';
import { AppTestingModule } from '../../testing/app-testing.module';
import { AppExtensionService } from '@alfresco/aca-shared';
import { AppExtensionService, AppService } from '@alfresco/aca-shared';
import { BehaviorSubject, Subject } from 'rxjs';
describe('SidenavComponent', () => {
let fixture: ComponentFixture<SidenavComponent>;
@@ -37,6 +38,15 @@ describe('SidenavComponent', () => {
TestBed.configureTestingModule({
imports: [AppTestingModule],
declarations: [SidenavComponent],
providers: [
{
provide: AppService,
useValue: {
appNavNarMode$: new BehaviorSubject('expanded'),
toggleAppNavBar$: new Subject()
}
}
],
schemas: [NO_ERRORS_SCHEMA]
});

View File

@@ -28,7 +28,8 @@ import { Store } from '@ngrx/store';
import { AppStore, getSideNavState } from '@alfresco/aca-shared/store';
import { Subject } from 'rxjs';
import { takeUntil, distinctUntilChanged, debounceTime } from 'rxjs/operators';
import { AppExtensionService } from '@alfresco/aca-shared';
import { AppExtensionService, AppService } from '@alfresco/aca-shared';
import { SidenavLayoutComponent } from '@alfresco/adf-core';
@Component({
selector: 'app-sidenav',
@@ -39,12 +40,15 @@ import { AppExtensionService } from '@alfresco/aca-shared';
})
export class SidenavComponent implements OnInit, OnDestroy {
@Input()
mode: 'collapsed' | 'expanded' = 'expanded';
data: {
layout?: SidenavLayoutComponent;
mode?: 'collapsed' | 'expanded';
} = {};
groups: Array<NavBarGroupRef> = [];
private onDestroy$ = new Subject<boolean>();
constructor(private store: Store<AppStore>, private extensions: AppExtensionService) {}
constructor(private store: Store<AppStore>, private extensions: AppExtensionService, private appService: AppService) {}
ngOnInit() {
this.store
@@ -53,6 +57,9 @@ export class SidenavComponent implements OnInit, OnDestroy {
.subscribe(() => {
this.groups = this.extensions.getApplicationNavigation(this.extensions.navbar);
});
this.appService.appNavNarMode$.next(this.data.mode);
this.appService.toggleAppNavBar$.pipe(takeUntil(this.onDestroy$)).subscribe(() => this.toggleNavBar());
}
trackByGroupId(_: number, obj: NavBarGroupRef): string {
@@ -63,6 +70,15 @@ export class SidenavComponent implements OnInit, OnDestroy {
return obj.id;
}
toggleClick() {
this.toggleNavBar();
}
private toggleNavBar() {
this.data.layout.toggleMenu();
this.appService.appNavNarMode$.next(this.data.layout.isMenuMinimized ? 'collapsed' : 'expanded');
}
ngOnDestroy() {
this.onDestroy$.next(true);
this.onDestroy$.complete();

View File

@@ -24,11 +24,9 @@
import { NgModule } from '@angular/core';
import { AppCreateMenuModule } from '../create-menu/create-menu.module';
import { CommonModule } from '@angular/common';
import { CoreModule } from '@alfresco/adf-core';
import { RouterModule } from '@angular/router';
import { ExtensionsModule } from '@alfresco/adf-extensions';
import { CoreExtensionsModule } from '../../extensions/core.extensions.module';
import { ExpansionPanelDirective } from './directives/expansion-panel.directive';
import { MenuPanelDirective } from './directives/menu-panel.directive';
import { SidenavComponent } from './sidenav.component';
@@ -36,19 +34,11 @@ import { ActiveLinkDirective } from './directives/active-link.directive';
import { ExpandMenuComponent } from './components/expand-menu.component';
import { ButtonMenuComponent } from './components/button-menu.component';
import { ActionDirective } from './directives/action.directive';
import { MainActionModule } from '../main-action/main-action.module';
import { SidenavWrapperComponent } from './sidenav-wrapper/sidenav-wrapper.component';
import { SidenavHeaderComponent } from './components/sidenav-header.component';
import { SharedToolbarModule } from '@alfresco/aca-shared';
@NgModule({
imports: [
CommonModule,
CoreModule.forChild(),
CoreExtensionsModule.forChild(),
ExtensionsModule.forChild(),
RouterModule,
AppCreateMenuModule,
MainActionModule
],
imports: [CoreModule.forChild(), ExtensionsModule.forChild(), RouterModule, AppCreateMenuModule, SharedToolbarModule],
declarations: [
MenuPanelDirective,
ExpansionPanelDirective,
@@ -57,7 +47,7 @@ import { SidenavWrapperComponent } from './sidenav-wrapper/sidenav-wrapper.compo
ExpandMenuComponent,
ButtonMenuComponent,
SidenavComponent,
SidenavWrapperComponent
SidenavHeaderComponent
],
exports: [
MenuPanelDirective,