@akemona-org/strapi-plugin-i18n 3.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (147) hide show
  1. package/LICENSE +22 -0
  2. package/README.md +19 -0
  3. package/admin/src/assets/images/logo.svg +1 -0
  4. package/admin/src/components/CMEditViewCopyLocale/index.js +183 -0
  5. package/admin/src/components/CMEditViewCopyLocale/utils/cleanData.js +36 -0
  6. package/admin/src/components/CMEditViewCopyLocale/utils/generateOptions.js +22 -0
  7. package/admin/src/components/CMEditViewCopyLocale/utils/index.js +2 -0
  8. package/admin/src/components/CMEditViewCopyLocale/utils/removePasswordAndRelationsFieldFromData.js +54 -0
  9. package/admin/src/components/CMEditViewCopyLocale/utils/tests/cleanData.test.js +83 -0
  10. package/admin/src/components/CMEditViewCopyLocale/utils/tests/data.js +219 -0
  11. package/admin/src/components/CMEditViewCopyLocale/utils/tests/generateOptions.test.js +79 -0
  12. package/admin/src/components/CMEditViewCopyLocale/utils/tests/removePasswordAndRelationsFieldFromData.test.js +40 -0
  13. package/admin/src/components/CMEditViewInjectedComponents/index.js +58 -0
  14. package/admin/src/components/CMEditViewLocalePicker/Option.js +66 -0
  15. package/admin/src/components/CMEditViewLocalePicker/Wrapper.js +8 -0
  16. package/admin/src/components/CMEditViewLocalePicker/index.js +160 -0
  17. package/admin/src/components/CMEditViewLocalePicker/utils/addStatusColorToLocale.js +24 -0
  18. package/admin/src/components/CMEditViewLocalePicker/utils/createLocalesOption.js +20 -0
  19. package/admin/src/components/CMEditViewLocalePicker/utils/index.js +2 -0
  20. package/admin/src/components/CheckboxConfirmation/Wrapper.js +12 -0
  21. package/admin/src/components/CheckboxConfirmation/index.js +70 -0
  22. package/admin/src/components/DeleteModalAdditionalInfos/index.js +25 -0
  23. package/admin/src/components/LocaleList/index.js +101 -0
  24. package/admin/src/components/LocaleListCell/LocaleListCell.js +90 -0
  25. package/admin/src/components/LocaleListCell/tests/LocaleListCell.test.js +128 -0
  26. package/admin/src/components/LocalePicker/index.js +126 -0
  27. package/admin/src/components/LocaleRow/index.js +77 -0
  28. package/admin/src/components/ModalCreate/AdvancedForm.js +45 -0
  29. package/admin/src/components/ModalCreate/BaseForm.js +103 -0
  30. package/admin/src/components/ModalCreate/index.js +136 -0
  31. package/admin/src/components/ModalDelete/index.js +49 -0
  32. package/admin/src/components/ModalEdit/AdvancedForm.js +51 -0
  33. package/admin/src/components/ModalEdit/BaseForm.js +91 -0
  34. package/admin/src/components/ModalEdit/index.js +122 -0
  35. package/admin/src/components/SettingsModal.js +66 -0
  36. package/admin/src/components/index.js +2 -0
  37. package/admin/src/containers/Initializer.js +31 -0
  38. package/admin/src/containers/SettingsPage/LocaleSettingsPage.js +69 -0
  39. package/admin/src/containers/SettingsPage/index.js +33 -0
  40. package/admin/src/containers/SettingsPage/tests/SettingsPage.test.js +744 -0
  41. package/admin/src/containers/SettingsPage/tests/__snapshots__/SettingsPage.test.js.snap +241 -0
  42. package/admin/src/hooks/constants.js +6 -0
  43. package/admin/src/hooks/reducers.js +63 -0
  44. package/admin/src/hooks/tests/reducers.test.js +203 -0
  45. package/admin/src/hooks/useAddLocale/index.js +60 -0
  46. package/admin/src/hooks/useContentTypePermissions/index.js +16 -0
  47. package/admin/src/hooks/useDefaultLocales/index.js +27 -0
  48. package/admin/src/hooks/useDeleteLocale/index.js +45 -0
  49. package/admin/src/hooks/useEditLocale/index.js +46 -0
  50. package/admin/src/hooks/useHasI18n/index.js +13 -0
  51. package/admin/src/hooks/useLocales/index.js +35 -0
  52. package/admin/src/index.js +169 -0
  53. package/admin/src/middlewares/addCommonFieldsToInitialDataMiddleware.js +83 -0
  54. package/admin/src/middlewares/addLocaleColumnToListViewMiddleware.js +32 -0
  55. package/admin/src/middlewares/addLocaleToCollectionTypesMiddleware.js +25 -0
  56. package/admin/src/middlewares/addLocaleToSingleTypesMiddleware.js +25 -0
  57. package/admin/src/middlewares/extendCMEditViewLayoutMiddleware.js +159 -0
  58. package/admin/src/middlewares/extendCTBAttributeInitialDataMiddleware.js +58 -0
  59. package/admin/src/middlewares/extendCTBInitialDataMiddleware.js +33 -0
  60. package/admin/src/middlewares/index.js +21 -0
  61. package/admin/src/middlewares/localePermissionMiddleware.js +39 -0
  62. package/admin/src/middlewares/tests/addCommonFieldsToInitialDataMiddleware.test.js +97 -0
  63. package/admin/src/middlewares/tests/addLocaleColumnToListViewMiddleware.test.js +68 -0
  64. package/admin/src/middlewares/tests/addLocaleToCollectionTypesMiddleware.test.js +200 -0
  65. package/admin/src/middlewares/tests/addLocaleToSingleTypesMiddleware.test.js +193 -0
  66. package/admin/src/middlewares/tests/extendCMEditViewLayoutMiddleware.test.js +556 -0
  67. package/admin/src/middlewares/tests/extendCTBAttrributeInitialDataMiddleware.test.js +124 -0
  68. package/admin/src/middlewares/tests/extendCTBInitialDataMiddleware.test.js +92 -0
  69. package/admin/src/middlewares/tests/localePermissionMiddleware.test.js +150 -0
  70. package/admin/src/middlewares/utils/addLocaleToLinksSearch.js +56 -0
  71. package/admin/src/middlewares/utils/tests/addLocaleToLinksSearch.test.js +137 -0
  72. package/admin/src/permissions.js +9 -0
  73. package/admin/src/pluginId.js +5 -0
  74. package/admin/src/schemas.js +7 -0
  75. package/admin/src/selectors/selectCollectionTypesRelatedPermissions.js +4 -0
  76. package/admin/src/selectors/selectI18nLocales.js +3 -0
  77. package/admin/src/translations/en.json +60 -0
  78. package/admin/src/translations/fr.json +9 -0
  79. package/admin/src/translations/index.js +11 -0
  80. package/admin/src/translations/zh-Hans.json +60 -0
  81. package/admin/src/utils/getDefaultLocale.js +60 -0
  82. package/admin/src/utils/getInitialLocale.js +14 -0
  83. package/admin/src/utils/getLocaleFromQuery.js +7 -0
  84. package/admin/src/utils/getTrad.js +5 -0
  85. package/admin/src/utils/index.js +2 -0
  86. package/admin/src/utils/localizedFields.js +23 -0
  87. package/admin/src/utils/mutateCTBContentTypeSchema.js +66 -0
  88. package/admin/src/utils/tests/getDefaultLocale.test.js +337 -0
  89. package/admin/src/utils/tests/getInitialLocale.test.js +106 -0
  90. package/admin/src/utils/tests/mutateCTBContentTypeSchema.test.js +205 -0
  91. package/config/functions/bootstrap.js +57 -0
  92. package/config/functions/migrations/__tests__/content-type.test.js +255 -0
  93. package/config/functions/migrations/__tests__/field.test.js +150 -0
  94. package/config/functions/migrations/content-type/disable/index.js +34 -0
  95. package/config/functions/migrations/content-type/disable/migrate-for-bookshelf.js +58 -0
  96. package/config/functions/migrations/content-type/disable/migrate-for-mongoose.js +39 -0
  97. package/config/functions/migrations/content-type/enable/index.js +40 -0
  98. package/config/functions/migrations/content-type/utils/index.js +27 -0
  99. package/config/functions/migrations/field/__tests__/utils.test.js +53 -0
  100. package/config/functions/migrations/field/index.js +37 -0
  101. package/config/functions/migrations/field/migrate-for-bookshelf.js +72 -0
  102. package/config/functions/migrations/field/migrate-for-mongoose.js +24 -0
  103. package/config/functions/migrations/field/migrate.js +55 -0
  104. package/config/functions/migrations/field/utils.js +58 -0
  105. package/config/functions/register.js +46 -0
  106. package/config/policies/validateLocaleCreation.js +68 -0
  107. package/config/routes.json +64 -0
  108. package/constants/__tests__/index.test.js +27 -0
  109. package/constants/index.js +36 -0
  110. package/constants/iso-locales.json +2002 -0
  111. package/controllers/__tests__/content-types.test.js +113 -0
  112. package/controllers/__tests__/iso-locales.test.js +26 -0
  113. package/controllers/__tests__/locales.test.js +308 -0
  114. package/controllers/content-types.js +64 -0
  115. package/controllers/iso-locales.js +11 -0
  116. package/controllers/locales.js +104 -0
  117. package/domain/locale.js +10 -0
  118. package/middlewares/i18n/defaults.json +5 -0
  119. package/middlewares/i18n/index.js +28 -0
  120. package/models/Locale.settings.json +31 -0
  121. package/oas.yml +195 -0
  122. package/package.json +31 -0
  123. package/services/__tests__/__snapshots__/iso-locales.test.js.snap +2006 -0
  124. package/services/__tests__/content-types.test.js +545 -0
  125. package/services/__tests__/core-api.test.js +106 -0
  126. package/services/__tests__/entity-service-decorator.test.js +280 -0
  127. package/services/__tests__/iso-locales.test.js +11 -0
  128. package/services/__tests__/locales.test.js +237 -0
  129. package/services/__tests__/localizations.test.js +187 -0
  130. package/services/__tests__/metrics.test.js +90 -0
  131. package/services/content-types.js +200 -0
  132. package/services/core-api.js +296 -0
  133. package/services/entity-service-decorator.js +155 -0
  134. package/services/iso-locales.js +9 -0
  135. package/services/locales.js +97 -0
  136. package/services/localizations.js +65 -0
  137. package/services/metrics.js +24 -0
  138. package/services/permissions/actions.js +124 -0
  139. package/services/permissions/engine.js +63 -0
  140. package/services/permissions/sections-builder.js +48 -0
  141. package/services/permissions.js +11 -0
  142. package/tests/content-manager/list-relation.test.e2e.js +122 -0
  143. package/tests/graphql.test.e2e.js +120 -0
  144. package/tests/locales.test.e2e.js +414 -0
  145. package/utils/index.js +20 -0
  146. package/validation/content-types.js +30 -0
  147. package/validation/locales.js +39 -0
