@strapi/content-manager 0.0.0-experimental.e60ec1829240dae21c1e1d29076681c322288813 → 0.0.0-experimental.e9122b401c96877b6707775c4f893660eab93ae3

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 (180) hide show
  1. package/LICENSE +18 -3
  2. package/dist/_chunks/{CardDragPreview-DSVYodBX.js → CardDragPreview-C0QyJgRA.js} +10 -14
  3. package/dist/_chunks/CardDragPreview-C0QyJgRA.js.map +1 -0
  4. package/dist/_chunks/{CardDragPreview-ikSG4M46.mjs → CardDragPreview-DOxamsuj.mjs} +7 -9
  5. package/dist/_chunks/CardDragPreview-DOxamsuj.mjs.map +1 -0
  6. package/dist/_chunks/{ComponentConfigurationPage-BPvzFjM7.mjs → ComponentConfigurationPage-CpBFh6_r.mjs} +3 -3
  7. package/dist/_chunks/{ComponentConfigurationPage-BPvzFjM7.mjs.map → ComponentConfigurationPage-CpBFh6_r.mjs.map} +1 -1
  8. package/dist/_chunks/{ComponentConfigurationPage-DjWJdz6Y.js → ComponentConfigurationPage-_zF8p6CY.js} +3 -3
  9. package/dist/_chunks/{ComponentConfigurationPage-DjWJdz6Y.js.map → ComponentConfigurationPage-_zF8p6CY.js.map} +1 -1
  10. package/dist/_chunks/{ComponentIcon-BBQsYCVn.js → ComponentIcon-BXdiCGQp.js} +8 -2
  11. package/dist/_chunks/ComponentIcon-BXdiCGQp.js.map +1 -0
  12. package/dist/_chunks/{ComponentIcon-BOFnK76n.mjs → ComponentIcon-u4bIXTFY.mjs} +9 -3
  13. package/dist/_chunks/ComponentIcon-u4bIXTFY.mjs.map +1 -0
  14. package/dist/_chunks/{EditConfigurationPage-DacbqQ_f.mjs → EditConfigurationPage-CE_yavTi.mjs} +3 -3
  15. package/dist/_chunks/{EditConfigurationPage-DacbqQ_f.mjs.map → EditConfigurationPage-CE_yavTi.mjs.map} +1 -1
  16. package/dist/_chunks/{EditConfigurationPage-Dmv83RlS.js → EditConfigurationPage-_aG2DJSU.js} +3 -3
  17. package/dist/_chunks/{EditConfigurationPage-Dmv83RlS.js.map → EditConfigurationPage-_aG2DJSU.js.map} +1 -1
  18. package/dist/_chunks/{EditViewPage-DDS6H9HO.mjs → EditViewPage-DeTn7rAF.mjs} +59 -48
  19. package/dist/_chunks/EditViewPage-DeTn7rAF.mjs.map +1 -0
  20. package/dist/_chunks/{EditViewPage-DvNpQkam.js → EditViewPage-G9uNzwYL.js} +58 -49
  21. package/dist/_chunks/EditViewPage-G9uNzwYL.js.map +1 -0
  22. package/dist/_chunks/{Field-6gvGdPBV.mjs → Field-CnCKhI1R.mjs} +995 -795
  23. package/dist/_chunks/Field-CnCKhI1R.mjs.map +1 -0
  24. package/dist/_chunks/{Field-DmVKIAOo.js → Field-DDHUWEfV.js} +1041 -842
  25. package/dist/_chunks/Field-DDHUWEfV.js.map +1 -0
  26. package/dist/_chunks/{Form-CPZC9vWa.js → Form-DYETaKUX.js} +65 -45
  27. package/dist/_chunks/Form-DYETaKUX.js.map +1 -0
  28. package/dist/_chunks/{Form-DW6K1IH-.mjs → Form-IvVVwqRL.mjs} +65 -44
  29. package/dist/_chunks/Form-IvVVwqRL.mjs.map +1 -0
  30. package/dist/_chunks/{History-Dmr9fmUA.mjs → History-BMunT-do.mjs} +148 -54
  31. package/dist/_chunks/History-BMunT-do.mjs.map +1 -0
  32. package/dist/_chunks/{History-DeAPlvtv.js → History-CnZDctSO.js} +149 -56
  33. package/dist/_chunks/History-CnZDctSO.js.map +1 -0
  34. package/dist/_chunks/{ListConfigurationPage-DPCwW5Vr.js → ListConfigurationPage-BynalOp8.js} +67 -58
  35. package/dist/_chunks/ListConfigurationPage-BynalOp8.js.map +1 -0
  36. package/dist/_chunks/{ListConfigurationPage-DhwvYcNv.mjs → ListConfigurationPage-CDqkCxgV.mjs} +63 -53
  37. package/dist/_chunks/ListConfigurationPage-CDqkCxgV.mjs.map +1 -0
  38. package/dist/_chunks/{ListViewPage-5ySZ-VUs.js → ListViewPage-I88Ouzoq.js} +126 -137
  39. package/dist/_chunks/ListViewPage-I88Ouzoq.js.map +1 -0
  40. package/dist/_chunks/{ListViewPage-BtAwuYLE.mjs → ListViewPage-_5gS-DOF.mjs} +123 -134
  41. package/dist/_chunks/ListViewPage-_5gS-DOF.mjs.map +1 -0
  42. package/dist/_chunks/{NoContentTypePage-DOC_yWOf.js → NoContentTypePage-BaWQ7HsA.js} +3 -3
  43. package/dist/_chunks/NoContentTypePage-BaWQ7HsA.js.map +1 -0
  44. package/dist/_chunks/{NoContentTypePage-DSPxnxxp.mjs → NoContentTypePage-Dht-55hr.mjs} +3 -3
  45. package/dist/_chunks/NoContentTypePage-Dht-55hr.mjs.map +1 -0
  46. package/dist/_chunks/{NoPermissionsPage-UWDC-1Tw.mjs → NoPermissionsPage-Bs8D5W_v.mjs} +2 -2
  47. package/dist/_chunks/{NoPermissionsPage-UWDC-1Tw.mjs.map → NoPermissionsPage-Bs8D5W_v.mjs.map} +1 -1
  48. package/dist/_chunks/{NoPermissionsPage-Dwu8rRJu.js → NoPermissionsPage-DCVUh5at.js} +2 -2
  49. package/dist/_chunks/{NoPermissionsPage-Dwu8rRJu.js.map → NoPermissionsPage-DCVUh5at.js.map} +1 -1
  50. package/dist/_chunks/{Relations-CgWtgnPe.js → Relations-BPgFQeGj.js} +71 -62
  51. package/dist/_chunks/Relations-BPgFQeGj.js.map +1 -0
  52. package/dist/_chunks/{Relations-J8cscLlR.mjs → Relations-Chdt5qWc.mjs} +67 -57
  53. package/dist/_chunks/Relations-Chdt5qWc.mjs.map +1 -0
  54. package/dist/_chunks/{en-C-V1_90f.js → en-BVzUkPxZ.js} +16 -8
  55. package/dist/_chunks/{en-C-V1_90f.js.map → en-BVzUkPxZ.js.map} +1 -1
  56. package/dist/_chunks/{en-MBPul9Su.mjs → en-CPTj6CjC.mjs} +16 -8
  57. package/dist/_chunks/{en-MBPul9Su.mjs.map → en-CPTj6CjC.mjs.map} +1 -1
  58. package/dist/_chunks/{index-C6AH2hEl.js → index-BhbLFX4l.js} +1752 -903
  59. package/dist/_chunks/index-BhbLFX4l.js.map +1 -0
  60. package/dist/_chunks/{index-CwRRo1V9.mjs → index-D4UGPFZC.mjs} +1778 -928
  61. package/dist/_chunks/index-D4UGPFZC.mjs.map +1 -0
  62. package/dist/_chunks/{layout-B_SXLhqf.js → layout-CYA7s0qO.js} +45 -29
  63. package/dist/_chunks/layout-CYA7s0qO.js.map +1 -0
  64. package/dist/_chunks/{layout-jIDzX0Fp.mjs → layout-D4HI4_PS.mjs} +45 -27
  65. package/dist/_chunks/layout-D4HI4_PS.mjs.map +1 -0
  66. package/dist/_chunks/{relations-CuvIgCqI.mjs → relations-1pXaYpBK.mjs} +2 -2
  67. package/dist/_chunks/{relations-CuvIgCqI.mjs.map → relations-1pXaYpBK.mjs.map} +1 -1
  68. package/dist/_chunks/{relations-iBMa_OFG.js → relations-DDZ9OxNo.js} +2 -2
  69. package/dist/_chunks/{relations-iBMa_OFG.js.map → relations-DDZ9OxNo.js.map} +1 -1
  70. package/dist/_chunks/useDebounce-CtcjDB3L.js +28 -0
  71. package/dist/_chunks/useDebounce-CtcjDB3L.js.map +1 -0
  72. package/dist/_chunks/useDebounce-DmuSJIF3.mjs +29 -0
  73. package/dist/_chunks/useDebounce-DmuSJIF3.mjs.map +1 -0
  74. package/dist/_chunks/useDragAndDrop-DdHgKsqq.mjs.map +1 -1
  75. package/dist/_chunks/useDragAndDrop-J0TUUbR6.js.map +1 -1
  76. package/dist/admin/index.js +2 -1
  77. package/dist/admin/index.js.map +1 -1
  78. package/dist/admin/index.mjs +8 -7
  79. package/dist/admin/src/components/ComponentIcon.d.ts +6 -3
  80. package/dist/admin/src/content-manager.d.ts +3 -3
  81. package/dist/admin/src/exports.d.ts +1 -0
  82. package/dist/admin/src/history/components/VersionInputRenderer.d.ts +1 -1
  83. package/dist/admin/src/history/index.d.ts +3 -0
  84. package/dist/admin/src/history/services/historyVersion.d.ts +1 -1
  85. package/dist/admin/src/hooks/useDocument.d.ts +5 -8
  86. package/dist/admin/src/hooks/useDocumentActions.d.ts +24 -3
  87. package/dist/admin/src/hooks/useDocumentLayout.d.ts +2 -2
  88. package/dist/admin/src/hooks/useDragAndDrop.d.ts +4 -4
  89. package/dist/admin/src/hooks/useKeyboardDragAndDrop.d.ts +1 -1
  90. package/dist/admin/src/index.d.ts +1 -0
  91. package/dist/admin/src/pages/EditView/components/DocumentActions.d.ts +11 -4
  92. package/dist/admin/src/pages/EditView/components/FormInputs/BlocksInput/BlocksInput.d.ts +3 -3
  93. package/dist/admin/src/pages/EditView/components/FormInputs/BlocksInput/utils/constants.d.ts +4 -0
  94. package/dist/admin/src/pages/EditView/components/FormInputs/Component/Input.d.ts +2 -2
  95. package/dist/admin/src/pages/EditView/components/FormInputs/DynamicZone/ComponentCategory.d.ts +3 -5
  96. package/dist/admin/src/pages/EditView/components/FormInputs/DynamicZone/Field.d.ts +1 -1
  97. package/dist/admin/src/pages/EditView/components/FormInputs/Relations.d.ts +30 -18
  98. package/dist/admin/src/pages/EditView/components/FormInputs/UID.d.ts +2 -2
  99. package/dist/admin/src/pages/EditView/components/FormInputs/Wysiwyg/EditorLayout.d.ts +3 -49
  100. package/dist/admin/src/pages/EditView/components/FormInputs/Wysiwyg/Field.d.ts +2 -2
  101. package/dist/admin/src/pages/EditView/components/FormInputs/Wysiwyg/WysiwygFooter.d.ts +2 -2
  102. package/dist/admin/src/pages/EditView/components/FormInputs/Wysiwyg/WysiwygStyles.d.ts +16 -53
  103. package/dist/admin/src/pages/EditView/components/Header.d.ts +10 -11
  104. package/dist/admin/src/pages/EditView/components/InputRenderer.d.ts +2 -10
  105. package/dist/admin/src/pages/ListView/components/BulkActions/Actions.d.ts +3 -30
  106. package/dist/admin/src/pages/ListView/components/BulkActions/ConfirmBulkActionDialog.d.ts +2 -2
  107. package/dist/admin/src/pages/ListView/components/BulkActions/PublishAction.d.ts +9 -26
  108. package/dist/admin/src/services/api.d.ts +2 -3
  109. package/dist/admin/src/services/components.d.ts +2 -2
  110. package/dist/admin/src/services/contentTypes.d.ts +5 -5
  111. package/dist/admin/src/services/documents.d.ts +31 -17
  112. package/dist/admin/src/services/init.d.ts +2 -2
  113. package/dist/admin/src/services/relations.d.ts +3 -3
  114. package/dist/admin/src/services/uid.d.ts +3 -3
  115. package/dist/admin/src/utils/api.d.ts +4 -18
  116. package/dist/admin/src/utils/validation.d.ts +5 -7
  117. package/dist/server/index.js +436 -281
  118. package/dist/server/index.js.map +1 -1
  119. package/dist/server/index.mjs +444 -289
  120. package/dist/server/index.mjs.map +1 -1
  121. package/dist/server/src/controllers/collection-types.d.ts.map +1 -1
  122. package/dist/server/src/controllers/relations.d.ts.map +1 -1
  123. package/dist/server/src/controllers/single-types.d.ts.map +1 -1
  124. package/dist/server/src/controllers/uid.d.ts.map +1 -1
  125. package/dist/server/src/controllers/utils/metadata.d.ts +8 -0
  126. package/dist/server/src/controllers/utils/metadata.d.ts.map +1 -0
  127. package/dist/server/src/controllers/validation/dimensions.d.ts +11 -0
  128. package/dist/server/src/controllers/validation/dimensions.d.ts.map +1 -0
  129. package/dist/server/src/controllers/validation/index.d.ts +1 -1
  130. package/dist/server/src/history/services/history.d.ts.map +1 -1
  131. package/dist/server/src/history/services/lifecycles.d.ts.map +1 -1
  132. package/dist/server/src/history/services/utils.d.ts +2 -1
  133. package/dist/server/src/history/services/utils.d.ts.map +1 -1
  134. package/dist/server/src/index.d.ts +18 -39
  135. package/dist/server/src/index.d.ts.map +1 -1
  136. package/dist/server/src/policies/hasPermissions.d.ts.map +1 -1
  137. package/dist/server/src/services/document-manager.d.ts +13 -12
  138. package/dist/server/src/services/document-manager.d.ts.map +1 -1
  139. package/dist/server/src/services/document-metadata.d.ts +8 -29
  140. package/dist/server/src/services/document-metadata.d.ts.map +1 -1
  141. package/dist/server/src/services/index.d.ts +18 -39
  142. package/dist/server/src/services/index.d.ts.map +1 -1
  143. package/dist/server/src/services/permission-checker.d.ts.map +1 -1
  144. package/dist/server/src/services/utils/populate.d.ts +8 -1
  145. package/dist/server/src/services/utils/populate.d.ts.map +1 -1
  146. package/dist/shared/contracts/collection-types.d.ts +17 -7
  147. package/dist/shared/contracts/collection-types.d.ts.map +1 -1
  148. package/dist/shared/contracts/relations.d.ts +2 -2
  149. package/dist/shared/contracts/relations.d.ts.map +1 -1
  150. package/package.json +14 -15
  151. package/dist/_chunks/CardDragPreview-DSVYodBX.js.map +0 -1
  152. package/dist/_chunks/CardDragPreview-ikSG4M46.mjs.map +0 -1
  153. package/dist/_chunks/ComponentIcon-BBQsYCVn.js.map +0 -1
  154. package/dist/_chunks/ComponentIcon-BOFnK76n.mjs.map +0 -1
  155. package/dist/_chunks/EditViewPage-DDS6H9HO.mjs.map +0 -1
  156. package/dist/_chunks/EditViewPage-DvNpQkam.js.map +0 -1
  157. package/dist/_chunks/Field-6gvGdPBV.mjs.map +0 -1
  158. package/dist/_chunks/Field-DmVKIAOo.js.map +0 -1
  159. package/dist/_chunks/Form-CPZC9vWa.js.map +0 -1
  160. package/dist/_chunks/Form-DW6K1IH-.mjs.map +0 -1
  161. package/dist/_chunks/History-DeAPlvtv.js.map +0 -1
  162. package/dist/_chunks/History-Dmr9fmUA.mjs.map +0 -1
  163. package/dist/_chunks/ListConfigurationPage-DPCwW5Vr.js.map +0 -1
  164. package/dist/_chunks/ListConfigurationPage-DhwvYcNv.mjs.map +0 -1
  165. package/dist/_chunks/ListViewPage-5ySZ-VUs.js.map +0 -1
  166. package/dist/_chunks/ListViewPage-BtAwuYLE.mjs.map +0 -1
  167. package/dist/_chunks/NoContentTypePage-DOC_yWOf.js.map +0 -1
  168. package/dist/_chunks/NoContentTypePage-DSPxnxxp.mjs.map +0 -1
  169. package/dist/_chunks/Relations-CgWtgnPe.js.map +0 -1
  170. package/dist/_chunks/Relations-J8cscLlR.mjs.map +0 -1
  171. package/dist/_chunks/index-C6AH2hEl.js.map +0 -1
  172. package/dist/_chunks/index-CwRRo1V9.mjs.map +0 -1
  173. package/dist/_chunks/layout-B_SXLhqf.js.map +0 -1
  174. package/dist/_chunks/layout-jIDzX0Fp.mjs.map +0 -1
  175. package/dist/_chunks/urls-CbOsUOoW.mjs +0 -7
  176. package/dist/_chunks/urls-CbOsUOoW.mjs.map +0 -1
  177. package/dist/_chunks/urls-DzZya_gm.js +0 -6
  178. package/dist/_chunks/urls-DzZya_gm.js.map +0 -1
  179. package/dist/server/src/controllers/utils/dimensions.d.ts +0 -5
  180. package/dist/server/src/controllers/utils/dimensions.d.ts.map +0 -1
@@ -2,17 +2,15 @@
2
2
  const Icons = require("@strapi/icons");
3
3
  const jsxRuntime = require("react/jsx-runtime");
4
4
  const strapiAdmin = require("@strapi/admin/strapi-admin");
5
- const qs = require("qs");
6
- const reactIntl = require("react-intl");
7
- const reactRouterDom = require("react-router-dom");
8
5
  const React = require("react");
9
6
  const designSystem = require("@strapi/design-system");
10
- const styled = require("styled-components");
7
+ const reactIntl = require("react-intl");
8
+ const reactRouterDom = require("react-router-dom");
11
9
  const yup = require("yup");
12
- const react = require("@reduxjs/toolkit/query/react");
13
- const axios = require("axios");
14
10
  const pipe = require("lodash/fp/pipe");
15
11
  const dateFns = require("date-fns");
12
+ const styledComponents = require("styled-components");
13
+ const qs = require("qs");
16
14
  const toolkit = require("@reduxjs/toolkit");
17
15
  const _interopDefault = (e) => e && e.__esModule ? e : { default: e };
