Skip to content
Snippets Groups Projects
Unverified Commit 670caadf authored by Christopher Hanna Johnson's avatar Christopher Hanna Johnson Committed by GitHub
Browse files

Merge pull request #2324 from ProjectMirador/2185-2188-mutliple-add-plugins-and-order

Allow multiple add plugins but give wrap plugins precedence. Closes #…
parents 9ff6931e 7a9571d1
No related branches found
No related tags found
No related merge requests found
import { pluginStore } from '../../../src/extend';
describe('storePlugins()', () => {
it('should run without throw error when Array is passed', () => {
expect(() => pluginStore.storePlugins([])).not.toThrow();
});
it('should run without throw error when nothing is passed', () => {
expect(() => pluginStore.storePlugins()).not.toThrow();
});
});
describe('getPlugins', () => {
it('returns undefined if no plugin for target exist', () => {
pluginStore.storePlugins();
expect(pluginStore.getPlugins('target')).not.toBeDefined();
});
it('returns mode->plugins mapping for target', () => {
const plugins = [
{ mode: 'wrap', target: 'Window' },
{ mode: 'wrap', target: 'Window' },
{ mode: 'add', target: 'Window' },
{ mode: 'add', target: 'Window' },
{ mode: 'wrap', target: 'TopBar' },
{ mode: 'wrap', target: 'TopBar' },
{ mode: 'add', target: 'TopBar' },
{ mode: 'add', target: 'TopBar' },
];
pluginStore.storePlugins(plugins);
expect(pluginStore.getPlugins('Window')).toEqual({
add: [
{ mode: 'add', target: 'Window' },
{ mode: 'add', target: 'Window' },
],
wrap: [
{ mode: 'wrap', target: 'Window' },
{ mode: 'wrap', target: 'Window' },
],
});
expect(pluginStore.getPlugins('TopBar')).toEqual({
add: [
{ mode: 'add', target: 'TopBar' },
{ mode: 'add', target: 'TopBar' },
],
wrap: [
{ mode: 'wrap', target: 'TopBar' },
{ mode: 'wrap', target: 'TopBar' },
],
});
});
});
import React from 'react';
import { shallow } from 'enzyme';
import { withPlugins } from '../../../src/extend';
import { pluginStore } from '../../../src/extend/pluginStore';
jest.mock('../../../src/extend/pluginStore');
/** */
const Target = props => <div>Hello</div>;
/** create wrapper */
function createWrapper(plugins) {
pluginStore.getPlugins = () => plugins;
const props = {
bar: 2,
foo: 1,
};
const PluginWrapper = withPlugins('Target', Target);
return shallow(<PluginWrapper {...props} />);
}
describe('withPlugins', () => {
it('should return a function (normal function call)', () => {
expect(withPlugins('Target', Target)).toBeInstanceOf(Function);
});
it('should return a function (curry function call)', () => {
expect(withPlugins('Target')(Target)).toBeInstanceOf(Function);
});
it('displayName prop of returned function is based on target name argument', () => {
expect(withPlugins('Bubu', Target).displayName)
.toBe('WithPlugins(Bubu)');
});
});
describe('PluginHoc: if no plugin exists for the target', () => {
it('renders the target component', () => {
const wrapper = createWrapper([]);
expect(wrapper.find(Target).length).toBe(1);
expect(wrapper.find(Target).props().foo).toBe(1);
expect(wrapper.find(Target).props().bar).toBe(2);
});
});
describe('PluginHoc: if a wrap plugin extists for the target', () => {
it('renders the plugin component and passes the target component as a prop', () => {
/** */
const PluginComponent = props => <div>look i am a plugin</div>;
const plugin = {
component: PluginComponent,
mode: 'wrap',
target: 'Target',
};
const wrapper = createWrapper([plugin]);
const selector = 'Connect(PluginComponent)';
expect(wrapper.find(selector).length).toBe(1);
expect(wrapper.find(selector).props().foo).toBe(1);
expect(wrapper.find(selector).props().bar).toBe(2);
expect(wrapper.find(selector).props().TargetComponent)
.toBe(Target);
});
});
describe('PluginHoc: if a add plugin exists for the target', () => {
it('renders the target component and passes the plugin component as a prop', () => {
/** */
const PluginComponent = props => <div>look i am a plugin</div>;
const plugin = {
component: PluginComponent,
mode: 'add',
target: 'Target',
};
const wrapper = createWrapper([plugin]);
expect(wrapper.find(Target).length).toBe(1);
expect(wrapper.find(Target).props().foo).toBe(1);
expect(wrapper.find(Target).props().bar).toBe(2);
expect(wrapper.find(Target).props().PluginComponent.WrappedComponent)
.toBe(PluginComponent);
});
});
import React from 'react';
import { shallow } from 'enzyme';
import { withPlugins } from '../../../src/extend';
import { pluginStore } from '../../../src/extend/pluginStore';
jest.mock('../../../src/extend/pluginStore');
/** Mock target component */
const Target = props => <div>Hello</div>;
/** create wrapper */
function createPluginHoc(plugins) {
pluginStore.getPlugins = () => plugins;
const props = { bar: 2, foo: 1 };
const PluginHoc = withPlugins('Target', Target);
return shallow(<PluginHoc {...props} />);
}
describe('withPlugins', () => {
it('should return a function (normal function call)', () => {
expect(withPlugins('Target', Target)).toBeInstanceOf(Function);
});
it('should return a function (curry function call)', () => {
expect(withPlugins('Target')(Target)).toBeInstanceOf(Function);
});
it('displayName prop of returned function is based on target name argument', () => {
expect(withPlugins('Bubu', Target).displayName)
.toBe('WithPlugins(Bubu)');
});
});
describe('PluginHoc: if no plugin exists for the target', () => {
it('renders the target component', () => {
const hoc = createPluginHoc([]);
expect(hoc.find(Target).length).toBe(1);
expect(hoc.find(Target).props().foo).toBe(1);
expect(hoc.find(Target).props().bar).toBe(2);
});
});
describe('PluginHoc: if wrap plugins exist for target', () => {
it('renders the first wrap plugin and passes the target component as prop', () => {
/** */ const WrapPluginComponentA = props => <div>look i am a plugin</div>;
/** */ const WrapPluginComponentB = props => <div>look i am a plugin</div>;
const plugins = {
wrap: [
{ component: WrapPluginComponentA, mode: 'wrap', target: 'Target' },
{ component: WrapPluginComponentB, mode: 'wrap', target: 'Target' },
],
};
const hoc = createPluginHoc(plugins);
const selector = 'Connect(WrapPluginComponentA)';
expect(hoc.find(selector).length).toBe(1);
expect(hoc.find(selector).props().foo).toBe(1);
expect(hoc.find(selector).props().bar).toBe(2);
expect(hoc.find(selector).props().TargetComponent).toBe(Target);
});
});
describe('PluginHoc: if add plugins exist but no wrap plugin', () => {
it('renders the target component and passes all add plugin components as a prop', () => {
/** */ const AddPluginComponentA = props => <div>look i am a plugin</div>;
/** */ const AddPluginComponentB = props => <div>look i am a plugin</div>;
const plugins = {
add: [
{ component: AddPluginComponentA, mode: 'add', target: 'Target' },
{ component: AddPluginComponentB, mode: 'add', target: 'Target' },
],
};
const hoc = createPluginHoc(plugins);
const selector = Target;
expect(hoc.find(selector).length).toBe(1);
expect(hoc.find(selector).props().foo).toBe(1);
expect(hoc.find(selector).props().bar).toBe(2);
expect(hoc.find(selector).props().PluginComponents[0].displayName)
.toBe('Connect(AddPluginComponentA)');
expect(hoc.find(selector).props().PluginComponents[1].displayName)
.toBe('Connect(AddPluginComponentB)');
});
});
describe('PluginHoc: if wrap plugins AND add plugins exist for target', () => {
it('renders the first wrap plugin, ignores add plugins', () => {
/** */ const WrapPluginComponentA = props => <div>look i am a plugin</div>;
/** */ const WrapPluginComponentB = props => <div>look i am a plugin</div>;
/** */ const AddPluginComponentA = props => <div>look i am a plugin</div>;
/** */ const AddPluginComponentB = props => <div>look i am a plugin</div>;
const plugins = {
add: [
{ component: AddPluginComponentA, mode: 'add', target: 'Target' },
{ component: AddPluginComponentB, mode: 'add', target: 'Target' },
],
wrap: [
{ component: WrapPluginComponentA, mode: 'wrap', target: 'Target' },
{ component: WrapPluginComponentB, mode: 'wrap', target: 'Target' },
],
};
const hoc = createPluginHoc(plugins);
expect(hoc.find('Connect(WrapPluginComponentA)').length).toBe(1);
expect(hoc.find(Target).length).toBe(0);
});
});
import update from 'lodash/update';
export const pluginStore = {
/** */
getPlugins() {
return this.plugins || [];
/**
* Get plugins for target
*
* @param {String} targetName
* @return {Object | undefined } - looks like:
*
* {
* wrap: [plugin1, ...],
* add: [plugin2, ...],
* }
*/
getPlugins(target) {
return this.pluginMap[target];
},
/** */
/**
* Store Plugins
*
* @param {Array} plugins
*/
storePlugins(plugins) {
this.plugins = plugins || [];
this.pluginMap = mapPlugins(plugins || []);
},
};
/**
* Returns a mapping from plugins to targets and modes
*
* @param {Array} plugins
* @return {Object} - looks like:
*
*
* {
* 'WorkspacePanel': {
* wrap: [plugin3, ...],
* add: [plugin4, ...],
* },
* 'Window': {
* wrap: [plugin3, ...],
* add: [plugin4, ...],
* }
* }
*/
function mapPlugins(plugins) {
return plugins.reduce((map, plugin) => (
update(map, [plugin.target, plugin.mode], x => [...x || [], plugin])
), {});
}
import React, { Component } from 'react';
import curry from 'lodash/curry';
import isEmpty from 'lodash/isEmpty';
import { connect } from 'react-redux';
import { pluginStore } from '.';
......@@ -8,18 +9,22 @@ function _withPlugins(targetName, TargetComponent) { // eslint-disable-line no-u
/** plugin wrapper hoc */
class PluginHoc extends Component {
/** render */
render() {
const plugin = pluginStore.getPlugins().find(p => p.target === targetName);
render() { // eslint-disable-line consistent-return
const plugins = pluginStore.getPlugins(targetName);
if (plugin && plugin.mode === 'wrap') {
const PluginComponent = connectPluginComponent(plugin);
return <PluginComponent {...this.props} TargetComponent={TargetComponent} />;
if (isEmpty(plugins)) {
return <TargetComponent {...this.props} />;
}
if (plugin && plugin.mode === 'add') {
const PluginComponent = connectPluginComponent(plugin);
return <TargetComponent {...this.props} PluginComponent={PluginComponent} />;
if (!isEmpty(plugins.wrap)) {
const WrapPluginComponent = connectPluginComponent(plugins.wrap[0]);
return <WrapPluginComponent {...this.props} TargetComponent={TargetComponent} />;
}
if (!isEmpty(plugins.add)) {
const AddPluginComponents = plugins.add.map(plugin => connectPluginComponent(plugin));
return <TargetComponent {...this.props} PluginComponents={AddPluginComponents} />;
}
return <TargetComponent {...this.props} />;
}
}
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment