mirror of
https://github.com/strapi/strapi.git
synced 2025-11-02 10:55:37 +00:00
Merge pull request #10522 from strapi/core/remove-middleware-cm-table
Remove addColumnToLV middleware in i18n
This commit is contained in:
commit
31c75b2bd0
@ -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();
|
||||
|
||||
|
||||
@ -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,
|
||||
|
||||
@ -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}
|
||||
|
||||
@ -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,
|
||||
};
|
||||
|
||||
|
||||
@ -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' }];
|
||||
|
||||
@ -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;
|
||||
@ -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"}]'
|
||||
);
|
||||
});
|
||||
});
|
||||
@ -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: {
|
||||
|
||||
@ -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;
|
||||
@ -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,
|
||||
];
|
||||
|
||||
|
||||
@ -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}}}}'
|
||||
);
|
||||
});
|
||||
});
|
||||
Loading…
x
Reference in New Issue
Block a user