diff --git a/packages/core/admin/admin/src/StrapiApp.js b/packages/core/admin/admin/src/StrapiApp.js
index 274544ad40..85d0535b5f 100644
--- a/packages/core/admin/admin/src/StrapiApp.js
+++ b/packages/core/admin/admin/src/StrapiApp.js
@@ -5,7 +5,7 @@ import { QueryClientProvider, QueryClient } from 'react-query';
import { ThemeProvider } from 'styled-components';
import { StrapiProvider } from '@strapi/helper-plugin';
import configureStore from './core/store/configureStore';
-import { Middlewares, Plugin } from './core/apis';
+import { Plugin } from './core/apis';
import basename from './utils/basename';
import App from './pages/App';
import LanguageProvider from './components/LanguageProvider';
@@ -19,7 +19,7 @@ import themes from './themes';
import reducers from './reducers';
// TODO
-import translationMessages from './translations';
+import translations from './translations';
window.strapi = {
backendURL: process.env.STRAPI_ADMIN_BACKEND_URL,
@@ -33,14 +33,22 @@ const queryClient = new QueryClient({
},
});
+// FIXME
+const appLocales = Object.keys(translations);
+
class StrapiApp {
constructor({ appPlugins }) {
+ this.translationMessages = translations;
this.appPlugins = appPlugins || {};
- this.middlewares = Middlewares();
+ this.middlewares = [];
this.plugins = {};
this.reducers = { ...reducers };
}
+ addMiddleware(middleware) {
+ this.middlewares.push(middleware);
+ }
+
addReducers(reducers) {
Object.keys(reducers).forEach(reducerName => {
this.reducers[reducerName] = reducers[reducerName];
@@ -51,22 +59,60 @@ class StrapiApp {
Object.keys(this.appPlugins).forEach(plugin => {
this.appPlugins[plugin].register(this);
});
-
- return this;
}
async boot() {
- console.log('booting');
+ Object.keys(this.appPlugins).forEach(plugin => {
+ const boot = this.appPlugins[plugin].boot;
- return this;
+ if (boot) {
+ boot(this);
+ }
+ });
}
getPlugin(pluginId) {
return this.plugins[pluginId] || null;
}
+ // FIXME
+ registerPluginTranslations(pluginId, trads) {
+ const pluginTranslations = appLocales.reduce((acc, currentLanguage) => {
+ const currentLocale = trads[currentLanguage];
+
+ if (currentLocale) {
+ const localeprefixedWithPluginId = Object.keys(currentLocale).reduce((acc2, current) => {
+ acc2[`${pluginId}.${current}`] = currentLocale[current];
+
+ return acc2;
+ }, {});
+
+ acc[currentLanguage] = localeprefixedWithPluginId;
+ }
+
+ return acc;
+ }, {});
+
+ this.translationMessages = Object.keys(this.translationMessages).reduce((acc, current) => {
+ acc[current] = {
+ ...this.translationMessages[current],
+ ...(pluginTranslations[current] || {}),
+ };
+
+ return acc;
+ }, {});
+ }
+
registerPlugin(pluginConf) {
- this.plugins[pluginConf.id] = Plugin(pluginConf);
+ const plugin = Plugin(pluginConf);
+
+ this.plugins[plugin.pluginId] = plugin;
+
+ // FIXME
+ // Translations should be loaded differently
+ // This is a temporary fix
+
+ this.registerPluginTranslations(plugin.pluginId, plugin.trads);
}
render() {
@@ -79,7 +125,7 @@ class StrapiApp {
-
+
<>
diff --git a/packages/core/admin/admin/src/components/PluginsInitializer/index.js b/packages/core/admin/admin/src/components/PluginsInitializer/index.js
new file mode 100644
index 0000000000..ceb9af2260
--- /dev/null
+++ b/packages/core/admin/admin/src/components/PluginsInitializer/index.js
@@ -0,0 +1,41 @@
+import React, { useReducer, useRef } from 'react';
+import { LoadingIndicatorPage, useStrapi } from '@strapi/helper-plugin';
+import Admin from '../../pages/Admin';
+import init from './init';
+import reducer, { initialState } from './reducer';
+
+const PluginsInitializer = () => {
+ // TODO rename strapi to avoid mismatch with the window.strapi
+ const { strapi: app } = useStrapi();
+ const [{ plugins }, dispatch] = useReducer(reducer, initialState, () => init(app.plugins));
+ const setPlugin = useRef(pluginId => {
+ dispatch({ type: 'SET_PLUGIN_READY', pluginId });
+ });
+
+ const hasApluginNotReady = Object.keys(plugins).some(plugin => plugins[plugin].isReady === false);
+
+ if (hasApluginNotReady) {
+ const initializers = Object.keys(plugins).reduce((acc, current) => {
+ const InitializerComponent = plugins[current].initializer;
+
+ if (InitializerComponent) {
+ const key = plugins[current].pluginId;
+
+ acc.push();
+ }
+
+ return acc;
+ }, []);
+
+ return (
+ <>
+ {initializers}
+
+ >
+ );
+ }
+
+ return ;
+};
+
+export default PluginsInitializer;
diff --git a/packages/core/admin/admin/src/components/PluginsInitializer/init.js b/packages/core/admin/admin/src/components/PluginsInitializer/init.js
new file mode 100644
index 0000000000..50429ad16f
--- /dev/null
+++ b/packages/core/admin/admin/src/components/PluginsInitializer/init.js
@@ -0,0 +1,11 @@
+const init = plugins => {
+ return {
+ plugins: Object.keys(plugins).reduce((acc, current) => {
+ acc[current] = { ...plugins[current] };
+
+ return acc;
+ }, {}),
+ };
+};
+
+export default init;
diff --git a/packages/core/admin/admin/src/components/PluginsInitializer/reducer.js b/packages/core/admin/admin/src/components/PluginsInitializer/reducer.js
new file mode 100644
index 0000000000..d21382e503
--- /dev/null
+++ b/packages/core/admin/admin/src/components/PluginsInitializer/reducer.js
@@ -0,0 +1,22 @@
+import produce from 'immer';
+import set from 'lodash/set';
+
+const initialState = {
+ plugins: null,
+};
+
+const reducer = (state = initialState, action) =>
+ /* eslint-disable-next-line consistent-return */
+ produce(state, draftState => {
+ switch (action.type) {
+ case 'SET_PLUGIN_READY': {
+ set(draftState, ['plugins', action.pluginId, 'isReady'], true);
+ break;
+ }
+ default:
+ return draftState;
+ }
+ });
+
+export { initialState };
+export default reducer;
diff --git a/packages/core/admin/admin/src/components/PluginsInitializer/tests/index.test.js b/packages/core/admin/admin/src/components/PluginsInitializer/tests/index.test.js
new file mode 100644
index 0000000000..bde576f1ee
--- /dev/null
+++ b/packages/core/admin/admin/src/components/PluginsInitializer/tests/index.test.js
@@ -0,0 +1,18 @@
+import React from 'react';
+import { StrapiProvider } from '@strapi/helper-plugin';
+import { render } from '@testing-library/react';
+import PluginsInitializer from '../index';
+
+jest.mock('../../../pages/Admin', () => () => ADMIN
);
+
+describe('ADMIN | COMPONENTS | PluginsInitializer', () => {
+ it('should not crash', () => {
+ expect(
+ render(
+
+
+
+ )
+ );
+ });
+});
diff --git a/packages/core/admin/admin/src/components/PluginsInitializer/tests/init.test.js b/packages/core/admin/admin/src/components/PluginsInitializer/tests/init.test.js
new file mode 100644
index 0000000000..89ba385879
--- /dev/null
+++ b/packages/core/admin/admin/src/components/PluginsInitializer/tests/init.test.js
@@ -0,0 +1,16 @@
+import init from '../init';
+
+describe('ADMIN | COMPONENT | PluginsInitializer | init', () => {
+ it('should return the initialState', () => {
+ const plugins = {
+ pluginA: {
+ isReady: false,
+ },
+ pluginB: {
+ isReady: false,
+ },
+ };
+
+ expect(init(plugins)).toEqual({ plugins });
+ });
+});
diff --git a/packages/core/admin/admin/src/components/PluginsInitializer/tests/reducer.test.js b/packages/core/admin/admin/src/components/PluginsInitializer/tests/reducer.test.js
new file mode 100644
index 0000000000..808ebce395
--- /dev/null
+++ b/packages/core/admin/admin/src/components/PluginsInitializer/tests/reducer.test.js
@@ -0,0 +1,40 @@
+import reducer, { initialState } from '../reducer';
+
+describe('ADMIN | COMPONENTS | PluginsInitializer | reducer', () => {
+ let state;
+
+ beforeEach(() => {
+ state = initialState;
+ });
+
+ describe('DEFAULT_ACTION', () => {
+ it('should return the initialState', () => {
+ expect(reducer(state, {})).toEqual(initialState);
+ });
+ });
+
+ describe('SET_PLUGIN_READY', () => {
+ it('should set the isReady property to true for a plugin', () => {
+ state = {
+ plugins: {
+ pluginA: {
+ isReady: false,
+ },
+ },
+ };
+
+ const expected = {
+ plugins: {
+ pluginA: { isReady: true },
+ },
+ };
+
+ const action = {
+ type: 'SET_PLUGIN_READY',
+ pluginId: 'pluginA',
+ };
+
+ expect(reducer(state, action)).toEqual(expected);
+ });
+ });
+});
diff --git a/packages/core/admin/admin/src/core/apis/Middlewares.js b/packages/core/admin/admin/src/core/apis/Middlewares.js
deleted file mode 100644
index ff3d4e332a..0000000000
--- a/packages/core/admin/admin/src/core/apis/Middlewares.js
+++ /dev/null
@@ -1,15 +0,0 @@
-import cloneDeep from 'lodash/cloneDeep';
-
-class Middlewares {
- middlewares = [];
-
- add(middleware) {
- this.middlewares.push(middleware);
- }
-
- get middlewares() {
- return cloneDeep(this.middlewares);
- }
-}
-
-export default () => new Middlewares();
diff --git a/packages/core/admin/admin/src/core/apis/Plugin.js b/packages/core/admin/admin/src/core/apis/Plugin.js
index 954b7b3f3a..c7aee59f2d 100644
--- a/packages/core/admin/admin/src/core/apis/Plugin.js
+++ b/packages/core/admin/admin/src/core/apis/Plugin.js
@@ -5,8 +5,9 @@ class Plugin {
this.description = pluginConf.description;
// TODO
this.icon = pluginConf.icon;
+ this.initializer = pluginConf.initializer || null;
this.injectionZones = pluginConf.injectionZones || {};
- this.isReady = pluginConf.isReady || true;
+ this.isReady = pluginConf.isReady !== undefined ? pluginConf.isReady : true;
// TODO
this.isRequired = pluginConf.isRequired;
// TODO
diff --git a/packages/core/admin/admin/src/core/apis/index.js b/packages/core/admin/admin/src/core/apis/index.js
index db21b53c4d..77c8702e6d 100644
--- a/packages/core/admin/admin/src/core/apis/index.js
+++ b/packages/core/admin/admin/src/core/apis/index.js
@@ -1,2 +1,2 @@
-export { default as Middlewares } from './Middlewares';
+// eslint-disable-next-line import/prefer-default-export
export { default as Plugin } from './Plugin';
diff --git a/packages/core/admin/admin/src/core/store/configureStore.js b/packages/core/admin/admin/src/core/store/configureStore.js
index c283d389ef..5d2ecdbbc2 100644
--- a/packages/core/admin/admin/src/core/store/configureStore.js
+++ b/packages/core/admin/admin/src/core/store/configureStore.js
@@ -2,9 +2,12 @@ import { createStore, applyMiddleware } from 'redux';
import createReducer from './createReducer';
const configureStore = app => {
- // TODO
const middlewares = [];
+ middlewares.forEach(middleware => {
+ middlewares.push(middleware());
+ });
+
return createStore(createReducer(app.reducers), {}, applyMiddleware(...middlewares));
};
diff --git a/packages/core/admin/admin/src/index.js b/packages/core/admin/admin/src/index.js
index 838dae0364..e5eb0ddf93 100644
--- a/packages/core/admin/admin/src/index.js
+++ b/packages/core/admin/admin/src/index.js
@@ -2,8 +2,6 @@ import ReactDOM from 'react-dom';
import StrapiApp from './StrapiApp';
import plugins from './plugins';
-console.log({ plugins });
-
const app = StrapiApp({ appPlugins: plugins });
const MOUNT_NODE = document.getElementById('app');
diff --git a/packages/core/admin/admin/src/pages/Admin/index.js b/packages/core/admin/admin/src/pages/Admin/index.js
index 942a2de7bf..c1bbb6061a 100644
--- a/packages/core/admin/admin/src/pages/Admin/index.js
+++ b/packages/core/admin/admin/src/pages/Admin/index.js
@@ -17,7 +17,6 @@ import { isEmpty } from 'lodash';
import {
difference,
GlobalContextProvider,
- LoadingIndicatorPage,
CheckPagePermissions,
request,
} from '@strapi/helper-plugin';
@@ -149,45 +148,11 @@ export class Admin extends React.Component {
}
};
- hasApluginNotReady = props => {
- const {
- global: { plugins },
- } = props;
-
- return !Object.keys(plugins).every(plugin => plugins[plugin].isReady === true);
- };
-
initApp = async () => {
await this.fetchAppInfo();
await this.fetchStrapiLatestRelease();
};
- /**
- * Display the app loader until the app is ready
- * @returns {Boolean}
- */
- showLoader = () => {
- return this.hasApluginNotReady(this.props);
- };
-
- renderInitializers = () => {
- const {
- global: { plugins },
- } = this.props;
-
- return Object.keys(plugins).reduce((acc, current) => {
- const InitializerComponent = plugins[current].initializer;
-
- if (InitializerComponent) {
- const key = plugins[current].id;
-
- acc.push();
- }
-
- return acc;
- }, []);
- };
-
renderPluginDispatcher = props => {
// NOTE: Send the needed props instead of everything...
@@ -203,22 +168,14 @@ export class Admin extends React.Component {
render() {
const {
admin: { shouldUpdateStrapi },
- global: { autoReload, currentEnvironment, plugins, strapiVersion },
+ global: { autoReload, currentEnvironment, strapiVersion },
// FIXME
intl: { formatMessage, locale },
+ // FIXME
+ plugins,
updatePlugin,
} = this.props;
- // We need the admin data in order to make the initializers work
- if (this.showLoader()) {
- return (
- <>
- {this.renderInitializers()}
-
- >
- );
- }
-
return (
', () => {
getUserPermissions: jest.fn(),
getUserPermissionsError: jest.fn(),
getUserPermissionsSucceeded: jest.fn(),
+ plugins: {},
global: {
autoReload: false,
currentEnvironment: 'development',
hasAdminUser: false,
isLoading: true,
- plugins: {},
strapiVersion: '3',
uuid: false,
},
diff --git a/packages/core/admin/admin/src/pages/App/index.js b/packages/core/admin/admin/src/pages/App/index.js
index 57f0a0f3c3..bf5dc95891 100644
--- a/packages/core/admin/admin/src/pages/App/index.js
+++ b/packages/core/admin/admin/src/pages/App/index.js
@@ -10,8 +10,8 @@ import { Switch, Route } from 'react-router-dom';
import { connect } from 'react-redux';
import { bindActionCreators, compose } from 'redux';
import { LoadingIndicatorPage, auth, request } from '@strapi/helper-plugin';
+import PluginsInitializer from '../../components/PluginsInitializer';
import PrivateRoute from '../../components/PrivateRoute';
-import Admin from '../Admin';
import AuthPage from '../AuthPage';
import NotFoundPage from '../NotFoundPage';
import { getUID } from './utils';
@@ -117,7 +117,7 @@ function App(props) {
)}
exact
/>
-
+
diff --git a/packages/core/admin/admin/src/pages/PluginDispatcher/index.js b/packages/core/admin/admin/src/pages/PluginDispatcher/index.js
index 59cbe6f255..7357ad38c4 100644
--- a/packages/core/admin/admin/src/pages/PluginDispatcher/index.js
+++ b/packages/core/admin/admin/src/pages/PluginDispatcher/index.js
@@ -14,7 +14,7 @@ import PageTitle from '../../components/PageTitle';
export function PluginDispatcher(props) {
const {
- global: { plugins },
+ plugins,
match: {
params: { pluginId },
},
@@ -53,12 +53,12 @@ export function PluginDispatcher(props) {
PluginDispatcher.defaultProps = {};
PluginDispatcher.propTypes = {
- global: PropTypes.object.isRequired,
match: PropTypes.shape({
params: PropTypes.shape({
pluginId: PropTypes.string,
}),
}).isRequired,
+ plugins: PropTypes.object.isRequired,
};
export default memo(PluginDispatcher);
diff --git a/packages/core/admin/admin/src/pages/PluginDispatcher/tests/index.test.js b/packages/core/admin/admin/src/pages/PluginDispatcher/tests/index.test.js
index bac1d139a2..e5f2f6824e 100644
--- a/packages/core/admin/admin/src/pages/PluginDispatcher/tests/index.test.js
+++ b/packages/core/admin/admin/src/pages/PluginDispatcher/tests/index.test.js
@@ -9,7 +9,7 @@ const Email = () => Email Plugin
;
describe('', () => {
it('Should return null if the params does not match the pluginId', () => {
const props = {
- global: { plugins: {} },
+ plugins: {},
match: { params: { pluginId: 'email' } },
};
@@ -20,13 +20,11 @@ describe('', () => {
it('Should return the BlockerComponent if the plugin preventRendering prop is true', () => {
const props = {
- global: {
- plugins: {
- email: {
- mainComponent: Email,
- preventComponentRendering: true,
- blockerComponent: null,
- },
+ plugins: {
+ email: {
+ mainComponent: Email,
+ preventComponentRendering: true,
+ blockerComponent: null,
},
},
match: { params: { pluginId: 'email' } },
@@ -39,13 +37,11 @@ describe('', () => {
it('Should return a custom BlockerComponent if the plugin preventRendering prop is true and a custom blocker is given', () => {
const props = {
- global: {
- plugins: {
- email: {
- mainComponent: Email,
- preventComponentRendering: true,
- blockerComponent: BlockerComponent2,
- },
+ plugins: {
+ email: {
+ mainComponent: Email,
+ preventComponentRendering: true,
+ blockerComponent: BlockerComponent2,
},
},
match: { params: { pluginId: 'email' } },
@@ -58,11 +54,9 @@ describe('', () => {
it("Should return the plugin's mainComponent if all conditions are met", () => {
const props = {
- global: {
- plugins: {
- email: {
- mainComponent: Email,
- },
+ plugins: {
+ email: {
+ mainComponent: Email,
},
},
match: { params: { pluginId: 'email' } },
diff --git a/packages/core/admin/admin/src/reducers.js b/packages/core/admin/admin/src/reducers.js
index 1e3c075a9e..29c1b57b63 100644
--- a/packages/core/admin/admin/src/reducers.js
+++ b/packages/core/admin/admin/src/reducers.js
@@ -1,15 +1,15 @@
import globalReducer from './pages/App/reducer';
import adminReducer from './pages/Admin/reducer';
import languageProviderReducer from './components/LanguageProvider/reducer';
-import permissionsManagerReducer from './components/PermissionsManager/reducer';
import menuReducer from './components/LeftMenu/reducer';
+import permissionsManagerReducer from './components/PermissionsManager/reducer';
const reducers = {
- app: globalReducer,
admin: adminReducer,
+ app: globalReducer,
language: languageProviderReducer,
- permissionsManager: permissionsManagerReducer,
menu: menuReducer,
+ permissionsManager: permissionsManagerReducer,
};
export default reducers;
diff --git a/packages/plugins/documentation/admin/src/index.js b/packages/plugins/documentation/admin/src/index.js
index d755e12c53..56c2949e8b 100644
--- a/packages/plugins/documentation/admin/src/index.js
+++ b/packages/plugins/documentation/admin/src/index.js
@@ -4,7 +4,6 @@
// Here's the file: strapi/docs/3.0.0-beta.x/guides/registering-a-field-in-admin.md
// Also the strapi-generate-plugins/files/admin/src/index.js needs to be updated
// IF THE DOC IS NOT UPDATED THE PULL REQUEST WILL NOT BE MERGED
-
import pluginPkg from '../../package.json';
import pluginPermissions from './permissions';
import pluginId from './pluginId';
@@ -12,43 +11,6 @@ import pluginLogo from './assets/images/logo.svg';
import App from './containers/App';
import trads from './translations';
-// export default strapi => {
-// const pluginDescription = pluginPkg.strapi.description || pluginPkg.description;
-// const icon = pluginPkg.strapi.icon;
-// const name = pluginPkg.strapi.name;
-// const plugin = {
-// blockerComponent: null,
-// blockerComponentProps: {},
-// description: pluginDescription,
-// icon,
-// id: pluginId,
-// injectedComponents: [],
-// isReady: true,
-// isRequired: pluginPkg.strapi.required || false,
-// mainComponent: App,
-// name,
-// pluginLogo,
-// preventComponentRendering: false,
-// trads,
-// menu: {
-// pluginsSectionLinks: [
-// {
-// destination: `/plugins/${pluginId}`,
-// icon,
-// label: {
-// id: `${pluginId}.plugin.name`,
-// defaultMessage: 'Documentation',
-// },
-// name,
-// permissions: pluginPermissions.main,
-// },
-// ],
-// },
-// };
-
-// return strapi.registerPlugin(plugin);
-// };
-
const pluginDescription = pluginPkg.strapi.description || pluginPkg.description;
const icon = pluginPkg.strapi.icon;
const name = pluginPkg.strapi.name;