mirror of
https://github.com/Alfresco/alfresco-content-app.git
synced 2025-07-24 17:31:52 +00:00
[ACA-1544] extensions: toolbar separators and menus (#504)
* toolbar separators * remove the need for "target" for separators * simplify code * menu stub, reducing separators * toolbar action component * render menu items * menu items
This commit is contained in:
@@ -200,8 +200,13 @@
|
||||
"content": {
|
||||
"actions": [
|
||||
{
|
||||
"disabled": false,
|
||||
"id": "aca:toolbar/separator-1",
|
||||
"order": 5,
|
||||
"type": "separator"
|
||||
},
|
||||
{
|
||||
"id": "aca:toolbar/create-folder",
|
||||
"type": "button",
|
||||
"order": 10,
|
||||
"title": "APP.NEW_MENU.TOOLTIPS.CREATE_FOLDER",
|
||||
"icon": "create_new_folder",
|
||||
@@ -212,8 +217,8 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
"disabled": false,
|
||||
"id": "aca:toolbar/preview",
|
||||
"type": "button",
|
||||
"order": 15,
|
||||
"title": "APP.ACTIONS.VIEW",
|
||||
"icon": "open_in_browser",
|
||||
@@ -224,8 +229,8 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
"disabled": false,
|
||||
"id": "aca:toolbar/download",
|
||||
"type": "button",
|
||||
"order": 20,
|
||||
"title": "APP.ACTIONS.DOWNLOAD",
|
||||
"icon": "get_app",
|
||||
@@ -237,8 +242,8 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
"disabled": false,
|
||||
"id": "aca:toolbar/edit-folder",
|
||||
"type": "button",
|
||||
"order": 30,
|
||||
"title": "APP.ACTIONS.EDIT",
|
||||
"icon": "create",
|
||||
@@ -249,30 +254,44 @@
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
{
|
||||
"disabled": false,
|
||||
"id": "aca:action3",
|
||||
"order": 101,
|
||||
"title": "Settings",
|
||||
"icon": "settings_applications",
|
||||
"target": {
|
||||
"types": [],
|
||||
"permissions": [],
|
||||
"action": "aca:actions/settings"
|
||||
}
|
||||
"id": "aca:toolbar/separator-2",
|
||||
"order": 200,
|
||||
"type": "separator"
|
||||
},
|
||||
{
|
||||
"disabled": false,
|
||||
"id": "aca:action4",
|
||||
"order": 101,
|
||||
"title": "Error",
|
||||
"icon": "report_problem",
|
||||
"target": {
|
||||
"types": ["file"],
|
||||
"permissions": ["update", "delete"],
|
||||
"action": "aca:actions/error"
|
||||
}
|
||||
"id": "aca:toolbar/menu-1",
|
||||
"type": "menu",
|
||||
"icon": "storage",
|
||||
"order": 300,
|
||||
"children": [
|
||||
{
|
||||
"id": "aca:action3",
|
||||
"type": "button",
|
||||
"title": "Settings",
|
||||
"icon": "settings_applications",
|
||||
"target": {
|
||||
"types": [],
|
||||
"permissions": [],
|
||||
"action": "aca:actions/settings"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "aca:action4",
|
||||
"type": "button",
|
||||
"title": "Error",
|
||||
"icon": "report_problem",
|
||||
"target": {
|
||||
"types": ["file"],
|
||||
"permissions": ["update", "delete"],
|
||||
"action": "aca:actions/error"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "aca:toolbar/separator-3",
|
||||
"type": "separator"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
@@ -13,15 +13,9 @@
|
||||
</button>
|
||||
|
||||
<ng-container *ifExperimental="'extensions'">
|
||||
<adf-toolbar-divider></adf-toolbar-divider>
|
||||
<button *ngFor="let entry of actions"
|
||||
mat-icon-button
|
||||
color="primary"
|
||||
title="{{ entry.title | translate }}"
|
||||
(click)="runAction(entry.target.action)">
|
||||
<mat-icon>{{ entry.icon }}</mat-icon>
|
||||
</button>
|
||||
<adf-toolbar-divider></adf-toolbar-divider>
|
||||
<ng-container *ngFor="let entry of actions">
|
||||
<aca-toolbar-action [entry]="entry"></aca-toolbar-action>
|
||||
</ng-container>
|
||||
</ng-container>
|
||||
|
||||
<ng-container *ngIf="!selection.isEmpty">
|
||||
|
@@ -16,15 +16,9 @@
|
||||
</button>
|
||||
|
||||
<ng-container *ifExperimental="'extensions'">
|
||||
<adf-toolbar-divider></adf-toolbar-divider>
|
||||
<button *ngFor="let entry of actions"
|
||||
mat-icon-button
|
||||
color="primary"
|
||||
title="{{ entry.title | translate }}"
|
||||
(click)="runAction(entry.target.action)">
|
||||
<mat-icon>{{ entry.icon }}</mat-icon>
|
||||
</button>
|
||||
<adf-toolbar-divider></adf-toolbar-divider>
|
||||
<ng-container *ngFor="let entry of actions">
|
||||
<aca-toolbar-action [entry]="entry"></aca-toolbar-action>
|
||||
</ng-container>
|
||||
</ng-container>
|
||||
|
||||
<ng-container *ngIf="!selection.isEmpty">
|
||||
|
@@ -83,7 +83,8 @@ export abstract class PageComponent implements OnInit, OnDestroy {
|
||||
if (selection.isEmpty) {
|
||||
this.infoDrawerOpened = false;
|
||||
}
|
||||
this.actions = this.extensions.getSelectedContentActions(selection, this.node);
|
||||
const selectedNodes = selection ? selection.nodes : null;
|
||||
this.actions = this.extensions.getAllowedContentActions(selectedNodes, this.node);
|
||||
this.canUpdateFile = this.selection.file && this.content.canUpdateNode(selection.file);
|
||||
this.canUpdateNode = this.selection.count === 1 && this.content.canUpdateNode(selection.first);
|
||||
this.canDelete = !this.selection.isEmpty && this.content.canDeleteNodes(selection.nodes);
|
||||
|
@@ -13,15 +13,9 @@
|
||||
</button>
|
||||
|
||||
<ng-container *ifExperimental="'extensions'">
|
||||
<adf-toolbar-divider></adf-toolbar-divider>
|
||||
<button *ngFor="let entry of actions"
|
||||
mat-icon-button
|
||||
color="primary"
|
||||
title="{{ entry.title | translate }}"
|
||||
(click)="runAction(entry.target.action)">
|
||||
<mat-icon>{{ entry.icon }}</mat-icon>
|
||||
</button>
|
||||
<adf-toolbar-divider></adf-toolbar-divider>
|
||||
<ng-container *ngFor="let entry of actions">
|
||||
<aca-toolbar-action [entry]="entry"></aca-toolbar-action>
|
||||
</ng-container>
|
||||
</ng-container>
|
||||
|
||||
<ng-container *ngIf="!selection.isEmpty">
|
||||
|
@@ -4,15 +4,9 @@
|
||||
</adf-breadcrumb>
|
||||
<adf-toolbar class="inline">
|
||||
<ng-container *ifExperimental="'extensions'">
|
||||
<adf-toolbar-divider></adf-toolbar-divider>
|
||||
<button *ngFor="let entry of actions"
|
||||
mat-icon-button
|
||||
color="primary"
|
||||
title="{{ entry.title | translate }}"
|
||||
(click)="runAction(entry.target.action)">
|
||||
<mat-icon>{{ entry.icon }}</mat-icon>
|
||||
</button>
|
||||
<adf-toolbar-divider></adf-toolbar-divider>
|
||||
<ng-container *ngFor="let entry of actions">
|
||||
<aca-toolbar-action [entry]="entry"></aca-toolbar-action>
|
||||
</ng-container>
|
||||
</ng-container>
|
||||
|
||||
<ng-container *ngIf="!selection.isEmpty">
|
||||
|
@@ -13,15 +13,9 @@
|
||||
</button>
|
||||
|
||||
<ng-container *ifExperimental="'extensions'">
|
||||
<adf-toolbar-divider></adf-toolbar-divider>
|
||||
<button *ngFor="let entry of actions"
|
||||
mat-icon-button
|
||||
color="primary"
|
||||
title="{{ entry.title | translate }}"
|
||||
(click)="runAction(entry.target.action)">
|
||||
<mat-icon>{{ entry.icon }}</mat-icon>
|
||||
</button>
|
||||
<adf-toolbar-divider></adf-toolbar-divider>
|
||||
<ng-container *ngFor="let entry of actions">
|
||||
<aca-toolbar-action [entry]="entry"></aca-toolbar-action>
|
||||
</ng-container>
|
||||
</ng-container>
|
||||
|
||||
<ng-container *ngIf="!selection.isEmpty">
|
||||
|
@@ -13,15 +13,9 @@
|
||||
</button>
|
||||
|
||||
<ng-container *ifExperimental="'extensions'">
|
||||
<adf-toolbar-divider></adf-toolbar-divider>
|
||||
<button *ngFor="let entry of actions"
|
||||
mat-icon-button
|
||||
color="primary"
|
||||
title="{{ entry.title | translate }}"
|
||||
(click)="runAction(entry.target.action)">
|
||||
<mat-icon>{{ entry.icon }}</mat-icon>
|
||||
</button>
|
||||
<adf-toolbar-divider></adf-toolbar-divider>
|
||||
<ng-container *ngFor="let entry of actions">
|
||||
<aca-toolbar-action [entry]="entry"></aca-toolbar-action>
|
||||
</ng-container>
|
||||
</ng-container>
|
||||
|
||||
<ng-container *ngIf="!selection.isEmpty">
|
||||
|
@@ -0,0 +1,30 @@
|
||||
<ng-container [ngSwitch]="entry.type">
|
||||
<button *ngSwitchCase="'button'"
|
||||
mat-icon-button
|
||||
color="primary"
|
||||
title="{{ entry.title | translate }}"
|
||||
(click)="runAction(entry.target.action)">
|
||||
<mat-icon>{{ entry.icon }}</mat-icon>
|
||||
</button>
|
||||
<adf-toolbar-divider *ngSwitchCase="'separator'"></adf-toolbar-divider>
|
||||
<ng-container *ngSwitchCase="'menu'">
|
||||
<button
|
||||
color="primary"
|
||||
mat-icon-button
|
||||
title="{{ entry.title | translate }}"
|
||||
[matMenuTriggerFor]="menu">
|
||||
<mat-icon>{{ entry.icon }}</mat-icon>
|
||||
</button>
|
||||
|
||||
<mat-menu #menu="matMenu"
|
||||
[overlapTrigger]="false">
|
||||
<ng-container *ngFor="let child of entry.children">
|
||||
<button mat-menu-item
|
||||
(click)="runAction(child.target.action)">
|
||||
<mat-icon>{{ child.icon }}</mat-icon>
|
||||
<span>{{ child.title | translate }}</span>
|
||||
</button>
|
||||
</ng-container>
|
||||
</mat-menu>
|
||||
</ng-container>
|
||||
</ng-container>
|
@@ -0,0 +1,81 @@
|
||||
/*!
|
||||
* @license
|
||||
* Alfresco Example Content Application
|
||||
*
|
||||
* Copyright (C) 2005 - 2018 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,
|
||||
ViewEncapsulation,
|
||||
ChangeDetectionStrategy,
|
||||
Input,
|
||||
OnInit,
|
||||
OnDestroy
|
||||
} from '@angular/core';
|
||||
import { ContentActionExtension } from '../../content-action.extension';
|
||||
import { AppStore, SelectionState } from '../../../store/states';
|
||||
import { Store } from '@ngrx/store';
|
||||
import { ExtensionService } from '../../extension.service';
|
||||
import { appSelection } from '../../../store/selectors/app.selectors';
|
||||
import { Subject } from 'rxjs/Rx';
|
||||
import { takeUntil } from 'rxjs/operators';
|
||||
|
||||
@Component({
|
||||
selector: 'aca-toolbar-action',
|
||||
templateUrl: './toolbar-action.component.html',
|
||||
encapsulation: ViewEncapsulation.None,
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
host: { class: 'aca-toolbar-action' }
|
||||
})
|
||||
export class ToolbarActionComponent implements OnInit, OnDestroy {
|
||||
@Input() entry: ContentActionExtension;
|
||||
|
||||
selection: SelectionState;
|
||||
onDestroy$: Subject<boolean> = new Subject<boolean>();
|
||||
|
||||
constructor(
|
||||
protected store: Store<AppStore>,
|
||||
protected extensions: ExtensionService
|
||||
) {}
|
||||
|
||||
ngOnInit() {
|
||||
this.store
|
||||
.select(appSelection)
|
||||
.pipe(takeUntil(this.onDestroy$))
|
||||
.subscribe(selection => {
|
||||
this.selection = selection;
|
||||
});
|
||||
}
|
||||
|
||||
ngOnDestroy() {
|
||||
this.onDestroy$.next(true);
|
||||
this.onDestroy$.complete();
|
||||
}
|
||||
|
||||
runAction(actionId: string) {
|
||||
const context = {
|
||||
selection: this.selection
|
||||
};
|
||||
|
||||
this.extensions.runActionById(actionId, context);
|
||||
}
|
||||
}
|
@@ -23,12 +23,21 @@
|
||||
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
export enum ContentActionType {
|
||||
default = 'button',
|
||||
button = 'button',
|
||||
separator = 'separator',
|
||||
menu = 'menu'
|
||||
}
|
||||
|
||||
export interface ContentActionExtension {
|
||||
id: string;
|
||||
type: ContentActionType;
|
||||
order?: number;
|
||||
title: string;
|
||||
icon?: string;
|
||||
disabled?: boolean;
|
||||
children?: Array<ContentActionExtension>;
|
||||
target: {
|
||||
types: Array<string>;
|
||||
permissions: Array<string>,
|
||||
|
@@ -24,14 +24,20 @@
|
||||
*/
|
||||
|
||||
import { NgModule } from '@angular/core';
|
||||
import { AuthGuardEcm } from '@alfresco/adf-core';
|
||||
import { AuthGuardEcm, CoreModule } from '@alfresco/adf-core';
|
||||
import { ExtensionService } from './extension.service';
|
||||
import { AboutComponent } from '../components/about/about.component';
|
||||
import { LayoutComponent } from '../components/layout/layout.component';
|
||||
import { ToolbarActionComponent } from './components/toolbar-action/toolbar-action.component';
|
||||
import { CommonModule } from '@angular/common';
|
||||
|
||||
@NgModule({
|
||||
imports: [],
|
||||
declarations: [],
|
||||
imports: [
|
||||
CommonModule,
|
||||
CoreModule.forChild()
|
||||
],
|
||||
declarations: [ToolbarActionComponent],
|
||||
exports: [ToolbarActionComponent],
|
||||
entryComponents: [AboutComponent]
|
||||
})
|
||||
export class CoreExtensionsModule {
|
||||
|
@@ -27,13 +27,14 @@ import { Injectable, Type } from '@angular/core';
|
||||
import { RouteExtension } from './route.extension';
|
||||
import { ActionExtension } from './action.extension';
|
||||
import { AppConfigService } from '@alfresco/adf-core';
|
||||
import { ContentActionExtension } from './content-action.extension';
|
||||
import { ContentActionExtension, ContentActionType } from './content-action.extension';
|
||||
import { OpenWithExtension } from './open-with.extension';
|
||||
import { AppStore, SelectionState } from '../store/states';
|
||||
import { AppStore } from '../store/states';
|
||||
import { Store } from '@ngrx/store';
|
||||
import { NavigationExtension } from './navigation.extension';
|
||||
import { Route } from '@angular/router';
|
||||
import { Node } from 'alfresco-js-api';
|
||||
import { Node, MinimalNodeEntity } from 'alfresco-js-api';
|
||||
import { reduceSeparators, sortByOrder, filterEnabled, copyAction, reduceEmptyMenus } from './utils';
|
||||
|
||||
@Injectable()
|
||||
export class ExtensionService {
|
||||
@@ -70,7 +71,7 @@ export class ExtensionService {
|
||||
'extensions.core.features.content.actions',
|
||||
[]
|
||||
)
|
||||
.sort(this.sortByOrder);
|
||||
.sort(sortByOrder);
|
||||
|
||||
this.openWithActions = this.config
|
||||
.get<Array<OpenWithExtension>>(
|
||||
@@ -78,14 +79,14 @@ export class ExtensionService {
|
||||
[]
|
||||
)
|
||||
.filter(entry => !entry.disabled)
|
||||
.sort(this.sortByOrder);
|
||||
.sort(sortByOrder);
|
||||
|
||||
this.createActions = this.config
|
||||
.get<Array<ContentActionExtension>>(
|
||||
'extensions.core.features.create',
|
||||
[]
|
||||
)
|
||||
.sort(this.sortByOrder);
|
||||
.sort(sortByOrder);
|
||||
}
|
||||
|
||||
getRouteById(id: string): RouteExtension {
|
||||
@@ -178,7 +179,7 @@ export class ExtensionService {
|
||||
|
||||
// evaluates create actions for the folder node
|
||||
getFolderCreateActions(folder: Node): Array<ContentActionExtension> {
|
||||
return this.createActions.filter(this.filterOutDisabled).map(action => {
|
||||
return this.createActions.filter(filterEnabled).map(action => {
|
||||
if (
|
||||
action.target &&
|
||||
action.target.permissions &&
|
||||
@@ -200,64 +201,72 @@ export class ExtensionService {
|
||||
}
|
||||
|
||||
// evaluates content actions for the selection and parent folder node
|
||||
getSelectedContentActions(
|
||||
selection: SelectionState,
|
||||
getAllowedContentActions(
|
||||
nodes: MinimalNodeEntity[],
|
||||
parentNode: Node
|
||||
): Array<ContentActionExtension> {
|
||||
return this.contentActions
|
||||
.filter(this.filterOutDisabled)
|
||||
.filter(action => action.target)
|
||||
.filter(action => this.filterByTarget(selection, action))
|
||||
.filter(action =>
|
||||
this.filterByPermission(selection, action, parentNode)
|
||||
);
|
||||
.filter(filterEnabled)
|
||||
.filter(action => this.filterByTarget(nodes, action))
|
||||
.filter(action => this.filterByPermission(nodes, action, parentNode))
|
||||
.reduce(reduceSeparators, [])
|
||||
.map(action => {
|
||||
if (action.type === ContentActionType.menu) {
|
||||
const copy = copyAction(action);
|
||||
if (copy.children && copy.children.length > 0) {
|
||||
copy.children = copy.children
|
||||
.filter(childAction => this.filterByTarget(nodes, childAction))
|
||||
.filter(childAction => this.filterByPermission(nodes, childAction, parentNode))
|
||||
.reduce(reduceSeparators, []);
|
||||
}
|
||||
return copy;
|
||||
}
|
||||
return action;
|
||||
})
|
||||
.reduce(reduceEmptyMenus, []);
|
||||
}
|
||||
|
||||
private sortByOrder(
|
||||
a: { order?: number | undefined },
|
||||
b: { order?: number | undefined }
|
||||
) {
|
||||
const left = a.order === undefined ? Number.MAX_SAFE_INTEGER : a.order;
|
||||
const right = b.order === undefined ? Number.MAX_SAFE_INTEGER : b.order;
|
||||
return left - right;
|
||||
}
|
||||
|
||||
private filterOutDisabled(entry: { disabled?: boolean }): boolean {
|
||||
return !entry.disabled;
|
||||
}
|
||||
|
||||
// todo: support multiple selected nodes
|
||||
private filterByTarget(
|
||||
selection: SelectionState,
|
||||
nodes: MinimalNodeEntity[],
|
||||
action: ContentActionExtension
|
||||
): boolean {
|
||||
|
||||
if (!action) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!action.target) {
|
||||
return action.type === ContentActionType.separator
|
||||
|| action.type === ContentActionType.menu;
|
||||
}
|
||||
|
||||
const types = action.target.types;
|
||||
|
||||
if (!types || types.length === 0) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (selection && !selection.isEmpty) {
|
||||
if (nodes && nodes.length > 0) {
|
||||
|
||||
if (selection.nodes.length === 1) {
|
||||
if (selection.folder && types.includes('folder')) {
|
||||
return true;
|
||||
if (nodes.length === 1) {
|
||||
if (types.includes('folder')) {
|
||||
return nodes.every(node => node.entry.isFolder);
|
||||
}
|
||||
if (selection.file && types.includes('file')) {
|
||||
return true;
|
||||
if (types.includes('file')) {
|
||||
return nodes.every(node => node.entry.isFile);
|
||||
}
|
||||
return false;
|
||||
} else {
|
||||
if (types.length === 1) {
|
||||
if (types.includes('folder')) {
|
||||
if (action.target.multiple) {
|
||||
return selection.nodes.every(node => node.entry.isFolder);
|
||||
return nodes.every(node => node.entry.isFolder);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
if (types.includes('file')) {
|
||||
if (action.target.multiple) {
|
||||
return selection.nodes.every(node => node.entry.isFile);
|
||||
return nodes.every(node => node.entry.isFile);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@@ -265,13 +274,13 @@ export class ExtensionService {
|
||||
return types.some(type => {
|
||||
if (type === 'folder') {
|
||||
return action.target.multiple
|
||||
? selection.nodes.some(node => node.entry.isFolder)
|
||||
: selection.nodes.every(node => node.entry.isFolder);
|
||||
? nodes.some(node => node.entry.isFolder)
|
||||
: nodes.every(node => node.entry.isFolder);
|
||||
}
|
||||
if (type === 'file') {
|
||||
return action.target.multiple
|
||||
? selection.nodes.some(node => node.entry.isFile)
|
||||
: selection.nodes.every(node => node.entry.isFile);
|
||||
? nodes.some(node => node.entry.isFile)
|
||||
: nodes.every(node => node.entry.isFile);
|
||||
}
|
||||
return false;
|
||||
});
|
||||
@@ -284,10 +293,19 @@ export class ExtensionService {
|
||||
|
||||
// todo: support multiple selected nodes
|
||||
private filterByPermission(
|
||||
selection: SelectionState,
|
||||
nodes: MinimalNodeEntity[],
|
||||
action: ContentActionExtension,
|
||||
parentNode: Node
|
||||
): boolean {
|
||||
if (!action) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!action.target) {
|
||||
return action.type === ContentActionType.separator
|
||||
|| action.type === ContentActionType.menu;
|
||||
}
|
||||
|
||||
const permissions = action.target.permissions;
|
||||
|
||||
if (!permissions || permissions.length === 0) {
|
||||
@@ -298,15 +316,14 @@ export class ExtensionService {
|
||||
if (permission.startsWith('parent.')) {
|
||||
if (parentNode) {
|
||||
const parentQuery = permission.split('.')[1];
|
||||
// console.log(parentNode.allowableOperations, parentQuery);
|
||||
return this.nodeHasPermissions(parentNode, [parentQuery]);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
if (selection && selection.first) {
|
||||
if (nodes && nodes.length > 0) {
|
||||
return this.nodeHasPermissions(
|
||||
selection.first.entry,
|
||||
nodes[0].entry,
|
||||
permissions
|
||||
);
|
||||
}
|
||||
|
87
src/app/extensions/utils.ts
Normal file
87
src/app/extensions/utils.ts
Normal file
@@ -0,0 +1,87 @@
|
||||
/*!
|
||||
* @license
|
||||
* Alfresco Example Content Application
|
||||
*
|
||||
* Copyright (C) 2005 - 2018 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 {
|
||||
ContentActionExtension,
|
||||
ContentActionType
|
||||
} from './content-action.extension';
|
||||
|
||||
export function reduceSeparators(
|
||||
acc: ContentActionExtension[],
|
||||
el: ContentActionExtension,
|
||||
i: number,
|
||||
arr: ContentActionExtension[]
|
||||
): ContentActionExtension[] {
|
||||
// remove duplicate separators
|
||||
if (i > 0) {
|
||||
const prev = arr[i - 1];
|
||||
if (
|
||||
prev.type === ContentActionType.separator &&
|
||||
el.type === ContentActionType.separator
|
||||
) {
|
||||
return acc;
|
||||
}
|
||||
}
|
||||
// remove trailing separator
|
||||
if (i === arr.length - 1) {
|
||||
if (el.type === ContentActionType.separator) {
|
||||
return acc;
|
||||
}
|
||||
}
|
||||
return acc.concat(el);
|
||||
}
|
||||
|
||||
|
||||
export function reduceEmptyMenus(
|
||||
acc: ContentActionExtension[],
|
||||
el: ContentActionExtension
|
||||
): ContentActionExtension[] {
|
||||
if (el.type === ContentActionType.menu) {
|
||||
if ((el.children || []).length === 0) {
|
||||
return acc;
|
||||
}
|
||||
}
|
||||
return acc.concat(el);
|
||||
}
|
||||
|
||||
export function sortByOrder(
|
||||
a: { order?: number | undefined },
|
||||
b: { order?: number | undefined }
|
||||
) {
|
||||
const left = a.order === undefined ? Number.MAX_SAFE_INTEGER : a.order;
|
||||
const right = b.order === undefined ? Number.MAX_SAFE_INTEGER : b.order;
|
||||
return left - right;
|
||||
}
|
||||
|
||||
export function filterEnabled(entry: { disabled?: boolean }): boolean {
|
||||
return !entry.disabled;
|
||||
}
|
||||
|
||||
export function copyAction(action: ContentActionExtension): ContentActionExtension {
|
||||
return {
|
||||
...action,
|
||||
children: (action.children || []).map(copyAction)
|
||||
};
|
||||
}
|
Reference in New Issue
Block a user