@strapi/i18n 5.9.0 → 5.10.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.
- package/dist/admin/chunks/SettingsPage-B6ikxVOg.js +820 -0
- package/dist/admin/chunks/SettingsPage-B6ikxVOg.js.map +1 -0
- package/dist/admin/chunks/SettingsPage-DydtYvMJ.mjs +797 -0
- package/dist/admin/chunks/SettingsPage-DydtYvMJ.mjs.map +1 -0
- package/dist/admin/chunks/de-Cm8mYdaO.mjs +64 -0
- package/dist/admin/chunks/de-Cm8mYdaO.mjs.map +1 -0
- package/dist/admin/chunks/de-nEMWvIiY.js +66 -0
- package/dist/admin/chunks/de-nEMWvIiY.js.map +1 -0
- package/dist/admin/chunks/dk-BeUFOegB.mjs +64 -0
- package/dist/admin/chunks/dk-BeUFOegB.mjs.map +1 -0
- package/dist/admin/chunks/dk-CYATLPVe.js +66 -0
- package/dist/admin/chunks/dk-CYATLPVe.js.map +1 -0
- package/dist/admin/chunks/en-CG5cUCbD.js +81 -0
- package/dist/admin/chunks/en-CG5cUCbD.js.map +1 -0
- package/dist/admin/chunks/en-eWSaCeOb.mjs +79 -0
- package/dist/admin/chunks/en-eWSaCeOb.mjs.map +1 -0
- package/dist/admin/chunks/es-CWsogTGm.js +66 -0
- package/dist/admin/chunks/es-CWsogTGm.js.map +1 -0
- package/dist/admin/chunks/es-DqF_IdAc.mjs +64 -0
- package/dist/admin/chunks/es-DqF_IdAc.mjs.map +1 -0
- package/dist/admin/chunks/fr-CC7UFcYd.js +66 -0
- package/dist/admin/chunks/fr-CC7UFcYd.js.map +1 -0
- package/dist/admin/chunks/fr-CyARbZ3c.mjs +64 -0
- package/dist/admin/chunks/fr-CyARbZ3c.mjs.map +1 -0
- package/dist/admin/chunks/index-Dch-2xao.js +2035 -0
- package/dist/admin/chunks/index-Dch-2xao.js.map +1 -0
- package/dist/admin/chunks/index-k3BHSNs0.mjs +2006 -0
- package/dist/admin/chunks/index-k3BHSNs0.mjs.map +1 -0
- package/dist/admin/chunks/ko-Ax4NSedM.mjs +63 -0
- package/dist/admin/chunks/ko-Ax4NSedM.mjs.map +1 -0
- package/dist/admin/chunks/ko-XwGmfhoq.js +65 -0
- package/dist/admin/chunks/ko-XwGmfhoq.js.map +1 -0
- package/dist/admin/chunks/pl-B-aqvMqL.mjs +64 -0
- package/dist/admin/chunks/pl-B-aqvMqL.mjs.map +1 -0
- package/dist/admin/chunks/pl-B_vzY_ZB.js +66 -0
- package/dist/admin/chunks/pl-B_vzY_ZB.js.map +1 -0
- package/dist/admin/chunks/ru-VkPjQ-Sk.mjs +66 -0
- package/dist/admin/chunks/ru-VkPjQ-Sk.mjs.map +1 -0
- package/dist/admin/chunks/ru-WzHcJV1f.js +68 -0
- package/dist/admin/chunks/ru-WzHcJV1f.js.map +1 -0
- package/dist/admin/chunks/tr-CcWp6u3w.js +66 -0
- package/dist/admin/chunks/tr-CcWp6u3w.js.map +1 -0
- package/dist/admin/chunks/tr-DcTR88c9.mjs +64 -0
- package/dist/admin/chunks/tr-DcTR88c9.mjs.map +1 -0
- package/dist/admin/chunks/zh-C9So4SGq.js +66 -0
- package/dist/admin/chunks/zh-C9So4SGq.js.map +1 -0
- package/dist/admin/chunks/zh-Hans-DnU2bhri.js +57 -0
- package/dist/admin/chunks/zh-Hans-DnU2bhri.js.map +1 -0
- package/dist/admin/chunks/zh-Hans-L3wsRegj.mjs +55 -0
- package/dist/admin/chunks/zh-Hans-L3wsRegj.mjs.map +1 -0
- package/dist/admin/chunks/zh-RZyMiPIs.mjs +64 -0
- package/dist/admin/chunks/zh-RZyMiPIs.mjs.map +1 -0
- package/dist/admin/index.js +20 -4
- package/dist/admin/index.js.map +1 -1
- package/dist/admin/index.mjs +15 -6
- package/dist/admin/index.mjs.map +1 -1
- package/dist/admin/src/components/CMHeaderActions.d.ts +1 -1
- package/dist/admin/src/components/tests/CreateLocale.test.d.ts +1 -0
- package/dist/admin/src/components/tests/DeleteLocale.test.d.ts +1 -0
- package/dist/admin/src/components/tests/EditLocale.test.d.ts +1 -0
- package/dist/admin/src/components/tests/LocaleListCell.test.d.ts +1 -0
- package/dist/admin/src/contentReleasesHooks/releaseDetailsView.d.ts +1 -1
- package/dist/admin/src/pages/tests/SettingsPage.test.d.ts +1 -0
- package/dist/admin/tests/server.d.ts +1 -0
- package/dist/admin/tests/utils.d.ts +6 -0
- package/dist/server/index.js +3650 -3390
- package/dist/server/index.js.map +1 -1
- package/dist/server/index.mjs +3632 -3374
- package/dist/server/index.mjs.map +1 -1
- package/dist/server/src/services/localizations.d.ts +1 -1
- package/dist/server/src/services/localizations.d.ts.map +1 -1
- package/dist/shared/contracts/content-manager.d.ts +1 -1
- package/dist/shared/contracts/shared.d.ts +1 -1
- package/package.json +14 -11
- package/dist/_chunks/SettingsPage-B-KzAqT3.mjs +0 -554
- package/dist/_chunks/SettingsPage-B-KzAqT3.mjs.map +0 -1
- package/dist/_chunks/SettingsPage-hyOi94O9.js +0 -573
- package/dist/_chunks/SettingsPage-hyOi94O9.js.map +0 -1
- package/dist/_chunks/de-BOhNX_-5.js +0 -65
- package/dist/_chunks/de-BOhNX_-5.js.map +0 -1
- package/dist/_chunks/de-D80IRBP9.mjs +0 -65
- package/dist/_chunks/de-D80IRBP9.mjs.map +0 -1
- package/dist/_chunks/dk-CJ6Zzz78.mjs +0 -65
- package/dist/_chunks/dk-CJ6Zzz78.mjs.map +0 -1
- package/dist/_chunks/dk-cjXm0p3m.js +0 -65
- package/dist/_chunks/dk-cjXm0p3m.js.map +0 -1
- package/dist/_chunks/en-BTyF7WVW.mjs +0 -80
- package/dist/_chunks/en-BTyF7WVW.mjs.map +0 -1
- package/dist/_chunks/en-UlC0jh2t.js +0 -80
- package/dist/_chunks/en-UlC0jh2t.js.map +0 -1
- package/dist/_chunks/es-V8WnPN7w.mjs +0 -65
- package/dist/_chunks/es-V8WnPN7w.mjs.map +0 -1
- package/dist/_chunks/es-hr9b_HLp.js +0 -65
- package/dist/_chunks/es-hr9b_HLp.js.map +0 -1
- package/dist/_chunks/fr-BFmBbE0H.js +0 -65
- package/dist/_chunks/fr-BFmBbE0H.js.map +0 -1
- package/dist/_chunks/fr-F94noFiV.mjs +0 -65
- package/dist/_chunks/fr-F94noFiV.mjs.map +0 -1
- package/dist/_chunks/index-BcYj5jo9.mjs +0 -1589
- package/dist/_chunks/index-BcYj5jo9.mjs.map +0 -1
- package/dist/_chunks/index-C8NzsAKp.js +0 -1610
- package/dist/_chunks/index-C8NzsAKp.js.map +0 -1
- package/dist/_chunks/ko-C40pNQ9b.js +0 -64
- package/dist/_chunks/ko-C40pNQ9b.js.map +0 -1
- package/dist/_chunks/ko-CF-P3Car.mjs +0 -64
- package/dist/_chunks/ko-CF-P3Car.mjs.map +0 -1
- package/dist/_chunks/pl-Dxr9RUmD.mjs +0 -65
- package/dist/_chunks/pl-Dxr9RUmD.mjs.map +0 -1
- package/dist/_chunks/pl-JtWBy-JQ.js +0 -65
- package/dist/_chunks/pl-JtWBy-JQ.js.map +0 -1
- package/dist/_chunks/ru-B-4sVwXN.mjs +0 -67
- package/dist/_chunks/ru-B-4sVwXN.mjs.map +0 -1
- package/dist/_chunks/ru-COSWt3Nu.js +0 -67
- package/dist/_chunks/ru-COSWt3Nu.js.map +0 -1
- package/dist/_chunks/tr-BVj1O5ch.js +0 -65
- package/dist/_chunks/tr-BVj1O5ch.js.map +0 -1
- package/dist/_chunks/tr-Ccu6Yj11.mjs +0 -65
- package/dist/_chunks/tr-Ccu6Yj11.mjs.map +0 -1
- package/dist/_chunks/zh-BIz395Ms.mjs +0 -65
- package/dist/_chunks/zh-BIz395Ms.mjs.map +0 -1
- package/dist/_chunks/zh-Hans-Bfo6_TCM.mjs +0 -56
- package/dist/_chunks/zh-Hans-Bfo6_TCM.mjs.map +0 -1
- package/dist/_chunks/zh-Hans-DIEm_EMC.js +0 -56
- package/dist/_chunks/zh-Hans-DIEm_EMC.js.map +0 -1
- package/dist/_chunks/zh-wkBPBkhc.js +0 -65
- package/dist/_chunks/zh-wkBPBkhc.js.map +0 -1
@@ -0,0 +1,2006 @@
|
|
1
|
+
import get from 'lodash/get';
|
2
|
+
import * as yup from 'yup';
|
3
|
+
import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
|
4
|
+
import * as React from 'react';
|
5
|
+
import { Typography, Dialog, Field, Checkbox, Flex, Button, Modal, Box, Status, IconButton, Tooltip, SingleSelect, SingleSelectOption, VisuallyHidden, useCollator, Popover } from '@strapi/design-system';
|
6
|
+
import { WarningCircle, Pencil, CrossCircle, CheckCircle, ArrowsCounterClockwise, Trash, Plus, Download, ListPlus, Cross, Earth, CaretDown } from '@strapi/icons';
|
7
|
+
import { useIntl } from 'react-intl';
|
8
|
+
import { styled } from 'styled-components';
|
9
|
+
import { skipToken } from '@reduxjs/toolkit/query';
|
10
|
+
import { useAuth, adminApi, useTable, Table, useQueryParams, useForm, useNotification, useAPIErrorHandler } from '@strapi/admin/strapi-admin';
|
11
|
+
import { unstable_useDocument, unstable_useDocumentActions, buildValidParams } from '@strapi/content-manager/strapi-admin';
|
12
|
+
import { useParams, Link, useNavigate, matchPath } from 'react-router-dom';
|
13
|
+
import * as qs from 'qs';
|
14
|
+
import { stringify } from 'qs';
|
15
|
+
import omit from 'lodash/omit';
|
16
|
+
|
17
|
+
const pluginId = 'i18n';
|
18
|
+
|
19
|
+
const getTranslation = (id)=>`${pluginId}.${id}`;
|
20
|
+
|
21
|
+
const TextAlignTypography = styled(Typography)`
|
22
|
+
text-align: center;
|
23
|
+
`;
|
24
|
+
const CheckboxConfirmation = ({ description, isCreating = false, intlLabel, name, onChange, value })=>{
|
25
|
+
const { formatMessage } = useIntl();
|
26
|
+
const [isOpen, setIsOpen] = React.useState(false);
|
27
|
+
const handleChange = (value)=>{
|
28
|
+
if (isCreating || value) {
|
29
|
+
return onChange({
|
30
|
+
target: {
|
31
|
+
name,
|
32
|
+
value,
|
33
|
+
type: 'checkbox'
|
34
|
+
}
|
35
|
+
});
|
36
|
+
}
|
37
|
+
if (!value) {
|
38
|
+
return setIsOpen(true);
|
39
|
+
}
|
40
|
+
return null;
|
41
|
+
};
|
42
|
+
const handleConfirm = ()=>{
|
43
|
+
onChange({
|
44
|
+
target: {
|
45
|
+
name,
|
46
|
+
value: false,
|
47
|
+
type: 'checkbox'
|
48
|
+
}
|
49
|
+
});
|
50
|
+
};
|
51
|
+
const label = intlLabel.id ? formatMessage({
|
52
|
+
id: intlLabel.id,
|
53
|
+
defaultMessage: intlLabel.defaultMessage
|
54
|
+
}, {
|
55
|
+
...intlLabel.values
|
56
|
+
}) : name;
|
57
|
+
const hint = description ? formatMessage({
|
58
|
+
id: description.id,
|
59
|
+
defaultMessage: description.defaultMessage
|
60
|
+
}, {
|
61
|
+
...description.values
|
62
|
+
}) : '';
|
63
|
+
return /*#__PURE__*/ jsxs(Dialog.Root, {
|
64
|
+
open: isOpen,
|
65
|
+
onOpenChange: setIsOpen,
|
66
|
+
children: [
|
67
|
+
/*#__PURE__*/ jsxs(Field.Root, {
|
68
|
+
hint: hint,
|
69
|
+
name: name,
|
70
|
+
children: [
|
71
|
+
/*#__PURE__*/ jsx(Checkbox, {
|
72
|
+
onCheckedChange: handleChange,
|
73
|
+
checked: value,
|
74
|
+
children: label
|
75
|
+
}),
|
76
|
+
/*#__PURE__*/ jsx(Field.Hint, {})
|
77
|
+
]
|
78
|
+
}),
|
79
|
+
/*#__PURE__*/ jsxs(Dialog.Content, {
|
80
|
+
children: [
|
81
|
+
/*#__PURE__*/ jsx(Dialog.Header, {
|
82
|
+
children: formatMessage({
|
83
|
+
id: getTranslation('CheckboxConfirmation.Modal.title'),
|
84
|
+
defaultMessage: 'Disable localization'
|
85
|
+
})
|
86
|
+
}),
|
87
|
+
/*#__PURE__*/ jsx(Dialog.Body, {
|
88
|
+
icon: /*#__PURE__*/ jsx(WarningCircle, {}),
|
89
|
+
children: /*#__PURE__*/ jsxs(Flex, {
|
90
|
+
direction: "column",
|
91
|
+
alignItems: "stretch",
|
92
|
+
gap: 2,
|
93
|
+
children: [
|
94
|
+
/*#__PURE__*/ jsx(Flex, {
|
95
|
+
justifyContent: "center",
|
96
|
+
children: /*#__PURE__*/ jsx(TextAlignTypography, {
|
97
|
+
children: formatMessage({
|
98
|
+
id: getTranslation('CheckboxConfirmation.Modal.content'),
|
99
|
+
defaultMessage: 'Disabling localization will engender the deletion of all your content but the one associated to your default locale (if existing).'
|
100
|
+
})
|
101
|
+
})
|
102
|
+
}),
|
103
|
+
/*#__PURE__*/ jsx(Flex, {
|
104
|
+
justifyContent: "center",
|
105
|
+
children: /*#__PURE__*/ jsx(Typography, {
|
106
|
+
fontWeight: "semiBold",
|
107
|
+
children: formatMessage({
|
108
|
+
id: getTranslation('CheckboxConfirmation.Modal.body'),
|
109
|
+
defaultMessage: 'Do you want to disable it?'
|
110
|
+
})
|
111
|
+
})
|
112
|
+
})
|
113
|
+
]
|
114
|
+
})
|
115
|
+
}),
|
116
|
+
/*#__PURE__*/ jsxs(Dialog.Footer, {
|
117
|
+
children: [
|
118
|
+
/*#__PURE__*/ jsx(Dialog.Cancel, {
|
119
|
+
children: /*#__PURE__*/ jsx(Button, {
|
120
|
+
variant: "tertiary",
|
121
|
+
children: formatMessage({
|
122
|
+
id: 'components.popUpWarning.button.cancel',
|
123
|
+
defaultMessage: 'No, cancel'
|
124
|
+
})
|
125
|
+
})
|
126
|
+
}),
|
127
|
+
/*#__PURE__*/ jsx(Dialog.Action, {
|
128
|
+
children: /*#__PURE__*/ jsx(Button, {
|
129
|
+
variant: "danger-light",
|
130
|
+
onClick: handleConfirm,
|
131
|
+
children: formatMessage({
|
132
|
+
id: getTranslation('CheckboxConfirmation.Modal.button-confirm'),
|
133
|
+
defaultMessage: 'Yes, disable'
|
134
|
+
})
|
135
|
+
})
|
136
|
+
})
|
137
|
+
]
|
138
|
+
})
|
139
|
+
]
|
140
|
+
})
|
141
|
+
]
|
142
|
+
});
|
143
|
+
};
|
144
|
+
|
145
|
+
const LOCALIZED_FIELDS = [
|
146
|
+
'biginteger',
|
147
|
+
'boolean',
|
148
|
+
'component',
|
149
|
+
'date',
|
150
|
+
'datetime',
|
151
|
+
'decimal',
|
152
|
+
'dynamiczone',
|
153
|
+
'email',
|
154
|
+
'enumeration',
|
155
|
+
'float',
|
156
|
+
'integer',
|
157
|
+
'json',
|
158
|
+
'media',
|
159
|
+
'number',
|
160
|
+
'password',
|
161
|
+
'richtext',
|
162
|
+
'blocks',
|
163
|
+
'string',
|
164
|
+
'text',
|
165
|
+
'time'
|
166
|
+
];
|
167
|
+
const doesPluginOptionsHaveI18nLocalized = (opts)=>typeof opts === 'object' && opts !== null && 'i18n' in opts && typeof opts.i18n === 'object' && opts.i18n !== null && 'localized' in opts.i18n && typeof opts.i18n.localized === 'boolean';
|
168
|
+
|
169
|
+
const capitalize = (str)=>str.charAt(0).toUpperCase() + str.slice(1);
|
170
|
+
|
171
|
+
/**
|
172
|
+
* @alpha
|
173
|
+
* @description This hook is used to get the i18n status of a content type.
|
174
|
+
* Also returns the CRUDP permission locale properties for the content type
|
175
|
+
* so we know which locales the user can perform actions on.
|
176
|
+
*/ const useI18n = ()=>{
|
177
|
+
// Extract the params from the URL to pass to our useDocument hook
|
178
|
+
const params = useParams();
|
179
|
+
const userPermissions = useAuth('useI18n', (state)=>state.permissions);
|
180
|
+
const actions = React.useMemo(()=>{
|
181
|
+
const permissions = userPermissions.filter((permission)=>permission.subject === params.slug);
|
182
|
+
return permissions.reduce((acc, permission)=>{
|
183
|
+
const [actionShorthand] = permission.action.split('.').slice(-1);
|
184
|
+
return {
|
185
|
+
...acc,
|
186
|
+
[`can${capitalize(actionShorthand)}`]: permission.properties?.locales ?? []
|
187
|
+
};
|
188
|
+
}, {
|
189
|
+
canCreate: [],
|
190
|
+
canRead: [],
|
191
|
+
canUpdate: [],
|
192
|
+
canDelete: [],
|
193
|
+
canPublish: []
|
194
|
+
});
|
195
|
+
}, [
|
196
|
+
params.slug,
|
197
|
+
userPermissions
|
198
|
+
]);
|
199
|
+
// TODO: use specific hook to get schema only
|
200
|
+
const { schema } = unstable_useDocument({
|
201
|
+
// We can non-null assert these because below we skip the query if they are not present
|
202
|
+
collectionType: params.collectionType,
|
203
|
+
model: params.slug
|
204
|
+
}, {
|
205
|
+
skip: true
|
206
|
+
});
|
207
|
+
if (doesPluginOptionsHaveI18nLocalized(schema?.pluginOptions)) {
|
208
|
+
return {
|
209
|
+
hasI18n: schema.pluginOptions.i18n.localized,
|
210
|
+
...actions
|
211
|
+
};
|
212
|
+
}
|
213
|
+
return {
|
214
|
+
hasI18n: false,
|
215
|
+
...actions
|
216
|
+
};
|
217
|
+
};
|
218
|
+
|
219
|
+
const i18nApi = adminApi.enhanceEndpoints({
|
220
|
+
addTagTypes: [
|
221
|
+
'Locale'
|
222
|
+
]
|
223
|
+
});
|
224
|
+
|
225
|
+
const localesApi = i18nApi.injectEndpoints({
|
226
|
+
endpoints: (builder)=>({
|
227
|
+
createLocale: builder.mutation({
|
228
|
+
query: (data)=>({
|
229
|
+
url: '/i18n/locales',
|
230
|
+
method: 'POST',
|
231
|
+
data
|
232
|
+
}),
|
233
|
+
invalidatesTags: [
|
234
|
+
{
|
235
|
+
type: 'Locale',
|
236
|
+
id: 'LIST'
|
237
|
+
}
|
238
|
+
]
|
239
|
+
}),
|
240
|
+
deleteLocale: builder.mutation({
|
241
|
+
query: (id)=>({
|
242
|
+
url: `/i18n/locales/${id}`,
|
243
|
+
method: 'DELETE'
|
244
|
+
}),
|
245
|
+
invalidatesTags: (result, error, id)=>[
|
246
|
+
{
|
247
|
+
type: 'Locale',
|
248
|
+
id
|
249
|
+
}
|
250
|
+
]
|
251
|
+
}),
|
252
|
+
getLocales: builder.query({
|
253
|
+
query: ()=>'/i18n/locales',
|
254
|
+
providesTags: (res)=>[
|
255
|
+
{
|
256
|
+
type: 'Locale',
|
257
|
+
id: 'LIST'
|
258
|
+
},
|
259
|
+
...Array.isArray(res) ? res.map((locale)=>({
|
260
|
+
type: 'Locale',
|
261
|
+
id: locale.id
|
262
|
+
})) : []
|
263
|
+
]
|
264
|
+
}),
|
265
|
+
getDefaultLocales: builder.query({
|
266
|
+
query: ()=>'/i18n/iso-locales'
|
267
|
+
}),
|
268
|
+
updateLocale: builder.mutation({
|
269
|
+
query: ({ id, ...data })=>({
|
270
|
+
url: `/i18n/locales/${id}`,
|
271
|
+
method: 'PUT',
|
272
|
+
data
|
273
|
+
}),
|
274
|
+
invalidatesTags: (result, error, { id })=>[
|
275
|
+
{
|
276
|
+
type: 'Locale',
|
277
|
+
id
|
278
|
+
}
|
279
|
+
]
|
280
|
+
})
|
281
|
+
})
|
282
|
+
});
|
283
|
+
const { useCreateLocaleMutation, useDeleteLocaleMutation, useGetLocalesQuery, useGetDefaultLocalesQuery, useUpdateLocaleMutation } = localesApi;
|
284
|
+
|
285
|
+
const relationsApi = i18nApi.injectEndpoints({
|
286
|
+
overrideExisting: true,
|
287
|
+
endpoints: (builder)=>({
|
288
|
+
getManyDraftRelationCount: builder.query({
|
289
|
+
query: ({ model, ...params })=>({
|
290
|
+
url: `/content-manager/collection-types/${model}/actions/countManyEntriesDraftRelations`,
|
291
|
+
method: 'GET',
|
292
|
+
config: {
|
293
|
+
params
|
294
|
+
}
|
295
|
+
}),
|
296
|
+
transformResponse: (response)=>response.data
|
297
|
+
})
|
298
|
+
})
|
299
|
+
});
|
300
|
+
const { useGetManyDraftRelationCountQuery } = relationsApi;
|
301
|
+
|
302
|
+
const cleanData = (data, schema, components)=>{
|
303
|
+
const cleanedData = removeFields(data, [
|
304
|
+
'createdAt',
|
305
|
+
'createdBy',
|
306
|
+
'updatedAt',
|
307
|
+
'updatedBy',
|
308
|
+
'id',
|
309
|
+
'documentId',
|
310
|
+
'publishedAt',
|
311
|
+
'strapi_stage',
|
312
|
+
'strapi_assignee',
|
313
|
+
'locale',
|
314
|
+
'status'
|
315
|
+
]);
|
316
|
+
const cleanedDataWithoutPasswordAndRelation = recursiveRemoveFieldTypes(cleanedData, schema, components, [
|
317
|
+
'relation',
|
318
|
+
'password'
|
319
|
+
]);
|
320
|
+
return cleanedDataWithoutPasswordAndRelation;
|
321
|
+
};
|
322
|
+
const removeFields = (data, fields)=>{
|
323
|
+
return Object.keys(data).reduce((acc, current)=>{
|
324
|
+
if (fields.includes(current)) {
|
325
|
+
return acc;
|
326
|
+
}
|
327
|
+
acc[current] = data[current];
|
328
|
+
return acc;
|
329
|
+
}, {});
|
330
|
+
};
|
331
|
+
const recursiveRemoveFieldTypes = (data, schema, components, fields)=>{
|
332
|
+
return Object.keys(data).reduce((acc, current)=>{
|
333
|
+
const attribute = schema.attributes[current] ?? {
|
334
|
+
type: undefined
|
335
|
+
};
|
336
|
+
if (fields.includes(attribute.type)) {
|
337
|
+
return acc;
|
338
|
+
}
|
339
|
+
if (attribute.type === 'dynamiczone') {
|
340
|
+
acc[current] = data[current].map((componentValue, index)=>{
|
341
|
+
const { id: _, ...rest } = recursiveRemoveFieldTypes(componentValue, components[componentValue.__component], components, fields);
|
342
|
+
return {
|
343
|
+
...rest,
|
344
|
+
__temp_key__: index + 1
|
345
|
+
};
|
346
|
+
});
|
347
|
+
} else if (attribute.type === 'component') {
|
348
|
+
const { repeatable, component } = attribute;
|
349
|
+
if (repeatable) {
|
350
|
+
acc[current] = (data[current] ?? []).map((compoData, index)=>{
|
351
|
+
const { id: _, ...rest } = recursiveRemoveFieldTypes(compoData, components[component], components, fields);
|
352
|
+
return {
|
353
|
+
...rest,
|
354
|
+
__temp_key__: index + 1
|
355
|
+
};
|
356
|
+
});
|
357
|
+
} else {
|
358
|
+
const { id: _, ...rest } = recursiveRemoveFieldTypes(data[current] ?? {}, components[component], components, fields);
|
359
|
+
acc[current] = rest;
|
360
|
+
}
|
361
|
+
} else {
|
362
|
+
acc[current] = data[current];
|
363
|
+
}
|
364
|
+
return acc;
|
365
|
+
}, {});
|
366
|
+
};
|
367
|
+
|
368
|
+
const isErrorMessageDescriptor = (object)=>{
|
369
|
+
return typeof object === 'object' && object !== null && 'id' in object && 'defaultMessage' in object;
|
370
|
+
};
|
371
|
+
const EntryValidationText = ({ status = 'draft', validationErrors, action })=>{
|
372
|
+
const { formatMessage } = useIntl();
|
373
|
+
/**
|
374
|
+
* TODO: Should this be extracted an made into a factory to recursively get
|
375
|
+
* error messages??
|
376
|
+
*/ const getErrorStr = (key, value)=>{
|
377
|
+
if (typeof value === 'string') {
|
378
|
+
return `${key}: ${value}`;
|
379
|
+
} else if (isErrorMessageDescriptor(value)) {
|
380
|
+
return `${key}: ${formatMessage(value)}`;
|
381
|
+
} else if (Array.isArray(value)) {
|
382
|
+
return value.map((v)=>getErrorStr(key, v)).join(' ');
|
383
|
+
} else if (typeof value === 'object' && !Array.isArray(value)) {
|
384
|
+
return Object.entries(value).map(([k, v])=>getErrorStr(k, v)).join(' ');
|
385
|
+
} else {
|
386
|
+
/**
|
387
|
+
* unlikely to happen, but we need to return something
|
388
|
+
*/ return '';
|
389
|
+
}
|
390
|
+
};
|
391
|
+
if (validationErrors) {
|
392
|
+
const validationErrorsMessages = Object.entries(validationErrors).map(([key, value])=>{
|
393
|
+
return getErrorStr(key, value);
|
394
|
+
}).join(' ');
|
395
|
+
return /*#__PURE__*/ jsxs(Flex, {
|
396
|
+
gap: 2,
|
397
|
+
children: [
|
398
|
+
/*#__PURE__*/ jsx(CrossCircle, {
|
399
|
+
fill: "danger600"
|
400
|
+
}),
|
401
|
+
/*#__PURE__*/ jsx(Tooltip, {
|
402
|
+
label: validationErrorsMessages,
|
403
|
+
children: /*#__PURE__*/ jsx(Typography, {
|
404
|
+
maxWidth: '30rem',
|
405
|
+
textColor: "danger600",
|
406
|
+
variant: "omega",
|
407
|
+
fontWeight: "semiBold",
|
408
|
+
ellipsis: true,
|
409
|
+
children: validationErrorsMessages
|
410
|
+
})
|
411
|
+
})
|
412
|
+
]
|
413
|
+
});
|
414
|
+
}
|
415
|
+
const getStatusMessage = ()=>{
|
416
|
+
if (action === 'bulk-publish') {
|
417
|
+
if (status === 'published') {
|
418
|
+
return {
|
419
|
+
icon: /*#__PURE__*/ jsx(CheckCircle, {
|
420
|
+
fill: "success600"
|
421
|
+
}),
|
422
|
+
text: formatMessage({
|
423
|
+
id: 'content-manager.bulk-publish.already-published',
|
424
|
+
defaultMessage: 'Already Published'
|
425
|
+
}),
|
426
|
+
textColor: 'success600',
|
427
|
+
fontWeight: 'bold'
|
428
|
+
};
|
429
|
+
} else if (status === 'modified') {
|
430
|
+
return {
|
431
|
+
icon: /*#__PURE__*/ jsx(ArrowsCounterClockwise, {
|
432
|
+
fill: "alternative600"
|
433
|
+
}),
|
434
|
+
text: formatMessage({
|
435
|
+
id: 'app.utils.ready-to-publish-changes',
|
436
|
+
defaultMessage: 'Ready to publish changes'
|
437
|
+
})
|
438
|
+
};
|
439
|
+
} else {
|
440
|
+
return {
|
441
|
+
icon: /*#__PURE__*/ jsx(CheckCircle, {
|
442
|
+
fill: "success600"
|
443
|
+
}),
|
444
|
+
text: formatMessage({
|
445
|
+
id: 'app.utils.ready-to-publish',
|
446
|
+
defaultMessage: 'Ready to publish'
|
447
|
+
})
|
448
|
+
};
|
449
|
+
}
|
450
|
+
} else {
|
451
|
+
if (status === 'draft') {
|
452
|
+
return {
|
453
|
+
icon: /*#__PURE__*/ jsx(CheckCircle, {
|
454
|
+
fill: "success600"
|
455
|
+
}),
|
456
|
+
text: formatMessage({
|
457
|
+
id: 'content-manager.bulk-unpublish.already-unpublished',
|
458
|
+
defaultMessage: 'Already Unpublished'
|
459
|
+
}),
|
460
|
+
textColor: 'success600',
|
461
|
+
fontWeight: 'bold'
|
462
|
+
};
|
463
|
+
} else {
|
464
|
+
return {
|
465
|
+
icon: /*#__PURE__*/ jsx(CheckCircle, {
|
466
|
+
fill: "success600"
|
467
|
+
}),
|
468
|
+
text: formatMessage({
|
469
|
+
id: 'app.utils.ready-to-unpublish-changes',
|
470
|
+
defaultMessage: 'Ready to unpublish'
|
471
|
+
}),
|
472
|
+
textColor: 'success600',
|
473
|
+
fontWeight: 'bold'
|
474
|
+
};
|
475
|
+
}
|
476
|
+
}
|
477
|
+
};
|
478
|
+
const { icon, text, textColor = 'success600', fontWeight = 'normal' } = getStatusMessage();
|
479
|
+
return /*#__PURE__*/ jsxs(Flex, {
|
480
|
+
gap: 2,
|
481
|
+
children: [
|
482
|
+
icon,
|
483
|
+
/*#__PURE__*/ jsx(Typography, {
|
484
|
+
textColor: textColor,
|
485
|
+
fontWeight: fontWeight,
|
486
|
+
children: text
|
487
|
+
})
|
488
|
+
]
|
489
|
+
});
|
490
|
+
};
|
491
|
+
/* -------------------------------------------------------------------------------------------------
|
492
|
+
* BoldChunk
|
493
|
+
* -----------------------------------------------------------------------------------------------*/ const BoldChunk = (chunks)=>/*#__PURE__*/ jsx(Typography, {
|
494
|
+
fontWeight: "bold",
|
495
|
+
children: chunks
|
496
|
+
});
|
497
|
+
const BulkLocaleActionModal = ({ headers, rows, localesMetadata, validationErrors = {}, action })=>{
|
498
|
+
const { formatMessage } = useIntl();
|
499
|
+
const selectedRows = useTable('BulkLocaleActionModal', (state)=>state.selectedRows);
|
500
|
+
const getFormattedCountMessage = ()=>{
|
501
|
+
const currentStatusByLocale = rows.reduce((acc, { locale, status })=>{
|
502
|
+
acc[locale] = status;
|
503
|
+
return acc;
|
504
|
+
}, {});
|
505
|
+
const localesWithErrors = Object.keys(validationErrors);
|
506
|
+
const publishedCount = selectedRows.filter(({ locale })=>currentStatusByLocale[locale] === 'published').length;
|
507
|
+
const draftCount = selectedRows.filter(({ locale })=>(currentStatusByLocale[locale] === 'draft' || currentStatusByLocale[locale] === 'modified') && !localesWithErrors.includes(locale)).length;
|
508
|
+
const withErrorsCount = localesWithErrors.length;
|
509
|
+
const messageId = action === 'bulk-publish' ? 'content-manager.containers.list.selectedEntriesModal.selectedCount.publish' : 'content-manager.containers.list.selectedEntriesModal.selectedCount.unpublish';
|
510
|
+
const defaultMessage = action === 'bulk-publish' ? '<b>{publishedCount}</b> {publishedCount, plural, =0 {entries} one {entry} other {entries}} already published. <b>{draftCount}</b> {draftCount, plural, =0 {entries} one {entry} other {entries}} ready to publish. <b>{withErrorsCount}</b> {withErrorsCount, plural, =0 {entries} one {entry} other {entries}} waiting for action.' : '<b>{draftCount}</b> {draftCount, plural, =0 {entries} one {entry} other {entries}} already unpublished. <b>{publishedCount}</b> {publishedCount, plural, =0 {entries} one {entry} other {entries}} ready to unpublish.';
|
511
|
+
return formatMessage({
|
512
|
+
id: messageId,
|
513
|
+
defaultMessage
|
514
|
+
}, {
|
515
|
+
withErrorsCount,
|
516
|
+
draftCount,
|
517
|
+
publishedCount,
|
518
|
+
b: BoldChunk
|
519
|
+
});
|
520
|
+
};
|
521
|
+
return /*#__PURE__*/ jsxs(Modal.Body, {
|
522
|
+
children: [
|
523
|
+
/*#__PURE__*/ jsx(Typography, {
|
524
|
+
children: getFormattedCountMessage()
|
525
|
+
}),
|
526
|
+
/*#__PURE__*/ jsx(Box, {
|
527
|
+
marginTop: 5,
|
528
|
+
children: /*#__PURE__*/ jsxs(Table.Content, {
|
529
|
+
children: [
|
530
|
+
/*#__PURE__*/ jsxs(Table.Head, {
|
531
|
+
children: [
|
532
|
+
/*#__PURE__*/ jsx(Table.HeaderCheckboxCell, {}),
|
533
|
+
headers.map((head)=>/*#__PURE__*/ jsx(Table.HeaderCell, {
|
534
|
+
...head
|
535
|
+
}, head.name))
|
536
|
+
]
|
537
|
+
}),
|
538
|
+
/*#__PURE__*/ jsx(Table.Body, {
|
539
|
+
children: rows.map(({ locale, status }, index)=>{
|
540
|
+
const error = validationErrors?.[locale] ?? null;
|
541
|
+
const statusVariant = status === 'draft' ? 'primary' : status === 'published' ? 'success' : 'alternative';
|
542
|
+
return /*#__PURE__*/ jsxs(Table.Row, {
|
543
|
+
children: [
|
544
|
+
/*#__PURE__*/ jsx(Table.CheckboxCell, {
|
545
|
+
id: locale,
|
546
|
+
"aria-label": `Select ${locale}`
|
547
|
+
}),
|
548
|
+
/*#__PURE__*/ jsx(Table.Cell, {
|
549
|
+
children: /*#__PURE__*/ jsx(Typography, {
|
550
|
+
variant: "sigma",
|
551
|
+
textColor: "neutral600",
|
552
|
+
children: Array.isArray(localesMetadata) ? localesMetadata.find((localeEntry)=>localeEntry.code === locale)?.name : locale
|
553
|
+
})
|
554
|
+
}),
|
555
|
+
/*#__PURE__*/ jsx(Table.Cell, {
|
556
|
+
children: /*#__PURE__*/ jsx(Box, {
|
557
|
+
display: "flex",
|
558
|
+
children: /*#__PURE__*/ jsx(Status, {
|
559
|
+
display: "flex",
|
560
|
+
paddingLeft: "6px",
|
561
|
+
paddingRight: "6px",
|
562
|
+
paddingTop: "2px",
|
563
|
+
paddingBottom: "2px",
|
564
|
+
size: 'S',
|
565
|
+
variant: statusVariant,
|
566
|
+
children: /*#__PURE__*/ jsx(Typography, {
|
567
|
+
tag: "span",
|
568
|
+
variant: "pi",
|
569
|
+
fontWeight: "bold",
|
570
|
+
children: capitalize(status)
|
571
|
+
})
|
572
|
+
})
|
573
|
+
})
|
574
|
+
}),
|
575
|
+
/*#__PURE__*/ jsx(Table.Cell, {
|
576
|
+
children: /*#__PURE__*/ jsx(EntryValidationText, {
|
577
|
+
validationErrors: error,
|
578
|
+
status: status,
|
579
|
+
action: action
|
580
|
+
})
|
581
|
+
}),
|
582
|
+
/*#__PURE__*/ jsx(Table.Cell, {
|
583
|
+
children: /*#__PURE__*/ jsx(IconButton, {
|
584
|
+
tag: Link,
|
585
|
+
to: {
|
586
|
+
search: stringify({
|
587
|
+
plugins: {
|
588
|
+
i18n: {
|
589
|
+
locale
|
590
|
+
}
|
591
|
+
}
|
592
|
+
})
|
593
|
+
},
|
594
|
+
label: formatMessage({
|
595
|
+
id: getTranslation('Settings.list.actions.edit'),
|
596
|
+
defaultMessage: 'Edit {name} locale'
|
597
|
+
}, {
|
598
|
+
name: locale
|
599
|
+
}),
|
600
|
+
variant: "ghost",
|
601
|
+
children: /*#__PURE__*/ jsx(Pencil, {})
|
602
|
+
})
|
603
|
+
})
|
604
|
+
]
|
605
|
+
}, index);
|
606
|
+
})
|
607
|
+
})
|
608
|
+
]
|
609
|
+
})
|
610
|
+
})
|
611
|
+
]
|
612
|
+
});
|
613
|
+
};
|
614
|
+
|
615
|
+
const statusVariants = {
|
616
|
+
draft: 'secondary',
|
617
|
+
published: 'success',
|
618
|
+
modified: 'alternative'
|
619
|
+
};
|
620
|
+
const LocaleOption = ({ isDraftAndPublishEnabled, locale, status, entryExists })=>{
|
621
|
+
const { formatMessage } = useIntl();
|
622
|
+
if (!entryExists) {
|
623
|
+
return formatMessage({
|
624
|
+
id: getTranslation('CMEditViewLocalePicker.locale.create'),
|
625
|
+
defaultMessage: 'Create <bold>{locale}</bold> locale'
|
626
|
+
}, {
|
627
|
+
bold: (locale)=>/*#__PURE__*/ jsx("b", {
|
628
|
+
children: locale
|
629
|
+
}),
|
630
|
+
locale: locale.name
|
631
|
+
});
|
632
|
+
}
|
633
|
+
return /*#__PURE__*/ jsxs(Flex, {
|
634
|
+
width: "100%",
|
635
|
+
gap: 1,
|
636
|
+
justifyContent: "space-between",
|
637
|
+
children: [
|
638
|
+
/*#__PURE__*/ jsx(Typography, {
|
639
|
+
children: locale.name
|
640
|
+
}),
|
641
|
+
isDraftAndPublishEnabled ? /*#__PURE__*/ jsx(Status, {
|
642
|
+
display: "flex",
|
643
|
+
paddingLeft: "6px",
|
644
|
+
paddingRight: "6px",
|
645
|
+
paddingTop: "2px",
|
646
|
+
paddingBottom: "2px",
|
647
|
+
size: "S",
|
648
|
+
variant: statusVariants[status],
|
649
|
+
children: /*#__PURE__*/ jsx(Typography, {
|
650
|
+
tag: "span",
|
651
|
+
variant: "pi",
|
652
|
+
fontWeight: "bold",
|
653
|
+
children: capitalize(status)
|
654
|
+
})
|
655
|
+
}) : null
|
656
|
+
]
|
657
|
+
});
|
658
|
+
};
|
659
|
+
const LocalePickerAction = ({ document, meta, model, collectionType, documentId })=>{
|
660
|
+
const { formatMessage } = useIntl();
|
661
|
+
const [{ query }, setQuery] = useQueryParams();
|
662
|
+
const { hasI18n, canCreate, canRead } = useI18n();
|
663
|
+
const { data: locales = [] } = useGetLocalesQuery();
|
664
|
+
const currentDesiredLocale = query.plugins?.i18n?.locale;
|
665
|
+
const { schema } = unstable_useDocument({
|
666
|
+
model,
|
667
|
+
collectionType,
|
668
|
+
documentId,
|
669
|
+
params: {
|
670
|
+
locale: currentDesiredLocale
|
671
|
+
}
|
672
|
+
});
|
673
|
+
const handleSelect = React.useCallback((value)=>{
|
674
|
+
setQuery({
|
675
|
+
plugins: {
|
676
|
+
...query.plugins,
|
677
|
+
i18n: {
|
678
|
+
locale: value
|
679
|
+
}
|
680
|
+
}
|
681
|
+
});
|
682
|
+
}, [
|
683
|
+
query.plugins,
|
684
|
+
setQuery
|
685
|
+
]);
|
686
|
+
React.useEffect(()=>{
|
687
|
+
if (!Array.isArray(locales) || !hasI18n) {
|
688
|
+
return;
|
689
|
+
}
|
690
|
+
/**
|
691
|
+
* Handle the case where the current locale query param doesn't exist
|
692
|
+
* in the list of available locales, so we redirect to the default locale.
|
693
|
+
*/ const doesLocaleExist = locales.find((loc)=>loc.code === currentDesiredLocale);
|
694
|
+
const defaultLocale = locales.find((locale)=>locale.isDefault);
|
695
|
+
if (!doesLocaleExist && defaultLocale?.code) {
|
696
|
+
handleSelect(defaultLocale.code);
|
697
|
+
}
|
698
|
+
}, [
|
699
|
+
handleSelect,
|
700
|
+
hasI18n,
|
701
|
+
locales,
|
702
|
+
currentDesiredLocale
|
703
|
+
]);
|
704
|
+
const currentLocale = Array.isArray(locales) ? locales.find((locale)=>locale.code === currentDesiredLocale) : undefined;
|
705
|
+
const allCurrentLocales = [
|
706
|
+
{
|
707
|
+
status: getDocumentStatus(document, meta),
|
708
|
+
locale: currentLocale?.code
|
709
|
+
},
|
710
|
+
...document?.localizations ?? []
|
711
|
+
];
|
712
|
+
if (!hasI18n || !Array.isArray(locales) || locales.length === 0) {
|
713
|
+
return null;
|
714
|
+
}
|
715
|
+
const displayedLocales = locales.filter((locale)=>{
|
716
|
+
/**
|
717
|
+
* If you can read we allow you to see the locale exists
|
718
|
+
* otherwise the locale is hidden.
|
719
|
+
*/ return canRead.includes(locale.code);
|
720
|
+
});
|
721
|
+
return {
|
722
|
+
label: formatMessage({
|
723
|
+
id: getTranslation('Settings.locales.modal.locales.label'),
|
724
|
+
defaultMessage: 'Locales'
|
725
|
+
}),
|
726
|
+
options: displayedLocales.map((locale)=>{
|
727
|
+
const entryWithLocaleExists = allCurrentLocales.some((doc)=>doc.locale === locale.code);
|
728
|
+
const currentLocaleDoc = allCurrentLocales.find((doc)=>'locale' in doc ? doc.locale === locale.code : false);
|
729
|
+
const permissionsToCheck = currentLocaleDoc ? canRead : canCreate;
|
730
|
+
return {
|
731
|
+
disabled: !permissionsToCheck.includes(locale.code),
|
732
|
+
value: locale.code,
|
733
|
+
label: /*#__PURE__*/ jsx(LocaleOption, {
|
734
|
+
isDraftAndPublishEnabled: !!schema?.options?.draftAndPublish,
|
735
|
+
locale: locale,
|
736
|
+
status: currentLocaleDoc?.status,
|
737
|
+
entryExists: entryWithLocaleExists
|
738
|
+
}),
|
739
|
+
startIcon: !entryWithLocaleExists ? /*#__PURE__*/ jsx(Plus, {}) : null
|
740
|
+
};
|
741
|
+
}),
|
742
|
+
customizeContent: ()=>currentLocale?.name,
|
743
|
+
onSelect: handleSelect,
|
744
|
+
value: currentLocale
|
745
|
+
};
|
746
|
+
};
|
747
|
+
const getDocumentStatus = (document, meta)=>{
|
748
|
+
const docStatus = document?.status;
|
749
|
+
const statuses = meta?.availableStatus ?? [];
|
750
|
+
/**
|
751
|
+
* Creating an entry
|
752
|
+
*/ if (!docStatus) {
|
753
|
+
return 'draft';
|
754
|
+
}
|
755
|
+
/**
|
756
|
+
* We're viewing a draft, but the document could have a published version
|
757
|
+
*/ if (docStatus === 'draft' && statuses.find((doc)=>doc.publishedAt !== null)) {
|
758
|
+
return 'published';
|
759
|
+
}
|
760
|
+
return docStatus;
|
761
|
+
};
|
762
|
+
/* -------------------------------------------------------------------------------------------------
|
763
|
+
* FillFromAnotherLocaleAction
|
764
|
+
* -----------------------------------------------------------------------------------------------*/ const FillFromAnotherLocaleAction = ({ documentId, meta, model, collectionType })=>{
|
765
|
+
const { formatMessage } = useIntl();
|
766
|
+
const [{ query }] = useQueryParams();
|
767
|
+
const { hasI18n } = useI18n();
|
768
|
+
const currentDesiredLocale = query.plugins?.i18n?.locale;
|
769
|
+
const [localeSelected, setLocaleSelected] = React.useState(null);
|
770
|
+
const setValues = useForm('FillFromAnotherLocale', (state)=>state.setValues);
|
771
|
+
const { getDocument } = unstable_useDocumentActions();
|
772
|
+
const { schema, components } = unstable_useDocument({
|
773
|
+
model,
|
774
|
+
documentId,
|
775
|
+
collectionType,
|
776
|
+
params: {
|
777
|
+
locale: currentDesiredLocale
|
778
|
+
}
|
779
|
+
});
|
780
|
+
const { data: locales = [] } = useGetLocalesQuery();
|
781
|
+
const availableLocales = Array.isArray(locales) ? locales.filter((locale)=>meta?.availableLocales.some((l)=>l.locale === locale.code)) : [];
|
782
|
+
const fillFromLocale = (onClose)=>async ()=>{
|
783
|
+
const response = await getDocument({
|
784
|
+
collectionType,
|
785
|
+
model,
|
786
|
+
documentId,
|
787
|
+
params: {
|
788
|
+
locale: localeSelected
|
789
|
+
}
|
790
|
+
});
|
791
|
+
if (!response || !schema) {
|
792
|
+
return;
|
793
|
+
}
|
794
|
+
const { data } = response;
|
795
|
+
const cleanedData = cleanData(data, schema, components);
|
796
|
+
setValues(cleanedData);
|
797
|
+
onClose();
|
798
|
+
};
|
799
|
+
if (!hasI18n) {
|
800
|
+
return null;
|
801
|
+
}
|
802
|
+
return {
|
803
|
+
type: 'icon',
|
804
|
+
icon: /*#__PURE__*/ jsx(Download, {}),
|
805
|
+
disabled: availableLocales.length === 0,
|
806
|
+
label: formatMessage({
|
807
|
+
id: getTranslation('CMEditViewCopyLocale.copy-text'),
|
808
|
+
defaultMessage: 'Fill in from another locale'
|
809
|
+
}),
|
810
|
+
dialog: {
|
811
|
+
type: 'dialog',
|
812
|
+
title: formatMessage({
|
813
|
+
id: getTranslation('CMEditViewCopyLocale.dialog.title'),
|
814
|
+
defaultMessage: 'Confirmation'
|
815
|
+
}),
|
816
|
+
content: ({ onClose })=>/*#__PURE__*/ jsxs(Fragment, {
|
817
|
+
children: [
|
818
|
+
/*#__PURE__*/ jsx(Dialog.Body, {
|
819
|
+
children: /*#__PURE__*/ jsxs(Flex, {
|
820
|
+
direction: "column",
|
821
|
+
gap: 3,
|
822
|
+
children: [
|
823
|
+
/*#__PURE__*/ jsx(WarningCircle, {
|
824
|
+
width: "24px",
|
825
|
+
height: "24px",
|
826
|
+
fill: "danger600"
|
827
|
+
}),
|
828
|
+
/*#__PURE__*/ jsx(Typography, {
|
829
|
+
textAlign: "center",
|
830
|
+
children: formatMessage({
|
831
|
+
id: getTranslation('CMEditViewCopyLocale.dialog.body'),
|
832
|
+
defaultMessage: 'Your current content will be erased and filled by the content of the selected locale:'
|
833
|
+
})
|
834
|
+
}),
|
835
|
+
/*#__PURE__*/ jsxs(Field.Root, {
|
836
|
+
width: "100%",
|
837
|
+
children: [
|
838
|
+
/*#__PURE__*/ jsx(Field.Label, {
|
839
|
+
children: formatMessage({
|
840
|
+
id: getTranslation('CMEditViewCopyLocale.dialog.field.label'),
|
841
|
+
defaultMessage: 'Locale'
|
842
|
+
})
|
843
|
+
}),
|
844
|
+
/*#__PURE__*/ jsx(SingleSelect, {
|
845
|
+
value: localeSelected,
|
846
|
+
placeholder: formatMessage({
|
847
|
+
id: getTranslation('CMEditViewCopyLocale.dialog.field.placeholder'),
|
848
|
+
defaultMessage: 'Select one locale...'
|
849
|
+
}),
|
850
|
+
// @ts-expect-error – the DS will handle numbers, but we're not allowing the API.
|
851
|
+
onChange: (value)=>setLocaleSelected(value),
|
852
|
+
children: availableLocales.map((locale)=>/*#__PURE__*/ jsx(SingleSelectOption, {
|
853
|
+
value: locale.code,
|
854
|
+
children: locale.name
|
855
|
+
}, locale.code))
|
856
|
+
})
|
857
|
+
]
|
858
|
+
})
|
859
|
+
]
|
860
|
+
})
|
861
|
+
}),
|
862
|
+
/*#__PURE__*/ jsx(Dialog.Footer, {
|
863
|
+
children: /*#__PURE__*/ jsxs(Flex, {
|
864
|
+
gap: 2,
|
865
|
+
width: "100%",
|
866
|
+
children: [
|
867
|
+
/*#__PURE__*/ jsx(Button, {
|
868
|
+
flex: "auto",
|
869
|
+
variant: "tertiary",
|
870
|
+
onClick: onClose,
|
871
|
+
children: formatMessage({
|
872
|
+
id: getTranslation('CMEditViewCopyLocale.cancel-text'),
|
873
|
+
defaultMessage: 'No, cancel'
|
874
|
+
})
|
875
|
+
}),
|
876
|
+
/*#__PURE__*/ jsx(Button, {
|
877
|
+
flex: "auto",
|
878
|
+
variant: "success",
|
879
|
+
onClick: fillFromLocale(onClose),
|
880
|
+
children: formatMessage({
|
881
|
+
id: getTranslation('CMEditViewCopyLocale.submit-text'),
|
882
|
+
defaultMessage: 'Yes, fill in'
|
883
|
+
})
|
884
|
+
})
|
885
|
+
]
|
886
|
+
})
|
887
|
+
})
|
888
|
+
]
|
889
|
+
})
|
890
|
+
}
|
891
|
+
};
|
892
|
+
};
|
893
|
+
/* -------------------------------------------------------------------------------------------------
|
894
|
+
* DeleteLocaleAction
|
895
|
+
* -----------------------------------------------------------------------------------------------*/ const DeleteLocaleAction = ({ document, documentId, model, collectionType })=>{
|
896
|
+
const { formatMessage } = useIntl();
|
897
|
+
const navigate = useNavigate();
|
898
|
+
const { toggleNotification } = useNotification();
|
899
|
+
const { delete: deleteAction } = unstable_useDocumentActions();
|
900
|
+
const { hasI18n, canDelete } = useI18n();
|
901
|
+
// Get the current locale object, using the URL instead of document so it works while creating
|
902
|
+
const [{ query }] = useQueryParams();
|
903
|
+
const { data: locales = [] } = useGetLocalesQuery();
|
904
|
+
const currentDesiredLocale = query.plugins?.i18n?.locale;
|
905
|
+
const locale = !('error' in locales) && locales.find((loc)=>loc.code === currentDesiredLocale);
|
906
|
+
if (!hasI18n) {
|
907
|
+
return null;
|
908
|
+
}
|
909
|
+
return {
|
910
|
+
disabled: document?.locale && !canDelete.includes(document.locale) || !document || !document.id,
|
911
|
+
position: [
|
912
|
+
'header',
|
913
|
+
'table-row'
|
914
|
+
],
|
915
|
+
label: formatMessage({
|
916
|
+
id: getTranslation('actions.delete.label'),
|
917
|
+
defaultMessage: 'Delete entry ({locale})'
|
918
|
+
}, {
|
919
|
+
locale: locale && locale.name
|
920
|
+
}),
|
921
|
+
icon: /*#__PURE__*/ jsx(StyledTrash, {}),
|
922
|
+
variant: 'danger',
|
923
|
+
dialog: {
|
924
|
+
type: 'dialog',
|
925
|
+
title: formatMessage({
|
926
|
+
id: getTranslation('actions.delete.dialog.title'),
|
927
|
+
defaultMessage: 'Confirmation'
|
928
|
+
}),
|
929
|
+
content: /*#__PURE__*/ jsxs(Flex, {
|
930
|
+
direction: "column",
|
931
|
+
gap: 2,
|
932
|
+
children: [
|
933
|
+
/*#__PURE__*/ jsx(WarningCircle, {
|
934
|
+
width: "24px",
|
935
|
+
height: "24px",
|
936
|
+
fill: "danger600"
|
937
|
+
}),
|
938
|
+
/*#__PURE__*/ jsx(Typography, {
|
939
|
+
tag: "p",
|
940
|
+
variant: "omega",
|
941
|
+
textAlign: "center",
|
942
|
+
children: formatMessage({
|
943
|
+
id: getTranslation('actions.delete.dialog.body'),
|
944
|
+
defaultMessage: 'Are you sure?'
|
945
|
+
})
|
946
|
+
})
|
947
|
+
]
|
948
|
+
}),
|
949
|
+
onConfirm: async ()=>{
|
950
|
+
const unableToDelete = // We are unable to delete a collection type without a document ID
|
951
|
+
// & unable to delete generally if there is no document locale
|
952
|
+
collectionType !== 'single-types' && !documentId || !document?.locale;
|
953
|
+
if (unableToDelete) {
|
954
|
+
console.error("You're trying to delete a document without an id or locale, this is likely a bug with Strapi. Please open an issue.");
|
955
|
+
toggleNotification({
|
956
|
+
message: formatMessage({
|
957
|
+
id: getTranslation('actions.delete.error'),
|
958
|
+
defaultMessage: 'An error occurred while trying to delete the document locale.'
|
959
|
+
}),
|
960
|
+
type: 'danger'
|
961
|
+
});
|
962
|
+
return;
|
963
|
+
}
|
964
|
+
const res = await deleteAction({
|
965
|
+
documentId,
|
966
|
+
model,
|
967
|
+
collectionType,
|
968
|
+
params: {
|
969
|
+
locale: document.locale
|
970
|
+
}
|
971
|
+
});
|
972
|
+
if (!('error' in res)) {
|
973
|
+
navigate({
|
974
|
+
pathname: `../${collectionType}/${model}`
|
975
|
+
}, {
|
976
|
+
replace: true
|
977
|
+
});
|
978
|
+
}
|
979
|
+
}
|
980
|
+
}
|
981
|
+
};
|
982
|
+
};
|
983
|
+
/* -------------------------------------------------------------------------------------------------
|
984
|
+
* BulkLocaleAction
|
985
|
+
*
|
986
|
+
* This component is used to handle bulk publish and unpublish actions on locales.
|
987
|
+
* -----------------------------------------------------------------------------------------------*/ const BulkLocaleAction = ({ document, documentId, model, collectionType, action })=>{
|
988
|
+
const locale = document?.locale ?? null;
|
989
|
+
const [{ query }] = useQueryParams();
|
990
|
+
const params = React.useMemo(()=>buildValidParams(query), [
|
991
|
+
query
|
992
|
+
]);
|
993
|
+
const isOnPublishedTab = query.status === 'published';
|
994
|
+
const { formatMessage } = useIntl();
|
995
|
+
const { hasI18n, canPublish } = useI18n();
|
996
|
+
const { toggleNotification } = useNotification();
|
997
|
+
const { _unstableFormatAPIError: formatAPIError } = useAPIErrorHandler();
|
998
|
+
const [selectedRows, setSelectedRows] = React.useState([]);
|
999
|
+
const [isDraftRelationConfirmationOpen, setIsDraftRelationConfirmationOpen] = React.useState(false);
|
1000
|
+
const { publishMany: publishManyAction, unpublishMany: unpublishManyAction } = unstable_useDocumentActions();
|
1001
|
+
const { schema, validate } = unstable_useDocument({
|
1002
|
+
model,
|
1003
|
+
collectionType,
|
1004
|
+
documentId,
|
1005
|
+
params: {
|
1006
|
+
locale
|
1007
|
+
}
|
1008
|
+
}, {
|
1009
|
+
// No need to fetch the document, the data is already available in the `document` prop
|
1010
|
+
skip: true
|
1011
|
+
});
|
1012
|
+
const { data: localesMetadata = [] } = useGetLocalesQuery(hasI18n ? undefined : skipToken);
|
1013
|
+
const headers = [
|
1014
|
+
{
|
1015
|
+
label: formatMessage({
|
1016
|
+
id: 'global.name',
|
1017
|
+
defaultMessage: 'Name'
|
1018
|
+
}),
|
1019
|
+
name: 'name'
|
1020
|
+
},
|
1021
|
+
{
|
1022
|
+
label: formatMessage({
|
1023
|
+
id: getTranslation('CMEditViewBulkLocale.status'),
|
1024
|
+
defaultMessage: 'Status'
|
1025
|
+
}),
|
1026
|
+
name: 'status'
|
1027
|
+
},
|
1028
|
+
{
|
1029
|
+
label: formatMessage({
|
1030
|
+
id: getTranslation('CMEditViewBulkLocale.publication-status'),
|
1031
|
+
defaultMessage: 'Publication Status'
|
1032
|
+
}),
|
1033
|
+
name: 'publication-status'
|
1034
|
+
}
|
1035
|
+
];
|
1036
|
+
// Extract the rows for the bulk locale publish modal and any validation
|
1037
|
+
// errors per locale
|
1038
|
+
const [rows, validationErrors] = React.useMemo(()=>{
|
1039
|
+
if (!document) {
|
1040
|
+
return [
|
1041
|
+
[],
|
1042
|
+
{}
|
1043
|
+
];
|
1044
|
+
}
|
1045
|
+
const localizations = document.localizations ?? [];
|
1046
|
+
// Build the rows for the bulk locale publish modal by combining the current
|
1047
|
+
// document with all the available locales from the document meta
|
1048
|
+
const locales = localizations.map((doc)=>{
|
1049
|
+
const { locale, status } = doc;
|
1050
|
+
return {
|
1051
|
+
locale,
|
1052
|
+
status
|
1053
|
+
};
|
1054
|
+
});
|
1055
|
+
// Add the current document locale
|
1056
|
+
locales.unshift({
|
1057
|
+
locale: document.locale,
|
1058
|
+
status: document.status
|
1059
|
+
});
|
1060
|
+
// Build the validation errors for each locale.
|
1061
|
+
const allDocuments = [
|
1062
|
+
document,
|
1063
|
+
...localizations
|
1064
|
+
];
|
1065
|
+
const errors = allDocuments.reduce((errs, document)=>{
|
1066
|
+
if (!document) {
|
1067
|
+
return errs;
|
1068
|
+
}
|
1069
|
+
// Validate each locale entry via the useDocument validate function and store any errors in a dictionary
|
1070
|
+
const validation = validate(document);
|
1071
|
+
if (validation !== null) {
|
1072
|
+
errs[document.locale] = validation;
|
1073
|
+
}
|
1074
|
+
return errs;
|
1075
|
+
}, {});
|
1076
|
+
return [
|
1077
|
+
locales,
|
1078
|
+
errors
|
1079
|
+
];
|
1080
|
+
}, [
|
1081
|
+
document,
|
1082
|
+
validate
|
1083
|
+
]);
|
1084
|
+
const isBulkPublish = action === 'bulk-publish';
|
1085
|
+
const localesForAction = selectedRows.reduce((acc, selectedRow)=>{
|
1086
|
+
const isValidLocale = // Validation errors are irrelevant if we are trying to unpublish
|
1087
|
+
!isBulkPublish || !Object.keys(validationErrors).includes(selectedRow.locale);
|
1088
|
+
const shouldAddLocale = isBulkPublish ? selectedRow.status !== 'published' && isValidLocale : selectedRow.status !== 'draft' && isValidLocale;
|
1089
|
+
if (shouldAddLocale) {
|
1090
|
+
acc.push(selectedRow.locale);
|
1091
|
+
}
|
1092
|
+
return acc;
|
1093
|
+
}, []);
|
1094
|
+
// TODO skipping this for now as there is a bug with the draft relation count that will be worked on separately
|
1095
|
+
// see https://www.notion.so/strapi/Count-draft-relations-56901b492efb45ab90d42fe975b32bd8?pvs=4
|
1096
|
+
const enableDraftRelationsCount = false;
|
1097
|
+
const { data: draftRelationsCount = 0, isLoading: isDraftRelationsLoading, error: isDraftRelationsError } = useGetManyDraftRelationCountQuery({
|
1098
|
+
model,
|
1099
|
+
documentIds: [
|
1100
|
+
documentId
|
1101
|
+
],
|
1102
|
+
locale: localesForAction
|
1103
|
+
}, {
|
1104
|
+
skip: !enableDraftRelationsCount
|
1105
|
+
});
|
1106
|
+
React.useEffect(()=>{
|
1107
|
+
if (isDraftRelationsError) {
|
1108
|
+
toggleNotification({
|
1109
|
+
type: 'danger',
|
1110
|
+
message: formatAPIError(isDraftRelationsError)
|
1111
|
+
});
|
1112
|
+
}
|
1113
|
+
}, [
|
1114
|
+
isDraftRelationsError,
|
1115
|
+
toggleNotification,
|
1116
|
+
formatAPIError
|
1117
|
+
]);
|
1118
|
+
if (!schema?.options?.draftAndPublish) {
|
1119
|
+
return null;
|
1120
|
+
}
|
1121
|
+
if (!hasI18n) {
|
1122
|
+
return null;
|
1123
|
+
}
|
1124
|
+
if (!documentId) {
|
1125
|
+
return null;
|
1126
|
+
}
|
1127
|
+
// This document action can be enabled given that draft and publish and i18n are
|
1128
|
+
// enabled and we can publish the current locale.
|
1129
|
+
const publish = async ()=>{
|
1130
|
+
await publishManyAction({
|
1131
|
+
model,
|
1132
|
+
documentIds: [
|
1133
|
+
documentId
|
1134
|
+
],
|
1135
|
+
params: {
|
1136
|
+
...params,
|
1137
|
+
locale: localesForAction
|
1138
|
+
}
|
1139
|
+
});
|
1140
|
+
setSelectedRows([]);
|
1141
|
+
};
|
1142
|
+
const unpublish = async ()=>{
|
1143
|
+
await unpublishManyAction({
|
1144
|
+
model,
|
1145
|
+
documentIds: [
|
1146
|
+
documentId
|
1147
|
+
],
|
1148
|
+
params: {
|
1149
|
+
...params,
|
1150
|
+
locale: localesForAction
|
1151
|
+
}
|
1152
|
+
});
|
1153
|
+
setSelectedRows([]);
|
1154
|
+
};
|
1155
|
+
const handleAction = async ()=>{
|
1156
|
+
if (draftRelationsCount > 0) {
|
1157
|
+
setIsDraftRelationConfirmationOpen(true);
|
1158
|
+
} else if (isBulkPublish) {
|
1159
|
+
await publish();
|
1160
|
+
} else {
|
1161
|
+
await unpublish();
|
1162
|
+
}
|
1163
|
+
};
|
1164
|
+
if (isDraftRelationConfirmationOpen) {
|
1165
|
+
return {
|
1166
|
+
label: formatMessage({
|
1167
|
+
id: 'app.components.ConfirmDialog.title',
|
1168
|
+
defaultMessage: 'Confirmation'
|
1169
|
+
}),
|
1170
|
+
variant: 'danger',
|
1171
|
+
dialog: {
|
1172
|
+
onCancel: ()=>{
|
1173
|
+
setIsDraftRelationConfirmationOpen(false);
|
1174
|
+
},
|
1175
|
+
onConfirm: async ()=>{
|
1176
|
+
await publish();
|
1177
|
+
setIsDraftRelationConfirmationOpen(false);
|
1178
|
+
},
|
1179
|
+
type: 'dialog',
|
1180
|
+
title: formatMessage({
|
1181
|
+
id: getTranslation('actions.publish.dialog.title'),
|
1182
|
+
defaultMessage: 'Confirmation'
|
1183
|
+
}),
|
1184
|
+
content: /*#__PURE__*/ jsxs(Flex, {
|
1185
|
+
direction: "column",
|
1186
|
+
alignItems: "center",
|
1187
|
+
gap: 2,
|
1188
|
+
children: [
|
1189
|
+
/*#__PURE__*/ jsx(WarningCircle, {
|
1190
|
+
width: "2.4rem",
|
1191
|
+
height: "2.4rem",
|
1192
|
+
fill: "danger600"
|
1193
|
+
}),
|
1194
|
+
/*#__PURE__*/ jsx(Typography, {
|
1195
|
+
textAlign: "center",
|
1196
|
+
children: formatMessage({
|
1197
|
+
id: getTranslation('CMEditViewBulkLocale.draft-relation-warning'),
|
1198
|
+
defaultMessage: 'Some locales are related to draft entries. Publishing them could leave broken links in your app.'
|
1199
|
+
})
|
1200
|
+
}),
|
1201
|
+
/*#__PURE__*/ jsx(Typography, {
|
1202
|
+
textAlign: "center",
|
1203
|
+
children: formatMessage({
|
1204
|
+
id: getTranslation('CMEditViewBulkLocale.continue-confirmation'),
|
1205
|
+
defaultMessage: 'Are you sure you want to continue?'
|
1206
|
+
})
|
1207
|
+
})
|
1208
|
+
]
|
1209
|
+
})
|
1210
|
+
}
|
1211
|
+
};
|
1212
|
+
}
|
1213
|
+
const hasPermission = selectedRows.map(({ locale })=>locale).every((locale)=>canPublish.includes(locale));
|
1214
|
+
return {
|
1215
|
+
label: formatMessage({
|
1216
|
+
id: getTranslation(`CMEditViewBulkLocale.${isBulkPublish ? 'publish' : 'unpublish'}-title`),
|
1217
|
+
defaultMessage: `${isBulkPublish ? 'Publish' : 'Unpublish'} Multiple Locales`
|
1218
|
+
}),
|
1219
|
+
variant: isBulkPublish ? 'secondary' : 'danger',
|
1220
|
+
icon: isBulkPublish ? /*#__PURE__*/ jsx(ListPlus, {}) : /*#__PURE__*/ jsx(Cross, {}),
|
1221
|
+
disabled: isOnPublishedTab || canPublish.length === 0,
|
1222
|
+
position: [
|
1223
|
+
'panel'
|
1224
|
+
],
|
1225
|
+
dialog: {
|
1226
|
+
type: 'modal',
|
1227
|
+
title: formatMessage({
|
1228
|
+
id: getTranslation(`CMEditViewBulkLocale.${isBulkPublish ? 'publish' : 'unpublish'}-title`),
|
1229
|
+
defaultMessage: `${isBulkPublish ? 'Publish' : 'Unpublish'} Multiple Locales`
|
1230
|
+
}),
|
1231
|
+
content: ()=>{
|
1232
|
+
return /*#__PURE__*/ jsx(Table.Root, {
|
1233
|
+
headers: headers,
|
1234
|
+
rows: rows.map((row)=>({
|
1235
|
+
...row,
|
1236
|
+
id: row.locale
|
1237
|
+
})),
|
1238
|
+
selectedRows: selectedRows,
|
1239
|
+
onSelectedRowsChange: (tableSelectedRows)=>setSelectedRows(tableSelectedRows),
|
1240
|
+
children: /*#__PURE__*/ jsx(BulkLocaleActionModal, {
|
1241
|
+
validationErrors: validationErrors,
|
1242
|
+
headers: headers,
|
1243
|
+
rows: rows,
|
1244
|
+
localesMetadata: localesMetadata,
|
1245
|
+
action: action ?? 'bulk-publish'
|
1246
|
+
})
|
1247
|
+
});
|
1248
|
+
},
|
1249
|
+
footer: ()=>/*#__PURE__*/ jsx(Modal.Footer, {
|
1250
|
+
justifyContent: "flex-end",
|
1251
|
+
children: /*#__PURE__*/ jsx(Button, {
|
1252
|
+
loading: isDraftRelationsLoading,
|
1253
|
+
disabled: !hasPermission || localesForAction.length === 0,
|
1254
|
+
variant: "default",
|
1255
|
+
onClick: handleAction,
|
1256
|
+
children: formatMessage({
|
1257
|
+
id: isBulkPublish ? 'app.utils.publish' : 'app.utils.unpublish',
|
1258
|
+
defaultMessage: isBulkPublish ? 'Publish' : 'Unpublish'
|
1259
|
+
})
|
1260
|
+
})
|
1261
|
+
})
|
1262
|
+
}
|
1263
|
+
};
|
1264
|
+
};
|
1265
|
+
/* -------------------------------------------------------------------------------------------------
|
1266
|
+
* BulkLocalePublishAction
|
1267
|
+
* -----------------------------------------------------------------------------------------------*/ const BulkLocalePublishAction = (props)=>{
|
1268
|
+
return BulkLocaleAction({
|
1269
|
+
action: 'bulk-publish',
|
1270
|
+
...props
|
1271
|
+
});
|
1272
|
+
};
|
1273
|
+
/* -------------------------------------------------------------------------------------------------
|
1274
|
+
* BulkLocaleUnpublishAction
|
1275
|
+
* -----------------------------------------------------------------------------------------------*/ const BulkLocaleUnpublishAction = (props)=>{
|
1276
|
+
return BulkLocaleAction({
|
1277
|
+
action: 'bulk-unpublish',
|
1278
|
+
...props
|
1279
|
+
});
|
1280
|
+
};
|
1281
|
+
/**
|
1282
|
+
* Because the icon system is completely broken, we have to do
|
1283
|
+
* this to remove the fill from the cog.
|
1284
|
+
*/ const StyledTrash = styled(Trash)`
|
1285
|
+
path {
|
1286
|
+
fill: currentColor;
|
1287
|
+
}
|
1288
|
+
`;
|
1289
|
+
|
1290
|
+
const Emphasis = (chunks)=>{
|
1291
|
+
return /*#__PURE__*/ jsx(Typography, {
|
1292
|
+
fontWeight: "semiBold",
|
1293
|
+
textColor: "danger500",
|
1294
|
+
children: chunks
|
1295
|
+
});
|
1296
|
+
};
|
1297
|
+
const DeleteModalAdditionalInfo = ()=>{
|
1298
|
+
const { hasI18n } = useI18n();
|
1299
|
+
const { formatMessage } = useIntl();
|
1300
|
+
if (!hasI18n) {
|
1301
|
+
return null;
|
1302
|
+
}
|
1303
|
+
return /*#__PURE__*/ jsx(Typography, {
|
1304
|
+
textColor: "danger500",
|
1305
|
+
children: formatMessage({
|
1306
|
+
id: getTranslation('Settings.list.actions.deleteAdditionalInfos'),
|
1307
|
+
defaultMessage: 'This will delete the active locale versions <em>(from Internationalization)</em>'
|
1308
|
+
}, {
|
1309
|
+
em: Emphasis
|
1310
|
+
})
|
1311
|
+
});
|
1312
|
+
};
|
1313
|
+
const PublishModalAdditionalInfo = ()=>{
|
1314
|
+
const { hasI18n } = useI18n();
|
1315
|
+
const { formatMessage } = useIntl();
|
1316
|
+
if (!hasI18n) {
|
1317
|
+
return null;
|
1318
|
+
}
|
1319
|
+
return /*#__PURE__*/ jsx(Typography, {
|
1320
|
+
textColor: "danger500",
|
1321
|
+
children: formatMessage({
|
1322
|
+
id: getTranslation('Settings.list.actions.publishAdditionalInfos'),
|
1323
|
+
defaultMessage: 'This will publish the active locale versions <em>(from Internationalization)</em>'
|
1324
|
+
}, {
|
1325
|
+
em: Emphasis
|
1326
|
+
})
|
1327
|
+
});
|
1328
|
+
};
|
1329
|
+
const UnpublishModalAdditionalInfo = ()=>{
|
1330
|
+
const { hasI18n } = useI18n();
|
1331
|
+
const { formatMessage } = useIntl();
|
1332
|
+
if (!hasI18n) {
|
1333
|
+
return null;
|
1334
|
+
}
|
1335
|
+
return /*#__PURE__*/ jsx(Typography, {
|
1336
|
+
textColor: "danger500",
|
1337
|
+
children: formatMessage({
|
1338
|
+
id: getTranslation('Settings.list.actions.unpublishAdditionalInfos'),
|
1339
|
+
defaultMessage: 'This will unpublish the active locale versions <em>(from Internationalization)</em>'
|
1340
|
+
}, {
|
1341
|
+
em: Emphasis
|
1342
|
+
})
|
1343
|
+
});
|
1344
|
+
};
|
1345
|
+
|
1346
|
+
const LocalePicker = ()=>{
|
1347
|
+
const { formatMessage } = useIntl();
|
1348
|
+
const [{ query }, setQuery] = useQueryParams();
|
1349
|
+
const { hasI18n, canRead, canCreate } = useI18n();
|
1350
|
+
const { data: locales = [] } = useGetLocalesQuery(undefined, {
|
1351
|
+
skip: !hasI18n
|
1352
|
+
});
|
1353
|
+
const handleChange = React.useCallback((code, replace = false)=>{
|
1354
|
+
setQuery({
|
1355
|
+
page: 1,
|
1356
|
+
plugins: {
|
1357
|
+
...query.plugins,
|
1358
|
+
i18n: {
|
1359
|
+
locale: code
|
1360
|
+
}
|
1361
|
+
}
|
1362
|
+
}, 'push', replace);
|
1363
|
+
}, [
|
1364
|
+
query.plugins,
|
1365
|
+
setQuery
|
1366
|
+
]);
|
1367
|
+
React.useEffect(()=>{
|
1368
|
+
if (!Array.isArray(locales) || !hasI18n) {
|
1369
|
+
return;
|
1370
|
+
}
|
1371
|
+
/**
|
1372
|
+
* Handle the case where the current locale query param doesn't exist
|
1373
|
+
* in the list of available locales, so we redirect to the default locale.
|
1374
|
+
*/ const currentDesiredLocale = query.plugins?.i18n?.locale;
|
1375
|
+
const doesLocaleExist = locales.find((loc)=>loc.code === currentDesiredLocale);
|
1376
|
+
const defaultLocale = locales.find((locale)=>locale.isDefault);
|
1377
|
+
if (!doesLocaleExist && defaultLocale?.code) {
|
1378
|
+
handleChange(defaultLocale.code, true);
|
1379
|
+
}
|
1380
|
+
}, [
|
1381
|
+
hasI18n,
|
1382
|
+
handleChange,
|
1383
|
+
locales,
|
1384
|
+
query.plugins?.i18n?.locale
|
1385
|
+
]);
|
1386
|
+
if (!hasI18n || !Array.isArray(locales) || locales.length === 0) {
|
1387
|
+
return null;
|
1388
|
+
}
|
1389
|
+
const displayedLocales = locales.filter((locale)=>{
|
1390
|
+
/**
|
1391
|
+
* If you can create or read we allow you to see the locale exists
|
1392
|
+
* this is because in the ListView, you may be able to create a new entry
|
1393
|
+
* in a locale you can't read.
|
1394
|
+
*/ return canCreate.includes(locale.code) || canRead.includes(locale.code);
|
1395
|
+
});
|
1396
|
+
return /*#__PURE__*/ jsx(SingleSelect, {
|
1397
|
+
size: "S",
|
1398
|
+
"aria-label": formatMessage({
|
1399
|
+
id: getTranslation('actions.select-locale'),
|
1400
|
+
defaultMessage: 'Select locale'
|
1401
|
+
}),
|
1402
|
+
value: query.plugins?.i18n?.locale || locales.find((locale)=>locale.isDefault)?.code,
|
1403
|
+
// @ts-expect-error – This can be removed in V2 of the DS.
|
1404
|
+
onChange: handleChange,
|
1405
|
+
children: displayedLocales.map((locale)=>/*#__PURE__*/ jsx(SingleSelectOption, {
|
1406
|
+
value: locale.code,
|
1407
|
+
children: locale.name
|
1408
|
+
}, locale.id))
|
1409
|
+
});
|
1410
|
+
};
|
1411
|
+
|
1412
|
+
const PERMISSIONS = {
|
1413
|
+
accessMain: [
|
1414
|
+
{
|
1415
|
+
action: 'plugin::i18n.locale.read',
|
1416
|
+
subject: null
|
1417
|
+
}
|
1418
|
+
],
|
1419
|
+
create: [
|
1420
|
+
{
|
1421
|
+
action: 'plugin::i18n.locale.create',
|
1422
|
+
subject: null
|
1423
|
+
}
|
1424
|
+
],
|
1425
|
+
delete: [
|
1426
|
+
{
|
1427
|
+
action: 'plugin::i18n.locale.delete',
|
1428
|
+
subject: null
|
1429
|
+
}
|
1430
|
+
],
|
1431
|
+
update: [
|
1432
|
+
{
|
1433
|
+
action: 'plugin::i18n.locale.update',
|
1434
|
+
subject: null
|
1435
|
+
}
|
1436
|
+
],
|
1437
|
+
read: [
|
1438
|
+
{
|
1439
|
+
action: 'plugin::i18n.locale.read',
|
1440
|
+
subject: null
|
1441
|
+
}
|
1442
|
+
]
|
1443
|
+
};
|
1444
|
+
|
1445
|
+
const mutateEditViewHook = ({ layout })=>{
|
1446
|
+
// If i18n isn't explicitly enabled on the content type, then no field can be localized
|
1447
|
+
if (!('i18n' in layout.options) || typeof layout.options.i18n === 'object' && layout.options.i18n !== null && 'localized' in layout.options.i18n && !layout.options.i18n.localized) {
|
1448
|
+
return {
|
1449
|
+
layout
|
1450
|
+
};
|
1451
|
+
}
|
1452
|
+
const components = Object.entries(layout.components).reduce((acc, [key, componentLayout])=>{
|
1453
|
+
return {
|
1454
|
+
...acc,
|
1455
|
+
[key]: {
|
1456
|
+
...componentLayout,
|
1457
|
+
layout: componentLayout.layout.map((row)=>row.map(addLabelActionToField))
|
1458
|
+
}
|
1459
|
+
};
|
1460
|
+
}, {});
|
1461
|
+
return {
|
1462
|
+
layout: {
|
1463
|
+
...layout,
|
1464
|
+
components,
|
1465
|
+
layout: layout.layout.map((panel)=>panel.map((row)=>row.map(addLabelActionToField)))
|
1466
|
+
}
|
1467
|
+
};
|
1468
|
+
};
|
1469
|
+
const addLabelActionToField = (field)=>{
|
1470
|
+
const isFieldLocalized = doesFieldHaveI18nPluginOpt(field.attribute.pluginOptions) ? field.attribute.pluginOptions.i18n.localized : true;
|
1471
|
+
const labelActionProps = {
|
1472
|
+
title: {
|
1473
|
+
id: isFieldLocalized ? getTranslation('Field.localized') : getTranslation('Field.not-localized'),
|
1474
|
+
defaultMessage: isFieldLocalized ? 'This value is unique for the selected locale' : 'This value is the same across all locales'
|
1475
|
+
},
|
1476
|
+
icon: isFieldLocalized ? /*#__PURE__*/ jsx(Earth, {}) : null
|
1477
|
+
};
|
1478
|
+
return {
|
1479
|
+
...field,
|
1480
|
+
labelAction: isFieldLocalized ? /*#__PURE__*/ jsx(LabelAction, {
|
1481
|
+
...labelActionProps
|
1482
|
+
}) : null
|
1483
|
+
};
|
1484
|
+
};
|
1485
|
+
const doesFieldHaveI18nPluginOpt = (pluginOpts)=>{
|
1486
|
+
if (!pluginOpts) {
|
1487
|
+
return false;
|
1488
|
+
}
|
1489
|
+
return 'i18n' in pluginOpts && typeof pluginOpts.i18n === 'object' && pluginOpts.i18n !== null && 'localized' in pluginOpts.i18n;
|
1490
|
+
};
|
1491
|
+
const LabelAction = ({ title, icon })=>{
|
1492
|
+
const { formatMessage } = useIntl();
|
1493
|
+
return /*#__PURE__*/ jsxs(Span, {
|
1494
|
+
tag: "span",
|
1495
|
+
children: [
|
1496
|
+
/*#__PURE__*/ jsx(VisuallyHidden, {
|
1497
|
+
tag: "span",
|
1498
|
+
children: formatMessage(title)
|
1499
|
+
}),
|
1500
|
+
/*#__PURE__*/ React.cloneElement(icon, {
|
1501
|
+
'aria-hidden': true,
|
1502
|
+
focusable: false
|
1503
|
+
})
|
1504
|
+
]
|
1505
|
+
});
|
1506
|
+
};
|
1507
|
+
const Span = styled(Flex)`
|
1508
|
+
svg {
|
1509
|
+
width: 12px;
|
1510
|
+
height: 12px;
|
1511
|
+
|
1512
|
+
fill: ${({ theme })=>theme.colors.neutral500};
|
1513
|
+
|
1514
|
+
path {
|
1515
|
+
fill: ${({ theme })=>theme.colors.neutral500};
|
1516
|
+
}
|
1517
|
+
}
|
1518
|
+
`;
|
1519
|
+
|
1520
|
+
const LocaleListCell = ({ locale: currentLocale, localizations })=>{
|
1521
|
+
const { locale: language } = useIntl();
|
1522
|
+
const { data: locales = [] } = useGetLocalesQuery();
|
1523
|
+
const formatter = useCollator(language, {
|
1524
|
+
sensitivity: 'base'
|
1525
|
+
});
|
1526
|
+
if (!Array.isArray(locales) || !localizations) {
|
1527
|
+
return null;
|
1528
|
+
}
|
1529
|
+
const availableLocales = localizations.map((loc)=>loc.locale);
|
1530
|
+
const localesForDocument = locales.reduce((acc, locale)=>{
|
1531
|
+
const createdLocale = [
|
1532
|
+
currentLocale,
|
1533
|
+
...availableLocales
|
1534
|
+
].find((loc)=>{
|
1535
|
+
return loc === locale.code;
|
1536
|
+
});
|
1537
|
+
if (createdLocale) {
|
1538
|
+
acc.push(locale);
|
1539
|
+
}
|
1540
|
+
return acc;
|
1541
|
+
}, []).map((locale)=>{
|
1542
|
+
if (locale.isDefault) {
|
1543
|
+
return `${locale.name} (default)`;
|
1544
|
+
}
|
1545
|
+
return locale.name;
|
1546
|
+
}).toSorted((a, b)=>formatter.compare(a, b));
|
1547
|
+
return /*#__PURE__*/ jsxs(Popover.Root, {
|
1548
|
+
children: [
|
1549
|
+
/*#__PURE__*/ jsx(Popover.Trigger, {
|
1550
|
+
children: /*#__PURE__*/ jsx(Button, {
|
1551
|
+
variant: "ghost",
|
1552
|
+
type: "button",
|
1553
|
+
onClick: (e)=>e.stopPropagation(),
|
1554
|
+
children: /*#__PURE__*/ jsxs(Flex, {
|
1555
|
+
minWidth: "100%",
|
1556
|
+
alignItems: "center",
|
1557
|
+
justifyContent: "center",
|
1558
|
+
fontWeight: "regular",
|
1559
|
+
children: [
|
1560
|
+
/*#__PURE__*/ jsx(Typography, {
|
1561
|
+
textColor: "neutral800",
|
1562
|
+
ellipsis: true,
|
1563
|
+
marginRight: 2,
|
1564
|
+
children: localesForDocument.join(', ')
|
1565
|
+
}),
|
1566
|
+
/*#__PURE__*/ jsx(Flex, {
|
1567
|
+
children: /*#__PURE__*/ jsx(CaretDown, {
|
1568
|
+
width: "1.2rem",
|
1569
|
+
height: "1.2rem"
|
1570
|
+
})
|
1571
|
+
})
|
1572
|
+
]
|
1573
|
+
})
|
1574
|
+
})
|
1575
|
+
}),
|
1576
|
+
/*#__PURE__*/ jsx(Popover.Content, {
|
1577
|
+
sideOffset: 16,
|
1578
|
+
children: /*#__PURE__*/ jsx("ul", {
|
1579
|
+
children: localesForDocument.map((name)=>/*#__PURE__*/ jsx(Box, {
|
1580
|
+
padding: 3,
|
1581
|
+
tag: "li",
|
1582
|
+
children: /*#__PURE__*/ jsx(Typography, {
|
1583
|
+
children: name
|
1584
|
+
})
|
1585
|
+
}, name))
|
1586
|
+
})
|
1587
|
+
})
|
1588
|
+
]
|
1589
|
+
});
|
1590
|
+
};
|
1591
|
+
|
1592
|
+
const addColumnToTableHook = ({ displayedHeaders, layout })=>{
|
1593
|
+
const { options } = layout;
|
1594
|
+
const isFieldLocalized = doesPluginOptionsHaveI18nLocalized(options) ? options.i18n.localized : false;
|
1595
|
+
if (!isFieldLocalized) {
|
1596
|
+
return {
|
1597
|
+
displayedHeaders,
|
1598
|
+
layout
|
1599
|
+
};
|
1600
|
+
}
|
1601
|
+
return {
|
1602
|
+
displayedHeaders: [
|
1603
|
+
...displayedHeaders,
|
1604
|
+
{
|
1605
|
+
attribute: {
|
1606
|
+
type: 'string'
|
1607
|
+
},
|
1608
|
+
label: {
|
1609
|
+
id: getTranslation('list-view.table.header.label'),
|
1610
|
+
defaultMessage: 'Available in'
|
1611
|
+
},
|
1612
|
+
searchable: false,
|
1613
|
+
sortable: false,
|
1614
|
+
name: 'locales',
|
1615
|
+
// @ts-expect-error – ID is seen as number | string; this will change when we move the type over.
|
1616
|
+
cellFormatter: (props, _header, meta)=>/*#__PURE__*/ jsx(LocaleListCell, {
|
1617
|
+
...props,
|
1618
|
+
...meta
|
1619
|
+
})
|
1620
|
+
}
|
1621
|
+
],
|
1622
|
+
layout
|
1623
|
+
};
|
1624
|
+
};
|
1625
|
+
|
1626
|
+
const addLocaleToReleasesHook = ({ displayedHeaders = [] })=>{
|
1627
|
+
return {
|
1628
|
+
displayedHeaders: [
|
1629
|
+
...displayedHeaders,
|
1630
|
+
{
|
1631
|
+
label: {
|
1632
|
+
id: 'content-releases.page.ReleaseDetails.table.header.label.locale',
|
1633
|
+
defaultMessage: 'locale'
|
1634
|
+
},
|
1635
|
+
name: 'locale'
|
1636
|
+
}
|
1637
|
+
],
|
1638
|
+
hasI18nEnabled: true
|
1639
|
+
};
|
1640
|
+
};
|
1641
|
+
|
1642
|
+
const extendCTBAttributeInitialDataMiddleware = ()=>{
|
1643
|
+
return ({ getState })=>(next)=>(action)=>{
|
1644
|
+
const enhanceAction = ()=>{
|
1645
|
+
// the block here is to catch the error when trying to access the state
|
1646
|
+
// of the ctb when the plugin is not mounted
|
1647
|
+
try {
|
1648
|
+
const store = getState();
|
1649
|
+
const hasi18nEnabled = get(store, [
|
1650
|
+
'content-type-builder_dataManagerProvider',
|
1651
|
+
'modifiedData',
|
1652
|
+
'contentType',
|
1653
|
+
'schema',
|
1654
|
+
'pluginOptions',
|
1655
|
+
'i18n',
|
1656
|
+
'localized'
|
1657
|
+
], false);
|
1658
|
+
if (hasi18nEnabled) {
|
1659
|
+
const pluginOptions = action.options ? {
|
1660
|
+
...action.options.pluginOptions,
|
1661
|
+
i18n: {
|
1662
|
+
localized: true
|
1663
|
+
}
|
1664
|
+
} : {
|
1665
|
+
i18n: {
|
1666
|
+
localized: true
|
1667
|
+
}
|
1668
|
+
};
|
1669
|
+
return next({
|
1670
|
+
...action,
|
1671
|
+
options: {
|
1672
|
+
pluginOptions
|
1673
|
+
}
|
1674
|
+
});
|
1675
|
+
}
|
1676
|
+
return next(action);
|
1677
|
+
} catch (err) {
|
1678
|
+
return next(action);
|
1679
|
+
}
|
1680
|
+
};
|
1681
|
+
if (action.type === 'ContentTypeBuilder/FormModal/SET_ATTRIBUTE_DATA_SCHEMA' && action.forTarget === 'contentType' && ![
|
1682
|
+
'relation',
|
1683
|
+
'component'
|
1684
|
+
].includes(action.attributeType) && !action.isEditing) {
|
1685
|
+
return enhanceAction();
|
1686
|
+
}
|
1687
|
+
if (action.type === 'ContentTypeBuilder/FormModal/SET_CUSTOM_FIELD_DATA_SCHEMA' && action.forTarget === 'contentType' && !action.isEditing) {
|
1688
|
+
return enhanceAction();
|
1689
|
+
}
|
1690
|
+
if ((action.type === 'ContentTypeBuilder/FormModal/RESET_PROPS_AND_SET_FORM_FOR_ADDING_AN_EXISTING_COMPO' || action.type === 'ContentTypeBuilder/FormModal/RESET_PROPS_AND_SAVE_CURRENT_DATA') && action.forTarget === 'contentType') {
|
1691
|
+
return enhanceAction();
|
1692
|
+
}
|
1693
|
+
return next(action);
|
1694
|
+
};
|
1695
|
+
};
|
1696
|
+
|
1697
|
+
const extendCTBInitialDataMiddleware = ()=>{
|
1698
|
+
return ()=>(next)=>(action)=>{
|
1699
|
+
if (action.type === 'ContentTypeBuilder/FormModal/SET_DATA_TO_EDIT' && action.modalType === 'contentType') {
|
1700
|
+
const i18n = {
|
1701
|
+
localized: false
|
1702
|
+
};
|
1703
|
+
const pluginOptions = action.data.pluginOptions ? {
|
1704
|
+
...action.data.pluginOptions,
|
1705
|
+
i18n
|
1706
|
+
} : {
|
1707
|
+
i18n
|
1708
|
+
};
|
1709
|
+
const data = {
|
1710
|
+
...action.data,
|
1711
|
+
pluginOptions
|
1712
|
+
};
|
1713
|
+
if (action.actionType === 'create') {
|
1714
|
+
return next({
|
1715
|
+
...action,
|
1716
|
+
data
|
1717
|
+
});
|
1718
|
+
}
|
1719
|
+
// Override the action if the pluginOption config does not contain i18n
|
1720
|
+
// In this case we need to set the proper initialData shape
|
1721
|
+
if (!action.data.pluginOptions?.i18n?.localized) {
|
1722
|
+
return next({
|
1723
|
+
...action,
|
1724
|
+
data
|
1725
|
+
});
|
1726
|
+
}
|
1727
|
+
}
|
1728
|
+
// action is not the one we want to override
|
1729
|
+
return next(action);
|
1730
|
+
};
|
1731
|
+
};
|
1732
|
+
|
1733
|
+
const localeMiddleware = (ctx)=>(next)=>(permissions)=>{
|
1734
|
+
const match = matchPath('/content-manager/:collectionType/:model?/:id', ctx.pathname);
|
1735
|
+
if (!match) {
|
1736
|
+
return next(permissions);
|
1737
|
+
}
|
1738
|
+
const search = qs.parse(ctx.search);
|
1739
|
+
if (typeof search !== 'object') {
|
1740
|
+
return next(permissions);
|
1741
|
+
}
|
1742
|
+
if (!('plugins' in search && typeof search.plugins === 'object')) {
|
1743
|
+
return next(permissions);
|
1744
|
+
}
|
1745
|
+
if (!('i18n' in search.plugins && typeof search.plugins.i18n === 'object' && !Array.isArray(search.plugins.i18n))) {
|
1746
|
+
return next(permissions);
|
1747
|
+
}
|
1748
|
+
const { locale } = search.plugins.i18n;
|
1749
|
+
if (typeof locale !== 'string') {
|
1750
|
+
return next(permissions);
|
1751
|
+
}
|
1752
|
+
const revisedPermissions = permissions.filter((permission)=>!permission.properties?.locales || permission.properties.locales.includes(locale));
|
1753
|
+
return next(revisedPermissions);
|
1754
|
+
};
|
1755
|
+
|
1756
|
+
const prefixPluginTranslations = (trad, pluginId)=>{
|
1757
|
+
return Object.keys(trad).reduce((acc, current)=>{
|
1758
|
+
acc[`${pluginId}.${current}`] = trad[current];
|
1759
|
+
return acc;
|
1760
|
+
}, {});
|
1761
|
+
};
|
1762
|
+
|
1763
|
+
/* -------------------------------------------------------------------------------------------------
|
1764
|
+
* mutateCTBContentTypeSchema
|
1765
|
+
* -----------------------------------------------------------------------------------------------*/ const mutateCTBContentTypeSchema = (nextSchema, prevSchema)=>{
|
1766
|
+
// Don't perform mutations components
|
1767
|
+
if (!doesPluginOptionsHaveI18nLocalized(nextSchema.pluginOptions)) {
|
1768
|
+
return nextSchema;
|
1769
|
+
}
|
1770
|
+
const isNextSchemaLocalized = nextSchema.pluginOptions.i18n.localized;
|
1771
|
+
const isPrevSchemaLocalized = doesPluginOptionsHaveI18nLocalized(prevSchema?.schema?.pluginOptions) ? prevSchema?.schema?.pluginOptions.i18n.localized : false;
|
1772
|
+
// No need to perform modification on the schema, if the i18n feature was not changed
|
1773
|
+
// at the ct level
|
1774
|
+
if (isNextSchemaLocalized && isPrevSchemaLocalized) {
|
1775
|
+
return nextSchema;
|
1776
|
+
}
|
1777
|
+
if (isNextSchemaLocalized) {
|
1778
|
+
const attributes = addLocalisationToFields(nextSchema.attributes);
|
1779
|
+
return {
|
1780
|
+
...nextSchema,
|
1781
|
+
attributes
|
1782
|
+
};
|
1783
|
+
}
|
1784
|
+
// Remove the i18n object from the pluginOptions
|
1785
|
+
if (!isNextSchemaLocalized) {
|
1786
|
+
const pluginOptions = omit(nextSchema.pluginOptions, 'i18n');
|
1787
|
+
const attributes = disableAttributesLocalisation(nextSchema.attributes);
|
1788
|
+
return {
|
1789
|
+
...nextSchema,
|
1790
|
+
pluginOptions,
|
1791
|
+
attributes
|
1792
|
+
};
|
1793
|
+
}
|
1794
|
+
return nextSchema;
|
1795
|
+
};
|
1796
|
+
/* -------------------------------------------------------------------------------------------------
|
1797
|
+
* addLocalisationToFields
|
1798
|
+
* -----------------------------------------------------------------------------------------------*/ const addLocalisationToFields = (attributes)=>Object.keys(attributes).reduce((acc, current)=>{
|
1799
|
+
const currentAttribute = attributes[current];
|
1800
|
+
if (LOCALIZED_FIELDS.includes(currentAttribute.type)) {
|
1801
|
+
const i18n = {
|
1802
|
+
localized: true
|
1803
|
+
};
|
1804
|
+
const pluginOptions = currentAttribute.pluginOptions ? {
|
1805
|
+
...currentAttribute.pluginOptions,
|
1806
|
+
i18n
|
1807
|
+
} : {
|
1808
|
+
i18n
|
1809
|
+
};
|
1810
|
+
acc[current] = {
|
1811
|
+
...currentAttribute,
|
1812
|
+
pluginOptions
|
1813
|
+
};
|
1814
|
+
return acc;
|
1815
|
+
}
|
1816
|
+
acc[current] = currentAttribute;
|
1817
|
+
return acc;
|
1818
|
+
}, {});
|
1819
|
+
const disableAttributesLocalisation = (attributes)=>Object.keys(attributes).reduce((acc, current)=>{
|
1820
|
+
acc[current] = omit(attributes[current], 'pluginOptions.i18n');
|
1821
|
+
return acc;
|
1822
|
+
}, {});
|
1823
|
+
|
1824
|
+
function __variableDynamicImportRuntime1__(path) {
|
1825
|
+
switch (path) {
|
1826
|
+
case './translations/de.json': return import('./de-Cm8mYdaO.mjs');
|
1827
|
+
case './translations/dk.json': return import('./dk-BeUFOegB.mjs');
|
1828
|
+
case './translations/en.json': return import('./en-eWSaCeOb.mjs');
|
1829
|
+
case './translations/es.json': return import('./es-DqF_IdAc.mjs');
|
1830
|
+
case './translations/fr.json': return import('./fr-CyARbZ3c.mjs');
|
1831
|
+
case './translations/ko.json': return import('./ko-Ax4NSedM.mjs');
|
1832
|
+
case './translations/pl.json': return import('./pl-B-aqvMqL.mjs');
|
1833
|
+
case './translations/ru.json': return import('./ru-VkPjQ-Sk.mjs');
|
1834
|
+
case './translations/tr.json': return import('./tr-DcTR88c9.mjs');
|
1835
|
+
case './translations/zh-Hans.json': return import('./zh-Hans-L3wsRegj.mjs');
|
1836
|
+
case './translations/zh.json': return import('./zh-RZyMiPIs.mjs');
|
1837
|
+
default: return new Promise(function(resolve, reject) {
|
1838
|
+
(typeof queueMicrotask === 'function' ? queueMicrotask : setTimeout)(
|
1839
|
+
reject.bind(null, new Error("Unknown variable dynamic import: " + path))
|
1840
|
+
);
|
1841
|
+
})
|
1842
|
+
}
|
1843
|
+
}
|
1844
|
+
// eslint-disable-next-line import/no-default-export
|
1845
|
+
var index = {
|
1846
|
+
register (app) {
|
1847
|
+
app.addMiddlewares([
|
1848
|
+
extendCTBAttributeInitialDataMiddleware,
|
1849
|
+
extendCTBInitialDataMiddleware
|
1850
|
+
]);
|
1851
|
+
app.addMiddlewares([
|
1852
|
+
()=>i18nApi.middleware
|
1853
|
+
]);
|
1854
|
+
app.addReducers({
|
1855
|
+
[i18nApi.reducerPath]: i18nApi.reducer
|
1856
|
+
});
|
1857
|
+
app.addRBACMiddleware([
|
1858
|
+
localeMiddleware
|
1859
|
+
]);
|
1860
|
+
app.registerPlugin({
|
1861
|
+
id: pluginId,
|
1862
|
+
name: pluginId
|
1863
|
+
});
|
1864
|
+
},
|
1865
|
+
bootstrap (app) {
|
1866
|
+
// // Hook that adds a column into the CM's LV table
|
1867
|
+
app.registerHook('Admin/CM/pages/ListView/inject-column-in-table', addColumnToTableHook);
|
1868
|
+
app.registerHook('Admin/CM/pages/EditView/mutate-edit-view-layout', mutateEditViewHook);
|
1869
|
+
// Hooks that checks if the locale is present in the release
|
1870
|
+
app.registerHook('ContentReleases/pages/ReleaseDetails/add-locale-in-releases', addLocaleToReleasesHook);
|
1871
|
+
// Add the settings link
|
1872
|
+
app.addSettingsLink('global', {
|
1873
|
+
intlLabel: {
|
1874
|
+
id: getTranslation('plugin.name'),
|
1875
|
+
defaultMessage: 'Internationalization'
|
1876
|
+
},
|
1877
|
+
id: 'internationalization',
|
1878
|
+
to: 'internationalization',
|
1879
|
+
Component: ()=>import('./SettingsPage-DydtYvMJ.mjs').then((mod)=>({
|
1880
|
+
default: mod.ProtectedSettingsPage
|
1881
|
+
})),
|
1882
|
+
permissions: PERMISSIONS.accessMain
|
1883
|
+
});
|
1884
|
+
const contentManager = app.getPlugin('content-manager');
|
1885
|
+
contentManager.apis.addDocumentHeaderAction([
|
1886
|
+
LocalePickerAction,
|
1887
|
+
FillFromAnotherLocaleAction
|
1888
|
+
]);
|
1889
|
+
contentManager.apis.addDocumentAction((actions)=>{
|
1890
|
+
const indexOfDeleteAction = actions.findIndex((action)=>action.type === 'delete');
|
1891
|
+
actions.splice(indexOfDeleteAction, 0, DeleteLocaleAction);
|
1892
|
+
return actions;
|
1893
|
+
});
|
1894
|
+
contentManager.apis.addDocumentAction((actions)=>{
|
1895
|
+
// When enabled the bulk locale publish action should be the first action
|
1896
|
+
// in 'More Document Actions' and therefore the third action in the array
|
1897
|
+
actions.splice(2, 0, BulkLocalePublishAction);
|
1898
|
+
actions.splice(5, 0, BulkLocaleUnpublishAction);
|
1899
|
+
return actions;
|
1900
|
+
});
|
1901
|
+
contentManager.injectComponent('listView', 'actions', {
|
1902
|
+
name: 'i18n-locale-filter',
|
1903
|
+
Component: LocalePicker
|
1904
|
+
});
|
1905
|
+
contentManager.injectComponent('listView', 'publishModalAdditionalInfos', {
|
1906
|
+
name: 'i18n-publish-bullets-in-modal',
|
1907
|
+
Component: PublishModalAdditionalInfo
|
1908
|
+
});
|
1909
|
+
contentManager.injectComponent('listView', 'unpublishModalAdditionalInfos', {
|
1910
|
+
name: 'i18n-unpublish-bullets-in-modal',
|
1911
|
+
Component: UnpublishModalAdditionalInfo
|
1912
|
+
});
|
1913
|
+
contentManager.injectComponent('listView', 'deleteModalAdditionalInfos', {
|
1914
|
+
name: 'i18n-delete-bullets-in-modal',
|
1915
|
+
Component: DeleteModalAdditionalInfo
|
1916
|
+
});
|
1917
|
+
const ctbPlugin = app.getPlugin('content-type-builder');
|
1918
|
+
if (ctbPlugin) {
|
1919
|
+
const ctbFormsAPI = ctbPlugin.apis.forms;
|
1920
|
+
ctbFormsAPI.addContentTypeSchemaMutation(mutateCTBContentTypeSchema);
|
1921
|
+
ctbFormsAPI.components.add({
|
1922
|
+
id: 'checkboxConfirmation',
|
1923
|
+
component: CheckboxConfirmation
|
1924
|
+
});
|
1925
|
+
ctbFormsAPI.extendContentType({
|
1926
|
+
validator: ()=>({
|
1927
|
+
i18n: yup.object().shape({
|
1928
|
+
localized: yup.bool()
|
1929
|
+
})
|
1930
|
+
}),
|
1931
|
+
form: {
|
1932
|
+
advanced () {
|
1933
|
+
return [
|
1934
|
+
{
|
1935
|
+
name: 'pluginOptions.i18n.localized',
|
1936
|
+
description: {
|
1937
|
+
id: getTranslation('plugin.schema.i18n.localized.description-content-type'),
|
1938
|
+
defaultMessage: 'Allows translating an entry into different languages'
|
1939
|
+
},
|
1940
|
+
type: 'checkboxConfirmation',
|
1941
|
+
intlLabel: {
|
1942
|
+
id: getTranslation('plugin.schema.i18n.localized.label-content-type'),
|
1943
|
+
defaultMessage: 'Localization'
|
1944
|
+
}
|
1945
|
+
}
|
1946
|
+
];
|
1947
|
+
}
|
1948
|
+
}
|
1949
|
+
});
|
1950
|
+
ctbFormsAPI.extendFields(LOCALIZED_FIELDS, {
|
1951
|
+
form: {
|
1952
|
+
advanced ({ contentTypeSchema, forTarget, type, step }) {
|
1953
|
+
if (forTarget !== 'contentType') {
|
1954
|
+
return [];
|
1955
|
+
}
|
1956
|
+
const hasI18nEnabled = get(contentTypeSchema, [
|
1957
|
+
'schema',
|
1958
|
+
'pluginOptions',
|
1959
|
+
'i18n',
|
1960
|
+
'localized'
|
1961
|
+
], false);
|
1962
|
+
if (!hasI18nEnabled) {
|
1963
|
+
return [];
|
1964
|
+
}
|
1965
|
+
if (type === 'component' && step === '1') {
|
1966
|
+
return [];
|
1967
|
+
}
|
1968
|
+
return [
|
1969
|
+
{
|
1970
|
+
name: 'pluginOptions.i18n.localized',
|
1971
|
+
description: {
|
1972
|
+
id: getTranslation('plugin.schema.i18n.localized.description-field'),
|
1973
|
+
defaultMessage: 'The field can have different values in each locale'
|
1974
|
+
},
|
1975
|
+
type: 'checkbox',
|
1976
|
+
intlLabel: {
|
1977
|
+
id: getTranslation('plugin.schema.i18n.localized.label-field'),
|
1978
|
+
defaultMessage: 'Enable localization for this field'
|
1979
|
+
}
|
1980
|
+
}
|
1981
|
+
];
|
1982
|
+
}
|
1983
|
+
}
|
1984
|
+
});
|
1985
|
+
}
|
1986
|
+
},
|
1987
|
+
async registerTrads ({ locales }) {
|
1988
|
+
const importedTrads = await Promise.all(locales.map((locale)=>{
|
1989
|
+
return __variableDynamicImportRuntime1__(`./translations/${locale}.json`).then(({ default: data })=>{
|
1990
|
+
return {
|
1991
|
+
data: prefixPluginTranslations(data, pluginId),
|
1992
|
+
locale
|
1993
|
+
};
|
1994
|
+
}).catch(()=>{
|
1995
|
+
return {
|
1996
|
+
data: {},
|
1997
|
+
locale
|
1998
|
+
};
|
1999
|
+
});
|
2000
|
+
}));
|
2001
|
+
return Promise.resolve(importedTrads);
|
2002
|
+
}
|
2003
|
+
};
|
2004
|
+
|
2005
|
+
export { PERMISSIONS as P, useGetDefaultLocalesQuery as a, useDeleteLocaleMutation as b, useUpdateLocaleMutation as c, useGetLocalesQuery as d, getTranslation as g, index as i, useCreateLocaleMutation as u };
|
2006
|
+
//# sourceMappingURL=index-k3BHSNs0.mjs.map
|