mirror of
https://github.com/strapi/strapi.git
synced 2025-11-06 13:01:40 +00:00
chore(i18n): convert CM List view components to TS (#18838)
This commit is contained in:
parent
306b218011
commit
a1c8cbb8a8
File diff suppressed because one or more lines are too long
@ -1,41 +0,0 @@
|
|||||||
import * as React from 'react';
|
|
||||||
|
|
||||||
import { Typography } from '@strapi/design-system';
|
|
||||||
import { useIntl } from 'react-intl';
|
|
||||||
|
|
||||||
import useHasI18n from '../../../hooks/useHasI18n';
|
|
||||||
import { getTranslation } from '../../../utils/getTranslation';
|
|
||||||
|
|
||||||
const Emphasis = (chunks: React.ReactNode) => {
|
|
||||||
return (
|
|
||||||
<Typography fontWeight="semiBold" textColor="danger500">
|
|
||||||
{chunks}
|
|
||||||
</Typography>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
const DeleteModalAdditionalInfos = () => {
|
|
||||||
const hasI18nEnabled = useHasI18n();
|
|
||||||
const { formatMessage } = useIntl();
|
|
||||||
|
|
||||||
if (!hasI18nEnabled) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Typography textColor="danger500">
|
|
||||||
{formatMessage(
|
|
||||||
{
|
|
||||||
id: getTranslation('Settings.list.actions.deleteAdditionalInfos'),
|
|
||||||
defaultMessage:
|
|
||||||
'This will delete the active locale versions <em>(from Internationalization)</em>',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
em: Emphasis,
|
|
||||||
}
|
|
||||||
)}
|
|
||||||
</Typography>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export default DeleteModalAdditionalInfos;
|
|
||||||
@ -1,41 +0,0 @@
|
|||||||
import * as React from 'react';
|
|
||||||
|
|
||||||
import { Typography } from '@strapi/design-system';
|
|
||||||
import { useIntl } from 'react-intl';
|
|
||||||
|
|
||||||
import useHasI18n from '../../../hooks/useHasI18n';
|
|
||||||
import { getTranslation } from '../../../utils/getTranslation';
|
|
||||||
|
|
||||||
const Emphasis = (chunks: React.ReactNode) => {
|
|
||||||
return (
|
|
||||||
<Typography fontWeight="semiBold" textColor="danger500">
|
|
||||||
{chunks}
|
|
||||||
</Typography>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
const PublishModalAdditionalInfos = () => {
|
|
||||||
const hasI18nEnabled = useHasI18n();
|
|
||||||
const { formatMessage } = useIntl();
|
|
||||||
|
|
||||||
if (!hasI18nEnabled) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Typography textColor="danger500">
|
|
||||||
{formatMessage(
|
|
||||||
{
|
|
||||||
id: getTranslation('Settings.list.actions.publishAdditionalInfos'),
|
|
||||||
defaultMessage:
|
|
||||||
'This will publish the active locale versions <em>(from Internationalization)</em>',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
em: Emphasis,
|
|
||||||
}
|
|
||||||
)}
|
|
||||||
</Typography>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export default PublishModalAdditionalInfos;
|
|
||||||
@ -1,41 +0,0 @@
|
|||||||
import * as React from 'react';
|
|
||||||
|
|
||||||
import { Typography } from '@strapi/design-system';
|
|
||||||
import { useIntl } from 'react-intl';
|
|
||||||
|
|
||||||
import useHasI18n from '../../../hooks/useHasI18n';
|
|
||||||
import { getTranslation } from '../../../utils/getTranslation';
|
|
||||||
|
|
||||||
const Emphasis = (chunks: React.ReactNode) => {
|
|
||||||
return (
|
|
||||||
<Typography fontWeight="semiBold" textColor="danger500">
|
|
||||||
{chunks}
|
|
||||||
</Typography>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
const UnpublishModalAdditionalInfos = () => {
|
|
||||||
const hasI18nEnabled = useHasI18n();
|
|
||||||
const { formatMessage } = useIntl();
|
|
||||||
|
|
||||||
if (!hasI18nEnabled) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Typography textColor="danger500">
|
|
||||||
{formatMessage(
|
|
||||||
{
|
|
||||||
id: getTranslation('Settings.list.actions.unpublishAdditionalInfos'),
|
|
||||||
defaultMessage:
|
|
||||||
'This will unpublish the active locale versions <em>(from Internationalization)</em>',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
em: Emphasis,
|
|
||||||
}
|
|
||||||
)}
|
|
||||||
</Typography>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export default UnpublishModalAdditionalInfos;
|
|
||||||
@ -0,0 +1,89 @@
|
|||||||
|
import * as React from 'react';
|
||||||
|
|
||||||
|
import { Typography } from '@strapi/design-system';
|
||||||
|
import { useIntl } from 'react-intl';
|
||||||
|
|
||||||
|
import { useContentTypeHasI18n } from '../hooks/useContentTypeHasI18n';
|
||||||
|
import { getTranslation } from '../utils/getTranslation';
|
||||||
|
|
||||||
|
const Emphasis = (chunks: React.ReactNode) => {
|
||||||
|
return (
|
||||||
|
<Typography fontWeight="semiBold" textColor="danger500">
|
||||||
|
{chunks}
|
||||||
|
</Typography>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const DeleteModalAdditionalInfo = () => {
|
||||||
|
const hasI18nEnabled = useContentTypeHasI18n();
|
||||||
|
const { formatMessage } = useIntl();
|
||||||
|
|
||||||
|
if (!hasI18nEnabled) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Typography textColor="danger500">
|
||||||
|
{formatMessage(
|
||||||
|
{
|
||||||
|
id: getTranslation('Settings.list.actions.deleteAdditionalInfos'),
|
||||||
|
defaultMessage:
|
||||||
|
'This will delete the active locale versions <em>(from Internationalization)</em>',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
em: Emphasis,
|
||||||
|
}
|
||||||
|
)}
|
||||||
|
</Typography>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const PublishModalAdditionalInfo = () => {
|
||||||
|
const hasI18nEnabled = useContentTypeHasI18n();
|
||||||
|
const { formatMessage } = useIntl();
|
||||||
|
|
||||||
|
if (!hasI18nEnabled) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Typography textColor="danger500">
|
||||||
|
{formatMessage(
|
||||||
|
{
|
||||||
|
id: getTranslation('Settings.list.actions.publishAdditionalInfos'),
|
||||||
|
defaultMessage:
|
||||||
|
'This will publish the active locale versions <em>(from Internationalization)</em>',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
em: Emphasis,
|
||||||
|
}
|
||||||
|
)}
|
||||||
|
</Typography>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const UnpublishModalAdditionalInfo = () => {
|
||||||
|
const hasI18nEnabled = useContentTypeHasI18n();
|
||||||
|
const { formatMessage } = useIntl();
|
||||||
|
|
||||||
|
if (!hasI18nEnabled) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Typography textColor="danger500">
|
||||||
|
{formatMessage(
|
||||||
|
{
|
||||||
|
id: getTranslation('Settings.list.actions.unpublishAdditionalInfos'),
|
||||||
|
defaultMessage:
|
||||||
|
'This will unpublish the active locale versions <em>(from Internationalization)</em>',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
em: Emphasis,
|
||||||
|
}
|
||||||
|
)}
|
||||||
|
</Typography>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export { DeleteModalAdditionalInfo, PublishModalAdditionalInfo, UnpublishModalAdditionalInfo };
|
||||||
84
packages/plugins/i18n/admin/src/components/LocalePicker.tsx
Normal file
84
packages/plugins/i18n/admin/src/components/LocalePicker.tsx
Normal file
@ -0,0 +1,84 @@
|
|||||||
|
import { useState } from 'react';
|
||||||
|
|
||||||
|
import { SingleSelect, SingleSelectOption, SingleSelectProps } from '@strapi/design-system';
|
||||||
|
import { useQueryParams } from '@strapi/helper-plugin';
|
||||||
|
import { useIntl } from 'react-intl';
|
||||||
|
import { useDispatch } from 'react-redux';
|
||||||
|
import { useRouteMatch } from 'react-router-dom';
|
||||||
|
|
||||||
|
import { useContentTypeHasI18n } from '../hooks/useContentTypeHasI18n';
|
||||||
|
import { useContentTypePermissions } from '../hooks/useContentTypePermissions';
|
||||||
|
import { useTypedSelector } from '../store/hooks';
|
||||||
|
import { getTranslation } from '../utils/getTranslation';
|
||||||
|
import { getInitialLocale } from '../utils/locales';
|
||||||
|
|
||||||
|
const LocalePicker = () => {
|
||||||
|
const { formatMessage } = useIntl();
|
||||||
|
const dispatch = useDispatch();
|
||||||
|
const locales = useTypedSelector((state) => state.i18n_locales.locales);
|
||||||
|
const [{ query }, setQuery] = useQueryParams<{
|
||||||
|
page: number;
|
||||||
|
plugins: { i18n: { locale: string } };
|
||||||
|
}>();
|
||||||
|
const match = useRouteMatch<{ slug: string }>('/content-manager/collectionType/:slug');
|
||||||
|
const isContentTypeLocalized = useContentTypeHasI18n();
|
||||||
|
const { createPermissions, readPermissions } = useContentTypePermissions(match?.params.slug);
|
||||||
|
|
||||||
|
const initialLocale = getInitialLocale(query, locales);
|
||||||
|
const [selected, setSelected] = useState(initialLocale?.code || '');
|
||||||
|
|
||||||
|
if (!isContentTypeLocalized) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!locales || locales.length === 0) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
const displayedLocales = locales.filter((locale) => {
|
||||||
|
const canCreate = createPermissions.some(({ properties }) =>
|
||||||
|
(properties?.locales ?? []).includes(locale.code)
|
||||||
|
);
|
||||||
|
const canRead = readPermissions.some(({ properties }) =>
|
||||||
|
(properties?.locales ?? []).includes(locale.code)
|
||||||
|
);
|
||||||
|
|
||||||
|
return canCreate || canRead;
|
||||||
|
});
|
||||||
|
|
||||||
|
// @ts-expect-error – This can be removed in V2 of the DS.
|
||||||
|
const handleChange: SingleSelectProps['onChange'] = (code: string) => {
|
||||||
|
if (code === selected) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
setSelected(code);
|
||||||
|
|
||||||
|
dispatch({ type: 'ContentManager/RBACManager/RESET_PERMISSIONS' });
|
||||||
|
|
||||||
|
setQuery({
|
||||||
|
page: 1,
|
||||||
|
plugins: { ...query.plugins, i18n: { locale: code } },
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<SingleSelect
|
||||||
|
size="S"
|
||||||
|
aria-label={formatMessage({
|
||||||
|
id: getTranslation('actions.select-locale'),
|
||||||
|
defaultMessage: 'Select locale',
|
||||||
|
})}
|
||||||
|
value={selected}
|
||||||
|
onChange={handleChange}
|
||||||
|
>
|
||||||
|
{displayedLocales.map((locale) => (
|
||||||
|
<SingleSelectOption key={locale.id} value={locale.code}>
|
||||||
|
{locale.name}
|
||||||
|
</SingleSelectOption>
|
||||||
|
))}
|
||||||
|
</SingleSelect>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export { LocalePicker };
|
||||||
@ -1,93 +0,0 @@
|
|||||||
import { useState } from 'react';
|
|
||||||
|
|
||||||
import { Option, Select } from '@strapi/design-system';
|
|
||||||
import { useQueryParams } from '@strapi/helper-plugin';
|
|
||||||
import get from 'lodash/get';
|
|
||||||
import { useIntl } from 'react-intl';
|
|
||||||
import { useDispatch } from 'react-redux';
|
|
||||||
import { useRouteMatch } from 'react-router-dom';
|
|
||||||
|
|
||||||
import { useContentTypePermissions } from '../../hooks/useContentTypePermissions';
|
|
||||||
import useHasI18n from '../../hooks/useHasI18n';
|
|
||||||
import { useTypedSelector } from '../../store/hooks';
|
|
||||||
import getInitialLocale from '../../utils/getInitialLocale';
|
|
||||||
import { getTranslation } from '../../utils/getTranslation';
|
|
||||||
|
|
||||||
const LocalePicker = () => {
|
|
||||||
const { formatMessage } = useIntl();
|
|
||||||
const dispatch = useDispatch();
|
|
||||||
const locales = useTypedSelector((state) => state.i18n_locales.locales);
|
|
||||||
const [{ query }, setQuery] = useQueryParams<any>();
|
|
||||||
const {
|
|
||||||
params: { slug },
|
|
||||||
} = useRouteMatch('/content-manager/collectionType/:slug') as any;
|
|
||||||
const isFieldLocalized = useHasI18n();
|
|
||||||
const { createPermissions, readPermissions } = useContentTypePermissions(slug);
|
|
||||||
|
|
||||||
const initialLocale = getInitialLocale(query, locales);
|
|
||||||
const [selected, setSelected] = useState(initialLocale?.code || '');
|
|
||||||
|
|
||||||
if (!isFieldLocalized) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!locales || locales.length === 0) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
const displayedLocales = locales.filter((locale: any) => {
|
|
||||||
const canCreate = createPermissions.find(({ properties }: any) => {
|
|
||||||
return get(properties, 'locales', []).includes(locale.code);
|
|
||||||
});
|
|
||||||
const canRead = readPermissions.find(({ properties }: any) =>
|
|
||||||
get(properties, 'locales', []).includes(locale.code)
|
|
||||||
);
|
|
||||||
|
|
||||||
return canCreate || canRead;
|
|
||||||
});
|
|
||||||
|
|
||||||
const handleClick = (code: string) => {
|
|
||||||
if (code === selected) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
setSelected(code);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* if the selected value is set at the same time as the dispatcher
|
|
||||||
* is run, react might not have enough time to re-render the Select
|
|
||||||
* component, which leads to the `source` ref, which is passed to
|
|
||||||
* Popout, not being defined.
|
|
||||||
*
|
|
||||||
* By pushing the dispatcher to the end of the current execution
|
|
||||||
* context, we can guarantee the rendering can finish before.
|
|
||||||
*/
|
|
||||||
setTimeout(() => {
|
|
||||||
dispatch({ type: 'ContentManager/RBACManager/RESET_PERMISSIONS' });
|
|
||||||
setQuery({
|
|
||||||
page: 1,
|
|
||||||
plugins: { ...query.plugins, i18n: { locale: code } },
|
|
||||||
});
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Select
|
|
||||||
size="S"
|
|
||||||
aria-label={formatMessage({
|
|
||||||
id: getTranslation('actions.select-locale'),
|
|
||||||
defaultMessage: '',
|
|
||||||
})}
|
|
||||||
value={selected}
|
|
||||||
onChange={handleClick as any}
|
|
||||||
>
|
|
||||||
{displayedLocales.map((locale) => (
|
|
||||||
<Option key={locale.id} id={`menu-item${locale.name || locale.code}`} value={locale.code}>
|
|
||||||
{locale.name}
|
|
||||||
</Option>
|
|
||||||
))}
|
|
||||||
</Select>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export default LocalePicker;
|
|
||||||
@ -1,7 +1,7 @@
|
|||||||
import get from 'lodash/get';
|
import get from 'lodash/get';
|
||||||
import { parse, stringify } from 'qs';
|
import { parse, stringify } from 'qs';
|
||||||
|
|
||||||
import getDefaultLocale from '../../utils/getDefaultLocale';
|
import { getDefaultLocale } from '../../utils/locales';
|
||||||
|
|
||||||
const addLocaleToLinksSearch = (
|
const addLocaleToLinksSearch = (
|
||||||
links: any[],
|
links: any[],
|
||||||
|
|||||||
@ -0,0 +1 @@
|
|||||||
|
export const useContentTypeHasI18n = jest.fn().mockReturnValue(true);
|
||||||
@ -0,0 +1,12 @@
|
|||||||
|
import { useTypedSelector } from '../store/hooks';
|
||||||
|
|
||||||
|
const useContentTypeHasI18n = (): boolean => {
|
||||||
|
const pluginOptions = useTypedSelector(
|
||||||
|
// @ts-expect-error – we've not typed the CM ListView yet.
|
||||||
|
(state) => state['content-manager_listView'].contentType.pluginOptions
|
||||||
|
);
|
||||||
|
|
||||||
|
return pluginOptions?.i18n?.localized ?? false;
|
||||||
|
};
|
||||||
|
|
||||||
|
export { useContentTypeHasI18n };
|
||||||
@ -1,14 +1,23 @@
|
|||||||
|
import { useMemo } from 'react';
|
||||||
|
|
||||||
import { createSelector } from '@reduxjs/toolkit';
|
import { createSelector } from '@reduxjs/toolkit';
|
||||||
|
import { Permission } from '@strapi/helper-plugin';
|
||||||
|
|
||||||
import { useTypedSelector } from '../store/hooks';
|
import { useTypedSelector } from '../store/hooks';
|
||||||
import { RootState } from '../store/reducers';
|
import { RootState } from '../store/reducers';
|
||||||
|
|
||||||
const selectContentTypePermissions = createSelector(
|
const makeSelectContentTypePermissions = () =>
|
||||||
|
// @ts-expect-error – I have no idea why this fails like this.
|
||||||
|
createSelector(
|
||||||
(state: RootState) => state.rbacProvider.collectionTypesRelatedPermissions,
|
(state: RootState) => state.rbacProvider.collectionTypesRelatedPermissions,
|
||||||
(_, slug: string) => slug,
|
(_, slug: string) => slug,
|
||||||
(state, slug) => {
|
(state: RootState['rbacProvider']['collectionTypesRelatedPermissions'], slug: string) => {
|
||||||
// @ts-expect-error – Selectors are weird, why don't they work with TS?
|
const currentCTRelatedPermissions = slug ? state[slug] : {};
|
||||||
const currentCTRelatedPermissions = state[slug];
|
|
||||||
|
if (!currentCTRelatedPermissions) {
|
||||||
|
return { createPermissions: [], readPermissions: [] };
|
||||||
|
}
|
||||||
|
|
||||||
const readPermissions =
|
const readPermissions =
|
||||||
currentCTRelatedPermissions['plugin::content-manager.explorer.read'] || [];
|
currentCTRelatedPermissions['plugin::content-manager.explorer.read'] || [];
|
||||||
const createPermissions =
|
const createPermissions =
|
||||||
@ -18,7 +27,11 @@ const selectContentTypePermissions = createSelector(
|
|||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
const useContentTypePermissions = (slug: string) =>
|
const useContentTypePermissions = (
|
||||||
useTypedSelector((state) => selectContentTypePermissions(state, slug));
|
slug?: string
|
||||||
|
): { createPermissions: Permission[]; readPermissions: Permission[] } => {
|
||||||
|
const selectContentTypePermissions = useMemo(makeSelectContentTypePermissions, []);
|
||||||
|
return useTypedSelector((state) => selectContentTypePermissions(state, slug));
|
||||||
|
};
|
||||||
|
|
||||||
export { useContentTypePermissions };
|
export { useContentTypePermissions };
|
||||||
|
|||||||
@ -1,13 +0,0 @@
|
|||||||
import get from 'lodash/get';
|
|
||||||
import { useSelector } from 'react-redux';
|
|
||||||
|
|
||||||
const selectContentManagerListViewPluginOptions = (state: any) =>
|
|
||||||
state['content-manager_listView'].contentType.pluginOptions;
|
|
||||||
|
|
||||||
const useHasI18n = () => {
|
|
||||||
const pluginOptions = useSelector(selectContentManagerListViewPluginOptions);
|
|
||||||
|
|
||||||
return get(pluginOptions, 'i18n.localized', false);
|
|
||||||
};
|
|
||||||
|
|
||||||
export default useHasI18n;
|
|
||||||
@ -4,11 +4,13 @@ import * as yup from 'yup';
|
|||||||
|
|
||||||
import CheckboxConfirmation from './components/CheckboxConfirmation';
|
import CheckboxConfirmation from './components/CheckboxConfirmation';
|
||||||
import { CMEditViewInjectedComponents } from './components/CMEditViewInjectedComponents';
|
import { CMEditViewInjectedComponents } from './components/CMEditViewInjectedComponents';
|
||||||
import DeleteModalAdditionalInfos from './components/CMListViewInjectedComponents/DeleteModalAdditionalInfos';
|
import {
|
||||||
import PublishModalAdditionalInfos from './components/CMListViewInjectedComponents/PublishModalAdditionalInfos';
|
DeleteModalAdditionalInfo,
|
||||||
import UnpublishModalAdditionalInfos from './components/CMListViewInjectedComponents/UnpublishModalAdditionalInfos';
|
PublishModalAdditionalInfo,
|
||||||
|
UnpublishModalAdditionalInfo,
|
||||||
|
} from './components/CMListViewModalsAdditionalInformation';
|
||||||
import Initializer from './components/Initializer';
|
import Initializer from './components/Initializer';
|
||||||
import LocalePicker from './components/LocalePicker';
|
import { LocalePicker } from './components/LocalePicker';
|
||||||
import { PERMISSIONS } from './constants';
|
import { PERMISSIONS } from './constants';
|
||||||
import addColumnToTableHook from './contentManagerHooks/addColumnToTable';
|
import addColumnToTableHook from './contentManagerHooks/addColumnToTable';
|
||||||
import addLocaleToCollectionTypesLinksHook from './contentManagerHooks/addLocaleToCollectionTypesLinks';
|
import addLocaleToCollectionTypesLinksHook from './contentManagerHooks/addLocaleToCollectionTypesLinks';
|
||||||
@ -81,17 +83,17 @@ export default {
|
|||||||
|
|
||||||
app.injectContentManagerComponent('listView', 'deleteModalAdditionalInfos', {
|
app.injectContentManagerComponent('listView', 'deleteModalAdditionalInfos', {
|
||||||
name: 'i18n-delete-bullets-in-modal',
|
name: 'i18n-delete-bullets-in-modal',
|
||||||
Component: DeleteModalAdditionalInfos,
|
Component: DeleteModalAdditionalInfo,
|
||||||
});
|
});
|
||||||
|
|
||||||
app.injectContentManagerComponent('listView', 'publishModalAdditionalInfos', {
|
app.injectContentManagerComponent('listView', 'publishModalAdditionalInfos', {
|
||||||
name: 'i18n-publish-bullets-in-modal',
|
name: 'i18n-publish-bullets-in-modal',
|
||||||
Component: PublishModalAdditionalInfos,
|
Component: PublishModalAdditionalInfo,
|
||||||
});
|
});
|
||||||
|
|
||||||
app.injectContentManagerComponent('listView', 'unpublishModalAdditionalInfos', {
|
app.injectContentManagerComponent('listView', 'unpublishModalAdditionalInfos', {
|
||||||
name: 'i18n-unpublish-bullets-in-modal',
|
name: 'i18n-unpublish-bullets-in-modal',
|
||||||
Component: UnpublishModalAdditionalInfos,
|
Component: UnpublishModalAdditionalInfo,
|
||||||
});
|
});
|
||||||
|
|
||||||
const ctbPlugin = app.getPlugin('content-type-builder');
|
const ctbPlugin = app.getPlugin('content-type-builder');
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
import { createSelector, Dispatch, Selector } from '@reduxjs/toolkit';
|
import { Dispatch } from '@reduxjs/toolkit';
|
||||||
import { TypedUseSelectorHook, useDispatch, useSelector } from 'react-redux';
|
import { TypedUseSelectorHook, useDispatch, useSelector } from 'react-redux';
|
||||||
|
|
||||||
import { Action, RootState } from './reducers';
|
import { Action, RootState } from './reducers';
|
||||||
@ -8,9 +8,4 @@ type AppDispatch = Dispatch<Action>;
|
|||||||
const useTypedDispatch: () => AppDispatch = useDispatch;
|
const useTypedDispatch: () => AppDispatch = useDispatch;
|
||||||
const useTypedSelector: TypedUseSelectorHook<RootState> = useSelector;
|
const useTypedSelector: TypedUseSelectorHook<RootState> = useSelector;
|
||||||
|
|
||||||
const createTypedSelector = <TResult, TSelector extends Selector<RootState, TResult>>(
|
export { useTypedSelector, useTypedDispatch };
|
||||||
selector: TSelector
|
|
||||||
// @ts-expect-error – TODO: this is needed to avoid TS2742. But it's not quite right.
|
|
||||||
): ReturnType<TSelector> => createSelector((state: RootState) => state, selector);
|
|
||||||
|
|
||||||
export { useTypedSelector, createTypedSelector, useTypedDispatch };
|
|
||||||
|
|||||||
@ -1,60 +0,0 @@
|
|||||||
import get from 'lodash/get';
|
|
||||||
|
|
||||||
const hasLocalePermission = (permissions: any, localeCode: any) => {
|
|
||||||
if (permissions) {
|
|
||||||
const hasPermission = permissions.some((permission: any) =>
|
|
||||||
get(permission, 'properties.locales', []).includes(localeCode)
|
|
||||||
);
|
|
||||||
|
|
||||||
if (hasPermission) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
};
|
|
||||||
|
|
||||||
const getFirstLocale = (permissions: any) => {
|
|
||||||
if (permissions && permissions.length > 0) {
|
|
||||||
const firstAuthorizedNonDefaultLocale = get(permissions, [0, 'properties', 'locales', 0], null);
|
|
||||||
|
|
||||||
if (firstAuthorizedNonDefaultLocale) {
|
|
||||||
return firstAuthorizedNonDefaultLocale;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Entry point of the module
|
|
||||||
*/
|
|
||||||
const getDefaultLocale = (ctPermissions: any, locales: any = []) => {
|
|
||||||
const defaultLocale = locales.find((locale: any) => locale.isDefault);
|
|
||||||
|
|
||||||
if (!defaultLocale) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
const readPermissions = ctPermissions['plugin::content-manager.explorer.read'];
|
|
||||||
const createPermissions = ctPermissions['plugin::content-manager.explorer.create'];
|
|
||||||
|
|
||||||
if (hasLocalePermission(readPermissions, defaultLocale.code)) {
|
|
||||||
return defaultLocale.code;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (hasLocalePermission(createPermissions, defaultLocale.code)) {
|
|
||||||
return defaultLocale.code;
|
|
||||||
}
|
|
||||||
|
|
||||||
// When the default locale is not authorized, we return the first authorized locale
|
|
||||||
const firstAuthorizedForReadNonDefaultLocale = getFirstLocale(readPermissions);
|
|
||||||
|
|
||||||
if (firstAuthorizedForReadNonDefaultLocale) {
|
|
||||||
return firstAuthorizedForReadNonDefaultLocale;
|
|
||||||
}
|
|
||||||
|
|
||||||
return getFirstLocale(createPermissions);
|
|
||||||
};
|
|
||||||
|
|
||||||
export default getDefaultLocale;
|
|
||||||
@ -1,14 +0,0 @@
|
|||||||
import getLocaleFromQuery from './getLocaleFromQuery';
|
|
||||||
|
|
||||||
const getInitialLocale = (query: any, locales: any = []) => {
|
|
||||||
const localeFromQuery = getLocaleFromQuery(query);
|
|
||||||
|
|
||||||
if (localeFromQuery) {
|
|
||||||
return locales.find((locale: any) => locale.code === localeFromQuery);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Returns the default locale when nothing is in the query
|
|
||||||
return locales.find((locale: any) => locale.isDefault);
|
|
||||||
};
|
|
||||||
|
|
||||||
export default getInitialLocale;
|
|
||||||
@ -1,7 +0,0 @@
|
|||||||
import get from 'lodash/get';
|
|
||||||
|
|
||||||
const getLocaleFromQuery = (query: any) => {
|
|
||||||
return get(query, 'plugins.i18n.locale', undefined);
|
|
||||||
};
|
|
||||||
|
|
||||||
export default getLocaleFromQuery;
|
|
||||||
76
packages/plugins/i18n/admin/src/utils/locales.ts
Normal file
76
packages/plugins/i18n/admin/src/utils/locales.ts
Normal file
@ -0,0 +1,76 @@
|
|||||||
|
import { Locale, RootState } from '../store/reducers';
|
||||||
|
|
||||||
|
interface PotentialQueryWithLocale {
|
||||||
|
plugins?: { i18n?: { locale?: string; [key: string]: unknown }; [key: string]: unknown };
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the locale from the passed query.
|
||||||
|
* If a default value is passed, it will return it if the locale does not exist.
|
||||||
|
*/
|
||||||
|
function getLocaleFromQuery(query: PotentialQueryWithLocale): string | undefined;
|
||||||
|
function getLocaleFromQuery(query: PotentialQueryWithLocale, defaultValue: string): string;
|
||||||
|
function getLocaleFromQuery(
|
||||||
|
query: PotentialQueryWithLocale,
|
||||||
|
defaultValue?: string
|
||||||
|
): string | undefined {
|
||||||
|
const locale = query?.plugins?.i18n?.locale;
|
||||||
|
|
||||||
|
if (!locale && defaultValue) {
|
||||||
|
return defaultValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
return locale;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the initial locale from the query falling back to the default locale
|
||||||
|
* listed in the collection of locales provided.
|
||||||
|
*/
|
||||||
|
const getInitialLocale = (
|
||||||
|
query: PotentialQueryWithLocale,
|
||||||
|
locales: Locale[] = []
|
||||||
|
): Locale | undefined => {
|
||||||
|
const localeFromQuery = getLocaleFromQuery(query);
|
||||||
|
|
||||||
|
if (localeFromQuery) {
|
||||||
|
return locales.find((locale) => locale.code === localeFromQuery);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns the default locale when nothing is in the query
|
||||||
|
return locales.find((locale) => locale.isDefault);
|
||||||
|
};
|
||||||
|
|
||||||
|
const getDefaultLocale = (
|
||||||
|
ctPermissions: RootState['rbacProvider']['collectionTypesRelatedPermissions'][string],
|
||||||
|
locales: Locale[] = []
|
||||||
|
) => {
|
||||||
|
const defaultLocale = locales.find((locale) => locale.isDefault);
|
||||||
|
|
||||||
|
if (!defaultLocale) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
const readPermissions = ctPermissions['plugin::content-manager.explorer.read'] ?? [];
|
||||||
|
const createPermissions = ctPermissions['plugin::content-manager.explorer.create'] ?? [];
|
||||||
|
|
||||||
|
if (
|
||||||
|
readPermissions.some(({ properties }) =>
|
||||||
|
(properties?.locales ?? []).includes(defaultLocale.code)
|
||||||
|
) ||
|
||||||
|
createPermissions.some(({ properties }) =>
|
||||||
|
(properties?.locales ?? []).includes(defaultLocale.code)
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
return defaultLocale.code;
|
||||||
|
}
|
||||||
|
|
||||||
|
// When the default locale is not authorized, we return the first authorized locale
|
||||||
|
return (
|
||||||
|
(readPermissions[0]?.properties?.locales?.[0] ||
|
||||||
|
createPermissions[0]?.properties?.locales?.[0]) ??
|
||||||
|
null
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export { getLocaleFromQuery, getInitialLocale, getDefaultLocale };
|
||||||
@ -1,337 +0,0 @@
|
|||||||
import getDefaultLocale from '../getDefaultLocale';
|
|
||||||
|
|
||||||
describe('getDefaultLocale', () => {
|
|
||||||
it('gives fr-FR when it s the default locale and that it has read access to it', () => {
|
|
||||||
const locales = [
|
|
||||||
{
|
|
||||||
id: 1,
|
|
||||||
name: 'English',
|
|
||||||
code: 'en',
|
|
||||||
createdAt: '2021-03-09T14:57:03.016Z',
|
|
||||||
updatedAt: '2021-03-09T14:57:03.016Z',
|
|
||||||
isDefault: false,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 2,
|
|
||||||
name: 'French (France) (fr-FR)',
|
|
||||||
code: 'fr-FR',
|
|
||||||
createdAt: '2021-03-09T15:03:06.992Z',
|
|
||||||
updatedAt: '2021-03-17T13:01:03.569Z',
|
|
||||||
isDefault: true,
|
|
||||||
},
|
|
||||||
];
|
|
||||||
|
|
||||||
const ctPermissions = {
|
|
||||||
'plugin::content-manager.explorer.create': [
|
|
||||||
{
|
|
||||||
id: 1325,
|
|
||||||
action: 'plugin::content-manager.explorer.create',
|
|
||||||
subject: 'api::address.address',
|
|
||||||
properties: {
|
|
||||||
fields: [
|
|
||||||
'postal_coder',
|
|
||||||
'categories',
|
|
||||||
'cover',
|
|
||||||
'images',
|
|
||||||
'city',
|
|
||||||
'likes',
|
|
||||||
'json',
|
|
||||||
'slug',
|
|
||||||
],
|
|
||||||
locales: [],
|
|
||||||
},
|
|
||||||
conditions: [],
|
|
||||||
},
|
|
||||||
],
|
|
||||||
'plugin::content-manager.explorer.read': [
|
|
||||||
{
|
|
||||||
id: 1326,
|
|
||||||
action: 'plugin::content-manager.explorer.read',
|
|
||||||
subject: 'api::address.address',
|
|
||||||
properties: {
|
|
||||||
fields: [],
|
|
||||||
locales: ['en', 'fr-FR'],
|
|
||||||
},
|
|
||||||
conditions: [],
|
|
||||||
},
|
|
||||||
],
|
|
||||||
};
|
|
||||||
|
|
||||||
const expected = 'fr-FR';
|
|
||||||
const actual = getDefaultLocale(ctPermissions, locales);
|
|
||||||
|
|
||||||
expect(actual).toEqual(expected);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('gives fr-FR when it s the default locale and that it has create access to it', () => {
|
|
||||||
const locales = [
|
|
||||||
{
|
|
||||||
id: 1,
|
|
||||||
name: 'English',
|
|
||||||
code: 'en',
|
|
||||||
createdAt: '2021-03-09T14:57:03.016Z',
|
|
||||||
updatedAt: '2021-03-09T14:57:03.016Z',
|
|
||||||
isDefault: false,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 2,
|
|
||||||
name: 'French (France) (fr-FR)',
|
|
||||||
code: 'fr-FR',
|
|
||||||
createdAt: '2021-03-09T15:03:06.992Z',
|
|
||||||
updatedAt: '2021-03-17T13:01:03.569Z',
|
|
||||||
isDefault: true,
|
|
||||||
},
|
|
||||||
];
|
|
||||||
|
|
||||||
const ctPermissions = {
|
|
||||||
'plugin::content-manager.explorer.create': [
|
|
||||||
{
|
|
||||||
id: 1325,
|
|
||||||
action: 'plugin::content-manager.explorer.create',
|
|
||||||
subject: 'api::address.address',
|
|
||||||
properties: {
|
|
||||||
fields: [
|
|
||||||
'postal_coder',
|
|
||||||
'categories',
|
|
||||||
'cover',
|
|
||||||
'images',
|
|
||||||
'city',
|
|
||||||
'likes',
|
|
||||||
'json',
|
|
||||||
'slug',
|
|
||||||
],
|
|
||||||
locales: ['fr-FR'],
|
|
||||||
},
|
|
||||||
conditions: [],
|
|
||||||
},
|
|
||||||
],
|
|
||||||
'plugin::content-manager.explorer.read': [
|
|
||||||
{
|
|
||||||
id: 1326,
|
|
||||||
action: 'plugin::content-manager.explorer.read',
|
|
||||||
subject: 'api::address.address',
|
|
||||||
properties: {
|
|
||||||
fields: [],
|
|
||||||
locales: ['en'],
|
|
||||||
},
|
|
||||||
conditions: [],
|
|
||||||
},
|
|
||||||
],
|
|
||||||
};
|
|
||||||
|
|
||||||
const expected = 'fr-FR';
|
|
||||||
const actual = getDefaultLocale(ctPermissions, locales);
|
|
||||||
|
|
||||||
expect(actual).toEqual(expected);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('gives gives the first locale with read permission ("en") when the locale is allowed', () => {
|
|
||||||
const locales = [
|
|
||||||
{
|
|
||||||
id: 1,
|
|
||||||
name: 'English',
|
|
||||||
code: 'en',
|
|
||||||
createdAt: '2021-03-09T14:57:03.016Z',
|
|
||||||
updatedAt: '2021-03-09T14:57:03.016Z',
|
|
||||||
isDefault: false,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 2,
|
|
||||||
name: 'French (France) (fr-FR)',
|
|
||||||
code: 'fr-FR',
|
|
||||||
createdAt: '2021-03-09T15:03:06.992Z',
|
|
||||||
updatedAt: '2021-03-17T13:01:03.569Z',
|
|
||||||
isDefault: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 3,
|
|
||||||
name: 'Another lang',
|
|
||||||
code: 'de',
|
|
||||||
createdAt: '2021-03-09T15:03:06.992Z',
|
|
||||||
updatedAt: '2021-03-17T13:01:03.569Z',
|
|
||||||
isDefault: false,
|
|
||||||
},
|
|
||||||
];
|
|
||||||
|
|
||||||
const ctPermissions = {
|
|
||||||
'plugin::content-manager.explorer.create': [
|
|
||||||
{
|
|
||||||
id: 1325,
|
|
||||||
action: 'plugin::content-manager.explorer.create',
|
|
||||||
subject: 'api::address.address',
|
|
||||||
properties: {
|
|
||||||
fields: [
|
|
||||||
'postal_coder',
|
|
||||||
'categories',
|
|
||||||
'cover',
|
|
||||||
'images',
|
|
||||||
'city',
|
|
||||||
'likes',
|
|
||||||
'json',
|
|
||||||
'slug',
|
|
||||||
],
|
|
||||||
locales: [],
|
|
||||||
},
|
|
||||||
conditions: [],
|
|
||||||
},
|
|
||||||
],
|
|
||||||
'plugin::content-manager.explorer.read': [
|
|
||||||
{
|
|
||||||
id: 1326,
|
|
||||||
action: 'plugin::content-manager.explorer.read',
|
|
||||||
subject: 'api::address.address',
|
|
||||||
properties: {
|
|
||||||
fields: [],
|
|
||||||
locales: ['en', 'de'],
|
|
||||||
},
|
|
||||||
conditions: [],
|
|
||||||
},
|
|
||||||
],
|
|
||||||
};
|
|
||||||
|
|
||||||
const expected = 'en';
|
|
||||||
const actual = getDefaultLocale(ctPermissions, locales);
|
|
||||||
|
|
||||||
expect(actual).toEqual(expected);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('gives gives the first locale with create permission ("en") when the locale is allowed', () => {
|
|
||||||
const locales = [
|
|
||||||
{
|
|
||||||
id: 1,
|
|
||||||
name: 'English',
|
|
||||||
code: 'en',
|
|
||||||
createdAt: '2021-03-09T14:57:03.016Z',
|
|
||||||
updatedAt: '2021-03-09T14:57:03.016Z',
|
|
||||||
isDefault: false,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 2,
|
|
||||||
name: 'French (France) (fr-FR)',
|
|
||||||
code: 'fr-FR',
|
|
||||||
createdAt: '2021-03-09T15:03:06.992Z',
|
|
||||||
updatedAt: '2021-03-17T13:01:03.569Z',
|
|
||||||
isDefault: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 3,
|
|
||||||
name: 'Another lang',
|
|
||||||
code: 'de',
|
|
||||||
createdAt: '2021-03-09T15:03:06.992Z',
|
|
||||||
updatedAt: '2021-03-17T13:01:03.569Z',
|
|
||||||
isDefault: false,
|
|
||||||
},
|
|
||||||
];
|
|
||||||
|
|
||||||
const ctPermissions = {
|
|
||||||
'plugin::content-manager.explorer.create': [
|
|
||||||
{
|
|
||||||
id: 1325,
|
|
||||||
action: 'plugin::content-manager.explorer.create',
|
|
||||||
subject: 'api::address.address',
|
|
||||||
properties: {
|
|
||||||
fields: [
|
|
||||||
'postal_coder',
|
|
||||||
'categories',
|
|
||||||
'cover',
|
|
||||||
'images',
|
|
||||||
'city',
|
|
||||||
'likes',
|
|
||||||
'json',
|
|
||||||
'slug',
|
|
||||||
],
|
|
||||||
locales: ['en', 'de'],
|
|
||||||
},
|
|
||||||
conditions: [],
|
|
||||||
},
|
|
||||||
],
|
|
||||||
'plugin::content-manager.explorer.read': [
|
|
||||||
{
|
|
||||||
id: 1326,
|
|
||||||
action: 'plugin::content-manager.explorer.read',
|
|
||||||
subject: 'api::address.address',
|
|
||||||
properties: {
|
|
||||||
fields: [],
|
|
||||||
locales: [],
|
|
||||||
},
|
|
||||||
conditions: [],
|
|
||||||
},
|
|
||||||
],
|
|
||||||
};
|
|
||||||
|
|
||||||
const expected = 'en';
|
|
||||||
const actual = getDefaultLocale(ctPermissions, locales);
|
|
||||||
|
|
||||||
expect(actual).toEqual(expected);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('gives null when the user has no permission on any locale', () => {
|
|
||||||
const locales = [
|
|
||||||
{
|
|
||||||
id: 1,
|
|
||||||
name: 'English',
|
|
||||||
code: 'en',
|
|
||||||
createdAt: '2021-03-09T14:57:03.016Z',
|
|
||||||
updatedAt: '2021-03-09T14:57:03.016Z',
|
|
||||||
isDefault: false,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 2,
|
|
||||||
name: 'French (France) (fr-FR)',
|
|
||||||
code: 'fr-FR',
|
|
||||||
createdAt: '2021-03-09T15:03:06.992Z',
|
|
||||||
updatedAt: '2021-03-17T13:01:03.569Z',
|
|
||||||
isDefault: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 3,
|
|
||||||
name: 'Another lang',
|
|
||||||
code: 'de',
|
|
||||||
createdAt: '2021-03-09T15:03:06.992Z',
|
|
||||||
updatedAt: '2021-03-17T13:01:03.569Z',
|
|
||||||
isDefault: false,
|
|
||||||
},
|
|
||||||
];
|
|
||||||
|
|
||||||
const ctPermissions = {
|
|
||||||
'plugin::content-manager.explorer.create': [
|
|
||||||
{
|
|
||||||
id: 1325,
|
|
||||||
action: 'plugin::content-manager.explorer.create',
|
|
||||||
subject: 'api::address.address',
|
|
||||||
properties: {
|
|
||||||
fields: [
|
|
||||||
'postal_coder',
|
|
||||||
'categories',
|
|
||||||
'cover',
|
|
||||||
'images',
|
|
||||||
'city',
|
|
||||||
'likes',
|
|
||||||
'json',
|
|
||||||
'slug',
|
|
||||||
],
|
|
||||||
locales: [],
|
|
||||||
},
|
|
||||||
conditions: [],
|
|
||||||
},
|
|
||||||
],
|
|
||||||
'plugin::content-manager.explorer.read': [
|
|
||||||
{
|
|
||||||
id: 1326,
|
|
||||||
action: 'plugin::content-manager.explorer.read',
|
|
||||||
subject: 'api::address.address',
|
|
||||||
properties: {
|
|
||||||
fields: [],
|
|
||||||
locales: [],
|
|
||||||
},
|
|
||||||
conditions: [],
|
|
||||||
},
|
|
||||||
],
|
|
||||||
};
|
|
||||||
|
|
||||||
const expected = null;
|
|
||||||
const actual = getDefaultLocale(ctPermissions, locales);
|
|
||||||
|
|
||||||
expect(actual).toEqual(expected);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
@ -1,106 +0,0 @@
|
|||||||
import getInitialLocale from '../getInitialLocale';
|
|
||||||
|
|
||||||
describe('getInitialLocale', () => {
|
|
||||||
it('gives "fr-FR" when the query.plugins.locale is "fr-FR"', () => {
|
|
||||||
const query = {
|
|
||||||
page: '1',
|
|
||||||
pageSize: '10',
|
|
||||||
sort: 'Name:ASC',
|
|
||||||
plugins: {
|
|
||||||
i18n: { locale: 'fr-FR' },
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
const locales = [
|
|
||||||
{
|
|
||||||
id: 1,
|
|
||||||
name: 'English',
|
|
||||||
code: 'en',
|
|
||||||
createdAt: '2021-03-09T14:57:03.016Z',
|
|
||||||
updatedAt: '2021-03-09T14:57:03.016Z',
|
|
||||||
isDefault: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 2,
|
|
||||||
name: 'French (France) (fr-FR)',
|
|
||||||
code: 'fr-FR',
|
|
||||||
createdAt: '2021-03-09T15:03:06.992Z',
|
|
||||||
updatedAt: '2021-03-09T15:03:06.996Z',
|
|
||||||
isDefault: false,
|
|
||||||
},
|
|
||||||
];
|
|
||||||
|
|
||||||
const expected = {
|
|
||||||
id: 2,
|
|
||||||
name: 'French (France) (fr-FR)',
|
|
||||||
code: 'fr-FR',
|
|
||||||
createdAt: '2021-03-09T15:03:06.992Z',
|
|
||||||
updatedAt: '2021-03-09T15:03:06.996Z',
|
|
||||||
isDefault: false,
|
|
||||||
};
|
|
||||||
const actual = getInitialLocale(query, locales);
|
|
||||||
|
|
||||||
expect(actual).toEqual(expected);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('gives the default locale ("en") when there s no locale in the query', () => {
|
|
||||||
const query = {
|
|
||||||
page: '1',
|
|
||||||
pageSize: '10',
|
|
||||||
sort: 'Name:ASC',
|
|
||||||
plugins: {
|
|
||||||
something: 'great',
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
const locales = [
|
|
||||||
{
|
|
||||||
id: 2,
|
|
||||||
name: 'French (France) (fr-FR)',
|
|
||||||
code: 'fr-FR',
|
|
||||||
createdAt: '2021-03-09T15:03:06.992Z',
|
|
||||||
updatedAt: '2021-03-09T15:03:06.996Z',
|
|
||||||
isDefault: false,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 1,
|
|
||||||
name: 'English',
|
|
||||||
code: 'en',
|
|
||||||
createdAt: '2021-03-09T14:57:03.016Z',
|
|
||||||
updatedAt: '2021-03-09T14:57:03.016Z',
|
|
||||||
isDefault: true,
|
|
||||||
},
|
|
||||||
];
|
|
||||||
|
|
||||||
const expected = {
|
|
||||||
id: 1,
|
|
||||||
name: 'English',
|
|
||||||
code: 'en',
|
|
||||||
createdAt: '2021-03-09T14:57:03.016Z',
|
|
||||||
updatedAt: '2021-03-09T14:57:03.016Z',
|
|
||||||
isDefault: true,
|
|
||||||
};
|
|
||||||
|
|
||||||
const actual = getInitialLocale(query, locales);
|
|
||||||
|
|
||||||
expect(actual).toEqual(expected);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('gives "undefined" when theres no locale. IMPORTANT: such case should not exist since at least one locale is created on the backend when plug-in i18n', () => {
|
|
||||||
const query = {
|
|
||||||
page: '1',
|
|
||||||
pageSize: '10',
|
|
||||||
sort: 'Name:ASC',
|
|
||||||
plugins: {
|
|
||||||
something: 'great',
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
const locales: any = [];
|
|
||||||
|
|
||||||
const expected = undefined;
|
|
||||||
const actual = getInitialLocale(query, locales);
|
|
||||||
|
|
||||||
expect(actual).toEqual(expected);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
502
packages/plugins/i18n/admin/src/utils/tests/locales.test.ts
Normal file
502
packages/plugins/i18n/admin/src/utils/tests/locales.test.ts
Normal file
@ -0,0 +1,502 @@
|
|||||||
|
import { Locale } from '../../store/reducers';
|
||||||
|
import { getInitialLocale, getLocaleFromQuery, getDefaultLocale } from '../locales';
|
||||||
|
|
||||||
|
describe('locales', () => {
|
||||||
|
describe('getLocaleFromQuery', () => {
|
||||||
|
it('returns the locale from the query', () => {
|
||||||
|
const query = {
|
||||||
|
plugins: {
|
||||||
|
i18n: {
|
||||||
|
locale: 'en-GB',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
expect(getLocaleFromQuery(query)).toBe('en-GB');
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should return undefined if the locale doesn't exist", () => {
|
||||||
|
expect(
|
||||||
|
getLocaleFromQuery({
|
||||||
|
plugins: {
|
||||||
|
i18n: {},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
).toBe(undefined);
|
||||||
|
expect(
|
||||||
|
getLocaleFromQuery({
|
||||||
|
plugins: {},
|
||||||
|
})
|
||||||
|
).toBe(undefined);
|
||||||
|
expect(getLocaleFromQuery({})).toBe(undefined);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should return the default value if the locale does not exist', () => {
|
||||||
|
expect(
|
||||||
|
getLocaleFromQuery(
|
||||||
|
{
|
||||||
|
plugins: {
|
||||||
|
i18n: {},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
'en-GB'
|
||||||
|
)
|
||||||
|
).toBe('en-GB');
|
||||||
|
expect(
|
||||||
|
getLocaleFromQuery(
|
||||||
|
{
|
||||||
|
plugins: {},
|
||||||
|
},
|
||||||
|
'en-GB'
|
||||||
|
)
|
||||||
|
).toBe('en-GB');
|
||||||
|
expect(getLocaleFromQuery({}, 'en-GB')).toBe('en-GB');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('getInitialLocale', () => {
|
||||||
|
it('gives "fr-FR" when the query.plugins.locale is "fr-FR"', () => {
|
||||||
|
const query = {
|
||||||
|
page: '1',
|
||||||
|
pageSize: '10',
|
||||||
|
sort: 'Name:ASC',
|
||||||
|
plugins: {
|
||||||
|
i18n: { locale: 'en-GB' },
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const locales: Locale[] = [
|
||||||
|
{
|
||||||
|
id: 1,
|
||||||
|
name: 'English',
|
||||||
|
code: 'en-GB',
|
||||||
|
createdAt: '2021-03-09T14:57:03.016Z',
|
||||||
|
updatedAt: '2021-03-09T14:57:03.016Z',
|
||||||
|
isDefault: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 2,
|
||||||
|
name: 'French (France) (fr-FR)',
|
||||||
|
code: 'fr-FR',
|
||||||
|
createdAt: '2021-03-09T15:03:06.992Z',
|
||||||
|
updatedAt: '2021-03-09T15:03:06.996Z',
|
||||||
|
isDefault: false,
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
const actual = getInitialLocale(query, locales);
|
||||||
|
|
||||||
|
expect(actual).toMatchInlineSnapshot(`
|
||||||
|
{
|
||||||
|
"code": "en-GB",
|
||||||
|
"createdAt": "2021-03-09T14:57:03.016Z",
|
||||||
|
"id": 1,
|
||||||
|
"isDefault": true,
|
||||||
|
"name": "English",
|
||||||
|
"updatedAt": "2021-03-09T14:57:03.016Z",
|
||||||
|
}
|
||||||
|
`);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('gives the default locale ("en") when there s no locale in the query', () => {
|
||||||
|
const query = {
|
||||||
|
page: '1',
|
||||||
|
pageSize: '10',
|
||||||
|
sort: 'Name:ASC',
|
||||||
|
plugins: {
|
||||||
|
something: 'great',
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const locales: Locale[] = [
|
||||||
|
{
|
||||||
|
id: 2,
|
||||||
|
name: 'French (France) (fr-FR)',
|
||||||
|
code: 'fr-FR',
|
||||||
|
createdAt: '2021-03-09T15:03:06.992Z',
|
||||||
|
updatedAt: '2021-03-09T15:03:06.996Z',
|
||||||
|
isDefault: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 1,
|
||||||
|
name: 'English',
|
||||||
|
code: 'en-GB',
|
||||||
|
createdAt: '2021-03-09T14:57:03.016Z',
|
||||||
|
updatedAt: '2021-03-09T14:57:03.016Z',
|
||||||
|
isDefault: true,
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
const actual = getInitialLocale(query, locales);
|
||||||
|
|
||||||
|
expect(actual).toMatchInlineSnapshot(`
|
||||||
|
{
|
||||||
|
"code": "en-GB",
|
||||||
|
"createdAt": "2021-03-09T14:57:03.016Z",
|
||||||
|
"id": 1,
|
||||||
|
"isDefault": true,
|
||||||
|
"name": "English",
|
||||||
|
"updatedAt": "2021-03-09T14:57:03.016Z",
|
||||||
|
}
|
||||||
|
`);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('gives "undefined" when theres no locale', () => {
|
||||||
|
/**
|
||||||
|
* @note this case should not exist since at least one locale
|
||||||
|
* is created on the backend when plug-in i18n. But you can
|
||||||
|
* never trust the server.
|
||||||
|
*/
|
||||||
|
const query = {
|
||||||
|
page: '1',
|
||||||
|
pageSize: '10',
|
||||||
|
sort: 'Name:ASC',
|
||||||
|
plugins: {
|
||||||
|
something: 'great',
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const locales: Locale[] = [];
|
||||||
|
|
||||||
|
const actual = getInitialLocale(query, locales);
|
||||||
|
|
||||||
|
expect(actual).toMatchInlineSnapshot(`undefined`);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('getDefaultLocale', () => {
|
||||||
|
it('gives fr-FR when it s the default locale and that it has read access to it', () => {
|
||||||
|
const locales = [
|
||||||
|
{
|
||||||
|
id: 1,
|
||||||
|
name: 'English',
|
||||||
|
code: 'en',
|
||||||
|
createdAt: '2021-03-09T14:57:03.016Z',
|
||||||
|
updatedAt: '2021-03-09T14:57:03.016Z',
|
||||||
|
isDefault: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 2,
|
||||||
|
name: 'French (France) (fr-FR)',
|
||||||
|
code: 'fr-FR',
|
||||||
|
createdAt: '2021-03-09T15:03:06.992Z',
|
||||||
|
updatedAt: '2021-03-17T13:01:03.569Z',
|
||||||
|
isDefault: true,
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
const ctPermissions = {
|
||||||
|
'plugin::content-manager.explorer.create': [
|
||||||
|
{
|
||||||
|
id: 1325,
|
||||||
|
action: 'plugin::content-manager.explorer.create',
|
||||||
|
subject: 'api::address.address',
|
||||||
|
properties: {
|
||||||
|
fields: [
|
||||||
|
'postal_coder',
|
||||||
|
'categories',
|
||||||
|
'cover',
|
||||||
|
'images',
|
||||||
|
'city',
|
||||||
|
'likes',
|
||||||
|
'json',
|
||||||
|
'slug',
|
||||||
|
],
|
||||||
|
locales: [],
|
||||||
|
},
|
||||||
|
conditions: [],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
'plugin::content-manager.explorer.read': [
|
||||||
|
{
|
||||||
|
id: 1326,
|
||||||
|
action: 'plugin::content-manager.explorer.read',
|
||||||
|
subject: 'api::address.address',
|
||||||
|
properties: {
|
||||||
|
fields: [],
|
||||||
|
locales: ['en', 'fr-FR'],
|
||||||
|
},
|
||||||
|
conditions: [],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
|
|
||||||
|
const expected = 'fr-FR';
|
||||||
|
const actual = getDefaultLocale(ctPermissions, locales);
|
||||||
|
|
||||||
|
expect(actual).toEqual(expected);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('gives fr-FR when it s the default locale and that it has create access to it', () => {
|
||||||
|
const locales = [
|
||||||
|
{
|
||||||
|
id: 1,
|
||||||
|
name: 'English',
|
||||||
|
code: 'en',
|
||||||
|
createdAt: '2021-03-09T14:57:03.016Z',
|
||||||
|
updatedAt: '2021-03-09T14:57:03.016Z',
|
||||||
|
isDefault: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 2,
|
||||||
|
name: 'French (France) (fr-FR)',
|
||||||
|
code: 'fr-FR',
|
||||||
|
createdAt: '2021-03-09T15:03:06.992Z',
|
||||||
|
updatedAt: '2021-03-17T13:01:03.569Z',
|
||||||
|
isDefault: true,
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
const ctPermissions = {
|
||||||
|
'plugin::content-manager.explorer.create': [
|
||||||
|
{
|
||||||
|
id: 1325,
|
||||||
|
action: 'plugin::content-manager.explorer.create',
|
||||||
|
subject: 'api::address.address',
|
||||||
|
properties: {
|
||||||
|
fields: [
|
||||||
|
'postal_coder',
|
||||||
|
'categories',
|
||||||
|
'cover',
|
||||||
|
'images',
|
||||||
|
'city',
|
||||||
|
'likes',
|
||||||
|
'json',
|
||||||
|
'slug',
|
||||||
|
],
|
||||||
|
locales: ['fr-FR'],
|
||||||
|
},
|
||||||
|
conditions: [],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
'plugin::content-manager.explorer.read': [
|
||||||
|
{
|
||||||
|
id: 1326,
|
||||||
|
action: 'plugin::content-manager.explorer.read',
|
||||||
|
subject: 'api::address.address',
|
||||||
|
properties: {
|
||||||
|
fields: [],
|
||||||
|
locales: ['en'],
|
||||||
|
},
|
||||||
|
conditions: [],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
|
|
||||||
|
const expected = 'fr-FR';
|
||||||
|
const actual = getDefaultLocale(ctPermissions, locales);
|
||||||
|
|
||||||
|
expect(actual).toEqual(expected);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('gives gives the first locale with read permission ("en") when the locale is allowed', () => {
|
||||||
|
const locales = [
|
||||||
|
{
|
||||||
|
id: 1,
|
||||||
|
name: 'English',
|
||||||
|
code: 'en',
|
||||||
|
createdAt: '2021-03-09T14:57:03.016Z',
|
||||||
|
updatedAt: '2021-03-09T14:57:03.016Z',
|
||||||
|
isDefault: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 2,
|
||||||
|
name: 'French (France) (fr-FR)',
|
||||||
|
code: 'fr-FR',
|
||||||
|
createdAt: '2021-03-09T15:03:06.992Z',
|
||||||
|
updatedAt: '2021-03-17T13:01:03.569Z',
|
||||||
|
isDefault: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 3,
|
||||||
|
name: 'Another lang',
|
||||||
|
code: 'de',
|
||||||
|
createdAt: '2021-03-09T15:03:06.992Z',
|
||||||
|
updatedAt: '2021-03-17T13:01:03.569Z',
|
||||||
|
isDefault: false,
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
const ctPermissions = {
|
||||||
|
'plugin::content-manager.explorer.create': [
|
||||||
|
{
|
||||||
|
id: 1325,
|
||||||
|
action: 'plugin::content-manager.explorer.create',
|
||||||
|
subject: 'api::address.address',
|
||||||
|
properties: {
|
||||||
|
fields: [
|
||||||
|
'postal_coder',
|
||||||
|
'categories',
|
||||||
|
'cover',
|
||||||
|
'images',
|
||||||
|
'city',
|
||||||
|
'likes',
|
||||||
|
'json',
|
||||||
|
'slug',
|
||||||
|
],
|
||||||
|
locales: [],
|
||||||
|
},
|
||||||
|
conditions: [],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
'plugin::content-manager.explorer.read': [
|
||||||
|
{
|
||||||
|
id: 1326,
|
||||||
|
action: 'plugin::content-manager.explorer.read',
|
||||||
|
subject: 'api::address.address',
|
||||||
|
properties: {
|
||||||
|
fields: [],
|
||||||
|
locales: ['en', 'de'],
|
||||||
|
},
|
||||||
|
conditions: [],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
|
|
||||||
|
const expected = 'en';
|
||||||
|
const actual = getDefaultLocale(ctPermissions, locales);
|
||||||
|
|
||||||
|
expect(actual).toEqual(expected);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('gives gives the first locale with create permission ("en") when the locale is allowed', () => {
|
||||||
|
const locales = [
|
||||||
|
{
|
||||||
|
id: 1,
|
||||||
|
name: 'English',
|
||||||
|
code: 'en',
|
||||||
|
createdAt: '2021-03-09T14:57:03.016Z',
|
||||||
|
updatedAt: '2021-03-09T14:57:03.016Z',
|
||||||
|
isDefault: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 2,
|
||||||
|
name: 'French (France) (fr-FR)',
|
||||||
|
code: 'fr-FR',
|
||||||
|
createdAt: '2021-03-09T15:03:06.992Z',
|
||||||
|
updatedAt: '2021-03-17T13:01:03.569Z',
|
||||||
|
isDefault: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 3,
|
||||||
|
name: 'Another lang',
|
||||||
|
code: 'de',
|
||||||
|
createdAt: '2021-03-09T15:03:06.992Z',
|
||||||
|
updatedAt: '2021-03-17T13:01:03.569Z',
|
||||||
|
isDefault: false,
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
const ctPermissions = {
|
||||||
|
'plugin::content-manager.explorer.create': [
|
||||||
|
{
|
||||||
|
id: 1325,
|
||||||
|
action: 'plugin::content-manager.explorer.create',
|
||||||
|
subject: 'api::address.address',
|
||||||
|
properties: {
|
||||||
|
fields: [
|
||||||
|
'postal_coder',
|
||||||
|
'categories',
|
||||||
|
'cover',
|
||||||
|
'images',
|
||||||
|
'city',
|
||||||
|
'likes',
|
||||||
|
'json',
|
||||||
|
'slug',
|
||||||
|
],
|
||||||
|
locales: ['en', 'de'],
|
||||||
|
},
|
||||||
|
conditions: [],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
'plugin::content-manager.explorer.read': [
|
||||||
|
{
|
||||||
|
id: 1326,
|
||||||
|
action: 'plugin::content-manager.explorer.read',
|
||||||
|
subject: 'api::address.address',
|
||||||
|
properties: {
|
||||||
|
fields: [],
|
||||||
|
locales: [],
|
||||||
|
},
|
||||||
|
conditions: [],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
|
|
||||||
|
const expected = 'en';
|
||||||
|
const actual = getDefaultLocale(ctPermissions, locales);
|
||||||
|
|
||||||
|
expect(actual).toEqual(expected);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('gives null when the user has no permission on any locale', () => {
|
||||||
|
const locales = [
|
||||||
|
{
|
||||||
|
id: 1,
|
||||||
|
name: 'English',
|
||||||
|
code: 'en',
|
||||||
|
createdAt: '2021-03-09T14:57:03.016Z',
|
||||||
|
updatedAt: '2021-03-09T14:57:03.016Z',
|
||||||
|
isDefault: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 2,
|
||||||
|
name: 'French (France) (fr-FR)',
|
||||||
|
code: 'fr-FR',
|
||||||
|
createdAt: '2021-03-09T15:03:06.992Z',
|
||||||
|
updatedAt: '2021-03-17T13:01:03.569Z',
|
||||||
|
isDefault: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 3,
|
||||||
|
name: 'Another lang',
|
||||||
|
code: 'de',
|
||||||
|
createdAt: '2021-03-09T15:03:06.992Z',
|
||||||
|
updatedAt: '2021-03-17T13:01:03.569Z',
|
||||||
|
isDefault: false,
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
const ctPermissions = {
|
||||||
|
'plugin::content-manager.explorer.create': [
|
||||||
|
{
|
||||||
|
id: 1325,
|
||||||
|
action: 'plugin::content-manager.explorer.create',
|
||||||
|
subject: 'api::address.address',
|
||||||
|
properties: {
|
||||||
|
fields: [
|
||||||
|
'postal_coder',
|
||||||
|
'categories',
|
||||||
|
'cover',
|
||||||
|
'images',
|
||||||
|
'city',
|
||||||
|
'likes',
|
||||||
|
'json',
|
||||||
|
'slug',
|
||||||
|
],
|
||||||
|
locales: [],
|
||||||
|
},
|
||||||
|
conditions: [],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
'plugin::content-manager.explorer.read': [
|
||||||
|
{
|
||||||
|
id: 1326,
|
||||||
|
action: 'plugin::content-manager.explorer.read',
|
||||||
|
subject: 'api::address.address',
|
||||||
|
properties: {
|
||||||
|
fields: [],
|
||||||
|
locales: [],
|
||||||
|
},
|
||||||
|
conditions: [],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
|
|
||||||
|
const expected = null;
|
||||||
|
const actual = getDefaultLocale(ctPermissions, locales);
|
||||||
|
|
||||||
|
expect(actual).toEqual(expected);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
@ -219,7 +219,7 @@ const getNestedPopulateOfNonLocalizedAttributes = (modelUID: any) => {
|
|||||||
return attributesToPopulate;
|
return attributesToPopulate;
|
||||||
};
|
};
|
||||||
|
|
||||||
export default () => ({
|
const contentTypes = () => ({
|
||||||
isLocalizedContentType,
|
isLocalizedContentType,
|
||||||
getValidLocale,
|
getValidLocale,
|
||||||
getNewLocalizationsFrom,
|
getNewLocalizationsFrom,
|
||||||
@ -230,3 +230,8 @@ export default () => ({
|
|||||||
fillNonLocalizedAttributes,
|
fillNonLocalizedAttributes,
|
||||||
getNestedPopulateOfNonLocalizedAttributes,
|
getNestedPopulateOfNonLocalizedAttributes,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
type ContentTypesService = typeof contentTypes;
|
||||||
|
|
||||||
|
export default contentTypes;
|
||||||
|
export { ContentTypesService };
|
||||||
|
|||||||
@ -277,9 +277,14 @@ const addGraphqlLocalizationAction = (contentType: any) => {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
export default () => ({
|
const coreApi = () => ({
|
||||||
addCreateLocalizationAction,
|
addCreateLocalizationAction,
|
||||||
addGraphqlLocalizationAction,
|
addGraphqlLocalizationAction,
|
||||||
createSanitizer,
|
createSanitizer,
|
||||||
createCreateLocalizationHandler,
|
createCreateLocalizationHandler,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
type CoreApiService = typeof coreApi;
|
||||||
|
|
||||||
|
export default coreApi;
|
||||||
|
export { CoreApiService };
|
||||||
|
|||||||
@ -196,7 +196,12 @@ const decorator = (service: any) => ({
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
export default () => ({
|
const entityServiceDecorator = () => ({
|
||||||
decorator,
|
decorator,
|
||||||
wrapParams,
|
wrapParams,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
type EntityServiceDecoratorService = typeof entityServiceDecorator;
|
||||||
|
|
||||||
|
export default entityServiceDecorator;
|
||||||
|
export type { EntityServiceDecoratorService };
|
||||||
|
|||||||
@ -2,6 +2,11 @@ import { isoLocales } from '../constants';
|
|||||||
|
|
||||||
const getIsoLocales = () => isoLocales;
|
const getIsoLocales = () => isoLocales;
|
||||||
|
|
||||||
export default () => ({
|
const isoLocalesService = () => ({
|
||||||
getIsoLocales,
|
getIsoLocales,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
type ISOLocalesService = typeof isoLocalesService;
|
||||||
|
|
||||||
|
export default isoLocalesService;
|
||||||
|
export type { ISOLocalesService };
|
||||||
|
|||||||
@ -79,7 +79,7 @@ const deleteAllLocalizedEntriesFor = async ({ locale }: any) => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
export default () => ({
|
const locales = () => ({
|
||||||
find,
|
find,
|
||||||
findById,
|
findById,
|
||||||
findByCode,
|
findByCode,
|
||||||
@ -92,3 +92,8 @@ export default () => ({
|
|||||||
delete: deleteFn,
|
delete: deleteFn,
|
||||||
initDefaultLocale,
|
initDefaultLocale,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
type LocaleService = typeof locales;
|
||||||
|
|
||||||
|
export default locales;
|
||||||
|
export type { LocaleService };
|
||||||
|
|||||||
@ -82,8 +82,13 @@ const syncNonLocalizedAttributes = async (entry: any, { model }: any) => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
export default () => ({
|
const localizations = () => ({
|
||||||
assignDefaultLocaleToEntries,
|
assignDefaultLocaleToEntries,
|
||||||
syncLocalizations,
|
syncLocalizations,
|
||||||
syncNonLocalizedAttributes,
|
syncNonLocalizedAttributes,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
type LocalizationsService = typeof localizations;
|
||||||
|
|
||||||
|
export default localizations;
|
||||||
|
export type { LocalizationsService };
|
||||||
|
|||||||
@ -21,7 +21,12 @@ const sendDidUpdateI18nLocalesEvent = async () => {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
export default () => ({
|
const metrics = () => ({
|
||||||
sendDidInitializeEvent,
|
sendDidInitializeEvent,
|
||||||
sendDidUpdateI18nLocalesEvent,
|
sendDidUpdateI18nLocalesEvent,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
type MetricsService = typeof metrics;
|
||||||
|
|
||||||
|
export default metrics;
|
||||||
|
export type { MetricsService };
|
||||||
|
|||||||
@ -2,8 +2,13 @@ import i18nActionsService from './permissions/actions';
|
|||||||
import sectionsBuilderService from './permissions/sections-builder';
|
import sectionsBuilderService from './permissions/sections-builder';
|
||||||
import engineService from './permissions/engine';
|
import engineService from './permissions/engine';
|
||||||
|
|
||||||
export default () => ({
|
const permissions = () => ({
|
||||||
actions: i18nActionsService,
|
actions: i18nActionsService,
|
||||||
sectionsBuilder: sectionsBuilderService,
|
sectionsBuilder: sectionsBuilderService,
|
||||||
engine: engineService,
|
engine: engineService,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
type PermissionsService = typeof permissions;
|
||||||
|
|
||||||
|
export default permissions;
|
||||||
|
export type { PermissionsService };
|
||||||
|
|||||||
@ -1,21 +1,21 @@
|
|||||||
import locales from '../services/locales';
|
import type { LocaleService } from '../services/locales';
|
||||||
import permissions from '../services/permissions';
|
import type { PermissionsService } from '../services/permissions';
|
||||||
import contentTypes from '../services/content-types';
|
import type { ContentTypesService } from '../services/content-types';
|
||||||
import metrics from '../services/metrics';
|
import type { MetricsService } from '../services/metrics';
|
||||||
import entityServiceDecorator from '../services/entity-service-decorator';
|
import type { EntityServiceDecoratorService } from '../services/entity-service-decorator';
|
||||||
import coreAPI from '../services/core-api';
|
import type { CoreApiService } from '../services/core-api';
|
||||||
import ISOLocales from '../services/iso-locales';
|
import type { ISOLocalesService } from '../services/iso-locales';
|
||||||
import localizations from '../services/localizations';
|
import type { LocalizationsService } from '../services/localizations';
|
||||||
|
|
||||||
type S = {
|
type S = {
|
||||||
permissions: typeof permissions;
|
permissions: PermissionsService;
|
||||||
metrics: typeof metrics;
|
metrics: MetricsService;
|
||||||
locales: typeof locales;
|
locales: LocaleService;
|
||||||
localizations: typeof localizations;
|
localizations: LocalizationsService;
|
||||||
['iso-locales']: typeof ISOLocales;
|
['iso-locales']: ISOLocalesService;
|
||||||
['content-types']: typeof contentTypes;
|
['content-types']: ContentTypesService;
|
||||||
['entity-service-decorator']: typeof entityServiceDecorator;
|
['entity-service-decorator']: EntityServiceDecoratorService;
|
||||||
['core-api']: typeof coreAPI;
|
['core-api']: CoreApiService;
|
||||||
};
|
};
|
||||||
|
|
||||||
const getCoreStore = () => {
|
const getCoreStore = () => {
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user