diff --git a/examples/kitchensink/config/plugins.js b/examples/kitchensink/config/plugins.js new file mode 100644 index 0000000000..f33912876b --- /dev/null +++ b/examples/kitchensink/config/plugins.js @@ -0,0 +1,8 @@ +module.exports = { + // ... + test: { + enabled: true, + resolve: './src/plugins/test', + }, + // ... +}; diff --git a/examples/kitchensink/src/plugins/test/README.md b/examples/kitchensink/src/plugins/test/README.md new file mode 100644 index 0000000000..aa542fd459 --- /dev/null +++ b/examples/kitchensink/src/plugins/test/README.md @@ -0,0 +1,3 @@ +# Strapi plugin test + +A quick description of test. diff --git a/examples/kitchensink/src/plugins/test/admin/src/components/Initializer/index.tsx b/examples/kitchensink/src/plugins/test/admin/src/components/Initializer/index.tsx new file mode 100644 index 0000000000..09d4a346f5 --- /dev/null +++ b/examples/kitchensink/src/plugins/test/admin/src/components/Initializer/index.tsx @@ -0,0 +1,25 @@ +/** + * + * Initializer + * + */ + +import React, { useEffect, useRef } from 'react'; +import pluginId from '../../pluginId'; + +type InitializerProps = { + setPlugin: (id: string) => void; +}; + +const Initializer: React.FC = ({ setPlugin }) => { + const ref = useRef<(id: string) => void | null>(null); + ref.current = setPlugin; + + useEffect(() => { + ref.current(pluginId); + }, []); + + return null; +}; + +export default Initializer; diff --git a/examples/kitchensink/src/plugins/test/admin/src/components/PluginIcon/index.tsx b/examples/kitchensink/src/plugins/test/admin/src/components/PluginIcon/index.tsx new file mode 100644 index 0000000000..5ca6385b75 --- /dev/null +++ b/examples/kitchensink/src/plugins/test/admin/src/components/PluginIcon/index.tsx @@ -0,0 +1,12 @@ +/** + * + * PluginIcon + * + */ + +import React from 'react'; +import Puzzle from '@strapi/icons/Puzzle'; + +const PluginIcon: React.VoidFunctionComponent = () => ; + +export default PluginIcon; diff --git a/examples/kitchensink/src/plugins/test/admin/src/index.tsx b/examples/kitchensink/src/plugins/test/admin/src/index.tsx new file mode 100644 index 0000000000..0a1802e892 --- /dev/null +++ b/examples/kitchensink/src/plugins/test/admin/src/index.tsx @@ -0,0 +1,77 @@ +import React from 'react'; +import { prefixPluginTranslations } from '@strapi/helper-plugin'; +import pluginPkg from '../../package.json'; +import pluginId from './pluginId'; +import Initializer from './components/Initializer'; +import PluginIcon from './components/PluginIcon'; + +const name = pluginPkg.strapi.name; + +type InitializerProps = { + setPlugin: (id: string) => void; +}; + +type Plugin = { + id: string; + initializer?: React.FC; + isReady?: boolean; + name: string; +}; + +export default { + register(app) { + app.addMenuLink({ + to: `/plugins/${pluginId}`, + icon: PluginIcon, + intlLabel: { + id: `${pluginId}.plugin.name`, + defaultMessage: name, + }, + Component: async () => { + const component = await import(/* webpackChunkName: "[request]" */ './pages/App'); + + return component; + }, + permissions: [ + // Uncomment to set the permissions of the plugin here + // { + // action: '', // the action name should be plugin::plugin-name.actionType + // subject: null, + // }, + ], + }); + const plugin: Plugin = { + id: pluginId, + initializer: Initializer, + isReady: false, + name, + }; + + app.registerPlugin(plugin); + }, + + bootstrap(app) {}, + async registerTrads(app) { + const { locales } = app; + + const importedTrads = await Promise.all( + locales.map((locale) => { + return import(`./translations/${locale}.json`) + .then(({ default: data }) => { + return { + data: prefixPluginTranslations(data, pluginId), + locale, + }; + }) + .catch(() => { + return { + data: {}, + locale, + }; + }); + }) + ); + + return Promise.resolve(importedTrads); + }, +}; diff --git a/examples/kitchensink/src/plugins/test/admin/src/pages/App/index.tsx b/examples/kitchensink/src/plugins/test/admin/src/pages/App/index.tsx new file mode 100644 index 0000000000..36ccc83448 --- /dev/null +++ b/examples/kitchensink/src/plugins/test/admin/src/pages/App/index.tsx @@ -0,0 +1,25 @@ +/** + * + * This component is the skeleton around the actual pages, and should only + * contain code that should be seen on all pages. (e.g. navigation bar) + * + */ + +import React from 'react'; +import { Switch, Route } from 'react-router-dom'; +import { NotFound } from '@strapi/helper-plugin'; +import pluginId from '../../pluginId'; +import HomePage from '../HomePage'; + +const App: React.VoidFunctionComponent = () => { + return ( +
+ + + + +
+ ); +}; + +export default App; diff --git a/examples/kitchensink/src/plugins/test/admin/src/pages/HomePage/index.tsx b/examples/kitchensink/src/plugins/test/admin/src/pages/HomePage/index.tsx new file mode 100644 index 0000000000..471e1db776 --- /dev/null +++ b/examples/kitchensink/src/plugins/test/admin/src/pages/HomePage/index.tsx @@ -0,0 +1,19 @@ +/* + * + * HomePage + * + */ + +import React from 'react'; +import pluginId from '../../pluginId'; + +const HomePage: React.VoidFunctionComponent = () => { + return ( +
+

{pluginId}'s HomePage

+

Happy codineg

+
+ ); +}; + +export default HomePage; diff --git a/examples/kitchensink/src/plugins/test/admin/src/pluginId.ts b/examples/kitchensink/src/plugins/test/admin/src/pluginId.ts new file mode 100644 index 0000000000..791a6797b8 --- /dev/null +++ b/examples/kitchensink/src/plugins/test/admin/src/pluginId.ts @@ -0,0 +1,5 @@ +import pluginPkg from '../../package.json'; + +const pluginId = pluginPkg.name.replace(/^@strapi\/plugin-/i, ''); + +export default pluginId; diff --git a/examples/kitchensink/src/plugins/test/admin/src/translations/en.json b/examples/kitchensink/src/plugins/test/admin/src/translations/en.json new file mode 100644 index 0000000000..9e26dfeeb6 --- /dev/null +++ b/examples/kitchensink/src/plugins/test/admin/src/translations/en.json @@ -0,0 +1 @@ +{} \ No newline at end of file diff --git a/examples/kitchensink/src/plugins/test/admin/src/translations/fr.json b/examples/kitchensink/src/plugins/test/admin/src/translations/fr.json new file mode 100644 index 0000000000..9e26dfeeb6 --- /dev/null +++ b/examples/kitchensink/src/plugins/test/admin/src/translations/fr.json @@ -0,0 +1 @@ +{} \ No newline at end of file diff --git a/examples/kitchensink/src/plugins/test/admin/src/utils/axiosInstance.ts b/examples/kitchensink/src/plugins/test/admin/src/utils/axiosInstance.ts new file mode 100644 index 0000000000..3d03d75c18 --- /dev/null +++ b/examples/kitchensink/src/plugins/test/admin/src/utils/axiosInstance.ts @@ -0,0 +1,40 @@ +/** + * axios with a custom config. + */ + +import axios from 'axios'; +import { auth } from '@strapi/helper-plugin'; + +const instance = axios.create({ + baseURL: process.env.STRAPI_ADMIN_BACKEND_URL, +}); + +instance.interceptors.request.use( + async (config) => { + config.headers = { + Authorization: `Bearer ${auth.getToken()}`, + Accept: 'application/json', + 'Content-Type': 'application/json', + }; + + return config; + }, + (error) => { + Promise.reject(error); + } +); + +instance.interceptors.response.use( + (response) => response, + (error) => { + // whatever you want to do with the error + if (error.response?.status === 401) { + auth.clearAppStorage(); + window.location.reload(); + } + + throw error; + } +); + +export default instance; diff --git a/examples/kitchensink/src/plugins/test/admin/src/utils/getTrad.ts b/examples/kitchensink/src/plugins/test/admin/src/utils/getTrad.ts new file mode 100644 index 0000000000..a539a50151 --- /dev/null +++ b/examples/kitchensink/src/plugins/test/admin/src/utils/getTrad.ts @@ -0,0 +1,5 @@ +import pluginId from '../pluginId'; + +const getTrad = (id: string) => `${pluginId}.${id}`; + +export default getTrad; diff --git a/examples/kitchensink/src/plugins/test/package.json b/examples/kitchensink/src/plugins/test/package.json new file mode 100644 index 0000000000..2c571b8a8b --- /dev/null +++ b/examples/kitchensink/src/plugins/test/package.json @@ -0,0 +1,24 @@ +{ + "name": "test", + "version": "0.0.0", + "description": "This is the description of the plugin.", + "strapi": { + "name": "test", + "description": "Description of test plugin", + "kind": "plugin" + }, + "dependencies": {}, + "author": { + "name": "A Strapi developer" + }, + "maintainers": [ + { + "name": "A Strapi developer" + } + ], + "engines": { + "node": ">=12.x.x <=16.x.x", + "npm": ">=6.0.0" + }, + "license": "MIT" +} diff --git a/examples/kitchensink/src/plugins/test/server/bootstrap.js b/examples/kitchensink/src/plugins/test/server/bootstrap.js new file mode 100644 index 0000000000..2aa48af4b3 --- /dev/null +++ b/examples/kitchensink/src/plugins/test/server/bootstrap.js @@ -0,0 +1,5 @@ +'use strict'; + +module.exports = ({ strapi }) => { + // bootstrap phase +}; diff --git a/examples/kitchensink/src/plugins/test/server/config/index.js b/examples/kitchensink/src/plugins/test/server/config/index.js new file mode 100644 index 0000000000..56b5ae6a46 --- /dev/null +++ b/examples/kitchensink/src/plugins/test/server/config/index.js @@ -0,0 +1,6 @@ +'use strict'; + +module.exports = { + default: {}, + validator() {}, +}; diff --git a/examples/kitchensink/src/plugins/test/server/content-types/index.js b/examples/kitchensink/src/plugins/test/server/content-types/index.js new file mode 100644 index 0000000000..8b46fbbaad --- /dev/null +++ b/examples/kitchensink/src/plugins/test/server/content-types/index.js @@ -0,0 +1,3 @@ +'use strict'; + +module.exports = {}; diff --git a/examples/kitchensink/src/plugins/test/server/controllers/index.js b/examples/kitchensink/src/plugins/test/server/controllers/index.js new file mode 100644 index 0000000000..c8c47b5bdd --- /dev/null +++ b/examples/kitchensink/src/plugins/test/server/controllers/index.js @@ -0,0 +1,7 @@ +'use strict'; + +const myController = require('./my-controller'); + +module.exports = { + myController, +}; diff --git a/examples/kitchensink/src/plugins/test/server/controllers/my-controller.js b/examples/kitchensink/src/plugins/test/server/controllers/my-controller.js new file mode 100644 index 0000000000..363f048717 --- /dev/null +++ b/examples/kitchensink/src/plugins/test/server/controllers/my-controller.js @@ -0,0 +1,7 @@ +'use strict'; + +module.exports = { + index(ctx) { + ctx.body = strapi.plugin('test').service('myService').getWelcomeMessage(); + }, +}; diff --git a/examples/kitchensink/src/plugins/test/server/destroy.js b/examples/kitchensink/src/plugins/test/server/destroy.js new file mode 100644 index 0000000000..75f32f48c3 --- /dev/null +++ b/examples/kitchensink/src/plugins/test/server/destroy.js @@ -0,0 +1,5 @@ +'use strict'; + +module.exports = ({ strapi }) => { + // destroy phase +}; diff --git a/examples/kitchensink/src/plugins/test/server/index.js b/examples/kitchensink/src/plugins/test/server/index.js new file mode 100644 index 0000000000..5b524b1aff --- /dev/null +++ b/examples/kitchensink/src/plugins/test/server/index.js @@ -0,0 +1,25 @@ +'use strict'; + +const register = require('./register'); +const bootstrap = require('./bootstrap'); +const destroy = require('./destroy'); +const config = require('./config'); +const contentTypes = require('./content-types'); +const controllers = require('./controllers'); +const routes = require('./routes'); +const middlewares = require('./middlewares'); +const policies = require('./policies'); +const services = require('./services'); + +module.exports = { + register, + bootstrap, + destroy, + config, + controllers, + routes, + services, + contentTypes, + policies, + middlewares, +}; diff --git a/examples/kitchensink/src/plugins/test/server/middlewares/index.js b/examples/kitchensink/src/plugins/test/server/middlewares/index.js new file mode 100644 index 0000000000..8b46fbbaad --- /dev/null +++ b/examples/kitchensink/src/plugins/test/server/middlewares/index.js @@ -0,0 +1,3 @@ +'use strict'; + +module.exports = {}; diff --git a/examples/kitchensink/src/plugins/test/server/policies/index.js b/examples/kitchensink/src/plugins/test/server/policies/index.js new file mode 100644 index 0000000000..8b46fbbaad --- /dev/null +++ b/examples/kitchensink/src/plugins/test/server/policies/index.js @@ -0,0 +1,3 @@ +'use strict'; + +module.exports = {}; diff --git a/examples/kitchensink/src/plugins/test/server/register.js b/examples/kitchensink/src/plugins/test/server/register.js new file mode 100644 index 0000000000..437d48ed7b --- /dev/null +++ b/examples/kitchensink/src/plugins/test/server/register.js @@ -0,0 +1,5 @@ +'use strict'; + +module.exports = ({ strapi }) => { + // registeration phase +}; diff --git a/examples/kitchensink/src/plugins/test/server/routes/index.js b/examples/kitchensink/src/plugins/test/server/routes/index.js new file mode 100644 index 0000000000..4158ea39b1 --- /dev/null +++ b/examples/kitchensink/src/plugins/test/server/routes/index.js @@ -0,0 +1,10 @@ +module.exports = [ + { + method: 'GET', + path: '/', + handler: 'myController.index', + config: { + policies: [], + }, + }, +]; diff --git a/examples/kitchensink/src/plugins/test/server/services/index.js b/examples/kitchensink/src/plugins/test/server/services/index.js new file mode 100644 index 0000000000..8d643e9d53 --- /dev/null +++ b/examples/kitchensink/src/plugins/test/server/services/index.js @@ -0,0 +1,7 @@ +'use strict'; + +const myService = require('./my-service'); + +module.exports = { + myService, +}; diff --git a/examples/kitchensink/src/plugins/test/server/services/my-service.js b/examples/kitchensink/src/plugins/test/server/services/my-service.js new file mode 100644 index 0000000000..f565002462 --- /dev/null +++ b/examples/kitchensink/src/plugins/test/server/services/my-service.js @@ -0,0 +1,7 @@ +'use strict'; + +module.exports = ({ strapi }) => ({ + getWelcomeMessage() { + return 'Welcome to Strapi 🚀'; + }, +}); diff --git a/examples/kitchensink/src/plugins/test/strapi-admin.js b/examples/kitchensink/src/plugins/test/strapi-admin.js new file mode 100644 index 0000000000..2d1a3d93ac --- /dev/null +++ b/examples/kitchensink/src/plugins/test/strapi-admin.js @@ -0,0 +1,3 @@ +'use strict'; + +module.exports = require('./admin/src').default; diff --git a/examples/kitchensink/src/plugins/test/strapi-server.js b/examples/kitchensink/src/plugins/test/strapi-server.js new file mode 100644 index 0000000000..8a908be91d --- /dev/null +++ b/examples/kitchensink/src/plugins/test/strapi-server.js @@ -0,0 +1,3 @@ +'use strict'; + +module.exports = require('./server'); diff --git a/examples/kitchensink/tsconfig.admin.json b/examples/kitchensink/tsconfig.admin.json new file mode 100644 index 0000000000..037bb49073 --- /dev/null +++ b/examples/kitchensink/tsconfig.admin.json @@ -0,0 +1,18 @@ +{ + "compilerOptions": { + "noImplicitAny": false, + "module": "es2020", + "target": "es5", + "jsx": "react", + "allowJs": true, + "moduleResolution": "node", + "skipLibCheck": true, + "esModuleInterop": true, + "allowSyntheticDefaultImports": true, + "resolveJsonModule": true, + "noEmit": false, + "incremental": true + }, + + "exclude": ["node_modules", "**/*.test.js", "*.js"] +} diff --git a/packages/core/admin/webpack.config.js b/packages/core/admin/webpack.config.js index 86597fa294..6801f2ab69 100644 --- a/packages/core/admin/webpack.config.js +++ b/packages/core/admin/webpack.config.js @@ -52,7 +52,8 @@ module.exports = ({ if (useTypeScript) { const tsChecker = new ForkTsCheckerPlugin({ typescript: { - configFile: path.join(cacheDir, 'admin', 'src', 'tsconfig.json'), + // FIXME + configFile: path.join(cacheDir, '..', 'tsconfig.admin.json'), }, }); diff --git a/packages/core/strapi/lib/commands/develop.js b/packages/core/strapi/lib/commands/develop.js index 6708528480..9d81d73df0 100644 --- a/packages/core/strapi/lib/commands/develop.js +++ b/packages/core/strapi/lib/commands/develop.js @@ -16,7 +16,7 @@ const buildAdmin = require('./build'); * `$ strapi develop` * */ -module.exports = async function({ build, watchAdmin, polling, browser }) { +module.exports = async function ({ build, watchAdmin, polling, browser }) { const dir = process.cwd(); const config = loadConfiguration(dir); const logger = createLogger(config.logger, {}); @@ -79,7 +79,7 @@ module.exports = async function({ build, watchAdmin, polling, browser }) { polling, }); - process.on('message', async message => { + process.on('message', async (message) => { switch (message) { case 'kill': await strapiInstance.destroy(); @@ -138,15 +138,15 @@ function watchFileChanges({ dir, strapiInstance, watchIgnoreFiles, polling }) { }); watcher - .on('add', path => { + .on('add', (path) => { strapiInstance.log.info(`File created: ${path}`); restart(); }) - .on('change', path => { + .on('change', (path) => { strapiInstance.log.info(`File changed: ${path}`); restart(); }) - .on('unlink', path => { + .on('unlink', (path) => { strapiInstance.log.info(`File deleted: ${path}`); restart(); }); diff --git a/packages/generators/generators/lib/files/plugin/admin/src/pages/HomePage/index.js b/packages/generators/generators/lib/files/plugin/admin/src/pages/HomePage/index.js index 05c5a6a377..d8077665b8 100644 --- a/packages/generators/generators/lib/files/plugin/admin/src/pages/HomePage/index.js +++ b/packages/generators/generators/lib/files/plugin/admin/src/pages/HomePage/index.js @@ -4,7 +4,7 @@ * */ -import React, { memo } from 'react'; +import React from 'react'; // import PropTypes from 'prop-types'; import pluginId from '../../pluginId'; @@ -17,4 +17,4 @@ const HomePage = () => { ); }; -export default memo(HomePage); +export default HomePage; diff --git a/packages/generators/generators/lib/files/plugin/admin/src/pluginId.js b/packages/generators/generators/lib/files/plugin/admin/src/pluginId.js index f604a009da..791a6797b8 100644 --- a/packages/generators/generators/lib/files/plugin/admin/src/pluginId.js +++ b/packages/generators/generators/lib/files/plugin/admin/src/pluginId.js @@ -1,5 +1,5 @@ -const pluginPkg = require('../../package.json'); +import pluginPkg from '../../package.json'; const pluginId = pluginPkg.name.replace(/^@strapi\/plugin-/i, ''); -module.exports = pluginId; +export default pluginId;