From 1288db6315371fb5091e0c04c0c9c0e6ebfe8fc1 Mon Sep 17 00:00:00 2001 From: soupette Date: Tue, 22 Jun 2021 09:15:52 +0200 Subject: [PATCH] Remove addColumnToLv middleware in i18n Signed-off-by: soupette --- packages/core/admin/admin/src/StrapiApp.js | 48 ++++++------- .../core/content-manager/admin/src/index.js | 6 +- .../admin/src/pages/ListView/index.js | 11 ++- .../LocaleListCell/LocaleListCell.js | 12 ++-- .../tests/LocaleListCell.test.js | 10 +++ .../contentManagerHooks/addColumnToTable.js | 24 +++++++ .../tests/addColumnToTable.test.js | 36 ++++++++++ packages/plugins/i18n/admin/src/index.js | 2 + .../addLocaleColumnToListViewMiddleware.js | 32 --------- .../i18n/admin/src/middlewares/index.js | 2 - ...ddLocaleColumnToListViewMiddleware.test.js | 67 ------------------- 11 files changed, 116 insertions(+), 134 deletions(-) create mode 100644 packages/plugins/i18n/admin/src/contentManagerHooks/addColumnToTable.js create mode 100644 packages/plugins/i18n/admin/src/contentManagerHooks/tests/addColumnToTable.test.js delete mode 100644 packages/plugins/i18n/admin/src/middlewares/addLocaleColumnToListViewMiddleware.js delete mode 100644 packages/plugins/i18n/admin/src/middlewares/tests/addLocaleColumnToListViewMiddleware.test.js diff --git a/packages/core/admin/admin/src/StrapiApp.js b/packages/core/admin/admin/src/StrapiApp.js index a7177d0a14..59def16361 100644 --- a/packages/core/admin/admin/src/StrapiApp.js +++ b/packages/core/admin/admin/src/StrapiApp.js @@ -153,21 +153,6 @@ class StrapiApp { }); }; - async initialize() { - Object.keys(this.appPlugins).forEach(plugin => { - this.appPlugins[plugin].register({ - addComponents: this.addComponents, - addCorePluginMenuLink: this.addCorePluginMenuLink, - addFields: this.addFields, - addMenuLink: this.addMenuLink, - addMiddlewares: this.addMiddlewares, - addReducers: this.addReducers, - createSettingSection: this.createSettingSection, - registerPlugin: this.registerPlugin, - }); - }); - } - async boot() { Object.keys(this.appPlugins).forEach(plugin => { const boot = this.appPlugins[plugin].boot; @@ -177,11 +162,16 @@ class StrapiApp { addSettingsLink: this.addSettingsLink, addSettingsLinks: this.addSettingsLinks, getPlugin: this.getPlugin, + registerHook: this.registerHook, }); } }); } + createHook = name => { + this.hooksDict[name] = createHook(); + }; + createSettingSection = (section, links) => { invariant(section.id, 'section.id should be defined'); invariant( @@ -209,6 +199,22 @@ class StrapiApp { return this.plugins[pluginId]; }; + async initialize() { + Object.keys(this.appPlugins).forEach(plugin => { + this.appPlugins[plugin].register({ + addComponents: this.addComponents, + addCorePluginMenuLink: this.addCorePluginMenuLink, + addFields: this.addFields, + addMenuLink: this.addMenuLink, + addMiddlewares: this.addMiddlewares, + addReducers: this.addReducers, + createHook: this.createHook, + createSettingSection: this.createSettingSection, + registerPlugin: this.registerPlugin, + }); + }); + } + async loadAdminTrads() { const arrayOfPromises = this.appLocales.map(locale => { return import(/* webpackChunkName: "[request]" */ `./translations/${locale}.json`) @@ -270,20 +276,16 @@ class StrapiApp { return Promise.resolve(); } + registerHook = (name, fn) => { + this.hooksDict[name].register(fn); + }; + registerPlugin = pluginConf => { const plugin = Plugin(pluginConf); this.plugins[plugin.pluginId] = plugin; }; - createHook = name => { - this.hooksDict[name] = createHook(); - }; - - registerHook = (name, fn) => { - this.hooksDict[name].register(fn); - }; - runHookSeries = (name, asynchronous = false) => asynchronous ? this.hooksDict[name].runSeriesAsync() : this.hooksDict[name].runSeries(); diff --git a/packages/core/content-manager/admin/src/index.js b/packages/core/content-manager/admin/src/index.js index e56705bd19..51be4181ff 100644 --- a/packages/core/content-manager/admin/src/index.js +++ b/packages/core/content-manager/admin/src/index.js @@ -17,7 +17,6 @@ const name = pluginPkg.strapi.name; export default { register(app) { - app.addReducers(reducers); app.addCorePluginMenuLink({ to: `/plugins/${pluginId}`, icon: 'book-open', @@ -28,6 +27,11 @@ export default { permissions: pluginPermissions.main, }); + app.addReducers(reducers); + + // Hook that allows to mutate the displayed headers of the list view table + app.createHook('cm/inject-column-in-table'); + app.registerPlugin({ description: pluginDescription, icon, diff --git a/packages/core/content-manager/admin/src/pages/ListView/index.js b/packages/core/content-manager/admin/src/pages/ListView/index.js index 3d7e128de2..8943475365 100644 --- a/packages/core/content-manager/admin/src/pages/ListView/index.js +++ b/packages/core/content-manager/admin/src/pages/ListView/index.js @@ -18,6 +18,7 @@ import { useNotification, useQueryParams, useRBACProvider, + useStrapiApp, request, } from '@strapi/helper-plugin'; import pluginId from '../../pluginId'; @@ -93,6 +94,14 @@ function ListView({ const trackUsageRef = useRef(trackUsage); const fetchPermissionsRef = useRef(refetchPermissions); + const { runHookWaterfall } = useStrapiApp(); + + const tableHeaders = useMemo(() => { + const headers = runHookWaterfall('cm/inject-column-in-table', { displayedHeaders, layout }); + + return headers; + }, [runHookWaterfall, displayedHeaders, layout]); + const [{ query }, setQuery] = useQueryParams(); const params = buildQueryString(query); @@ -466,7 +475,7 @@ function ListView({ canCreate={canCreate} canDelete={canDelete} canUpdate={canUpdate} - displayedHeaders={displayedHeaders} + displayedHeaders={tableHeaders} hasDraftAndPublish={hasDraftAndPublish} isBulkable={isBulkable} setQuery={setQuery} diff --git a/packages/plugins/i18n/admin/src/components/LocaleListCell/LocaleListCell.js b/packages/plugins/i18n/admin/src/components/LocaleListCell/LocaleListCell.js index 2414cb90c6..3f9871ccb1 100644 --- a/packages/plugins/i18n/admin/src/components/LocaleListCell/LocaleListCell.js +++ b/packages/plugins/i18n/admin/src/components/LocaleListCell/LocaleListCell.js @@ -1,9 +1,11 @@ import React from 'react'; import PropTypes from 'prop-types'; +import { useSelector } from 'react-redux'; import { Padded, Text } from '@buffetjs/core'; import { Tooltip } from '@buffetjs/styles'; import get from 'lodash/get'; import styled from 'styled-components'; +import selectI18NLocales from '../../selectors/selectI18nLocales'; const mapToLocaleName = (locales, localeCode) => get( @@ -18,7 +20,8 @@ const LocaleName = styled.div` white-space: nowrap; `; -const LocaleListCell = ({ locales, localizations, locale: currentLocaleCode, id }) => { +const LocaleListCell = ({ localizations, locale: currentLocaleCode, id }) => { + const locales = useSelector(selectI18NLocales); const allLocalizations = [{ locale: currentLocaleCode }, ...localizations]; const localizationNames = allLocalizations.map(locale => locale.locale); const defaultLocale = locales.find(locale => locale.isDefault); @@ -77,13 +80,6 @@ LocaleListCell.propTypes = { locale: PropTypes.string.isRequired, }) ).isRequired, - locales: PropTypes.arrayOf( - PropTypes.shape({ - name: PropTypes.string.isRequired, - code: PropTypes.string.isRequired, - isDefault: PropTypes.bool, - }) - ).isRequired, locale: PropTypes.string.isRequired, }; diff --git a/packages/plugins/i18n/admin/src/components/LocaleListCell/tests/LocaleListCell.test.js b/packages/plugins/i18n/admin/src/components/LocaleListCell/tests/LocaleListCell.test.js index 0717eb46fb..29d7b00dbb 100644 --- a/packages/plugins/i18n/admin/src/components/LocaleListCell/tests/LocaleListCell.test.js +++ b/packages/plugins/i18n/admin/src/components/LocaleListCell/tests/LocaleListCell.test.js @@ -1,5 +1,6 @@ import React from 'react'; import { render, screen } from '@testing-library/react'; +import { useSelector } from 'react-redux'; import LocaleListCell from '../LocaleListCell'; jest.mock('@buffetjs/styles', () => ({ @@ -11,6 +12,10 @@ jest.mock('@buffetjs/core', () => ({ Text: props =>

, })); +jest.mock('react-redux', () => ({ + useSelector: jest.fn(() => []), +})); + describe('LocaleListCell', () => { it('returns the default locale first, then the others sorted alphabetically', () => { const locales = [ @@ -40,6 +45,8 @@ describe('LocaleListCell', () => { }, ]; + useSelector.mockImplementation(() => locales); + const locale = 'en'; const localizations = [{ locale: 'fr-FR' }, { locale: 'ar' }]; @@ -78,6 +85,8 @@ describe('LocaleListCell', () => { }, ]; + useSelector.mockImplementation(() => locales); + const locale = 'en'; const localizations = [{ locale: 'ar' }]; @@ -115,6 +124,7 @@ describe('LocaleListCell', () => { isDefault: false, }, ]; + useSelector.mockImplementation(() => locales); const locale = 'fr-FR'; const localizations = [{ locale: 'en' }, { locale: 'ar' }]; diff --git a/packages/plugins/i18n/admin/src/contentManagerHooks/addColumnToTable.js b/packages/plugins/i18n/admin/src/contentManagerHooks/addColumnToTable.js new file mode 100644 index 0000000000..0a38339a62 --- /dev/null +++ b/packages/plugins/i18n/admin/src/contentManagerHooks/addColumnToTable.js @@ -0,0 +1,24 @@ +import React from 'react'; +import get from 'lodash/get'; +import LocaleListCell from '../components/LocaleListCell/LocaleListCell'; + +const addColumnToTableHook = ({ displayedHeaders, layout }) => { + const isFieldLocalized = get(layout, 'contentType.pluginOptions.i18n.localized', false); + + if (!isFieldLocalized) { + return displayedHeaders; + } + + return [ + ...displayedHeaders, + { + key: '__locale_key__', + fieldSchema: { type: 'string' }, + metadatas: { label: 'Content available in', searchable: false, sortable: false }, + name: 'locales', + cellFormatter: props => , + }, + ]; +}; + +export default addColumnToTableHook; diff --git a/packages/plugins/i18n/admin/src/contentManagerHooks/tests/addColumnToTable.test.js b/packages/plugins/i18n/admin/src/contentManagerHooks/tests/addColumnToTable.test.js new file mode 100644 index 0000000000..ab95ef06bb --- /dev/null +++ b/packages/plugins/i18n/admin/src/contentManagerHooks/tests/addColumnToTable.test.js @@ -0,0 +1,36 @@ +import addColumnToTable from '../addColumnToTable'; + +describe('i18n | contentManagerHooks | addColumnToTable', () => { + it('does nothing when there s no i18n.localized key in the action', () => { + const displayedHeaders = ['one']; + const layout = { + contentType: { pluginOptions: {} }, + }; + + const result = addColumnToTable({ displayedHeaders, layout }); + + expect(result).toHaveLength(1); + expect(result).toEqual(['one']); + }); + + it('adds a header to the displayedHeaders array when the content type is localized', () => { + const displayedHeaders = []; + const layout = { + contentType: { + pluginOptions: { + i18n: { localized: true }, + }, + }, + }; + + const result = addColumnToTable({ displayedHeaders, layout }); + + // The anonymous function of cellFormatter creates problem, because it's anonymous + // In our scenario, it's even more tricky because we use a closure in order to pass + // the locales. + // Stringifying the action allows us to have a name inside the expectation for the "cellFormatter" key + expect(JSON.stringify(result)).toBe( + '[{"key":"__locale_key__","fieldSchema":{"type":"string"},"metadatas":{"label":"Content available in","searchable":false,"sortable":false},"name":"locales"}]' + ); + }); +}); diff --git a/packages/plugins/i18n/admin/src/index.js b/packages/plugins/i18n/admin/src/index.js index 4788b7b385..7f6d82511b 100644 --- a/packages/plugins/i18n/admin/src/index.js +++ b/packages/plugins/i18n/admin/src/index.js @@ -16,6 +16,7 @@ import mutateCTBContentTypeSchema from './utils/mutateCTBContentTypeSchema'; import LOCALIZED_FIELDS from './utils/localizedFields'; import i18nReducers from './hooks/reducers'; import DeleteModalAdditionalInfos from './components/DeleteModalAdditionalInfos'; +import addColumnToTableHook from './contentManagerHooks/addColumnToTable'; const pluginDescription = pluginPkg.strapi.description || pluginPkg.description; const icon = pluginPkg.strapi.icon; @@ -39,6 +40,7 @@ export default { }); }, boot(app) { + app.registerHook('cm/inject-column-in-table', addColumnToTableHook); // Add the settings link app.addSettingsLink('global', { intlLabel: { diff --git a/packages/plugins/i18n/admin/src/middlewares/addLocaleColumnToListViewMiddleware.js b/packages/plugins/i18n/admin/src/middlewares/addLocaleColumnToListViewMiddleware.js deleted file mode 100644 index d142ca68c3..0000000000 --- a/packages/plugins/i18n/admin/src/middlewares/addLocaleColumnToListViewMiddleware.js +++ /dev/null @@ -1,32 +0,0 @@ -import React from 'react'; -import get from 'lodash/get'; -import LocaleListCell from '../components/LocaleListCell/LocaleListCell'; - -const addLocaleColumnToListViewMiddleware = () => ({ getState }) => next => action => { - if (action.type !== 'ContentManager/ListView/SET_LIST_LAYOUT ') { - return next(action); - } - - const isFieldLocalized = get(action, 'contentType.pluginOptions.i18n.localized', false); - - if (!isFieldLocalized) { - return next(action); - } - - const store = getState(); - const { locales } = store.i18n_locales; - - const locale = { - key: '__locale_key__', - fieldSchema: { type: 'string' }, - metadatas: { label: 'Content available in', searchable: false, sortable: false }, - name: 'locales', - cellFormatter: props => , - }; - - action.displayedHeaders = [...action.displayedHeaders, locale]; - - return next(action); -}; - -export default addLocaleColumnToListViewMiddleware; diff --git a/packages/plugins/i18n/admin/src/middlewares/index.js b/packages/plugins/i18n/admin/src/middlewares/index.js index 8cf0f59b92..b465e9331b 100644 --- a/packages/plugins/i18n/admin/src/middlewares/index.js +++ b/packages/plugins/i18n/admin/src/middlewares/index.js @@ -4,7 +4,6 @@ import addLocaleToSingleTypesMiddleware from './addLocaleToSingleTypesMiddleware import extendCMEditViewLayoutMiddleware from './extendCMEditViewLayoutMiddleware'; import extendCTBInitialDataMiddleware from './extendCTBInitialDataMiddleware'; import extendCTBAttributeInitialDataMiddleware from './extendCTBAttributeInitialDataMiddleware'; -import addLocaleColumnToListViewMiddleware from './addLocaleColumnToListViewMiddleware'; import localePermissionMiddleware from './localePermissionMiddleware'; const middlewares = [ @@ -14,7 +13,6 @@ const middlewares = [ extendCMEditViewLayoutMiddleware, extendCTBInitialDataMiddleware, extendCTBAttributeInitialDataMiddleware, - addLocaleColumnToListViewMiddleware, localePermissionMiddleware, ]; diff --git a/packages/plugins/i18n/admin/src/middlewares/tests/addLocaleColumnToListViewMiddleware.test.js b/packages/plugins/i18n/admin/src/middlewares/tests/addLocaleColumnToListViewMiddleware.test.js deleted file mode 100644 index c87c97faef..0000000000 --- a/packages/plugins/i18n/admin/src/middlewares/tests/addLocaleColumnToListViewMiddleware.test.js +++ /dev/null @@ -1,67 +0,0 @@ -import { fixtures } from '../../../../../../admin-test-utils'; -import addLocaleColumnToListViewMiddleware from '../addLocaleColumnToListViewMiddleware'; - -describe('addLocaleColumnToListViewMiddleware', () => { - let getState; - - beforeEach(() => { - const store = { ...fixtures.store.state, i18n_locales: { locales: [] } }; - - getState = () => store; - }); - - it('does nothing on unknown actions', () => { - const middleware = addLocaleColumnToListViewMiddleware()({ getState }); - const nextFn = jest.fn(); - const action = { type: 'UNKNOWN' }; - - middleware(nextFn)(action); - - expect(nextFn).toBeCalledWith(action); - expect(action).toEqual({ - type: 'UNKNOWN', - }); - }); - - it('does nothing when there s no i18n.localized key in the action', () => { - const middleware = addLocaleColumnToListViewMiddleware()({ getState }); - const nextFn = jest.fn(); - const action = { - type: 'ContentManager/ListView/SET_LIST_LAYOUT ', - contentType: { pluginOptions: {} }, - }; - - middleware(nextFn)(action); - - expect(nextFn).toBeCalledWith(action); - expect(action).toEqual({ - contentType: { pluginOptions: {} }, - type: 'ContentManager/ListView/SET_LIST_LAYOUT ', - }); - }); - - it('adds a header to the displayedHeaders array when the content type is localized', () => { - const middleware = addLocaleColumnToListViewMiddleware()({ getState }); - const nextFn = jest.fn(); - const action = { - type: 'ContentManager/ListView/SET_LIST_LAYOUT ', - displayedHeaders: [], - contentType: { - pluginOptions: { - i18n: { localized: true }, - }, - }, - }; - - middleware(nextFn)(action); - - expect(nextFn).toBeCalledWith(action); - // The anonymous function of cellFormatter creates problem, because it's anonymous - // In our scenario, it's even more tricky because we use a closure in order to pass - // the locales. - // Stringifying the action allows us to have a name inside the expectation for the "cellFormatter" key - expect(JSON.stringify(action)).toBe( - '{"type":"ContentManager/ListView/SET_LIST_LAYOUT ","displayedHeaders":[{"key":"__locale_key__","fieldSchema":{"type":"string"},"metadatas":{"label":"Content available in","searchable":false,"sortable":false},"name":"locales"}],"contentType":{"pluginOptions":{"i18n":{"localized":true}}}}' - ); - }); -});