diff --git a/lib/extensions/src/lib/config/extension.config.ts b/lib/extensions/src/lib/config/extension.config.ts index 844aa0fa98..b718b6fedf 100644 --- a/lib/extensions/src/lib/config/extension.config.ts +++ b/lib/extensions/src/lib/config/extension.config.ts @@ -41,4 +41,5 @@ export interface ExtensionRef { export interface ExtensionConfig extends ExtensionRef { $references?: Array; + $ignoreReferenceList?: Array; } diff --git a/lib/extensions/src/lib/config/schema/plugin-extension.schema.json b/lib/extensions/src/lib/config/schema/plugin-extension.schema.json index f8b679245d..68c5b9f282 100644 --- a/lib/extensions/src/lib/config/schema/plugin-extension.schema.json +++ b/lib/extensions/src/lib/config/schema/plugin-extension.schema.json @@ -593,6 +593,15 @@ "minItems": 0, "uniqueItems": true }, + "$ignoreReferenceList": { + "description": "Plugins references to exclude", + "type": "array", + "items": { + "type": "string" + }, + "minItems": 0, + "uniqueItems": true + }, "rules": { "description": "List of rule definitions", "type": "array", diff --git a/lib/extensions/src/lib/services/extension-loader.service.spec.ts b/lib/extensions/src/lib/services/extension-loader.service.spec.ts new file mode 100644 index 0000000000..8b9f13dc6a --- /dev/null +++ b/lib/extensions/src/lib/services/extension-loader.service.spec.ts @@ -0,0 +1,121 @@ +/*! + * @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 { async, TestBed } from '@angular/core/testing'; +import { HttpClientTestingModule } from '@angular/common/http/testing'; +import { ExtensionConfig } from '../config/extension.config'; +import { ExtensionLoaderService } from './extension-loader.service'; +import { HttpClient } from '@angular/common/http'; +import { of } from 'rxjs'; + +describe('ExtensionLoaderService', () => { + let extensionLoaderService: ExtensionLoaderService; + let httpClient: HttpClient; + let appExtensionsConfig: ExtensionConfig; + const pluginConfig1: ExtensionConfig = { + $id: 'test1', + $name: 'test.extension.1', + $version: '1.0.0', + $vendor: 'Alfresco', + $license: 'MIT', + $runtime: '2.6.1' + }; + const pluginConfig2: ExtensionConfig = { + $id: 'test2', + $name: 'test.extension.2', + $version: '1.0.0', + $vendor: 'Alfresco', + $license: 'MIT', + $runtime: '2.6.1' + }; + const pluginConfig3: ExtensionConfig = { + $id: 'test3', + $name: 'test.extension.3', + $version: '1.0.0', + $vendor: 'Alfresco', + $license: 'MIT', + $runtime: '2.6.1' + }; + + beforeEach(() => { + TestBed.configureTestingModule({ + imports: [HttpClientTestingModule], + providers: [ + HttpClient, + ExtensionLoaderService + ] + }); + extensionLoaderService = TestBed.inject(ExtensionLoaderService); + httpClient = TestBed.inject(HttpClient); + + appExtensionsConfig = { + $id: 'test', + $name: 'test.config', + $version: '1.0.0', + $vendor: 'Alfresco', + $license: 'MIT', + $runtime: '2.6.1', + $references: [], + $ignoreReferenceList: [] + }; + + spyOn(httpClient, 'get').and.callFake((url: string) => { + if (url === 'assets/app.extensions.json') { + return of(appExtensionsConfig); + } + + if (url === 'assets/plugins/test.extension.1.json') { + return of(pluginConfig1); + } + + if (url === 'assets/plugins/test.extension.2.json') { + return of(pluginConfig2); + } + + if (url === 'assets/plugins/test.extension.3.json') { + return of(pluginConfig3); + } + + return of({}); + }); + }); + + it('should load default registered app extensions when no custom $references defined', async(() => { + extensionLoaderService.load('assets/app.extensions.json', 'assets/plugins', ['test.extension.1.json']).then((config: ExtensionConfig) => { + const pluginsReference = config.$references.map((entry: ExtensionConfig) => entry.$name); + expect(pluginsReference).toEqual(['test.extension.1']); + }); + })); + + it('should ignore default registered app extension if defined in $ignoreReferenceList', async(() => { + appExtensionsConfig.$ignoreReferenceList = ['test.extension.1.json']; + + extensionLoaderService.load('assets/app.extensions.json', 'assets/plugins', ['test.extension.1.json']).then((config: ExtensionConfig) => { + const pluginsReference = config.$references.map((entry: ExtensionConfig) => entry.$name); + expect(pluginsReference).toEqual([]); + }); + })); + + it('should load only extensions defined by $references', async(() => { + appExtensionsConfig.$references = ['test.extension.1.json']; + + extensionLoaderService.load('assets/app.extensions.json', 'assets/plugins', ['test.extension.2.json, test.extension.3.json']).then((config: ExtensionConfig) => { + const pluginsReference = config.$references.map((entry: ExtensionConfig) => entry.$name); + expect(pluginsReference).toEqual(['test.extension.1']); + }); + })); +}); diff --git a/lib/extensions/src/lib/services/extension-loader.service.ts b/lib/extensions/src/lib/services/extension-loader.service.ts index be75b3b786..3f2635f43a 100644 --- a/lib/extensions/src/lib/services/extension-loader.service.ts +++ b/lib/extensions/src/lib/services/extension-loader.service.ts @@ -31,7 +31,7 @@ export class ExtensionLoaderService { constructor(private http: HttpClient) { } - load(configPath: string, pluginsPath: string, extensions?: ExtensionConfig[]): Promise { + load(configPath: string, pluginsPath: string, extensions?: string[]): Promise { return new Promise((resolve) => { this.loadConfig(configPath, 0).then((result) => { if (result) { @@ -42,6 +42,12 @@ export class ExtensionLoaderService { config = JSON.parse(override); } + if (!config.$references || !config.$references.length) { + config.$references = this.filterIgnoredExtensions(extensions || [], config.$ignoreReferenceList); + } else { + config.$references = this.filterIgnoredExtensions(config.$references, config.$ignoreReferenceList); + } + if (config.$references && config.$references.length > 0) { const plugins = config.$references.map((name, idx) => this.loadConfig(`${pluginsPath}/${name}`, idx) @@ -53,10 +59,6 @@ export class ExtensionLoaderService { .sort(sortByOrder) .map((entry) => entry.config); - if (extensions && extensions.length > 0) { - configs.push(...extensions); - } - if (configs.length > 0) { config = mergeObjects(config, ...configs); } @@ -166,4 +168,12 @@ export class ExtensionLoaderService { } return action; } + + private filterIgnoredExtensions(extensions: Array, ignoreReferenceList: string[]): Array { + if (!ignoreReferenceList || !ignoreReferenceList.length) { + return extensions; + } + + return extensions.map((file: string) => file.match('(?!.*\/).+')[0]).filter((fileName: string) => !ignoreReferenceList.includes(fileName)); + } } diff --git a/lib/extensions/src/lib/services/extension.service.ts b/lib/extensions/src/lib/services/extension.service.ts index 69b53fb704..518f785967 100644 --- a/lib/extensions/src/lib/services/extension.service.ts +++ b/lib/extensions/src/lib/services/extension.service.ts @@ -17,7 +17,7 @@ import { Injectable, Type, InjectionToken, Inject } from '@angular/core'; import { RuleEvaluator, RuleRef, RuleContext } from '../config/rule.extensions'; -import { ExtensionConfig, ExtensionRef } from '../config/extension.config'; +import { ExtensionConfig } from '../config/extension.config'; import { ExtensionLoaderService } from './extension-loader.service'; import { RouteRef } from '../config/routing.extensions'; import { ActionRef } from '../config/action.extensions'; @@ -30,12 +30,12 @@ export function extensionJsonsFactory() { return []; } -export const EXTENSION_JSONS = new InjectionToken('extension-jsons', { +export const EXTENSION_JSONS = new InjectionToken('extension-jsons', { providedIn: 'root', factory: extensionJsonsFactory }); -export function provideExtensionConfig(jsons: ExtensionRef[]) { +export function provideExtensionConfig(jsons: string[]) { return { provide: EXTENSION_JSONS, useValue: jsons, @@ -62,7 +62,7 @@ export class ExtensionService { protected loader: ExtensionLoaderService, protected componentRegister: ComponentRegisterService, protected ruleService: RuleService, - @Inject(EXTENSION_JSONS) protected extensionJsons: ExtensionRef[] + @Inject(EXTENSION_JSONS) protected extensionJsons: string[] ) { }