mirror of
https://github.com/Alfresco/alfresco-ng2-components.git
synced 2025-07-24 17:32:15 +00:00
move adf-extensions lib to the ADF repo (#3781)
* adf-extensions lib * remove console.log calls * integrate with angular.json * fix output path * update scripts * Add extensions to scripts * update travis setup * Travis step II.
This commit is contained in:
committed by
Eugenio Romano
parent
9a9c3dbfbc
commit
155131370c
@@ -30,6 +30,9 @@ jobs:
|
|||||||
- stage: Unit test
|
- stage: Unit test
|
||||||
env: STAGE=core
|
env: STAGE=core
|
||||||
script: (./scripts/npm-build-all.sh -si -sb -t "core" --skip-lint || exit 1;);
|
script: (./scripts/npm-build-all.sh -si -sb -t "core" --skip-lint || exit 1;);
|
||||||
|
- stage: Unit test
|
||||||
|
env: STAGE=extensions
|
||||||
|
script: (./scripts/npm-build-all.sh -si -sb -t "extensions" --skip-lint || exit 1;);
|
||||||
- stage: Unit test
|
- stage: Unit test
|
||||||
env: STAGE=process-services
|
env: STAGE=process-services
|
||||||
script: (./scripts/npm-build-all.sh -si -sb -t "process-services" --skip-lint|| exit 1;);
|
script: (./scripts/npm-build-all.sh -si -sb -t "process-services" --skip-lint|| exit 1;);
|
||||||
|
36
angular.json
36
angular.json
@@ -660,6 +660,42 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"extensions": {
|
||||||
|
"root": "lib/extensions",
|
||||||
|
"sourceRoot": "lib/extensions/src/lib",
|
||||||
|
"projectType": "library",
|
||||||
|
"prefix": "adf",
|
||||||
|
"architect": {
|
||||||
|
"build": {
|
||||||
|
"builder": "@angular-devkit/build-ng-packagr:build",
|
||||||
|
"options": {
|
||||||
|
"tsConfig": "lib/extensions/tsconfig.lib.json",
|
||||||
|
"project": "lib/extensions/ng-package.json"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"test": {
|
||||||
|
"builder": "@angular-devkit/build-angular:karma",
|
||||||
|
"options": {
|
||||||
|
"main": "lib/extensions/src/test.ts",
|
||||||
|
"tsConfig": "lib/extensions/tsconfig.spec.json",
|
||||||
|
"karmaConfig": "lib/extensions/karma.conf.js",
|
||||||
|
"sourceMap": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"lint": {
|
||||||
|
"builder": "@angular-devkit/build-angular:tslint",
|
||||||
|
"options": {
|
||||||
|
"tsConfig": [
|
||||||
|
"lib/extensions/tsconfig.lib.json",
|
||||||
|
"lib/extensions/tsconfig.spec.json"
|
||||||
|
],
|
||||||
|
"exclude": [
|
||||||
|
"**/node_modules/**"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"defaultProject": "dist",
|
"defaultProject": "dist",
|
||||||
|
42
lib/extensions/karma.conf.js
Normal file
42
lib/extensions/karma.conf.js
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
// Karma configuration file, see link for more information
|
||||||
|
// https://karma-runner.github.io/1.0/config/configuration-file.html
|
||||||
|
|
||||||
|
module.exports = function (config) {
|
||||||
|
config.set({
|
||||||
|
basePath: '',
|
||||||
|
frameworks: ['jasmine', '@angular-devkit/build-angular'],
|
||||||
|
plugins: [
|
||||||
|
require('karma-jasmine'),
|
||||||
|
require('karma-chrome-launcher'),
|
||||||
|
require('karma-jasmine-html-reporter'),
|
||||||
|
require('karma-coverage-istanbul-reporter'),
|
||||||
|
require('@angular-devkit/build-angular/plugins/karma')
|
||||||
|
],
|
||||||
|
client: {
|
||||||
|
clearContext: false // leave Jasmine Spec Runner output visible in browser
|
||||||
|
},
|
||||||
|
coverageIstanbulReporter: {
|
||||||
|
dir: require('path').join(__dirname, '../../coverage'),
|
||||||
|
reports: ['html', 'lcovonly'],
|
||||||
|
fixWebpackSourcePaths: true
|
||||||
|
},
|
||||||
|
reporters: ['progress', 'kjhtml'],
|
||||||
|
port: 9876,
|
||||||
|
colors: true,
|
||||||
|
logLevel: config.LOG_INFO,
|
||||||
|
autoWatch: true,
|
||||||
|
browsers: [/*'Chrome',*/ 'ChromeHeadless'],
|
||||||
|
customLaunchers: {
|
||||||
|
ChromeHeadless: {
|
||||||
|
base: 'Chrome',
|
||||||
|
flags: [
|
||||||
|
'--no-sandbox',
|
||||||
|
'--headless',
|
||||||
|
'--disable-gpu',
|
||||||
|
'--remote-debugging-port=9222'
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
singleRun: false
|
||||||
|
});
|
||||||
|
};
|
13
lib/extensions/ng-package.json
Normal file
13
lib/extensions/ng-package.json
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
{
|
||||||
|
"$schema": "../../node_modules/ng-packagr/ng-package.schema.json",
|
||||||
|
"dest": "../dist/extensions/",
|
||||||
|
"deleteDestPath": false,
|
||||||
|
"lib": {
|
||||||
|
"languageLevel": ["dom", "es2017"],
|
||||||
|
"entryFile": "src/public_api.ts",
|
||||||
|
"flatModuleFile": "adf-extensions",
|
||||||
|
"umdModuleIds": {
|
||||||
|
"alfresco-js-api": "alfresco-js-api"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
10
lib/extensions/package.json
Normal file
10
lib/extensions/package.json
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
{
|
||||||
|
"name": "@alfresco/adf-extensions",
|
||||||
|
"version": "0.1.0",
|
||||||
|
"peerDependencies": {
|
||||||
|
"@angular/common": "^6.0.0",
|
||||||
|
"@angular/core": "^6.0.0",
|
||||||
|
"@angular/http": "^6.1.4",
|
||||||
|
"alfresco-js-api": "^2.5.0"
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,67 @@
|
|||||||
|
/*!
|
||||||
|
* @license
|
||||||
|
* Copyright 2016 - 2018 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 {
|
||||||
|
Component,
|
||||||
|
Input,
|
||||||
|
ComponentRef,
|
||||||
|
OnInit,
|
||||||
|
ComponentFactoryResolver,
|
||||||
|
ViewChild,
|
||||||
|
ViewContainerRef,
|
||||||
|
OnDestroy
|
||||||
|
} from '@angular/core';
|
||||||
|
import { ExtensionService } from '../../services/extension.service';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'adf-dynamic-component',
|
||||||
|
template: `<div #content></div>`
|
||||||
|
})
|
||||||
|
export class DynamicExtensionComponent implements OnInit, OnDestroy {
|
||||||
|
@ViewChild('content', { read: ViewContainerRef })
|
||||||
|
content: ViewContainerRef;
|
||||||
|
|
||||||
|
@Input() id: string;
|
||||||
|
|
||||||
|
private componentRef: ComponentRef<any>;
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
private extensions: ExtensionService,
|
||||||
|
private componentFactoryResolver: ComponentFactoryResolver
|
||||||
|
) {}
|
||||||
|
|
||||||
|
ngOnInit() {
|
||||||
|
const componentType = this.extensions.getComponentById(this.id);
|
||||||
|
if (componentType) {
|
||||||
|
const factory = this.componentFactoryResolver.resolveComponentFactory(
|
||||||
|
componentType
|
||||||
|
);
|
||||||
|
if (factory) {
|
||||||
|
this.content.clear();
|
||||||
|
this.componentRef = this.content.createComponent(factory, 0);
|
||||||
|
// this.setupWidget(this.componentRef);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ngOnDestroy() {
|
||||||
|
if (this.componentRef) {
|
||||||
|
this.componentRef.destroy();
|
||||||
|
this.componentRef = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,94 @@
|
|||||||
|
/*!
|
||||||
|
* @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,
|
||||||
|
Input,
|
||||||
|
OnInit,
|
||||||
|
OnDestroy,
|
||||||
|
ViewChild,
|
||||||
|
ViewContainerRef,
|
||||||
|
ComponentRef,
|
||||||
|
ComponentFactoryResolver,
|
||||||
|
OnChanges,
|
||||||
|
SimpleChanges
|
||||||
|
} from '@angular/core';
|
||||||
|
import { MinimalNodeEntryEntity } from 'alfresco-js-api';
|
||||||
|
import { ExtensionService } from '../../services/extension.service';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'adf-dynamic-tab',
|
||||||
|
template: `<div #content></div>`
|
||||||
|
})
|
||||||
|
export class DynamicTabComponent implements OnInit, OnChanges, OnDestroy {
|
||||||
|
@ViewChild('content', { read: ViewContainerRef })
|
||||||
|
content: ViewContainerRef;
|
||||||
|
|
||||||
|
@Input()
|
||||||
|
id: string;
|
||||||
|
|
||||||
|
@Input()
|
||||||
|
node: MinimalNodeEntryEntity;
|
||||||
|
|
||||||
|
private componentRef: ComponentRef<any>;
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
private extensions: ExtensionService,
|
||||||
|
private componentFactoryResolver: ComponentFactoryResolver
|
||||||
|
) {}
|
||||||
|
|
||||||
|
ngOnInit() {
|
||||||
|
const componentType = this.extensions.getComponentById(this.id);
|
||||||
|
if (componentType) {
|
||||||
|
const factory = this.componentFactoryResolver.resolveComponentFactory(
|
||||||
|
componentType
|
||||||
|
);
|
||||||
|
if (factory) {
|
||||||
|
this.content.clear();
|
||||||
|
this.componentRef = this.content.createComponent(factory, 0);
|
||||||
|
this.updateInstance();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ngOnChanges(changes: SimpleChanges) {
|
||||||
|
if (changes.node) {
|
||||||
|
this.updateInstance();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ngOnDestroy() {
|
||||||
|
if (this.componentRef) {
|
||||||
|
this.componentRef.destroy();
|
||||||
|
this.componentRef = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private updateInstance() {
|
||||||
|
if (this.componentRef && this.componentRef.instance) {
|
||||||
|
this.componentRef.instance.node = this.node;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
51
lib/extensions/src/lib/config/action.extensions.ts
Normal file
51
lib/extensions/src/lib/config/action.extensions.ts
Normal file
@@ -0,0 +1,51 @@
|
|||||||
|
/*!
|
||||||
|
* @license
|
||||||
|
* Copyright 2016 - 2018 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 { ExtensionElement } from './extension-element';
|
||||||
|
|
||||||
|
export enum ContentActionType {
|
||||||
|
default = 'default',
|
||||||
|
button = 'button',
|
||||||
|
separator = 'separator',
|
||||||
|
menu = 'menu',
|
||||||
|
custom = 'custom'
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ContentActionRef extends ExtensionElement {
|
||||||
|
type: ContentActionType;
|
||||||
|
|
||||||
|
title?: string;
|
||||||
|
description?: string;
|
||||||
|
icon?: string;
|
||||||
|
children?: Array<ContentActionRef>;
|
||||||
|
component?: string;
|
||||||
|
actions?: {
|
||||||
|
click?: string;
|
||||||
|
[key: string]: string;
|
||||||
|
};
|
||||||
|
rules?: {
|
||||||
|
enabled?: string;
|
||||||
|
visible?: string;
|
||||||
|
[key: string]: string;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ActionRef {
|
||||||
|
id: string;
|
||||||
|
type: string;
|
||||||
|
payload?: string;
|
||||||
|
}
|
23
lib/extensions/src/lib/config/extension-element.ts
Normal file
23
lib/extensions/src/lib/config/extension-element.ts
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
/*!
|
||||||
|
* @license
|
||||||
|
* Copyright 2016 - 2018 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
export interface ExtensionElement {
|
||||||
|
id: string;
|
||||||
|
|
||||||
|
order?: number;
|
||||||
|
disabled?: boolean;
|
||||||
|
}
|
150
lib/extensions/src/lib/config/extension-utils.ts
Normal file
150
lib/extensions/src/lib/config/extension-utils.ts
Normal file
@@ -0,0 +1,150 @@
|
|||||||
|
/*!
|
||||||
|
* @license
|
||||||
|
* Copyright 2016 - 2018 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 { 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);
|
||||||
|
}
|
35
lib/extensions/src/lib/config/extension.config.ts
Normal file
35
lib/extensions/src/lib/config/extension.config.ts
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
/*!
|
||||||
|
* @license
|
||||||
|
* Copyright 2016 - 2018 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 { RouteRef } from './routing.extensions';
|
||||||
|
import { RuleRef } from './rule.extensions';
|
||||||
|
import { ActionRef } from './action.extensions';
|
||||||
|
|
||||||
|
export interface ExtensionConfig {
|
||||||
|
$name: string;
|
||||||
|
$version: string;
|
||||||
|
$description?: string;
|
||||||
|
$references?: Array<string>;
|
||||||
|
|
||||||
|
rules?: Array<RuleRef>;
|
||||||
|
routes?: Array<RouteRef>;
|
||||||
|
actions?: Array<ActionRef>;
|
||||||
|
|
||||||
|
features?: {
|
||||||
|
[key: string]: any;
|
||||||
|
};
|
||||||
|
}
|
31
lib/extensions/src/lib/config/navbar.extensions.ts
Normal file
31
lib/extensions/src/lib/config/navbar.extensions.ts
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
/*!
|
||||||
|
* @license
|
||||||
|
* Copyright 2016 - 2018 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 { ExtensionElement } from './extension-element';
|
||||||
|
|
||||||
|
export interface NavBarGroupRef extends ExtensionElement {
|
||||||
|
items: Array<NavBarLinkRef>;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface NavBarLinkRef extends ExtensionElement {
|
||||||
|
icon: string;
|
||||||
|
title: string;
|
||||||
|
route: string;
|
||||||
|
|
||||||
|
url?: string; // evaluated at runtime based on route ref
|
||||||
|
description?: string;
|
||||||
|
}
|
20
lib/extensions/src/lib/config/permission.extensions.ts
Normal file
20
lib/extensions/src/lib/config/permission.extensions.ts
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
/*!
|
||||||
|
* @license
|
||||||
|
* Copyright 2016 - 2018 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
export interface NodePermissions {
|
||||||
|
check(source: any, permissions: string[], options?: any): boolean;
|
||||||
|
}
|
26
lib/extensions/src/lib/config/routing.extensions.ts
Normal file
26
lib/extensions/src/lib/config/routing.extensions.ts
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
/*!
|
||||||
|
* @license
|
||||||
|
* Copyright 2016 - 2018 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
export interface RouteRef {
|
||||||
|
id: string;
|
||||||
|
path: string;
|
||||||
|
component: string;
|
||||||
|
|
||||||
|
layout?: string;
|
||||||
|
auth?: string[];
|
||||||
|
data?: { [key: string]: string };
|
||||||
|
}
|
44
lib/extensions/src/lib/config/rule.extensions.ts
Normal file
44
lib/extensions/src/lib/config/rule.extensions.ts
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
/*!
|
||||||
|
* @license
|
||||||
|
* Copyright 2016 - 2018 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 { SelectionState } from '../store/states/selection.state';
|
||||||
|
import { NavigationState } from '../store/states/navigation.state';
|
||||||
|
import { NodePermissions } from './permission.extensions';
|
||||||
|
import { ProfileState } from '../store/states/profile.state';
|
||||||
|
|
||||||
|
export type RuleEvaluator = (context: RuleContext, ...args: any[]) => boolean;
|
||||||
|
|
||||||
|
export interface RuleContext {
|
||||||
|
selection: SelectionState;
|
||||||
|
navigation: NavigationState;
|
||||||
|
profile: ProfileState;
|
||||||
|
permissions: NodePermissions;
|
||||||
|
|
||||||
|
getEvaluator(key: string): RuleEvaluator;
|
||||||
|
}
|
||||||
|
|
||||||
|
export class RuleRef {
|
||||||
|
type: string;
|
||||||
|
id?: string;
|
||||||
|
parameters?: Array<RuleParameter>;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface RuleParameter {
|
||||||
|
type: string;
|
||||||
|
value: any;
|
||||||
|
parameters?: Array<RuleParameter>;
|
||||||
|
}
|
29
lib/extensions/src/lib/config/sidebar.extensions.ts
Normal file
29
lib/extensions/src/lib/config/sidebar.extensions.ts
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
/*!
|
||||||
|
* @license
|
||||||
|
* Copyright 2016 - 2018 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 { ExtensionElement } from './extension-element';
|
||||||
|
|
||||||
|
export interface SidebarTabRef extends ExtensionElement {
|
||||||
|
title: string;
|
||||||
|
component: string;
|
||||||
|
|
||||||
|
icon?: string;
|
||||||
|
rules?: {
|
||||||
|
visible?: string;
|
||||||
|
[key: string]: string;
|
||||||
|
};
|
||||||
|
}
|
23
lib/extensions/src/lib/config/viewer.extensions.ts
Normal file
23
lib/extensions/src/lib/config/viewer.extensions.ts
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
/*!
|
||||||
|
* @license
|
||||||
|
* Copyright 2016 - 2018 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 { ExtensionElement } from './extension-element';
|
||||||
|
|
||||||
|
export interface ViewerExtensionRef extends ExtensionElement {
|
||||||
|
fileExtension: string;
|
||||||
|
component: string;
|
||||||
|
}
|
237
lib/extensions/src/lib/evaluators/core.evaluators.spec.ts
Normal file
237
lib/extensions/src/lib/evaluators/core.evaluators.spec.ts
Normal file
@@ -0,0 +1,237 @@
|
|||||||
|
/*!
|
||||||
|
* @license
|
||||||
|
* Copyright 2016 - 2018 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 { every, not, some } from './core.evaluators';
|
||||||
|
import { RuleParameter } from '../config/rule.extensions';
|
||||||
|
|
||||||
|
describe('Core Evaluators', () => {
|
||||||
|
|
||||||
|
const context: any = {
|
||||||
|
getEvaluator(key: string) {
|
||||||
|
switch (key) {
|
||||||
|
case 'positive':
|
||||||
|
return () => true;
|
||||||
|
case 'negative':
|
||||||
|
return () => false;
|
||||||
|
default:
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
describe('not', () => {
|
||||||
|
it('should evaluate a single rule to [true]', () => {
|
||||||
|
const parameter: RuleParameter = {
|
||||||
|
type: 'primitive',
|
||||||
|
value: 'negative'
|
||||||
|
};
|
||||||
|
|
||||||
|
const result = not(context, parameter);
|
||||||
|
expect(result).toBeTruthy();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should evaluate to [false] when no parameters provided', () => {
|
||||||
|
const result = not(context);
|
||||||
|
expect(result).toBeFalsy();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should evaluate to [false] when evaluator not available', () => {
|
||||||
|
const parameter: RuleParameter = {
|
||||||
|
type: 'primitive',
|
||||||
|
value: 'missing'
|
||||||
|
};
|
||||||
|
|
||||||
|
const result = not(context, parameter);
|
||||||
|
expect(result).toBeFalsy();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should evaluate a single rule to [false]', () => {
|
||||||
|
const parameter: RuleParameter = {
|
||||||
|
type: 'primitive',
|
||||||
|
value: 'positive'
|
||||||
|
};
|
||||||
|
|
||||||
|
const result = not(context, parameter);
|
||||||
|
expect(result).toBeFalsy();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should evaluate multiple rules to [true]', () => {
|
||||||
|
const parameter1: RuleParameter = {
|
||||||
|
type: 'primitive',
|
||||||
|
value: 'negative'
|
||||||
|
};
|
||||||
|
|
||||||
|
const parameter2: RuleParameter = {
|
||||||
|
type: 'primitive',
|
||||||
|
value: 'negative'
|
||||||
|
};
|
||||||
|
|
||||||
|
const parameter3: RuleParameter = {
|
||||||
|
type: 'primitive',
|
||||||
|
value: 'negative'
|
||||||
|
};
|
||||||
|
|
||||||
|
const result = not(context, parameter1, parameter2, parameter3);
|
||||||
|
expect(result).toBeTruthy();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should evaluate to [false] when one of the rules fails', () => {
|
||||||
|
const parameter1: RuleParameter = {
|
||||||
|
type: 'primitive',
|
||||||
|
value: 'negative'
|
||||||
|
};
|
||||||
|
|
||||||
|
const parameter2: RuleParameter = {
|
||||||
|
type: 'primitive',
|
||||||
|
value: 'negative'
|
||||||
|
};
|
||||||
|
|
||||||
|
const parameter3: RuleParameter = {
|
||||||
|
type: 'primitive',
|
||||||
|
value: 'positive'
|
||||||
|
};
|
||||||
|
|
||||||
|
const result = not(context, parameter1, parameter2, parameter3);
|
||||||
|
expect(result).toBeFalsy();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('every', () => {
|
||||||
|
it('should evaluate a single rule to [true]', () => {
|
||||||
|
const parameter: RuleParameter = {
|
||||||
|
type: 'primitive',
|
||||||
|
value: 'positive'
|
||||||
|
};
|
||||||
|
|
||||||
|
const result = every(context, parameter);
|
||||||
|
expect(result).toBeTruthy();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should evaluate to [false] when no parameters provided', () => {
|
||||||
|
const result = every(context);
|
||||||
|
expect(result).toBeFalsy();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should evaluate to [false] when evaluator not available', () => {
|
||||||
|
const parameter: RuleParameter = {
|
||||||
|
type: 'primitive',
|
||||||
|
value: 'missing'
|
||||||
|
};
|
||||||
|
|
||||||
|
const result = every(context, parameter);
|
||||||
|
expect(result).toBeFalsy();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should evaluate a single rule to [false]', () => {
|
||||||
|
const parameter: RuleParameter = {
|
||||||
|
type: 'primitive',
|
||||||
|
value: 'negative'
|
||||||
|
};
|
||||||
|
|
||||||
|
const result = every(context, parameter);
|
||||||
|
expect(result).toBeFalsy();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should evaluate multiple rules to [true]', () => {
|
||||||
|
const parameter1: RuleParameter = {
|
||||||
|
type: 'primitive',
|
||||||
|
value: 'positive'
|
||||||
|
};
|
||||||
|
|
||||||
|
const parameter2: RuleParameter = {
|
||||||
|
type: 'primitive',
|
||||||
|
value: 'positive'
|
||||||
|
};
|
||||||
|
|
||||||
|
const parameter3: RuleParameter = {
|
||||||
|
type: 'primitive',
|
||||||
|
value: 'positive'
|
||||||
|
};
|
||||||
|
|
||||||
|
const result = every(context, parameter1, parameter2, parameter3);
|
||||||
|
expect(result).toBeTruthy();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should evaluate to [false] when one of the rules fails', () => {
|
||||||
|
const parameter1: RuleParameter = {
|
||||||
|
type: 'primitive',
|
||||||
|
value: 'positive'
|
||||||
|
};
|
||||||
|
|
||||||
|
const parameter2: RuleParameter = {
|
||||||
|
type: 'primitive',
|
||||||
|
value: 'positive'
|
||||||
|
};
|
||||||
|
|
||||||
|
const parameter3: RuleParameter = {
|
||||||
|
type: 'primitive',
|
||||||
|
value: 'negative'
|
||||||
|
};
|
||||||
|
|
||||||
|
const result = every(context, parameter1, parameter2, parameter3);
|
||||||
|
expect(result).toBeFalsy();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('some', () => {
|
||||||
|
it('should evaluate a single rule to [true]', () => {
|
||||||
|
const parameter: RuleParameter = {
|
||||||
|
type: 'primitive',
|
||||||
|
value: 'positive'
|
||||||
|
};
|
||||||
|
|
||||||
|
const result = some(context, parameter);
|
||||||
|
expect(result).toBeTruthy();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should evaluate to [false] when no parameters provided', () => {
|
||||||
|
const result = some(context);
|
||||||
|
expect(result).toBeFalsy();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should evaluate to [false] when evaluator not available', () => {
|
||||||
|
const parameter: RuleParameter = {
|
||||||
|
type: 'primitive',
|
||||||
|
value: 'missing'
|
||||||
|
};
|
||||||
|
|
||||||
|
const result = some(context, parameter);
|
||||||
|
expect(result).toBeFalsy();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should evaluate to [true] if any rule succeeds', () => {
|
||||||
|
const parameter1: RuleParameter = {
|
||||||
|
type: 'primitive',
|
||||||
|
value: 'negative'
|
||||||
|
};
|
||||||
|
|
||||||
|
const parameter2: RuleParameter = {
|
||||||
|
type: 'primitive',
|
||||||
|
value: 'positive'
|
||||||
|
};
|
||||||
|
|
||||||
|
const parameter3: RuleParameter = {
|
||||||
|
type: 'primitive',
|
||||||
|
value: 'negative'
|
||||||
|
};
|
||||||
|
|
||||||
|
const result = some(context, parameter1, parameter2, parameter3);
|
||||||
|
expect(result).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
66
lib/extensions/src/lib/evaluators/core.evaluators.ts
Normal file
66
lib/extensions/src/lib/evaluators/core.evaluators.ts
Normal file
@@ -0,0 +1,66 @@
|
|||||||
|
/*!
|
||||||
|
* @license
|
||||||
|
* Copyright 2016 - 2018 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 { RuleContext, RuleParameter } from '../config/rule.extensions';
|
||||||
|
|
||||||
|
export function not(context: RuleContext, ...args: RuleParameter[]): boolean {
|
||||||
|
if (!args || args.length === 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return args
|
||||||
|
.every(arg => {
|
||||||
|
const evaluator = context.getEvaluator(arg.value);
|
||||||
|
if (!evaluator) {
|
||||||
|
console.warn('evaluator not found: ' + arg.value);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return !evaluator(context, ...(arg.parameters || []));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
export function every(context: RuleContext, ...args: RuleParameter[]): boolean {
|
||||||
|
if (!args || args.length === 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return args
|
||||||
|
.every(arg => {
|
||||||
|
const evaluator = context.getEvaluator(arg.value);
|
||||||
|
if (!evaluator) {
|
||||||
|
console.warn('evaluator not found: ' + arg.value);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return evaluator(context, ...(arg.parameters || []));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
export function some(context: RuleContext, ...args: RuleParameter[]): boolean {
|
||||||
|
if (!args || args.length === 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return args
|
||||||
|
.some(arg => {
|
||||||
|
const evaluator = context.getEvaluator(arg.value);
|
||||||
|
if (!evaluator) {
|
||||||
|
console.warn('evaluator not found: ' + arg.value);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return evaluator(context, ...(arg.parameters || []));
|
||||||
|
});
|
||||||
|
}
|
42
lib/extensions/src/lib/extensions.module.ts
Normal file
42
lib/extensions/src/lib/extensions.module.ts
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
/*!
|
||||||
|
* @license
|
||||||
|
* Copyright 2016 - 2018 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 { NgModule, ModuleWithProviders } from '@angular/core';
|
||||||
|
import { ExtensionLoaderService } from './services/extension-loader.service';
|
||||||
|
import { ExtensionService } from './services/extension.service';
|
||||||
|
import { DynamicExtensionComponent } from './components/dynamic-component/dynamic.component';
|
||||||
|
import { DynamicTabComponent } from './components/dynamic-tab/dynamic-tab.component';
|
||||||
|
|
||||||
|
@NgModule({
|
||||||
|
imports: [],
|
||||||
|
declarations: [DynamicExtensionComponent, DynamicTabComponent],
|
||||||
|
exports: [DynamicExtensionComponent, DynamicTabComponent]
|
||||||
|
})
|
||||||
|
export class ExtensionsModule {
|
||||||
|
static forRoot(): ModuleWithProviders {
|
||||||
|
return {
|
||||||
|
ngModule: ExtensionsModule,
|
||||||
|
providers: [ExtensionLoaderService, ExtensionService]
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
static forChild(): ModuleWithProviders {
|
||||||
|
return {
|
||||||
|
ngModule: ExtensionsModule
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
138
lib/extensions/src/lib/services/extension-loader.service.ts
Normal file
138
lib/extensions/src/lib/services/extension-loader.service.ts
Normal file
@@ -0,0 +1,138 @@
|
|||||||
|
/*!
|
||||||
|
* @license
|
||||||
|
* Copyright 2016 - 2018 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 { HttpClient } from '@angular/common/http';
|
||||||
|
import { Injectable } from '@angular/core';
|
||||||
|
import { ActionRef, ContentActionRef, ContentActionType } from '../config/action.extensions';
|
||||||
|
import { ExtensionElement } from '../config/extension-element';
|
||||||
|
import { filterEnabled, getValue, mergeObjects, sortByOrder } from '../config/extension-utils';
|
||||||
|
import { ExtensionConfig } from '../config/extension.config';
|
||||||
|
import { RouteRef } from '../config/routing.extensions';
|
||||||
|
import { RuleRef } from '../config/rule.extensions';
|
||||||
|
|
||||||
|
@Injectable({
|
||||||
|
providedIn: 'root'
|
||||||
|
})
|
||||||
|
export class ExtensionLoaderService {
|
||||||
|
constructor(private http: HttpClient) {}
|
||||||
|
|
||||||
|
load(configPath: string, pluginsPath: string): Promise<ExtensionConfig> {
|
||||||
|
return new Promise<any>(resolve => {
|
||||||
|
this.loadConfig(configPath, 0).then(result => {
|
||||||
|
let config = result.config;
|
||||||
|
|
||||||
|
const override = sessionStorage.getItem('aca.extension.config');
|
||||||
|
if (override) {
|
||||||
|
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<ExtensionConfig>(url).subscribe(
|
||||||
|
config => {
|
||||||
|
resolve({
|
||||||
|
order,
|
||||||
|
config
|
||||||
|
});
|
||||||
|
},
|
||||||
|
error => {
|
||||||
|
resolve(null);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
getElements<T extends ExtensionElement>(
|
||||||
|
config: ExtensionConfig,
|
||||||
|
key: string,
|
||||||
|
fallback: Array<T> = []
|
||||||
|
): Array<T> {
|
||||||
|
const values = getValue(config, key) || fallback || [];
|
||||||
|
return values.filter(filterEnabled).sort(sortByOrder);
|
||||||
|
}
|
||||||
|
|
||||||
|
getContentActions(
|
||||||
|
config: ExtensionConfig,
|
||||||
|
key: string
|
||||||
|
): Array<ContentActionRef> {
|
||||||
|
return this.getElements(config, key).map(this.setActionDefaults);
|
||||||
|
}
|
||||||
|
|
||||||
|
getRules(config: ExtensionConfig): Array<RuleRef> {
|
||||||
|
if (config && config.rules) {
|
||||||
|
return config.rules;
|
||||||
|
}
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
getRoutes(config: ExtensionConfig): Array<RouteRef> {
|
||||||
|
if (config) {
|
||||||
|
return config.routes || [];
|
||||||
|
}
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
getActions(config: ExtensionConfig): Array<ActionRef> {
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
379
lib/extensions/src/lib/services/extension.service.spec.ts
Normal file
379
lib/extensions/src/lib/services/extension.service.spec.ts
Normal file
@@ -0,0 +1,379 @@
|
|||||||
|
/*!
|
||||||
|
* @license
|
||||||
|
* Copyright 2016 - 2018 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 { ExtensionService } from './extension.service';
|
||||||
|
import { ExtensionLoaderService } from './extension-loader.service';
|
||||||
|
import { ExtensionConfig } from '../config/extension.config';
|
||||||
|
import { RuleRef } from '../config/rule.extensions';
|
||||||
|
import { RouteRef } from '../config/routing.extensions';
|
||||||
|
import { ActionRef } from '../config/action.extensions';
|
||||||
|
|
||||||
|
describe('ExtensionService', () => {
|
||||||
|
const blankConfig: ExtensionConfig = {
|
||||||
|
$name: 'test.config',
|
||||||
|
$version: '1.0.0'
|
||||||
|
};
|
||||||
|
|
||||||
|
let loader: ExtensionLoaderService;
|
||||||
|
let service: ExtensionService;
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
loader = new ExtensionLoaderService(null);
|
||||||
|
service = new ExtensionService(loader);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should load and setup a config', async () => {
|
||||||
|
spyOn(loader, 'load').and.callFake(() => {
|
||||||
|
return Promise.resolve(blankConfig);
|
||||||
|
});
|
||||||
|
|
||||||
|
spyOn(service, 'setup').and.stub();
|
||||||
|
|
||||||
|
await service.load();
|
||||||
|
|
||||||
|
expect(loader.load).toHaveBeenCalled();
|
||||||
|
expect(service.setup).toHaveBeenCalledWith(blankConfig);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should raise warning if setting up with missing config', () => {
|
||||||
|
spyOn(console, 'warn').and.stub();
|
||||||
|
|
||||||
|
service.setup(null);
|
||||||
|
|
||||||
|
expect(console.warn).toHaveBeenCalledWith('Extension configuration not found');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should setup default evaluators', () => {
|
||||||
|
service.setup(blankConfig);
|
||||||
|
|
||||||
|
const evaluators = ['core.every', 'core.some', 'core.not'];
|
||||||
|
evaluators.forEach(key => {
|
||||||
|
expect(service.getEvaluator(key)).toBeDefined(`Evaluator ${key} is missing`);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should set custom evaluators', () => {
|
||||||
|
const evaluator1 = () => true;
|
||||||
|
const evaluator2 = () => false;
|
||||||
|
|
||||||
|
service.setEvaluators({
|
||||||
|
'eval1': evaluator1,
|
||||||
|
'eval2': evaluator2
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(service.getEvaluator('eval1')).toBe(evaluator1);
|
||||||
|
expect(service.getEvaluator('eval2')).toBe(evaluator2);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should override existing evaluators', () => {
|
||||||
|
const evaluator1 = () => true;
|
||||||
|
const evaluator2 = () => false;
|
||||||
|
|
||||||
|
service.setup(blankConfig);
|
||||||
|
expect(service.getEvaluator('core.every')).toBeDefined();
|
||||||
|
expect(service.getEvaluator('core.every')).not.toBe(evaluator1);
|
||||||
|
|
||||||
|
service.setEvaluators({
|
||||||
|
'core.every': evaluator1,
|
||||||
|
'eval2': evaluator2
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(service.getEvaluator('core.every')).toBe(evaluator1);
|
||||||
|
expect(service.getEvaluator('eval2')).toBe(evaluator2);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should negate existing evaluator', () => {
|
||||||
|
const positive = () => true;
|
||||||
|
|
||||||
|
service.setEvaluators({
|
||||||
|
'positive': positive
|
||||||
|
});
|
||||||
|
|
||||||
|
let evaluator = service.getEvaluator('positive');
|
||||||
|
expect(evaluator(null)).toBe(true);
|
||||||
|
|
||||||
|
evaluator = service.getEvaluator('!positive');
|
||||||
|
expect(evaluator(null, 'param1', 'param2')).toBe(false);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should not update evaluators with null value', () => {
|
||||||
|
service.setup(blankConfig);
|
||||||
|
service.setEvaluators(null);
|
||||||
|
|
||||||
|
expect(service.getEvaluator('core.every')).toBeDefined();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should set authentication guards', () => {
|
||||||
|
let registered = service.getAuthGuards(['guard1']);
|
||||||
|
expect(registered.length).toBe(0);
|
||||||
|
|
||||||
|
const guard1: any = {};
|
||||||
|
const guard2: any = {};
|
||||||
|
|
||||||
|
service.setAuthGuards({
|
||||||
|
'auth1': guard1,
|
||||||
|
'auth2': guard2
|
||||||
|
});
|
||||||
|
|
||||||
|
registered = service.getAuthGuards(['auth1', 'auth2']);
|
||||||
|
expect(registered.length).toBe(2);
|
||||||
|
expect(registered[0]).toBe(guard1);
|
||||||
|
expect(registered[1]).toBe(guard2);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should overwrite authentication guards', () => {
|
||||||
|
const guard1: any = {};
|
||||||
|
const guard2: any = {};
|
||||||
|
|
||||||
|
service.setAuthGuards({
|
||||||
|
'auth': guard1
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(service.getAuthGuards(['auth'])).toEqual([guard1]);
|
||||||
|
|
||||||
|
service.setAuthGuards({
|
||||||
|
'auth': guard2
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(service.getAuthGuards(['auth'])).toEqual([guard2]);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should not set authentication guards with null value', () => {
|
||||||
|
const guard1: any = {};
|
||||||
|
|
||||||
|
service.setAuthGuards({
|
||||||
|
'auth': guard1
|
||||||
|
});
|
||||||
|
|
||||||
|
service.setAuthGuards(null);
|
||||||
|
|
||||||
|
expect(service.getAuthGuards(['auth'])).toEqual([guard1]);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should not fetch auth guards for missing ids', () => {
|
||||||
|
const guards = service.getAuthGuards(null);
|
||||||
|
expect(guards).toEqual([]);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should set components', () => {
|
||||||
|
const component: any = {};
|
||||||
|
|
||||||
|
service.setComponents({
|
||||||
|
'component1': component
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(service.getComponentById('component1')).toBe(component);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should overwrite components', () => {
|
||||||
|
const component1: any = {};
|
||||||
|
const component2: any = {};
|
||||||
|
|
||||||
|
service.setComponents({
|
||||||
|
'component': component1
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(service.getComponentById('component')).toBe(component1);
|
||||||
|
|
||||||
|
service.setComponents({
|
||||||
|
'component': component2
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(service.getComponentById('component')).toBe(component2);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should not set components with null value', () => {
|
||||||
|
const component: any = {};
|
||||||
|
|
||||||
|
service.setComponents({
|
||||||
|
'component1': component
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(service.getComponentById('component1')).toBe(component);
|
||||||
|
|
||||||
|
service.setComponents(null);
|
||||||
|
|
||||||
|
expect(service.getComponentById('component1')).toBe(component);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should fetch route by id', () => {
|
||||||
|
const route: RouteRef = {
|
||||||
|
id: 'test.route',
|
||||||
|
component: 'component',
|
||||||
|
path: '/ext/route1'
|
||||||
|
};
|
||||||
|
|
||||||
|
spyOn(loader, 'getRoutes').and.returnValue([route]);
|
||||||
|
service.setup(blankConfig);
|
||||||
|
|
||||||
|
expect(service.getRouteById('test.route')).toBe(route);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should fetch action by id', () => {
|
||||||
|
const action: ActionRef = {
|
||||||
|
id: 'test.action',
|
||||||
|
type: 'action'
|
||||||
|
};
|
||||||
|
|
||||||
|
spyOn(loader, 'getActions').and.returnValue([action]);
|
||||||
|
service.setup(blankConfig);
|
||||||
|
|
||||||
|
expect(service.getActionById('test.action')).toBe(action);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should fetch rule by id', () => {
|
||||||
|
const rule: RuleRef = {
|
||||||
|
id: 'test.rule',
|
||||||
|
type: 'core.every'
|
||||||
|
};
|
||||||
|
|
||||||
|
spyOn(loader, 'getRules').and.returnValue([rule]);
|
||||||
|
service.setup(blankConfig);
|
||||||
|
|
||||||
|
expect(service.getRuleById('test.rule')).toBe(rule);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should evaluate condition', () => {
|
||||||
|
const condition = () => true;
|
||||||
|
|
||||||
|
service.setEvaluators({
|
||||||
|
'test.condition': condition
|
||||||
|
});
|
||||||
|
|
||||||
|
const context: any = {
|
||||||
|
getEvaluator(key: string) {
|
||||||
|
return service.getEvaluator(key);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const result = service.evaluateRule('test.condition', context);
|
||||||
|
expect(result).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should evaluate missing condition as [false]', () => {
|
||||||
|
const context: any = {
|
||||||
|
getEvaluator(key: string) {
|
||||||
|
return service.getEvaluator(key);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const result = service.evaluateRule('missing.condition', context);
|
||||||
|
expect(result).toBe(false);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should evaluate rule by reference', () => {
|
||||||
|
const ruleRef: RuleRef = {
|
||||||
|
id: 'test.rule',
|
||||||
|
type: 'core.every',
|
||||||
|
parameters: [
|
||||||
|
{
|
||||||
|
type: 'rule',
|
||||||
|
value: 'test.condition'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
};
|
||||||
|
|
||||||
|
spyOn(loader, 'getRules').and.returnValue([ruleRef]);
|
||||||
|
service.setup(blankConfig);
|
||||||
|
|
||||||
|
const condition = () => true;
|
||||||
|
|
||||||
|
service.setEvaluators({
|
||||||
|
'test.condition': condition
|
||||||
|
});
|
||||||
|
|
||||||
|
const context: any = {
|
||||||
|
getEvaluator(key: string) {
|
||||||
|
return service.getEvaluator(key);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const result = service.evaluateRule('test.rule', context);
|
||||||
|
expect(result).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should evaluate rule ref with missing condition as [false]', () => {
|
||||||
|
const ruleRef: RuleRef = {
|
||||||
|
id: 'test.rule',
|
||||||
|
type: 'missing.evaluator'
|
||||||
|
};
|
||||||
|
|
||||||
|
spyOn(loader, 'getRules').and.returnValue([ruleRef]);
|
||||||
|
service.setup(blankConfig);
|
||||||
|
|
||||||
|
const context: any = {
|
||||||
|
getEvaluator(key: string) {
|
||||||
|
return service.getEvaluator(key);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const result = service.evaluateRule('test.rule', context);
|
||||||
|
expect(result).toBe(false);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should evaluate rule ref with missing evaluator as [false]', () => {
|
||||||
|
const ruleRef: RuleRef = {
|
||||||
|
id: 'test.rule',
|
||||||
|
type: 'core.every',
|
||||||
|
parameters: [
|
||||||
|
{
|
||||||
|
type: 'rule',
|
||||||
|
value: 'missing.condition'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
};
|
||||||
|
|
||||||
|
spyOn(loader, 'getRules').and.returnValue([ruleRef]);
|
||||||
|
service.setup(blankConfig);
|
||||||
|
|
||||||
|
const context: any = {
|
||||||
|
getEvaluator(key: string) {
|
||||||
|
return service.getEvaluator(key);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const result = service.evaluateRule('test.rule', context);
|
||||||
|
expect(result).toBe(false);
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('expressions', () => {
|
||||||
|
it('should eval static value', () => {
|
||||||
|
const value = service.runExpression('hello world');
|
||||||
|
expect(value).toBe('hello world');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should eval string as an expression', () => {
|
||||||
|
const value = service.runExpression('$( "hello world" )');
|
||||||
|
expect(value).toBe('hello world');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should eval expression with no context', () => {
|
||||||
|
const value = service.runExpression('$( 1 + 1 )');
|
||||||
|
expect(value).toBe(2);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should eval expression with context', () => {
|
||||||
|
const context = {
|
||||||
|
a: 'hey',
|
||||||
|
b: 'there'
|
||||||
|
};
|
||||||
|
const expression = '$( context.a + " " + context.b + "!" )';
|
||||||
|
const value = service.runExpression(expression, context);
|
||||||
|
expect(value).toBe('hey there!');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
148
lib/extensions/src/lib/services/extension.service.ts
Normal file
148
lib/extensions/src/lib/services/extension.service.ts
Normal file
@@ -0,0 +1,148 @@
|
|||||||
|
/*!
|
||||||
|
* @license
|
||||||
|
* Copyright 2016 - 2018 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 { Injectable, Type } from '@angular/core';
|
||||||
|
import { RuleEvaluator, RuleRef, RuleContext, RuleParameter } from '../config/rule.extensions';
|
||||||
|
import { ExtensionConfig } from '../config/extension.config';
|
||||||
|
import { ExtensionLoaderService } from './extension-loader.service';
|
||||||
|
import { RouteRef } from '../config/routing.extensions';
|
||||||
|
import { ActionRef } from '../config/action.extensions';
|
||||||
|
import * as core from '../evaluators/core.evaluators';
|
||||||
|
|
||||||
|
@Injectable()
|
||||||
|
export class ExtensionService {
|
||||||
|
configPath = 'assets/app.extensions.json';
|
||||||
|
pluginsPath = 'assets/plugins';
|
||||||
|
|
||||||
|
rules: Array<RuleRef> = [];
|
||||||
|
routes: Array<RouteRef> = [];
|
||||||
|
actions: Array<ActionRef> = [];
|
||||||
|
|
||||||
|
authGuards: { [key: string]: Type<{}> } = {};
|
||||||
|
components: { [key: string]: Type<{}> } = {};
|
||||||
|
evaluators: { [key: string]: RuleEvaluator } = {};
|
||||||
|
|
||||||
|
constructor(private loader: ExtensionLoaderService) {}
|
||||||
|
|
||||||
|
async load(): Promise<ExtensionConfig> {
|
||||||
|
const config = await this.loader.load(
|
||||||
|
this.configPath,
|
||||||
|
this.pluginsPath
|
||||||
|
);
|
||||||
|
this.setup(config);
|
||||||
|
return config;
|
||||||
|
}
|
||||||
|
|
||||||
|
setup(config: ExtensionConfig) {
|
||||||
|
if (!config) {
|
||||||
|
console.warn('Extension configuration not found');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.setEvaluators({
|
||||||
|
'core.every': core.every,
|
||||||
|
'core.some': core.some,
|
||||||
|
'core.not': core.not
|
||||||
|
});
|
||||||
|
|
||||||
|
this.rules = this.loader.getRules(config);
|
||||||
|
this.actions = this.loader.getActions(config);
|
||||||
|
this.routes = this.loader.getRoutes(config);
|
||||||
|
}
|
||||||
|
|
||||||
|
setEvaluators(values: { [key: string]: RuleEvaluator }) {
|
||||||
|
if (values) {
|
||||||
|
this.evaluators = Object.assign({}, this.evaluators, values);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
setAuthGuards(values: { [key: string]: Type<{}> }) {
|
||||||
|
if (values) {
|
||||||
|
this.authGuards = Object.assign({}, this.authGuards, values);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
setComponents(values: { [key: string]: Type<{}> }) {
|
||||||
|
if (values) {
|
||||||
|
this.components = Object.assign({}, this.components, values);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
getRouteById(id: string): RouteRef {
|
||||||
|
return this.routes.find(route => route.id === id);
|
||||||
|
}
|
||||||
|
|
||||||
|
getAuthGuards(ids: string[]): Array<Type<{}>> {
|
||||||
|
return (ids || [])
|
||||||
|
.map(id => this.authGuards[id])
|
||||||
|
.filter(guard => guard);
|
||||||
|
}
|
||||||
|
|
||||||
|
getActionById(id: string): ActionRef {
|
||||||
|
return this.actions.find(action => action.id === id);
|
||||||
|
}
|
||||||
|
|
||||||
|
getEvaluator(key: string): RuleEvaluator {
|
||||||
|
if (key && key.startsWith('!')) {
|
||||||
|
const fn = this.evaluators[key.substring(1)];
|
||||||
|
return (context: RuleContext, ...args: RuleParameter[]): boolean => {
|
||||||
|
return !fn(context, ...args);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
return this.evaluators[key];
|
||||||
|
}
|
||||||
|
|
||||||
|
evaluateRule(ruleId: string, context: RuleContext): boolean {
|
||||||
|
const ruleRef = this.getRuleById(ruleId);
|
||||||
|
|
||||||
|
if (ruleRef) {
|
||||||
|
const evaluator = this.getEvaluator(ruleRef.type);
|
||||||
|
if (evaluator) {
|
||||||
|
return evaluator(context, ...ruleRef.parameters);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
const evaluator = this.getEvaluator(ruleId);
|
||||||
|
if (evaluator) {
|
||||||
|
return evaluator(context);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
getComponentById(id: string): Type<{}> {
|
||||||
|
return this.components[id];
|
||||||
|
}
|
||||||
|
|
||||||
|
getRuleById(id: string): RuleRef {
|
||||||
|
return this.rules.find(ref => ref.id === id);
|
||||||
|
}
|
||||||
|
|
||||||
|
runExpression(value: string, context?: any) {
|
||||||
|
const pattern = new RegExp(/\$\((.*\)?)\)/g);
|
||||||
|
const matches = pattern.exec(value);
|
||||||
|
|
||||||
|
if (matches && matches.length > 1) {
|
||||||
|
const expression = matches[1];
|
||||||
|
const fn = new Function('context', `return ${expression}`);
|
||||||
|
const result = fn(context);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
}
|
23
lib/extensions/src/lib/store/states/navigation.state.ts
Normal file
23
lib/extensions/src/lib/store/states/navigation.state.ts
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
/*!
|
||||||
|
* @license
|
||||||
|
* Copyright 2016 - 2018 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 { Node } from 'alfresco-js-api';
|
||||||
|
|
||||||
|
export interface NavigationState {
|
||||||
|
currentFolder?: Node;
|
||||||
|
url?: string;
|
||||||
|
}
|
25
lib/extensions/src/lib/store/states/profile.state.ts
Normal file
25
lib/extensions/src/lib/store/states/profile.state.ts
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
/*!
|
||||||
|
* @license
|
||||||
|
* Copyright 2016 - 2018 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
export interface ProfileState {
|
||||||
|
id: string;
|
||||||
|
isAdmin: boolean;
|
||||||
|
firstName: string;
|
||||||
|
lastName: string;
|
||||||
|
userName?: string;
|
||||||
|
initials?: string;
|
||||||
|
}
|
30
lib/extensions/src/lib/store/states/selection.state.ts
Normal file
30
lib/extensions/src/lib/store/states/selection.state.ts
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
/*!
|
||||||
|
* @license
|
||||||
|
* Copyright 2016 - 2018 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 { MinimalNodeEntity, SiteEntry } from 'alfresco-js-api';
|
||||||
|
|
||||||
|
export interface SelectionState {
|
||||||
|
count: number;
|
||||||
|
nodes: MinimalNodeEntity[];
|
||||||
|
libraries: SiteEntry[];
|
||||||
|
isEmpty: boolean;
|
||||||
|
first?: MinimalNodeEntity;
|
||||||
|
last?: MinimalNodeEntity;
|
||||||
|
folder?: MinimalNodeEntity;
|
||||||
|
file?: MinimalNodeEntity;
|
||||||
|
library?: SiteEntry;
|
||||||
|
}
|
36
lib/extensions/src/public_api.ts
Normal file
36
lib/extensions/src/public_api.ts
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
/*!
|
||||||
|
* @license
|
||||||
|
* Copyright 2016 - 2018 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
export * from './lib/config/action.extensions';
|
||||||
|
export * from './lib/config/extension-element';
|
||||||
|
export * from './lib/config/extension-utils';
|
||||||
|
export * from './lib/config/extension.config';
|
||||||
|
export * from './lib/config/navbar.extensions';
|
||||||
|
export * from './lib/config/permission.extensions';
|
||||||
|
export * from './lib/config/routing.extensions';
|
||||||
|
export * from './lib/config/rule.extensions';
|
||||||
|
export * from './lib/config/sidebar.extensions';
|
||||||
|
export * from './lib/config/viewer.extensions';
|
||||||
|
|
||||||
|
export * from './lib/services/extension-loader.service';
|
||||||
|
export * from './lib/services/extension.service';
|
||||||
|
|
||||||
|
export * from './lib/store/states/navigation.state';
|
||||||
|
export * from './lib/store/states/profile.state';
|
||||||
|
export * from './lib/store/states/selection.state';
|
||||||
|
|
||||||
|
export * from './lib/extensions.module';
|
22
lib/extensions/src/test.ts
Normal file
22
lib/extensions/src/test.ts
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
// This file is required by karma.conf.js and loads recursively all the .spec and framework files
|
||||||
|
|
||||||
|
import 'core-js/es7/reflect';
|
||||||
|
import 'zone.js/dist/zone';
|
||||||
|
import 'zone.js/dist/zone-testing';
|
||||||
|
import { getTestBed } from '@angular/core/testing';
|
||||||
|
import {
|
||||||
|
BrowserDynamicTestingModule,
|
||||||
|
platformBrowserDynamicTesting
|
||||||
|
} from '@angular/platform-browser-dynamic/testing';
|
||||||
|
|
||||||
|
declare const require: any;
|
||||||
|
|
||||||
|
// First, initialize the Angular testing environment.
|
||||||
|
getTestBed().initTestEnvironment(
|
||||||
|
BrowserDynamicTestingModule,
|
||||||
|
platformBrowserDynamicTesting()
|
||||||
|
);
|
||||||
|
// Then we find all the tests.
|
||||||
|
const context = require.context('./', true, /\.spec\.ts$/);
|
||||||
|
// And load the modules.
|
||||||
|
context.keys().map(context);
|
34
lib/extensions/tsconfig.lib.json
Normal file
34
lib/extensions/tsconfig.lib.json
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
{
|
||||||
|
"extends": "../../tsconfig.json",
|
||||||
|
"compilerOptions": {
|
||||||
|
"outDir": "../../out-tsc/lib",
|
||||||
|
"target": "es2015",
|
||||||
|
"module": "es2015",
|
||||||
|
"moduleResolution": "node",
|
||||||
|
"declaration": true,
|
||||||
|
"sourceMap": true,
|
||||||
|
"inlineSources": true,
|
||||||
|
"emitDecoratorMetadata": true,
|
||||||
|
"experimentalDecorators": true,
|
||||||
|
"importHelpers": true,
|
||||||
|
"types": [],
|
||||||
|
"lib": [
|
||||||
|
"dom",
|
||||||
|
"es2015"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"angularCompilerOptions": {
|
||||||
|
"annotateForClosureCompiler": true,
|
||||||
|
"skipTemplateCodegen": true,
|
||||||
|
"strictMetadataEmit": true,
|
||||||
|
"fullTemplateTypeCheck": true,
|
||||||
|
"strictInjectionParameters": true,
|
||||||
|
"flatModuleId": "AUTOGENERATED",
|
||||||
|
"flatModuleOutFile": "AUTOGENERATED",
|
||||||
|
"enableResourceInlining": true
|
||||||
|
},
|
||||||
|
"exclude": [
|
||||||
|
"src/test.ts",
|
||||||
|
"**/*.spec.ts"
|
||||||
|
]
|
||||||
|
}
|
17
lib/extensions/tsconfig.spec.json
Normal file
17
lib/extensions/tsconfig.spec.json
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
{
|
||||||
|
"extends": "../../tsconfig.json",
|
||||||
|
"compilerOptions": {
|
||||||
|
"outDir": "../../out-tsc/spec",
|
||||||
|
"types": [
|
||||||
|
"jasmine",
|
||||||
|
"node"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"files": [
|
||||||
|
"src/test.ts"
|
||||||
|
],
|
||||||
|
"include": [
|
||||||
|
"**/*.spec.ts",
|
||||||
|
"**/*.d.ts"
|
||||||
|
]
|
||||||
|
}
|
17
lib/extensions/tslint.json
Normal file
17
lib/extensions/tslint.json
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
{
|
||||||
|
"extends": "../../tslint.json",
|
||||||
|
"rules": {
|
||||||
|
"directive-selector": [
|
||||||
|
true,
|
||||||
|
"attribute",
|
||||||
|
"adf",
|
||||||
|
"camelCase"
|
||||||
|
],
|
||||||
|
"component-selector": [
|
||||||
|
true,
|
||||||
|
"element",
|
||||||
|
"adf",
|
||||||
|
"kebab-case"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
@@ -9,22 +9,32 @@ rm -rf node_modules/@alfresco
|
|||||||
|
|
||||||
echo "====== Build lib ====="
|
echo "====== Build lib ====="
|
||||||
|
|
||||||
|
echo "------ Build core -----"
|
||||||
npm run ng-packagr -- -p ./lib/core/ && \
|
npm run ng-packagr -- -p ./lib/core/ && \
|
||||||
mkdir -p ./node_modules/@alfresco/adf-core/ && \
|
mkdir -p ./node_modules/@alfresco/adf-core/ && \
|
||||||
cp -R ./lib/dist/core/* ./node_modules/@alfresco/adf-core/
|
cp -R ./lib/dist/core/* ./node_modules/@alfresco/adf-core/
|
||||||
|
|
||||||
|
echo "------ Build content-services -----"
|
||||||
npm run ng-packagr -- -p ./lib/content-services/ && \
|
npm run ng-packagr -- -p ./lib/content-services/ && \
|
||||||
mkdir -p ./node_modules/@alfresco/adf-content-services/ && \
|
mkdir -p ./node_modules/@alfresco/adf-content-services/ && \
|
||||||
cp -R ./lib/dist/content-services/* ./node_modules/@alfresco/adf-content-services/
|
cp -R ./lib/dist/content-services/* ./node_modules/@alfresco/adf-content-services/
|
||||||
|
|
||||||
|
echo "------ Build process-services -----"
|
||||||
npm run ng-packagr -- -p ./lib/process-services/ && \
|
npm run ng-packagr -- -p ./lib/process-services/ && \
|
||||||
mkdir -p ./node_modules/@alfresco/adf-process-services/ && \
|
mkdir -p ./node_modules/@alfresco/adf-process-services/ && \
|
||||||
cp -R ./lib/dist/process-services/* ./node_modules/@alfresco/adf-process-services/
|
cp -R ./lib/dist/process-services/* ./node_modules/@alfresco/adf-process-services/
|
||||||
|
|
||||||
|
echo "------ Build insights -----"
|
||||||
npm run ng-packagr -- -p ./lib/insights/ && \
|
npm run ng-packagr -- -p ./lib/insights/ && \
|
||||||
mkdir -p ./node_modules/@alfresco/adf-insights/ && \
|
mkdir -p ./node_modules/@alfresco/adf-insights/ && \
|
||||||
cp -R ./lib/dist/insights/* ./node_modules/@alfresco/adf-insights/
|
cp -R ./lib/dist/insights/* ./node_modules/@alfresco/adf-insights/
|
||||||
|
|
||||||
|
echo "------ Build extensions -----"
|
||||||
|
npm run ng-packagr -- -p ./lib/extensions/ && \
|
||||||
|
mkdir -p ./node_modules/@alfresco/adf-extensions/ && \
|
||||||
|
cp -R ./lib/dist/extensions/* ./node_modules/@alfresco/adf-extensions/
|
||||||
|
|
||||||
|
|
||||||
echo "====== Build style ====="
|
echo "====== Build style ====="
|
||||||
|
|
||||||
node ./lib/config/bundle-scss.js
|
node ./lib/config/bundle-scss.js
|
||||||
@@ -45,6 +55,7 @@ cp -R ./lib/process-services/i18n/* ./lib/dist/process-services/bundles/assets/a
|
|||||||
mkdir -p ./lib/dist/insights/bundles/assets/adf-insights/i18n
|
mkdir -p ./lib/dist/insights/bundles/assets/adf-insights/i18n
|
||||||
cp -R ./lib/insights/i18n/* ./lib/dist/insights/bundles/assets/adf-insights/i18n
|
cp -R ./lib/insights/i18n/* ./lib/dist/insights/bundles/assets/adf-insights/i18n
|
||||||
|
|
||||||
|
|
||||||
echo "====== Copy assets ====="
|
echo "====== Copy assets ====="
|
||||||
|
|
||||||
cp -R ./lib/core/assets/* ./lib/dist/core/bundles/assets
|
cp -R ./lib/core/assets/* ./lib/dist/core/bundles/assets
|
||||||
|
@@ -18,7 +18,8 @@ eval EXECLINT=true
|
|||||||
eval projects=( "core"
|
eval projects=( "core"
|
||||||
"content-services"
|
"content-services"
|
||||||
"insights"
|
"insights"
|
||||||
"process-services" )
|
"process-services"
|
||||||
|
"extensions" )
|
||||||
|
|
||||||
show_help() {
|
show_help() {
|
||||||
echo "Usage: npm-build-all.sh"
|
echo "Usage: npm-build-all.sh"
|
||||||
|
@@ -7,6 +7,7 @@ eval VERSION=""
|
|||||||
eval projects=( "adf-core"
|
eval projects=( "adf-core"
|
||||||
"adf-insights"
|
"adf-insights"
|
||||||
"adf-content-services"
|
"adf-content-services"
|
||||||
|
"extensions"
|
||||||
"adf-process-services" )
|
"adf-process-services" )
|
||||||
|
|
||||||
show_help() {
|
show_help() {
|
||||||
|
@@ -5,7 +5,8 @@ DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
|
|||||||
eval projects=( "@alfresco/adf-core"
|
eval projects=( "@alfresco/adf-core"
|
||||||
"@alfresco/adf-content-services"
|
"@alfresco/adf-content-services"
|
||||||
"@alfresco/adf-insights"
|
"@alfresco/adf-insights"
|
||||||
"@alfresco/adf-process-services" )
|
"@alfresco/adf-process-services"
|
||||||
|
"@alfresco/adf-extensions" )
|
||||||
|
|
||||||
show_help() {
|
show_help() {
|
||||||
echo "Usage: npm-clean.sh"
|
echo "Usage: npm-clean.sh"
|
||||||
|
@@ -20,7 +20,8 @@ eval projects=(
|
|||||||
"core"
|
"core"
|
||||||
"insights"
|
"insights"
|
||||||
"content-services"
|
"content-services"
|
||||||
"process-services" )
|
"process-services"
|
||||||
|
"extensions" )
|
||||||
|
|
||||||
cd "$DIR/../"
|
cd "$DIR/../"
|
||||||
|
|
||||||
|
@@ -19,7 +19,8 @@ eval GIT_ISH=""
|
|||||||
|
|
||||||
eval projects=( "@alfresco/core"
|
eval projects=( "@alfresco/core"
|
||||||
"@alfresco/content-service"
|
"@alfresco/content-service"
|
||||||
"@alfresco/process-service" )
|
"@alfresco/process-service"
|
||||||
|
"@alfresco/extensions" )
|
||||||
|
|
||||||
show_help() {
|
show_help() {
|
||||||
echo "Usage: start.sh"
|
echo "Usage: start.sh"
|
||||||
|
@@ -43,11 +43,13 @@ mkdir -p $DIR/../node_modules/@alfresco/adf-core
|
|||||||
mkdir -p $DIR/../node_modules/@alfresco/adf-content-services
|
mkdir -p $DIR/../node_modules/@alfresco/adf-content-services
|
||||||
mkdir -p $DIR/../node_modules/@alfresco/adf-process-services
|
mkdir -p $DIR/../node_modules/@alfresco/adf-process-services
|
||||||
mkdir -p $DIR/../node_modules/@alfresco/adf-insights
|
mkdir -p $DIR/../node_modules/@alfresco/adf-insights
|
||||||
|
mkdir -p $DIR/../node_modules/@alfresco/adf-extensions
|
||||||
|
|
||||||
cp -R $DIR/../lib/dist/core/* $DIR/../node_modules/@alfresco/adf-core
|
cp -R $DIR/../lib/dist/core/* $DIR/../node_modules/@alfresco/adf-core
|
||||||
cp -R $DIR/../lib/dist/content-services/* $DIR/../node_modules/@alfresco/adf-content-services
|
cp -R $DIR/../lib/dist/content-services/* $DIR/../node_modules/@alfresco/adf-content-services
|
||||||
cp -R $DIR/../lib/dist/process-services/* $DIR/../node_modules/@alfresco/adf-process-services
|
cp -R $DIR/../lib/dist/process-services/* $DIR/../node_modules/@alfresco/adf-process-services
|
||||||
cp -R $DIR/../lib/dist/insights/* $DIR/../node_modules/@alfresco/adf-insights
|
cp -R $DIR/../lib/dist/insights/* $DIR/../node_modules/@alfresco/adf-insights
|
||||||
|
cp -R $DIR/../lib/dist/extensions/* $DIR/../node_modules/@alfresco/adf-extensions
|
||||||
|
|
||||||
echo "====== Build dist demo shell ===== "
|
echo "====== Build dist demo shell ===== "
|
||||||
|
|
||||||
|
@@ -10,7 +10,8 @@ eval TOTAL_BUILD=true;
|
|||||||
eval projects=( "core"
|
eval projects=( "core"
|
||||||
"content-services"
|
"content-services"
|
||||||
"process-services"
|
"process-services"
|
||||||
"insights" )
|
"insights"
|
||||||
|
"extensions" )
|
||||||
|
|
||||||
cd `dirname $0`
|
cd `dirname $0`
|
||||||
|
|
||||||
|
@@ -16,7 +16,7 @@
|
|||||||
"node_modules/@types"
|
"node_modules/@types"
|
||||||
],
|
],
|
||||||
"lib": [
|
"lib": [
|
||||||
"es2016",
|
"es2017",
|
||||||
"dom"
|
"dom"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
Reference in New Issue
Block a user