mirror of
https://github.com/strapi/strapi.git
synced 2025-11-14 01:02:04 +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() {
|
async boot() {
|
||||||
Object.keys(this.appPlugins).forEach(plugin => {
|
Object.keys(this.appPlugins).forEach(plugin => {
|
||||||
const boot = this.appPlugins[plugin].boot;
|
const boot = this.appPlugins[plugin].boot;
|
||||||
@ -177,11 +162,16 @@ class StrapiApp {
|
|||||||
addSettingsLink: this.addSettingsLink,
|
addSettingsLink: this.addSettingsLink,
|
||||||
addSettingsLinks: this.addSettingsLinks,
|
addSettingsLinks: this.addSettingsLinks,
|
||||||
getPlugin: this.getPlugin,
|
getPlugin: this.getPlugin,
|
||||||
|
registerHook: this.registerHook,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
createHook = name => {
|
||||||
|
this.hooksDict[name] = createHook();
|
||||||
|
};
|
||||||
|
|
||||||
createSettingSection = (section, links) => {
|
createSettingSection = (section, links) => {
|
||||||
invariant(section.id, 'section.id should be defined');
|
invariant(section.id, 'section.id should be defined');
|
||||||
invariant(
|
invariant(
|
||||||
@ -209,6 +199,22 @@ class StrapiApp {
|
|||||||
return this.plugins[pluginId];
|
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() {
|
async loadAdminTrads() {
|
||||||
const arrayOfPromises = this.appLocales.map(locale => {
|
const arrayOfPromises = this.appLocales.map(locale => {
|
||||||
return import(/* webpackChunkName: "[request]" */ `./translations/${locale}.json`)
|
return import(/* webpackChunkName: "[request]" */ `./translations/${locale}.json`)
|
||||||
@ -270,20 +276,16 @@ class StrapiApp {
|
|||||||
return Promise.resolve();
|
return Promise.resolve();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
registerHook = (name, fn) => {
|
||||||
|
this.hooksDict[name].register(fn);
|
||||||
|
};
|
||||||
|
|
||||||
registerPlugin = pluginConf => {
|
registerPlugin = pluginConf => {
|
||||||
const plugin = Plugin(pluginConf);
|
const plugin = Plugin(pluginConf);
|
||||||
|
|
||||||
this.plugins[plugin.pluginId] = plugin;
|
this.plugins[plugin.pluginId] = plugin;
|
||||||
};
|
};
|
||||||
|
|
||||||
createHook = name => {
|
|
||||||
this.hooksDict[name] = createHook();
|
|
||||||
};
|
|
||||||
|
|
||||||
registerHook = (name, fn) => {
|
|
||||||
this.hooksDict[name].register(fn);
|
|
||||||
};
|
|
||||||
|
|
||||||
runHookSeries = (name, asynchronous = false) =>
|
runHookSeries = (name, asynchronous = false) =>
|
||||||
asynchronous ? this.hooksDict[name].runSeriesAsync() : this.hooksDict[name].runSeries();
|
asynchronous ? this.hooksDict[name].runSeriesAsync() : this.hooksDict[name].runSeries();
|
||||||
|
|
||||||
|
|||||||
@ -17,7 +17,6 @@ const name = pluginPkg.strapi.name;
|
|||||||
|
|
||||||
export default {
|
export default {
|
||||||
register(app) {
|
register(app) {
|
||||||
app.addReducers(reducers);
|
|
||||||
app.addCorePluginMenuLink({
|
app.addCorePluginMenuLink({
|
||||||
to: `/plugins/${pluginId}`,
|
to: `/plugins/${pluginId}`,
|
||||||
icon: 'book-open',
|
icon: 'book-open',
|
||||||
@ -28,6 +27,11 @@ export default {
|
|||||||
permissions: pluginPermissions.main,
|
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({
|
app.registerPlugin({
|
||||||
description: pluginDescription,
|
description: pluginDescription,
|
||||||
icon,
|
icon,
|
||||||
|
|||||||
@ -18,6 +18,7 @@ import {
|
|||||||
useNotification,
|
useNotification,
|
||||||
useQueryParams,
|
useQueryParams,
|
||||||
useRBACProvider,
|
useRBACProvider,
|
||||||
|
useStrapiApp,
|
||||||
request,
|
request,
|
||||||
} from '@strapi/helper-plugin';
|
} from '@strapi/helper-plugin';
|
||||||
import pluginId from '../../pluginId';
|
import pluginId from '../../pluginId';
|
||||||
@ -93,6 +94,14 @@ function ListView({
|
|||||||
const trackUsageRef = useRef(trackUsage);
|
const trackUsageRef = useRef(trackUsage);
|
||||||
const fetchPermissionsRef = useRef(refetchPermissions);
|
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 [{ query }, setQuery] = useQueryParams();
|
||||||
const params = buildQueryString(query);
|
const params = buildQueryString(query);
|
||||||
|
|
||||||
@ -466,7 +475,7 @@ function ListView({
|
|||||||
canCreate={canCreate}
|
canCreate={canCreate}
|
||||||
canDelete={canDelete}
|
canDelete={canDelete}
|
||||||
canUpdate={canUpdate}
|
canUpdate={canUpdate}
|
||||||
displayedHeaders={displayedHeaders}
|
displayedHeaders={tableHeaders}
|
||||||
hasDraftAndPublish={hasDraftAndPublish}
|
hasDraftAndPublish={hasDraftAndPublish}
|
||||||
isBulkable={isBulkable}
|
isBulkable={isBulkable}
|
||||||
setQuery={setQuery}
|
setQuery={setQuery}
|
||||||
|
|||||||
@ -1,9 +1,11 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
|
import { useSelector } from 'react-redux';
|
||||||
import { Padded, Text } from '@buffetjs/core';
|
import { Padded, Text } from '@buffetjs/core';
|
||||||
import { Tooltip } from '@buffetjs/styles';
|
import { Tooltip } from '@buffetjs/styles';
|
||||||
import get from 'lodash/get';
|
import get from 'lodash/get';
|
||||||
import styled from 'styled-components';
|
import styled from 'styled-components';
|
||||||
|
import selectI18NLocales from '../../selectors/selectI18nLocales';
|
||||||
|
|
||||||
const mapToLocaleName = (locales, localeCode) =>
|
const mapToLocaleName = (locales, localeCode) =>
|
||||||
get(
|
get(
|
||||||
@ -18,7 +20,8 @@ const LocaleName = styled.div`
|
|||||||
white-space: nowrap;
|
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 allLocalizations = [{ locale: currentLocaleCode }, ...localizations];
|
||||||
const localizationNames = allLocalizations.map(locale => locale.locale);
|
const localizationNames = allLocalizations.map(locale => locale.locale);
|
||||||
const defaultLocale = locales.find(locale => locale.isDefault);
|
const defaultLocale = locales.find(locale => locale.isDefault);
|
||||||
@ -77,13 +80,6 @@ LocaleListCell.propTypes = {
|
|||||||
locale: PropTypes.string.isRequired,
|
locale: PropTypes.string.isRequired,
|
||||||
})
|
})
|
||||||
).isRequired,
|
).isRequired,
|
||||||
locales: PropTypes.arrayOf(
|
|
||||||
PropTypes.shape({
|
|
||||||
name: PropTypes.string.isRequired,
|
|
||||||
code: PropTypes.string.isRequired,
|
|
||||||
isDefault: PropTypes.bool,
|
|
||||||
})
|
|
||||||
).isRequired,
|
|
||||||
locale: PropTypes.string.isRequired,
|
locale: PropTypes.string.isRequired,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@ -1,5 +1,6 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { render, screen } from '@testing-library/react';
|
import { render, screen } from '@testing-library/react';
|
||||||
|
import { useSelector } from 'react-redux';
|
||||||
import LocaleListCell from '../LocaleListCell';
|
import LocaleListCell from '../LocaleListCell';
|
||||||
|
|
||||||
jest.mock('@buffetjs/styles', () => ({
|
jest.mock('@buffetjs/styles', () => ({
|
||||||
@ -11,6 +12,10 @@ jest.mock('@buffetjs/core', () => ({
|
|||||||
Text: props => <p {...props} />,
|
Text: props => <p {...props} />,
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
jest.mock('react-redux', () => ({
|
||||||
|
useSelector: jest.fn(() => []),
|
||||||
|
}));
|
||||||
|
|
||||||
describe('LocaleListCell', () => {
|
describe('LocaleListCell', () => {
|
||||||
it('returns the default locale first, then the others sorted alphabetically', () => {
|
it('returns the default locale first, then the others sorted alphabetically', () => {
|
||||||
const locales = [
|
const locales = [
|
||||||
@ -40,6 +45,8 @@ describe('LocaleListCell', () => {
|
|||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
|
useSelector.mockImplementation(() => locales);
|
||||||
|
|
||||||
const locale = 'en';
|
const locale = 'en';
|
||||||
const localizations = [{ locale: 'fr-FR' }, { locale: 'ar' }];
|
const localizations = [{ locale: 'fr-FR' }, { locale: 'ar' }];
|
||||||
|
|
||||||
@ -78,6 +85,8 @@ describe('LocaleListCell', () => {
|
|||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
|
useSelector.mockImplementation(() => locales);
|
||||||
|
|
||||||
const locale = 'en';
|
const locale = 'en';
|
||||||
const localizations = [{ locale: 'ar' }];
|
const localizations = [{ locale: 'ar' }];
|
||||||
|
|
||||||
@ -115,6 +124,7 @@ describe('LocaleListCell', () => {
|
|||||||
isDefault: false,
|
isDefault: false,
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
useSelector.mockImplementation(() => locales);
|
||||||
|
|
||||||
const locale = 'fr-FR';
|
const locale = 'fr-FR';
|
||||||
const localizations = [{ locale: 'en' }, { locale: 'ar' }];
|
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 LOCALIZED_FIELDS from './utils/localizedFields';
|
||||||
import i18nReducers from './hooks/reducers';
|
import i18nReducers from './hooks/reducers';
|
||||||
import DeleteModalAdditionalInfos from './components/DeleteModalAdditionalInfos';
|
import DeleteModalAdditionalInfos from './components/DeleteModalAdditionalInfos';
|
||||||
|
import addColumnToTableHook from './contentManagerHooks/addColumnToTable';
|
||||||
|
|
||||||
const pluginDescription = pluginPkg.strapi.description || pluginPkg.description;
|
const pluginDescription = pluginPkg.strapi.description || pluginPkg.description;
|
||||||
const icon = pluginPkg.strapi.icon;
|
const icon = pluginPkg.strapi.icon;
|
||||||
@ -39,6 +40,7 @@ export default {
|
|||||||
});
|
});
|
||||||
},
|
},
|
||||||
boot(app) {
|
boot(app) {
|
||||||
|
app.registerHook('cm/inject-column-in-table', addColumnToTableHook);
|
||||||
// Add the settings link
|
// Add the settings link
|
||||||
app.addSettingsLink('global', {
|
app.addSettingsLink('global', {
|
||||||
intlLabel: {
|
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 extendCMEditViewLayoutMiddleware from './extendCMEditViewLayoutMiddleware';
|
||||||
import extendCTBInitialDataMiddleware from './extendCTBInitialDataMiddleware';
|
import extendCTBInitialDataMiddleware from './extendCTBInitialDataMiddleware';
|
||||||
import extendCTBAttributeInitialDataMiddleware from './extendCTBAttributeInitialDataMiddleware';
|
import extendCTBAttributeInitialDataMiddleware from './extendCTBAttributeInitialDataMiddleware';
|
||||||
import addLocaleColumnToListViewMiddleware from './addLocaleColumnToListViewMiddleware';
|
|
||||||
import localePermissionMiddleware from './localePermissionMiddleware';
|
import localePermissionMiddleware from './localePermissionMiddleware';
|
||||||
|
|
||||||
const middlewares = [
|
const middlewares = [
|
||||||
@ -14,7 +13,6 @@ const middlewares = [
|
|||||||
extendCMEditViewLayoutMiddleware,
|
extendCMEditViewLayoutMiddleware,
|
||||||
extendCTBInitialDataMiddleware,
|
extendCTBInitialDataMiddleware,
|
||||||
extendCTBAttributeInitialDataMiddleware,
|
extendCTBAttributeInitialDataMiddleware,
|
||||||
addLocaleColumnToListViewMiddleware,
|
|
||||||
localePermissionMiddleware,
|
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