mirror of
https://github.com/Alfresco/alfresco-content-app.git
synced 2025-05-12 17:04:46 +00:00
[ACA-1597] allow extensions overwrite existing settings (#523)
* merge objects within the arrays * metadata properties * code cleanup
This commit is contained in:
parent
8c9ffc1160
commit
3ab9cee163
@ -214,20 +214,20 @@
|
|||||||
},
|
},
|
||||||
|
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"required": ["name", "version"],
|
"required": ["$name", "$version"],
|
||||||
"properties": {
|
"properties": {
|
||||||
"name": {
|
"$name": {
|
||||||
"description": "Extension name",
|
"description": "Extension name",
|
||||||
"type": "string"
|
"type": "string"
|
||||||
},
|
},
|
||||||
"version": {
|
"$version": {
|
||||||
"description": "Extension version",
|
"description": "Extension version",
|
||||||
"type": "string"
|
"type": "string"
|
||||||
},
|
},
|
||||||
"description": {
|
"$description": {
|
||||||
"description": "Brief description on what the extension does"
|
"description": "Brief description on what the extension does"
|
||||||
},
|
},
|
||||||
"references": {
|
"$references": {
|
||||||
"description": "References to external files",
|
"description": "References to external files",
|
||||||
"type": "array",
|
"type": "array",
|
||||||
"items": {
|
"items": {
|
||||||
|
@ -29,8 +29,10 @@ import { RuleRef } from './rule.extensions';
|
|||||||
import { ActionRef, ContentActionRef } from './action.extensions';
|
import { ActionRef, ContentActionRef } from './action.extensions';
|
||||||
|
|
||||||
export interface ExtensionConfig {
|
export interface ExtensionConfig {
|
||||||
version: string;
|
$name: string;
|
||||||
references?: Array<string>;
|
$version: string;
|
||||||
|
$description?: string;
|
||||||
|
$references?: Array<string>;
|
||||||
rules?: Array<RuleRef>;
|
rules?: Array<RuleRef>;
|
||||||
routes?: Array<RouteRef>;
|
routes?: Array<RouteRef>;
|
||||||
actions?: Array<ActionRef>;
|
actions?: Array<ActionRef>;
|
||||||
|
@ -43,10 +43,59 @@ describe('ExtensionService', () => {
|
|||||||
extensions = TestBed.get(ExtensionService);
|
extensions = TestBed.get(ExtensionService);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('configs', () => {
|
||||||
|
it('should merge two arrays based on [id] keys', () => {
|
||||||
|
const left = [
|
||||||
|
{
|
||||||
|
name: 'item0'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: '#1',
|
||||||
|
name: 'item1'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: '#2',
|
||||||
|
name: 'item2'
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
|
const right = [
|
||||||
|
{
|
||||||
|
name: 'extra-1'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: '#2',
|
||||||
|
name: 'custom2',
|
||||||
|
tag: 'extra tag'
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
|
const result = extensions.mergeArrays(left, right);
|
||||||
|
expect(result).toEqual([
|
||||||
|
{
|
||||||
|
id: '#1',
|
||||||
|
name: 'item1'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: '#2',
|
||||||
|
name: 'custom2',
|
||||||
|
tag: 'extra tag'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'item0'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'extra-1'
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
describe('actions', () => {
|
describe('actions', () => {
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
extensions.setup({
|
extensions.setup({
|
||||||
version: '1.0.0',
|
$name: 'test',
|
||||||
|
$version: '1.0.0',
|
||||||
actions: [
|
actions: [
|
||||||
{
|
{
|
||||||
id: 'aca:actions/create-folder',
|
id: 'aca:actions/create-folder',
|
||||||
@ -179,7 +228,8 @@ describe('ExtensionService', () => {
|
|||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
extensions.setup({
|
extensions.setup({
|
||||||
version: '1.0.0',
|
$name: 'test',
|
||||||
|
$version: '1.0.0',
|
||||||
routes: [
|
routes: [
|
||||||
{
|
{
|
||||||
id: 'aca:routes/about',
|
id: 'aca:routes/about',
|
||||||
@ -237,7 +287,8 @@ describe('ExtensionService', () => {
|
|||||||
describe('content actions', () => {
|
describe('content actions', () => {
|
||||||
it('should load content actions from the config', () => {
|
it('should load content actions from the config', () => {
|
||||||
extensions.setup({
|
extensions.setup({
|
||||||
version: '1.0.0',
|
$name: 'test',
|
||||||
|
$version: '1.0.0',
|
||||||
features: {
|
features: {
|
||||||
content: {
|
content: {
|
||||||
actions: [
|
actions: [
|
||||||
@ -263,7 +314,8 @@ describe('ExtensionService', () => {
|
|||||||
|
|
||||||
it('should sort content actions by order', () => {
|
it('should sort content actions by order', () => {
|
||||||
extensions.setup({
|
extensions.setup({
|
||||||
version: '1.0.0',
|
$name: 'test',
|
||||||
|
$version: '1.0.0',
|
||||||
features: {
|
features: {
|
||||||
content: {
|
content: {
|
||||||
actions: [
|
actions: [
|
||||||
@ -297,7 +349,8 @@ describe('ExtensionService', () => {
|
|||||||
describe('open with', () => {
|
describe('open with', () => {
|
||||||
it('should load [open with] actions for the viewer', () => {
|
it('should load [open with] actions for the viewer', () => {
|
||||||
extensions.setup({
|
extensions.setup({
|
||||||
version: '1.0.0',
|
$name: 'test',
|
||||||
|
$version: '1.0.0',
|
||||||
features: {
|
features: {
|
||||||
viewer: {
|
viewer: {
|
||||||
openWith: [
|
openWith: [
|
||||||
@ -322,7 +375,8 @@ describe('ExtensionService', () => {
|
|||||||
|
|
||||||
it('should load only enabled [open with] actions for the viewer', () => {
|
it('should load only enabled [open with] actions for the viewer', () => {
|
||||||
extensions.setup({
|
extensions.setup({
|
||||||
version: '1.0.0',
|
$name: 'test',
|
||||||
|
$version: '1.0.0',
|
||||||
features: {
|
features: {
|
||||||
viewer: {
|
viewer: {
|
||||||
openWith: [
|
openWith: [
|
||||||
@ -358,7 +412,8 @@ describe('ExtensionService', () => {
|
|||||||
|
|
||||||
it('should sort [open with] actions by order', () => {
|
it('should sort [open with] actions by order', () => {
|
||||||
extensions.setup({
|
extensions.setup({
|
||||||
version: '1.0.0',
|
$name: 'test',
|
||||||
|
$version: '1.0.0',
|
||||||
features: {
|
features: {
|
||||||
viewer: {
|
viewer: {
|
||||||
openWith: [
|
openWith: [
|
||||||
@ -396,7 +451,8 @@ describe('ExtensionService', () => {
|
|||||||
describe('create', () => {
|
describe('create', () => {
|
||||||
it('should load [create] actions from config', () => {
|
it('should load [create] actions from config', () => {
|
||||||
extensions.setup({
|
extensions.setup({
|
||||||
version: '1.0.0',
|
$name: 'test',
|
||||||
|
$version: '1.0.0',
|
||||||
features: {
|
features: {
|
||||||
create: [
|
create: [
|
||||||
{
|
{
|
||||||
@ -415,7 +471,8 @@ describe('ExtensionService', () => {
|
|||||||
|
|
||||||
it('should sort [create] actions by order', () => {
|
it('should sort [create] actions by order', () => {
|
||||||
extensions.setup({
|
extensions.setup({
|
||||||
version: '1.0.0',
|
$name: 'test',
|
||||||
|
$version: '1.0.0',
|
||||||
features: {
|
features: {
|
||||||
create: [
|
create: [
|
||||||
{
|
{
|
||||||
|
@ -74,8 +74,8 @@ export class ExtensionService implements RuleContext {
|
|||||||
this.loadConfig(this.configPath, 0).then(result => {
|
this.loadConfig(this.configPath, 0).then(result => {
|
||||||
let config = result.config;
|
let config = result.config;
|
||||||
|
|
||||||
if (config.references && config.references.length > 0) {
|
if (config.$references && config.$references.length > 0) {
|
||||||
const plugins = config.references.map(
|
const plugins = config.$references.map(
|
||||||
(name, idx) => this.loadConfig(`${this.pluginsPath}/${name}`, idx)
|
(name, idx) => this.loadConfig(`${this.pluginsPath}/${name}`, idx)
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -86,7 +86,7 @@ export class ExtensionService implements RuleContext {
|
|||||||
.map(entry => entry.config);
|
.map(entry => entry.config);
|
||||||
|
|
||||||
if (configs.length > 0) {
|
if (configs.length > 0) {
|
||||||
config = this.mergeConfigs(config, ...configs);
|
config = this.mergeObjects(config, ...configs);
|
||||||
}
|
}
|
||||||
|
|
||||||
this.setup(config);
|
this.setup(config);
|
||||||
@ -411,23 +411,50 @@ export class ExtensionService implements RuleContext {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// todo: requires overwrite support for array entries
|
mergeObjects(...objects): any {
|
||||||
// todo: overwrite only particular areas, don't touch version or other top-level props
|
|
||||||
protected mergeConfigs(...objects): any {
|
|
||||||
const result = {};
|
const result = {};
|
||||||
|
|
||||||
objects.forEach(source => {
|
objects.forEach(source => {
|
||||||
Object.keys(source).forEach(prop => {
|
Object.keys(source).forEach(prop => {
|
||||||
if (prop in result && Array.isArray(result[prop])) {
|
if (!prop.startsWith('$')) {
|
||||||
result[prop] = result[prop].concat(source[prop]);
|
if (prop in result && Array.isArray(result[prop])) {
|
||||||
} else if (prop in result && typeof result[prop] === 'object') {
|
// result[prop] = result[prop].concat(source[prop]);
|
||||||
result[prop] = this.mergeConfigs(result[prop], source[prop]);
|
result[prop] = this.mergeArrays(result[prop], source[prop]);
|
||||||
} else {
|
} else if (prop in result && typeof result[prop] === 'object') {
|
||||||
result[prop] = source[prop];
|
result[prop] = this.mergeObjects(result[prop], source[prop]);
|
||||||
|
} else {
|
||||||
|
result[prop] = source[prop];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
return result;
|
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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,9 +1,8 @@
|
|||||||
{
|
{
|
||||||
"$schema": "../../extension.schema.json",
|
"$schema": "../../extension.schema.json",
|
||||||
"name": "app",
|
"$name": "app",
|
||||||
"version": "1.0.0",
|
"$version": "1.0.0",
|
||||||
|
"$references": [
|
||||||
"references": [
|
|
||||||
"plugin1.json",
|
"plugin1.json",
|
||||||
"plugin2.json"
|
"plugin2.json"
|
||||||
],
|
],
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
{
|
{
|
||||||
"$schema": "../../../extension.schema.json",
|
"$schema": "../../../extension.schema.json",
|
||||||
"version": "1.0.0",
|
"$version": "1.0.0",
|
||||||
"name": "plugin1",
|
"$name": "plugin1",
|
||||||
"description": "demo plugin",
|
"$description": "demo plugin",
|
||||||
|
|
||||||
"actions": [
|
"actions": [
|
||||||
{
|
{
|
||||||
@ -36,6 +36,19 @@
|
|||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
"navbar": [
|
||||||
|
{
|
||||||
|
"id": "app.navbar.primary",
|
||||||
|
"items": [
|
||||||
|
{
|
||||||
|
"id": "app.navbar.personalFiles",
|
||||||
|
"icon": "extension",
|
||||||
|
"title": "APP.BROWSE.PERSONAL.SIDENAV_LINK.LABEL",
|
||||||
|
"route": "personal-files"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
"content": {
|
"content": {
|
||||||
"actions": [
|
"actions": [
|
||||||
{
|
{
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
{
|
{
|
||||||
"$schema": "../../../extension.schema.json",
|
"$schema": "../../../extension.schema.json",
|
||||||
"version": "1.0.0",
|
"$version": "1.0.0",
|
||||||
"name": "plugin2",
|
"$name": "plugin2",
|
||||||
"description": "demo plugin",
|
"$description": "demo plugin",
|
||||||
|
|
||||||
"routes": [
|
"routes": [
|
||||||
{
|
{
|
||||||
|
Loading…
x
Reference in New Issue
Block a user