Skip to content

Commit

Permalink
Added (monitored) state usage in plugins cfg expressions (including s…
Browse files Browse the repository at this point in the history
…howIn and hideFrom) (#1452)

* Added state to plugins configuration scope

* clean up

* Added scope support to showIn and hideFrom

* Fixed eslint error
  • Loading branch information
mbarto authored Feb 15, 2017
1 parent 6313495 commit 9d21254
Show file tree
Hide file tree
Showing 5 changed files with 80 additions and 44 deletions.
13 changes: 10 additions & 3 deletions web/client/components/plugins/PluginsContainer.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ const PluginsUtils = require('../../utils/PluginsUtils');

const assign = require('object-assign');

const {get} = require('lodash');

const PluginsContainer = React.createClass({
propTypes: {
mode: React.PropTypes.string,
Expand All @@ -21,6 +23,7 @@ const PluginsContainer = React.createClass({
className: React.PropTypes.string,
style: React.PropTypes.object,
pluginsState: React.PropTypes.object,
monitoredState: React.PropTypes.object,
defaultMode: React.PropTypes.string
},
getDefaultProps() {
Expand All @@ -33,7 +36,8 @@ const PluginsContainer = React.createClass({
id: "plugins-container",
className: "plugins-container",
style: {},
pluginsState: {}
pluginsState: {},
monitoredState: {}
};
},
getInitialState() {
Expand All @@ -47,8 +51,11 @@ const PluginsContainer = React.createClass({
componentWillReceiveProps(newProps) {
this.loadPlugins(newProps.pluginsState);
},
getState(path) {
return get(this.props.monitoredState, path) || get(this.props.params, path);
},
getPluginDescriptor(plugin) {
return PluginsUtils.getPluginDescriptor(this.props.plugins,
return PluginsUtils.getPluginDescriptor(this.getState, this.props.plugins,
this.props.pluginsConfig[this.props.mode], plugin, this.state.loadedPlugins);
},
renderPlugins(plugins) {
Expand Down Expand Up @@ -78,7 +85,7 @@ const PluginsContainer = React.createClass({
},
loadPlugins(state) {
(this.props.pluginsConfig && this.props.pluginsConfig[this.props.mode] || [])
.map((plugin) => PluginsUtils.getPluginDescriptor(this.props.plugins,
.map((plugin) => PluginsUtils.getPluginDescriptor(this.getState, this.props.plugins,
this.props.pluginsConfig[this.props.mode], plugin, this.state.loadedPlugins))
.filter((plugin) => plugin.impl.loadPlugin).forEach((plugin) => {
if (!this.state.loadedPlugins[plugin.name]) {
Expand Down
6 changes: 4 additions & 2 deletions web/client/containers/Embedded.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,13 @@ const {connect} = require('react-redux');

const url = require('url');
const urlQuery = url.parse(window.location.href, true).query;

const PluginsUtils = require('../utils/PluginsUtils');
const ConfigUtils = require('../utils/ConfigUtils');

const PluginsContainer = connect((state) => ({
mode: (urlQuery.mode || (state.browser && state.browser.mobile ? 'mobile' : 'desktop')),
pluginsState: state && state.controls || {}
pluginsState: state && state.controls || {},
monitoredState: PluginsUtils.filterState(state, ConfigUtils.getConfigProp('monitorState') || [])
}))(require('../components/plugins/PluginsContainer'));

const Embedded = React.createClass({
Expand Down
4 changes: 3 additions & 1 deletion web/client/containers/MapViewer.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,13 @@ const url = require('url');
const urlQuery = url.parse(window.location.href, true).query;

const ConfigUtils = require('../utils/ConfigUtils');
const PluginsUtils = require('../utils/PluginsUtils');

const PluginsContainer = connect((state) => ({
pluginsConfig: state.plugins || ConfigUtils.getConfigProp('plugins') || null,
mode: (urlQuery.mode || (state.browser && state.browser.mobile ? 'mobile' : 'desktop')),
pluginsState: state && state.controls || {}
pluginsState: state && state.controls || {},
monitoredState: PluginsUtils.filterState(state, ConfigUtils.getConfigProp('monitorState') || [])
}))(require('../components/plugins/PluginsContainer'));

const MapViewer = React.createClass({
Expand Down
5 changes: 4 additions & 1 deletion web/client/containers/Page.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,12 @@ const {connect} = require('react-redux');

const url = require('url');
const urlQuery = url.parse(window.location.href, true).query;
const PluginsUtils = require('../utils/PluginsUtils');
const ConfigUtils = require('../utils/ConfigUtils');

const PluginsContainer = connect((state) => ({
mode: urlQuery.mode || ((urlQuery.mobile || (state.browser && state.browser.mobile)) ? 'mobile' : 'desktop')
mode: urlQuery.mode || ((urlQuery.mobile || (state.browser && state.browser.mobile)) ? 'mobile' : 'desktop'),
monitoredState: PluginsUtils.filterState(state, ConfigUtils.getConfigProp('monitorState') || [])
}))(require('../components/plugins/PluginsContainer'));

const Page = React.createClass({
Expand Down
96 changes: 59 additions & 37 deletions web/client/utils/PluginsUtils.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,20 +7,53 @@
*/

const assign = require('object-assign');
const {omit, isObject, head, isArray} = require('lodash');
const {omit, isObject, head, isArray, isString} = require('lodash');
const {combineReducers} = require('redux');

const {memoize, get} = require('lodash');

const filterState = memoize((state, monitor) => {
return monitor.reduce((previous, current) => {
return assign(previous, {
[current.name]: get(state, current.path)
});
}, {});
}, (state, monitor) => {
return monitor.reduce((previous, current) => {
return previous + JSON.stringify(get(state, current.path));
}, '');
});

const isPluginConfigured = (pluginsConfig, plugin) => {
const cfg = pluginsConfig;
const pluginName = plugin.substring(0, plugin.length - 6);
return head(cfg.filter((cfgObj) => cfgObj.name === pluginName || cfgObj === pluginName));
};

const showIn = (cfg, name, id, isDefault) => {
return ((id && cfg.showIn && cfg.showIn.indexOf(id) !== -1) ||
(cfg.showIn && cfg.showIn.indexOf(name) !== -1) ||
/*eslint-disable */
const parseExpression = (state, requires, value) => {
const searchExpression = /^\{(.*?)\}$/;
const context = requires || {};
const expression = searchExpression.exec(value);
if (expression !== null) {
return eval(expression[1]);
}
return value;
};
/*eslint-enable */

const handleExpression = (state, requires, expression) => {
if (isString(expression) && expression.indexOf('{') === 0) {
return parseExpression(state, requires, expression);
}
return expression;
};

const showIn = (state, requires, cfg, name, id, isDefault) => {
return ((id && cfg.showIn && handleExpression(state, requires, cfg.showIn).indexOf(id) !== -1) ||
(cfg.showIn && handleExpression(state, requires, cfg.showIn).indexOf(name) !== -1) ||
(!cfg.showIn && isDefault)) &&
!((cfg.hideFrom && cfg.hideFrom.indexOf(name) !== -1) || (id && cfg.hideFrom && cfg.hideFrom.indexOf(id) !== -1));
!((cfg.hideFrom && handleExpression(state, requires, cfg.hideFrom).indexOf(name) !== -1) || (id && cfg.hideFrom && handleExpression(state, requires, cfg.hideFrom).indexOf(id) !== -1));
};

const includeLoaded = (name, loadedPlugins, plugin) => {
Expand All @@ -44,12 +77,25 @@ const getMorePrioritizedContainer = (pluginImpl, plugins, priority) => {
}, {plugin: null, priority: priority});
};

const getPluginItems = (plugins, pluginsConfig, name, id, isDefault, loadedPlugins) => {
const parsePluginConfig = (state, requires, cfg) => {
if (isArray(cfg)) {
return cfg.map((value) => parsePluginConfig(state, requires, value));
}
if (isObject(cfg)) {
return Object.keys(cfg).reduce((previous, current) => {
const value = cfg[current];
return assign(previous, {[current]: parsePluginConfig(state, requires, value)});
}, {});
}
return parseExpression(state, requires, cfg);
};

const getPluginItems = (state, plugins, pluginsConfig, name, id, isDefault, loadedPlugins) => {
return Object.keys(plugins)
.filter((plugin) => plugins[plugin][name])
.filter((plugin) => {
const cfgObj = isPluginConfigured(pluginsConfig, plugin);
return cfgObj && showIn(cfgObj, name, id, isDefault);
return cfgObj && showIn(state, plugins.requires, cfgObj, name, id, isDefault);
})
.filter((plugin) => getMorePrioritizedContainer(plugins[plugin], pluginsConfig, plugins[plugin][name].priority || 0).plugin === null)
.map((plugin) => {
Expand All @@ -61,40 +107,15 @@ const getPluginItems = (plugins, pluginsConfig, name, id, isDefault, loadedPlugi
item,
pluginCfg.override && pluginCfg.override[name] || {},
{
cfg: pluginCfg && pluginCfg.cfg || undefined
cfg: pluginCfg && parsePluginConfig(state, plugins.requires, pluginCfg.cfg || {}) || undefined
},
{
plugin: pluginImpl,
items: getPluginItems(plugins, pluginsConfig, pluginName, null, true, loadedPlugins)
items: getPluginItems(state, plugins, pluginsConfig, pluginName, null, true, loadedPlugins)
});
});
};

/*eslint-disable */
const parseExpression = (requires, value) => {
const searchExpression = /^\{(.*?)\}$/;
const context = requires || {};
const expression = searchExpression.exec(value);
if (expression !== null) {
return eval(expression[1]);
}
return value;
};
/*eslint-enable */


const parsePluginConfig = (requires, cfg) => {
if (isArray(cfg)) {
return cfg.map((value) => parsePluginConfig(requires, value));
}
if (isObject(cfg)) {
return Object.keys(cfg).reduce((previous, current) => {
const value = cfg[current];
return assign(previous, {[current]: parsePluginConfig(requires, value)});
}, {});
}
return parseExpression(requires, cfg);
};
const getReducers = (plugins) => Object.keys(plugins).map((name) => plugins[name].reducers)
.reduce((previous, current) => assign({}, previous, current), {});

Expand All @@ -104,9 +125,10 @@ const PluginsUtils = {
return combineReducers(assign({}, reducers, pluginsReducers));
},
getReducers,
filterState,
getPlugins: (plugins) => Object.keys(plugins).map((name) => plugins[name])
.reduce((previous, current) => assign({}, previous, omit(current, 'reducers')), {}),
getPluginDescriptor: (plugins, pluginsConfig, pluginDef, loadedPlugins = {}) => {
getPluginDescriptor: (state, plugins, pluginsConfig, pluginDef, loadedPlugins = {}) => {
const name = isObject(pluginDef) ? pluginDef.name : pluginDef;
const id = isObject(pluginDef) ? pluginDef.id : null;
const stateSelector = isObject(pluginDef) ? pluginDef.stateSelector : id || undefined;
Expand All @@ -120,8 +142,8 @@ const PluginsUtils = {
id: id || name,
name,
impl: includeLoaded(name, loadedPlugins, (impl.loadPlugin || impl.displayName) ? impl : impl(stateSelector)),
cfg: isObject(pluginDef) ? parsePluginConfig(plugins.requires, pluginDef.cfg) : {},
items: getPluginItems(plugins, pluginsConfig, name, id, isDefault, loadedPlugins)
cfg: isObject(pluginDef) ? parsePluginConfig(state, plugins.requires, pluginDef.cfg) : {},
items: getPluginItems(state, plugins, pluginsConfig, name, id, isDefault, loadedPlugins)
};
},
getMorePrioritizedContainer
Expand Down

0 comments on commit 9d21254

Please sign in to comment.