diff --git a/src/app/extensions/core.extensions.module.ts b/src/app/extensions/core.extensions.module.ts
index 9cc7bebfe..e5dd8aa00 100644
--- a/src/app/extensions/core.extensions.module.ts
+++ b/src/app/extensions/core.extensions.module.ts
@@ -39,6 +39,7 @@ import { ToolbarButtonComponent } from './components/toolbar/toolbar-button.comp
import { MetadataTabComponent } from '../components/info-drawer/metadata-tab/metadata-tab.component';
import { CommentsTabComponent } from '../components/info-drawer/comments-tab/comments-tab.component';
import { VersionsTabComponent } from '../components/info-drawer/versions-tab/versions-tab.component';
+import { ExtensionLoaderService } from './extension-loader.service';
export function setupExtensions(extensions: ExtensionService): Function {
extensions.setComponents({
@@ -106,6 +107,7 @@ export class CoreExtensionsModule {
return {
ngModule: CoreExtensionsModule,
providers: [
+ ExtensionLoaderService,
ExtensionService,
{
provide: APP_INITIALIZER,
diff --git a/src/app/extensions/extension-element.ts b/src/app/extensions/extension-element.ts
new file mode 100644
index 000000000..2b3604f4f
--- /dev/null
+++ b/src/app/extensions/extension-element.ts
@@ -0,0 +1,31 @@
+/*!
+ * @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 .
+ */
+
+export interface ExtensionElement {
+ id: string;
+
+ order?: number;
+ disabled?: boolean;
+}
diff --git a/src/app/extensions/extension-loader.service.ts b/src/app/extensions/extension-loader.service.ts
new file mode 100644
index 000000000..ba636f552
--- /dev/null
+++ b/src/app/extensions/extension-loader.service.ts
@@ -0,0 +1,140 @@
+/*!
+ * @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 .
+ */
+
+import { Injectable } from '@angular/core';
+import { ExtensionConfig } from './extension.config';
+import { HttpClient } from '@angular/common/http';
+import { ExtensionElement } from './extension-element';
+import { ContentActionRef, ContentActionType, ActionRef } from './action.extensions';
+import { RuleRef } from './rule.extensions';
+import { RouteRef } from './routing.extensions';
+import { sortByOrder, filterEnabled, getValue, mergeObjects } from './extension-utils';
+
+@Injectable()
+export class ExtensionLoaderService {
+ constructor(private http: HttpClient) {}
+
+ load(configPath: string, pluginsPath: string): Promise {
+ return new Promise(resolve => {
+ this.loadConfig(configPath, 0).then(result => {
+ let config = result.config;
+
+ const override = sessionStorage.getItem('aca.extension.config');
+ if (override) {
+ console.log('overriding extension config');
+ config = JSON.parse(override);
+ }
+
+ const externalPlugins = localStorage.getItem('experimental.external-plugins') === 'true';
+
+ if (externalPlugins && config.$references && config.$references.length > 0) {
+ const plugins = config.$references.map(
+ (name, idx) => this.loadConfig(`${pluginsPath}/${name}`, idx)
+ );
+
+ Promise.all(plugins).then((results => {
+ const configs = results
+ .filter(entry => entry)
+ .sort(sortByOrder)
+ .map(entry => entry.config);
+
+ if (configs.length > 0) {
+ config = mergeObjects(config, ...configs);
+ }
+
+ resolve(config);
+ }));
+ } else {
+ resolve(config);
+ }
+ });
+ });
+ }
+
+ protected loadConfig(
+ url: string,
+ order: number
+ ): Promise<{ order: number; config: ExtensionConfig }> {
+ return new Promise(resolve => {
+ this.http.get(url).subscribe(
+ config => {
+ resolve({
+ order,
+ config
+ });
+ },
+ error => {
+ console.log(error);
+ resolve(null);
+ }
+ );
+ });
+ }
+
+ getElements(
+ config: ExtensionConfig,
+ key: string,
+ fallback: Array = []
+ ): Array {
+ const values = getValue(config, key) || fallback || [];
+ return values.filter(filterEnabled).sort(sortByOrder);
+ }
+
+ getContentActions(
+ config: ExtensionConfig,
+ key: string
+ ): Array {
+ return this.getElements(config, key).map(this.setActionDefaults);
+ }
+
+ getRules(config: ExtensionConfig): Array {
+ if (config && config.rules) {
+ return config.rules;
+ }
+ return [];
+ }
+
+ getRoutes(config: ExtensionConfig): Array {
+ if (config) {
+ return config.routes || [];
+ }
+ return [];
+ }
+
+ getActions(config: ExtensionConfig): Array {
+ if (config) {
+ return config.actions || [];
+ }
+ return [];
+ }
+
+ protected setActionDefaults(action: ContentActionRef): ContentActionRef {
+ if (action) {
+ action.type = action.type || ContentActionType.default;
+ action.icon = action.icon || 'extension';
+ }
+ return action;
+ }
+}
diff --git a/src/app/extensions/extension-utils.ts b/src/app/extensions/extension-utils.ts
new file mode 100644
index 000000000..56a8572f4
--- /dev/null
+++ b/src/app/extensions/extension-utils.ts
@@ -0,0 +1,158 @@
+/*!
+ * @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 .
+ */
+
+import { ContentActionRef, ContentActionType } from './action.extensions';
+
+export function getValue(target: any, key: string): any {
+ if (!target) {
+ return undefined;
+ }
+
+ const keys = key.split('.');
+ key = '';
+
+ do {
+ key += keys.shift();
+ const value = target[key];
+ if (
+ value !== undefined &&
+ (typeof value === 'object' || !keys.length)
+ ) {
+ target = value;
+ key = '';
+ } else if (!keys.length) {
+ target = undefined;
+ } else {
+ key += '.';
+ }
+ } while (keys.length);
+
+ return target;
+}
+
+export function filterEnabled(entry: { disabled?: boolean }): boolean {
+ return !entry.disabled;
+}
+
+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 reduceSeparators(
+ acc: ContentActionRef[],
+ el: ContentActionRef,
+ i: number,
+ arr: ContentActionRef[]
+): ContentActionRef[] {
+ // remove leading separator
+ if (i === 0) {
+ if (arr[i].type === ContentActionType.separator) {
+ return acc;
+ }
+ }
+ // 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: ContentActionRef[],
+ el: ContentActionRef
+): ContentActionRef[] {
+ if (el.type === ContentActionType.menu) {
+ if ((el.children || []).length === 0) {
+ return acc;
+ }
+ }
+ return acc.concat(el);
+}
+
+export function mergeObjects(...objects): any {
+ const result = {};
+
+ objects.forEach(source => {
+ Object.keys(source).forEach(prop => {
+ if (!prop.startsWith('$')) {
+ if (prop in result && Array.isArray(result[prop])) {
+ // result[prop] = result[prop].concat(source[prop]);
+ result[prop] = mergeArrays(result[prop], source[prop]);
+ } else if (prop in result && typeof result[prop] === 'object') {
+ result[prop] = mergeObjects(result[prop], source[prop]);
+ } else {
+ result[prop] = source[prop];
+ }
+ }
+ });
+ });
+
+ return result;
+}
+
+export function mergeArrays(left: any[], right: any[]): any[] {
+ const result = [];
+ const map = {};
+
+ (left || []).forEach(entry => {
+ const element = entry;
+ if (element && element.hasOwnProperty('id')) {
+ map[element.id] = element;
+ } else {
+ result.push(element);
+ }
+ });
+
+ (right || []).forEach(entry => {
+ const element = entry;
+ if (element && element.hasOwnProperty('id') && map[element.id]) {
+ const merged = mergeObjects(map[element.id], element);
+ map[element.id] = merged;
+ } else {
+ result.push(element);
+ }
+ });
+
+ return Object.values(map).concat(result);
+}
diff --git a/src/app/extensions/extension.config.ts b/src/app/extensions/extension.config.ts
index 6fb4aed11..86cd76634 100644
--- a/src/app/extensions/extension.config.ts
+++ b/src/app/extensions/extension.config.ts
@@ -23,32 +23,21 @@
* along with Alfresco. If not, see .
*/
-import { NavBarGroupRef } from './navbar.extensions';
import { RouteRef } from './routing.extensions';
import { RuleRef } from './rule.extensions';
-import { ActionRef, ContentActionRef } from './action.extensions';
-import { SidebarTabRef } from './sidebar.extensions';
-import { ViewerExtensionRef } from './viewer.extensions';
+import { ActionRef } from './action.extensions';
export interface ExtensionConfig {
$name: string;
$version: string;
$description?: string;
$references?: Array;
+
rules?: Array;
routes?: Array;
actions?: Array;
+
features?: {
[key: string]: any;
- create?: Array;
- viewer?: {
- openWith?: Array;
- toolbar?: Array;
- content?: Array;
- };
- navbar?: Array;
- sidebar?: Array;
- toolbar?: Array;
- contextMenu?: Array;
};
}
diff --git a/src/app/extensions/extension.service.spec.ts b/src/app/extensions/extension.service.spec.ts
index 9a73383ee..758f7672c 100644
--- a/src/app/extensions/extension.service.spec.ts
+++ b/src/app/extensions/extension.service.spec.ts
@@ -29,6 +29,7 @@ import { ExtensionService } from './extension.service';
import { Store } from '@ngrx/store';
import { AppStore } from '../store/states';
import { ContentActionType } from './action.extensions';
+import { mergeArrays, sortByOrder, filterEnabled, reduceSeparators, reduceEmptyMenus } from './extension-utils';
describe('ExtensionService', () => {
let extensions: ExtensionService;
@@ -70,7 +71,7 @@ describe('ExtensionService', () => {
}
];
- const result = extensions.mergeArrays(left, right);
+ const result = mergeArrays(left, right);
expect(result).toEqual([
{
id: '#1',
@@ -501,7 +502,7 @@ describe('ExtensionService', () => {
{ id: '1', order: 10 },
{ id: '2', order: 1 },
{ id: '3', order: 5 }
- ].sort(extensions.sortByOrder);
+ ].sort(sortByOrder);
expect(sorted[0].id).toBe('2');
expect(sorted[1].id).toBe('3');
@@ -513,7 +514,7 @@ describe('ExtensionService', () => {
{ id: '3'},
{ id: '2' },
{ id: '1', order: 1 }
- ].sort(extensions.sortByOrder);
+ ].sort(sortByOrder);
expect(sorted[0].id).toBe('1');
expect(sorted[1].id).toBe('3');
@@ -527,7 +528,7 @@ describe('ExtensionService', () => {
{ id: 1, disabled: true },
{ id: 2 },
{ id: 3, disabled: true }
- ].filter(extensions.filterEnabled);
+ ].filter(filterEnabled);
expect(items.length).toBe(1);
expect(items[0].id).toBe(2);
@@ -543,7 +544,7 @@ describe('ExtensionService', () => {
{ id: '5', type: ContentActionType.button }
];
- const result = actions.reduce(extensions.reduceSeparators, []);
+ const result = actions.reduce(reduceSeparators, []);
expect(result.length).toBe(3);
expect(result[0].id).toBe('1');
expect(result[1].id).toBe('2');
@@ -556,7 +557,7 @@ describe('ExtensionService', () => {
{ id: '2', type: ContentActionType.separator }
];
- const result = actions.reduce(extensions.reduceSeparators, []);
+ const result = actions.reduce(reduceSeparators, []);
expect(result.length).toBe(1);
expect(result[0].id).toBe('1');
});
@@ -575,7 +576,7 @@ describe('ExtensionService', () => {
}
];
- const result = actions.reduce(extensions.reduceEmptyMenus, []);
+ const result = actions.reduce(reduceEmptyMenus, []);
expect(result.length).toBe(2);
expect(result[0].id).toBe('1');
diff --git a/src/app/extensions/extension.service.ts b/src/app/extensions/extension.service.ts
index c335ca164..9d55aafdb 100644
--- a/src/app/extensions/extension.service.ts
+++ b/src/app/extensions/extension.service.ts
@@ -24,7 +24,6 @@
*/
import { Injectable, Type } from '@angular/core';
-import { HttpClient } from '@angular/common/http';
import { Store } from '@ngrx/store';
import { Route } from '@angular/router';
import { ExtensionConfig } from './extension.config';
@@ -40,6 +39,8 @@ import { NodePermissionService } from '../services/node-permission.service';
import { SidebarTabRef } from './sidebar.extensions';
import { ProfileResolver } from '../services/profile.resolver';
import { ViewerExtensionRef } from './viewer.extensions';
+import { ExtensionLoaderService } from './extension-loader.service';
+import { sortByOrder, filterEnabled, reduceSeparators, reduceEmptyMenus } from './extension-utils';
@Injectable()
export class ExtensionService implements RuleContext {
@@ -72,8 +73,8 @@ export class ExtensionService implements RuleContext {
navigation: NavigationState;
constructor(
- private http: HttpClient,
private store: Store,
+ private loader: ExtensionLoaderService,
public permissions: NodePermissionService) {
this.evaluators = {
@@ -88,43 +89,9 @@ export class ExtensionService implements RuleContext {
});
}
- load(): Promise {
- return new Promise(resolve => {
- this.loadConfig(this.configPath, 0).then(result => {
- let config = result.config;
-
- const override = sessionStorage.getItem('aca.extension.config');
- if (override) {
- console.log('overriding extension config');
- config = JSON.parse(override);
- }
-
- const externalPlugins = localStorage.getItem('experimental.external-plugins') === 'true';
-
- if (externalPlugins && config.$references && config.$references.length > 0) {
- const plugins = config.$references.map(
- (name, idx) => this.loadConfig(`${this.pluginsPath}/${name}`, idx)
- );
-
- Promise.all(plugins).then((results => {
- const configs = results
- .filter(entry => entry)
- .sort(this.sortByOrder)
- .map(entry => entry.config);
-
- if (configs.length > 0) {
- config = this.mergeObjects(config, ...configs);
- }
-
- this.setup(config);
- resolve(true);
- }));
- } else {
- this.setup(config);
- resolve(true);
- }
- });
- });
+ async load() {
+ const config = await this.loader.load(this.configPath, this.pluginsPath);
+ this.setup(config);
}
setup(config: ExtensionConfig) {
@@ -133,143 +100,38 @@ export class ExtensionService implements RuleContext {
return;
}
- this.rules = this.loadRules(config);
- this.actions = this.loadActions(config);
- this.routes = this.loadRoutes(config);
- this.toolbarActions = this.loadToolbarActions(config);
- this.viewerToolbarActions = this.loadViewerToolbarActions(config);
- this.viewerContentExtensions = this.loadViewerContentExtensions(config);
- this.contextMenuActions = this.loadContextMenuActions(config);
- this.openWithActions = this.loadViewerOpenWith(config);
- this.createActions = this.loadCreateActions(config);
+ this.rules = this.loader.getRules(config);
+ this.actions = this.loader.getActions(config);
+ this.routes = this.loader.getRoutes(config);
+ this.toolbarActions = this.loader.getContentActions(config, 'features.toolbar');
+ this.viewerToolbarActions = this.loader.getContentActions(config, 'features.viewer.toolbar');
+ this.viewerContentExtensions = this.loader.getElements(config, 'features.viewer.content');
+ this.contextMenuActions = this.loader.getContentActions(config, 'features.contextMenu');
+ this.openWithActions = this.loader.getContentActions(config, 'features.viewer.openWith');
+ this.createActions = this.loader.getElements(config, 'features.create');
this.navbar = this.loadNavBar(config);
- this.sidebar = this.loadSidebar(config);
- }
-
- protected loadConfig(url: string, order: number): Promise<{ order: number, config: ExtensionConfig }> {
- return new Promise(resolve => {
- this.http.get(url).subscribe(
- config => {
- resolve({
- order,
- config
- });
- },
- error => {
- console.log(error);
- resolve(null);
- }
- );
- });
- }
-
- protected loadCreateActions(config: ExtensionConfig): Array {
- if (config && config.features) {
- return (config.features.create || []).sort(
- this.sortByOrder
- );
- }
- return [];
- }
-
- protected loadToolbarActions(config: ExtensionConfig) {
- if (config && config.features && config.features.toolbar) {
- return (config.features.toolbar || [])
- .sort(this.sortByOrder)
- .map(this.setActionDefaults);
- }
- return [];
- }
-
- protected loadViewerToolbarActions(config: ExtensionConfig): Array {
- if (config && config.features && config.features.viewer) {
- return (config.features.viewer.toolbar || [])
- .sort(this.sortByOrder)
- .map(this.setActionDefaults);
- }
- return [];
- }
-
- protected loadViewerContentExtensions(config: ExtensionConfig): Array {
- if (config && config.features && config.features.viewer) {
- return (config.features.viewer.content || [])
- .filter(entry => !entry.disabled)
- .sort(this.sortByOrder);
- }
- return [];
- }
-
- protected loadContextMenuActions(config: ExtensionConfig): Array {
- if (config && config.features && config.features.contextMenu) {
- return (config.features.contextMenu || [])
- .sort(this.sortByOrder)
- .map(this.setActionDefaults);
- }
- return [];
+ this.sidebar = this.loader.getElements(config, 'features.sidebar');
}
protected loadNavBar(config: ExtensionConfig): Array {
- if (config && config.features) {
- return (config.features.navbar || [])
- .filter(entry => !entry.disabled)
- .sort(this.sortByOrder)
- .map(group => {
- return {
- ...group,
- items: (group.items || [])
- .filter(item => !item.disabled)
- .sort(this.sortByOrder)
- .map(item => {
- const routeRef = this.getRouteById(item.route);
- const url = `/${routeRef ? routeRef.path : item.route}`;
- return {
- ...item,
- url
- };
- })
- };
- });
- }
- return [];
- }
+ const elements = this.loader.getElements(config, 'features.navbar');
- protected loadSidebar(config: ExtensionConfig): Array {
- if (config && config.features) {
- return (config.features.sidebar || [])
- .filter(entry => !entry.disabled)
- .sort(this.sortByOrder);
- }
- return [];
- }
-
- protected loadViewerOpenWith(config: ExtensionConfig): Array {
- if (config && config.features && config.features.viewer) {
- return (config.features.viewer.openWith || [])
- .filter(entry => !entry.disabled)
- .sort(this.sortByOrder);
- }
- return [];
- }
-
- protected loadRules(config: ExtensionConfig): Array {
- if (config && config.rules) {
- return config.rules;
- }
- return [];
- }
-
- protected loadRoutes(config: ExtensionConfig): Array {
- if (config) {
- return config.routes || [];
- }
- return [];
- }
-
- protected loadActions(config: ExtensionConfig): Array {
- if (config) {
- return config.actions || [];
- }
- return [];
+ return elements.map(group => {
+ return {
+ ...group,
+ items: (group.items || [])
+ .filter(item => !item.disabled)
+ .sort(sortByOrder)
+ .map(item => {
+ const routeRef = this.getRouteById(item.route);
+ const url = `/${routeRef ? routeRef.path : item.route}`;
+ return {
+ ...item,
+ url
+ };
+ })
+ };
+ });
}
setEvaluators(values: { [key: string]: RuleEvaluator }) {
@@ -339,7 +201,7 @@ export class ExtensionService implements RuleContext {
getCreateActions(): Array {
return this.createActions
- .filter(this.filterEnabled)
+ .filter(filterEnabled)
.filter(action => this.filterByRules(action))
.map(action => {
let disabled = false;
@@ -358,7 +220,7 @@ export class ExtensionService implements RuleContext {
// evaluates content actions for the selection and parent folder node
getAllowedToolbarActions(): Array {
return this.toolbarActions
- .filter(this.filterEnabled)
+ .filter(filterEnabled)
.filter(action => this.filterByRules(action))
.map(action => {
if (action.type === ContentActionType.menu) {
@@ -368,94 +230,28 @@ export class ExtensionService implements RuleContext {
.filter(childAction =>
this.filterByRules(childAction)
)
- .reduce(this.reduceSeparators, []);
+ .reduce(reduceSeparators, []);
}
return copy;
}
return action;
})
- .reduce(this.reduceEmptyMenus, [])
- .reduce(this.reduceSeparators, []);
+ .reduce(reduceEmptyMenus, [])
+ .reduce(reduceSeparators, []);
}
getViewerToolbarActions(): Array {
return this.viewerToolbarActions
- .filter(this.filterEnabled)
+ .filter(filterEnabled)
.filter(action => this.filterByRules(action));
}
getAllowedContextMenuActions(): Array {
return this.contextMenuActions
- .filter(this.filterEnabled)
+ .filter(filterEnabled)
.filter(action => this.filterByRules(action));
}
- setActionDefaults(action: ContentActionRef): ContentActionRef {
- if (action) {
- action.type = action.type || ContentActionType.default;
- action.icon = action.icon || 'extension';
- }
- return action;
- }
-
- reduceSeparators(
- acc: ContentActionRef[],
- el: ContentActionRef,
- i: number,
- arr: ContentActionRef[]
- ): ContentActionRef[] {
- // remove leading separator
- if (i === 0) {
- if (arr[i].type === ContentActionType.separator) {
- return acc;
- }
- }
- // 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);
- }
-
- reduceEmptyMenus(
- acc: ContentActionRef[],
- el: ContentActionRef
- ): ContentActionRef[] {
- if (el.type === ContentActionType.menu) {
- if ((el.children || []).length === 0) {
- return acc;
- }
- }
- return acc.concat(el);
- }
-
- 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;
- }
-
- filterEnabled(entry: { disabled?: boolean }): boolean {
- return !entry.disabled;
- }
-
copyAction(action: ContentActionRef): ContentActionRef {
return {
...action,
@@ -529,51 +325,4 @@ export class ExtensionService implements RuleContext {
}
return false;
}
-
- mergeObjects(...objects): any {
- const result = {};
-
- objects.forEach(source => {
- Object.keys(source).forEach(prop => {
- if (!prop.startsWith('$')) {
- if (prop in result && Array.isArray(result[prop])) {
- // result[prop] = result[prop].concat(source[prop]);
- result[prop] = this.mergeArrays(result[prop], source[prop]);
- } else if (prop in result && typeof result[prop] === 'object') {
- result[prop] = this.mergeObjects(result[prop], source[prop]);
- } else {
- result[prop] = source[prop];
- }
- }
- });
- });
-
- return result;
- }
-
- mergeArrays(left: any[], right: any[]): any[] {
- const result = [];
- const map = {};
-
- (left || []).forEach(entry => {
- const element = entry;
- if (element && element.hasOwnProperty('id')) {
- map[element.id] = element;
- } else {
- result.push(element);
- }
- });
-
- (right || []).forEach(entry => {
- const element = entry;
- if (element && element.hasOwnProperty('id') && map[element.id]) {
- const merged = this.mergeObjects(map[element.id], element);
- map[element.id] = merged;
- } else {
- result.push(element);
- }
- });
-
- return Object.values(map).concat(result);
- }
}
diff --git a/src/app/extensions/navbar.extensions.ts b/src/app/extensions/navbar.extensions.ts
index e456cd737..3eb972804 100644
--- a/src/app/extensions/navbar.extensions.ts
+++ b/src/app/extensions/navbar.extensions.ts
@@ -23,22 +23,17 @@
* along with Alfresco. If not, see .
*/
-export interface NavBarGroupRef {
- id: string;
- items: Array;
+import { ExtensionElement } from './extension-element';
- order?: number;
- disabled?: boolean;
+export interface NavBarGroupRef extends ExtensionElement {
+ items: Array;
}
-export interface NavBarLinkRef {
- id: string;
+export interface NavBarLinkRef extends ExtensionElement {
icon: string;
title: string;
route: string;
url?: string; // evaluated at runtime based on route ref
description?: string;
- order?: number;
- disabled?: boolean;
}
diff --git a/src/app/extensions/sidebar.extensions.ts b/src/app/extensions/sidebar.extensions.ts
index a64807d68..bb72c9630 100644
--- a/src/app/extensions/sidebar.extensions.ts
+++ b/src/app/extensions/sidebar.extensions.ts
@@ -23,14 +23,13 @@
* along with Alfresco. If not, see .
*/
-export class SidebarTabRef {
- id: string;
+import { ExtensionElement } from './extension-element';
+
+export interface SidebarTabRef extends ExtensionElement {
title: string;
component: string;
icon?: string;
- disabled?: boolean;
- order?: number;
rules?: {
visible?: string;
[key: string]: string;
diff --git a/src/app/extensions/viewer.extensions.ts b/src/app/extensions/viewer.extensions.ts
index aff7d1d2e..063a94b5a 100644
--- a/src/app/extensions/viewer.extensions.ts
+++ b/src/app/extensions/viewer.extensions.ts
@@ -23,11 +23,9 @@
* along with Alfresco. If not, see .
*/
-export interface ViewerExtensionRef {
- id: string;
+import { ExtensionElement } from './extension-element';
+
+export interface ViewerExtensionRef extends ExtensionElement {
fileExtension: string;
component: string;
-
- disabled?: boolean;
- order?: number;
}
diff --git a/src/app/testing/app-testing.module.ts b/src/app/testing/app-testing.module.ts
index 939e66e73..a958cd1de 100644
--- a/src/app/testing/app-testing.module.ts
+++ b/src/app/testing/app-testing.module.ts
@@ -61,6 +61,7 @@ import { NodePermissionService } from '../services/node-permission.service';
import { ContentApiService } from '../services/content-api.service';
import { ExtensionService } from '../extensions/extension.service';
import { ViewUtilService } from '../components/preview/view-util.service';
+import { ExtensionLoaderService } from '../extensions/extension-loader.service';
@NgModule({
imports: [
@@ -114,6 +115,7 @@ import { ViewUtilService } from '../components/preview/view-util.service';
NodePermissionService,
ContentApiService,
ExtensionService,
+ ExtensionLoaderService,
ViewUtilService
]
})