mirror of
https://github.com/Alfresco/alfresco-content-app.git
synced 2025-09-17 14:21:14 +00:00
added header and search layout changes
This commit is contained in:
committed by
Yasa-Nataliya
parent
d4cf1eddcc
commit
5b39510106
@@ -132,44 +132,6 @@
|
|||||||
}
|
}
|
||||||
],
|
],
|
||||||
"create": [
|
"create": [
|
||||||
{
|
|
||||||
"id": "app.create.uploadFile",
|
|
||||||
"order": 100,
|
|
||||||
"icon": "file_upload",
|
|
||||||
"title": "APP.NEW_MENU.MENU_ITEMS.UPLOAD_FILE",
|
|
||||||
"description": "APP.NEW_MENU.TOOLTIPS.UPLOAD_FILES",
|
|
||||||
"description-disabled": "APP.NEW_MENU.TOOLTIPS.UPLOAD_FILES_NOT_ALLOWED",
|
|
||||||
"actions": {
|
|
||||||
"click": "UPLOAD_FILES"
|
|
||||||
},
|
|
||||||
"rules": {
|
|
||||||
"enabled": "app.navigation.folder.canUpload",
|
|
||||||
"visible": "app.isContentServiceEnabled"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": "app.create.uploadFolder",
|
|
||||||
"order": 200,
|
|
||||||
"icon": "file_upload",
|
|
||||||
"title": "APP.NEW_MENU.MENU_ITEMS.UPLOAD_FOLDER",
|
|
||||||
"description": "APP.NEW_MENU.TOOLTIPS.UPLOAD_FOLDERS",
|
|
||||||
"description-disabled": "APP.NEW_MENU.TOOLTIPS.UPLOAD_FOLDERS_NOT_ALLOWED",
|
|
||||||
"actions": {
|
|
||||||
"click": "UPLOAD_FOLDER"
|
|
||||||
},
|
|
||||||
"rules": {
|
|
||||||
"enabled": "app.navigation.folder.canUpload",
|
|
||||||
"visible": "app.isContentServiceEnabled"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": "app.create.separator.1",
|
|
||||||
"type": "separator",
|
|
||||||
"order": 300,
|
|
||||||
"rules": {
|
|
||||||
"visible": "app.isContentServiceEnabled"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"id": "app.create.folder",
|
"id": "app.create.folder",
|
||||||
"order": 400,
|
"order": 400,
|
||||||
@@ -198,14 +160,6 @@
|
|||||||
"visible": "app.isContentServiceEnabled"
|
"visible": "app.isContentServiceEnabled"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"id": "app.create.separator.2",
|
|
||||||
"type": "separator",
|
|
||||||
"order": 650,
|
|
||||||
"rules": {
|
|
||||||
"visible": "app.isContentServiceEnabled"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"id": "app.create.fileFromTemplate",
|
"id": "app.create.fileFromTemplate",
|
||||||
"order": 700,
|
"order": 700,
|
||||||
@@ -237,6 +191,38 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
"upload": [
|
||||||
|
{
|
||||||
|
"id": "app.create.uploadFile",
|
||||||
|
"order": 100,
|
||||||
|
"icon": "file_upload",
|
||||||
|
"title": "APP.NEW_MENU.MENU_ITEMS.UPLOAD_FILE",
|
||||||
|
"description": "APP.NEW_MENU.TOOLTIPS.UPLOAD_FILES",
|
||||||
|
"description-disabled": "APP.NEW_MENU.TOOLTIPS.UPLOAD_FILES_NOT_ALLOWED",
|
||||||
|
"actions": {
|
||||||
|
"click": "UPLOAD_FILES"
|
||||||
|
},
|
||||||
|
"rules": {
|
||||||
|
"enabled": "app.navigation.folder.canUpload",
|
||||||
|
"visible": "app.isContentServiceEnabled"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "app.create.uploadFolder",
|
||||||
|
"order": 200,
|
||||||
|
"icon": "file_upload",
|
||||||
|
"title": "APP.NEW_MENU.MENU_ITEMS.UPLOAD_FOLDER",
|
||||||
|
"description": "APP.NEW_MENU.TOOLTIPS.UPLOAD_FOLDERS",
|
||||||
|
"description-disabled": "APP.NEW_MENU.TOOLTIPS.UPLOAD_FOLDERS_NOT_ALLOWED",
|
||||||
|
"actions": {
|
||||||
|
"click": "UPLOAD_FOLDER"
|
||||||
|
},
|
||||||
|
"rules": {
|
||||||
|
"enabled": "app.navigation.folder.canUpload",
|
||||||
|
"visible": "app.isContentServiceEnabled"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
"navbar": [
|
"navbar": [
|
||||||
{
|
{
|
||||||
"id": "app.navbar.primary",
|
"id": "app.navbar.primary",
|
||||||
|
@@ -103,6 +103,12 @@
|
|||||||
"CREATE_LIBRARY": "Create a new File Library"
|
"CREATE_LIBRARY": "Create a new File Library"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"HEADER": {
|
||||||
|
"BUTTONS": {
|
||||||
|
"CREATE": "Create",
|
||||||
|
"UPLOAD": "Upload"
|
||||||
|
}
|
||||||
|
},
|
||||||
"BROWSE": {
|
"BROWSE": {
|
||||||
"FILE": {
|
"FILE": {
|
||||||
"TITLE": "Files",
|
"TITLE": "Files",
|
||||||
|
@@ -122,6 +122,7 @@ import { AcaFolderRulesModule } from '@alfresco/aca-folder-rules';
|
|||||||
import { TagsColumnComponent } from './components/dl-custom-components/tags-column/tags-column.component';
|
import { TagsColumnComponent } from './components/dl-custom-components/tags-column/tags-column.component';
|
||||||
import { UserInfoComponent } from './components/common/user-info/user-info.component';
|
import { UserInfoComponent } from './components/common/user-info/user-info.component';
|
||||||
import { CustomIconsModule } from './extensions/custom-icons.module';
|
import { CustomIconsModule } from './extensions/custom-icons.module';
|
||||||
|
import { AppHeaderActionsModule } from './components/header-actions/header-actions.module';
|
||||||
|
|
||||||
registerLocaleData(localeFr);
|
registerLocaleData(localeFr);
|
||||||
registerLocaleData(localeDe);
|
registerLocaleData(localeDe);
|
||||||
@@ -163,6 +164,7 @@ registerLocaleData(localeSv);
|
|||||||
AppCreateMenuModule,
|
AppCreateMenuModule,
|
||||||
DocumentListCustomComponentsModule,
|
DocumentListCustomComponentsModule,
|
||||||
AppSearchInputModule,
|
AppSearchInputModule,
|
||||||
|
AppHeaderActionsModule,
|
||||||
AppSearchResultsModule,
|
AppSearchResultsModule,
|
||||||
AppHeaderModule,
|
AppHeaderModule,
|
||||||
AppNodeVersionModule,
|
AppNodeVersionModule,
|
||||||
|
@@ -1,7 +1,7 @@
|
|||||||
<aca-page-layout>
|
<aca-page-layout>
|
||||||
<aca-page-layout-header>
|
<aca-page-layout-header>
|
||||||
<adf-breadcrumb root="APP.BROWSE.LIBRARIES.MENU.FAVORITE_LIBRARIES.TITLE"> </adf-breadcrumb>
|
<adf-breadcrumb root="APP.BROWSE.LIBRARIES.MENU.FAVORITE_LIBRARIES.TITLE"> </adf-breadcrumb>
|
||||||
|
<aca-header-actions></aca-header-actions>
|
||||||
<adf-toolbar class="adf-toolbar--inline">
|
<adf-toolbar class="adf-toolbar--inline">
|
||||||
<ng-container *ngFor="let entry of actions; trackBy: trackByActionId">
|
<ng-container *ngFor="let entry of actions; trackBy: trackByActionId">
|
||||||
<aca-toolbar-action [actionRef]="entry"></aca-toolbar-action>
|
<aca-toolbar-action [actionRef]="entry"></aca-toolbar-action>
|
||||||
|
@@ -1,7 +1,7 @@
|
|||||||
<aca-page-layout>
|
<aca-page-layout>
|
||||||
<aca-page-layout-header>
|
<aca-page-layout-header>
|
||||||
<adf-breadcrumb root="APP.BROWSE.FAVORITES.TITLE"> </adf-breadcrumb>
|
<adf-breadcrumb root="APP.BROWSE.FAVORITES.TITLE"> </adf-breadcrumb>
|
||||||
|
<aca-header-actions></aca-header-actions>
|
||||||
<adf-toolbar class="adf-toolbar--inline">
|
<adf-toolbar class="adf-toolbar--inline">
|
||||||
<ng-container *ngFor="let entry of actions; trackBy: trackByActionId">
|
<ng-container *ngFor="let entry of actions; trackBy: trackByActionId">
|
||||||
<aca-toolbar-action [actionRef]="entry"></aca-toolbar-action>
|
<aca-toolbar-action [actionRef]="entry"></aca-toolbar-action>
|
||||||
|
@@ -1,7 +1,7 @@
|
|||||||
<aca-page-layout [hasError]="!isValidPath">
|
<aca-page-layout [hasError]="!isValidPath">
|
||||||
<aca-page-layout-header>
|
<aca-page-layout-header>
|
||||||
<adf-breadcrumb [root]="title" [folderNode]="node" [maxItems]="isSmallScreen ? 1 : 0" (navigate)="onBreadcrumbNavigate($event)"> </adf-breadcrumb>
|
<adf-breadcrumb [root]="title" [folderNode]="node" [maxItems]="isSmallScreen ? 1 : 0" (navigate)="onBreadcrumbNavigate($event)"> </adf-breadcrumb>
|
||||||
|
<aca-header-actions></aca-header-actions>
|
||||||
<adf-toolbar class="adf-toolbar--inline">
|
<adf-toolbar class="adf-toolbar--inline">
|
||||||
<ng-container *ngFor="let entry of actions; trackBy: trackByActionId">
|
<ng-container *ngFor="let entry of actions; trackBy: trackByActionId">
|
||||||
<aca-toolbar-action [actionRef]="entry"></aca-toolbar-action>
|
<aca-toolbar-action [actionRef]="entry"></aca-toolbar-action>
|
||||||
|
@@ -0,0 +1,33 @@
|
|||||||
|
<div>
|
||||||
|
<div class="adf-toolbar--spacer adf-toolbar-divider"></div>
|
||||||
|
<span class="action-bar">
|
||||||
|
<button class="aca-mat-button aca-create-button" mat-stroked-button data-automation-id="create-button"
|
||||||
|
*ngIf="canShowCreateButton()"
|
||||||
|
[matMenuTriggerFor]="createMenu">
|
||||||
|
{{ 'APP.HEADER.BUTTONS.CREATE' | translate }}
|
||||||
|
</button>
|
||||||
|
<mat-menu #createMenu="matMenu" role="menu" class="app-create-menu__root-menu app-create-menu__sub-menu"
|
||||||
|
[overlapTrigger]="false" yPosition="below">
|
||||||
|
<div *ngFor="let action of createActions; trackBy: trackByActionId">
|
||||||
|
<app-toolbar-menu-item [actionRef]="action"></app-toolbar-menu-item>
|
||||||
|
</div>
|
||||||
|
</mat-menu>
|
||||||
|
|
||||||
|
<button class="aca-mat-button aca-upload-button" mat-stroked-button data-automation-id="upload-button"
|
||||||
|
*ngIf="canShowUploadButton()" [matMenuTriggerFor]="uploadMenu">
|
||||||
|
{{ 'APP.HEADER.BUTTONS.UPLOAD' | translate }}
|
||||||
|
</button>
|
||||||
|
<mat-menu #uploadMenu="matMenu" role="menu" class="app-upload-menu__root-menu app-upload-menu__sub-menu"
|
||||||
|
[overlapTrigger]="false" yPosition="below">
|
||||||
|
<div *ngFor="let action of uploadActions; trackBy: trackByActionId">
|
||||||
|
<app-toolbar-menu-item [actionRef]="action"></app-toolbar-menu-item>
|
||||||
|
</div>
|
||||||
|
</mat-menu>
|
||||||
|
|
||||||
|
<app-main-action *ngIf="isTasksRoute() || isProcessesRoute()"></app-main-action>
|
||||||
|
|
||||||
|
<adf-toolbar-divider *ngIf="canShowSearchSeparator()">
|
||||||
|
</adf-toolbar-divider>
|
||||||
|
<aca-search-input class="app-search-input"></aca-search-input>
|
||||||
|
</span>
|
||||||
|
</div>
|
@@ -0,0 +1,80 @@
|
|||||||
|
.aca-page-layout-header {
|
||||||
|
// display: flex;
|
||||||
|
// align-items: center;
|
||||||
|
// flex: 0 0 65px;
|
||||||
|
// flex-basis: 96px;
|
||||||
|
// background: var(--theme-page-layout-header-background-color);
|
||||||
|
// border-bottom: 1px solid var(--theme-border-color, rgba(0, 0, 0, 0.07));
|
||||||
|
// padding: 0 24px;
|
||||||
|
|
||||||
|
.adf-breadcrumb-item {
|
||||||
|
font-size: 20px !important;
|
||||||
|
font-weight: 400 !important;
|
||||||
|
letter-spacing: 0.15px !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.app-search-input {
|
||||||
|
background: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.action-bar {
|
||||||
|
display: flex;
|
||||||
|
flex: auto;
|
||||||
|
height: 32px;
|
||||||
|
margin-left: 24px;
|
||||||
|
|
||||||
|
adf-toolbar-divider {
|
||||||
|
width: 24px !important;
|
||||||
|
height: 32px !important;
|
||||||
|
margin: 4px 0 0 12px !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.aca-mat-button {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
letter-spacing: 0.25px;
|
||||||
|
font-weight: 500;
|
||||||
|
font-size: 14px;
|
||||||
|
font-style: normal;
|
||||||
|
border-radius: 6px;
|
||||||
|
border: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.aca-create-button {
|
||||||
|
width: 71px !important;
|
||||||
|
min-width: 71px;
|
||||||
|
height: 32px;
|
||||||
|
background-color: var(--theme-create-button-background-color);
|
||||||
|
color: var(--theme-create-button-text-color);
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
display: flex;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.aca-upload-button {
|
||||||
|
width: 73px !important;
|
||||||
|
min-width: 73px;
|
||||||
|
height: 32px;
|
||||||
|
background-color: var(--theme-upload-button-background-color);
|
||||||
|
color: var(--theme-upload-button-text-color);
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
display: flex;
|
||||||
|
padding: 0;
|
||||||
|
margin-left: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
// .aca-process-button {
|
||||||
|
// width: 130px !important;
|
||||||
|
// min-width: 130px;
|
||||||
|
// height: 32px;
|
||||||
|
// background-color: var(--theme-upload-button-background-color);
|
||||||
|
// color: var(--theme-upload-button-text-color);
|
||||||
|
// text-overflow: ellipsis;
|
||||||
|
// display: flex;
|
||||||
|
// padding: 0;
|
||||||
|
// margin-left: 12px;
|
||||||
|
// }
|
||||||
|
}
|
@@ -0,0 +1,109 @@
|
|||||||
|
/*!
|
||||||
|
* @license
|
||||||
|
* Copyright 2019 Alfresco Software, Ltd.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||||
|
import { AppTestingModule } from '../../testing/app-testing.module';
|
||||||
|
import { HeaderActionsComponent } from './header-actions.component';
|
||||||
|
import { HarnessLoader } from '@angular/cdk/testing';
|
||||||
|
import { TestbedHarnessEnvironment } from '@angular/cdk/testing/testbed';
|
||||||
|
import { MatButtonHarness } from '@angular/material/button/testing';
|
||||||
|
import { MatMenuHarness } from '@angular/material/menu/testing';
|
||||||
|
import { NoopAnimationsModule } from '@angular/platform-browser/animations';
|
||||||
|
import { MatButtonModule } from '@angular/material/button';
|
||||||
|
import { MatMenuModule } from '@angular/material/menu';
|
||||||
|
import { By } from '@angular/platform-browser';
|
||||||
|
|
||||||
|
describe('HeaderActionsComponent', () => {
|
||||||
|
let component: HeaderActionsComponent;
|
||||||
|
let fixture: ComponentFixture<HeaderActionsComponent>;
|
||||||
|
let loader: HarnessLoader;
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
TestBed.configureTestingModule({
|
||||||
|
imports: [AppTestingModule, NoopAnimationsModule, MatButtonModule, MatMenuModule],
|
||||||
|
declarations: [HeaderActionsComponent]
|
||||||
|
});
|
||||||
|
|
||||||
|
fixture = TestBed.createComponent(HeaderActionsComponent);
|
||||||
|
component = fixture.componentInstance;
|
||||||
|
loader = TestbedHarnessEnvironment.loader(fixture);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('total number of buttons in header should be 2 if route is personal-files', async () => {
|
||||||
|
spyOn(component, 'isPersonalFilesRoute').and.returnValue(true);
|
||||||
|
const buttons = await loader.getAllHarnesses(MatButtonHarness);
|
||||||
|
const createButton = await loader.getAllHarnesses(MatButtonHarness.with({text: 'APP.HEADER.BUTTONS.CREATE'}));
|
||||||
|
const uploadButton = await loader.getAllHarnesses(MatButtonHarness.with({text: 'APP.HEADER.BUTTONS.UPLOAD'}));
|
||||||
|
|
||||||
|
expect(buttons.length).toBe(2);
|
||||||
|
expect(createButton.length).toBe(1);
|
||||||
|
expect(uploadButton.length).toBe(1);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('total number of buttons in header should be 1 if route is libraries', async () => {
|
||||||
|
spyOn(component, 'isLibrariesRoute').and.returnValue(true);
|
||||||
|
const buttons = await loader.getAllHarnesses(MatButtonHarness);
|
||||||
|
const createButton = await loader.getAllHarnesses(MatButtonHarness.with({text: 'APP.HEADER.BUTTONS.CREATE'}));
|
||||||
|
|
||||||
|
expect(buttons.length).toBe(1);
|
||||||
|
expect(createButton.length).toBe(1);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should open and close the create menu', async () => {
|
||||||
|
spyOn(component, 'isPersonalFilesRoute').and.returnValue(true);
|
||||||
|
const createMenu = await loader.getHarness(MatMenuHarness.with({ triggerText: 'APP.HEADER.BUTTONS.CREATE' }));
|
||||||
|
|
||||||
|
expect(await createMenu.isOpen()).toBe(false);
|
||||||
|
await createMenu.open();
|
||||||
|
expect(await createMenu.isOpen()).toBe(true);
|
||||||
|
|
||||||
|
await createMenu.close();
|
||||||
|
expect(await createMenu.isOpen()).toBe(false);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should open and close the upload menu', async () => {
|
||||||
|
spyOn(component, 'isPersonalFilesRoute').and.returnValue(true);
|
||||||
|
const uploadMenu = await loader.getHarness(MatMenuHarness.with({ triggerText: 'APP.HEADER.BUTTONS.UPLOAD' }));
|
||||||
|
|
||||||
|
expect(await uploadMenu.isOpen()).toBe(false);
|
||||||
|
await uploadMenu.open();
|
||||||
|
expect(await uploadMenu.isOpen()).toBe(true);
|
||||||
|
|
||||||
|
await uploadMenu.close();
|
||||||
|
expect(await uploadMenu.isOpen()).toBe(false);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should load create menu on click of create button', async () => {
|
||||||
|
spyOn(component, 'isPersonalFilesRoute').and.returnValue(true);
|
||||||
|
|
||||||
|
const buttons = await loader.getHarness(MatButtonHarness.with({ selector: '.aca-create-button' }));
|
||||||
|
buttons.click();
|
||||||
|
|
||||||
|
const createMenu = fixture.debugElement.queryAll(By.css('.app-create-menu__root-menu app-create-menu__sub-menu'));
|
||||||
|
expect(createMenu).toBeTruthy();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should load upload menu on click of upload button', async () => {
|
||||||
|
spyOn(component, 'isPersonalFilesRoute').and.returnValue(true);
|
||||||
|
|
||||||
|
const buttons = await loader.getHarness(MatButtonHarness.with({ selector: '.aca-upload-button' }));
|
||||||
|
buttons.click();
|
||||||
|
|
||||||
|
const uploadMenu = fixture.debugElement.queryAll(By.css('.app-upload-menu__root-menu app-upload-menu__sub-menu'));
|
||||||
|
expect(uploadMenu).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
@@ -0,0 +1,96 @@
|
|||||||
|
/*!
|
||||||
|
* @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 <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { Component, OnDestroy, OnInit, ViewEncapsulation } from '@angular/core';
|
||||||
|
import { Router } from '@angular/router';
|
||||||
|
import { Store } from '@ngrx/store';
|
||||||
|
import { ContentManagementService } from '../../services/content-management.service';
|
||||||
|
import { AppExtensionService, PageComponent } from '@alfresco/aca-shared';
|
||||||
|
import { SetCurrentFolderAction, AppStore } from '@alfresco/aca-shared/store';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'aca-header-actions',
|
||||||
|
templateUrl: './header-actions.component.html',
|
||||||
|
styleUrls: ['./header-actions.component.scss'],
|
||||||
|
encapsulation: ViewEncapsulation.None
|
||||||
|
})
|
||||||
|
export class HeaderActionsComponent extends PageComponent implements OnInit, OnDestroy {
|
||||||
|
constructor(private router: Router, store: Store<AppStore>, content: ContentManagementService, extensions: AppExtensionService) {
|
||||||
|
super(store, extensions, content);
|
||||||
|
}
|
||||||
|
|
||||||
|
ngOnInit() {
|
||||||
|
super.ngOnInit();
|
||||||
|
}
|
||||||
|
|
||||||
|
ngOnDestroy() {
|
||||||
|
this.store.dispatch(new SetCurrentFolderAction(null));
|
||||||
|
super.ngOnDestroy();
|
||||||
|
}
|
||||||
|
|
||||||
|
isPersonalFilesRoute(): boolean {
|
||||||
|
return this.router.url.includes('/personal-files');
|
||||||
|
}
|
||||||
|
|
||||||
|
isFavoriteLibrariesRoute(): boolean {
|
||||||
|
return this.router.url.includes('/favorite/libraries');
|
||||||
|
}
|
||||||
|
|
||||||
|
isLibrariesRoute(): boolean {
|
||||||
|
return this.router.url.includes('/libraries');
|
||||||
|
}
|
||||||
|
|
||||||
|
canShowCreateButton(): boolean {
|
||||||
|
if (this.isPersonalFilesRoute() || this.isFavoriteLibrariesRoute() || this.isLibrariesRoute()) {
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
canShowUploadButton(): boolean {
|
||||||
|
if (this.isPersonalFilesRoute()) {
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
canShowSearchSeparator(): boolean {
|
||||||
|
if (this.isPersonalFilesRoute() || this.isFavoriteLibrariesRoute() || this.isLibrariesRoute()) {
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
isTasksRoute(): boolean {
|
||||||
|
return this.router.url.includes('/tasks');
|
||||||
|
}
|
||||||
|
|
||||||
|
isProcessesRoute(): boolean {
|
||||||
|
return this.router.url.includes('/processes');
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,55 @@
|
|||||||
|
/*!
|
||||||
|
* @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 <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { NgModule } from '@angular/core';
|
||||||
|
import { CommonModule } from '@angular/common';
|
||||||
|
import { CoreModule } from '@alfresco/adf-core';
|
||||||
|
import { ContentModule } from '@alfresco/adf-content-services';
|
||||||
|
import { AppCommonModule } from '../common/common.module';
|
||||||
|
import { AppToolbarModule } from '../toolbar/toolbar.module';
|
||||||
|
import { DirectivesModule } from '../../directives/directives.module';
|
||||||
|
import { ContextMenuModule } from '../context-menu/context-menu.module';
|
||||||
|
import { AppLayoutModule } from '../layout/layout.module';
|
||||||
|
import { AppSearchInputModule } from '../search/search-input.module';
|
||||||
|
import { HeaderActionsComponent } from './header-actions.component';
|
||||||
|
import { MainActionModule } from '../main-action/main-action.module';
|
||||||
|
|
||||||
|
@NgModule({
|
||||||
|
imports: [
|
||||||
|
CommonModule,
|
||||||
|
CoreModule.forChild(),
|
||||||
|
ContentModule.forChild(),
|
||||||
|
DirectivesModule,
|
||||||
|
AppCommonModule,
|
||||||
|
AppToolbarModule,
|
||||||
|
ContextMenuModule,
|
||||||
|
AppLayoutModule,
|
||||||
|
AppSearchInputModule,
|
||||||
|
MainActionModule
|
||||||
|
],
|
||||||
|
declarations: [HeaderActionsComponent],
|
||||||
|
exports: [HeaderActionsComponent]
|
||||||
|
})
|
||||||
|
export class AppHeaderActionsModule {}
|
@@ -1,7 +1,7 @@
|
|||||||
<aca-page-layout>
|
<aca-page-layout>
|
||||||
<aca-page-layout-header>
|
<aca-page-layout-header>
|
||||||
<adf-breadcrumb root="APP.BROWSE.LIBRARIES.MENU.MY_LIBRARIES.TITLE"> </adf-breadcrumb>
|
<adf-breadcrumb root="APP.BROWSE.LIBRARIES.MENU.MY_LIBRARIES.TITLE"> </adf-breadcrumb>
|
||||||
|
<aca-header-actions></aca-header-actions>
|
||||||
<adf-toolbar class="adf-toolbar--inline">
|
<adf-toolbar class="adf-toolbar--inline">
|
||||||
<ng-container *ngFor="let entry of actions; trackBy: trackByActionId">
|
<ng-container *ngFor="let entry of actions; trackBy: trackByActionId">
|
||||||
<aca-toolbar-action [actionRef]="entry"></aca-toolbar-action>
|
<aca-toolbar-action [actionRef]="entry"></aca-toolbar-action>
|
||||||
|
@@ -1,7 +1,7 @@
|
|||||||
<aca-page-layout>
|
<aca-page-layout>
|
||||||
<aca-page-layout-header>
|
<aca-page-layout-header>
|
||||||
<adf-breadcrumb root="APP.BROWSE.RECENT.TITLE"> </adf-breadcrumb>
|
<adf-breadcrumb root="APP.BROWSE.RECENT.TITLE"> </adf-breadcrumb>
|
||||||
|
<aca-header-actions></aca-header-actions>
|
||||||
<adf-toolbar class="adf-toolbar--inline">
|
<adf-toolbar class="adf-toolbar--inline">
|
||||||
<ng-container *ngFor="let entry of actions; trackBy: trackByActionId">
|
<ng-container *ngFor="let entry of actions; trackBy: trackByActionId">
|
||||||
<aca-toolbar-action [actionRef]="entry"></aca-toolbar-action>
|
<aca-toolbar-action [actionRef]="entry"></aca-toolbar-action>
|
||||||
|
@@ -6,6 +6,7 @@ $top-margin: 12px;
|
|||||||
font-size: 16px;
|
font-size: 16px;
|
||||||
padding-left: 15px;
|
padding-left: 15px;
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
|
margin-bottom: 12px !important;
|
||||||
|
|
||||||
.mat-form-field {
|
.mat-form-field {
|
||||||
font-size: 16px;
|
font-size: 16px;
|
||||||
|
@@ -0,0 +1,66 @@
|
|||||||
|
/*!
|
||||||
|
* @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 <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { TestBed } from '@angular/core/testing';
|
||||||
|
import { CoreModule } from '@alfresco/adf-core';
|
||||||
|
import { TranslateModule } from '@ngx-translate/core';
|
||||||
|
import { SearchInputService } from './search-input.service';
|
||||||
|
import { Router } from '@angular/router';
|
||||||
|
|
||||||
|
describe('SearchInputService', () => {
|
||||||
|
let service: SearchInputService;
|
||||||
|
let router: Router;
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
TestBed.configureTestingModule({
|
||||||
|
imports: [TranslateModule.forRoot(), CoreModule.forRoot()]
|
||||||
|
});
|
||||||
|
service = TestBed.inject(SearchInputService);
|
||||||
|
router = TestBed.inject(Router);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should not navigate to saved route when exitSearch function is called if saved route is null', () => {
|
||||||
|
const routerNavigate = spyOn(router, 'navigate');
|
||||||
|
service.savedRoute = '';
|
||||||
|
service.exitSearch();
|
||||||
|
|
||||||
|
expect(routerNavigate).not.toHaveBeenCalledWith([service.savedRoute]);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should navigate to saved route when exitSearch function is called', () => {
|
||||||
|
const routerNavigate = spyOn(router, 'navigate');
|
||||||
|
service.savedRoute = '/personal-files';
|
||||||
|
service.exitSearch();
|
||||||
|
|
||||||
|
expect(routerNavigate).toHaveBeenCalledWith([service.savedRoute]);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should navigate to Search when navigateToSearch function is called', () => {
|
||||||
|
const routerNavigate = spyOn(router, 'navigate');
|
||||||
|
service.navigateToSearch();
|
||||||
|
|
||||||
|
expect(routerNavigate).toHaveBeenCalledWith(['/search']);
|
||||||
|
});
|
||||||
|
});
|
@@ -0,0 +1,55 @@
|
|||||||
|
/*!
|
||||||
|
* @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 <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { Injectable } from '@angular/core';
|
||||||
|
import { Router } from '@angular/router';
|
||||||
|
|
||||||
|
@Injectable({
|
||||||
|
providedIn: 'root'
|
||||||
|
})
|
||||||
|
export class SearchInputService {
|
||||||
|
savedRoute = '';
|
||||||
|
|
||||||
|
constructor(private router: Router) {}
|
||||||
|
|
||||||
|
isSearchRoute(): boolean {
|
||||||
|
return this.router.url.includes('/search');
|
||||||
|
}
|
||||||
|
|
||||||
|
saveRoute(route: string) {
|
||||||
|
this.savedRoute = route;
|
||||||
|
}
|
||||||
|
|
||||||
|
exitSearch() {
|
||||||
|
if (this.savedRoute.length > 0) {
|
||||||
|
this.router.navigate([this.savedRoute]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
navigateToSearch() {
|
||||||
|
this.saveRoute(this.router.url);
|
||||||
|
this.router.navigate(['/search']);
|
||||||
|
}
|
||||||
|
}
|
@@ -1,13 +1,14 @@
|
|||||||
<div
|
<div *ngIf="searchInputService.isSearchRoute()"
|
||||||
class="app-search-container searchMenuTrigger"
|
class="app-search-container searchMenuTrigger"
|
||||||
[matMenuTriggerFor]="searchOptionsMenu"
|
[matMenuTriggerFor]="searchOptionsMenu"
|
||||||
(menuOpened)="onMenuOpened()"
|
(menuOpened)="onMenuOpened()"
|
||||||
(menuClosed)="syncInputValues()"
|
(menuClosed)="syncInputValues()"
|
||||||
>
|
>
|
||||||
|
|
||||||
<button mat-icon-button class="app-search-button" (click)="searchByOption()" [title]="'SEARCH.BUTTON.TOOLTIP' | translate">
|
<button mat-icon-button class="app-search-button" (click)="searchByOption()" [title]="'SEARCH.BUTTON.TOOLTIP' | translate">
|
||||||
<mat-icon [attr.aria-label]="'SEARCH.BUTTON.ARIA-LABEL' | translate">search</mat-icon>
|
<mat-icon [attr.aria-label]="'SEARCH.BUTTON.ARIA-LABEL' | translate">search</mat-icon>
|
||||||
</button>
|
</button>
|
||||||
<mat-form-field class="app-input-form-field" [floatLabel]="'never'">
|
<mat-form-field class="app-input-form-field" [floatLabel]="'never'">
|
||||||
<input
|
<input
|
||||||
matInput
|
matInput
|
||||||
[attr.aria-label]="'SEARCH.INPUT.ARIA-LABEL' | translate"
|
[attr.aria-label]="'SEARCH.INPUT.ARIA-LABEL' | translate"
|
||||||
@@ -20,9 +21,20 @@
|
|||||||
<div matSuffix class="app-suffix-search-icon-wrapper">
|
<div matSuffix class="app-suffix-search-icon-wrapper">
|
||||||
<mat-icon>arrow_drop_down</mat-icon>
|
<mat-icon>arrow_drop_down</mat-icon>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<button mat-icon-button matSuffix class="app-suffix-search-icon-wrapper app-close-icon" (click)="exitSearch()" (keypressk)="exitSearch()">
|
||||||
|
<mat-icon>close</mat-icon>
|
||||||
|
</button>
|
||||||
</mat-form-field>
|
</mat-form-field>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div *ngIf="!searchInputService.isSearchRoute()"
|
||||||
|
class="app-search-container">
|
||||||
|
<button mat-icon-button class="app-search-button" (click)="navigateToSearch()" [title]="'SEARCH.BUTTON.TOOLTIP' | translate">
|
||||||
|
<mat-icon [attr.aria-label]="'SEARCH.BUTTON.ARIA-LABEL' | translate">search</mat-icon>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
<mat-menu #searchOptionsMenu="matMenu" [overlapTrigger]="true" class="app-search-options-menu">
|
<mat-menu #searchOptionsMenu="matMenu" [overlapTrigger]="true" class="app-search-options-menu">
|
||||||
<div (keydown.tab)="$event.stopPropagation()" (keydown.shift.tab)="$event.stopPropagation()">
|
<div (keydown.tab)="$event.stopPropagation()" (keydown.shift.tab)="$event.stopPropagation()">
|
||||||
<div cdkTrapFocus>
|
<div cdkTrapFocus>
|
||||||
|
@@ -1,13 +1,33 @@
|
|||||||
$search-width: 594px;
|
$search-width: 594px;
|
||||||
$search-height: 40px;
|
$search-height: 32px;
|
||||||
$search-background: #f5f6f5;
|
$search-background: #f5f6f5;
|
||||||
$search-border-radius: 4px;
|
$search-border-radius: 4px;
|
||||||
$top-margin: 12px;
|
$top-margin: 12px;
|
||||||
|
|
||||||
.app-search-container {
|
.app-search-container {
|
||||||
color: var(--theme-foreground-text-color);
|
color: var(--theme-foreground-text-color);
|
||||||
|
max-width: 100%;
|
||||||
|
margin: 0 !important;
|
||||||
|
|
||||||
|
.app-search-button {
|
||||||
|
width: 32px !important;
|
||||||
|
height: 32px !important;
|
||||||
|
margin-left: 0 !important;
|
||||||
|
padding-left: 0 !important;
|
||||||
|
margin-top: -4px !important;
|
||||||
|
}
|
||||||
|
|
||||||
.app-input-form-field {
|
.app-input-form-field {
|
||||||
|
|
||||||
|
.app-close-icon {
|
||||||
|
height: 6px;
|
||||||
|
|
||||||
|
.mat-icon {
|
||||||
|
font-size: 18px !important;
|
||||||
|
line-height: 28px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.mat-input-element {
|
.mat-input-element {
|
||||||
caret-color: var(--theme-text-color);
|
caret-color: var(--theme-text-color);
|
||||||
|
|
||||||
@@ -54,6 +74,8 @@ mat-checkbox {
|
|||||||
background-color: $search-background;
|
background-color: $search-background;
|
||||||
border-radius: $search-border-radius;
|
border-radius: $search-border-radius;
|
||||||
height: $search-height;
|
height: $search-height;
|
||||||
|
margin-bottom: 0 !important;
|
||||||
|
padding-bottom: 26px !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
.app-search-container {
|
.app-search-container {
|
||||||
|
@@ -32,12 +32,14 @@ import { SearchByTermAction, SearchActionTypes, SnackbarErrorAction, SnackbarAct
|
|||||||
import { AppHookService } from '@alfresco/aca-shared';
|
import { AppHookService } from '@alfresco/aca-shared';
|
||||||
import { map } from 'rxjs/operators';
|
import { map } from 'rxjs/operators';
|
||||||
import { SearchQueryBuilderService } from '@alfresco/adf-content-services';
|
import { SearchQueryBuilderService } from '@alfresco/adf-content-services';
|
||||||
|
import { SearchInputService } from '../search-input.service';
|
||||||
|
|
||||||
describe('SearchInputComponent', () => {
|
describe('SearchInputComponent', () => {
|
||||||
let fixture: ComponentFixture<SearchInputComponent>;
|
let fixture: ComponentFixture<SearchInputComponent>;
|
||||||
let component: SearchInputComponent;
|
let component: SearchInputComponent;
|
||||||
let actions$: Actions;
|
let actions$: Actions;
|
||||||
let appHookService: AppHookService;
|
let appHookService: AppHookService;
|
||||||
|
let searchInputService: SearchInputService;
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
TestBed.configureTestingModule({
|
TestBed.configureTestingModule({
|
||||||
@@ -50,12 +52,21 @@ describe('SearchInputComponent', () => {
|
|||||||
actions$ = TestBed.inject(Actions);
|
actions$ = TestBed.inject(Actions);
|
||||||
fixture = TestBed.createComponent(SearchInputComponent);
|
fixture = TestBed.createComponent(SearchInputComponent);
|
||||||
appHookService = TestBed.inject(AppHookService);
|
appHookService = TestBed.inject(AppHookService);
|
||||||
|
searchInputService = TestBed.inject(SearchInputService);
|
||||||
component = fixture.componentInstance;
|
component = fixture.componentInstance;
|
||||||
fixture.detectChanges();
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should change flag on library400Error event', () => {
|
afterEach(() => {
|
||||||
|
fixture.destroy();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should change flag on library400Error event', async () => {
|
||||||
|
spyOn(searchInputService, 'isSearchRoute').and.returnValue(true);
|
||||||
|
fixture.detectChanges();
|
||||||
|
await fixture.whenStable();
|
||||||
|
|
||||||
expect(component.has400LibraryError).toBe(false);
|
expect(component.has400LibraryError).toBe(false);
|
||||||
|
|
||||||
appHookService.library400Error.next();
|
appHookService.library400Error.next();
|
||||||
|
|
||||||
expect(component.has400LibraryError).toBe(true);
|
expect(component.has400LibraryError).toBe(true);
|
||||||
@@ -65,9 +76,14 @@ describe('SearchInputComponent', () => {
|
|||||||
expect(component.hasLibraryConstraint()).toBe(false);
|
expect(component.hasLibraryConstraint()).toBe(false);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should have library constraint on 400 error received', () => {
|
it('should have library constraint on 400 error received', async () => {
|
||||||
|
spyOn(searchInputService, 'isSearchRoute').and.returnValue(true);
|
||||||
|
fixture.detectChanges();
|
||||||
|
await fixture.whenStable();
|
||||||
|
|
||||||
const libItem = component.searchOptions.find((item) => item.key.toLowerCase().indexOf('libraries') > 0);
|
const libItem = component.searchOptions.find((item) => item.key.toLowerCase().indexOf('libraries') > 0);
|
||||||
libItem.value = true;
|
libItem.value = true;
|
||||||
|
|
||||||
appHookService.library400Error.next();
|
appHookService.library400Error.next();
|
||||||
|
|
||||||
expect(component.hasLibraryConstraint()).toBe(true);
|
expect(component.hasLibraryConstraint()).toBe(true);
|
||||||
@@ -193,4 +209,44 @@ describe('SearchInputComponent', () => {
|
|||||||
expect(component.isContentChecked()).toBe(true);
|
expect(component.isContentChecked()).toBe(true);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('navigateToSearch()', () => {
|
||||||
|
it('should navigate to search on click of search icon', async () => {
|
||||||
|
spyOn(searchInputService, 'isSearchRoute').and.returnValue(false);
|
||||||
|
spyOn(component, 'navigateToSearch').and.callThrough();
|
||||||
|
spyOn(searchInputService, 'navigateToSearch').and.callThrough();
|
||||||
|
|
||||||
|
fixture.detectChanges();
|
||||||
|
await fixture.whenStable();
|
||||||
|
|
||||||
|
const searchIcon = fixture.debugElement.nativeElement.querySelector('.app-search-button');
|
||||||
|
searchIcon.click();
|
||||||
|
|
||||||
|
fixture.detectChanges();
|
||||||
|
await fixture.whenStable();
|
||||||
|
|
||||||
|
expect(component.navigateToSearch).toHaveBeenCalled();
|
||||||
|
expect(searchInputService.navigateToSearch).toHaveBeenCalledWith();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('exitSearch()', () => {
|
||||||
|
it('should exit search on click of close icon', async () => {
|
||||||
|
spyOn(searchInputService, 'isSearchRoute').and.returnValue(true);
|
||||||
|
spyOn(component, 'exitSearch').and.callThrough();
|
||||||
|
spyOn(searchInputService, 'exitSearch').and.callThrough();
|
||||||
|
|
||||||
|
fixture.detectChanges();
|
||||||
|
await fixture.whenStable();
|
||||||
|
|
||||||
|
const closeIcon = fixture.debugElement.nativeElement.querySelector('.app-close-icon');
|
||||||
|
closeIcon.click();
|
||||||
|
|
||||||
|
fixture.detectChanges();
|
||||||
|
await fixture.whenStable();
|
||||||
|
|
||||||
|
expect(component.exitSearch).toHaveBeenCalled();
|
||||||
|
expect(searchInputService.exitSearch).toHaveBeenCalledWith();
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
@@ -34,6 +34,7 @@ import { Store } from '@ngrx/store';
|
|||||||
import { Subject } from 'rxjs';
|
import { Subject } from 'rxjs';
|
||||||
import { filter, takeUntil } from 'rxjs/operators';
|
import { filter, takeUntil } from 'rxjs/operators';
|
||||||
import { SearchInputControlComponent } from '../search-input-control/search-input-control.component';
|
import { SearchInputControlComponent } from '../search-input-control/search-input-control.component';
|
||||||
|
import { SearchInputService } from '../search-input.service';
|
||||||
import { SearchLibrariesQueryBuilderService } from '../search-libraries-results/search-libraries-query-builder.service';
|
import { SearchLibrariesQueryBuilderService } from '../search-libraries-results/search-libraries-query-builder.service';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
@@ -85,26 +86,37 @@ export class SearchInputComponent implements OnInit, OnDestroy {
|
|||||||
private config: AppConfigService,
|
private config: AppConfigService,
|
||||||
private router: Router,
|
private router: Router,
|
||||||
private store: Store<AppStore>,
|
private store: Store<AppStore>,
|
||||||
private appHookService: AppHookService
|
private appHookService: AppHookService,
|
||||||
|
public searchInputService: SearchInputService
|
||||||
) {
|
) {
|
||||||
this.searchOnChange = this.config.get<boolean>('search.aca:triggeredOnChange', true);
|
this.searchOnChange = this.config.get<boolean>('search.aca:triggeredOnChange', true);
|
||||||
}
|
}
|
||||||
|
|
||||||
ngOnInit() {
|
ngOnInit() {
|
||||||
this.showInputValue();
|
if (this.searchInputService.isSearchRoute()) {
|
||||||
|
this.showInputValue();
|
||||||
|
|
||||||
this.router.events
|
this.router.events
|
||||||
.pipe(takeUntil(this.onDestroy$))
|
.pipe(takeUntil(this.onDestroy$))
|
||||||
.pipe(filter((e) => e instanceof RouterEvent))
|
.pipe(filter((e) => e instanceof RouterEvent))
|
||||||
.subscribe((event) => {
|
.subscribe((event) => {
|
||||||
if (event instanceof NavigationEnd) {
|
if (event instanceof NavigationEnd) {
|
||||||
this.showInputValue();
|
this.showInputValue();
|
||||||
}
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
this.appHookService.library400Error.pipe(takeUntil(this.onDestroy$)).subscribe(() => {
|
||||||
|
this.has400LibraryError = true;
|
||||||
});
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
this.appHookService.library400Error.pipe(takeUntil(this.onDestroy$)).subscribe(() => {
|
navigateToSearch() {
|
||||||
this.has400LibraryError = true;
|
this.searchInputService.navigateToSearch();
|
||||||
});
|
}
|
||||||
|
|
||||||
|
exitSearch() {
|
||||||
|
this.searchInputService.exitSearch();
|
||||||
}
|
}
|
||||||
|
|
||||||
showInputValue() {
|
showInputValue() {
|
||||||
@@ -140,7 +152,6 @@ export class SearchInputComponent implements OnInit, OnDestroy {
|
|||||||
} else {
|
} else {
|
||||||
this.store.dispatch(new SnackbarErrorAction('APP.BROWSE.SEARCH.EMPTY_SEARCH'));
|
this.store.dispatch(new SnackbarErrorAction('APP.BROWSE.SEARCH.EMPTY_SEARCH'));
|
||||||
}
|
}
|
||||||
this.trigger.closeMenu();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
onSearchChange(searchTerm: string) {
|
onSearchChange(searchTerm: string) {
|
||||||
|
@@ -39,6 +39,8 @@ import { AppLayoutModule } from '../layout/layout.module';
|
|||||||
import { ContextMenuModule } from '../context-menu/context-menu.module';
|
import { ContextMenuModule } from '../context-menu/context-menu.module';
|
||||||
import { SearchActionMenuComponent } from './search-action-menu/search-action-menu.component';
|
import { SearchActionMenuComponent } from './search-action-menu/search-action-menu.component';
|
||||||
import { DocumentListCustomComponentsModule } from '../dl-custom-components/document-list-custom-components.module';
|
import { DocumentListCustomComponentsModule } from '../dl-custom-components/document-list-custom-components.module';
|
||||||
|
import { AppSearchInputModule } from './search-input.module';
|
||||||
|
import { AppHeaderActionsModule } from '../header-actions/header-actions.module';
|
||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
imports: [
|
imports: [
|
||||||
@@ -52,7 +54,9 @@ import { DocumentListCustomComponentsModule } from '../dl-custom-components/docu
|
|||||||
AppLayoutModule,
|
AppLayoutModule,
|
||||||
ContextMenuModule,
|
ContextMenuModule,
|
||||||
LockedByModule,
|
LockedByModule,
|
||||||
DocumentListCustomComponentsModule
|
DocumentListCustomComponentsModule,
|
||||||
|
AppSearchInputModule,
|
||||||
|
AppHeaderActionsModule
|
||||||
],
|
],
|
||||||
declarations: [SearchResultsComponent, SearchLibrariesResultsComponent, SearchResultsRowComponent, SearchActionMenuComponent],
|
declarations: [SearchResultsComponent, SearchLibrariesResultsComponent, SearchResultsRowComponent, SearchActionMenuComponent],
|
||||||
exports: [SearchResultsComponent, SearchLibrariesResultsComponent, SearchResultsRowComponent, SearchActionMenuComponent]
|
exports: [SearchResultsComponent, SearchLibrariesResultsComponent, SearchResultsRowComponent, SearchActionMenuComponent]
|
||||||
|
@@ -1,7 +1,7 @@
|
|||||||
<aca-page-layout>
|
<aca-page-layout>
|
||||||
<aca-page-layout-header>
|
<aca-page-layout-header>
|
||||||
<adf-breadcrumb root="APP.BROWSE.SEARCH.TITLE"> </adf-breadcrumb>
|
<aca-search-input></aca-search-input>
|
||||||
<adf-toolbar class="adf-toolbar--inline">
|
<adf-toolbar class="adf-toolbar--inline adf-toolbar-search-results">
|
||||||
<ng-container *ngFor="let entry of actions; trackBy: trackByActionId">
|
<ng-container *ngFor="let entry of actions; trackBy: trackByActionId">
|
||||||
<aca-toolbar-action [actionRef]="entry"></aca-toolbar-action>
|
<aca-toolbar-action [actionRef]="entry"></aca-toolbar-action>
|
||||||
</ng-container>
|
</ng-container>
|
||||||
|
@@ -3,6 +3,13 @@
|
|||||||
$adf-chip-background: #efefef;
|
$adf-chip-background: #efefef;
|
||||||
$contrast-gray: #646569;
|
$contrast-gray: #646569;
|
||||||
|
|
||||||
|
.adf-toolbar-search-results {
|
||||||
|
position: fixed;
|
||||||
|
right: 24px;
|
||||||
|
height: 32px;
|
||||||
|
margin-bottom: 32px !important;
|
||||||
|
}
|
||||||
|
|
||||||
.adf-search-results {
|
.adf-search-results {
|
||||||
@include flex-row;
|
@include flex-row;
|
||||||
|
|
||||||
|
@@ -1,7 +1,7 @@
|
|||||||
<aca-page-layout>
|
<aca-page-layout>
|
||||||
<aca-page-layout-header>
|
<aca-page-layout-header>
|
||||||
<adf-breadcrumb root="APP.BROWSE.SHARED.TITLE"></adf-breadcrumb>
|
<adf-breadcrumb root="APP.BROWSE.SHARED.TITLE"></adf-breadcrumb>
|
||||||
|
<aca-header-actions></aca-header-actions>
|
||||||
<adf-toolbar class="adf-toolbar--inline">
|
<adf-toolbar class="adf-toolbar--inline">
|
||||||
<ng-container *ngFor="let entry of actions; trackBy: trackByActionId">
|
<ng-container *ngFor="let entry of actions; trackBy: trackByActionId">
|
||||||
<aca-toolbar-action [actionRef]="entry"></aca-toolbar-action>
|
<aca-toolbar-action [actionRef]="entry"></aca-toolbar-action>
|
||||||
|
@@ -1,7 +1,7 @@
|
|||||||
<aca-page-layout>
|
<aca-page-layout>
|
||||||
<aca-page-layout-header>
|
<aca-page-layout-header>
|
||||||
<adf-breadcrumb root="APP.BROWSE.TRASHCAN.TITLE"> </adf-breadcrumb>
|
<adf-breadcrumb root="APP.BROWSE.TRASHCAN.TITLE"> </adf-breadcrumb>
|
||||||
|
<aca-header-actions></aca-header-actions>
|
||||||
<adf-toolbar class="adf-toolbar--inline">
|
<adf-toolbar class="adf-toolbar--inline">
|
||||||
<ng-container *ngFor="let entry of actions; trackBy: trackByActionId">
|
<ng-container *ngFor="let entry of actions; trackBy: trackByActionId">
|
||||||
<aca-toolbar-action [actionRef]="entry"></aca-toolbar-action>
|
<aca-toolbar-action [actionRef]="entry"></aca-toolbar-action>
|
||||||
|
@@ -33,6 +33,8 @@ import { AppToolbarModule } from '../toolbar/toolbar.module';
|
|||||||
import { DirectivesModule } from '../../directives/directives.module';
|
import { DirectivesModule } from '../../directives/directives.module';
|
||||||
import { ContextMenuModule } from '../context-menu/context-menu.module';
|
import { ContextMenuModule } from '../context-menu/context-menu.module';
|
||||||
import { AppLayoutModule } from '../layout/layout.module';
|
import { AppLayoutModule } from '../layout/layout.module';
|
||||||
|
import { AppSearchInputModule } from '../search/search-input.module';
|
||||||
|
import { AppHeaderActionsModule } from '../header-actions/header-actions.module';
|
||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
imports: [
|
imports: [
|
||||||
@@ -43,7 +45,9 @@ import { AppLayoutModule } from '../layout/layout.module';
|
|||||||
AppCommonModule,
|
AppCommonModule,
|
||||||
AppToolbarModule,
|
AppToolbarModule,
|
||||||
ContextMenuModule,
|
ContextMenuModule,
|
||||||
AppLayoutModule
|
AppLayoutModule,
|
||||||
|
AppSearchInputModule,
|
||||||
|
AppHeaderActionsModule
|
||||||
],
|
],
|
||||||
declarations: [TrashcanComponent],
|
declarations: [TrashcanComponent],
|
||||||
exports: [TrashcanComponent]
|
exports: [TrashcanComponent]
|
||||||
|
@@ -51,6 +51,9 @@ $selected-text-color: #212121;
|
|||||||
$selected-background-color: rgba(31, 116, 219, 0.24);
|
$selected-background-color: rgba(31, 116, 219, 0.24);
|
||||||
$action-button-text-color: rgba(33, 35, 40, 0.7);
|
$action-button-text-color: rgba(33, 35, 40, 0.7);
|
||||||
$tooltip-background-color: #ffffff;
|
$tooltip-background-color: #ffffff;
|
||||||
|
$create-button-text-color: #212121;
|
||||||
|
$upload-button-background-color: #2A7DE1;
|
||||||
|
$page-layout-header-background-color: #ffffff;
|
||||||
|
|
||||||
$defaults: (
|
$defaults: (
|
||||||
--theme-primary-color: mat.get-color-from-palette($primary),
|
--theme-primary-color: mat.get-color-from-palette($primary),
|
||||||
@@ -95,6 +98,11 @@ $defaults: (
|
|||||||
--theme-action-button-text-color: $action-button-text-color,
|
--theme-action-button-text-color: $action-button-text-color,
|
||||||
--theme-header-border-color: $grey-background,
|
--theme-header-border-color: $grey-background,
|
||||||
--theme-tooltip-background-color: $tooltip-background-color,
|
--theme-tooltip-background-color: $tooltip-background-color,
|
||||||
|
--theme-page-layout-header-background-color: $page-layout-header-background-color,
|
||||||
|
--theme-create-button-background-color: $grey-text-background,
|
||||||
|
--theme-create-button-text-color: $create-button-text-color,
|
||||||
|
--theme-upload-button-background-color: $upload-button-background-color,
|
||||||
|
--theme-upload-button-text-color: $pagination-background-color,
|
||||||
);
|
);
|
||||||
|
|
||||||
// propagates SCSS variables into the CSS variables scope
|
// propagates SCSS variables into the CSS variables scope
|
||||||
|
@@ -25,7 +25,7 @@
|
|||||||
|
|
||||||
import { DocumentListComponent, ShareDataRow } from '@alfresco/adf-content-services';
|
import { DocumentListComponent, ShareDataRow } from '@alfresco/adf-content-services';
|
||||||
import { ShowHeaderMode } from '@alfresco/adf-core';
|
import { ShowHeaderMode } from '@alfresco/adf-core';
|
||||||
import { ContentActionRef, DocumentListPresetRef, SelectionState } from '@alfresco/adf-extensions';
|
import { ContentActionRef, ContentActionType, DocumentListPresetRef, SelectionState } from '@alfresco/adf-extensions';
|
||||||
import { OnDestroy, OnInit, OnChanges, ViewChild, SimpleChanges, Directive } from '@angular/core';
|
import { OnDestroy, OnInit, OnChanges, ViewChild, SimpleChanges, Directive } from '@angular/core';
|
||||||
import { Store } from '@ngrx/store';
|
import { Store } from '@ngrx/store';
|
||||||
import { MinimalNodeEntity, MinimalNodeEntryEntity, NodePaging } from '@alfresco/js-api';
|
import { MinimalNodeEntity, MinimalNodeEntryEntity, NodePaging } from '@alfresco/js-api';
|
||||||
@@ -68,12 +68,32 @@ export abstract class PageComponent implements OnInit, OnDestroy, OnChanges {
|
|||||||
nodeResult: NodePaging;
|
nodeResult: NodePaging;
|
||||||
showHeader = ShowHeaderMode.Data;
|
showHeader = ShowHeaderMode.Data;
|
||||||
filterSorting = 'name-asc';
|
filterSorting = 'name-asc';
|
||||||
|
createActions: Array<ContentActionRef> = [];
|
||||||
|
uploadActions: Array<ContentActionRef> = [];
|
||||||
|
mainAction$: Observable<ContentActionRef>;
|
||||||
|
actionTypes = ContentActionType;
|
||||||
|
|
||||||
protected subscriptions: Subscription[] = [];
|
protected subscriptions: Subscription[] = [];
|
||||||
|
|
||||||
protected constructor(protected store: Store<AppStore>, protected extensions: AppExtensionService, protected content: DocumentBasePageService) {}
|
protected constructor(protected store: Store<AppStore>, protected extensions: AppExtensionService, protected content: DocumentBasePageService) {}
|
||||||
|
|
||||||
ngOnInit() {
|
ngOnInit() {
|
||||||
|
this.mainAction$ = this.extensions.getMainAction().pipe(takeUntil(this.onDestroy$));
|
||||||
|
|
||||||
|
this.extensions
|
||||||
|
.getCreateActions()
|
||||||
|
.pipe(takeUntil(this.onDestroy$))
|
||||||
|
.subscribe((actions) => {
|
||||||
|
this.createActions = actions;
|
||||||
|
});
|
||||||
|
|
||||||
|
this.extensions
|
||||||
|
.getUploadActions()
|
||||||
|
.pipe(takeUntil(this.onDestroy$))
|
||||||
|
.subscribe((actions) => {
|
||||||
|
this.uploadActions = actions;
|
||||||
|
});
|
||||||
|
|
||||||
this.sharedPreviewUrl$ = this.store.select(getSharedUrl);
|
this.sharedPreviewUrl$ = this.store.select(getSharedUrl);
|
||||||
this.infoDrawerOpened$ = this.store.select(isInfoDrawerOpened).pipe(map((infoDrawerState) => !this.isOutletPreviewUrl() && infoDrawerState));
|
this.infoDrawerOpened$ = this.store.select(isInfoDrawerOpened).pipe(map((infoDrawerState) => !this.isOutletPreviewUrl() && infoDrawerState));
|
||||||
|
|
||||||
@@ -124,6 +144,10 @@ export abstract class PageComponent implements OnInit, OnDestroy, OnChanges {
|
|||||||
this.store.dispatch(new SetSelectedNodesAction([]));
|
this.store.dispatch(new SetSelectedNodesAction([]));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
runAction(action: string): void {
|
||||||
|
this.extensions.runActionById(action);
|
||||||
|
}
|
||||||
|
|
||||||
showPreview(node: MinimalNodeEntity, extras?: ViewNodeExtras) {
|
showPreview(node: MinimalNodeEntity, extras?: ViewNodeExtras) {
|
||||||
if (node && node.entry) {
|
if (node && node.entry) {
|
||||||
let id: string;
|
let id: string;
|
||||||
|
@@ -7,8 +7,8 @@
|
|||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
flex: 0 0 65px;
|
flex: 0 0 65px;
|
||||||
flex-basis: 48px;
|
flex-basis: 96px;
|
||||||
background: var(--theme-background-color);
|
background: var(--theme-page-layout-header-background-color);
|
||||||
border-bottom: 1px solid var(--theme-border-color, rgba(0, 0, 0, 0.07));
|
border-bottom: 1px solid var(--theme-border-color, rgba(0, 0, 0, 0.07));
|
||||||
padding: 0 24px;
|
padding: 0 24px;
|
||||||
}
|
}
|
||||||
|
@@ -79,6 +79,7 @@ export class AppExtensionService implements RuleContext {
|
|||||||
private _contextMenuActions = new BehaviorSubject<Array<ContentActionRef>>([]);
|
private _contextMenuActions = new BehaviorSubject<Array<ContentActionRef>>([]);
|
||||||
private _openWithActions = new BehaviorSubject<Array<ContentActionRef>>([]);
|
private _openWithActions = new BehaviorSubject<Array<ContentActionRef>>([]);
|
||||||
private _createActions = new BehaviorSubject<Array<ContentActionRef>>([]);
|
private _createActions = new BehaviorSubject<Array<ContentActionRef>>([]);
|
||||||
|
private _uploadActions = new BehaviorSubject<Array<ContentActionRef>>([]);
|
||||||
private _mainActions = new BehaviorSubject<ContentActionRef>(null);
|
private _mainActions = new BehaviorSubject<ContentActionRef>(null);
|
||||||
private _sidebarActions = new BehaviorSubject<Array<ContentActionRef>>([]);
|
private _sidebarActions = new BehaviorSubject<Array<ContentActionRef>>([]);
|
||||||
|
|
||||||
@@ -158,6 +159,7 @@ export class AppExtensionService implements RuleContext {
|
|||||||
this._contextMenuActions.next(this.loader.getContentActions(config, 'features.contextMenu'));
|
this._contextMenuActions.next(this.loader.getContentActions(config, 'features.contextMenu'));
|
||||||
this._openWithActions.next(this.loader.getContentActions(config, 'features.viewer.openWith'));
|
this._openWithActions.next(this.loader.getContentActions(config, 'features.viewer.openWith'));
|
||||||
this._createActions.next(this.loader.getElements<ContentActionRef>(config, 'features.create'));
|
this._createActions.next(this.loader.getElements<ContentActionRef>(config, 'features.create'));
|
||||||
|
this._uploadActions.next(this.loader.getElements<ContentActionRef>(config, 'features.upload'));
|
||||||
this._mainActions.next(this.loader.getFeatures(config).mainAction);
|
this._mainActions.next(this.loader.getFeatures(config).mainAction);
|
||||||
|
|
||||||
this.navbar = this.loadNavBar(config);
|
this.navbar = this.loadNavBar(config);
|
||||||
@@ -366,6 +368,18 @@ export class AppExtensionService implements RuleContext {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getUploadActions(): Observable<Array<ContentActionRef>> {
|
||||||
|
return this._uploadActions.pipe(
|
||||||
|
map((uploadActions) =>
|
||||||
|
uploadActions
|
||||||
|
.filter((action) => this.filterVisible(action))
|
||||||
|
.map((action) => this.copyAction(action))
|
||||||
|
.map((action) => this.buildMenu(action))
|
||||||
|
.map((action) => this.setActionDisabledFromRule(action))
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
getMainAction(): Observable<ContentActionRef> {
|
getMainAction(): Observable<ContentActionRef> {
|
||||||
return this._mainActions.pipe(
|
return this._mainActions.pipe(
|
||||||
filter((mainAction) => mainAction && this.filterVisible(mainAction)),
|
filter((mainAction) => mainAction && this.filterVisible(mainAction)),
|
||||||
|
Reference in New Issue
Block a user