Merge pull request #10522 from strapi/core/remove-middleware-cm-table

Remove addColumnToLV middleware in i18n
This commit is contained in:
cyril lopez 2021-06-22 12:38:11 +02:00 committed by GitHub
commit 31c75b2bd0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 116 additions and 134 deletions

View File

@ -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();

View File

@ -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,

View File

@ -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}

View File

@ -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,
};

View File

@ -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 => <p {...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' }];

View File

@ -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 => <LocaleListCell {...props} />,
},
];
};
export default addColumnToTableHook;

View File

@ -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"}]'
);
});
});

View File

@ -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: {

View File

@ -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 => <LocaleListCell {...props} locales={locales} />,
};
action.displayedHeaders = [...action.displayedHeaders, locale];
return next(action);
};
export default addLocaleColumnToListViewMiddleware;

View File

@ -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,
];

View File

@ -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}}}}'
);
});
});