18
16
  function _interopNamespace(e) {
@@ -34,7 +32,6 @@ function _interopNamespace(e) {
34
32
  return Object.freeze(n);
35
33
  }
36
34
  const React__namespace = /* @__PURE__ */ _interopNamespace(React);
37
- const styled__default = /* @__PURE__ */ _interopDefault(styled);
38
35
  const yup__namespace = /* @__PURE__ */ _interopNamespace(yup);
39
36
  const pipe__default = /* @__PURE__ */ _interopDefault(pipe);
40
37
  const __variableDynamicImportRuntimeHelper = (glob, path) => {
@@ -73,42 +70,6 @@ const useInjectionZone = (area) => {
73
70
  const [page, position] = area.split(".");
74
71
  return contentManagerPlugin.getInjectedComponents(page, position);
75
72
  };
76
- const HistoryAction = ({ model, document }) => {
77
- const { formatMessage } = reactIntl.useIntl();
78
- const [{ query }] = strapiAdmin.useQueryParams();
79
- const navigate = reactRouterDom.useNavigate();
80
- const pluginsQueryParams = qs.stringify({ plugins: query.plugins }, { encode: false });
81
- if (!window.strapi.features.isEnabled("cms-content-history")) {
82
- return null;
83
- }
84
- return {
85
- icon: /* @__PURE__ */ jsxRuntime.jsx(Icons.ClockCounterClockwise, {}),
86
- label: formatMessage({
87
- id: "content-manager.history.document-action",
88
- defaultMessage: "Content History"
89
- }),
90
- onClick: () => navigate({ pathname: "history", search: pluginsQueryParams }),
91
- disabled: (
92
- /**
93
- * The user is creating a new document.
94
- * It hasn't been saved yet, so there's no history to go to
95
- */
96
- !document || /**
97
- * The document has been created but the current dimension has never been saved.
98
- * For example, the user is creating a new locale in an existing document,
99
- * so there's no history for the document in that locale
100
- */
101
- !document.id || /**
102
- * History is only available for content types created by the user.
103
- * These have the `api::` prefix, as opposed to the ones created by Strapi or plugins,
104
- * which start with `admin::` or `plugin::`
105
- */
106
- !model.startsWith("api::")
107
- ),
108
- position: "header"
109
- };
110
- };
111
- HistoryAction.type = "history";
112
73
  const ID = "id";
113
74
  const CREATED_BY_ATTRIBUTE_NAME = "createdBy";
114
75
  const UPDATED_BY_ATTRIBUTE_NAME = "updatedBy";
@@ -179,9 +140,8 @@ const DocumentRBAC = ({ children, permissions }) => {
179
140
  const name = removeNumericalStrings(fieldName.split("."));
180
141
  const componentFieldNames = fieldsUserCanAction.filter((field) => field.split(".").length > 1);
181
142
  if (fieldType === "component") {
182
- const componentOrDynamicZoneFields = componentFieldNames.map((field) => field.split("."));
183
- return componentOrDynamicZoneFields.some((field) => {
184
- return field.includes(fieldName);
143
+ return componentFieldNames.some((field) => {
144
+ return field.includes(name.join("."));
185
145
  });
186
146
  }
187
147
  if (name.length > 1) {
@@ -211,89 +171,20 @@ const extractAndDedupeFields = (permissions = []) => permissions.flatMap((permis
211
171
  (field, index2, arr) => arr.indexOf(field) === index2 && typeof field === "string"
212
172
  );
213
173
  const removeNumericalStrings = (arr) => arr.filter((item) => isNaN(Number(item)));
214
- const buildValidParams = (query) => {
215
- if (!query)
216
- return query;
217
- const { plugins: _, ...validQueryParams } = {
218
- ...query,
219
- ...Object.values(query?.plugins ?? {}).reduce(
220
- (acc, current) => Object.assign(acc, current),
221
- {}
222
- )
223
- };
224
- if ("_q" in validQueryParams) {
225
- validQueryParams._q = encodeURIComponent(validQueryParams._q);
226
- }
227
- return validQueryParams;
228
- };
229
- const axiosBaseQuery = () => async (query, { signal }) => {
230
- try {
231
- const { get, post, del, put } = strapiAdmin.getFetchClient();
232
- if (typeof query === "string") {
233
- const result = await get(query, { signal });
234
- return { data: result.data };
235
- } else {
236
- const { url, method = "GET", data, config } = query;
237
- if (method === "POST") {
238
- const result2 = await post(url, data, { ...config, signal });
239
- return { data: result2.data };
240
- }
241
- if (method === "DELETE") {
242
- const result2 = await del(url, { ...config, signal });
243
- return { data: result2.data };
244
- }
245
- if (method === "PUT") {
246
- const result2 = await put(url, data, { ...config, signal });
247
- return { data: result2.data };
248
- }
249
- const result = await get(url, { ...config, signal });
250
- return { data: result.data };
251
- }
252
- } catch (err) {
253
- if (axios.isAxiosError(err)) {
254
- if (typeof err.response?.data === "object" && err.response?.data !== null && "error" in err.response?.data) {
255
- return { data: void 0, error: err.response?.data.error };
256
- } else {
257
- return {
258
- data: void 0,
259
- error: {
260
- name: "UnknownError",
261
- message: "There was an unknown error response from the API",
262
- details: err.response?.data,
263
- status: err.response?.status
264
- }
265
- };
266
- }
267
- }
268
- const error = err;
269
- return {
270
- data: void 0,
271
- error: {
272
- name: error.name,
273
- message: error.message,
274
- stack: error.stack
275
- }
276
- };
277
- }
278
- };
279
- const isBaseQueryError = (error) => {
280
- return error.name !== void 0;
281
- };
282
- const contentManagerApi = react.createApi({
283
- reducerPath: "contentManagerApi",
284
- baseQuery: axiosBaseQuery(),
285
- tagTypes: [
174
+ const contentManagerApi = strapiAdmin.adminApi.enhanceEndpoints({
175
+ addTagTypes: [
286
176
  "ComponentConfiguration",
287
177
  "ContentTypesConfiguration",
288
178
  "ContentTypeSettings",
289
179
  "Document",
290
180
  "InitialData",
291
181
  "HistoryVersion",
292
- "Relations"
293
- ],
294
- endpoints: () => ({})
182
+ "Relations",
183
+ "UidAvailability"
184
+ ]
295
185
  });
296
186
  const documentApi = contentManagerApi.injectEndpoints({
187
+ overrideExisting: true,
297
188
  endpoints: (builder) => ({
298
189
  autoCloneDocument: builder.mutation({
299
190
  query: ({ model, sourceId, query }) => ({
@@ -303,7 +194,12 @@ const documentApi = contentManagerApi.injectEndpoints({
303
194
  params: query
304
195
  }
305
196
  }),
306
- invalidatesTags: (_result, _error, { model }) => [{ type: "Document", id: `${model}_LIST` }]
197
+ invalidatesTags: (_result, error, { model }) => {
198
+ if (error) {
199
+ return [];
200
+ }
201
+ return [{ type: "Document", id: `${model}_LIST` }];
202
+ }
307
203
  }),
308
204
  cloneDocument: builder.mutation({
309
205
  query: ({ model, sourceId, data, params }) => ({
@@ -314,7 +210,10 @@ const documentApi = contentManagerApi.injectEndpoints({
314
210
  params
315
211
  }
316
212
  }),
317
- invalidatesTags: (_result, _error, { model }) => [{ type: "Document", id: `${model}_LIST` }]
213
+ invalidatesTags: (_result, _error, { model }) => [
214
+ { type: "Document", id: `${model}_LIST` },
215
+ { type: "UidAvailability", id: model }
216
+ ]
318
217
  }),
319
218
  /**
320
219
  * Creates a new collection-type document. This should ONLY be used for collection-types.
@@ -331,7 +230,8 @@ const documentApi = contentManagerApi.injectEndpoints({
331
230
  }),
332
231
  invalidatesTags: (result, _error, { model }) => [
333
232
  { type: "Document", id: `${model}_LIST` },
334
- "Relations"
233
+ "Relations",
234
+ { type: "UidAvailability", id: model }
335
235
  ]
336
236
  }),
337
237
  deleteDocument: builder.mutation({
@@ -347,12 +247,15 @@ const documentApi = contentManagerApi.injectEndpoints({
347
247
  ]
348
248
  }),
349
249
  deleteManyDocuments: builder.mutation({
350
- query: ({ model, ...body }) => ({
250
+ query: ({ model, params, ...body }) => ({
351
251
  url: `/content-manager/collection-types/${model}/actions/bulkDelete`,
352
252
  method: "POST",
353
- data: body
253
+ data: body,
254
+ config: {
255
+ params
256
+ }
354
257
  }),
355
- invalidatesTags: (_res, _error, { model, documentIds }) => documentIds.map((id) => ({ type: "Document", id: `${model}_${id}` }))
258
+ invalidatesTags: (_res, _error, { model }) => [{ type: "Document", id: `${model}_LIST` }]
356
259
  }),
357
260
  discardDocument: builder.mutation({
358
261
  query: ({ collectionType, model, documentId, params }) => ({
@@ -369,7 +272,8 @@ const documentApi = contentManagerApi.injectEndpoints({
369
272
  id: collectionType !== SINGLE_TYPES ? `${model}_${documentId}` : model
370
273
  },
371
274
  { type: "Document", id: `${model}_LIST` },
372
- "Relations"
275
+ "Relations",
276
+ { type: "UidAvailability", id: model }
373
277
  ];
374
278
  }
375
279
  }),
@@ -387,6 +291,7 @@ const documentApi = contentManagerApi.injectEndpoints({
387
291
  }),
388
292
  providesTags: (result, _error, arg) => {
389
293
  return [
294
+ { type: "Document", id: `ALL_LIST` },
390
295
  { type: "Document", id: `${arg.model}_LIST` },
391
296
  ...result?.results.map(({ documentId }) => ({
392
297
  type: "Document",
@@ -425,6 +330,11 @@ const documentApi = contentManagerApi.injectEndpoints({
425
330
  {
426
331
  type: "Document",
427
332
  id: collectionType !== SINGLE_TYPES ? `${model}_${result && "documentId" in result ? result.documentId : documentId}` : model
333
+ },
334
+ // Make it easy to invalidate all individual documents queries for a model
335
+ {
336
+ type: "Document",
337
+ id: `${model}_ALL_ITEMS`
428
338
  }
429
339
  ];
430
340
  }
@@ -463,10 +373,13 @@ const documentApi = contentManagerApi.injectEndpoints({
463
373
  }
464
374
  }),
465
375
  publishManyDocuments: builder.mutation({
466
- query: ({ model, ...body }) => ({
376
+ query: ({ model, params, ...body }) => ({
467
377
  url: `/content-manager/collection-types/${model}/actions/bulkPublish`,
468
378
  method: "POST",
469
- data: body
379
+ data: body,
380
+ config: {
381
+ params
382
+ }
470
383
  }),
471
384
  invalidatesTags: (_res, _error, { model, documentIds }) => documentIds.map((id) => ({ type: "Document", id: `${model}_${id}` }))
472
385
  }),
@@ -485,8 +398,21 @@ const documentApi = contentManagerApi.injectEndpoints({
485
398
  type: "Document",
486
399
  id: collectionType !== SINGLE_TYPES ? `${model}_${documentId}` : model
487
400
  },
488
- "Relations"
401
+ "Relations",
402
+ { type: "UidAvailability", id: model }
489
403
  ];
404
+ },
405
+ async onQueryStarted({ data, ...patch }, { dispatch, queryFulfilled }) {
406
+ const patchResult = dispatch(
407
+ documentApi.util.updateQueryData("getDocument", patch, (draft) => {
408
+ Object.assign(draft.data, data);
409
+ })
410
+ );
411
+ try {
412
+ await queryFulfilled;
413
+ } catch {
414
+ patchResult.undo();
415
+ }
490
416
  }
491
417
  }),
492
418
  unpublishDocument: builder.mutation({
@@ -508,10 +434,13 @@ const documentApi = contentManagerApi.injectEndpoints({
508
434
  }
509
435
  }),
510
436
  unpublishManyDocuments: builder.mutation({
511
- query: ({ model, ...body }) => ({
437
+ query: ({ model, params, ...body }) => ({
512
438
  url: `/content-manager/collection-types/${model}/actions/bulkUnpublish`,
513
439
  method: "POST",
514
- data: body
440
+ data: body,
441
+ config: {
442
+ params
443
+ }
515
444
  }),
516
445
  invalidatesTags: (_res, _error, { model, documentIds }) => documentIds.map((id) => ({ type: "Document", id: `${model}_${id}` }))
517
446
  })
@@ -535,7 +464,25 @@ const {
535
464
  useUnpublishDocumentMutation,
536
465
  useUnpublishManyDocumentsMutation
537
466
  } = documentApi;
538
- const createYupSchema = (attributes = {}, components = {}) => {
467
+ const buildValidParams = (query) => {
468
+ if (!query)
469
+ return query;
470
+ const { plugins: _, ...validQueryParams } = {
471
+ ...query,
472
+ ...Object.values(query?.plugins ?? {}).reduce(
473
+ (acc, current) => Object.assign(acc, current),
474
+ {}
475
+ )
476
+ };
477
+ if ("_q" in validQueryParams) {
478
+ validQueryParams._q = encodeURIComponent(validQueryParams._q);
479
+ }
480
+ return validQueryParams;
481
+ };
482
+ const isBaseQueryError = (error) => {
483
+ return error.name !== void 0;
484
+ };
485
+ const createYupSchema = (attributes = {}, components = {}, options = { status: null }) => {
539
486
  const createModelSchema = (attributes2) => yup__namespace.object().shape(
540
487
  Object.entries(attributes2).reduce((acc, [name, attribute]) => {
541
488
  if (DOCUMENT_META_FIELDS.includes(name)) {
@@ -548,7 +495,7 @@ const createYupSchema = (attributes = {}, components = {}) => {
548
495
  addMinValidation,
549
496
  addMaxValidation,
550
497
  addRegexValidation
551
- ].map((fn) => fn(attribute));
498
+ ].map((fn) => fn(attribute, options));
552
499
  const transformSchema = pipe__default.default(...validations);
553
500
  switch (attribute.type) {
554
501
  case "component": {
@@ -574,10 +521,14 @@ const createYupSchema = (attributes = {}, components = {}) => {
574
521
  yup__namespace.array().of(
575
522
  yup__namespace.lazy(
576
523
  (data) => {
577
- const { attributes: attributes3 } = components[data.__component];
578
- return yup__namespace.object().shape({
524
+ const attributes3 = components?.[data?.__component]?.attributes;
525
+ const validation = yup__namespace.object().shape({
579
526
  __component: yup__namespace.string().required().oneOf(Object.keys(components))
580
- }).nullable(false).concat(createModelSchema(attributes3));
527
+ }).nullable(false);
528
+ if (!attributes3) {
529
+ return validation;
530
+ }
531
+ return validation.concat(createModelSchema(attributes3));
581
532
  }
582
533
  )
583
534
  )
@@ -587,11 +538,25 @@ const createYupSchema = (attributes = {}, components = {}) => {
587
538
  return {
588
539
  ...acc,
589
540
  [name]: transformSchema(
590
- yup__namespace.array().of(
591
- yup__namespace.object().shape({
592
- id: yup__namespace.string().required()
593
- })
594
- )
541
+ yup__namespace.lazy((value) => {
542
+ if (!value) {
543
+ return yup__namespace.mixed().nullable(true);
544
+ } else if (Array.isArray(value)) {
545
+ return yup__namespace.array().of(
546
+ yup__namespace.object().shape({
547
+ id: yup__namespace.string().required()
548
+ })
549
+ );
550
+ } else if (typeof value === "object") {
551
+ return yup__namespace.object();
552
+ } else {
553
+ return yup__namespace.mixed().test(
554
+ "type-error",
555
+ "Relation values must be either null, an array of objects with {id} or an object.",
556
+ () => false
557
+ );
558
+ }
559
+ })
595
560
  )
596
561
  };
597
562
  default:
@@ -631,6 +596,14 @@ const createAttributeSchema = (attribute) => {
631
596
  if (!value || typeof value === "string" && value.length === 0) {
632
597
  return true;
633
598
  }
599
+ if (typeof value === "object") {
600
+ try {
601
+ JSON.stringify(value);
602
+ return true;
603
+ } catch (err) {
604
+ return false;
605
+ }
606
+ }
634
607
  try {
635
608
  JSON.parse(value);
636
609
  return true;
@@ -649,16 +622,30 @@ const createAttributeSchema = (attribute) => {
649
622
  return yup__namespace.mixed();
650
623
  }
651
624
  };
652
- const addRequiredValidation = (attribute) => (schema) => {
653
- if (attribute.required) {
654
- return schema.required({
655
- id: strapiAdmin.translatedErrors.required.id,
656
- defaultMessage: "This field is required."
657
- });
625
+ const nullableSchema = (schema) => {
626
+ return schema?.nullable ? schema.nullable() : (
627
+ // In some cases '.nullable' will not be available on the schema.
628
+ // e.g. when the schema has been built using yup.lazy (e.g. for relations).
629
+ // In these cases we should just return the schema as it is.
630
+ schema
631
+ );
632
+ };
633
+ const addRequiredValidation = (attribute, options) => (schema) => {
634
+ if (options.status === "draft") {
635
+ return nullableSchema(schema);
636
+ }
637
+ if ((attribute.type === "component" && attribute.repeatable || attribute.type === "dynamiczone") && attribute.required && "min" in schema) {
638
+ return schema.min(1, strapiAdmin.translatedErrors.required);
639
+ }
640
+ if (attribute.required && attribute.type !== "relation") {
641
+ return schema.required(strapiAdmin.translatedErrors.required);
658
642
  }
659
- return schema.nullable();
643
+ return nullableSchema(schema);
660
644
  };
661
- const addMinLengthValidation = (attribute) => (schema) => {
645
+ const addMinLengthValidation = (attribute, options) => (schema) => {
646
+ if (options.status === "draft") {
647
+ return schema;
648
+ }
662
649
  if ("minLength" in attribute && attribute.minLength && Number.isInteger(attribute.minLength) && "min" in schema) {
663
650
  return schema.min(attribute.minLength, {
664
651
  ...strapiAdmin.translatedErrors.minLength,
@@ -680,9 +667,31 @@ const addMaxLengthValidation = (attribute) => (schema) => {
680
667
  }
681
668
  return schema;
682
669
  };
683
- const addMinValidation = (attribute) => (schema) => {
670
+ const addMinValidation = (attribute, options) => (schema) => {
684
671
  if ("min" in attribute) {
685
672
  const min = toInteger(attribute.min);
673
+ if (attribute.type === "component" && attribute.repeatable || attribute.type === "dynamiczone") {
674
+ if (options.status !== "draft" && !attribute.required && "test" in schema && min) {
675
+ return schema.test(
676
+ "custom-min",
677
+ {
678
+ ...strapiAdmin.translatedErrors.min,
679
+ values: {
680
+ min: attribute.min
681
+ }
682
+ },
683
+ (value) => {
684
+ if (!value) {
685
+ return true;
686
+ }
687
+ if (Array.isArray(value) && value.length === 0) {
688
+ return true;
689
+ }
690
+ return value.length >= min;
691
+ }
692
+ );
693
+ }
694
+ }
686
695
  if ("min" in schema && min) {
687
696
  return schema.min(min, {
688
697
  ...strapiAdmin.translatedErrors.min,
@@ -728,24 +737,6 @@ const addRegexValidation = (attribute) => (schema) => {
728
737
  }
729
738
  return schema;
730
739
  };
731
- const extractValuesFromYupError = (errorType, errorParams) => {
732
- if (!errorType || !errorParams) {
733
- return {};
734
- }
735
- return {
736
- [errorType]: errorParams[errorType]
737
- };
738
- };
739
- const getInnerErrors = (error) => (error?.inner || []).reduce((acc, currentError) => {
740
- if (currentError.path) {
741
- acc[currentError.path.split("[").join(".").split("]").join("")] = {
742
- id: currentError.message,
743
- defaultMessage: currentError.message,
744
- values: extractValuesFromYupError(currentError?.type, currentError?.params)
745
- };
746
- }
747
- return acc;
748
- }, {});
749
740
  const initApi = contentManagerApi.injectEndpoints({
750
741
  endpoints: (builder) => ({
751
742
  getInitialData: builder.query({
@@ -759,27 +750,20 @@ const { useGetInitialDataQuery } = initApi;
759
750
  const useContentTypeSchema = (model) => {
760
751
  const { toggleNotification } = strapiAdmin.useNotification();
761
752
  const { _unstableFormatAPIError: formatAPIError } = strapiAdmin.useAPIErrorHandler();
762
- const { components, contentType, contentTypes, error, isLoading, isFetching } = useGetInitialDataQuery(void 0, {
763
- selectFromResult: (res) => {
764
- const contentType2 = res.data?.contentTypes.find((ct) => ct.uid === model);
765
- const componentsByKey = res.data?.components.reduce(
766
- (acc, component) => {
767
- acc[component.uid] = component;
768
- return acc;
769
- },
770
- {}
771
- );
772
- const components2 = extractContentTypeComponents(contentType2?.attributes, componentsByKey);
773
- return {
774
- isLoading: res.isLoading,
775
- isFetching: res.isFetching,
776
- error: res.error,
777
- components: Object.keys(components2).length === 0 ? void 0 : components2,
778
- contentType: contentType2,
779
- contentTypes: res.data?.contentTypes ?? []
780
- };
781
- }
782
- });
753
+ const { data, error, isLoading, isFetching } = useGetInitialDataQuery(void 0);
754
+ const { components, contentType, contentTypes } = React__namespace.useMemo(() => {
755
+ const contentType2 = data?.contentTypes.find((ct) => ct.uid === model);
756
+ const componentsByKey = data?.components.reduce((acc, component) => {
757
+ acc[component.uid] = component;
758
+ return acc;
759
+ }, {});
760
+ const components2 = extractContentTypeComponents(contentType2?.attributes, componentsByKey);
761
+ return {
762
+ components: Object.keys(components2).length === 0 ? void 0 : components2,
763
+ contentType: contentType2,
764
+ contentTypes: data?.contentTypes ?? []
765
+ };
766
+ }, [model, data]);
783
767
  React__namespace.useEffect(() => {
784
768
  if (error) {
785
769
  toggleNotification({
@@ -834,7 +818,10 @@ const useDocument = (args, opts) => {
834
818
  isLoading: isLoadingDocument,
835
819
  isFetching: isFetchingDocument,
836
820
  error
837
- } = useGetDocumentQuery(args, opts);
821
+ } = useGetDocumentQuery(args, {
822
+ ...opts,
823
+ skip: !args.documentId && args.collectionType !== SINGLE_TYPES || opts?.skip
824
+ });
838
825
  const { components, schema, isLoading: isLoadingSchema } = useContentTypeSchema(args.model);
839
826
  React__namespace.useEffect(() => {
840
827
  if (error) {
@@ -862,7 +849,7 @@ const useDocument = (args, opts) => {
862
849
  return null;
863
850
  } catch (error2) {
864
851
  if (error2 instanceof yup.ValidationError) {
865
- return getInnerErrors(error2);
852
+ return strapiAdmin.getYupValidationErrors(error2);
866
853
  }
867
854
  throw error2;
868
855
  }
@@ -920,6 +907,7 @@ const useDocumentActions = () => {
920
907
  const { formatMessage } = reactIntl.useIntl();
921
908
  const { trackUsage } = strapiAdmin.useTracking();
922
909
  const { _unstableFormatAPIError: formatAPIError } = strapiAdmin.useAPIErrorHandler();
910
+ const navigate = reactRouterDom.useNavigate();
923
911
  const [deleteDocument] = useDeleteDocumentMutation();
924
912
  const _delete = React__namespace.useCallback(
925
913
  async ({ collectionType, model, documentId, params }, trackerProperty) => {
@@ -958,14 +946,53 @@ const useDocumentActions = () => {
958
946
  },
959
947
  [trackUsage, deleteDocument, toggleNotification, formatMessage, formatAPIError]
960
948
  );
949
+ const [deleteManyDocuments] = useDeleteManyDocumentsMutation();
950
+ const deleteMany = React__namespace.useCallback(
951
+ async ({ model, documentIds, params }) => {
952
+ try {
953
+ trackUsage("willBulkDeleteEntries");
954
+ const res = await deleteManyDocuments({
955
+ model,
956
+ documentIds,
957
+ params
958
+ });
959
+ if ("error" in res) {
960
+ toggleNotification({
961
+ type: "danger",
962
+ message: formatAPIError(res.error)
963
+ });
964
+ return { error: res.error };
965
+ }
966
+ toggleNotification({
967
+ type: "success",
968
+ title: formatMessage({
969
+ id: getTranslation("success.records.delete"),
970
+ defaultMessage: "Successfully deleted."
971
+ }),
972
+ message: ""
973
+ });
974
+ trackUsage("didBulkDeleteEntries");
975
+ return res.data;
976
+ } catch (err) {
977
+ toggleNotification({
978
+ type: "danger",
979
+ message: formatMessage(DEFAULT_UNEXPECTED_ERROR_MSG)
980
+ });
981
+ trackUsage("didNotBulkDeleteEntries");
982
+ throw err;
983
+ }
984
+ },
985
+ [trackUsage, deleteManyDocuments, toggleNotification, formatMessage, formatAPIError]
986
+ );
961
987
  const [discardDocument] = useDiscardDocumentMutation();
962
988
  const discard = React__namespace.useCallback(
963
- async ({ collectionType, model, documentId }) => {
989
+ async ({ collectionType, model, documentId, params }) => {
964
990
  try {
965
991
  const res = await discardDocument({
966
992
  collectionType,
967
993
  model,
968
- documentId
994
+ documentId,
995
+ params
969
996
  });
970
997
  if ("error" in res) {
971
998
  toggleNotification({
@@ -1027,6 +1054,43 @@ const useDocumentActions = () => {
1027
1054
  },
1028
1055
  [trackUsage, publishDocument, toggleNotification, formatMessage, formatAPIError]
1029
1056
  );
1057
+ const [publishManyDocuments] = usePublishManyDocumentsMutation();
1058
+ const publishMany = React__namespace.useCallback(
1059
+ async ({ model, documentIds, params }) => {
1060
+ try {
1061
+ const res = await publishManyDocuments({
1062
+ model,
1063
+ documentIds,
1064
+ params
1065
+ });
1066
+ if ("error" in res) {
1067
+ toggleNotification({ type: "danger", message: formatAPIError(res.error) });
1068
+ return { error: res.error };
1069
+ }
1070
+ toggleNotification({
1071
+ type: "success",
1072
+ message: formatMessage({
1073
+ id: getTranslation("success.record.publish"),
1074
+ defaultMessage: "Published document"
1075
+ })
1076
+ });
1077
+ return res.data;
1078
+ } catch (err) {
1079
+ toggleNotification({
1080
+ type: "danger",
1081
+ message: formatMessage(DEFAULT_UNEXPECTED_ERROR_MSG)
1082
+ });
1083
+ throw err;
1084
+ }
1085
+ },
1086
+ [
1087
+ // trackUsage,
1088
+ publishManyDocuments,
1089
+ toggleNotification,
1090
+ formatMessage,
1091
+ formatAPIError
1092
+ ]
1093
+ );
1030
1094
  const [updateDocument] = useUpdateDocumentMutation();
1031
1095
  const update = React__namespace.useCallback(
1032
1096
  async ({ collectionType, model, documentId, params }, data, trackerProperty) => {
@@ -1101,6 +1165,41 @@ const useDocumentActions = () => {
1101
1165
  },
1102
1166
  [trackUsage, unpublishDocument, toggleNotification, formatMessage, formatAPIError]
1103
1167
  );
1168
+ const [unpublishManyDocuments] = useUnpublishManyDocumentsMutation();
1169
+ const unpublishMany = React__namespace.useCallback(
1170
+ async ({ model, documentIds, params }) => {
1171
+ try {
1172
+ trackUsage("willBulkUnpublishEntries");
1173
+ const res = await unpublishManyDocuments({
1174
+ model,
1175
+ documentIds,
1176
+ params
1177
+ });
1178
+ if ("error" in res) {
1179
+ toggleNotification({ type: "danger", message: formatAPIError(res.error) });
1180
+ return { error: res.error };
1181
+ }
1182
+ trackUsage("didBulkUnpublishEntries");
1183
+ toggleNotification({
1184
+ type: "success",
1185
+ title: formatMessage({
1186
+ id: getTranslation("success.records.unpublish"),
1187
+ defaultMessage: "Successfully unpublished."
1188
+ }),
1189
+ message: ""
1190
+ });
1191
+ return res.data;
1192
+ } catch (err) {
1193
+ toggleNotification({
1194
+ type: "danger",
1195
+ message: formatMessage(DEFAULT_UNEXPECTED_ERROR_MSG)
1196
+ });
1197
+ trackUsage("didNotBulkUnpublishEntries");
1198
+ throw err;
1199
+ }
1200
+ },
1201
+ [trackUsage, unpublishManyDocuments, toggleNotification, formatMessage, formatAPIError]
1202
+ );
1104
1203
  const [createDocument] = useCreateDocumentMutation();
1105
1204
  const create = React__namespace.useCallback(
1106
1205
  async ({ model, params }, data, trackerProperty) => {
@@ -1144,7 +1243,6 @@ const useDocumentActions = () => {
1144
1243
  sourceId
1145
1244
  });
1146
1245
  if ("error" in res) {
1147
- toggleNotification({ type: "danger", message: formatAPIError(res.error) });
1148
1246
  return { error: res.error };
1149
1247
  }
1150
1248
  toggleNotification({
@@ -1163,7 +1261,7 @@ const useDocumentActions = () => {
1163
1261
  throw err;
1164
1262
  }
1165
1263
  },
1166
- [autoCloneDocument, formatAPIError, formatMessage, toggleNotification]
1264
+ [autoCloneDocument, formatMessage, toggleNotification]
1167
1265
  );
1168
1266
  const [cloneDocument] = useCloneDocumentMutation();
1169
1267
  const clone = React__namespace.useCallback(
@@ -1189,6 +1287,7 @@ const useDocumentActions = () => {
1189
1287
  defaultMessage: "Cloned document"
1190
1288
  })
1191
1289
  });
1290
+ navigate(`../../${res.data.data.documentId}`, { relative: "path" });
1192
1291
  return res.data;
1193
1292
  } catch (err) {
1194
1293
  toggleNotification({
@@ -1199,7 +1298,7 @@ const useDocumentActions = () => {
1199
1298
  throw err;
1200
1299
  }
1201
1300
  },
1202
- [cloneDocument, trackUsage, toggleNotification, formatMessage, formatAPIError]
1301
+ [cloneDocument, trackUsage, toggleNotification, formatMessage, formatAPIError, navigate]
1203
1302
  );
1204
1303
  const [getDoc] = useLazyGetDocumentQuery();
1205
1304
  const getDocument = React__namespace.useCallback(
@@ -1214,15 +1313,18 @@ const useDocumentActions = () => {
1214
1313
  clone,
1215
1314
  create,
1216
1315
  delete: _delete,
1316
+ deleteMany,
1217
1317
  discard,
1218
1318
  getDocument,
1219
1319
  publish,
1320
+ publishMany,
1220
1321
  unpublish,
1322
+ unpublishMany,
1221
1323
  update
1222
1324
  };
1223
1325
  };
1224
1326
  const ProtectedHistoryPage = React.lazy(
1225
- () => Promise.resolve().then(() => require("./History-DeAPlvtv.js")).then((mod) => ({ default: mod.ProtectedHistoryPage }))
1327
+ () => Promise.resolve().then(() => require("./History-CnZDctSO.js")).then((mod) => ({ default: mod.ProtectedHistoryPage }))
1226
1328
  );
1227
1329
  const routes$1 = [
1228
1330
  {
@@ -1235,31 +1337,31 @@ const routes$1 = [
1235
1337
  }
1236
1338
  ];
1237
1339
  const ProtectedEditViewPage = React.lazy(
1238
- () => Promise.resolve().then(() => require("./EditViewPage-DvNpQkam.js")).then((mod) => ({ default: mod.ProtectedEditViewPage }))
1340
+ () => Promise.resolve().then(() => require("./EditViewPage-G9uNzwYL.js")).then((mod) => ({ default: mod.ProtectedEditViewPage }))
1239
1341
  );
1240
1342
  const ProtectedListViewPage = React.lazy(
1241
- () => Promise.resolve().then(() => require("./ListViewPage-5ySZ-VUs.js")).then((mod) => ({ default: mod.ProtectedListViewPage }))
1343
+ () => Promise.resolve().then(() => require("./ListViewPage-I88Ouzoq.js")).then((mod) => ({ default: mod.ProtectedListViewPage }))
1242
1344
  );
1243
1345
  const ProtectedListConfiguration = React.lazy(
1244
- () => Promise.resolve().then(() => require("./ListConfigurationPage-DPCwW5Vr.js")).then((mod) => ({
1346
+ () => Promise.resolve().then(() => require("./ListConfigurationPage-BynalOp8.js")).then((mod) => ({
1245
1347
  default: mod.ProtectedListConfiguration
1246
1348
  }))
1247
1349
  );
1248
1350
  const ProtectedEditConfigurationPage = React.lazy(
1249
- () => Promise.resolve().then(() => require("./EditConfigurationPage-Dmv83RlS.js")).then((mod) => ({
1351
+ () => Promise.resolve().then(() => require("./EditConfigurationPage-_aG2DJSU.js")).then((mod) => ({
1250
1352
  default: mod.ProtectedEditConfigurationPage
1251
1353
  }))
1252
1354
  );
1253
1355
  const ProtectedComponentConfigurationPage = React.lazy(
1254
- () => Promise.resolve().then(() => require("./ComponentConfigurationPage-DjWJdz6Y.js")).then((mod) => ({
1356
+ () => Promise.resolve().then(() => require("./ComponentConfigurationPage-_zF8p6CY.js")).then((mod) => ({
1255
1357
  default: mod.ProtectedComponentConfigurationPage
1256
1358
  }))
1257
1359
  );
1258
1360
  const NoPermissions = React.lazy(
1259
- () => Promise.resolve().then(() => require("./NoPermissionsPage-Dwu8rRJu.js")).then((mod) => ({ default: mod.NoPermissions }))
1361
+ () => Promise.resolve().then(() => require("./NoPermissionsPage-DCVUh5at.js")).then((mod) => ({ default: mod.NoPermissions }))
1260
1362
  );
1261
1363
  const NoContentType = React.lazy(
1262
- () => Promise.resolve().then(() => require("./NoContentTypePage-DOC_yWOf.js")).then((mod) => ({ default: mod.NoContentType }))
1364
+ () => Promise.resolve().then(() => require("./NoContentTypePage-BaWQ7HsA.js")).then((mod) => ({ default: mod.NoContentType }))
1263
1365
  );
1264
1366
  const CollectionTypePages = () => {
1265
1367
  const { collectionType } = reactRouterDom.useParams();
@@ -1373,12 +1475,14 @@ const DocumentActionButton = (action) => {
1373
1475
  /* @__PURE__ */ jsxRuntime.jsx(
1374
1476
  designSystem.Button,
1375
1477
  {
1376
- flex: 1,
1478
+ flex: "auto",
1377
1479
  startIcon: action.icon,
1378
1480
  disabled: action.disabled,
1379
1481
  onClick: handleClick(action),
1380
1482
  justifyContent: "center",
1381
1483
  variant: action.variant || "default",
1484
+ paddingTop: "7px",
1485
+ paddingBottom: "7px",
1382
1486
  children: action.label
1383
1487
  }
1384
1488
  ),
@@ -1386,7 +1490,7 @@ const DocumentActionButton = (action) => {
1386
1490
  DocumentActionConfirmDialog,
1387
1491
  {
1388
1492
  ...action.dialog,
1389
- variant: action.variant,
1493
+ variant: action.dialog?.variant ?? action.variant,
1390
1494
  isOpen: dialogId === action.id,
1391
1495
  onClose: handleClose
1392
1496
  }
@@ -1443,13 +1547,13 @@ const DocumentActionsMenu = ({
1443
1547
  disabled: isDisabled,
1444
1548
  size: "S",
1445
1549
  endIcon: null,
1446
- paddingTop: "7px",
1447
- paddingLeft: "9px",
1448
- paddingRight: "9px",
1550
+ paddingTop: "4px",
1551
+ paddingLeft: "7px",
1552
+ paddingRight: "7px",
1449
1553
  variant,
1450
1554
  children: [
1451
1555
  /* @__PURE__ */ jsxRuntime.jsx(Icons.More, { "aria-hidden": true, focusable: false }),
1452
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.VisuallyHidden, { as: "span", children: label || formatMessage({
1556
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.VisuallyHidden, { tag: "span", children: label || formatMessage({
1453
1557
  id: "content-manager.containers.edit.panels.default.more-actions",
1454
1558
  defaultMessage: "More document actions"
1455
1559
  }) })
@@ -1465,10 +1569,25 @@ const DocumentActionsMenu = ({
1465
1569
  onSelect: handleClick(action),
1466
1570
  display: "block",
1467
1571
  children: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { justifyContent: "space-between", gap: 4, children: [
1468
- /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { color: convertActionVariantToColor(action.variant), gap: 2, as: "span", children: [
1469
- action.icon,
1470
- action.label
1471
- ] }),
1572
+ /* @__PURE__ */ jsxRuntime.jsxs(
1573
+ designSystem.Flex,
1574
+ {
1575
+ color: !action.disabled ? convertActionVariantToColor(action.variant) : "inherit",
1576
+ gap: 2,
1577
+ tag: "span",
1578
+ children: [
1579
+ /* @__PURE__ */ jsxRuntime.jsx(
1580
+ designSystem.Flex,
1581
+ {
1582
+ tag: "span",
1583
+ color: !action.disabled ? convertActionVariantToIconColor(action.variant) : "inherit",
1584
+ children: action.icon
1585
+ }
1586
+ ),
1587
+ action.label
1588
+ ]
1589
+ }
1590
+ ),
1472
1591
  action.id.startsWith("HistoryAction") && /* @__PURE__ */ jsxRuntime.jsx(
1473
1592
  designSystem.Flex,
1474
1593
  {
@@ -1527,6 +1646,18 @@ const convertActionVariantToColor = (variant = "secondary") => {
1527
1646
  return "primary600";
1528
1647
  }
1529
1648
  };
1649
+ const convertActionVariantToIconColor = (variant = "secondary") => {
1650
+ switch (variant) {
1651
+ case "danger":
1652
+ return "danger600";
1653
+ case "secondary":
1654
+ return "neutral500";
1655
+ case "success":
1656
+ return "success600";
1657
+ default:
1658
+ return "primary600";
1659
+ }
1660
+ };
1530
1661
  const DocumentActionConfirmDialog = ({
1531
1662
  onClose,
1532
1663
  onCancel,
@@ -1549,61 +1680,42 @@ const DocumentActionConfirmDialog = ({
1549
1680
  }
1550
1681
  onClose();
1551
1682
  };
1552
- return /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Dialog, { isOpen, title, onClose: handleClose, children: [
1553
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.DialogBody, { children: content }),
1554
- /* @__PURE__ */ jsxRuntime.jsx(
1555
- designSystem.DialogFooter,
1556
- {
1557
- startAction: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Button, { onClick: handleClose, variant: "tertiary", children: formatMessage({
1558
- id: "app.components.Button.cancel",
1559
- defaultMessage: "Cancel"
1560
- }) }),
1561
- endAction: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Button, { onClick: handleConfirm, variant, children: formatMessage({
1562
- id: "app.components.Button.confirm",
1563
- defaultMessage: "Confirm"
1564
- }) })
1565
- }
1566
- )
1567
- ] });
1683
+ return /* @__PURE__ */ jsxRuntime.jsx(designSystem.Dialog.Root, { open: isOpen, onOpenChange: handleClose, children: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Dialog.Content, { children: [
1684
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Dialog.Header, { children: title }),
1685
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Dialog.Body, { children: content }),
1686
+ /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Dialog.Footer, { children: [
1687
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Dialog.Cancel, { children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Button, { variant: "tertiary", fullWidth: true, children: formatMessage({
1688
+ id: "app.components.Button.cancel",
1689
+ defaultMessage: "Cancel"
1690
+ }) }) }),
1691
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Button, { onClick: handleConfirm, variant, fullWidth: true, children: formatMessage({
1692
+ id: "app.components.Button.confirm",
1693
+ defaultMessage: "Confirm"
1694
+ }) })
1695
+ ] })
1696
+ ] }) });
1568
1697
  };
1569
1698
  const DocumentActionModal = ({
1570
1699
  isOpen,
1571
1700
  title,
1572
1701
  onClose,
1573
1702
  footer: Footer,
1574
- content,
1703
+ content: Content,
1575
1704
  onModalClose
1576
1705
  }) => {
1577
- const id = React__namespace.useId();
1578
- if (!isOpen) {
1579
- return null;
1580
- }
1581
1706
  const handleClose = () => {
1582
1707
  if (onClose) {
1583
1708
  onClose();
1584
1709
  }
1585
1710
  onModalClose();
1586
1711
  };
1587
- return /* @__PURE__ */ jsxRuntime.jsxs(designSystem.ModalLayout, { borderRadius: "4px", overflow: "hidden", onClose: handleClose, labelledBy: id, children: [
1588
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.ModalHeader, { children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { fontWeight: "bold", textColor: "neutral800", as: "h2", id, children: title }) }),
1589
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.ModalBody, { children: content }),
1590
- /* @__PURE__ */ jsxRuntime.jsx(
1591
- designSystem.Box,
1592
- {
1593
- paddingTop: 4,
1594
- paddingBottom: 4,
1595
- paddingLeft: 5,
1596
- paddingRight: 5,
1597
- borderWidth: "1px 0 0 0",
1598
- borderStyle: "solid",
1599
- borderColor: "neutral150",
1600
- background: "neutral100",
1601
- children: typeof Footer === "function" ? /* @__PURE__ */ jsxRuntime.jsx(Footer, { onClose: handleClose }) : Footer
1602
- }
1603
- )
1604
- ] });
1712
+ return /* @__PURE__ */ jsxRuntime.jsx(designSystem.Modal.Root, { open: isOpen, onOpenChange: handleClose, children: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Modal.Content, { children: [
1713
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Modal.Header, { children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Modal.Title, { children: title }) }),
1714
+ typeof Content === "function" ? /* @__PURE__ */ jsxRuntime.jsx(Content, { onClose: handleClose }) : /* @__PURE__ */ jsxRuntime.jsx(designSystem.Modal.Body, { children: Content }),
1715
+ typeof Footer === "function" ? /* @__PURE__ */ jsxRuntime.jsx(Footer, { onClose: handleClose }) : Footer
1716
+ ] }) });
1605
1717
  };
1606
- const PublishAction = ({
1718
+ const PublishAction$1 = ({
1607
1719
  activeTab,
1608
1720
  documentId,
1609
1721
  model,
@@ -1615,13 +1727,17 @@ const PublishAction = ({
1615
1727
  const navigate = reactRouterDom.useNavigate();
1616
1728
  const { toggleNotification } = strapiAdmin.useNotification();
1617
1729
  const { _unstableFormatValidationErrors: formatValidationErrors } = strapiAdmin.useAPIErrorHandler();
1730
+ const isListView = reactRouterDom.useMatch(LIST_PATH) !== null;
1618
1731
  const isCloning = reactRouterDom.useMatch(CLONE_PATH) !== null;
1619
1732
  const { formatMessage } = reactIntl.useIntl();
1620
- const { canPublish, canCreate, canUpdate } = useDocumentRBAC(
1621
- "PublishAction",
1622
- ({ canPublish: canPublish2, canCreate: canCreate2, canUpdate: canUpdate2 }) => ({ canPublish: canPublish2, canCreate: canCreate2, canUpdate: canUpdate2 })
1623
- );
1733
+ const canPublish = useDocumentRBAC("PublishAction", ({ canPublish: canPublish2 }) => canPublish2);
1624
1734
  const { publish } = useDocumentActions();
1735
+ const [
1736
+ countDraftRelations,
1737
+ { isLoading: isLoadingDraftRelations, isError: isErrorDraftRelations }
1738
+ ] = useLazyGetDraftRelationCountQuery();
1739
+ const [localCountOfDraftRelations, setLocalCountOfDraftRelations] = React__namespace.useState(0);
1740
+ const [serverCountOfDraftRelations, setServerCountOfDraftRelations] = React__namespace.useState(0);
1625
1741
  const [{ query, rawQuery }] = strapiAdmin.useQueryParams();
1626
1742
  const params = React__namespace.useMemo(() => buildValidParams(query), [query]);
1627
1743
  const modified = strapiAdmin.useForm("PublishAction", ({ modified: modified2 }) => modified2);
@@ -1630,10 +1746,103 @@ const PublishAction = ({
1630
1746
  const validate = strapiAdmin.useForm("PublishAction", (state) => state.validate);
1631
1747
  const setErrors = strapiAdmin.useForm("PublishAction", (state) => state.setErrors);
1632
1748
  const formValues = strapiAdmin.useForm("PublishAction", ({ values }) => values);
1749
+ React__namespace.useEffect(() => {
1750
+ if (isErrorDraftRelations) {
1751
+ toggleNotification({
1752
+ type: "danger",
1753
+ message: formatMessage({
1754
+ id: getTranslation("error.records.fetch-draft-relatons"),
1755
+ defaultMessage: "An error occurred while fetching draft relations on this document."
1756
+ })
1757
+ });
1758
+ }
1759
+ }, [isErrorDraftRelations, toggleNotification, formatMessage]);
1760
+ React__namespace.useEffect(() => {
1761
+ const localDraftRelations = /* @__PURE__ */ new Set();
1762
+ const extractDraftRelations = (data) => {
1763
+ const relations = data.connect || [];
1764
+ relations.forEach((relation) => {
1765
+ if (relation.status === "draft") {
1766
+ localDraftRelations.add(relation.id);
1767
+ }
1768
+ });
1769
+ };
1770
+ const traverseAndExtract = (data) => {
1771
+ Object.entries(data).forEach(([key, value]) => {
1772
+ if (key === "connect" && Array.isArray(value)) {
1773
+ extractDraftRelations({ connect: value });
1774
+ } else if (typeof value === "object" && value !== null) {
1775
+ traverseAndExtract(value);
1776
+ }
1777
+ });
1778
+ };
1779
+ if (!documentId || modified) {
1780
+ traverseAndExtract(formValues);
1781
+ setLocalCountOfDraftRelations(localDraftRelations.size);
1782
+ }
1783
+ }, [documentId, modified, formValues, setLocalCountOfDraftRelations]);
1784
+ React__namespace.useEffect(() => {
1785
+ if (!document || !document.documentId || isListView) {
1786
+ return;
1787
+ }
1788
+ const fetchDraftRelationsCount = async () => {
1789
+ const { data, error } = await countDraftRelations({
1790
+ collectionType,
1791
+ model,
1792
+ documentId,
1793
+ params
1794
+ });
1795
+ if (error) {
1796
+ throw error;
1797
+ }
1798
+ if (data) {
1799
+ setServerCountOfDraftRelations(data.data);
1800
+ }
1801
+ };
1802
+ fetchDraftRelationsCount();
1803
+ }, [isListView, document, documentId, countDraftRelations, collectionType, model, params]);
1633
1804
  const isDocumentPublished = (document?.[PUBLISHED_AT_ATTRIBUTE_NAME] || meta?.availableStatus.some((doc) => doc[PUBLISHED_AT_ATTRIBUTE_NAME] !== null)) && document?.status !== "modified";
1634
1805
  if (!schema?.options?.draftAndPublish) {
1635
1806
  return null;
1636
1807
  }
1808
+ const performPublish = async () => {
1809
+ setSubmitting(true);
1810
+ try {
1811
+ const { errors } = await validate();
1812
+ if (errors) {
1813
+ toggleNotification({
1814
+ type: "danger",
1815
+ message: formatMessage({
1816
+ id: "content-manager.validation.error",
1817
+ defaultMessage: "There are validation errors in your document. Please fix them before saving."
1818
+ })
1819
+ });
1820
+ return;
1821
+ }
1822
+ const res = await publish(
1823
+ {
1824
+ collectionType,
1825
+ model,
1826
+ documentId,
1827
+ params
1828
+ },
1829
+ formValues
1830
+ );
1831
+ if ("data" in res && collectionType !== SINGLE_TYPES) {
1832
+ navigate({
1833
+ pathname: `../${collectionType}/${model}/${res.data.documentId}`,
1834
+ search: rawQuery
1835
+ });
1836
+ } else if ("error" in res && isBaseQueryError(res.error) && res.error.name === "ValidationError") {
1837
+ setErrors(formatValidationErrors(res.error));
1838
+ }
1839
+ } finally {
1840
+ setSubmitting(false);
1841
+ }
1842
+ };
1843
+ const totalDraftRelations = localCountOfDraftRelations + serverCountOfDraftRelations;
1844
+ const enableDraftRelationsCount = false;
1845
+ const hasDraftRelations = enableDraftRelationsCount;
1637
1846
  return {
1638
1847
  /**
1639
1848
  * Disabled when:
@@ -1643,52 +1852,39 @@ const PublishAction = ({
1643
1852
  * - the document is already published & not modified
1644
1853
  * - the document is being created & not modified
1645
1854
  * - the user doesn't have the permission to publish
1646
- * - the user doesn't have the permission to create a new document
1647
- * - the user doesn't have the permission to update the document
1648
1855
  */
1649
- disabled: isCloning || isSubmitting || activeTab === "published" || !modified && isDocumentPublished || !modified && !document?.documentId || !canPublish || Boolean(!document?.documentId && !canCreate || document?.documentId && !canUpdate),
1856
+ disabled: isCloning || isSubmitting || isLoadingDraftRelations || activeTab === "published" || !modified && isDocumentPublished || !modified && !document?.documentId || !canPublish,
1650
1857
  label: formatMessage({
1651
1858
  id: "app.utils.publish",
1652
1859
  defaultMessage: "Publish"
1653
1860
  }),
1654
1861
  onClick: async () => {
1655
- setSubmitting(true);
1656
- try {
1657
- const { errors } = await validate();
1658
- if (errors) {
1659
- toggleNotification({
1660
- type: "danger",
1661
- message: formatMessage({
1662
- id: "content-manager.validation.error",
1663
- defaultMessage: "There are validation errors in your document. Please fix them before saving."
1664
- })
1665
- });
1666
- return;
1667
- }
1668
- const res = await publish(
1669
- {
1670
- collectionType,
1671
- model,
1672
- documentId,
1673
- params
1674
- },
1675
- formValues
1676
- );
1677
- if ("data" in res && collectionType !== SINGLE_TYPES) {
1678
- navigate({
1679
- pathname: `../${collectionType}/${model}/${res.data.documentId}`,
1680
- search: rawQuery
1681
- });
1682
- } else if ("error" in res && isBaseQueryError(res.error) && res.error.name === "ValidationError") {
1683
- setErrors(formatValidationErrors(res.error));
1862
+ await performPublish();
1863
+ },
1864
+ dialog: hasDraftRelations ? {
1865
+ type: "dialog",
1866
+ variant: "danger",
1867
+ footer: null,
1868
+ title: formatMessage({
1869
+ id: getTranslation(`popUpwarning.warning.bulk-has-draft-relations.title`),
1870
+ defaultMessage: "Confirmation"
1871
+ }),
1872
+ content: formatMessage(
1873
+ {
1874
+ id: getTranslation(`popUpwarning.warning.bulk-has-draft-relations.message`),
1875
+ defaultMessage: "This entry is related to {count, plural, one {# draft entry} other {# draft entries}}. Publishing it could leave broken links in your app."
1876
+ },
1877
+ {
1878
+ count: totalDraftRelations
1684
1879
  }
1685
- } finally {
1686
- setSubmitting(false);
1880
+ ),
1881
+ onConfirm: async () => {
1882
+ await performPublish();
1687
1883
  }
1688
- }
1884
+ } : void 0
1689
1885
  };
1690
1886
  };
1691
- PublishAction.type = "publish";
1887
+ PublishAction$1.type = "publish";
1692
1888
  const UpdateAction = ({
1693
1889
  activeTab,
1694
1890
  documentId,
@@ -1701,10 +1897,6 @@ const UpdateAction = ({
1701
1897
  const cloneMatch = reactRouterDom.useMatch(CLONE_PATH);
1702
1898
  const isCloning = cloneMatch !== null;
1703
1899
  const { formatMessage } = reactIntl.useIntl();
1704
- const { canCreate, canUpdate } = useDocumentRBAC("UpdateAction", ({ canCreate: canCreate2, canUpdate: canUpdate2 }) => ({
1705
- canCreate: canCreate2,
1706
- canUpdate: canUpdate2
1707
- }));
1708
1900
  const { create, update, clone } = useDocumentActions();
1709
1901
  const [{ query, rawQuery }] = strapiAdmin.useQueryParams();
1710
1902
  const params = React__namespace.useMemo(() => buildValidParams(query), [query]);
@@ -1721,10 +1913,8 @@ const UpdateAction = ({
1721
1913
  * - the form is submitting
1722
1914
  * - the document is not modified & we're not cloning (you can save a clone entity straight away)
1723
1915
  * - the active tab is the published tab
1724
- * - the user doesn't have the permission to create a new document
1725
- * - the user doesn't have the permission to update the document
1726
1916
  */
1727
- disabled: isSubmitting || !modified && !isCloning || activeTab === "published" || Boolean(!documentId && !canCreate || documentId && !canUpdate),
1917
+ disabled: isSubmitting || !modified && !isCloning || activeTab === "published",
1728
1918
  label: formatMessage({
1729
1919
  id: "content-manager.containers.Edit.save",
1730
1920
  defaultMessage: "Save"
@@ -1732,16 +1922,18 @@ const UpdateAction = ({
1732
1922
  onClick: async () => {
1733
1923
  setSubmitting(true);
1734
1924
  try {
1735
- const { errors } = await validate();
1736
- if (errors) {
1737
- toggleNotification({
1738
- type: "danger",
1739
- message: formatMessage({
1740
- id: "content-manager.validation.error",
1741
- defaultMessage: "There are validation errors in your document. Please fix them before saving."
1742
- })
1743
- });
1744
- return;
1925
+ if (activeTab !== "draft") {
1926
+ const { errors } = await validate();
1927
+ if (errors) {
1928
+ toggleNotification({
1929
+ type: "danger",
1930
+ message: formatMessage({
1931
+ id: "content-manager.validation.error",
1932
+ defaultMessage: "There are validation errors in your document. Please fix them before saving."
1933
+ })
1934
+ });
1935
+ return;
1936
+ }
1745
1937
  }
1746
1938
  if (isCloning) {
1747
1939
  const res = await clone(
@@ -1753,10 +1945,13 @@ const UpdateAction = ({
1753
1945
  document
1754
1946
  );
1755
1947
  if ("data" in res) {
1756
- navigate({
1757
- pathname: `../${collectionType}/${model}/${res.data.documentId}`,
1758
- search: rawQuery
1759
- });
1948
+ navigate(
1949
+ {
1950
+ pathname: `../${res.data.documentId}`,
1951
+ search: rawQuery
1952
+ },
1953
+ { relative: "path" }
1954
+ );
1760
1955
  } else if ("error" in res && isBaseQueryError(res.error) && res.error.name === "ValidationError") {
1761
1956
  setErrors(formatValidationErrors(res.error));
1762
1957
  }
@@ -1784,10 +1979,13 @@ const UpdateAction = ({
1784
1979
  document
1785
1980
  );
1786
1981
  if ("data" in res && collectionType !== SINGLE_TYPES) {
1787
- navigate({
1788
- pathname: `../${collectionType}/${model}/${res.data.documentId}`,
1789
- search: rawQuery
1790
- });
1982
+ navigate(
1983
+ {
1984
+ pathname: `../${res.data.documentId}`,
1985
+ search: rawQuery
1986
+ },
1987
+ { replace: true, relative: "path" }
1988
+ );
1791
1989
  } else if ("error" in res && isBaseQueryError(res.error) && res.error.name === "ValidationError") {
1792
1990
  setErrors(formatValidationErrors(res.error));
1793
1991
  }
@@ -1803,7 +2001,7 @@ const UNPUBLISH_DRAFT_OPTIONS = {
1803
2001
  KEEP: "keep",
1804
2002
  DISCARD: "discard"
1805
2003
  };
1806
- const UnpublishAction = ({
2004
+ const UnpublishAction$1 = ({
1807
2005
  activeTab,
1808
2006
  documentId,
1809
2007
  model,
@@ -1819,10 +2017,8 @@ const UnpublishAction = ({
1819
2017
  const { toggleNotification } = strapiAdmin.useNotification();
1820
2018
  const [shouldKeepDraft, setShouldKeepDraft] = React__namespace.useState(true);
1821
2019
  const isDocumentModified = document?.status === "modified";
1822
- const handleChange = (e) => {
1823
- if ("value" in e.target) {
1824
- setShouldKeepDraft(e.target.value === UNPUBLISH_DRAFT_OPTIONS.KEEP);
1825
- }
2020
+ const handleChange = (value) => {
2021
+ setShouldKeepDraft(value === UNPUBLISH_DRAFT_OPTIONS.KEEP);
1826
2022
  };
1827
2023
  if (!schema?.options?.draftAndPublish) {
1828
2024
  return null;
@@ -1833,7 +2029,7 @@ const UnpublishAction = ({
1833
2029
  id: "app.utils.unpublish",
1834
2030
  defaultMessage: "Unpublish"
1835
2031
  }),
1836
- icon: /* @__PURE__ */ jsxRuntime.jsx(StyledCrossCircle, {}),
2032
+ icon: /* @__PURE__ */ jsxRuntime.jsx(Icons.Cross, {}),
1837
2033
  onClick: async () => {
1838
2034
  if (!documentId && collectionType !== SINGLE_TYPES || isDocumentModified) {
1839
2035
  if (!documentId) {
@@ -1866,45 +2062,30 @@ const UnpublishAction = ({
1866
2062
  content: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { alignItems: "flex-start", direction: "column", gap: 6, children: [
1867
2063
  /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { width: "100%", direction: "column", gap: 2, children: [
1868
2064
  /* @__PURE__ */ jsxRuntime.jsx(Icons.WarningCircle, { width: "24px", height: "24px", fill: "danger600" }),
1869
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { as: "p", variant: "omega", textAlign: "center", children: formatMessage({
2065
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { tag: "p", variant: "omega", textAlign: "center", children: formatMessage({
1870
2066
  id: "content-manager.actions.unpublish.dialog.body",
1871
2067
  defaultMessage: "Are you sure?"
1872
2068
  }) })
1873
2069
  ] }),
1874
2070
  /* @__PURE__ */ jsxRuntime.jsxs(
1875
- designSystem.Flex,
2071
+ designSystem.Radio.Group,
1876
2072
  {
1877
- onChange: handleChange,
1878
- direction: "column",
1879
- alignItems: "flex-start",
1880
- as: "fieldset",
1881
- gap: 3,
2073
+ defaultValue: UNPUBLISH_DRAFT_OPTIONS.KEEP,
2074
+ name: "discard-options",
2075
+ "aria-label": formatMessage({
2076
+ id: "content-manager.actions.unpublish.dialog.radio-label",
2077
+ defaultMessage: "Choose an option to unpublish the document."
2078
+ }),
2079
+ onValueChange: handleChange,
1882
2080
  children: [
1883
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.VisuallyHidden, { as: "legend" }),
1884
- /* @__PURE__ */ jsxRuntime.jsx(
1885
- designSystem.Radio,
1886
- {
1887
- checked: shouldKeepDraft,
1888
- value: UNPUBLISH_DRAFT_OPTIONS.KEEP,
1889
- name: "discard-options",
1890
- children: formatMessage({
1891
- id: "content-manager.actions.unpublish.dialog.option.keep-draft",
1892
- defaultMessage: "Keep draft"
1893
- })
1894
- }
1895
- ),
1896
- /* @__PURE__ */ jsxRuntime.jsx(
1897
- designSystem.Radio,
1898
- {
1899
- checked: !shouldKeepDraft,
1900
- value: UNPUBLISH_DRAFT_OPTIONS.DISCARD,
1901
- name: "discard-options",
1902
- children: formatMessage({
1903
- id: "content-manager.actions.unpublish.dialog.option.replace-draft",
1904
- defaultMessage: "Replace draft"
1905
- })
1906
- }
1907
- )
2081
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Radio.Item, { checked: shouldKeepDraft, value: UNPUBLISH_DRAFT_OPTIONS.KEEP, children: formatMessage({
2082
+ id: "content-manager.actions.unpublish.dialog.option.keep-draft",
2083
+ defaultMessage: "Keep draft"
2084
+ }) }),
2085
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Radio.Item, { checked: !shouldKeepDraft, value: UNPUBLISH_DRAFT_OPTIONS.DISCARD, children: formatMessage({
2086
+ id: "content-manager.actions.unpublish.dialog.option.replace-draft",
2087
+ defaultMessage: "Replace draft"
2088
+ }) })
1908
2089
  ]
1909
2090
  }
1910
2091
  )
@@ -1937,7 +2118,7 @@ const UnpublishAction = ({
1937
2118
  position: ["panel", "table-row"]
1938
2119
  };
1939
2120
  };
1940
- UnpublishAction.type = "unpublish";
2121
+ UnpublishAction$1.type = "unpublish";
1941
2122
  const DiscardAction = ({
1942
2123
  activeTab,
1943
2124
  documentId,
@@ -1960,7 +2141,7 @@ const DiscardAction = ({
1960
2141
  id: "content-manager.actions.discard.label",
1961
2142
  defaultMessage: "Discard changes"
1962
2143
  }),
1963
- icon: /* @__PURE__ */ jsxRuntime.jsx(StyledCrossCircle, {}),
2144
+ icon: /* @__PURE__ */ jsxRuntime.jsx(Icons.Cross, {}),
1964
2145
  position: ["panel", "table-row"],
1965
2146
  variant: "danger",
1966
2147
  dialog: {
@@ -1971,7 +2152,7 @@ const DiscardAction = ({
1971
2152
  }),
1972
2153
  content: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { direction: "column", gap: 2, children: [
1973
2154
  /* @__PURE__ */ jsxRuntime.jsx(Icons.WarningCircle, { width: "24px", height: "24px", fill: "danger600" }),
1974
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { as: "p", variant: "omega", textAlign: "center", children: formatMessage({
2155
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { tag: "p", variant: "omega", textAlign: "center", children: formatMessage({
1975
2156
  id: "content-manager.actions.discard.dialog.body",
1976
2157
  defaultMessage: "Are you sure?"
1977
2158
  }) })
@@ -1988,12 +2169,7 @@ const DiscardAction = ({
1988
2169
  };
1989
2170
  };
1990
2171
  DiscardAction.type = "discard";
1991
- const StyledCrossCircle = styled__default.default(Icons.CrossCircle)`
1992
- path {
1993
- fill: currentColor;
1994
- }
1995
- `;
1996
- const DEFAULT_ACTIONS = [PublishAction, UpdateAction, UnpublishAction, DiscardAction];
2172
+ const DEFAULT_ACTIONS = [PublishAction$1, UpdateAction, UnpublishAction$1, DiscardAction];
1997
2173
  const intervals = ["years", "months", "days", "hours", "minutes", "seconds"];
1998
2174
  const RelativeTime = React__namespace.forwardRef(
1999
2175
  ({ timestamp, customIntervals = [], ...restProps }, forwardedRef) => {
@@ -2040,8 +2216,8 @@ const getDisplayName = ({
2040
2216
  };
2041
2217
  const capitalise = (str) => str.charAt(0).toUpperCase() + str.slice(1);
2042
2218
  const DocumentStatus = ({ status = "draft", ...restProps }) => {
2043
- const statusVariant = status === "draft" ? "primary" : status === "published" ? "success" : "alternative";
2044
- return /* @__PURE__ */ jsxRuntime.jsx(designSystem.Status, { ...restProps, showBullet: false, size: "S", variant: statusVariant, children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { as: "span", variant: "omega", fontWeight: "bold", children: capitalise(status) }) });
2219
+ const statusVariant = status === "draft" ? "secondary" : status === "published" ? "success" : "alternative";
2220
+ return /* @__PURE__ */ jsxRuntime.jsx(designSystem.Status, { ...restProps, showBullet: false, size: "S", variant: statusVariant, children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { tag: "span", variant: "omega", fontWeight: "bold", children: capitalise(status) }) });
2045
2221
  };
2046
2222
  const Header = ({ isCreating, status, title: documentTitle = "Untitled" }) => {
2047
2223
  const { formatMessage } = reactIntl.useIntl();
@@ -2050,23 +2226,13 @@ const Header = ({ isCreating, status, title: documentTitle = "Untitled" }) => {
2050
2226
  id: "content-manager.containers.edit.title.new",
2051
2227
  defaultMessage: "Create an entry"
2052
2228
  }) : documentTitle;
2053
- return /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { direction: "column", alignItems: "flex-start", paddingTop: 8, paddingBottom: 4, gap: 3, children: [
2229
+ return /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { direction: "column", alignItems: "flex-start", paddingTop: 6, paddingBottom: 4, gap: 2, children: [
2054
2230
  /* @__PURE__ */ jsxRuntime.jsx(strapiAdmin.BackButton, {}),
2055
- /* @__PURE__ */ jsxRuntime.jsxs(
2056
- designSystem.Flex,
2057
- {
2058
- width: "100%",
2059
- justifyContent: "space-between",
2060
- paddingTop: 1,
2061
- gap: "80px",
2062
- alignItems: "flex-start",
2063
- children: [
2064
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "alpha", as: "h1", children: title }),
2065
- /* @__PURE__ */ jsxRuntime.jsx(HeaderToolbar, {})
2066
- ]
2067
- }
2068
- ),
2069
- status ? /* @__PURE__ */ jsxRuntime.jsx(DocumentStatus, { status: isCloning ? "draft" : status }) : null
2231
+ /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { width: "100%", justifyContent: "space-between", gap: "80px", alignItems: "flex-start", children: [
2232
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "alpha", tag: "h1", children: title }),
2233
+ /* @__PURE__ */ jsxRuntime.jsx(HeaderToolbar, {})
2234
+ ] }),
2235
+ status ? /* @__PURE__ */ jsxRuntime.jsx(designSystem.Box, { marginTop: 1, children: /* @__PURE__ */ jsxRuntime.jsx(DocumentStatus, { status: isCloning ? "draft" : status }) }) : null
2070
2236
  ] });
2071
2237
  };
2072
2238
  const HeaderToolbar = () => {
@@ -2218,7 +2384,7 @@ const Information = ({ activeTab }) => {
2218
2384
  borderColor: "neutral150",
2219
2385
  direction: "column",
2220
2386
  marginTop: 2,
2221
- as: "dl",
2387
+ tag: "dl",
2222
2388
  padding: 5,
2223
2389
  gap: 3,
2224
2390
  alignItems: "flex-start",
@@ -2226,15 +2392,29 @@ const Information = ({ activeTab }) => {
2226
2392
  marginRight: "-0.4rem",
2227
2393
  width: "calc(100% + 8px)",
2228
2394
  children: information.map((info) => /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { gap: 1, direction: "column", alignItems: "flex-start", children: [
2229
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { as: "dt", variant: "pi", fontWeight: "bold", children: info.label }),
2230
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { as: "dd", variant: "pi", textColor: "neutral600", children: info.value })
2395
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { tag: "dt", variant: "pi", fontWeight: "bold", children: info.label }),
2396
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { tag: "dd", variant: "pi", textColor: "neutral600", children: info.value })
2231
2397
  ] }, info.label))
2232
2398
  }
2233
2399
  );
2234
2400
  };
2235
2401
  const HeaderActions = ({ actions: actions2 }) => {
2236
- return /* @__PURE__ */ jsxRuntime.jsx(designSystem.Flex, { children: actions2.map((action) => {
2237
- if ("options" in action) {
2402
+ const [dialogId, setDialogId] = React__namespace.useState(null);
2403
+ const handleClick = (action) => async (e) => {
2404
+ if (!("options" in action)) {
2405
+ const { onClick = () => false, dialog, id } = action;
2406
+ const muteDialog = await onClick(e);
2407
+ if (dialog && !muteDialog) {
2408
+ e.preventDefault();
2409
+ setDialogId(id);
2410
+ }
2411
+ }
2412
+ };
2413
+ const handleClose = () => {
2414
+ setDialogId(null);
2415
+ };
2416
+ return /* @__PURE__ */ jsxRuntime.jsx(designSystem.Flex, { gap: 1, children: actions2.map((action) => {
2417
+ if (action.options) {
2238
2418
  return /* @__PURE__ */ jsxRuntime.jsx(
2239
2419
  designSystem.SingleSelect,
2240
2420
  {
@@ -2248,10 +2428,49 @@ const HeaderActions = ({ actions: actions2 }) => {
2248
2428
  action.id
2249
2429
  );
2250
2430
  } else {
2251
- return null;
2431
+ if (action.type === "icon") {
2432
+ return /* @__PURE__ */ jsxRuntime.jsxs(React__namespace.Fragment, { children: [
2433
+ /* @__PURE__ */ jsxRuntime.jsx(
2434
+ designSystem.IconButton,
2435
+ {
2436
+ disabled: action.disabled,
2437
+ label: action.label,
2438
+ size: "S",
2439
+ onClick: handleClick(action),
2440
+ children: action.icon
2441
+ }
2442
+ ),
2443
+ action.dialog ? /* @__PURE__ */ jsxRuntime.jsx(
2444
+ HeaderActionDialog,
2445
+ {
2446
+ ...action.dialog,
2447
+ isOpen: dialogId === action.id,
2448
+ onClose: handleClose
2449
+ }
2450
+ ) : null
2451
+ ] }, action.id);
2452
+ }
2252
2453
  }
2253
2454
  }) });
2254
2455
  };
2456
+ const HeaderActionDialog = ({
2457
+ onClose,
2458
+ onCancel,
2459
+ title,
2460
+ content: Content,
2461
+ isOpen
2462
+ }) => {
2463
+ const handleClose = async () => {
2464
+ if (onCancel) {
2465
+ await onCancel();
2466
+ }
2467
+ onClose();
2468
+ };
2469
+ return /* @__PURE__ */ jsxRuntime.jsx(designSystem.Dialog.Root, { open: isOpen, onOpenChange: handleClose, children: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Dialog.Content, { children: [
2470
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Dialog.Header, { children: title }),
2471
+ typeof Content === "function" ? /* @__PURE__ */ jsxRuntime.jsx(Content, { onClose: handleClose }) : Content
2472
+ ] }) });
2473
+ };
2255
2474
  const ConfigureTheViewAction = ({ collectionType, model }) => {
2256
2475
  const navigate = reactRouterDom.useNavigate();
2257
2476
  const { formatMessage } = reactIntl.useIntl();
@@ -2260,7 +2479,7 @@ const ConfigureTheViewAction = ({ collectionType, model }) => {
2260
2479
  id: "app.links.configure-view",
2261
2480
  defaultMessage: "Configure the view"
2262
2481
  }),
2263
- icon: /* @__PURE__ */ jsxRuntime.jsx(StyledCog, {}),
2482
+ icon: /* @__PURE__ */ jsxRuntime.jsx(Icons.ListPlus, {}),
2264
2483
  onClick: () => {
2265
2484
  navigate(`../${collectionType}/${model}/configurations/edit`);
2266
2485
  },
@@ -2268,11 +2487,6 @@ const ConfigureTheViewAction = ({ collectionType, model }) => {
2268
2487
  };
2269
2488
  };
2270
2489
  ConfigureTheViewAction.type = "configure-the-view";
2271
- const StyledCog = styled__default.default(Icons.Cog)`
2272
- path {
2273
- fill: currentColor;
2274
- }
2275
- `;
2276
2490
  const EditTheModelAction = ({ model }) => {
2277
2491
  const navigate = reactRouterDom.useNavigate();
2278
2492
  const { formatMessage } = reactIntl.useIntl();
@@ -2281,7 +2495,7 @@ const EditTheModelAction = ({ model }) => {
2281
2495
  id: "content-manager.link-to-ctb",
2282
2496
  defaultMessage: "Edit the model"
2283
2497
  }),
2284
- icon: /* @__PURE__ */ jsxRuntime.jsx(StyledPencil$1, {}),
2498
+ icon: /* @__PURE__ */ jsxRuntime.jsx(Icons.Pencil, {}),
2285
2499
  onClick: () => {
2286
2500
  navigate(`/plugins/content-type-builder/content-types/${model}`);
2287
2501
  },
@@ -2289,12 +2503,7 @@ const EditTheModelAction = ({ model }) => {
2289
2503
  };
2290
2504
  };
2291
2505
  EditTheModelAction.type = "edit-the-model";
2292
- const StyledPencil$1 = styled__default.default(Icons.Pencil)`
2293
- path {
2294
- fill: currentColor;
2295
- }
2296
- `;
2297
- const DeleteAction = ({ documentId, model, collectionType, document }) => {
2506
+ const DeleteAction$1 = ({ documentId, model, collectionType, document }) => {
2298
2507
  const navigate = reactRouterDom.useNavigate();
2299
2508
  const { formatMessage } = reactIntl.useIntl();
2300
2509
  const listViewPathMatch = reactRouterDom.useMatch(LIST_PATH);
@@ -2308,7 +2517,7 @@ const DeleteAction = ({ documentId, model, collectionType, document }) => {
2308
2517
  id: "content-manager.actions.delete.label",
2309
2518
  defaultMessage: "Delete document"
2310
2519
  }),
2311
- icon: /* @__PURE__ */ jsxRuntime.jsx(StyledTrash, {}),
2520
+ icon: /* @__PURE__ */ jsxRuntime.jsx(Icons.Trash, {}),
2312
2521
  dialog: {
2313
2522
  type: "dialog",
2314
2523
  title: formatMessage({
@@ -2317,7 +2526,7 @@ const DeleteAction = ({ documentId, model, collectionType, document }) => {
2317
2526
  }),
2318
2527
  content: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { direction: "column", gap: 2, children: [
2319
2528
  /* @__PURE__ */ jsxRuntime.jsx(Icons.WarningCircle, { width: "24px", height: "24px", fill: "danger600" }),
2320
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { as: "p", variant: "omega", textAlign: "center", children: formatMessage({
2529
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { tag: "p", variant: "omega", textAlign: "center", children: formatMessage({
2321
2530
  id: "content-manager.actions.delete.dialog.body",
2322
2531
  defaultMessage: "Are you sure?"
2323
2532
  }) })
@@ -2362,13 +2571,8 @@ const DeleteAction = ({ documentId, model, collectionType, document }) => {
2362
2571
  position: ["header", "table-row"]
2363
2572
  };
2364
2573
  };
2365
- DeleteAction.type = "delete";
2366
- const StyledTrash = styled__default.default(Icons.Trash)`
2367
- path {
2368
- fill: currentColor;
2369
- }
2370
- `;
2371
- const DEFAULT_HEADER_ACTIONS = [EditTheModelAction, ConfigureTheViewAction, DeleteAction];
2574
+ DeleteAction$1.type = "delete";
2575
+ const DEFAULT_HEADER_ACTIONS = [EditTheModelAction, ConfigureTheViewAction, DeleteAction$1];
2372
2576
  const Panels = () => {
2373
2577
  const isCloning = reactRouterDom.useMatch(CLONE_PATH) !== null;
2374
2578
  const [
@@ -2402,7 +2606,7 @@ const ActionsPanel = () => {
2402
2606
  return {
2403
2607
  title: formatMessage({
2404
2608
  id: "content-manager.containers.edit.panels.default.title",
2405
- defaultMessage: "Document"
2609
+ defaultMessage: "Entry"
2406
2610
  }),
2407
2611
  content: /* @__PURE__ */ jsxRuntime.jsx(ActionsPanelContent, {})
2408
2612
  };
@@ -2442,7 +2646,7 @@ const Panel = React__namespace.forwardRef(({ children, title }, ref) => {
2442
2646
  designSystem.Flex,
2443
2647
  {
2444
2648
  ref,
2445
- as: "aside",
2649
+ tag: "aside",
2446
2650
  "aria-labelledby": "additional-information",
2447
2651
  background: "neutral0",
2448
2652
  borderColor: "neutral150",
@@ -2457,87 +2661,975 @@ const Panel = React__namespace.forwardRef(({ children, title }, ref) => {
2457
2661
  justifyContent: "stretch",
2458
2662
  alignItems: "flex-start",
2459
2663
  children: [
2460
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { as: "h2", variant: "sigma", textTransform: "uppercase", children: title }),
2664
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { tag: "h2", variant: "sigma", textTransform: "uppercase", children: title }),
2461
2665
  children
2462
2666
  ]
2463
2667
  }
2464
2668
  );
2465
2669
  });
2466
- const DEFAULT_BULK_ACTIONS = [];
2467
- const AutoCloneFailureModalBody = ({ prohibitedFields }) => {
2468
- const { formatMessage } = reactIntl.useIntl();
2469
- const getDefaultErrorMessage = (reason) => {
2470
- switch (reason) {
2471
- case "relation":
2472
- return "Duplicating the relation could remove it from the original entry.";
2473
- case "unique":
2474
- return "Identical values in a unique field are not allowed";
2475
- default:
2476
- return reason;
2477
- }
2478
- };
2479
- return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
2480
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "beta", children: formatMessage({
2481
- id: getTranslation("containers.list.autoCloneModal.title"),
2482
- defaultMessage: "This entry can't be duplicated directly."
2483
- }) }),
2484
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Box, { marginTop: 2, children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { textColor: "neutral600", children: formatMessage({
2485
- id: getTranslation("containers.list.autoCloneModal.description"),
2486
- defaultMessage: "A new entry will be created with the same content, but you'll have to change the following fields to save it."
2487
- }) }) }),
2488
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Flex, { marginTop: 6, gap: 2, direction: "column", alignItems: "stretch", children: prohibitedFields.map(([fieldPath, reason]) => /* @__PURE__ */ jsxRuntime.jsxs(
2489
- designSystem.Flex,
2490
- {
2491
- direction: "column",
2492
- gap: 2,
2493
- alignItems: "flex-start",
2494
- borderColor: "neutral200",
2495
- hasRadius: true,
2496
- padding: 6,
2497
- children: [
2498
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Flex, { direction: "row", as: "ol", children: fieldPath.map((pathSegment, index2) => /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Typography, { fontWeight: "semiBold", as: "li", children: [
2499
- pathSegment,
2500
- index2 !== fieldPath.length - 1 && /* @__PURE__ */ jsxRuntime.jsx(
2501
- Icons.ChevronRight,
2502
- {
2503
- fill: "neutral500",
2504
- height: "0.8rem",
2505
- width: "0.8rem",
2506
- style: { margin: "0 0.8rem" }
2507
- }
2508
- )
2509
- ] }, index2)) }),
2510
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { as: "p", textColor: "neutral600", children: formatMessage({
2511
- id: getTranslation(`containers.list.autoCloneModal.error.${reason}`),
2512
- defaultMessage: getDefaultErrorMessage(reason)
2513
- }) })
2514
- ]
2515
- },
2516
- fieldPath.join()
2517
- )) })
2518
- ] });
2670
+ const HOOKS = {
2671
+ /**
2672
+ * Hook that allows to mutate the displayed headers of the list view table
2673
+ * @constant
2674
+ * @type {string}
2675
+ */
2676
+ INJECT_COLUMN_IN_TABLE: "Admin/CM/pages/ListView/inject-column-in-table",
2677
+ /**
2678
+ * Hook that allows to mutate the CM's collection types links pre-set filters
2679
+ * @constant
2680
+ * @type {string}
2681
+ */
2682
+ MUTATE_COLLECTION_TYPES_LINKS: "Admin/CM/pages/App/mutate-collection-types-links",
2683
+ /**
2684
+ * Hook that allows to mutate the CM's edit view layout
2685
+ * @constant
2686
+ * @type {string}
2687
+ */
2688
+ MUTATE_EDIT_VIEW_LAYOUT: "Admin/CM/pages/EditView/mutate-edit-view-layout",
2689
+ /**
2690
+ * Hook that allows to mutate the CM's single types links pre-set filters
2691
+ * @constant
2692
+ * @type {string}
2693
+ */
2694
+ MUTATE_SINGLE_TYPES_LINKS: "Admin/CM/pages/App/mutate-single-types-links"
2519
2695
  };
2520
- const TableActions = ({ document }) => {
2521
- const { formatMessage } = reactIntl.useIntl();
2522
- const { model, collectionType } = useDoc();
2523
- const plugins = strapiAdmin.useStrapiApp("TableActions", (state) => state.plugins);
2524
- const props = {
2525
- activeTab: null,
2526
- model,
2527
- documentId: document.documentId,
2528
- collectionType,
2529
- document
2530
- };
2531
- return /* @__PURE__ */ jsxRuntime.jsx(
2532
- strapiAdmin.DescriptionComponentRenderer,
2533
- {
2534
- props,
2535
- descriptions: plugins["content-manager"].apis.getDocumentActions(),
2536
- children: (actions2) => {
2537
- const tableRowActions = actions2.filter((action) => {
2538
- const positions = Array.isArray(action.position) ? action.position : [action.position];
2539
- return positions.includes("table-row");
2540
- });
2696
+ const contentTypesApi = contentManagerApi.injectEndpoints({
2697
+ endpoints: (builder) => ({
2698
+ getContentTypeConfiguration: builder.query({
2699
+ query: (uid) => ({
2700
+ url: `/content-manager/content-types/${uid}/configuration`,
2701
+ method: "GET"
2702
+ }),
2703
+ transformResponse: (response) => response.data,
2704
+ providesTags: (_result, _error, uid) => [
2705
+ { type: "ContentTypesConfiguration", id: uid },
2706
+ { type: "ContentTypeSettings", id: "LIST" }
2707
+ ]
2708
+ }),
2709
+ getAllContentTypeSettings: builder.query({
2710
+ query: () => "/content-manager/content-types-settings",
2711
+ transformResponse: (response) => response.data,
2712
+ providesTags: [{ type: "ContentTypeSettings", id: "LIST" }]
2713
+ }),
2714
+ updateContentTypeConfiguration: builder.mutation({
2715
+ query: ({ uid, ...body }) => ({
2716
+ url: `/content-manager/content-types/${uid}/configuration`,
2717
+ method: "PUT",
2718
+ data: body
2719
+ }),
2720
+ transformResponse: (response) => response.data,
2721
+ invalidatesTags: (_result, _error, { uid }) => [
2722
+ { type: "ContentTypesConfiguration", id: uid },
2723
+ { type: "ContentTypeSettings", id: "LIST" },
2724
+ // Is this necessary?
2725
+ { type: "InitialData" }
2726
+ ]
2727
+ })
2728
+ })
2729
+ });
2730
+ const {
2731
+ useGetContentTypeConfigurationQuery,
2732
+ useGetAllContentTypeSettingsQuery,
2733
+ useUpdateContentTypeConfigurationMutation
2734
+ } = contentTypesApi;
2735
+ const checkIfAttributeIsDisplayable = (attribute) => {
2736
+ const { type } = attribute;
2737
+ if (type === "relation") {
2738
+ return !attribute.relation.toLowerCase().includes("morph");
2739
+ }
2740
+ return !["json", "dynamiczone", "richtext", "password", "blocks"].includes(type) && !!type;
2741
+ };
2742
+ const getMainField = (attribute, mainFieldName, { schemas, components }) => {
2743
+ if (!mainFieldName) {
2744
+ return void 0;
2745
+ }
2746
+ const mainFieldType = attribute.type === "component" ? components[attribute.component].attributes[mainFieldName].type : (
2747
+ // @ts-expect-error – `targetModel` does exist on the attribute for a relation.
2748
+ schemas.find((schema) => schema.uid === attribute.targetModel)?.attributes[mainFieldName].type
2749
+ );
2750
+ return {
2751
+ name: mainFieldName,
2752
+ type: mainFieldType ?? "string"
2753
+ };
2754
+ };
2755
+ const DEFAULT_SETTINGS = {
2756
+ bulkable: false,
2757
+ filterable: false,
2758
+ searchable: false,
2759
+ pagination: false,
2760
+ defaultSortBy: "",
2761
+ defaultSortOrder: "asc",
2762
+ mainField: "id",
2763
+ pageSize: 10
2764
+ };
2765
+ const useDocumentLayout = (model) => {
2766
+ const { schema, components } = useDocument({ model, collectionType: "" }, { skip: true });
2767
+ const [{ query }] = strapiAdmin.useQueryParams();
2768
+ const runHookWaterfall = strapiAdmin.useStrapiApp("useDocumentLayout", (state) => state.runHookWaterfall);
2769
+ const { toggleNotification } = strapiAdmin.useNotification();
2770
+ const { _unstableFormatAPIError: formatAPIError } = strapiAdmin.useAPIErrorHandler();
2771
+ const { isLoading: isLoadingSchemas, schemas } = useContentTypeSchema();
2772
+ const {
2773
+ data,
2774
+ isLoading: isLoadingConfigs,
2775
+ error,
2776
+ isFetching: isFetchingConfigs
2777
+ } = useGetContentTypeConfigurationQuery(model);
2778
+ const isLoading = isLoadingSchemas || isFetchingConfigs || isLoadingConfigs;
2779
+ React__namespace.useEffect(() => {
2780
+ if (error) {
2781
+ toggleNotification({
2782
+ type: "danger",
2783
+ message: formatAPIError(error)
2784
+ });
2785
+ }
2786
+ }, [error, formatAPIError, toggleNotification]);
2787
+ const editLayout = React__namespace.useMemo(
2788
+ () => data && !isLoading ? formatEditLayout(data, { schemas, schema, components }) : {
2789
+ layout: [],
2790
+ components: {},
2791
+ metadatas: {},
2792
+ options: {},
2793
+ settings: DEFAULT_SETTINGS
2794
+ },
2795
+ [data, isLoading, schemas, schema, components]
2796
+ );
2797
+ const listLayout = React__namespace.useMemo(() => {
2798
+ return data && !isLoading ? formatListLayout(data, { schemas, schema, components }) : {
2799
+ layout: [],
2800
+ metadatas: {},
2801
+ options: {},
2802
+ settings: DEFAULT_SETTINGS
2803
+ };
2804
+ }, [data, isLoading, schemas, schema, components]);
2805
+ const { layout: edit } = React__namespace.useMemo(
2806
+ () => runHookWaterfall(HOOKS.MUTATE_EDIT_VIEW_LAYOUT, {
2807
+ layout: editLayout,
2808
+ query
2809
+ }),
2810
+ [editLayout, query, runHookWaterfall]
2811
+ );
2812
+ return {
2813
+ error,
2814
+ isLoading,
2815
+ edit,
2816
+ list: listLayout
2817
+ };
2818
+ };
2819
+ const useDocLayout = () => {
2820
+ const { model } = useDoc();
2821
+ return useDocumentLayout(model);
2822
+ };
2823
+ const formatEditLayout = (data, {
2824
+ schemas,
2825
+ schema,
2826
+ components
2827
+ }) => {
2828
+ let currentPanelIndex = 0;
2829
+ const panelledEditAttributes = convertEditLayoutToFieldLayouts(
2830
+ data.contentType.layouts.edit,
2831
+ schema?.attributes,
2832
+ data.contentType.metadatas,
2833
+ { configurations: data.components, schemas: components },
2834
+ schemas
2835
+ ).reduce((panels, row) => {
2836
+ if (row.some((field) => field.type === "dynamiczone")) {
2837
+ panels.push([row]);
2838
+ currentPanelIndex += 2;
2839
+ } else {
2840
+ if (!panels[currentPanelIndex]) {
2841
+ panels.push([]);
2842
+ }
2843
+ panels[currentPanelIndex].push(row);
2844
+ }
2845
+ return panels;
2846
+ }, []);
2847
+ const componentEditAttributes = Object.entries(data.components).reduce(
2848
+ (acc, [uid, configuration]) => {
2849
+ acc[uid] = {
2850
+ layout: convertEditLayoutToFieldLayouts(
2851
+ configuration.layouts.edit,
2852
+ components[uid].attributes,
2853
+ configuration.metadatas,
2854
+ { configurations: data.components, schemas: components }
2855
+ ),
2856
+ settings: {
2857
+ ...configuration.settings,
2858
+ icon: components[uid].info.icon,
2859
+ displayName: components[uid].info.displayName
2860
+ }
2861
+ };
2862
+ return acc;
2863
+ },
2864
+ {}
2865
+ );
2866
+ const editMetadatas = Object.entries(data.contentType.metadatas).reduce(
2867
+ (acc, [attribute, metadata]) => {
2868
+ return {
2869
+ ...acc,
2870
+ [attribute]: metadata.edit
2871
+ };
2872
+ },
2873
+ {}
2874
+ );
2875
+ return {
2876
+ layout: panelledEditAttributes,
2877
+ components: componentEditAttributes,
2878
+ metadatas: editMetadatas,
2879
+ settings: {
2880
+ ...data.contentType.settings,
2881
+ displayName: schema?.info.displayName
2882
+ },
2883
+ options: {
2884
+ ...schema?.options,
2885
+ ...schema?.pluginOptions,
2886
+ ...data.contentType.options
2887
+ }
2888
+ };
2889
+ };
2890
+ const convertEditLayoutToFieldLayouts = (rows, attributes = {}, metadatas, components, schemas = []) => {
2891
+ return rows.map(
2892
+ (row) => row.map((field) => {
2893
+ const attribute = attributes[field.name];
2894
+ if (!attribute) {
2895
+ return null;
2896
+ }
2897
+ const { edit: metadata } = metadatas[field.name];
2898
+ const settings = attribute.type === "component" && components ? components.configurations[attribute.component].settings : {};
2899
+ return {
2900
+ attribute,
2901
+ disabled: !metadata.editable,
2902
+ hint: metadata.description,
2903
+ label: metadata.label ?? "",
2904
+ name: field.name,
2905
+ // @ts-expect-error – mainField does exist on the metadata for a relation.
2906
+ mainField: getMainField(attribute, metadata.mainField || settings.mainField, {
2907
+ schemas,
2908
+ components: components?.schemas ?? {}
2909
+ }),
2910
+ placeholder: metadata.placeholder ?? "",
2911
+ required: attribute.required ?? false,
2912
+ size: field.size,
2913
+ unique: "unique" in attribute ? attribute.unique : false,
2914
+ visible: metadata.visible ?? true,
2915
+ type: attribute.type
2916
+ };
2917
+ }).filter((field) => field !== null)
2918
+ );
2919
+ };
2920
+ const formatListLayout = (data, {
2921
+ schemas,
2922
+ schema,
2923
+ components
2924
+ }) => {
2925
+ const listMetadatas = Object.entries(data.contentType.metadatas).reduce(
2926
+ (acc, [attribute, metadata]) => {
2927
+ return {
2928
+ ...acc,
2929
+ [attribute]: metadata.list
2930
+ };
2931
+ },
2932
+ {}
2933
+ );
2934
+ const listAttributes = convertListLayoutToFieldLayouts(
2935
+ data.contentType.layouts.list,
2936
+ schema?.attributes,
2937
+ listMetadatas,
2938
+ { configurations: data.components, schemas: components },
2939
+ schemas
2940
+ );
2941
+ return {
2942
+ layout: listAttributes,
2943
+ settings: { ...data.contentType.settings, displayName: schema?.info.displayName },
2944
+ metadatas: listMetadatas,
2945
+ options: {
2946
+ ...schema?.options,
2947
+ ...schema?.pluginOptions,
2948
+ ...data.contentType.options
2949
+ }
2950
+ };
2951
+ };
2952
+ const convertListLayoutToFieldLayouts = (columns, attributes = {}, metadatas, components, schemas = []) => {
2953
+ return columns.map((name) => {
2954
+ const attribute = attributes[name];
2955
+ if (!attribute) {
2956
+ return null;
2957
+ }
2958
+ const metadata = metadatas[name];
2959
+ const settings = attribute.type === "component" && components ? components.configurations[attribute.component].settings : {};
2960
+ return {
2961
+ attribute,
2962
+ label: metadata.label ?? "",
2963
+ mainField: getMainField(attribute, metadata.mainField || settings.mainField, {
2964
+ schemas,
2965
+ components: components?.schemas ?? {}
2966
+ }),
2967
+ name,
2968
+ searchable: metadata.searchable ?? true,
2969
+ sortable: metadata.sortable ?? true
2970
+ };
2971
+ }).filter((field) => field !== null);
2972
+ };
2973
+ const ConfirmBulkActionDialog = ({
2974
+ onToggleDialog,
2975
+ isOpen = false,
2976
+ dialogBody,
2977
+ endAction
2978
+ }) => {
2979
+ const { formatMessage } = reactIntl.useIntl();
2980
+ return /* @__PURE__ */ jsxRuntime.jsx(designSystem.Dialog.Root, { open: isOpen, children: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Dialog.Content, { children: [
2981
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Dialog.Header, { children: formatMessage({
2982
+ id: "app.components.ConfirmDialog.title",
2983
+ defaultMessage: "Confirmation"
2984
+ }) }),
2985
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Dialog.Body, { children: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { direction: "column", alignItems: "stretch", gap: 2, children: [
2986
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Flex, { justifyContent: "center", children: /* @__PURE__ */ jsxRuntime.jsx(Icons.WarningCircle, { width: "24px", height: "24px", fill: "danger600" }) }),
2987
+ dialogBody
2988
+ ] }) }),
2989
+ /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Dialog.Footer, { children: [
2990
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Dialog.Cancel, { children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Button, { fullWidth: true, onClick: onToggleDialog, variant: "tertiary", children: formatMessage({
2991
+ id: "app.components.Button.cancel",
2992
+ defaultMessage: "Cancel"
2993
+ }) }) }),
2994
+ endAction
2995
+ ] })
2996
+ ] }) });
2997
+ };
2998
+ const BoldChunk$1 = (chunks) => /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { fontWeight: "bold", children: chunks });
2999
+ const ConfirmDialogPublishAll = ({
3000
+ isOpen,
3001
+ onToggleDialog,
3002
+ isConfirmButtonLoading = false,
3003
+ onConfirm
3004
+ }) => {
3005
+ const { formatMessage } = reactIntl.useIntl();
3006
+ const selectedEntries = strapiAdmin.useTable("ConfirmDialogPublishAll", (state) => state.selectedRows);
3007
+ const { toggleNotification } = strapiAdmin.useNotification();
3008
+ const { _unstableFormatAPIError: formatAPIError } = strapiAdmin.useAPIErrorHandler(getTranslation);
3009
+ const { model, schema } = useDoc();
3010
+ const [{ query }] = strapiAdmin.useQueryParams();
3011
+ const enableDraftRelationsCount = false;
3012
+ const {
3013
+ data: countDraftRelations = 0,
3014
+ isLoading,
3015
+ error
3016
+ } = useGetManyDraftRelationCountQuery(
3017
+ {
3018
+ model,
3019
+ documentIds: selectedEntries.map((entry) => entry.documentId),
3020
+ locale: query?.plugins?.i18n?.locale
3021
+ },
3022
+ {
3023
+ skip: !enableDraftRelationsCount
3024
+ }
3025
+ );
3026
+ React__namespace.useEffect(() => {
3027
+ if (error) {
3028
+ toggleNotification({ type: "danger", message: formatAPIError(error) });
3029
+ }
3030
+ }, [error, formatAPIError, toggleNotification]);
3031
+ if (error) {
3032
+ return null;
3033
+ }
3034
+ return /* @__PURE__ */ jsxRuntime.jsx(
3035
+ ConfirmBulkActionDialog,
3036
+ {
3037
+ isOpen: isOpen && !isLoading,
3038
+ onToggleDialog,
3039
+ dialogBody: /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
3040
+ /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Typography, { id: "confirm-description", textAlign: "center", children: [
3041
+ countDraftRelations > 0 && formatMessage(
3042
+ {
3043
+ id: getTranslation(`popUpwarning.warning.bulk-has-draft-relations.message`),
3044
+ defaultMessage: "<b>{count} {count, plural, one { relation } other { relations } } out of {entities} { entities, plural, one { entry } other { entries } } {count, plural, one { is } other { are } }</b> not published yet and might lead to unexpected behavior. "
3045
+ },
3046
+ {
3047
+ b: BoldChunk$1,
3048
+ count: countDraftRelations,
3049
+ entities: selectedEntries.length
3050
+ }
3051
+ ),
3052
+ formatMessage({
3053
+ id: getTranslation("popUpWarning.bodyMessage.contentType.publish.all"),
3054
+ defaultMessage: "Are you sure you want to publish these entries?"
3055
+ })
3056
+ ] }),
3057
+ schema?.pluginOptions && "i18n" in schema.pluginOptions && schema?.pluginOptions.i18n && /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { textColor: "danger500", textAlign: "center", children: formatMessage(
3058
+ {
3059
+ id: getTranslation("Settings.list.actions.publishAdditionalInfos"),
3060
+ defaultMessage: "This will publish the active locale versions <em>(from Internationalization)</em>"
3061
+ },
3062
+ {
3063
+ em: Emphasis
3064
+ }
3065
+ ) })
3066
+ ] }),
3067
+ endAction: /* @__PURE__ */ jsxRuntime.jsx(
3068
+ designSystem.Button,
3069
+ {
3070
+ onClick: onConfirm,
3071
+ variant: "secondary",
3072
+ startIcon: /* @__PURE__ */ jsxRuntime.jsx(Icons.Check, {}),
3073
+ loading: isConfirmButtonLoading,
3074
+ children: formatMessage({
3075
+ id: "app.utils.publish",
3076
+ defaultMessage: "Publish"
3077
+ })
3078
+ }
3079
+ )
3080
+ }
3081
+ );
3082
+ };
3083
+ const TypographyMaxWidth = styledComponents.styled(designSystem.Typography)`
3084
+ max-width: 300px;
3085
+ `;
3086
+ const formatErrorMessages = (errors, parentKey, formatMessage) => {
3087
+ const messages = [];
3088
+ Object.entries(errors).forEach(([key, value]) => {
3089
+ const currentKey = parentKey ? `${parentKey}.${key}` : key;
3090
+ if (typeof value === "object" && value !== null && !Array.isArray(value)) {
3091
+ if ("id" in value && "defaultMessage" in value) {
3092
+ messages.push(
3093
+ formatMessage(
3094
+ {
3095
+ id: `${value.id}.withField`,
3096
+ defaultMessage: value.defaultMessage
3097
+ },
3098
+ { field: currentKey }
3099
+ )
3100
+ );
3101
+ } else {
3102
+ messages.push(
3103
+ ...formatErrorMessages(
3104
+ // @ts-expect-error TODO: check why value is not compatible with FormErrors
3105
+ value,
3106
+ currentKey,
3107
+ formatMessage
3108
+ )
3109
+ );
3110
+ }
3111
+ } else {
3112
+ messages.push(
3113
+ formatMessage(
3114
+ {
3115
+ id: `${value}.withField`,
3116
+ defaultMessage: value
3117
+ },
3118
+ { field: currentKey }
3119
+ )
3120
+ );
3121
+ }
3122
+ });
3123
+ return messages;
3124
+ };
3125
+ const EntryValidationText = ({ validationErrors, status }) => {
3126
+ const { formatMessage } = reactIntl.useIntl();
3127
+ if (validationErrors) {
3128
+ const validationErrorsMessages = formatErrorMessages(validationErrors, "", formatMessage).join(
3129
+ " "
3130
+ );
3131
+ return /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { gap: 2, children: [
3132
+ /* @__PURE__ */ jsxRuntime.jsx(Icons.CrossCircle, { fill: "danger600" }),
3133
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Tooltip, { description: validationErrorsMessages, children: /* @__PURE__ */ jsxRuntime.jsx(TypographyMaxWidth, { textColor: "danger600", variant: "omega", fontWeight: "semiBold", ellipsis: true, children: validationErrorsMessages }) })
3134
+ ] });
3135
+ }
3136
+ if (status === "published") {
3137
+ return /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { gap: 2, children: [
3138
+ /* @__PURE__ */ jsxRuntime.jsx(Icons.CheckCircle, { fill: "success600" }),
3139
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { textColor: "success600", fontWeight: "bold", children: formatMessage({
3140
+ id: "content-manager.bulk-publish.already-published",
3141
+ defaultMessage: "Already Published"
3142
+ }) })
3143
+ ] });
3144
+ }
3145
+ if (status === "modified") {
3146
+ return /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { gap: 2, children: [
3147
+ /* @__PURE__ */ jsxRuntime.jsx(Icons.ArrowsCounterClockwise, { fill: "alternative600" }),
3148
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { children: formatMessage({
3149
+ id: "content-manager.bulk-publish.modified",
3150
+ defaultMessage: "Ready to publish changes"
3151
+ }) })
3152
+ ] });
3153
+ }
3154
+ return /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { gap: 2, children: [
3155
+ /* @__PURE__ */ jsxRuntime.jsx(Icons.CheckCircle, { fill: "success600" }),
3156
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { children: formatMessage({
3157
+ id: "app.utils.ready-to-publish",
3158
+ defaultMessage: "Ready to publish"
3159
+ }) })
3160
+ ] });
3161
+ };
3162
+ const TABLE_HEADERS = [
3163
+ { name: "id", label: "id" },
3164
+ { name: "name", label: "name" },
3165
+ { name: "status", label: "status" },
3166
+ { name: "publicationStatus", label: "Publication status" }
3167
+ ];
3168
+ const SelectedEntriesTableContent = ({
3169
+ isPublishing,
3170
+ rowsToDisplay = [],
3171
+ entriesToPublish = [],
3172
+ validationErrors = {}
3173
+ }) => {
3174
+ const { pathname } = reactRouterDom.useLocation();
3175
+ const { formatMessage } = reactIntl.useIntl();
3176
+ const {
3177
+ list: {
3178
+ settings: { mainField }
3179
+ }
3180
+ } = useDocLayout();
3181
+ const shouldDisplayMainField = mainField != null && mainField !== "id";
3182
+ return /* @__PURE__ */ jsxRuntime.jsxs(strapiAdmin.Table.Content, { children: [
3183
+ /* @__PURE__ */ jsxRuntime.jsxs(strapiAdmin.Table.Head, { children: [
3184
+ /* @__PURE__ */ jsxRuntime.jsx(strapiAdmin.Table.HeaderCheckboxCell, {}),
3185
+ TABLE_HEADERS.filter((head) => head.name !== "name" || shouldDisplayMainField).map(
3186
+ (head) => /* @__PURE__ */ jsxRuntime.jsx(strapiAdmin.Table.HeaderCell, { ...head }, head.name)
3187
+ )
3188
+ ] }),
3189
+ /* @__PURE__ */ jsxRuntime.jsx(strapiAdmin.Table.Loading, {}),
3190
+ /* @__PURE__ */ jsxRuntime.jsx(strapiAdmin.Table.Body, { children: rowsToDisplay.map((row, index2) => /* @__PURE__ */ jsxRuntime.jsxs(strapiAdmin.Table.Row, { children: [
3191
+ /* @__PURE__ */ jsxRuntime.jsx(strapiAdmin.Table.CheckboxCell, { id: row.id }),
3192
+ /* @__PURE__ */ jsxRuntime.jsx(strapiAdmin.Table.Cell, { children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { children: row.id }) }),
3193
+ shouldDisplayMainField && /* @__PURE__ */ jsxRuntime.jsx(strapiAdmin.Table.Cell, { children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { children: row[mainField] }) }),
3194
+ /* @__PURE__ */ jsxRuntime.jsx(strapiAdmin.Table.Cell, { children: /* @__PURE__ */ jsxRuntime.jsx(DocumentStatus, { status: row.status, maxWidth: "min-content" }) }),
3195
+ /* @__PURE__ */ jsxRuntime.jsx(strapiAdmin.Table.Cell, { children: isPublishing && entriesToPublish.includes(row.documentId) ? /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { gap: 2, children: [
3196
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { children: formatMessage({
3197
+ id: "content-manager.success.record.publishing",
3198
+ defaultMessage: "Publishing..."
3199
+ }) }),
3200
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Loader, { small: true })
3201
+ ] }) : /* @__PURE__ */ jsxRuntime.jsx(
3202
+ EntryValidationText,
3203
+ {
3204
+ validationErrors: validationErrors[row.documentId],
3205
+ status: row.status
3206
+ }
3207
+ ) }),
3208
+ /* @__PURE__ */ jsxRuntime.jsx(strapiAdmin.Table.Cell, { children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Flex, { children: /* @__PURE__ */ jsxRuntime.jsx(
3209
+ designSystem.IconButton,
3210
+ {
3211
+ tag: reactRouterDom.Link,
3212
+ to: {
3213
+ pathname: `${pathname}/${row.documentId}`,
3214
+ search: row.locale && `?plugins[i18n][locale]=${row.locale}`
3215
+ },
3216
+ state: { from: pathname },
3217
+ label: formatMessage(
3218
+ { id: "app.component.HelperPluginTable.edit", defaultMessage: "Edit {target}" },
3219
+ {
3220
+ target: formatMessage(
3221
+ {
3222
+ id: "content-manager.components.ListViewHelperPluginTable.row-line",
3223
+ defaultMessage: "item line {number}"
3224
+ },
3225
+ { number: index2 + 1 }
3226
+ )
3227
+ }
3228
+ ),
3229
+ target: "_blank",
3230
+ marginLeft: "auto",
3231
+ variant: "ghost",
3232
+ children: /* @__PURE__ */ jsxRuntime.jsx(Icons.Pencil, { width: "1.6rem", height: "1.6rem" })
3233
+ }
3234
+ ) }) })
3235
+ ] }, row.id)) })
3236
+ ] });
3237
+ };
3238
+ const BoldChunk = (chunks) => /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { fontWeight: "bold", children: chunks });
3239
+ const SelectedEntriesModalContent = ({
3240
+ listViewSelectedEntries,
3241
+ toggleModal,
3242
+ setListViewSelectedDocuments,
3243
+ model
3244
+ }) => {
3245
+ const { formatMessage } = reactIntl.useIntl();
3246
+ const { schema, components } = useContentTypeSchema(model);
3247
+ const documentIds = listViewSelectedEntries.map(({ documentId }) => documentId);
3248
+ const [{ query }] = strapiAdmin.useQueryParams();
3249
+ const params = React__namespace.useMemo(() => buildValidParams(query), [query]);
3250
+ const { data, isLoading, isFetching, refetch } = useGetAllDocumentsQuery(
3251
+ {
3252
+ model,
3253
+ params: {
3254
+ page: "1",
3255
+ pageSize: documentIds.length.toString(),
3256
+ sort: query.sort,
3257
+ filters: {
3258
+ documentId: {
3259
+ $in: documentIds
3260
+ }
3261
+ },
3262
+ locale: query.plugins?.i18n?.locale
3263
+ }
3264
+ },
3265
+ {
3266
+ selectFromResult: ({ data: data2, ...restRes }) => ({ data: data2?.results ?? [], ...restRes })
3267
+ }
3268
+ );
3269
+ const { rows, validationErrors } = React__namespace.useMemo(() => {
3270
+ if (data.length > 0 && schema) {
3271
+ const validate = createYupSchema(
3272
+ schema.attributes,
3273
+ components,
3274
+ // Since this is the "Publish" action, the validation
3275
+ // schema must enforce the rules for published entities
3276
+ { status: "published" }
3277
+ );
3278
+ const validationErrors2 = {};
3279
+ const rows2 = data.map((entry) => {
3280
+ try {
3281
+ validate.validateSync(entry, { abortEarly: false });
3282
+ return entry;
3283
+ } catch (e) {
3284
+ if (e instanceof yup.ValidationError) {
3285
+ validationErrors2[entry.documentId] = strapiAdmin.getYupValidationErrors(e);
3286
+ }
3287
+ return entry;
3288
+ }
3289
+ });
3290
+ return { rows: rows2, validationErrors: validationErrors2 };
3291
+ }
3292
+ return {
3293
+ rows: [],
3294
+ validationErrors: {}
3295
+ };
3296
+ }, [components, data, schema]);
3297
+ const [publishedCount, setPublishedCount] = React__namespace.useState(0);
3298
+ const [isDialogOpen, setIsDialogOpen] = React__namespace.useState(false);
3299
+ const { publishMany: bulkPublishAction } = useDocumentActions();
3300
+ const [, { isLoading: isSubmittingForm }] = usePublishManyDocumentsMutation();
3301
+ const selectedRows = strapiAdmin.useTable("publishAction", (state) => state.selectedRows);
3302
+ const selectedEntries = rows.filter(
3303
+ (entry) => selectedRows.some((selectedEntry) => selectedEntry.documentId === entry.documentId)
3304
+ );
3305
+ const entriesToPublish = selectedEntries.filter((entry) => !validationErrors[entry.documentId]).map((entry) => entry.documentId);
3306
+ const selectedEntriesWithErrorsCount = selectedEntries.filter(
3307
+ ({ documentId }) => validationErrors[documentId]
3308
+ ).length;
3309
+ const selectedEntriesPublished = selectedEntries.filter(
3310
+ ({ status }) => status === "published"
3311
+ ).length;
3312
+ const selectedEntriesWithNoErrorsCount = selectedEntries.length - selectedEntriesWithErrorsCount - selectedEntriesPublished;
3313
+ const toggleDialog = () => setIsDialogOpen((prev) => !prev);
3314
+ const handleConfirmBulkPublish = async () => {
3315
+ toggleDialog();
3316
+ const res = await bulkPublishAction({ model, documentIds: entriesToPublish, params });
3317
+ if (!("error" in res)) {
3318
+ setPublishedCount(res.count);
3319
+ const unpublishedEntries = rows.filter((row) => {
3320
+ return !entriesToPublish.includes(row.documentId);
3321
+ });
3322
+ setListViewSelectedDocuments(unpublishedEntries);
3323
+ }
3324
+ };
3325
+ const getFormattedCountMessage = () => {
3326
+ if (publishedCount) {
3327
+ return formatMessage(
3328
+ {
3329
+ id: getTranslation("containers.list.selectedEntriesModal.publishedCount"),
3330
+ defaultMessage: "<b>{publishedCount}</b> {publishedCount, plural, =0 {entries} one {entry} other {entries}} published. <b>{withErrorsCount}</b> {withErrorsCount, plural, =0 {entries} one {entry} other {entries}} waiting for action."
3331
+ },
3332
+ {
3333
+ publishedCount,
3334
+ withErrorsCount: selectedEntriesWithErrorsCount,
3335
+ b: BoldChunk
3336
+ }
3337
+ );
3338
+ }
3339
+ return formatMessage(
3340
+ {
3341
+ id: getTranslation("containers.list.selectedEntriesModal.selectedCount"),
3342
+ defaultMessage: "<b>{alreadyPublishedCount}</b> {alreadyPublishedCount, plural, =0 {entries} one {entry} other {entries}} already published. <b>{readyToPublishCount}</b> {readyToPublishCount, plural, =0 {entries} one {entry} other {entries}} ready to publish. <b>{withErrorsCount}</b> {withErrorsCount, plural, =0 {entries} one {entry} other {entries}} waiting for action."
3343
+ },
3344
+ {
3345
+ readyToPublishCount: selectedEntriesWithNoErrorsCount,
3346
+ withErrorsCount: selectedEntriesWithErrorsCount,
3347
+ alreadyPublishedCount: selectedEntriesPublished,
3348
+ b: BoldChunk
3349
+ }
3350
+ );
3351
+ };
3352
+ return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
3353
+ /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Modal.Body, { children: [
3354
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { children: getFormattedCountMessage() }),
3355
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Box, { marginTop: 5, children: /* @__PURE__ */ jsxRuntime.jsx(
3356
+ SelectedEntriesTableContent,
3357
+ {
3358
+ isPublishing: isSubmittingForm,
3359
+ rowsToDisplay: rows,
3360
+ entriesToPublish,
3361
+ validationErrors
3362
+ }
3363
+ ) })
3364
+ ] }),
3365
+ /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Modal.Footer, { children: [
3366
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Button, { onClick: toggleModal, variant: "tertiary", children: formatMessage({
3367
+ id: "app.components.Button.cancel",
3368
+ defaultMessage: "Cancel"
3369
+ }) }),
3370
+ /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { gap: 2, children: [
3371
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Button, { onClick: refetch, variant: "tertiary", loading: isFetching, children: formatMessage({ id: "app.utils.refresh", defaultMessage: "Refresh" }) }),
3372
+ /* @__PURE__ */ jsxRuntime.jsx(
3373
+ designSystem.Button,
3374
+ {
3375
+ onClick: toggleDialog,
3376
+ disabled: selectedEntries.length === 0 || selectedEntries.length === selectedEntriesWithErrorsCount || selectedEntriesPublished === selectedEntries.length || isLoading,
3377
+ loading: isSubmittingForm,
3378
+ children: formatMessage({ id: "app.utils.publish", defaultMessage: "Publish" })
3379
+ }
3380
+ )
3381
+ ] })
3382
+ ] }),
3383
+ /* @__PURE__ */ jsxRuntime.jsx(
3384
+ ConfirmDialogPublishAll,
3385
+ {
3386
+ isOpen: isDialogOpen,
3387
+ onToggleDialog: toggleDialog,
3388
+ isConfirmButtonLoading: isSubmittingForm,
3389
+ onConfirm: handleConfirmBulkPublish
3390
+ }
3391
+ )
3392
+ ] });
3393
+ };
3394
+ const PublishAction = ({ documents, model }) => {
3395
+ const { formatMessage } = reactIntl.useIntl();
3396
+ const hasPublishPermission = useDocumentRBAC("unpublishAction", (state) => state.canPublish);
3397
+ const showPublishButton = hasPublishPermission && documents.some(({ status }) => status !== "published");
3398
+ const setListViewSelectedDocuments = strapiAdmin.useTable("publishAction", (state) => state.selectRow);
3399
+ const refetchList = () => {
3400
+ contentManagerApi.util.invalidateTags([{ type: "Document", id: `${model}_LIST` }]);
3401
+ };
3402
+ if (!showPublishButton)
3403
+ return null;
3404
+ return {
3405
+ actionType: "publish",
3406
+ variant: "tertiary",
3407
+ label: formatMessage({ id: "app.utils.publish", defaultMessage: "Publish" }),
3408
+ dialog: {
3409
+ type: "modal",
3410
+ title: formatMessage({
3411
+ id: getTranslation("containers.ListPage.selectedEntriesModal.title"),
3412
+ defaultMessage: "Publish entries"
3413
+ }),
3414
+ content: ({ onClose }) => {
3415
+ return /* @__PURE__ */ jsxRuntime.jsx(strapiAdmin.Table.Root, { rows: documents, defaultSelectedRows: documents, headers: TABLE_HEADERS, children: /* @__PURE__ */ jsxRuntime.jsx(
3416
+ SelectedEntriesModalContent,
3417
+ {
3418
+ listViewSelectedEntries: documents,
3419
+ toggleModal: () => {
3420
+ onClose();
3421
+ refetchList();
3422
+ },
3423
+ setListViewSelectedDocuments,
3424
+ model
3425
+ }
3426
+ ) });
3427
+ },
3428
+ onClose: () => {
3429
+ refetchList();
3430
+ }
3431
+ }
3432
+ };
3433
+ };
3434
+ const BulkActionsRenderer = () => {
3435
+ const plugins = strapiAdmin.useStrapiApp("BulkActionsRenderer", (state) => state.plugins);
3436
+ const { model, collectionType } = useDoc();
3437
+ const { selectedRows } = strapiAdmin.useTable("BulkActionsRenderer", (state) => state);
3438
+ return /* @__PURE__ */ jsxRuntime.jsx(designSystem.Flex, { gap: 2, children: /* @__PURE__ */ jsxRuntime.jsx(
3439
+ strapiAdmin.DescriptionComponentRenderer,
3440
+ {
3441
+ props: {
3442
+ model,
3443
+ collectionType,
3444
+ documents: selectedRows
3445
+ },
3446
+ descriptions: plugins["content-manager"].apis.getBulkActions(),
3447
+ children: (actions2) => actions2.map((action) => /* @__PURE__ */ jsxRuntime.jsx(DocumentActionButton, { ...action }, action.id))
3448
+ }
3449
+ ) });
3450
+ };
3451
+ const DeleteAction = ({ documents, model }) => {
3452
+ const { formatMessage } = reactIntl.useIntl();
3453
+ const { schema: contentType } = useDoc();
3454
+ const selectRow = strapiAdmin.useTable("DeleteAction", (state) => state.selectRow);
3455
+ const hasI18nEnabled = Boolean(contentType?.pluginOptions?.i18n);
3456
+ const [{ query }] = strapiAdmin.useQueryParams();
3457
+ const params = React__namespace.useMemo(() => buildValidParams(query), [query]);
3458
+ const hasDeletePermission = useDocumentRBAC("deleteAction", (state) => state.canDelete);
3459
+ const { deleteMany: bulkDeleteAction } = useDocumentActions();
3460
+ const documentIds = documents.map(({ documentId }) => documentId);
3461
+ const handleConfirmBulkDelete = async () => {
3462
+ const res = await bulkDeleteAction({
3463
+ documentIds,
3464
+ model,
3465
+ params
3466
+ });
3467
+ if (!("error" in res)) {
3468
+ selectRow([]);
3469
+ }
3470
+ };
3471
+ if (!hasDeletePermission)
3472
+ return null;
3473
+ return {
3474
+ variant: "danger-light",
3475
+ label: formatMessage({ id: "global.delete", defaultMessage: "Delete" }),
3476
+ dialog: {
3477
+ type: "dialog",
3478
+ title: formatMessage({
3479
+ id: "app.components.ConfirmDialog.title",
3480
+ defaultMessage: "Confirmation"
3481
+ }),
3482
+ content: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { direction: "column", alignItems: "stretch", gap: 2, children: [
3483
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Flex, { justifyContent: "center", children: /* @__PURE__ */ jsxRuntime.jsx(Icons.WarningCircle, { width: "24px", height: "24px", fill: "danger600" }) }),
3484
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { id: "confirm-description", textAlign: "center", children: formatMessage({
3485
+ id: "popUpWarning.bodyMessage.contentType.delete.all",
3486
+ defaultMessage: "Are you sure you want to delete these entries?"
3487
+ }) }),
3488
+ hasI18nEnabled && /* @__PURE__ */ jsxRuntime.jsx(designSystem.Box, { textAlign: "center", padding: 3, children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { textColor: "danger500", children: formatMessage(
3489
+ {
3490
+ id: getTranslation("Settings.list.actions.deleteAdditionalInfos"),
3491
+ defaultMessage: "This will delete the active locale versions <em>(from Internationalization)</em>"
3492
+ },
3493
+ {
3494
+ em: Emphasis
3495
+ }
3496
+ ) }) })
3497
+ ] }),
3498
+ onConfirm: handleConfirmBulkDelete
3499
+ }
3500
+ };
3501
+ };
3502
+ DeleteAction.type = "delete";
3503
+ const UnpublishAction = ({ documents, model }) => {
3504
+ const { formatMessage } = reactIntl.useIntl();
3505
+ const { schema } = useDoc();
3506
+ const selectRow = strapiAdmin.useTable("UnpublishAction", (state) => state.selectRow);
3507
+ const hasPublishPermission = useDocumentRBAC("unpublishAction", (state) => state.canPublish);
3508
+ const hasI18nEnabled = Boolean(schema?.pluginOptions?.i18n);
3509
+ const hasDraftAndPublishEnabled = Boolean(schema?.options?.draftAndPublish);
3510
+ const { unpublishMany: bulkUnpublishAction } = useDocumentActions();
3511
+ const documentIds = documents.map(({ documentId }) => documentId);
3512
+ const [{ query }] = strapiAdmin.useQueryParams();
3513
+ const params = React__namespace.useMemo(() => buildValidParams(query), [query]);
3514
+ const handleConfirmBulkUnpublish = async () => {
3515
+ const data = await bulkUnpublishAction({ documentIds, model, params });
3516
+ if (!("error" in data)) {
3517
+ selectRow([]);
3518
+ }
3519
+ };
3520
+ const showUnpublishButton = hasDraftAndPublishEnabled && hasPublishPermission && documents.some((entry) => entry.status === "published" || entry.status === "modified");
3521
+ if (!showUnpublishButton)
3522
+ return null;
3523
+ return {
3524
+ variant: "tertiary",
3525
+ label: formatMessage({ id: "app.utils.unpublish", defaultMessage: "Unpublish" }),
3526
+ dialog: {
3527
+ type: "dialog",
3528
+ title: formatMessage({
3529
+ id: "app.components.ConfirmDialog.title",
3530
+ defaultMessage: "Confirmation"
3531
+ }),
3532
+ content: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { direction: "column", alignItems: "stretch", gap: 2, children: [
3533
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Flex, { justifyContent: "center", children: /* @__PURE__ */ jsxRuntime.jsx(Icons.WarningCircle, { width: "24px", height: "24px", fill: "danger600" }) }),
3534
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { id: "confirm-description", textAlign: "center", children: formatMessage({
3535
+ id: "popUpWarning.bodyMessage.contentType.unpublish.all",
3536
+ defaultMessage: "Are you sure you want to unpublish these entries?"
3537
+ }) }),
3538
+ hasI18nEnabled && /* @__PURE__ */ jsxRuntime.jsx(designSystem.Box, { textAlign: "center", padding: 3, children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { textColor: "danger500", children: formatMessage(
3539
+ {
3540
+ id: getTranslation("Settings.list.actions.unpublishAdditionalInfos"),
3541
+ defaultMessage: "This will unpublish the active locale versions <em>(from Internationalization)</em>"
3542
+ },
3543
+ {
3544
+ em: Emphasis
3545
+ }
3546
+ ) }) })
3547
+ ] }),
3548
+ confirmButton: formatMessage({
3549
+ id: "app.utils.unpublish",
3550
+ defaultMessage: "Unpublish"
3551
+ }),
3552
+ onConfirm: handleConfirmBulkUnpublish
3553
+ }
3554
+ };
3555
+ };
3556
+ UnpublishAction.type = "unpublish";
3557
+ const Emphasis = (chunks) => /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { fontWeight: "semiBold", textColor: "danger500", children: chunks });
3558
+ const DEFAULT_BULK_ACTIONS = [PublishAction, UnpublishAction, DeleteAction];
3559
+ const AutoCloneFailureModalBody = ({ prohibitedFields }) => {
3560
+ const { formatMessage } = reactIntl.useIntl();
3561
+ const getDefaultErrorMessage = (reason) => {
3562
+ switch (reason) {
3563
+ case "relation":
3564
+ return "Duplicating the relation could remove it from the original entry.";
3565
+ case "unique":
3566
+ return "Identical values in a unique field are not allowed";
3567
+ default:
3568
+ return reason;
3569
+ }
3570
+ };
3571
+ return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
3572
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "beta", children: formatMessage({
3573
+ id: getTranslation("containers.list.autoCloneModal.title"),
3574
+ defaultMessage: "This entry can't be duplicated directly."
3575
+ }) }),
3576
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Box, { marginTop: 2, children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { textColor: "neutral600", children: formatMessage({
3577
+ id: getTranslation("containers.list.autoCloneModal.description"),
3578
+ defaultMessage: "A new entry will be created with the same content, but you'll have to change the following fields to save it."
3579
+ }) }) }),
3580
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Flex, { marginTop: 6, gap: 2, direction: "column", alignItems: "stretch", children: prohibitedFields.map(([fieldPath, reason]) => /* @__PURE__ */ jsxRuntime.jsxs(
3581
+ designSystem.Flex,
3582
+ {
3583
+ direction: "column",
3584
+ gap: 2,
3585
+ alignItems: "flex-start",
3586
+ borderColor: "neutral200",
3587
+ hasRadius: true,
3588
+ padding: 6,
3589
+ children: [
3590
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Flex, { direction: "row", tag: "ol", children: fieldPath.map((pathSegment, index2) => /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Typography, { fontWeight: "semiBold", tag: "li", children: [
3591
+ pathSegment,
3592
+ index2 !== fieldPath.length - 1 && /* @__PURE__ */ jsxRuntime.jsx(
3593
+ Icons.ChevronRight,
3594
+ {
3595
+ fill: "neutral500",
3596
+ height: "0.8rem",
3597
+ width: "0.8rem",
3598
+ style: { margin: "0 0.8rem" }
3599
+ }
3600
+ )
3601
+ ] }, index2)) }),
3602
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { tag: "p", textColor: "neutral600", children: formatMessage({
3603
+ id: getTranslation(`containers.list.autoCloneModal.error.${reason}`),
3604
+ defaultMessage: getDefaultErrorMessage(reason)
3605
+ }) })
3606
+ ]
3607
+ },
3608
+ fieldPath.join()
3609
+ )) })
3610
+ ] });
3611
+ };
3612
+ const TableActions = ({ document }) => {
3613
+ const { formatMessage } = reactIntl.useIntl();
3614
+ const { model, collectionType } = useDoc();
3615
+ const plugins = strapiAdmin.useStrapiApp("TableActions", (state) => state.plugins);
3616
+ const props = {
3617
+ activeTab: null,
3618
+ model,
3619
+ documentId: document.documentId,
3620
+ collectionType,
3621
+ document
3622
+ };
3623
+ return /* @__PURE__ */ jsxRuntime.jsx(
3624
+ strapiAdmin.DescriptionComponentRenderer,
3625
+ {
3626
+ props,
3627
+ descriptions: plugins["content-manager"].apis.getDocumentActions().filter((action) => action.name !== "PublishAction"),
3628
+ children: (actions2) => {
3629
+ const tableRowActions = actions2.filter((action) => {
3630
+ const positions = Array.isArray(action.position) ? action.position : [action.position];
3631
+ return positions.includes("table-row");
3632
+ });
2541
3633
  return /* @__PURE__ */ jsxRuntime.jsx(
2542
3634
  DocumentActionsMenu,
2543
3635
  {
@@ -2591,7 +3683,7 @@ const EditAction = ({ documentId }) => {
2591
3683
  };
2592
3684
  };
2593
3685
  EditAction.type = "edit";
2594
- const StyledPencil = styled__default.default(Icons.Pencil)`
3686
+ const StyledPencil = styledComponents.styled(Icons.Pencil)`
2595
3687
  path {
2596
3688
  fill: currentColor;
2597
3689
  }
@@ -2643,7 +3735,7 @@ const CloneAction = ({ model, documentId }) => {
2643
3735
  }),
2644
3736
  content: /* @__PURE__ */ jsxRuntime.jsx(AutoCloneFailureModalBody, { prohibitedFields }),
2645
3737
  footer: ({ onClose }) => {
2646
- return /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { justifyContent: "space-between", children: [
3738
+ return /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Modal.Footer, { children: [
2647
3739
  /* @__PURE__ */ jsxRuntime.jsx(designSystem.Button, { onClick: onClose, variant: "tertiary", children: formatMessage({
2648
3740
  id: "cancel",
2649
3741
  defaultMessage: "Cancel"
@@ -2651,7 +3743,7 @@ const CloneAction = ({ model, documentId }) => {
2651
3743
  /* @__PURE__ */ jsxRuntime.jsx(
2652
3744
  designSystem.LinkButton,
2653
3745
  {
2654
- as: reactRouterDom.NavLink,
3746
+ tag: reactRouterDom.NavLink,
2655
3747
  to: {
2656
3748
  pathname: `clone/${documentId}`
2657
3749
  },
@@ -2667,7 +3759,7 @@ const CloneAction = ({ model, documentId }) => {
2667
3759
  };
2668
3760
  };
2669
3761
  CloneAction.type = "clone";
2670
- const StyledDuplicate = styled__default.default(Icons.Duplicate)`
3762
+ const StyledDuplicate = styledComponents.styled(Icons.Duplicate)`
2671
3763
  path {
2672
3764
  fill: currentColor;
2673
3765
  }
@@ -2684,442 +3776,183 @@ class ContentManagerPlugin {
2684
3776
  documentActions = [
2685
3777
  ...DEFAULT_ACTIONS,
2686
3778
  ...DEFAULT_TABLE_ROW_ACTIONS,
2687
- ...DEFAULT_HEADER_ACTIONS,
2688
- HistoryAction
3779
+ ...DEFAULT_HEADER_ACTIONS
2689
3780
  ];
2690
3781
  editViewSidePanels = [ActionsPanel];
2691
3782
  headerActions = [];
2692
3783
  constructor() {
2693
3784
  }
2694
3785
  addEditViewSidePanel(panels) {
2695
- if (Array.isArray(panels)) {
2696
- this.editViewSidePanels = [...this.editViewSidePanels, ...panels];
2697
- } else if (typeof panels === "function") {
2698
- this.editViewSidePanels = panels(this.editViewSidePanels);
2699
- } else {
2700
- throw new Error(
2701
- `Expected the \`panels\` passed to \`addEditViewSidePanel\` to be an array or a function, but received ${getPrintableType(
2702
- panels
2703
- )}`
2704
- );
2705
- }
2706
- }
2707
- addDocumentAction(actions2) {
2708
- if (Array.isArray(actions2)) {
2709
- this.documentActions = [...this.documentActions, ...actions2];
2710
- } else if (typeof actions2 === "function") {
2711
- this.documentActions = actions2(this.documentActions);
2712
- } else {
2713
- throw new Error(
2714
- `Expected the \`actions\` passed to \`addDocumentAction\` to be an array or a function, but received ${getPrintableType(
2715
- actions2
2716
- )}`
2717
- );
2718
- }
2719
- }
2720
- addDocumentHeaderAction(actions2) {
2721
- if (Array.isArray(actions2)) {
2722
- this.headerActions = [...this.headerActions, ...actions2];
2723
- } else if (typeof actions2 === "function") {
2724
- this.headerActions = actions2(this.headerActions);
3786
+ if (Array.isArray(panels)) {
3787
+ this.editViewSidePanels = [...this.editViewSidePanels, ...panels];
3788
+ } else if (typeof panels === "function") {
3789
+ this.editViewSidePanels = panels(this.editViewSidePanels);
2725
3790
  } else {
2726
3791
  throw new Error(
2727
- `Expected the \`actions\` passed to \`addDocumentHeaderAction\` to be an array or a function, but received ${getPrintableType(
2728
- actions2
3792
+ `Expected the \`panels\` passed to \`addEditViewSidePanel\` to be an array or a function, but received ${getPrintableType(
3793
+ panels
2729
3794
  )}`
2730
3795
  );
2731
3796
  }
2732
3797
  }
2733
- addBulkAction(actions2) {
3798
+ addDocumentAction(actions2) {
2734
3799
  if (Array.isArray(actions2)) {
2735
- this.bulkActions = [...this.bulkActions, ...actions2];
3800
+ this.documentActions = [...this.documentActions, ...actions2];
2736
3801
  } else if (typeof actions2 === "function") {
2737
- this.bulkActions = actions2(this.bulkActions);
3802
+ this.documentActions = actions2(this.documentActions);
2738
3803
  } else {
2739
3804
  throw new Error(
2740
- `Expected the \`actions\` passed to \`addBulkAction\` to be an array or a function, but received ${getPrintableType(
3805
+ `Expected the \`actions\` passed to \`addDocumentAction\` to be an array or a function, but received ${getPrintableType(
2741
3806
  actions2
2742
- )}`
2743
- );
2744
- }
2745
- }
2746
- get config() {
2747
- return {
2748
- id: PLUGIN_ID,
2749
- name: "Content Manager",
2750
- injectionZones: INJECTION_ZONES,
2751
- apis: {
2752
- addBulkAction: this.addBulkAction.bind(this),
2753
- addDocumentAction: this.addDocumentAction.bind(this),
2754
- addDocumentHeaderAction: this.addDocumentHeaderAction.bind(this),
2755
- addEditViewSidePanel: this.addEditViewSidePanel.bind(this),
2756
- getBulkActions: () => this.bulkActions,
2757
- getDocumentActions: () => this.documentActions,
2758
- getEditViewSidePanels: () => this.editViewSidePanels,
2759
- getHeaderActions: () => this.headerActions
2760
- }
2761
- };
2762
- }
2763
- }
2764
- const getPrintableType = (value) => {
2765
- const nativeType = typeof value;
2766
- if (nativeType === "object") {
2767
- if (value === null)
2768
- return "null";
2769
- if (Array.isArray(value))
2770
- return "array";
2771
- if (value instanceof Object && value.constructor.name !== "Object") {
2772
- return value.constructor.name;
2773
- }
2774
- }
2775
- return nativeType;
2776
- };
2777
- const initialState = {
2778
- collectionTypeLinks: [],
2779
- components: [],
2780
- fieldSizes: {},
2781
- models: [],
2782
- singleTypeLinks: [],
2783
- isLoading: true
2784
- };
2785
- const appSlice = toolkit.createSlice({
2786
- name: "app",
2787
- initialState,
2788
- reducers: {
2789
- setInitialData(state, action) {
2790
- const {
2791
- authorizedCollectionTypeLinks,
2792
- authorizedSingleTypeLinks,
2793
- components,
2794
- contentTypeSchemas,
2795
- fieldSizes
2796
- } = action.payload;
2797
- state.collectionTypeLinks = authorizedCollectionTypeLinks.filter(
2798
- ({ isDisplayed }) => isDisplayed
2799
- );
2800
- state.singleTypeLinks = authorizedSingleTypeLinks.filter(({ isDisplayed }) => isDisplayed);
2801
- state.components = components;
2802
- state.models = contentTypeSchemas;
2803
- state.fieldSizes = fieldSizes;
2804
- state.isLoading = false;
2805
- }
2806
- }
2807
- });
2808
- const { actions, reducer: reducer$1 } = appSlice;
2809
- const { setInitialData } = actions;
2810
- const reducer = toolkit.combineReducers({
2811
- app: reducer$1
2812
- });
2813
- const HOOKS = {
2814
- /**
2815
- * Hook that allows to mutate the displayed headers of the list view table
2816
- * @constant
2817
- * @type {string}
2818
- */
2819
- INJECT_COLUMN_IN_TABLE: "Admin/CM/pages/ListView/inject-column-in-table",
2820
- /**
2821
- * Hook that allows to mutate the CM's collection types links pre-set filters
2822
- * @constant
2823
- * @type {string}
2824
- */
2825
- MUTATE_COLLECTION_TYPES_LINKS: "Admin/CM/pages/App/mutate-collection-types-links",
2826
- /**
2827
- * Hook that allows to mutate the CM's edit view layout
2828
- * @constant
2829
- * @type {string}
2830
- */
2831
- MUTATE_EDIT_VIEW_LAYOUT: "Admin/CM/pages/EditView/mutate-edit-view-layout",
2832
- /**
2833
- * Hook that allows to mutate the CM's single types links pre-set filters
2834
- * @constant
2835
- * @type {string}
2836
- */
2837
- MUTATE_SINGLE_TYPES_LINKS: "Admin/CM/pages/App/mutate-single-types-links"
2838
- };
2839
- const contentTypesApi = contentManagerApi.injectEndpoints({
2840
- endpoints: (builder) => ({
2841
- getContentTypeConfiguration: builder.query({
2842
- query: (uid) => ({
2843
- url: `/content-manager/content-types/${uid}/configuration`,
2844
- method: "GET"
2845
- }),
2846
- transformResponse: (response) => response.data,
2847
- providesTags: (_result, _error, uid) => [
2848
- { type: "ContentTypesConfiguration", id: uid },
2849
- { type: "ContentTypeSettings", id: "LIST" }
2850
- ]
2851
- }),
2852
- getAllContentTypeSettings: builder.query({
2853
- query: () => "/content-manager/content-types-settings",
2854
- transformResponse: (response) => response.data,
2855
- providesTags: [{ type: "ContentTypeSettings", id: "LIST" }]
2856
- }),
2857
- updateContentTypeConfiguration: builder.mutation({
2858
- query: ({ uid, ...body }) => ({
2859
- url: `/content-manager/content-types/${uid}/configuration`,
2860
- method: "PUT",
2861
- data: body
2862
- }),
2863
- transformResponse: (response) => response.data,
2864
- invalidatesTags: (_result, _error, { uid }) => [
2865
- { type: "ContentTypesConfiguration", id: uid },
2866
- { type: "ContentTypeSettings", id: "LIST" },
2867
- // Is this necessary?
2868
- { type: "InitialData" }
2869
- ]
2870
- })
2871
- })
2872
- });
2873
- const {
2874
- useGetContentTypeConfigurationQuery,
2875
- useGetAllContentTypeSettingsQuery,
2876
- useUpdateContentTypeConfigurationMutation
2877
- } = contentTypesApi;
2878
- const checkIfAttributeIsDisplayable = (attribute) => {
2879
- const { type } = attribute;
2880
- if (type === "relation") {
2881
- return !attribute.relation.toLowerCase().includes("morph");
2882
- }
2883
- return !["json", "dynamiczone", "richtext", "password", "blocks"].includes(type) && !!type;
2884
- };
2885
- const getMainField = (attribute, mainFieldName, { schemas, components }) => {
2886
- if (!mainFieldName) {
2887
- return void 0;
2888
- }
2889
- const mainFieldType = attribute.type === "component" ? components[attribute.component].attributes[mainFieldName].type : (
2890
- // @ts-expect-error – `targetModel` does exist on the attribute for a relation.
2891
- schemas.find((schema) => schema.uid === attribute.targetModel)?.attributes[mainFieldName].type
2892
- );
2893
- return {
2894
- name: mainFieldName,
2895
- type: mainFieldType ?? "string"
2896
- };
2897
- };
2898
- const DEFAULT_SETTINGS = {
2899
- bulkable: false,
2900
- filterable: false,
2901
- searchable: false,
2902
- pagination: false,
2903
- defaultSortBy: "",
2904
- defaultSortOrder: "asc",
2905
- mainField: "id",
2906
- pageSize: 10
2907
- };
2908
- const useDocumentLayout = (model) => {
2909
- const { schema, components } = useDocument({ model, collectionType: "" }, { skip: true });
2910
- const [{ query }] = strapiAdmin.useQueryParams();
2911
- const runHookWaterfall = strapiAdmin.useStrapiApp("useDocumentLayout", (state) => state.runHookWaterfall);
2912
- const { toggleNotification } = strapiAdmin.useNotification();
2913
- const { _unstableFormatAPIError: formatAPIError } = strapiAdmin.useAPIErrorHandler();
2914
- const { isLoading: isLoadingSchemas, schemas } = useContentTypeSchema();
2915
- const {
2916
- data,
2917
- isLoading: isLoadingConfigs,
2918
- error,
2919
- isFetching: isFetchingConfigs
2920
- } = useGetContentTypeConfigurationQuery(model);
2921
- const isLoading = isLoadingSchemas || isFetchingConfigs || isLoadingConfigs;
2922
- React__namespace.useEffect(() => {
2923
- if (error) {
2924
- toggleNotification({
2925
- type: "danger",
2926
- message: formatAPIError(error)
2927
- });
2928
- }
2929
- }, [error, formatAPIError, toggleNotification]);
2930
- const editLayout = React__namespace.useMemo(
2931
- () => data && !isLoading ? formatEditLayout(data, { schemas, schema, components }) : {
2932
- layout: [],
2933
- components: {},
2934
- metadatas: {},
2935
- options: {},
2936
- settings: DEFAULT_SETTINGS
2937
- },
2938
- [data, isLoading, schemas, schema, components]
2939
- );
2940
- const listLayout = React__namespace.useMemo(() => {
2941
- return data && !isLoading ? formatListLayout(data, { schemas, schema, components }) : {
2942
- layout: [],
2943
- metadatas: {},
2944
- options: {},
2945
- settings: DEFAULT_SETTINGS
2946
- };
2947
- }, [data, isLoading, schemas, schema, components]);
2948
- const { layout: edit } = React__namespace.useMemo(
2949
- () => runHookWaterfall(HOOKS.MUTATE_EDIT_VIEW_LAYOUT, {
2950
- layout: editLayout,
2951
- query
2952
- }),
2953
- [editLayout, query, runHookWaterfall]
2954
- );
2955
- return {
2956
- error,
2957
- isLoading,
2958
- edit,
2959
- list: listLayout
2960
- };
2961
- };
2962
- const useDocLayout = () => {
2963
- const { model } = useDoc();
2964
- return useDocumentLayout(model);
2965
- };
2966
- const formatEditLayout = (data, {
2967
- schemas,
2968
- schema,
2969
- components
2970
- }) => {
2971
- let currentPanelIndex = 0;
2972
- const panelledEditAttributes = convertEditLayoutToFieldLayouts(
2973
- data.contentType.layouts.edit,
2974
- schema?.attributes,
2975
- data.contentType.metadatas,
2976
- { configurations: data.components, schemas: components },
2977
- schemas
2978
- ).reduce((panels, row) => {
2979
- if (row.some((field) => field.type === "dynamiczone")) {
2980
- panels.push([row]);
2981
- currentPanelIndex += 2;
3807
+ )}`
3808
+ );
3809
+ }
3810
+ }
3811
+ addDocumentHeaderAction(actions2) {
3812
+ if (Array.isArray(actions2)) {
3813
+ this.headerActions = [...this.headerActions, ...actions2];
3814
+ } else if (typeof actions2 === "function") {
3815
+ this.headerActions = actions2(this.headerActions);
2982
3816
  } else {
2983
- if (!panels[currentPanelIndex]) {
2984
- panels.push([]);
2985
- }
2986
- panels[currentPanelIndex].push(row);
3817
+ throw new Error(
3818
+ `Expected the \`actions\` passed to \`addDocumentHeaderAction\` to be an array or a function, but received ${getPrintableType(
3819
+ actions2
3820
+ )}`
3821
+ );
2987
3822
  }
2988
- return panels;
2989
- }, []);
2990
- const componentEditAttributes = Object.entries(data.components).reduce(
2991
- (acc, [uid, configuration]) => {
2992
- acc[uid] = {
2993
- layout: convertEditLayoutToFieldLayouts(
2994
- configuration.layouts.edit,
2995
- components[uid].attributes,
2996
- configuration.metadatas
2997
- ),
2998
- settings: {
2999
- ...configuration.settings,
3000
- icon: components[uid].info.icon,
3001
- displayName: components[uid].info.displayName
3002
- }
3003
- };
3004
- return acc;
3005
- },
3006
- {}
3007
- );
3008
- const editMetadatas = Object.entries(data.contentType.metadatas).reduce(
3009
- (acc, [attribute, metadata]) => {
3010
- return {
3011
- ...acc,
3012
- [attribute]: metadata.edit
3013
- };
3014
- },
3015
- {}
3016
- );
3017
- return {
3018
- layout: panelledEditAttributes,
3019
- components: componentEditAttributes,
3020
- metadatas: editMetadatas,
3021
- settings: {
3022
- ...data.contentType.settings,
3023
- displayName: schema?.info.displayName
3024
- },
3025
- options: {
3026
- ...schema?.options,
3027
- ...schema?.pluginOptions,
3028
- ...data.contentType.options
3823
+ }
3824
+ addBulkAction(actions2) {
3825
+ if (Array.isArray(actions2)) {
3826
+ this.bulkActions = [...this.bulkActions, ...actions2];
3827
+ } else if (typeof actions2 === "function") {
3828
+ this.bulkActions = actions2(this.bulkActions);
3829
+ } else {
3830
+ throw new Error(
3831
+ `Expected the \`actions\` passed to \`addBulkAction\` to be an array or a function, but received ${getPrintableType(
3832
+ actions2
3833
+ )}`
3834
+ );
3029
3835
  }
3030
- };
3031
- };
3032
- const convertEditLayoutToFieldLayouts = (rows, attributes = {}, metadatas, components, schemas = []) => {
3033
- return rows.map(
3034
- (row) => row.map((field) => {
3035
- const attribute = attributes[field.name];
3036
- if (!attribute) {
3037
- return null;
3836
+ }
3837
+ get config() {
3838
+ return {
3839
+ id: PLUGIN_ID,
3840
+ name: "Content Manager",
3841
+ injectionZones: INJECTION_ZONES,
3842
+ apis: {
3843
+ addBulkAction: this.addBulkAction.bind(this),
3844
+ addDocumentAction: this.addDocumentAction.bind(this),
3845
+ addDocumentHeaderAction: this.addDocumentHeaderAction.bind(this),
3846
+ addEditViewSidePanel: this.addEditViewSidePanel.bind(this),
3847
+ getBulkActions: () => this.bulkActions,
3848
+ getDocumentActions: () => this.documentActions,
3849
+ getEditViewSidePanels: () => this.editViewSidePanels,
3850
+ getHeaderActions: () => this.headerActions
3038
3851
  }
3039
- const { edit: metadata } = metadatas[field.name];
3040
- const settings = attribute.type === "component" && components ? components.configurations[attribute.component].settings : {};
3041
- return {
3042
- attribute,
3043
- disabled: !metadata.editable,
3044
- hint: metadata.description,
3045
- label: metadata.label ?? "",
3046
- name: field.name,
3047
- // @ts-expect-error – mainField does exist on the metadata for a relation.
3048
- mainField: getMainField(attribute, metadata.mainField || settings.mainField, {
3049
- schemas,
3050
- components: components?.schemas ?? {}
3051
- }),
3052
- placeholder: metadata.placeholder ?? "",
3053
- required: attribute.required ?? false,
3054
- size: field.size,
3055
- unique: "unique" in attribute ? attribute.unique : false,
3056
- visible: metadata.visible ?? true,
3057
- type: attribute.type
3058
- };
3059
- }).filter((field) => field !== null)
3060
- );
3852
+ };
3853
+ }
3854
+ }
3855
+ const getPrintableType = (value) => {
3856
+ const nativeType = typeof value;
3857
+ if (nativeType === "object") {
3858
+ if (value === null)
3859
+ return "null";
3860
+ if (Array.isArray(value))
3861
+ return "array";
3862
+ if (value instanceof Object && value.constructor.name !== "Object") {
3863
+ return value.constructor.name;
3864
+ }
3865
+ }
3866
+ return nativeType;
3061
3867
  };
3062
- const formatListLayout = (data, {
3063
- schemas,
3064
- schema,
3065
- components
3066
- }) => {
3067
- const listMetadatas = Object.entries(data.contentType.metadatas).reduce(
3068
- (acc, [attribute, metadata]) => {
3069
- return {
3070
- ...acc,
3071
- [attribute]: metadata.list
3072
- };
3073
- },
3074
- {}
3075
- );
3076
- const listAttributes = convertListLayoutToFieldLayouts(
3077
- data.contentType.layouts.list,
3078
- schema?.attributes,
3079
- listMetadatas,
3080
- { configurations: data.components, schemas: components },
3081
- schemas
3082
- );
3868
+ const HistoryAction = ({ model, document }) => {
3869
+ const { formatMessage } = reactIntl.useIntl();
3870
+ const [{ query }] = strapiAdmin.useQueryParams();
3871
+ const navigate = reactRouterDom.useNavigate();
3872
+ const pluginsQueryParams = qs.stringify({ plugins: query.plugins }, { encode: false });
3873
+ if (!window.strapi.features.isEnabled("cms-content-history")) {
3874
+ return null;
3875
+ }
3083
3876
  return {
3084
- layout: listAttributes,
3085
- settings: { ...data.contentType.settings, displayName: schema?.info.displayName },
3086
- metadatas: listMetadatas,
3087
- options: {
3088
- ...schema?.options,
3089
- ...schema?.pluginOptions,
3090
- ...data.contentType.options
3091
- }
3877
+ icon: /* @__PURE__ */ jsxRuntime.jsx(Icons.ClockCounterClockwise, {}),
3878
+ label: formatMessage({
3879
+ id: "content-manager.history.document-action",
3880
+ defaultMessage: "Content History"
3881
+ }),
3882
+ onClick: () => navigate({ pathname: "history", search: pluginsQueryParams }),
3883
+ disabled: (
3884
+ /**
3885
+ * The user is creating a new document.
3886
+ * It hasn't been saved yet, so there's no history to go to
3887
+ */
3888
+ !document || /**
3889
+ * The document has been created but the current dimension has never been saved.
3890
+ * For example, the user is creating a new locale in an existing document,
3891
+ * so there's no history for the document in that locale
3892
+ */
3893
+ !document.id || /**
3894
+ * History is only available for content types created by the user.
3895
+ * These have the `api::` prefix, as opposed to the ones created by Strapi or plugins,
3896
+ * which start with `admin::` or `plugin::`
3897
+ */
3898
+ !model.startsWith("api::")
3899
+ ),
3900
+ position: "header"
3092
3901
  };
3093
3902
  };
3094
- const convertListLayoutToFieldLayouts = (columns, attributes = {}, metadatas, components, schemas = []) => {
3095
- return columns.map((name) => {
3096
- const attribute = attributes[name];
3097
- if (!attribute) {
3098
- return null;
3099
- }
3100
- const metadata = metadatas[name];
3101
- const settings = attribute.type === "component" && components ? components.configurations[attribute.component].settings : {};
3102
- return {
3103
- attribute,
3104
- label: metadata.label ?? "",
3105
- mainField: getMainField(attribute, metadata.mainField || settings.mainField, {
3106
- schemas,
3107
- components: components?.schemas ?? {}
3108
- }),
3109
- name,
3110
- searchable: metadata.searchable ?? true,
3111
- sortable: metadata.sortable ?? true
3112
- };
3113
- }).filter((field) => field !== null);
3903
+ HistoryAction.type = "history";
3904
+ const historyAdmin = {
3905
+ bootstrap(app) {
3906
+ const { addDocumentAction } = app.getPlugin("content-manager").apis;
3907
+ addDocumentAction((actions2) => {
3908
+ const indexOfDeleteAction = actions2.findIndex((action) => action.type === "delete");
3909
+ actions2.splice(indexOfDeleteAction, 0, HistoryAction);
3910
+ return actions2;
3911
+ });
3912
+ }
3913
+ };
3914
+ const initialState = {
3915
+ collectionTypeLinks: [],
3916
+ components: [],
3917
+ fieldSizes: {},
3918
+ models: [],
3919
+ singleTypeLinks: [],
3920
+ isLoading: true
3114
3921
  };
3922
+ const appSlice = toolkit.createSlice({
3923
+ name: "app",
3924
+ initialState,
3925
+ reducers: {
3926
+ setInitialData(state, action) {
3927
+ const {
3928
+ authorizedCollectionTypeLinks,
3929
+ authorizedSingleTypeLinks,
3930
+ components,
3931
+ contentTypeSchemas,
3932
+ fieldSizes
3933
+ } = action.payload;
3934
+ state.collectionTypeLinks = authorizedCollectionTypeLinks.filter(
3935
+ ({ isDisplayed }) => isDisplayed
3936
+ );
3937
+ state.singleTypeLinks = authorizedSingleTypeLinks.filter(({ isDisplayed }) => isDisplayed);
3938
+ state.components = components;
3939
+ state.models = contentTypeSchemas;
3940
+ state.fieldSizes = fieldSizes;
3941
+ state.isLoading = false;
3942
+ }
3943
+ }
3944
+ });
3945
+ const { actions, reducer: reducer$1 } = appSlice;
3946
+ const { setInitialData } = actions;
3947
+ const reducer = toolkit.combineReducers({
3948
+ app: reducer$1
3949
+ });
3115
3950
  const index = {
3116
3951
  register(app) {
3117
3952
  const cm = new ContentManagerPlugin();
3118
3953
  app.addReducers({
3119
- [contentManagerApi.reducerPath]: contentManagerApi.reducer,
3120
3954
  [PLUGIN_ID]: reducer
3121
3955
  });
3122
- app.addMiddlewares([() => contentManagerApi.middleware]);
3123
3956
  app.addMenuLink({
3124
3957
  to: PLUGIN_ID,
3125
3958
  icon: Icons.Feather,
@@ -3128,14 +3961,29 @@ const index = {
3128
3961
  defaultMessage: "Content Manager"
3129
3962
  },
3130
3963
  permissions: [],
3131
- Component: () => Promise.resolve().then(() => require("./layout-B_SXLhqf.js")).then((mod) => ({ default: mod.Layout }))
3964
+ position: 1
3965
+ });
3966
+ app.router.addRoute({
3967
+ path: "content-manager/*",
3968
+ lazy: async () => {
3969
+ const { Layout } = await Promise.resolve().then(() => require("./layout-CYA7s0qO.js"));
3970
+ return {
3971
+ Component: Layout
3972
+ };
3973
+ },
3974
+ children: routes
3132
3975
  });
3133
3976
  app.registerPlugin(cm.config);
3134
3977
  },
3978
+ bootstrap(app) {
3979
+ if (typeof historyAdmin.bootstrap === "function") {
3980
+ historyAdmin.bootstrap(app);
3981
+ }
3982
+ },
3135
3983
  async registerTrads({ locales }) {
3136
3984
  const importedTrads = await Promise.all(
3137
3985
  locales.map((locale) => {
3138
- return __variableDynamicImportRuntimeHelper(/* @__PURE__ */ Object.assign({ "./translations/ar.json": () => Promise.resolve().then(() => require("./ar-BUUWXIYu.js")), "./translations/ca.json": () => Promise.resolve().then(() => require("./ca-Cmk45QO6.js")), "./translations/cs.json": () => Promise.resolve().then(() => require("./cs-CkJy6B2v.js")), "./translations/de.json": () => Promise.resolve().then(() => require("./de-CCEmbAah.js")), "./translations/en.json": () => Promise.resolve().then(() => require("./en-C-V1_90f.js")), "./translations/es.json": () => Promise.resolve().then(() => require("./es-EUonQTon.js")), "./translations/eu.json": () => Promise.resolve().then(() => require("./eu-VDH-3ovk.js")), "./translations/fr.json": () => Promise.resolve().then(() => require("./fr-B7kGGg3E.js")), "./translations/gu.json": () => Promise.resolve().then(() => require("./gu-BRmF601H.js")), "./translations/hi.json": () => Promise.resolve().then(() => require("./hi-CCJBptSq.js")), "./translations/hu.json": () => Promise.resolve().then(() => require("./hu-sNV_yLYy.js")), "./translations/id.json": () => Promise.resolve().then(() => require("./id-B5Ser98A.js")), "./translations/it.json": () => Promise.resolve().then(() => require("./it-DkBIs7vD.js")), "./translations/ja.json": () => Promise.resolve().then(() => require("./ja-CcFe8diO.js")), "./translations/ko.json": () => Promise.resolve().then(() => require("./ko-woFZPmLk.js")), "./translations/ml.json": () => Promise.resolve().then(() => require("./ml-C2W8N8k1.js")), "./translations/ms.json": () => Promise.resolve().then(() => require("./ms-BuFotyP_.js")), "./translations/nl.json": () => Promise.resolve().then(() => require("./nl-bbEOHChV.js")), "./translations/pl.json": () => Promise.resolve().then(() => require("./pl-uzwG-hk7.js")), "./translations/pt-BR.json": () => Promise.resolve().then(() => require("./pt-BR-BiOz37D9.js")), "./translations/pt.json": () => Promise.resolve().then(() => require("./pt-CeXQuq50.js")), "./translations/ru.json": () => Promise.resolve().then(() => require("./ru-BT3ybNny.js")), "./translations/sa.json": () => Promise.resolve().then(() => require("./sa-CcvkYInH.js")), "./translations/sk.json": () => Promise.resolve().then(() => require("./sk-CvY09Xjv.js")), "./translations/sv.json": () => Promise.resolve().then(() => require("./sv-MYDuzgvT.js")), "./translations/th.json": () => Promise.resolve().then(() => require("./th-D9_GfAjc.js")), "./translations/tr.json": () => Promise.resolve().then(() => require("./tr-D9UH-O_R.js")), "./translations/uk.json": () => Promise.resolve().then(() => require("./uk-C8EiqJY7.js")), "./translations/vi.json": () => Promise.resolve().then(() => require("./vi-CJlYDheJ.js")), "./translations/zh-Hans.json": () => Promise.resolve().then(() => require("./zh-Hans-9kOncHGw.js")), "./translations/zh.json": () => Promise.resolve().then(() => require("./zh-CQQfszqR.js")) }), `./translations/${locale}.json`).then(({ default: data }) => {
3986
+ return __variableDynamicImportRuntimeHelper(/* @__PURE__ */ Object.assign({ "./translations/ar.json": () => Promise.resolve().then(() => require("./ar-BUUWXIYu.js")), "./translations/ca.json": () => Promise.resolve().then(() => require("./ca-Cmk45QO6.js")), "./translations/cs.json": () => Promise.resolve().then(() => require("./cs-CkJy6B2v.js")), "./translations/de.json": () => Promise.resolve().then(() => require("./de-CCEmbAah.js")), "./translations/en.json": () => Promise.resolve().then(() => require("./en-BVzUkPxZ.js")), "./translations/es.json": () => Promise.resolve().then(() => require("./es-EUonQTon.js")), "./translations/eu.json": () => Promise.resolve().then(() => require("./eu-VDH-3ovk.js")), "./translations/fr.json": () => Promise.resolve().then(() => require("./fr-B7kGGg3E.js")), "./translations/gu.json": () => Promise.resolve().then(() => require("./gu-BRmF601H.js")), "./translations/hi.json": () => Promise.resolve().then(() => require("./hi-CCJBptSq.js")), "./translations/hu.json": () => Promise.resolve().then(() => require("./hu-sNV_yLYy.js")), "./translations/id.json": () => Promise.resolve().then(() => require("./id-B5Ser98A.js")), "./translations/it.json": () => Promise.resolve().then(() => require("./it-DkBIs7vD.js")), "./translations/ja.json": () => Promise.resolve().then(() => require("./ja-CcFe8diO.js")), "./translations/ko.json": () => Promise.resolve().then(() => require("./ko-woFZPmLk.js")), "./translations/ml.json": () => Promise.resolve().then(() => require("./ml-C2W8N8k1.js")), "./translations/ms.json": () => Promise.resolve().then(() => require("./ms-BuFotyP_.js")), "./translations/nl.json": () => Promise.resolve().then(() => require("./nl-bbEOHChV.js")), "./translations/pl.json": () => Promise.resolve().then(() => require("./pl-uzwG-hk7.js")), "./translations/pt-BR.json": () => Promise.resolve().then(() => require("./pt-BR-BiOz37D9.js")), "./translations/pt.json": () => Promise.resolve().then(() => require("./pt-CeXQuq50.js")), "./translations/ru.json": () => Promise.resolve().then(() => require("./ru-BT3ybNny.js")), "./translations/sa.json": () => Promise.resolve().then(() => require("./sa-CcvkYInH.js")), "./translations/sk.json": () => Promise.resolve().then(() => require("./sk-CvY09Xjv.js")), "./translations/sv.json": () => Promise.resolve().then(() => require("./sv-MYDuzgvT.js")), "./translations/th.json": () => Promise.resolve().then(() => require("./th-D9_GfAjc.js")), "./translations/tr.json": () => Promise.resolve().then(() => require("./tr-D9UH-O_R.js")), "./translations/uk.json": () => Promise.resolve().then(() => require("./uk-C8EiqJY7.js")), "./translations/vi.json": () => Promise.resolve().then(() => require("./vi-CJlYDheJ.js")), "./translations/zh-Hans.json": () => Promise.resolve().then(() => require("./zh-Hans-9kOncHGw.js")), "./translations/zh.json": () => Promise.resolve().then(() => require("./zh-CQQfszqR.js")) }), `./translations/${locale}.json`).then(({ default: data }) => {
3139
3987
  return {
3140
3988
  data: prefixPluginTranslations(data, PLUGIN_ID),
3141
3989
  locale
@@ -3152,6 +4000,8 @@ const index = {
3152
4000
  }
3153
4001
  };
3154
4002
  exports.ATTRIBUTE_TYPES_THAT_CANNOT_BE_MAIN_FIELD = ATTRIBUTE_TYPES_THAT_CANNOT_BE_MAIN_FIELD;
4003
+ exports.BulkActionsRenderer = BulkActionsRenderer;
4004
+ exports.CLONE_PATH = CLONE_PATH;
3155
4005
  exports.COLLECTION_TYPES = COLLECTION_TYPES;
3156
4006
  exports.CREATOR_FIELDS = CREATOR_FIELDS;
3157
4007
  exports.DEFAULT_SETTINGS = DEFAULT_SETTINGS;
@@ -3178,7 +4028,6 @@ exports.getDisplayName = getDisplayName;
3178
4028
  exports.getMainField = getMainField;
3179
4029
  exports.getTranslation = getTranslation;
3180
4030
  exports.index = index;
3181
- exports.routes = routes;
3182
4031
  exports.setInitialData = setInitialData;
3183
4032
  exports.useContentTypeSchema = useContentTypeSchema;
3184
4033
  exports.useDoc = useDoc;
@@ -3192,4 +4041,4 @@ exports.useGetAllDocumentsQuery = useGetAllDocumentsQuery;
3192
4041
  exports.useGetContentTypeConfigurationQuery = useGetContentTypeConfigurationQuery;
3193
4042
  exports.useGetInitialDataQuery = useGetInitialDataQuery;
3194
4043
  exports.useUpdateContentTypeConfigurationMutation = useUpdateContentTypeConfigurationMutation;
3195
- //# sourceMappingURL=index-C6AH2hEl.js.map
4044
+ //# sourceMappingURL=index-BhbLFX4l.js.map