@@ -0,0 +1,79 @@
1
+ import generateOptions from '../generateOptions';
2
+
3
+ const appLocales = [
4
+ { code: 'en', name: 'English' },
5
+ { code: 'fr', name: 'French' },
6
+ { code: 'it', name: 'Italian' },
7
+ ];
8
+
9
+ describe('I18n | Components | CMEditViewCopyLocale | utils', () => {
10
+ describe('generateOptions', () => {
11
+ it('should return an array', () => {
12
+ expect(generateOptions([])).toEqual([]);
13
+ });
14
+
15
+ it('should remove the current locale from the array', () => {
16
+ const permissions = [
17
+ { properties: { locales: [] } },
18
+ { properties: { locales: ['en', 'fr', 'it'] } },
19
+ ];
20
+ const currentLocale = 'en';
21
+ const localizations = [
22
+ { published_at: 'test', locale: 'en', id: 1 },
23
+ { published_at: 'test', locale: 'fr', id: 2 },
24
+ { published_at: 'test', locale: 'it', id: 3 },
25
+ ];
26
+
27
+ const expected = [
28
+ { label: 'French', value: 2 },
29
+ { label: 'Italian', value: 3 },
30
+ ];
31
+
32
+ expect(generateOptions(appLocales, currentLocale, localizations, permissions)).toEqual(
33
+ expected
34
+ );
35
+ });
36
+
37
+ it('should remove the locales that are not contained in the localizations array', () => {
38
+ const permissions = [
39
+ { properties: { locales: [] } },
40
+ { properties: { locales: ['en', 'fr', 'it'] } },
41
+ ];
42
+ const localizations = [
43
+ { published_at: 'test', locale: 'en', id: 1 },
44
+ { published_at: 'test', locale: 'fr', id: 2 },
45
+ ];
46
+
47
+ const expected = [
48
+ { label: 'English', value: 1 },
49
+ { label: 'French', value: 2 },
50
+ ];
51
+ const currentLocale = 'test';
52
+ expect(generateOptions(appLocales, currentLocale, localizations, permissions)).toEqual(
53
+ expected
54
+ );
55
+ });
56
+
57
+ it('should remove the locales when the user does not have the permission to read', () => {
58
+ const permissions = [
59
+ { properties: { locales: ['en'] } },
60
+ { properties: { locales: ['it'] } },
61
+ ];
62
+ const currentLocale = 'test';
63
+ const localizations = [
64
+ { published_at: 'test', locale: 'en', id: 1 },
65
+ { published_at: 'test', locale: 'fr', id: 2 },
66
+ { published_at: 'test', locale: 'it', id: 3 },
67
+ ];
68
+
69
+ const expected = [
70
+ { label: 'English', value: 1 },
71
+ { label: 'Italian', value: 3 },
72
+ ];
73
+
74
+ expect(generateOptions(appLocales, currentLocale, localizations, permissions)).toEqual(
75
+ expected
76
+ );
77
+ });
78
+ });
79
+ });
@@ -0,0 +1,40 @@
1
+ import testData from './data';
2
+ import removePasswordAndRelationsFieldFromData from '../removePasswordAndRelationsFieldFromData';
3
+
4
+ describe('I18n | Components | CMEditViewCopyLocale | utils', () => {
5
+ describe('removePasswordAndRelationsFieldFromData', () => {
6
+ it('should return an empty object', () => {
7
+ const { components, contentType } = testData;
8
+
9
+ expect(removePasswordAndRelationsFieldFromData({}, contentType, components)).toEqual({});
10
+ });
11
+
12
+ it('should return the initial data if there is no password field', () => {
13
+ const { components, contentType } = testData;
14
+
15
+ expect(
16
+ removePasswordAndRelationsFieldFromData({ name: 'test' }, contentType, components)
17
+ ).toEqual({
18
+ name: 'test',
19
+ });
20
+ });
21
+
22
+ it('should remove the password field for a simple data structure', () => {
23
+ const { components, contentType } = testData;
24
+ const data = { name: 'test', password: 'password' };
25
+ const expected = { name: 'test' };
26
+
27
+ expect(removePasswordAndRelationsFieldFromData(data, contentType, components)).toEqual(
28
+ expected
29
+ );
30
+ });
31
+
32
+ it('should remove all password fields', () => {
33
+ const { components, contentType, modifiedData, expectedModifiedData } = testData;
34
+
35
+ expect(
36
+ removePasswordAndRelationsFieldFromData(modifiedData, contentType, components)
37
+ ).toEqual(expectedModifiedData);
38
+ });
39
+ });
40
+ });
@@ -0,0 +1,58 @@
1
+ import React, { useMemo } from 'react';
2
+ import get from 'lodash/get';
3
+ import { useSelector } from 'react-redux';
4
+ import { useParams } from 'react-router-dom';
5
+ import { useContentManagerEditViewDataManager, useQueryParams } from 'strapi-helper-plugin';
6
+ import selectI18NLocales from '../../selectors/selectI18nLocales';
7
+ import useContentTypePermissions from '../../hooks/useContentTypePermissions';
8
+ import CMEditViewLocalePicker from '../CMEditViewLocalePicker';
9
+
10
+ const CMEditViewInjectedComponents = () => {
11
+ const { layout, modifiedData, slug, isSingleType } = useContentManagerEditViewDataManager();
12
+ const { createPermissions, readPermissions } = useContentTypePermissions(slug);
13
+ const locales = useSelector(selectI18NLocales);
14
+ const params = useParams();
15
+ const [{ query }, setQuery] = useQueryParams();
16
+
17
+ const id = get(params, 'id', null);
18
+ const currentEntityId = id;
19
+ const defaultLocale = locales.find(loc => loc.isDefault);
20
+ const currentLocale = get(query, 'plugins.i18n.locale', defaultLocale.code);
21
+ const hasI18nEnabled = get(layout, ['pluginOptions', 'i18n', 'localized'], false);
22
+ const hasDraftAndPublishEnabled = get(layout, ['options', 'draftAndPublish'], false);
23
+
24
+ const defaultQuery = useMemo(() => {
25
+ if (!query) {
26
+ return { plugins: { i18n: { locale: currentLocale } } };
27
+ }
28
+
29
+ return query;
30
+ }, [query, currentLocale]);
31
+
32
+ if (!hasI18nEnabled) {
33
+ return null;
34
+ }
35
+
36
+ if (!currentLocale) {
37
+ return null;
38
+ }
39
+
40
+ const localizations = get(modifiedData, 'localizations', []);
41
+
42
+ return (
43
+ <CMEditViewLocalePicker
44
+ appLocales={locales}
45
+ currentEntityId={currentEntityId}
46
+ createPermissions={createPermissions}
47
+ hasDraftAndPublishEnabled={hasDraftAndPublishEnabled}
48
+ localizations={localizations}
49
+ isSingleType={isSingleType}
50
+ query={defaultQuery}
51
+ readPermissions={readPermissions}
52
+ setQuery={setQuery}
53
+ slug={slug}
54
+ />
55
+ );
56
+ };
57
+
58
+ export default CMEditViewInjectedComponents;
@@ -0,0 +1,66 @@
1
+ import React from 'react';
2
+ import styled from 'styled-components';
3
+ import { components } from 'react-select';
4
+ import { useIntl } from 'react-intl';
5
+ import PropTypes from 'prop-types';
6
+ import get from 'lodash/get';
7
+ import { Flex, Text } from '@buffetjs/core';
8
+ import { RelationDPState } from 'strapi-helper-plugin';
9
+ import { getTrad } from '../../utils';
10
+
11
+ const TextGrow = styled(Text)`
12
+ flex-grow: 2;
13
+ `;
14
+
15
+ const statusToTitleMap = {
16
+ draft: 'content-manager.components.Select.draft-info-title',
17
+ published: 'content-manager.components.Select.publish-info-title',
18
+ 'did-not-create-locale': getTrad('components.Select.locales.not-available'),
19
+ };
20
+
21
+ const Option = props => {
22
+ const { formatMessage } = useIntl();
23
+ const Component = components.Option;
24
+ const options = get(props, ['selectProps', 'options'], {});
25
+ const currentOption = options.find(option => option.value === props.value);
26
+ const titleLabelID = statusToTitleMap[currentOption.status];
27
+ const title = formatMessage({ id: titleLabelID });
28
+ const fontWeight = props.isFocused ? 'bold' : 'regular';
29
+
30
+ return (
31
+ <Component {...props}>
32
+ <Flex>
33
+ <RelationDPState
34
+ {...currentOption}
35
+ marginLeft="0"
36
+ marginTop="1px"
37
+ marginRight="10px"
38
+ marginBottom="0"
39
+ title={title}
40
+ />
41
+
42
+ <TextGrow ellipsis as="div" fontWeight={fontWeight} title={props.label}>
43
+ {props.label}&nbsp;
44
+ </TextGrow>
45
+ </Flex>
46
+ </Component>
47
+ );
48
+ };
49
+
50
+ Option.defaultProps = {};
51
+
52
+ Option.propTypes = {
53
+ label: PropTypes.string.isRequired,
54
+ isFocused: PropTypes.bool.isRequired,
55
+ selectProps: PropTypes.shape({
56
+ options: PropTypes.arrayOf(
57
+ PropTypes.shape({
58
+ status: PropTypes.string.isRequired,
59
+ value: PropTypes.string.isRequired,
60
+ }).isRequired
61
+ ).isRequired,
62
+ }).isRequired,
63
+ value: PropTypes.string.isRequired,
64
+ };
65
+
66
+ export default Option;
@@ -0,0 +1,8 @@
1
+ import styled from 'styled-components';
2
+
3
+ const Wrapper = styled.div`
4
+ padding-bottom: ${({ paddingBottom }) => paddingBottom};
5
+ border-top: 1px solid rgba(14, 22, 34, 0.04);
6
+ `;
7
+
8
+ export default Wrapper;
@@ -0,0 +1,160 @@
1
+ import React from 'react';
2
+ import PropTypes from 'prop-types';
3
+ import { Label, Text, Padded } from '@buffetjs/core';
4
+ import get from 'lodash/get';
5
+ import Select, { components } from 'react-select';
6
+ import { useIntl } from 'react-intl';
7
+ import { useTheme } from 'styled-components';
8
+ import { DropdownIndicator, BaselineAlignment, selectStyles } from 'strapi-helper-plugin';
9
+ import { useHistory } from 'react-router-dom';
10
+ import { stringify } from 'qs';
11
+ import { getTrad } from '../../utils';
12
+ import { addStatusColorToLocale, createLocalesOption } from './utils';
13
+ import CMEditViewCopyLocale from '../CMEditViewCopyLocale';
14
+ import OptionComponent from './Option';
15
+ import Wrapper from './Wrapper';
16
+
17
+ const CMEditViewLocalePicker = ({
18
+ appLocales,
19
+ createPermissions,
20
+ currentEntityId,
21
+ hasDraftAndPublishEnabled,
22
+ isSingleType,
23
+ localizations,
24
+ query,
25
+ readPermissions,
26
+ setQuery,
27
+ slug,
28
+ }) => {
29
+ const { formatMessage } = useIntl();
30
+ const theme = useTheme();
31
+ const currentLocale = get(query, 'plugins.i18n.locale', false);
32
+ const { push } = useHistory();
33
+
34
+ const handleChange = ({ status, value, id }) => {
35
+ let defaultParams = {
36
+ plugins: {
37
+ ...query.plugins,
38
+ i18n: { ...query.plugins.i18n, locale: value },
39
+ },
40
+ };
41
+
42
+ if (currentEntityId) {
43
+ defaultParams.plugins.i18n.relatedEntityId = currentEntityId;
44
+ }
45
+
46
+ if (isSingleType) {
47
+ setQuery(defaultParams);
48
+
49
+ return;
50
+ }
51
+
52
+ if (status === 'did-not-create-locale') {
53
+ push({
54
+ pathname: `/plugins/content-manager/collectionType/${slug}/create`,
55
+ search: stringify(defaultParams, { encode: false }),
56
+ });
57
+
58
+ return;
59
+ }
60
+
61
+ push({
62
+ pathname: `/plugins/content-manager/collectionType/${slug}/${id}`,
63
+ search: stringify(defaultParams, { encode: false }),
64
+ });
65
+ };
66
+
67
+ const styles = selectStyles(theme);
68
+
69
+ const options = addStatusColorToLocale(
70
+ createLocalesOption(appLocales, localizations),
71
+ theme
72
+ ).filter(({ status, value }) => {
73
+ if (status === 'did-not-create-locale') {
74
+ return createPermissions.find(({ properties }) =>
75
+ get(properties, 'locales', []).includes(value)
76
+ );
77
+ }
78
+
79
+ return readPermissions.find(({ properties }) => get(properties, 'locales', []).includes(value));
80
+ });
81
+ const filteredOptions = options.filter(({ value }) => value !== currentLocale);
82
+ const value = options.find(({ value }) => {
83
+ return value === currentLocale;
84
+ });
85
+
86
+ const Option = hasDraftAndPublishEnabled ? OptionComponent : components.Option;
87
+ const paddingBottom = localizations.length ? '19px' : '29px';
88
+
89
+ return (
90
+ <Wrapper paddingBottom={paddingBottom}>
91
+ <BaselineAlignment top size="18px" />
92
+ <Padded left right size="smd">
93
+ <Text fontWeight="bold">
94
+ {formatMessage({ id: getTrad('plugin.name'), defaultMessage: 'Internationalization' })}
95
+ </Text>
96
+ <BaselineAlignment top size="18px" />
97
+ <span id="select-locale">
98
+ <Label htmlFor="">
99
+ {formatMessage({
100
+ id: getTrad('Settings.locales.modal.locales.label'),
101
+ })}
102
+ </Label>
103
+ </span>
104
+ <BaselineAlignment top size="3px" />
105
+ <Select
106
+ aria-labelledby="select-locale"
107
+ components={{ DropdownIndicator, Option }}
108
+ isSearchable={false}
109
+ onChange={handleChange}
110
+ options={filteredOptions}
111
+ styles={{
112
+ ...styles,
113
+ control: (base, state) => ({ ...base, ...styles.control(base, state), height: '34px' }),
114
+ indicatorsContainer: (base, state) => ({
115
+ ...base,
116
+ ...styles.indicatorsContainer(base, state),
117
+ height: '32px',
118
+ }),
119
+ valueContainer: base => ({
120
+ ...base,
121
+ padding: '2px 0px 4px 10px',
122
+ lineHeight: '18px',
123
+ }),
124
+ }}
125
+ value={value}
126
+ />
127
+ <CMEditViewCopyLocale
128
+ appLocales={appLocales}
129
+ currentLocale={currentLocale}
130
+ localizations={localizations}
131
+ readPermissions={readPermissions}
132
+ />
133
+ </Padded>
134
+ </Wrapper>
135
+ );
136
+ };
137
+
138
+ CMEditViewLocalePicker.defaultProps = {
139
+ createPermissions: [],
140
+ currentEntityId: null,
141
+ isSingleType: false,
142
+ localizations: [],
143
+ query: {},
144
+ readPermissions: [],
145
+ };
146
+
147
+ CMEditViewLocalePicker.propTypes = {
148
+ appLocales: PropTypes.array.isRequired,
149
+ createPermissions: PropTypes.array,
150
+ currentEntityId: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
151
+ hasDraftAndPublishEnabled: PropTypes.bool.isRequired,
152
+ isSingleType: PropTypes.bool,
153
+ localizations: PropTypes.array,
154
+ query: PropTypes.object,
155
+ readPermissions: PropTypes.array,
156
+ setQuery: PropTypes.func.isRequired,
157
+ slug: PropTypes.string.isRequired,
158
+ };
159
+
160
+ export default CMEditViewLocalePicker;
@@ -0,0 +1,24 @@
1
+ const addStatusColorToLocale = (locales, theme) =>
2
+ locales.map(({ status, ...rest }) => {
3
+ const statusMap = {
4
+ 'did-not-create-locale': {
5
+ backgroundColor: theme.main.colors.white,
6
+ border: `1px solid ${theme.main.colors.grey}`,
7
+ },
8
+ draft: {
9
+ backgroundColor: theme.main.colors.mediumBlue,
10
+ },
11
+ published: {
12
+ backgroundColor: theme.main.colors.green,
13
+ },
14
+ };
15
+ const props = statusMap[status];
16
+
17
+ return {
18
+ ...props,
19
+ status,
20
+ ...rest,
21
+ };
22
+ });
23
+
24
+ export default addStatusColorToLocale;
@@ -0,0 +1,20 @@
1
+ const createLocalesOption = (localesToDisplay, localesFromData) => {
2
+ return localesToDisplay.map(({ name, code }) => {
3
+ const matchingLocaleInData = localesFromData.find(({ locale }) => locale === code);
4
+
5
+ let status = 'did-not-create-locale';
6
+
7
+ if (matchingLocaleInData) {
8
+ status = matchingLocaleInData.published_at === null ? 'draft' : 'published';
9
+ }
10
+
11
+ return {
12
+ id: matchingLocaleInData ? matchingLocaleInData.id : null,
13
+ label: name,
14
+ value: code,
15
+ status,
16
+ };
17
+ });
18
+ };
19
+
20
+ export default createLocalesOption;
@@ -0,0 +1,2 @@
1
+ export { default as addStatusColorToLocale } from './addStatusColorToLocale';
2
+ export { default as createLocalesOption } from './createLocalesOption';
@@ -0,0 +1,12 @@
1
+ import styled from 'styled-components';
2
+
3
+ const Wrapper = styled.div`
4
+ position: relative;
5
+ padding-bottom: 18px;
6
+ label {
7
+ display: block;
8
+ margin-bottom: 1rem;
9
+ }
10
+ `;
11
+
12
+ export default Wrapper;
@@ -0,0 +1,70 @@
1
+ import React, { useState } from 'react';
2
+ import PropTypes from 'prop-types';
3
+ import { useIntl } from 'react-intl';
4
+ import { Checkbox, Text } from '@buffetjs/core';
5
+ import { ModalConfirm } from 'strapi-helper-plugin';
6
+ import { getTrad } from '../../utils';
7
+ import Wrapper from './Wrapper';
8
+
9
+ const CheckboxConfirmation = ({ description, isCreating, label, name, onChange, ...rest }) => {
10
+ const { formatMessage } = useIntl();
11
+ const [isOpen, setIsOpen] = useState(false);
12
+
13
+ const handleChange = e => {
14
+ if (isCreating || e.target.value) {
15
+ return onChange(e);
16
+ }
17
+
18
+ if (!e.target.value) {
19
+ return setIsOpen(true);
20
+ }
21
+
22
+ return null;
23
+ };
24
+
25
+ const handleConfirm = () => {
26
+ onChange({ target: { name, value: false, type: 'checkbox' } });
27
+ setIsOpen(false);
28
+ };
29
+
30
+ const handleToggle = () => setIsOpen(prev => !prev);
31
+
32
+ return (
33
+ <>
34
+ <Wrapper>
35
+ <Checkbox {...rest} message={label} name={name} onChange={handleChange} type="checkbox" />
36
+ {description && (
37
+ <Text color="grey" title={description} fontSize="sm" ellipsis>
38
+ {description}
39
+ </Text>
40
+ )}
41
+ </Wrapper>
42
+ <ModalConfirm
43
+ confirmButtonLabel={{ id: getTrad('CheckboxConfirmation.Modal.button-confirm') }}
44
+ content={{ id: getTrad('CheckboxConfirmation.Modal.content') }}
45
+ isOpen={isOpen}
46
+ toggle={handleToggle}
47
+ onConfirm={handleConfirm}
48
+ >
49
+ <Text fontWeight="bold">
50
+ {formatMessage({ id: getTrad('CheckboxConfirmation.Modal.body') })}
51
+ </Text>
52
+ </ModalConfirm>
53
+ </>
54
+ );
55
+ };
56
+
57
+ CheckboxConfirmation.defaultProps = {
58
+ description: null,
59
+ isCreating: false,
60
+ };
61
+
62
+ CheckboxConfirmation.propTypes = {
63
+ description: PropTypes.string,
64
+ label: PropTypes.string.isRequired,
65
+ isCreating: PropTypes.bool,
66
+ name: PropTypes.string.isRequired,
67
+ onChange: PropTypes.func.isRequired,
68
+ };
69
+
70
+ export default CheckboxConfirmation;
@@ -0,0 +1,25 @@
1
+ import * as React from 'react';
2
+ import { FormattedMessage } from 'react-intl';
3
+ import { getTrad } from '../../utils';
4
+ import useHasI18n from '../../hooks/useHasI18n';
5
+
6
+ const DeleteModalAdditionalInfos = () => {
7
+ const hasI18nEnabled = useHasI18n();
8
+
9
+ if (!hasI18nEnabled) {
10
+ return null;
11
+ }
12
+
13
+ return (
14
+ <span>
15
+ <FormattedMessage
16
+ id={getTrad('Settings.list.actions.deleteAdditionalInfos')}
17
+ values={{
18
+ em: chunks => <em>{chunks}</em>,
19
+ }}
20
+ />
21
+ </span>
22
+ );
23
+ };
24
+
25
+ export default DeleteModalAdditionalInfos;
@@ -0,0 +1,101 @@
1
+ import React, { useState } from 'react';
2
+ import { useIntl } from 'react-intl';
3
+ import { EmptyState, ListButton } from 'strapi-helper-plugin';
4
+ import { List } from '@buffetjs/custom';
5
+ import { Button } from '@buffetjs/core';
6
+ import { Plus } from '@buffetjs/icons';
7
+ import PropTypes from 'prop-types';
8
+ import useLocales from '../../hooks/useLocales';
9
+ import LocaleRow from '../LocaleRow';
10
+ import { getTrad } from '../../utils';
11
+ import ModalEdit from '../ModalEdit';
12
+ import ModalDelete from '../ModalDelete';
13
+ import ModalCreate from '../ModalCreate';
14
+
15
+ const LocaleList = ({ canUpdateLocale, canDeleteLocale, onToggleCreateModal, isCreating }) => {
16
+ const [localeToDelete, setLocaleToDelete] = useState();
17
+ const [localeToEdit, setLocaleToEdit] = useState();
18
+ const { locales, isLoading } = useLocales();
19
+ const { formatMessage } = useIntl();
20
+
21
+ // Delete actions
22
+ const closeModalToDelete = () => setLocaleToDelete(undefined);
23
+ const handleDeleteLocale = canDeleteLocale ? setLocaleToDelete : undefined;
24
+
25
+ // Edit actions
26
+ const closeModalToEdit = () => {
27
+ setLocaleToEdit(undefined);
28
+ };
29
+ const handleEditLocale = canUpdateLocale ? setLocaleToEdit : undefined;
30
+
31
+ if (isLoading || (locales && locales.length > 0)) {
32
+ const listTitle = isLoading
33
+ ? null
34
+ : formatMessage(
35
+ {
36
+ id: getTrad(
37
+ `Settings.locales.list.title${locales.length > 1 ? '.plural' : '.singular'}`
38
+ ),
39
+ },
40
+ { number: locales.length }
41
+ );
42
+
43
+ return (
44
+ <>
45
+ <List
46
+ radius="2px"
47
+ title={listTitle}
48
+ items={locales}
49
+ isLoading={isLoading}
50
+ customRowComponent={locale => (
51
+ <LocaleRow locale={locale} onDelete={handleDeleteLocale} onEdit={handleEditLocale} />
52
+ )}
53
+ />
54
+
55
+ <ModalCreate
56
+ isOpened={isCreating}
57
+ onClose={onToggleCreateModal}
58
+ alreadyUsedLocales={locales}
59
+ />
60
+ <ModalDelete localeToDelete={localeToDelete} onClose={closeModalToDelete} />
61
+ <ModalEdit localeToEdit={localeToEdit} onClose={closeModalToEdit} locales={locales} />
62
+ </>
63
+ );
64
+ }
65
+
66
+ return (
67
+ <>
68
+ <EmptyState
69
+ title={formatMessage({ id: getTrad('Settings.list.empty.title') })}
70
+ description={formatMessage({ id: getTrad('Settings.list.empty.description') })}
71
+ />
72
+
73
+ {onToggleCreateModal && (
74
+ <ListButton>
75
+ <Button
76
+ label={formatMessage({ id: getTrad('Settings.list.actions.add') })}
77
+ onClick={onToggleCreateModal}
78
+ color="primary"
79
+ type="button"
80
+ icon={<Plus fill="#007eff" width="11px" height="11px" />}
81
+ />
82
+ </ListButton>
83
+ )}
84
+
85
+ <ModalCreate isOpened={isCreating} onClose={onToggleCreateModal} />
86
+ </>
87
+ );
88
+ };
89
+
90
+ LocaleList.defaultProps = {
91
+ onToggleCreateModal: undefined,
92
+ };
93
+
94
+ LocaleList.propTypes = {
95
+ canUpdateLocale: PropTypes.bool.isRequired,
96
+ canDeleteLocale: PropTypes.bool.isRequired,
97
+ onToggleCreateModal: PropTypes.func,
98
+ isCreating: PropTypes.bool.isRequired,
99
+ };
100
+
101
+ export default LocaleList;