mirror of
https://github.com/Alfresco/alfresco-content-app.git
synced 2025-10-01 14:41:14 +00:00
[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:
@@ -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"
|
||||
|
@@ -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>
|
@@ -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;
|
||||
}
|
||||
}
|
@@ -1,3 +0,0 @@
|
||||
<app-sidenav
|
||||
[mode]="data.mode"
|
||||
></app-sidenav>
|
@@ -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>
|
||||
|
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -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]
|
||||
});
|
||||
|
||||
|
@@ -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();
|
||||
|
@@ -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,
|
||||
|
Reference in New Issue
Block a user