diff --git a/client/coral-embed-stream/src/Embed.js b/client/coral-embed-stream/src/Embed.js index fb130d26e..55e5a5d46 100644 --- a/client/coral-embed-stream/src/Embed.js +++ b/client/coral-embed-stream/src/Embed.js @@ -6,7 +6,7 @@ import isEqual from 'lodash/isEqual'; import I18n from 'coral-framework/modules/i18n/i18n'; import translations from 'coral-framework/translations'; const lang = new I18n(translations); -import {graphImporter} from 'coral-framework/helpers/plugins'; +import {queriesAndMutators as pluginQueriesAndMutators} from 'coral-framework/helpers/plugins'; import {TabBar, Tab, TabContent, Spinner} from 'coral-ui'; @@ -306,5 +306,5 @@ export default compose( removeCommentTag, deleteAction, queryStream, - ...graphImporter + ...pluginQueriesAndMutators, )(Embed); diff --git a/client/coral-framework/actions/index.js b/client/coral-framework/actions/index.js index 1168c9c9a..638630812 100644 --- a/client/coral-framework/actions/index.js +++ b/client/coral-framework/actions/index.js @@ -1,11 +1,11 @@ import * as authActions from './auth'; import * as assetActions from './asset'; import * as notificationActions from './notification'; -import {actionsImporter} from '../helpers/plugins'; +import {actions as pluginActions} from '../helpers/plugins'; export default { authActions, assetActions, notificationActions, - pluginActions: actionsImporter + pluginActions, }; diff --git a/client/coral-framework/components/Slot.js b/client/coral-framework/components/Slot.js index ecadd716c..c26fb17ca 100644 --- a/client/coral-framework/components/Slot.js +++ b/client/coral-framework/components/Slot.js @@ -1,11 +1,12 @@ import React, {Component} from 'react'; -import {injectPlugins} from 'coral-framework/helpers/plugins'; +import {getSlotComponents} from 'coral-framework/helpers/plugins'; class Slot extends Component { render() { + const {fill, ...rest} = this.props; return (
- {injectPlugins(this.props)} + {getSlotComponents(fill, rest)}
); } diff --git a/client/coral-framework/helpers/plugins.js b/client/coral-framework/helpers/plugins.js index e5ab297c8..cf12c4f62 100644 --- a/client/coral-framework/helpers/plugins.js +++ b/client/coral-framework/helpers/plugins.js @@ -1,157 +1,62 @@ import {client as clientPlugins} from 'pluginsConfig'; import React from 'react'; +import mapValues from 'lodash/mapValues'; +import values from 'lodash/values'; +import flatten from 'lodash/flatten'; +import merge from 'lodash/merge'; -function injectPlugins ({fill, ...props}) { - let context, - importedFiles; - - function buildContext() { - - /** - * buildContext creates the context for the plugins - * require.context(, true, - * path: The path where the importer builds the context. 'plugins' is allowed as path because it's an alias - * regxp: A Regular Expression to match the files that the importer needs. i.e (index.js, config.json) - * data such as path and regexp cannot be passed as arguments or variables - */ - context = require.context('plugins', true, /\.\/(.*)\/client\/(index|config).(js|json)$/); - return importedFiles = context - .keys() - .map(key => shapeData(key)); - } - - function getConfig (name) { - - /** - * getConfig finds a the config file for each plugin - * returns the config.json as an object to be passed as props to the plugin - */ - return importedFiles - .filter(key => key.format === 'json' && key.name === name) - .reduce((acc, plugin) => { - return context(plugin.key); - }, {}); - } - - function addProps (plugin) { - - /** - * addProps add properties to the injected plugins - */ - plugin.props = { - ...getConfig(plugin.name), - ...props - }; - - return plugin; - } - - function filterBySlot (plugin) { - - /** - * filterBySlot - */ - return plugin.props.slot === fill; - } - - function init() { - - /** - * init will build the context and - * returns a map with each plugin and its instance - */ - buildContext(); - - return importedFiles - .filter(filterByUserConfig) - .filter(key => key.format === 'js') - .map(addProps) - .filter(filterBySlot) - .reduce((entry, plugin, i) => { - const component = context(plugin.key); - const element = React.createElement(component, { - key: i, - ...plugin.props - }, null); - - entry = [...entry, element]; - return entry; - }, []); - } - - return init(); -} - -function shapeData(test) { - - /** - * shapeData shapes each item in the plugins array with useful data - * returns an Object with the name of the plugin, the format, and it's key(filename) - */ - const match = test.match(/\.\/(.*)\/client\/.*.(json|js)$/); - return { - name: match[1], - format: match[2], - key: match[0] - }; -} - -function filterByUserConfig (plugin) { - - /** - * filterByUserConfig will filter the imported files and will only keep the allowed plugins - */ - return clientPlugins.indexOf(plugin.name) > -1; -} - -function importAll(context) { - - /** - * importAll builds the map to import - */ - return context - .keys() - .map(key => shapeData(key)) - .filter(filterByUserConfig) - .reduce((entry, actionsPlugin) => { - const input = context(actionsPlugin.key); - return {...entry, ...input}; - }, {}); -} - -function importAllAsArr(context) { - - /** - * importAllAsArr builds the array to import - */ - return context - .keys() - .map(key => shapeData(key)) - .filter(filterByUserConfig) - .reduce((entry, graphPlugin) => { - const input = context(graphPlugin.key); - const res = Object.keys(input) - .map(key => input[key]); - return [...entry, ...res]; - }, []); -} - -function actionsImporter () { - return importAll(require.context('plugins', true, /\.\/(.*)\/client\/actions.js$/)); -} - -function reducersImporter () { - return importAll(require.context('plugins', true, /\.\/(.*)\/client\/reducer.js$/)); -} - -function graphImporter () { - return importAllAsArr(require.context('plugins', true, /\.\/(.*)\/client\/(queries|mutations)\/index.js$/)); -} - -export default { - injectPlugins, - actionsImporter: actionsImporter(), - reducersImporter: reducersImporter(), - graphImporter: graphImporter() +// Gather require context information of different parts of the plugins. +const contextMap = { + actions: require.context('plugins', true, /\.\/(.*)\/client\/actions.js$/), + reducers: require.context('plugins', true, /\.\/(.*)\/client\/reducer.js$/), + graph: require.context('plugins', true, /\.\/(.*)\/client\/(mutations|queries)\/index.js$/), + configs: require.context('plugins', true, /\.\/(.*)\/client\/config.json$/), + components: require.context('plugins', true, /\.\/(.*)\/client\/index.js$/), }; +const getPluginName = (key) => key.match(/\.\/(.*)\/client\/.*$/)[1]; +const isActivePlugin = (plugin) => clientPlugins.indexOf(plugin) > -1; + +/** + * Loads all enabled modules of the context and returns an + * Array with {plugin, module} entries. + */ +function loadActiveModules(context) { + return context + .keys() + .map(key => ({key, plugin: getPluginName(key)})) + .filter(info => isActivePlugin(info.plugin)) + .map(info => ({plugin: info.plugin, module: context(info.key)})); +} + +const loaded = mapValues(contextMap, loadActiveModules); + +/** + * getConfig returns the config object of given plugin. + */ +function getConfig(plugin) { + return loaded.configs.filter(o => o.plugin === plugin)[0].module; +} + +/** + * getSlotComponents returns React Elements for given slot. + */ +export function getSlotComponents(slot, props = {}) { + return loaded.components + .map((o, i) => ({ + component: o.module, + props: {...getConfig(o.plugin), ...props, key: i}, + })) + .filter(o => o.props.slot === slot) + .map(o => React.createElement(o.component, o.props)); +} + +// actions is a map of redux actions . +export const actions = merge(...loaded.actions.map(o => ({...o.module}))); + +// reducers is a map of redux reducers. +export const reducers = merge(...loaded.reducers.map(o => ({...o.module}))); + +// queriesAndMutators is an array of graphQL queries and mutators. +export const queriesAndMutators = flatten(loaded.graph.map(o => values(o.module))); + diff --git a/client/coral-framework/reducers/index.js b/client/coral-framework/reducers/index.js index e2e003f7d..f174ddbb2 100644 --- a/client/coral-framework/reducers/index.js +++ b/client/coral-framework/reducers/index.js @@ -1,11 +1,11 @@ import auth from './auth'; import user from './user'; import asset from './asset'; -import {reducersImporter} from '../helpers/plugins'; +import {reducers as pluginReducers} from '../helpers/plugins'; export default { auth, user, asset, - ...reducersImporter + ...pluginReducers };