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 ] })