Created
July 15, 2019 15:39
-
-
Save derrickmehaffy/10d7d6598358a3f155ed200b6d2bb466 to your computer and use it in GitHub Desktop.
Hacky way to use custom plugins in admin for Strapi beta from soupette
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| // First make sure your plugin has the following | |
| 1 - A pluginId file path my-plugin/admin/src/pluginId.js | |
| ``` | |
| import pluginPkg from '../../package.json'; | |
| const pluginId = pluginPkg.name.replace(/^strapi-plugin-/i, ''); | |
| export default pluginId; | |
| ``` | |
| 2 - An Initializer container filer containers/Initializer | |
| ``` | |
| class Initializer extends React.PureComponent { | |
| // eslint-disable-line react/prefer-stateless-function | |
| componentDidMount() { | |
| // Emit the event 'pluginReady' | |
| this.props.updatePlugin(pluginId, 'isReady', true); | |
| } | |
| render() { | |
| return null; | |
| } | |
| } | |
| ``` | |
| 3- An index.js file src/index.js | |
| ``` | |
| import React from 'react'; | |
| import pluginPkg from '../../package.json'; | |
| import pluginId from './pluginId'; | |
| import App from './containers/Main'; | |
| import Initializer from './containers/Initializer'; | |
| // import lifecycles from './lifecycles'; | |
| import trads from './translations'; | |
| const pluginDescription = pluginPkg.strapi.description || pluginPkg.description; | |
| function Comp(props) { | |
| return <App {...props} />; | |
| } | |
| const plugin = { | |
| blockerComponent: null, | |
| blockerComponentProps: {}, | |
| description: pluginDescription, | |
| icon: pluginPkg.strapi.icon, | |
| id: pluginId, | |
| initializer: Initializer, | |
| injectedComponents: [], | |
| isReady: false, | |
| layout: null, | |
| lifecycles: () => {}, | |
| leftMenuLinks: [], | |
| leftMenuSections: [], | |
| mainComponent: Comp, | |
| name: pluginPkg.strapi.name, | |
| preventComponentRendering: false, | |
| suffixUrl: '/ctm-configurations/models', | |
| trads, | |
| }; | |
| export default plugin; | |
| ``` | |
| // Once you have met the requirements | |
| 1- Create the admin folder | |
| path: my-app/admin | |
| 2- Create an app.js file | |
| path: my-app/admin/src/app.js | |
| 3 - Apply the following modifications | |
| ``` | |
| // /** | |
| // * | |
| // * app.js | |
| // * | |
| // * Entry point of the application | |
| // */ | |
| import '@babel/polyfill'; | |
| import 'sanitize.css/sanitize.css'; | |
| // Third party css library needed | |
| // Currently unable to bundle them | |
| import 'react-select/dist/react-select.css'; | |
| import 'react-datetime/css/react-datetime.css'; | |
| import './styles/main.scss'; | |
| import React from 'react'; | |
| import ReactDOM from 'react-dom'; | |
| import { Provider } from 'react-redux'; | |
| import { BrowserRouter } from 'react-router-dom'; | |
| import { merge, set } from 'lodash'; | |
| import { | |
| freezeApp, | |
| pluginLoaded, | |
| unfreezeApp, | |
| updatePlugin, | |
| getAppPluginsSucceeded, | |
| } from './containers/App/actions'; | |
| import { showNotification } from './containers/NotificationProvider/actions'; | |
| import basename from './utils/basename'; | |
| import injectReducer from './utils/injectReducer'; | |
| import injectSaga from './utils/injectSaga'; | |
| // Import root component | |
| import App from './containers/App'; | |
| // Import Language provider | |
| import LanguageProvider from './containers/LanguageProvider'; | |
| import configureStore from './configureStore'; | |
| // Import i18n messages | |
| import { translationMessages, languages } from './i18n'; | |
| // Create redux store with history | |
| import history from './utils/history'; | |
| import plugins from './plugins'; | |
| const customPlugins = ['my-plugin1', 'my-plugin2']; | |
| customPlugins.forEach(plugin => { | |
| set(plugins, plugin, require(`../../../plugins/${plugin}/admin/src`).default); | |
| }); | |
| const initialState = {}; | |
| const store = configureStore(initialState, history); | |
| const { dispatch } = store; | |
| const MOUNT_NODE = | |
| document.getElementById('app') || document.createElement('div'); | |
| dispatch(getAppPluginsSucceeded(Object.keys(plugins))); | |
| Object.keys(plugins).forEach(plugin => { | |
| const currentPlugin = plugins[plugin]; | |
| const pluginTradsPrefixed = languages.reduce((acc, lang) => { | |
| const currentLocale = currentPlugin.trads[lang]; | |
| if (currentLocale) { | |
| const localeprefixedWithPluginId = Object.keys(currentLocale).reduce( | |
| (acc2, current) => { | |
| acc2[`${plugins[plugin].id}.${current}`] = currentLocale[current]; | |
| return acc2; | |
| }, | |
| {}, | |
| ); | |
| acc[lang] = localeprefixedWithPluginId; | |
| } | |
| return acc; | |
| }, {}); | |
| try { | |
| merge(translationMessages, pluginTradsPrefixed); | |
| dispatch(pluginLoaded(currentPlugin)); | |
| } catch (err) { | |
| console.log({ err }); | |
| } | |
| }); | |
| // TODO | |
| const remoteURL = (() => { | |
| // Relative URL (ex: /dashboard) | |
| if (REMOTE_URL[0] === '/') { | |
| return (window.location.origin + REMOTE_URL).replace(/\/$/, ''); | |
| } | |
| return REMOTE_URL.replace(/\/$/, ''); | |
| })(); | |
| const displayNotification = (message, status) => { | |
| dispatch(showNotification(message, status)); | |
| }; | |
| const lockApp = data => { | |
| dispatch(freezeApp(data)); | |
| }; | |
| const unlockApp = () => { | |
| dispatch(unfreezeApp()); | |
| }; | |
| window.strapi = Object.assign(window.strapi || {}, { | |
| node: MODE || 'host', | |
| remoteURL, | |
| backendURL: BACKEND_URL === '/' ? window.location.origin : BACKEND_URL, | |
| notification: { | |
| success: message => { | |
| displayNotification(message, 'success'); | |
| }, | |
| warning: message => { | |
| displayNotification(message, 'warning'); | |
| }, | |
| error: message => { | |
| displayNotification(message, 'error'); | |
| }, | |
| info: message => { | |
| displayNotification(message, 'info'); | |
| }, | |
| }, | |
| refresh: pluginId => ({ | |
| translationMessages: translationMessagesUpdated => { | |
| render(merge({}, translationMessages, translationMessagesUpdated)); | |
| }, | |
| leftMenuSections: leftMenuSectionsUpdated => { | |
| store.dispatch( | |
| updatePlugin(pluginId, 'leftMenuSections', leftMenuSectionsUpdated), | |
| ); | |
| }, | |
| }), | |
| router: history, | |
| languages, | |
| currentLanguage: | |
| window.localStorage.getItem('strapi-admin-language') || | |
| window.navigator.language || | |
| window.navigator.userLanguage || | |
| 'en', | |
| lockApp, | |
| unlockApp, | |
| injectReducer, | |
| injectSaga, | |
| store, | |
| }); | |
| const render = messages => { | |
| ReactDOM.render( | |
| <Provider store={store}> | |
| <LanguageProvider messages={messages}> | |
| <BrowserRouter basename={basename}> | |
| <App store={store} /> | |
| </BrowserRouter> | |
| </LanguageProvider> | |
| </Provider>, | |
| MOUNT_NODE, | |
| ); | |
| }; | |
| if (module.hot) { | |
| module.hot.accept(['./i18n', './containers/App'], () => { | |
| ReactDOM.unmountComponentAtNode(MOUNT_NODE); | |
| render(translationMessages); | |
| }); | |
| } | |
| if (NODE_ENV !== 'test') { | |
| // Chunked polyfill for browsers without Intl support | |
| if (!window.Intl) { | |
| new Promise(resolve => { | |
| resolve(import('intl')); | |
| }) | |
| .then(() => | |
| Promise.all([ | |
| import('intl/locale-data/jsonp/en.js'), | |
| import('intl/locale-data/jsonp/de.js'), | |
| ]), | |
| ) // eslint-disable-line prettier/prettier | |
| .then(() => render(translationMessages)) | |
| .catch(err => { | |
| throw err; | |
| }); | |
| } else { | |
| render(translationMessages); | |
| } | |
| } | |
| // @Pierre Burgy exporting dispatch for the notifications... | |
| export { dispatch }; | |
| // TODO remove this for the new Cypress tests | |
| if (window.Cypress) { | |
| window.__store__ = Object.assign(window.__store__ || {}, { store }); | |
| } | |
| ``` | |
| // run `yarn build` and hope it's working |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment