@strapi/content-manager 0.0.0-experimental.a65a85fdea97faae8679d3ffc5f9d79af61abd26 → 0.0.0-experimental.a6728ad43ac70ae19dabb624dbfca1f2d9610a86

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 (189) 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--2aLCv-G.mjs → ComponentConfigurationPage-DJ5voqEK.mjs} +3 -3
  7. package/dist/_chunks/{ComponentConfigurationPage--2aLCv-G.mjs.map → ComponentConfigurationPage-DJ5voqEK.mjs.map} +1 -1
  8. package/dist/_chunks/{ComponentConfigurationPage-43KmCNQE.js → ComponentConfigurationPage-_6osrv39.js} +3 -3
  9. package/dist/_chunks/{ComponentConfigurationPage-43KmCNQE.js.map → ComponentConfigurationPage-_6osrv39.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-CUcGHHvQ.mjs → EditConfigurationPage-CZofxSLy.mjs} +3 -3
  15. package/dist/_chunks/{EditConfigurationPage-CUcGHHvQ.mjs.map → EditConfigurationPage-CZofxSLy.mjs.map} +1 -1
  16. package/dist/_chunks/{EditConfigurationPage-BfFzJ4Br.js → EditConfigurationPage-ZN3s568V.js} +3 -3
  17. package/dist/_chunks/{EditConfigurationPage-BfFzJ4Br.js.map → EditConfigurationPage-ZN3s568V.js.map} +1 -1
  18. package/dist/_chunks/{EditViewPage-CzOT5Kpj.js → EditViewPage-Co2IKQZH.js} +58 -49
  19. package/dist/_chunks/EditViewPage-Co2IKQZH.js.map +1 -0
  20. package/dist/_chunks/{EditViewPage-Bm8lgcm6.mjs → EditViewPage-HYljoEY7.mjs} +59 -48
  21. package/dist/_chunks/EditViewPage-HYljoEY7.mjs.map +1 -0
  22. package/dist/_chunks/{Field-Dlh0uGnL.mjs → Field-BOPUMZ1u.mjs} +995 -795
  23. package/dist/_chunks/Field-BOPUMZ1u.mjs.map +1 -0
  24. package/dist/_chunks/{Field-Caef4JjM.js → Field-G9CkFUtP.js} +1041 -842
  25. package/dist/_chunks/Field-G9CkFUtP.js.map +1 -0
  26. package/dist/_chunks/{Form-EnaQL_6L.mjs → Form-CDwNp7pU.mjs} +69 -48
  27. package/dist/_chunks/Form-CDwNp7pU.mjs.map +1 -0
  28. package/dist/_chunks/{Form-BzuAjtRq.js → Form-crsbkGxI.js} +68 -48
  29. package/dist/_chunks/Form-crsbkGxI.js.map +1 -0
  30. package/dist/_chunks/{History-D6sbCJvo.mjs → History-BDZrgfZ3.mjs} +151 -57
  31. package/dist/_chunks/History-BDZrgfZ3.mjs.map +1 -0
  32. package/dist/_chunks/{History-C17LiyRg.js → History-CWcM9HnW.js} +151 -58
  33. package/dist/_chunks/History-CWcM9HnW.js.map +1 -0
  34. package/dist/_chunks/{ListConfigurationPage-Ce4qs7qE.mjs → ListConfigurationPage-BZ3ScUna.mjs} +67 -57
  35. package/dist/_chunks/ListConfigurationPage-BZ3ScUna.mjs.map +1 -0
  36. package/dist/_chunks/{ListConfigurationPage-Dks5SX6f.js → ListConfigurationPage-DGzoQD_I.js} +70 -61
  37. package/dist/_chunks/ListConfigurationPage-DGzoQD_I.js.map +1 -0
  38. package/dist/_chunks/{ListViewPage-BwrZrPsh.js → ListViewPage-BBAC9aPu.js} +132 -139
  39. package/dist/_chunks/ListViewPage-BBAC9aPu.js.map +1 -0
  40. package/dist/_chunks/{ListViewPage-Be7S5aKL.mjs → ListViewPage-CsX7tWx-.mjs} +129 -136
  41. package/dist/_chunks/ListViewPage-CsX7tWx-.mjs.map +1 -0
  42. package/dist/_chunks/{NoContentTypePage-Cu5r1-JT.js → NoContentTypePage-CwVDx_YC.js} +5 -5
  43. package/dist/_chunks/NoContentTypePage-CwVDx_YC.js.map +1 -0
  44. package/dist/_chunks/{NoContentTypePage-CIPmYQMm.mjs → NoContentTypePage-LClTUPWs.mjs} +7 -7
  45. package/dist/_chunks/NoContentTypePage-LClTUPWs.mjs.map +1 -0
  46. package/dist/_chunks/{NoPermissionsPage-C-j6TEUF.js → NoPermissionsPage-D2iWw-sn.js} +4 -5
  47. package/dist/_chunks/NoPermissionsPage-D2iWw-sn.js.map +1 -0
  48. package/dist/_chunks/{NoPermissionsPage-DhJ7LYrr.mjs → NoPermissionsPage-S4Re3FwO.mjs} +5 -6
  49. package/dist/_chunks/NoPermissionsPage-S4Re3FwO.mjs.map +1 -0
  50. package/dist/_chunks/{Relations-CY7AtkDA.mjs → Relations-Dmv0Tpe5.mjs} +67 -57
  51. package/dist/_chunks/Relations-Dmv0Tpe5.mjs.map +1 -0
  52. package/dist/_chunks/{Relations-Czs-uZ-s.js → Relations-jwuTFGOV.js} +71 -62
  53. package/dist/_chunks/Relations-jwuTFGOV.js.map +1 -0
  54. package/dist/_chunks/{en-C-V1_90f.js → en-BlhnxQfj.js} +17 -9
  55. package/dist/_chunks/{en-C-V1_90f.js.map → en-BlhnxQfj.js.map} +1 -1
  56. package/dist/_chunks/{en-MBPul9Su.mjs → en-C8YBvRrK.mjs} +17 -9
  57. package/dist/_chunks/{en-MBPul9Su.mjs.map → en-C8YBvRrK.mjs.map} +1 -1
  58. package/dist/_chunks/{index-DNVx8ssZ.mjs → index-BmUAydCA.mjs} +1715 -813
  59. package/dist/_chunks/index-BmUAydCA.mjs.map +1 -0
  60. package/dist/_chunks/{index-X_2tafck.js → index-CBX6KyXv.js} +1815 -914
  61. package/dist/_chunks/index-CBX6KyXv.js.map +1 -0
  62. package/dist/_chunks/{layout-Dnh0PNp9.mjs → layout-ClP-DC72.mjs} +47 -29
  63. package/dist/_chunks/layout-ClP-DC72.mjs.map +1 -0
  64. package/dist/_chunks/{layout-dBc7wN7L.js → layout-CxxkX9jY.js} +47 -31
  65. package/dist/_chunks/layout-CxxkX9jY.js.map +1 -0
  66. package/dist/_chunks/{relations-4pHtBrHJ.js → relations-DIjTADIu.js} +2 -2
  67. package/dist/_chunks/{relations-4pHtBrHJ.js.map → relations-DIjTADIu.js.map} +1 -1
  68. package/dist/_chunks/{relations-Dx7tMKJN.mjs → relations-op89RClB.mjs} +2 -2
  69. package/dist/_chunks/{relations-Dx7tMKJN.mjs.map → relations-op89RClB.mjs.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 +3 -1
  77. package/dist/admin/index.js.map +1 -1
  78. package/dist/admin/index.mjs +9 -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 +2 -1
  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 +35 -9
  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 +648 -447
  118. package/dist/server/index.js.map +1 -1
  119. package/dist/server/index.mjs +656 -455
  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 +2 -4
  131. package/dist/server/src/history/services/history.d.ts.map +1 -1
  132. package/dist/server/src/history/services/index.d.ts +6 -2
  133. package/dist/server/src/history/services/index.d.ts.map +1 -1
  134. package/dist/server/src/history/services/lifecycles.d.ts +9 -0
  135. package/dist/server/src/history/services/lifecycles.d.ts.map +1 -0
  136. package/dist/server/src/history/services/utils.d.ts +42 -9
  137. package/dist/server/src/history/services/utils.d.ts.map +1 -1
  138. package/dist/server/src/history/utils.d.ts +6 -2
  139. package/dist/server/src/history/utils.d.ts.map +1 -1
  140. package/dist/server/src/index.d.ts +18 -39
  141. package/dist/server/src/index.d.ts.map +1 -1
  142. package/dist/server/src/policies/hasPermissions.d.ts.map +1 -1
  143. package/dist/server/src/services/document-manager.d.ts +13 -12
  144. package/dist/server/src/services/document-manager.d.ts.map +1 -1
  145. package/dist/server/src/services/document-metadata.d.ts +8 -29
  146. package/dist/server/src/services/document-metadata.d.ts.map +1 -1
  147. package/dist/server/src/services/index.d.ts +18 -39
  148. package/dist/server/src/services/index.d.ts.map +1 -1
  149. package/dist/server/src/services/permission-checker.d.ts.map +1 -1
  150. package/dist/server/src/services/utils/populate.d.ts +8 -1
  151. package/dist/server/src/services/utils/populate.d.ts.map +1 -1
  152. package/dist/shared/contracts/collection-types.d.ts +17 -7
  153. package/dist/shared/contracts/collection-types.d.ts.map +1 -1
  154. package/dist/shared/contracts/relations.d.ts +2 -2
  155. package/dist/shared/contracts/relations.d.ts.map +1 -1
  156. package/package.json +16 -17
  157. package/dist/_chunks/CardDragPreview-DSVYodBX.js.map +0 -1
  158. package/dist/_chunks/CardDragPreview-ikSG4M46.mjs.map +0 -1
  159. package/dist/_chunks/ComponentIcon-BBQsYCVn.js.map +0 -1
  160. package/dist/_chunks/ComponentIcon-BOFnK76n.mjs.map +0 -1
  161. package/dist/_chunks/EditViewPage-Bm8lgcm6.mjs.map +0 -1
  162. package/dist/_chunks/EditViewPage-CzOT5Kpj.js.map +0 -1
  163. package/dist/_chunks/Field-Caef4JjM.js.map +0 -1
  164. package/dist/_chunks/Field-Dlh0uGnL.mjs.map +0 -1
  165. package/dist/_chunks/Form-BzuAjtRq.js.map +0 -1
  166. package/dist/_chunks/Form-EnaQL_6L.mjs.map +0 -1
  167. package/dist/_chunks/History-C17LiyRg.js.map +0 -1
  168. package/dist/_chunks/History-D6sbCJvo.mjs.map +0 -1
  169. package/dist/_chunks/ListConfigurationPage-Ce4qs7qE.mjs.map +0 -1
  170. package/dist/_chunks/ListConfigurationPage-Dks5SX6f.js.map +0 -1
  171. package/dist/_chunks/ListViewPage-Be7S5aKL.mjs.map +0 -1
  172. package/dist/_chunks/ListViewPage-BwrZrPsh.js.map +0 -1
  173. package/dist/_chunks/NoContentTypePage-CIPmYQMm.mjs.map +0 -1
  174. package/dist/_chunks/NoContentTypePage-Cu5r1-JT.js.map +0 -1
  175. package/dist/_chunks/NoPermissionsPage-C-j6TEUF.js.map +0 -1
  176. package/dist/_chunks/NoPermissionsPage-DhJ7LYrr.mjs.map +0 -1
  177. package/dist/_chunks/Relations-CY7AtkDA.mjs.map +0 -1
  178. package/dist/_chunks/Relations-Czs-uZ-s.js.map +0 -1
  179. package/dist/_chunks/index-DNVx8ssZ.mjs.map +0 -1
  180. package/dist/_chunks/index-X_2tafck.js.map +0 -1
  181. package/dist/_chunks/layout-Dnh0PNp9.mjs.map +0 -1
  182. package/dist/_chunks/layout-dBc7wN7L.js.map +0 -1
  183. package/dist/_chunks/urls-CbOsUOoW.mjs +0 -7
  184. package/dist/_chunks/urls-CbOsUOoW.mjs.map +0 -1
  185. package/dist/_chunks/urls-DzZya_gm.js +0 -6
  186. package/dist/_chunks/urls-DzZya_gm.js.map +0 -1
  187. package/dist/server/src/controllers/utils/dimensions.d.ts +0 -5
  188. package/dist/server/src/controllers/utils/dimensions.d.ts.map +0 -1
  189. package/strapi-server.js +0 -3
@@ -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({
@@ -826,83 +810,434 @@ const extractContentTypeComponents = (attributes = {}, allComponents = {}) => {
826
810
  }, {});
827
811
  return componentsByKey;
828
812
  };
829
- const useDocument = (args, opts) => {
830
- const { toggleNotification } = strapiAdmin.useNotification();
831
- const { _unstableFormatAPIError: formatAPIError } = strapiAdmin.useAPIErrorHandler();
832
- const {
833
- currentData: data,
834
- isLoading: isLoadingDocument,
835
- isFetching: isFetchingDocument,
836
- error
837
- } = useGetDocumentQuery(args, opts);
838
- const { components, schema, isLoading: isLoadingSchema } = useContentTypeSchema(args.model);
839
- React__namespace.useEffect(() => {
840
- if (error) {
841
- toggleNotification({
842
- type: "danger",
843
- message: formatAPIError(error)
844
- });
845
- }
846
- }, [toggleNotification, error, formatAPIError, args.collectionType]);
847
- const validationSchema = React__namespace.useMemo(() => {
848
- if (!schema) {
849
- return null;
850
- }
851
- return createYupSchema(schema.attributes, components);
852
- }, [schema, components]);
853
- const validate = React__namespace.useCallback(
854
- (document) => {
855
- if (!validationSchema) {
856
- throw new Error(
857
- "There is no validation schema generated, this is likely due to the schema not being loaded yet."
858
- );
859
- }
860
- try {
861
- validationSchema.validateSync(document, { abortEarly: false, strict: true });
862
- return null;
863
- } catch (error2) {
864
- if (error2 instanceof yup.ValidationError) {
865
- return getInnerErrors(error2);
866
- }
867
- throw error2;
868
- }
869
- },
870
- [validationSchema]
871
- );
872
- const isLoading = isLoadingDocument || isFetchingDocument || isLoadingSchema;
873
- return {
874
- components,
875
- document: data?.data,
876
- meta: data?.meta,
877
- isLoading,
878
- schema,
879
- validate
880
- };
881
- };
882
- const useDoc = () => {
883
- const { id, slug, collectionType, origin } = reactRouterDom.useParams();
884
- const [{ query }] = strapiAdmin.useQueryParams();
885
- const params = React__namespace.useMemo(() => buildValidParams(query), [query]);
886
- if (!collectionType) {
887
- throw new Error("Could not find collectionType in url params");
888
- }
889
- if (!slug) {
890
- throw new Error("Could not find model in url params");
891
- }
892
- return {
893
- collectionType,
894
- model: slug,
895
- id: origin || id === "create" ? void 0 : id,
896
- ...useDocument(
897
- { documentId: origin || id, model: slug, collectionType, params },
898
- {
899
- skip: id === "create" || !origin && !id && collectionType !== SINGLE_TYPES
900
- }
901
- )
902
- };
813
+ const HOOKS = {
814
+ /**
815
+ * Hook that allows to mutate the displayed headers of the list view table
816
+ * @constant
817
+ * @type {string}
818
+ */
819
+ INJECT_COLUMN_IN_TABLE: "Admin/CM/pages/ListView/inject-column-in-table",
820
+ /**
821
+ * Hook that allows to mutate the CM's collection types links pre-set filters
822
+ * @constant
823
+ * @type {string}
824
+ */
825
+ MUTATE_COLLECTION_TYPES_LINKS: "Admin/CM/pages/App/mutate-collection-types-links",
826
+ /**
827
+ * Hook that allows to mutate the CM's edit view layout
828
+ * @constant
829
+ * @type {string}
830
+ */
831
+ MUTATE_EDIT_VIEW_LAYOUT: "Admin/CM/pages/EditView/mutate-edit-view-layout",
832
+ /**
833
+ * Hook that allows to mutate the CM's single types links pre-set filters
834
+ * @constant
835
+ * @type {string}
836
+ */
837
+ MUTATE_SINGLE_TYPES_LINKS: "Admin/CM/pages/App/mutate-single-types-links"
903
838
  };
904
- const prefixPluginTranslations = (trad, pluginId) => {
905
- if (!pluginId) {
839
+ const contentTypesApi = contentManagerApi.injectEndpoints({
840
+ endpoints: (builder) => ({
841
+ getContentTypeConfiguration: builder.query({
842
+ query: (uid) => ({
843
+ url: `/content-manager/content-types/${uid}/configuration`,
844
+ method: "GET"
845
+ }),
846
+ transformResponse: (response) => response.data,
847
+ providesTags: (_result, _error, uid) => [
848
+ { type: "ContentTypesConfiguration", id: uid },
849
+ { type: "ContentTypeSettings", id: "LIST" }
850
+ ]
851
+ }),
852
+ getAllContentTypeSettings: builder.query({
853
+ query: () => "/content-manager/content-types-settings",
854
+ transformResponse: (response) => response.data,
855
+ providesTags: [{ type: "ContentTypeSettings", id: "LIST" }]
856
+ }),
857
+ updateContentTypeConfiguration: builder.mutation({
858
+ query: ({ uid, ...body }) => ({
859
+ url: `/content-manager/content-types/${uid}/configuration`,
860
+ method: "PUT",
861
+ data: body
862
+ }),
863
+ transformResponse: (response) => response.data,
864
+ invalidatesTags: (_result, _error, { uid }) => [
865
+ { type: "ContentTypesConfiguration", id: uid },
866
+ { type: "ContentTypeSettings", id: "LIST" },
867
+ // Is this necessary?
868
+ { type: "InitialData" }
869
+ ]
870
+ })
871
+ })
872
+ });
873
+ const {
874
+ useGetContentTypeConfigurationQuery,
875
+ useGetAllContentTypeSettingsQuery,
876
+ useUpdateContentTypeConfigurationMutation
877
+ } = contentTypesApi;
878
+ const checkIfAttributeIsDisplayable = (attribute) => {
879
+ const { type } = attribute;
880
+ if (type === "relation") {
881
+ return !attribute.relation.toLowerCase().includes("morph");
882
+ }
883
+ return !["json", "dynamiczone", "richtext", "password", "blocks"].includes(type) && !!type;
884
+ };
885
+ const getMainField = (attribute, mainFieldName, { schemas, components }) => {
886
+ if (!mainFieldName) {
887
+ return void 0;
888
+ }
889
+ const mainFieldType = attribute.type === "component" ? components[attribute.component].attributes[mainFieldName].type : (
890
+ // @ts-expect-error – `targetModel` does exist on the attribute for a relation.
891
+ schemas.find((schema) => schema.uid === attribute.targetModel)?.attributes[mainFieldName].type
892
+ );
893
+ return {
894
+ name: mainFieldName,
895
+ type: mainFieldType ?? "string"
896
+ };
897
+ };
898
+ const DEFAULT_SETTINGS = {
899
+ bulkable: false,
900
+ filterable: false,
901
+ searchable: false,
902
+ pagination: false,
903
+ defaultSortBy: "",
904
+ defaultSortOrder: "asc",
905
+ mainField: "id",
906
+ pageSize: 10
907
+ };
908
+ const useDocumentLayout = (model) => {
909
+ const { schema, components } = useDocument({ model, collectionType: "" }, { skip: true });
910
+ const [{ query }] = strapiAdmin.useQueryParams();
911
+ const runHookWaterfall = strapiAdmin.useStrapiApp("useDocumentLayout", (state) => state.runHookWaterfall);
912
+ const { toggleNotification } = strapiAdmin.useNotification();
913
+ const { _unstableFormatAPIError: formatAPIError } = strapiAdmin.useAPIErrorHandler();
914
+ const { isLoading: isLoadingSchemas, schemas } = useContentTypeSchema();
915
+ const {
916
+ data,
917
+ isLoading: isLoadingConfigs,
918
+ error,
919
+ isFetching: isFetchingConfigs
920
+ } = useGetContentTypeConfigurationQuery(model);
921
+ const isLoading = isLoadingSchemas || isFetchingConfigs || isLoadingConfigs;
922
+ React__namespace.useEffect(() => {
923
+ if (error) {
924
+ toggleNotification({
925
+ type: "danger",
926
+ message: formatAPIError(error)
927
+ });
928
+ }
929
+ }, [error, formatAPIError, toggleNotification]);
930
+ const editLayout = React__namespace.useMemo(
931
+ () => data && !isLoading ? formatEditLayout(data, { schemas, schema, components }) : {
932
+ layout: [],
933
+ components: {},
934
+ metadatas: {},
935
+ options: {},
936
+ settings: DEFAULT_SETTINGS
937
+ },
938
+ [data, isLoading, schemas, schema, components]
939
+ );
940
+ const listLayout = React__namespace.useMemo(() => {
941
+ return data && !isLoading ? formatListLayout(data, { schemas, schema, components }) : {
942
+ layout: [],
943
+ metadatas: {},
944
+ options: {},
945
+ settings: DEFAULT_SETTINGS
946
+ };
947
+ }, [data, isLoading, schemas, schema, components]);
948
+ const { layout: edit } = React__namespace.useMemo(
949
+ () => runHookWaterfall(HOOKS.MUTATE_EDIT_VIEW_LAYOUT, {
950
+ layout: editLayout,
951
+ query
952
+ }),
953
+ [editLayout, query, runHookWaterfall]
954
+ );
955
+ return {
956
+ error,
957
+ isLoading,
958
+ edit,
959
+ list: listLayout
960
+ };
961
+ };
962
+ const useDocLayout = () => {
963
+ const { model } = useDoc();
964
+ return useDocumentLayout(model);
965
+ };
966
+ const formatEditLayout = (data, {
967
+ schemas,
968
+ schema,
969
+ components
970
+ }) => {
971
+ let currentPanelIndex = 0;
972
+ const panelledEditAttributes = convertEditLayoutToFieldLayouts(
973
+ data.contentType.layouts.edit,
974
+ schema?.attributes,
975
+ data.contentType.metadatas,
976
+ { configurations: data.components, schemas: components },
977
+ schemas
978
+ ).reduce((panels, row) => {
979
+ if (row.some((field) => field.type === "dynamiczone")) {
980
+ panels.push([row]);
981
+ currentPanelIndex += 2;
982
+ } else {
983
+ if (!panels[currentPanelIndex]) {
984
+ panels.push([]);
985
+ }
986
+ panels[currentPanelIndex].push(row);
987
+ }
988
+ return panels;
989
+ }, []);
990
+ const componentEditAttributes = Object.entries(data.components).reduce(
991
+ (acc, [uid, configuration]) => {
992
+ acc[uid] = {
993
+ layout: convertEditLayoutToFieldLayouts(
994
+ configuration.layouts.edit,
995
+ components[uid].attributes,
996
+ configuration.metadatas,
997
+ { configurations: data.components, schemas: components }
998
+ ),
999
+ settings: {
1000
+ ...configuration.settings,
1001
+ icon: components[uid].info.icon,
1002
+ displayName: components[uid].info.displayName
1003
+ }
1004
+ };
1005
+ return acc;
1006
+ },
1007
+ {}
1008
+ );
1009
+ const editMetadatas = Object.entries(data.contentType.metadatas).reduce(
1010
+ (acc, [attribute, metadata]) => {
1011
+ return {
1012
+ ...acc,
1013
+ [attribute]: metadata.edit
1014
+ };
1015
+ },
1016
+ {}
1017
+ );
1018
+ return {
1019
+ layout: panelledEditAttributes,
1020
+ components: componentEditAttributes,
1021
+ metadatas: editMetadatas,
1022
+ settings: {
1023
+ ...data.contentType.settings,
1024
+ displayName: schema?.info.displayName
1025
+ },
1026
+ options: {
1027
+ ...schema?.options,
1028
+ ...schema?.pluginOptions,
1029
+ ...data.contentType.options
1030
+ }
1031
+ };
1032
+ };
1033
+ const convertEditLayoutToFieldLayouts = (rows, attributes = {}, metadatas, components, schemas = []) => {
1034
+ return rows.map(
1035
+ (row) => row.map((field) => {
1036
+ const attribute = attributes[field.name];
1037
+ if (!attribute) {
1038
+ return null;
1039
+ }
1040
+ const { edit: metadata } = metadatas[field.name];
1041
+ const settings = attribute.type === "component" && components ? components.configurations[attribute.component].settings : {};
1042
+ return {
1043
+ attribute,
1044
+ disabled: !metadata.editable,
1045
+ hint: metadata.description,
1046
+ label: metadata.label ?? "",
1047
+ name: field.name,
1048
+ // @ts-expect-error – mainField does exist on the metadata for a relation.
1049
+ mainField: getMainField(attribute, metadata.mainField || settings.mainField, {
1050
+ schemas,
1051
+ components: components?.schemas ?? {}
1052
+ }),
1053
+ placeholder: metadata.placeholder ?? "",
1054
+ required: attribute.required ?? false,
1055
+ size: field.size,
1056
+ unique: "unique" in attribute ? attribute.unique : false,
1057
+ visible: metadata.visible ?? true,
1058
+ type: attribute.type
1059
+ };
1060
+ }).filter((field) => field !== null)
1061
+ );
1062
+ };
1063
+ const formatListLayout = (data, {
1064
+ schemas,
1065
+ schema,
1066
+ components
1067
+ }) => {
1068
+ const listMetadatas = Object.entries(data.contentType.metadatas).reduce(
1069
+ (acc, [attribute, metadata]) => {
1070
+ return {
1071
+ ...acc,
1072
+ [attribute]: metadata.list
1073
+ };
1074
+ },
1075
+ {}
1076
+ );
1077
+ const listAttributes = convertListLayoutToFieldLayouts(
1078
+ data.contentType.layouts.list,
1079
+ schema?.attributes,
1080
+ listMetadatas,
1081
+ { configurations: data.components, schemas: components },
1082
+ schemas
1083
+ );
1084
+ return {
1085
+ layout: listAttributes,
1086
+ settings: { ...data.contentType.settings, displayName: schema?.info.displayName },
1087
+ metadatas: listMetadatas,
1088
+ options: {
1089
+ ...schema?.options,
1090
+ ...schema?.pluginOptions,
1091
+ ...data.contentType.options
1092
+ }
1093
+ };
1094
+ };
1095
+ const convertListLayoutToFieldLayouts = (columns, attributes = {}, metadatas, components, schemas = []) => {
1096
+ return columns.map((name) => {
1097
+ const attribute = attributes[name];
1098
+ if (!attribute) {
1099
+ return null;
1100
+ }
1101
+ const metadata = metadatas[name];
1102
+ const settings = attribute.type === "component" && components ? components.configurations[attribute.component].settings : {};
1103
+ return {
1104
+ attribute,
1105
+ label: metadata.label ?? "",
1106
+ mainField: getMainField(attribute, metadata.mainField || settings.mainField, {
1107
+ schemas,
1108
+ components: components?.schemas ?? {}
1109
+ }),
1110
+ name,
1111
+ searchable: metadata.searchable ?? true,
1112
+ sortable: metadata.sortable ?? true
1113
+ };
1114
+ }).filter((field) => field !== null);
1115
+ };
1116
+ const useDocument = (args, opts) => {
1117
+ const { toggleNotification } = strapiAdmin.useNotification();
1118
+ const { _unstableFormatAPIError: formatAPIError } = strapiAdmin.useAPIErrorHandler();
1119
+ const {
1120
+ currentData: data,
1121
+ isLoading: isLoadingDocument,
1122
+ isFetching: isFetchingDocument,
1123
+ error
1124
+ } = useGetDocumentQuery(args, {
1125
+ ...opts,
1126
+ skip: !args.documentId && args.collectionType !== SINGLE_TYPES || opts?.skip
1127
+ });
1128
+ const {
1129
+ components,
1130
+ schema,
1131
+ schemas,
1132
+ isLoading: isLoadingSchema
1133
+ } = useContentTypeSchema(args.model);
1134
+ React__namespace.useEffect(() => {
1135
+ if (error) {
1136
+ toggleNotification({
1137
+ type: "danger",
1138
+ message: formatAPIError(error)
1139
+ });
1140
+ }
1141
+ }, [toggleNotification, error, formatAPIError, args.collectionType]);
1142
+ const validationSchema = React__namespace.useMemo(() => {
1143
+ if (!schema) {
1144
+ return null;
1145
+ }
1146
+ return createYupSchema(schema.attributes, components);
1147
+ }, [schema, components]);
1148
+ const validate = React__namespace.useCallback(
1149
+ (document) => {
1150
+ if (!validationSchema) {
1151
+ throw new Error(
1152
+ "There is no validation schema generated, this is likely due to the schema not being loaded yet."
1153
+ );
1154
+ }
1155
+ try {
1156
+ validationSchema.validateSync(document, { abortEarly: false, strict: true });
1157
+ return null;
1158
+ } catch (error2) {
1159
+ if (error2 instanceof yup.ValidationError) {
1160
+ return strapiAdmin.getYupValidationErrors(error2);
1161
+ }
1162
+ throw error2;
1163
+ }
1164
+ },
1165
+ [validationSchema]
1166
+ );
1167
+ const isLoading = isLoadingDocument || isFetchingDocument || isLoadingSchema;
1168
+ return {
1169
+ components,
1170
+ document: data?.data,
1171
+ meta: data?.meta,
1172
+ isLoading,
1173
+ schema,
1174
+ schemas,
1175
+ validate
1176
+ };
1177
+ };
1178
+ const useDoc = () => {
1179
+ const { id, slug, collectionType, origin } = reactRouterDom.useParams();
1180
+ const [{ query }] = strapiAdmin.useQueryParams();
1181
+ const params = React__namespace.useMemo(() => buildValidParams(query), [query]);
1182
+ if (!collectionType) {
1183
+ throw new Error("Could not find collectionType in url params");
1184
+ }
1185
+ if (!slug) {
1186
+ throw new Error("Could not find model in url params");
1187
+ }
1188
+ return {
1189
+ collectionType,
1190
+ model: slug,
1191
+ id: origin || id === "create" ? void 0 : id,
1192
+ ...useDocument(
1193
+ { documentId: origin || id, model: slug, collectionType, params },
1194
+ {
1195
+ skip: id === "create" || !origin && !id && collectionType !== SINGLE_TYPES
1196
+ }
1197
+ )
1198
+ };
1199
+ };
1200
+ const useContentManagerContext = () => {
1201
+ const {
1202
+ collectionType,
1203
+ model,
1204
+ id,
1205
+ components,
1206
+ isLoading: isLoadingDoc,
1207
+ schema,
1208
+ schemas
1209
+ } = useDoc();
1210
+ const layout = useDocumentLayout(model);
1211
+ const form = strapiAdmin.useForm("useContentManagerContext", (state) => state);
1212
+ const isSingleType = collectionType === SINGLE_TYPES;
1213
+ const slug = model;
1214
+ const isCreatingEntry = id === "create";
1215
+ useContentTypeSchema();
1216
+ const isLoading = isLoadingDoc || layout.isLoading;
1217
+ const error = layout.error;
1218
+ return {
1219
+ error,
1220
+ isLoading,
1221
+ // Base metadata
1222
+ model,
1223
+ collectionType,
1224
+ id,
1225
+ slug,
1226
+ isCreatingEntry,
1227
+ isSingleType,
1228
+ hasDraftAndPublish: schema?.options?.draftAndPublish ?? false,
1229
+ // All schema infos
1230
+ components,
1231
+ contentType: schema,
1232
+ contentTypes: schemas,
1233
+ // Form state
1234
+ form,
1235
+ // layout infos
1236
+ layout
1237
+ };
1238
+ };
1239
+ const prefixPluginTranslations = (trad, pluginId) => {
1240
+ if (!pluginId) {
906
1241
  throw new TypeError("pluginId can't be empty");
907
1242
  }
908
1243
  return Object.keys(trad).reduce((acc, current) => {
@@ -920,6 +1255,8 @@ const useDocumentActions = () => {
920
1255
  const { formatMessage } = reactIntl.useIntl();
921
1256
  const { trackUsage } = strapiAdmin.useTracking();
922
1257
  const { _unstableFormatAPIError: formatAPIError } = strapiAdmin.useAPIErrorHandler();
1258
+ const navigate = reactRouterDom.useNavigate();
1259
+ const setCurrentStep = strapiAdmin.useGuidedTour("useDocumentActions", (state) => state.setCurrentStep);
923
1260
  const [deleteDocument] = useDeleteDocumentMutation();
924
1261
  const _delete = React__namespace.useCallback(
925
1262
  async ({ collectionType, model, documentId, params }, trackerProperty) => {
@@ -958,14 +1295,53 @@ const useDocumentActions = () => {
958
1295
  },
959
1296
  [trackUsage, deleteDocument, toggleNotification, formatMessage, formatAPIError]
960
1297
  );
1298
+ const [deleteManyDocuments] = useDeleteManyDocumentsMutation();
1299
+ const deleteMany = React__namespace.useCallback(
1300
+ async ({ model, documentIds, params }) => {
1301
+ try {
1302
+ trackUsage("willBulkDeleteEntries");
1303
+ const res = await deleteManyDocuments({
1304
+ model,
1305
+ documentIds,
1306
+ params
1307
+ });
1308
+ if ("error" in res) {
1309
+ toggleNotification({
1310
+ type: "danger",
1311
+ message: formatAPIError(res.error)
1312
+ });
1313
+ return { error: res.error };
1314
+ }
1315
+ toggleNotification({
1316
+ type: "success",
1317
+ title: formatMessage({
1318
+ id: getTranslation("success.records.delete"),
1319
+ defaultMessage: "Successfully deleted."
1320
+ }),
1321
+ message: ""
1322
+ });
1323
+ trackUsage("didBulkDeleteEntries");
1324
+ return res.data;
1325
+ } catch (err) {
1326
+ toggleNotification({
1327
+ type: "danger",
1328
+ message: formatMessage(DEFAULT_UNEXPECTED_ERROR_MSG)
1329
+ });
1330
+ trackUsage("didNotBulkDeleteEntries");
1331
+ throw err;
1332
+ }
1333
+ },
1334
+ [trackUsage, deleteManyDocuments, toggleNotification, formatMessage, formatAPIError]
1335
+ );
961
1336
  const [discardDocument] = useDiscardDocumentMutation();
962
1337
  const discard = React__namespace.useCallback(
963
- async ({ collectionType, model, documentId }) => {
1338
+ async ({ collectionType, model, documentId, params }) => {
964
1339
  try {
965
1340
  const res = await discardDocument({
966
1341
  collectionType,
967
1342
  model,
968
- documentId
1343
+ documentId,
1344
+ params
969
1345
  });
970
1346
  if ("error" in res) {
971
1347
  toggleNotification({
@@ -1027,6 +1403,43 @@ const useDocumentActions = () => {
1027
1403
  },
1028
1404
  [trackUsage, publishDocument, toggleNotification, formatMessage, formatAPIError]
1029
1405
  );
1406
+ const [publishManyDocuments] = usePublishManyDocumentsMutation();
1407
+ const publishMany = React__namespace.useCallback(
1408
+ async ({ model, documentIds, params }) => {
1409
+ try {
1410
+ const res = await publishManyDocuments({
1411
+ model,
1412
+ documentIds,
1413
+ params
1414
+ });
1415
+ if ("error" in res) {
1416
+ toggleNotification({ type: "danger", message: formatAPIError(res.error) });
1417
+ return { error: res.error };
1418
+ }
1419
+ toggleNotification({
1420
+ type: "success",
1421
+ message: formatMessage({
1422
+ id: getTranslation("success.record.publish"),
1423
+ defaultMessage: "Published document"
1424
+ })
1425
+ });
1426
+ return res.data;
1427
+ } catch (err) {
1428
+ toggleNotification({
1429
+ type: "danger",
1430
+ message: formatMessage(DEFAULT_UNEXPECTED_ERROR_MSG)
1431
+ });
1432
+ throw err;
1433
+ }
1434
+ },
1435
+ [
1436
+ // trackUsage,
1437
+ publishManyDocuments,
1438
+ toggleNotification,
1439
+ formatMessage,
1440
+ formatAPIError
1441
+ ]
1442
+ );
1030
1443
  const [updateDocument] = useUpdateDocumentMutation();
1031
1444
  const update = React__namespace.useCallback(
1032
1445
  async ({ collectionType, model, documentId, params }, data, trackerProperty) => {
@@ -1101,6 +1514,41 @@ const useDocumentActions = () => {
1101
1514
  },
1102
1515
  [trackUsage, unpublishDocument, toggleNotification, formatMessage, formatAPIError]
1103
1516
  );
1517
+ const [unpublishManyDocuments] = useUnpublishManyDocumentsMutation();
1518
+ const unpublishMany = React__namespace.useCallback(
1519
+ async ({ model, documentIds, params }) => {
1520
+ try {
1521
+ trackUsage("willBulkUnpublishEntries");
1522
+ const res = await unpublishManyDocuments({
1523
+ model,
1524
+ documentIds,
1525
+ params
1526
+ });
1527
+ if ("error" in res) {
1528
+ toggleNotification({ type: "danger", message: formatAPIError(res.error) });
1529
+ return { error: res.error };
1530
+ }
1531
+ trackUsage("didBulkUnpublishEntries");
1532
+ toggleNotification({
1533
+ type: "success",
1534
+ title: formatMessage({
1535
+ id: getTranslation("success.records.unpublish"),
1536
+ defaultMessage: "Successfully unpublished."
1537
+ }),
1538
+ message: ""
1539
+ });
1540
+ return res.data;
1541
+ } catch (err) {
1542
+ toggleNotification({
1543
+ type: "danger",
1544
+ message: formatMessage(DEFAULT_UNEXPECTED_ERROR_MSG)
1545
+ });
1546
+ trackUsage("didNotBulkUnpublishEntries");
1547
+ throw err;
1548
+ }
1549
+ },
1550
+ [trackUsage, unpublishManyDocuments, toggleNotification, formatMessage, formatAPIError]
1551
+ );
1104
1552
  const [createDocument] = useCreateDocumentMutation();
1105
1553
  const create = React__namespace.useCallback(
1106
1554
  async ({ model, params }, data, trackerProperty) => {
@@ -1123,6 +1571,7 @@ const useDocumentActions = () => {
1123
1571
  defaultMessage: "Saved document"
1124
1572
  })
1125
1573
  });
1574
+ setCurrentStep("contentManager.success");
1126
1575
  return res.data;
1127
1576
  } catch (err) {
1128
1577
  toggleNotification({
@@ -1144,7 +1593,6 @@ const useDocumentActions = () => {
1144
1593
  sourceId
1145
1594
  });
1146
1595
  if ("error" in res) {
1147
- toggleNotification({ type: "danger", message: formatAPIError(res.error) });
1148
1596
  return { error: res.error };
1149
1597
  }
1150
1598
  toggleNotification({
@@ -1163,7 +1611,7 @@ const useDocumentActions = () => {
1163
1611
  throw err;
1164
1612
  }
1165
1613
  },
1166
- [autoCloneDocument, formatAPIError, formatMessage, toggleNotification]
1614
+ [autoCloneDocument, formatMessage, toggleNotification]
1167
1615
  );
1168
1616
  const [cloneDocument] = useCloneDocumentMutation();
1169
1617
  const clone = React__namespace.useCallback(
@@ -1189,6 +1637,7 @@ const useDocumentActions = () => {
1189
1637
  defaultMessage: "Cloned document"
1190
1638
  })
1191
1639
  });
1640
+ navigate(`../../${res.data.data.documentId}`, { relative: "path" });
1192
1641
  return res.data;
1193
1642
  } catch (err) {
1194
1643
  toggleNotification({
@@ -1199,7 +1648,7 @@ const useDocumentActions = () => {
1199
1648
  throw err;
1200
1649
  }
1201
1650
  },
1202
- [cloneDocument, trackUsage, toggleNotification, formatMessage, formatAPIError]
1651
+ [cloneDocument, trackUsage, toggleNotification, formatMessage, formatAPIError, navigate]
1203
1652
  );
1204
1653
  const [getDoc] = useLazyGetDocumentQuery();
1205
1654
  const getDocument = React__namespace.useCallback(
@@ -1214,15 +1663,18 @@ const useDocumentActions = () => {
1214
1663
  clone,
1215
1664
  create,
1216
1665
  delete: _delete,
1666
+ deleteMany,
1217
1667
  discard,
1218
1668
  getDocument,
1219
1669
  publish,
1670
+ publishMany,
1220
1671
  unpublish,
1672
+ unpublishMany,
1221
1673
  update
1222
1674
  };
1223
1675
  };
1224
1676
  const ProtectedHistoryPage = React.lazy(
1225
- () => Promise.resolve().then(() => require("./History-C17LiyRg.js")).then((mod) => ({ default: mod.ProtectedHistoryPage }))
1677
+ () => Promise.resolve().then(() => require("./History-CWcM9HnW.js")).then((mod) => ({ default: mod.ProtectedHistoryPage }))
1226
1678
  );
1227
1679
  const routes$1 = [
1228
1680
  {
@@ -1235,31 +1687,31 @@ const routes$1 = [
1235
1687
  }
1236
1688
  ];
1237
1689
  const ProtectedEditViewPage = React.lazy(
1238
- () => Promise.resolve().then(() => require("./EditViewPage-CzOT5Kpj.js")).then((mod) => ({ default: mod.ProtectedEditViewPage }))
1690
+ () => Promise.resolve().then(() => require("./EditViewPage-Co2IKQZH.js")).then((mod) => ({ default: mod.ProtectedEditViewPage }))
1239
1691
  );
1240
1692
  const ProtectedListViewPage = React.lazy(
1241
- () => Promise.resolve().then(() => require("./ListViewPage-BwrZrPsh.js")).then((mod) => ({ default: mod.ProtectedListViewPage }))
1693
+ () => Promise.resolve().then(() => require("./ListViewPage-BBAC9aPu.js")).then((mod) => ({ default: mod.ProtectedListViewPage }))
1242
1694
  );
1243
1695
  const ProtectedListConfiguration = React.lazy(
1244
- () => Promise.resolve().then(() => require("./ListConfigurationPage-Dks5SX6f.js")).then((mod) => ({
1696
+ () => Promise.resolve().then(() => require("./ListConfigurationPage-DGzoQD_I.js")).then((mod) => ({
1245
1697
  default: mod.ProtectedListConfiguration
1246
1698
  }))
1247
1699
  );
1248
1700
  const ProtectedEditConfigurationPage = React.lazy(
1249
- () => Promise.resolve().then(() => require("./EditConfigurationPage-BfFzJ4Br.js")).then((mod) => ({
1701
+ () => Promise.resolve().then(() => require("./EditConfigurationPage-ZN3s568V.js")).then((mod) => ({
1250
1702
  default: mod.ProtectedEditConfigurationPage
1251
1703
  }))
1252
1704
  );
1253
1705
  const ProtectedComponentConfigurationPage = React.lazy(
1254
- () => Promise.resolve().then(() => require("./ComponentConfigurationPage-43KmCNQE.js")).then((mod) => ({
1706
+ () => Promise.resolve().then(() => require("./ComponentConfigurationPage-_6osrv39.js")).then((mod) => ({
1255
1707
  default: mod.ProtectedComponentConfigurationPage
1256
1708
  }))
1257
1709
  );
1258
1710
  const NoPermissions = React.lazy(
1259
- () => Promise.resolve().then(() => require("./NoPermissionsPage-C-j6TEUF.js")).then((mod) => ({ default: mod.NoPermissions }))
1711
+ () => Promise.resolve().then(() => require("./NoPermissionsPage-D2iWw-sn.js")).then((mod) => ({ default: mod.NoPermissions }))
1260
1712
  );
1261
1713
  const NoContentType = React.lazy(
1262
- () => Promise.resolve().then(() => require("./NoContentTypePage-Cu5r1-JT.js")).then((mod) => ({ default: mod.NoContentType }))
1714
+ () => Promise.resolve().then(() => require("./NoContentTypePage-CwVDx_YC.js")).then((mod) => ({ default: mod.NoContentType }))
1263
1715
  );
1264
1716
  const CollectionTypePages = () => {
1265
1717
  const { collectionType } = reactRouterDom.useParams();
@@ -1373,12 +1825,14 @@ const DocumentActionButton = (action) => {
1373
1825
  /* @__PURE__ */ jsxRuntime.jsx(
1374
1826
  designSystem.Button,
1375
1827
  {
1376
- flex: 1,
1828
+ flex: "auto",
1377
1829
  startIcon: action.icon,
1378
1830
  disabled: action.disabled,
1379
1831
  onClick: handleClick(action),
1380
1832
  justifyContent: "center",
1381
1833
  variant: action.variant || "default",
1834
+ paddingTop: "7px",
1835
+ paddingBottom: "7px",
1382
1836
  children: action.label
1383
1837
  }
1384
1838
  ),
@@ -1386,7 +1840,7 @@ const DocumentActionButton = (action) => {
1386
1840
  DocumentActionConfirmDialog,
1387
1841
  {
1388
1842
  ...action.dialog,
1389
- variant: action.variant,
1843
+ variant: action.dialog?.variant ?? action.variant,
1390
1844
  isOpen: dialogId === action.id,
1391
1845
  onClose: handleClose
1392
1846
  }
@@ -1443,20 +1897,20 @@ const DocumentActionsMenu = ({
1443
1897
  disabled: isDisabled,
1444
1898
  size: "S",
1445
1899
  endIcon: null,
1446
- paddingTop: "7px",
1447
- paddingLeft: "9px",
1448
- paddingRight: "9px",
1900
+ paddingTop: "4px",
1901
+ paddingLeft: "7px",
1902
+ paddingRight: "7px",
1449
1903
  variant,
1450
1904
  children: [
1451
1905
  /* @__PURE__ */ jsxRuntime.jsx(Icons.More, { "aria-hidden": true, focusable: false }),
1452
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.VisuallyHidden, { as: "span", children: label || formatMessage({
1906
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.VisuallyHidden, { tag: "span", children: label || formatMessage({
1453
1907
  id: "content-manager.containers.edit.panels.default.more-actions",
1454
1908
  defaultMessage: "More document actions"
1455
1909
  }) })
1456
1910
  ]
1457
1911
  }
1458
1912
  ),
1459
- /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Menu.Content, { top: "4px", maxHeight: void 0, popoverPlacement: "bottom-end", children: [
1913
+ /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Menu.Content, { maxHeight: void 0, popoverPlacement: "bottom-end", children: [
1460
1914
  actions2.map((action) => {
1461
1915
  return /* @__PURE__ */ jsxRuntime.jsx(
1462
1916
  designSystem.Menu.Item,
@@ -1465,10 +1919,25 @@ const DocumentActionsMenu = ({
1465
1919
  onSelect: handleClick(action),
1466
1920
  display: "block",
1467
1921
  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
- ] }),
1922
+ /* @__PURE__ */ jsxRuntime.jsxs(
1923
+ designSystem.Flex,
1924
+ {
1925
+ color: !action.disabled ? convertActionVariantToColor(action.variant) : "inherit",
1926
+ gap: 2,
1927
+ tag: "span",
1928
+ children: [
1929
+ /* @__PURE__ */ jsxRuntime.jsx(
1930
+ designSystem.Flex,
1931
+ {
1932
+ tag: "span",
1933
+ color: !action.disabled ? convertActionVariantToIconColor(action.variant) : "inherit",
1934
+ children: action.icon
1935
+ }
1936
+ ),
1937
+ action.label
1938
+ ]
1939
+ }
1940
+ ),
1472
1941
  action.id.startsWith("HistoryAction") && /* @__PURE__ */ jsxRuntime.jsx(
1473
1942
  designSystem.Flex,
1474
1943
  {
@@ -1527,6 +1996,18 @@ const convertActionVariantToColor = (variant = "secondary") => {
1527
1996
  return "primary600";
1528
1997
  }
1529
1998
  };
1999
+ const convertActionVariantToIconColor = (variant = "secondary") => {
2000
+ switch (variant) {
2001
+ case "danger":
2002
+ return "danger600";
2003
+ case "secondary":
2004
+ return "neutral500";
2005
+ case "success":
2006
+ return "success600";
2007
+ default:
2008
+ return "primary600";
2009
+ }
2010
+ };
1530
2011
  const DocumentActionConfirmDialog = ({
1531
2012
  onClose,
1532
2013
  onCancel,
@@ -1549,61 +2030,42 @@ const DocumentActionConfirmDialog = ({
1549
2030
  }
1550
2031
  onClose();
1551
2032
  };
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
- ] });
2033
+ return /* @__PURE__ */ jsxRuntime.jsx(designSystem.Dialog.Root, { open: isOpen, onOpenChange: handleClose, children: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Dialog.Content, { children: [
2034
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Dialog.Header, { children: title }),
2035
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Dialog.Body, { children: content }),
2036
+ /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Dialog.Footer, { children: [
2037
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Dialog.Cancel, { children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Button, { variant: "tertiary", fullWidth: true, children: formatMessage({
2038
+ id: "app.components.Button.cancel",
2039
+ defaultMessage: "Cancel"
2040
+ }) }) }),
2041
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Button, { onClick: handleConfirm, variant, fullWidth: true, children: formatMessage({
2042
+ id: "app.components.Button.confirm",
2043
+ defaultMessage: "Confirm"
2044
+ }) })
2045
+ ] })
2046
+ ] }) });
1568
2047
  };
1569
2048
  const DocumentActionModal = ({
1570
2049
  isOpen,
1571
2050
  title,
1572
2051
  onClose,
1573
2052
  footer: Footer,
1574
- content,
2053
+ content: Content,
1575
2054
  onModalClose
1576
2055
  }) => {
1577
- const id = React__namespace.useId();
1578
- if (!isOpen) {
1579
- return null;
1580
- }
1581
2056
  const handleClose = () => {
1582
2057
  if (onClose) {
1583
2058
  onClose();
1584
2059
  }
1585
2060
  onModalClose();
1586
2061
  };
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
- ] });
2062
+ return /* @__PURE__ */ jsxRuntime.jsx(designSystem.Modal.Root, { open: isOpen, onOpenChange: handleClose, children: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Modal.Content, { children: [
2063
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Modal.Header, { children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Modal.Title, { children: title }) }),
2064
+ typeof Content === "function" ? /* @__PURE__ */ jsxRuntime.jsx(Content, { onClose: handleClose }) : /* @__PURE__ */ jsxRuntime.jsx(designSystem.Modal.Body, { children: Content }),
2065
+ typeof Footer === "function" ? /* @__PURE__ */ jsxRuntime.jsx(Footer, { onClose: handleClose }) : Footer
2066
+ ] }) });
1605
2067
  };
1606
- const PublishAction = ({
2068
+ const PublishAction$1 = ({
1607
2069
  activeTab,
1608
2070
  documentId,
1609
2071
  model,
@@ -1615,13 +2077,17 @@ const PublishAction = ({
1615
2077
  const navigate = reactRouterDom.useNavigate();
1616
2078
  const { toggleNotification } = strapiAdmin.useNotification();
1617
2079
  const { _unstableFormatValidationErrors: formatValidationErrors } = strapiAdmin.useAPIErrorHandler();
2080
+ const isListView = reactRouterDom.useMatch(LIST_PATH) !== null;
1618
2081
  const isCloning = reactRouterDom.useMatch(CLONE_PATH) !== null;
1619
2082
  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
- );
2083
+ const canPublish = useDocumentRBAC("PublishAction", ({ canPublish: canPublish2 }) => canPublish2);
1624
2084
  const { publish } = useDocumentActions();
2085
+ const [
2086
+ countDraftRelations,
2087
+ { isLoading: isLoadingDraftRelations, isError: isErrorDraftRelations }
2088
+ ] = useLazyGetDraftRelationCountQuery();
2089
+ const [localCountOfDraftRelations, setLocalCountOfDraftRelations] = React__namespace.useState(0);
2090
+ const [serverCountOfDraftRelations, setServerCountOfDraftRelations] = React__namespace.useState(0);
1625
2091
  const [{ query, rawQuery }] = strapiAdmin.useQueryParams();
1626
2092
  const params = React__namespace.useMemo(() => buildValidParams(query), [query]);
1627
2093
  const modified = strapiAdmin.useForm("PublishAction", ({ modified: modified2 }) => modified2);
@@ -1630,10 +2096,103 @@ const PublishAction = ({
1630
2096
  const validate = strapiAdmin.useForm("PublishAction", (state) => state.validate);
1631
2097
  const setErrors = strapiAdmin.useForm("PublishAction", (state) => state.setErrors);
1632
2098
  const formValues = strapiAdmin.useForm("PublishAction", ({ values }) => values);
2099
+ React__namespace.useEffect(() => {
2100
+ if (isErrorDraftRelations) {
2101
+ toggleNotification({
2102
+ type: "danger",
2103
+ message: formatMessage({
2104
+ id: getTranslation("error.records.fetch-draft-relatons"),
2105
+ defaultMessage: "An error occurred while fetching draft relations on this document."
2106
+ })
2107
+ });
2108
+ }
2109
+ }, [isErrorDraftRelations, toggleNotification, formatMessage]);
2110
+ React__namespace.useEffect(() => {
2111
+ const localDraftRelations = /* @__PURE__ */ new Set();
2112
+ const extractDraftRelations = (data) => {
2113
+ const relations = data.connect || [];
2114
+ relations.forEach((relation) => {
2115
+ if (relation.status === "draft") {
2116
+ localDraftRelations.add(relation.id);
2117
+ }
2118
+ });
2119
+ };
2120
+ const traverseAndExtract = (data) => {
2121
+ Object.entries(data).forEach(([key, value]) => {
2122
+ if (key === "connect" && Array.isArray(value)) {
2123
+ extractDraftRelations({ connect: value });
2124
+ } else if (typeof value === "object" && value !== null) {
2125
+ traverseAndExtract(value);
2126
+ }
2127
+ });
2128
+ };
2129
+ if (!documentId || modified) {
2130
+ traverseAndExtract(formValues);
2131
+ setLocalCountOfDraftRelations(localDraftRelations.size);
2132
+ }
2133
+ }, [documentId, modified, formValues, setLocalCountOfDraftRelations]);
2134
+ React__namespace.useEffect(() => {
2135
+ if (!document || !document.documentId || isListView) {
2136
+ return;
2137
+ }
2138
+ const fetchDraftRelationsCount = async () => {
2139
+ const { data, error } = await countDraftRelations({
2140
+ collectionType,
2141
+ model,
2142
+ documentId,
2143
+ params
2144
+ });
2145
+ if (error) {
2146
+ throw error;
2147
+ }
2148
+ if (data) {
2149
+ setServerCountOfDraftRelations(data.data);
2150
+ }
2151
+ };
2152
+ fetchDraftRelationsCount();
2153
+ }, [isListView, document, documentId, countDraftRelations, collectionType, model, params]);
1633
2154
  const isDocumentPublished = (document?.[PUBLISHED_AT_ATTRIBUTE_NAME] || meta?.availableStatus.some((doc) => doc[PUBLISHED_AT_ATTRIBUTE_NAME] !== null)) && document?.status !== "modified";
1634
2155
  if (!schema?.options?.draftAndPublish) {
1635
2156
  return null;
1636
2157
  }
2158
+ const performPublish = async () => {
2159
+ setSubmitting(true);
2160
+ try {
2161
+ const { errors } = await validate();
2162
+ if (errors) {
2163
+ toggleNotification({
2164
+ type: "danger",
2165
+ message: formatMessage({
2166
+ id: "content-manager.validation.error",
2167
+ defaultMessage: "There are validation errors in your document. Please fix them before saving."
2168
+ })
2169
+ });
2170
+ return;
2171
+ }
2172
+ const res = await publish(
2173
+ {
2174
+ collectionType,
2175
+ model,
2176
+ documentId,
2177
+ params
2178
+ },
2179
+ formValues
2180
+ );
2181
+ if ("data" in res && collectionType !== SINGLE_TYPES) {
2182
+ navigate({
2183
+ pathname: `../${collectionType}/${model}/${res.data.documentId}`,
2184
+ search: rawQuery
2185
+ });
2186
+ } else if ("error" in res && isBaseQueryError(res.error) && res.error.name === "ValidationError") {
2187
+ setErrors(formatValidationErrors(res.error));
2188
+ }
2189
+ } finally {
2190
+ setSubmitting(false);
2191
+ }
2192
+ };
2193
+ const totalDraftRelations = localCountOfDraftRelations + serverCountOfDraftRelations;
2194
+ const enableDraftRelationsCount = false;
2195
+ const hasDraftRelations = enableDraftRelationsCount;
1637
2196
  return {
1638
2197
  /**
1639
2198
  * Disabled when:
@@ -1643,52 +2202,39 @@ const PublishAction = ({
1643
2202
  * - the document is already published & not modified
1644
2203
  * - the document is being created & not modified
1645
2204
  * - 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
2205
  */
1649
- disabled: isCloning || isSubmitting || activeTab === "published" || !modified && isDocumentPublished || !modified && !document?.documentId || !canPublish || Boolean(!document?.documentId && !canCreate || document?.documentId && !canUpdate),
2206
+ disabled: isCloning || isSubmitting || isLoadingDraftRelations || activeTab === "published" || !modified && isDocumentPublished || !modified && !document?.documentId || !canPublish,
1650
2207
  label: formatMessage({
1651
2208
  id: "app.utils.publish",
1652
2209
  defaultMessage: "Publish"
1653
2210
  }),
1654
2211
  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));
2212
+ await performPublish();
2213
+ },
2214
+ dialog: hasDraftRelations ? {
2215
+ type: "dialog",
2216
+ variant: "danger",
2217
+ footer: null,
2218
+ title: formatMessage({
2219
+ id: getTranslation(`popUpwarning.warning.bulk-has-draft-relations.title`),
2220
+ defaultMessage: "Confirmation"
2221
+ }),
2222
+ content: formatMessage(
2223
+ {
2224
+ id: getTranslation(`popUpwarning.warning.bulk-has-draft-relations.message`),
2225
+ defaultMessage: "This entry is related to {count, plural, one {# draft entry} other {# draft entries}}. Publishing it could leave broken links in your app."
2226
+ },
2227
+ {
2228
+ count: totalDraftRelations
1684
2229
  }
1685
- } finally {
1686
- setSubmitting(false);
2230
+ ),
2231
+ onConfirm: async () => {
2232
+ await performPublish();
1687
2233
  }
1688
- }
2234
+ } : void 0
1689
2235
  };
1690
2236
  };
1691
- PublishAction.type = "publish";
2237
+ PublishAction$1.type = "publish";
1692
2238
  const UpdateAction = ({
1693
2239
  activeTab,
1694
2240
  documentId,
@@ -1701,10 +2247,6 @@ const UpdateAction = ({
1701
2247
  const cloneMatch = reactRouterDom.useMatch(CLONE_PATH);
1702
2248
  const isCloning = cloneMatch !== null;
1703
2249
  const { formatMessage } = reactIntl.useIntl();
1704
- const { canCreate, canUpdate } = useDocumentRBAC("UpdateAction", ({ canCreate: canCreate2, canUpdate: canUpdate2 }) => ({
1705
- canCreate: canCreate2,
1706
- canUpdate: canUpdate2
1707
- }));
1708
2250
  const { create, update, clone } = useDocumentActions();
1709
2251
  const [{ query, rawQuery }] = strapiAdmin.useQueryParams();
1710
2252
  const params = React__namespace.useMemo(() => buildValidParams(query), [query]);
@@ -1721,10 +2263,8 @@ const UpdateAction = ({
1721
2263
  * - the form is submitting
1722
2264
  * - the document is not modified & we're not cloning (you can save a clone entity straight away)
1723
2265
  * - 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
2266
  */
1727
- disabled: isSubmitting || !modified && !isCloning || activeTab === "published" || Boolean(!documentId && !canCreate || documentId && !canUpdate),
2267
+ disabled: isSubmitting || !modified && !isCloning || activeTab === "published",
1728
2268
  label: formatMessage({
1729
2269
  id: "content-manager.containers.Edit.save",
1730
2270
  defaultMessage: "Save"
@@ -1732,16 +2272,18 @@ const UpdateAction = ({
1732
2272
  onClick: async () => {
1733
2273
  setSubmitting(true);
1734
2274
  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;
2275
+ if (activeTab !== "draft") {
2276
+ const { errors } = await validate();
2277
+ if (errors) {
2278
+ toggleNotification({
2279
+ type: "danger",
2280
+ message: formatMessage({
2281
+ id: "content-manager.validation.error",
2282
+ defaultMessage: "There are validation errors in your document. Please fix them before saving."
2283
+ })
2284
+ });
2285
+ return;
2286
+ }
1745
2287
  }
1746
2288
  if (isCloning) {
1747
2289
  const res = await clone(
@@ -1753,10 +2295,13 @@ const UpdateAction = ({
1753
2295
  document
1754
2296
  );
1755
2297
  if ("data" in res) {
1756
- navigate({
1757
- pathname: `../${collectionType}/${model}/${res.data.documentId}`,
1758
- search: rawQuery
1759
- });
2298
+ navigate(
2299
+ {
2300
+ pathname: `../${res.data.documentId}`,
2301
+ search: rawQuery
2302
+ },
2303
+ { relative: "path" }
2304
+ );
1760
2305
  } else if ("error" in res && isBaseQueryError(res.error) && res.error.name === "ValidationError") {
1761
2306
  setErrors(formatValidationErrors(res.error));
1762
2307
  }
@@ -1784,10 +2329,13 @@ const UpdateAction = ({
1784
2329
  document
1785
2330
  );
1786
2331
  if ("data" in res && collectionType !== SINGLE_TYPES) {
1787
- navigate({
1788
- pathname: `../${collectionType}/${model}/${res.data.documentId}`,
1789
- search: rawQuery
1790
- });
2332
+ navigate(
2333
+ {
2334
+ pathname: `../${res.data.documentId}`,
2335
+ search: rawQuery
2336
+ },
2337
+ { replace: true, relative: "path" }
2338
+ );
1791
2339
  } else if ("error" in res && isBaseQueryError(res.error) && res.error.name === "ValidationError") {
1792
2340
  setErrors(formatValidationErrors(res.error));
1793
2341
  }
@@ -1803,7 +2351,7 @@ const UNPUBLISH_DRAFT_OPTIONS = {
1803
2351
  KEEP: "keep",
1804
2352
  DISCARD: "discard"
1805
2353
  };
1806
- const UnpublishAction = ({
2354
+ const UnpublishAction$1 = ({
1807
2355
  activeTab,
1808
2356
  documentId,
1809
2357
  model,
@@ -1819,10 +2367,8 @@ const UnpublishAction = ({
1819
2367
  const { toggleNotification } = strapiAdmin.useNotification();
1820
2368
  const [shouldKeepDraft, setShouldKeepDraft] = React__namespace.useState(true);
1821
2369
  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
- }
2370
+ const handleChange = (value) => {
2371
+ setShouldKeepDraft(value === UNPUBLISH_DRAFT_OPTIONS.KEEP);
1826
2372
  };
1827
2373
  if (!schema?.options?.draftAndPublish) {
1828
2374
  return null;
@@ -1833,7 +2379,7 @@ const UnpublishAction = ({
1833
2379
  id: "app.utils.unpublish",
1834
2380
  defaultMessage: "Unpublish"
1835
2381
  }),
1836
- icon: /* @__PURE__ */ jsxRuntime.jsx(StyledCrossCircle, {}),
2382
+ icon: /* @__PURE__ */ jsxRuntime.jsx(Icons.Cross, {}),
1837
2383
  onClick: async () => {
1838
2384
  if (!documentId && collectionType !== SINGLE_TYPES || isDocumentModified) {
1839
2385
  if (!documentId) {
@@ -1866,45 +2412,30 @@ const UnpublishAction = ({
1866
2412
  content: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { alignItems: "flex-start", direction: "column", gap: 6, children: [
1867
2413
  /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { width: "100%", direction: "column", gap: 2, children: [
1868
2414
  /* @__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({
2415
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { tag: "p", variant: "omega", textAlign: "center", children: formatMessage({
1870
2416
  id: "content-manager.actions.unpublish.dialog.body",
1871
2417
  defaultMessage: "Are you sure?"
1872
2418
  }) })
1873
2419
  ] }),
1874
2420
  /* @__PURE__ */ jsxRuntime.jsxs(
1875
- designSystem.Flex,
2421
+ designSystem.Radio.Group,
1876
2422
  {
1877
- onChange: handleChange,
1878
- direction: "column",
1879
- alignItems: "flex-start",
1880
- as: "fieldset",
1881
- gap: 3,
2423
+ defaultValue: UNPUBLISH_DRAFT_OPTIONS.KEEP,
2424
+ name: "discard-options",
2425
+ "aria-label": formatMessage({
2426
+ id: "content-manager.actions.unpublish.dialog.radio-label",
2427
+ defaultMessage: "Choose an option to unpublish the document."
2428
+ }),
2429
+ onValueChange: handleChange,
1882
2430
  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
- )
2431
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Radio.Item, { checked: shouldKeepDraft, value: UNPUBLISH_DRAFT_OPTIONS.KEEP, children: formatMessage({
2432
+ id: "content-manager.actions.unpublish.dialog.option.keep-draft",
2433
+ defaultMessage: "Keep draft"
2434
+ }) }),
2435
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Radio.Item, { checked: !shouldKeepDraft, value: UNPUBLISH_DRAFT_OPTIONS.DISCARD, children: formatMessage({
2436
+ id: "content-manager.actions.unpublish.dialog.option.replace-draft",
2437
+ defaultMessage: "Replace draft"
2438
+ }) })
1908
2439
  ]
1909
2440
  }
1910
2441
  )
@@ -1937,7 +2468,7 @@ const UnpublishAction = ({
1937
2468
  position: ["panel", "table-row"]
1938
2469
  };
1939
2470
  };
1940
- UnpublishAction.type = "unpublish";
2471
+ UnpublishAction$1.type = "unpublish";
1941
2472
  const DiscardAction = ({
1942
2473
  activeTab,
1943
2474
  documentId,
@@ -1960,7 +2491,7 @@ const DiscardAction = ({
1960
2491
  id: "content-manager.actions.discard.label",
1961
2492
  defaultMessage: "Discard changes"
1962
2493
  }),
1963
- icon: /* @__PURE__ */ jsxRuntime.jsx(StyledCrossCircle, {}),
2494
+ icon: /* @__PURE__ */ jsxRuntime.jsx(Icons.Cross, {}),
1964
2495
  position: ["panel", "table-row"],
1965
2496
  variant: "danger",
1966
2497
  dialog: {
@@ -1971,7 +2502,7 @@ const DiscardAction = ({
1971
2502
  }),
1972
2503
  content: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { direction: "column", gap: 2, children: [
1973
2504
  /* @__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({
2505
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { tag: "p", variant: "omega", textAlign: "center", children: formatMessage({
1975
2506
  id: "content-manager.actions.discard.dialog.body",
1976
2507
  defaultMessage: "Are you sure?"
1977
2508
  }) })
@@ -1988,12 +2519,7 @@ const DiscardAction = ({
1988
2519
  };
1989
2520
  };
1990
2521
  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];
2522
+ const DEFAULT_ACTIONS = [PublishAction$1, UpdateAction, UnpublishAction$1, DiscardAction];
1997
2523
  const intervals = ["years", "months", "days", "hours", "minutes", "seconds"];
1998
2524
  const RelativeTime = React__namespace.forwardRef(
1999
2525
  ({ timestamp, customIntervals = [], ...restProps }, forwardedRef) => {
@@ -2040,8 +2566,8 @@ const getDisplayName = ({
2040
2566
  };
2041
2567
  const capitalise = (str) => str.charAt(0).toUpperCase() + str.slice(1);
2042
2568
  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) }) });
2569
+ const statusVariant = status === "draft" ? "secondary" : status === "published" ? "success" : "alternative";
2570
+ 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
2571
  };
2046
2572
  const Header = ({ isCreating, status, title: documentTitle = "Untitled" }) => {
2047
2573
  const { formatMessage } = reactIntl.useIntl();
@@ -2050,23 +2576,13 @@ const Header = ({ isCreating, status, title: documentTitle = "Untitled" }) => {
2050
2576
  id: "content-manager.containers.edit.title.new",
2051
2577
  defaultMessage: "Create an entry"
2052
2578
  }) : documentTitle;
2053
- return /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { direction: "column", alignItems: "flex-start", paddingTop: 8, paddingBottom: 4, gap: 3, children: [
2579
+ return /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { direction: "column", alignItems: "flex-start", paddingTop: 6, paddingBottom: 4, gap: 2, children: [
2054
2580
  /* @__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
2581
+ /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { width: "100%", justifyContent: "space-between", gap: "80px", alignItems: "flex-start", children: [
2582
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "alpha", tag: "h1", children: title }),
2583
+ /* @__PURE__ */ jsxRuntime.jsx(HeaderToolbar, {})
2584
+ ] }),
2585
+ status ? /* @__PURE__ */ jsxRuntime.jsx(designSystem.Box, { marginTop: 1, children: /* @__PURE__ */ jsxRuntime.jsx(DocumentStatus, { status: isCloning ? "draft" : status }) }) : null
2070
2586
  ] });
2071
2587
  };
2072
2588
  const HeaderToolbar = () => {
@@ -2218,7 +2734,7 @@ const Information = ({ activeTab }) => {
2218
2734
  borderColor: "neutral150",
2219
2735
  direction: "column",
2220
2736
  marginTop: 2,
2221
- as: "dl",
2737
+ tag: "dl",
2222
2738
  padding: 5,
2223
2739
  gap: 3,
2224
2740
  alignItems: "flex-start",
@@ -2226,15 +2742,29 @@ const Information = ({ activeTab }) => {
2226
2742
  marginRight: "-0.4rem",
2227
2743
  width: "calc(100% + 8px)",
2228
2744
  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 })
2745
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { tag: "dt", variant: "pi", fontWeight: "bold", children: info.label }),
2746
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { tag: "dd", variant: "pi", textColor: "neutral600", children: info.value })
2231
2747
  ] }, info.label))
2232
2748
  }
2233
2749
  );
2234
2750
  };
2235
2751
  const HeaderActions = ({ actions: actions2 }) => {
2236
- return /* @__PURE__ */ jsxRuntime.jsx(designSystem.Flex, { children: actions2.map((action) => {
2237
- if ("options" in action) {
2752
+ const [dialogId, setDialogId] = React__namespace.useState(null);
2753
+ const handleClick = (action) => async (e) => {
2754
+ if (!("options" in action)) {
2755
+ const { onClick = () => false, dialog, id } = action;
2756
+ const muteDialog = await onClick(e);
2757
+ if (dialog && !muteDialog) {
2758
+ e.preventDefault();
2759
+ setDialogId(id);
2760
+ }
2761
+ }
2762
+ };
2763
+ const handleClose = () => {
2764
+ setDialogId(null);
2765
+ };
2766
+ return /* @__PURE__ */ jsxRuntime.jsx(designSystem.Flex, { gap: 1, children: actions2.map((action) => {
2767
+ if (action.options) {
2238
2768
  return /* @__PURE__ */ jsxRuntime.jsx(
2239
2769
  designSystem.SingleSelect,
2240
2770
  {
@@ -2248,10 +2778,49 @@ const HeaderActions = ({ actions: actions2 }) => {
2248
2778
  action.id
2249
2779
  );
2250
2780
  } else {
2251
- return null;
2781
+ if (action.type === "icon") {
2782
+ return /* @__PURE__ */ jsxRuntime.jsxs(React__namespace.Fragment, { children: [
2783
+ /* @__PURE__ */ jsxRuntime.jsx(
2784
+ designSystem.IconButton,
2785
+ {
2786
+ disabled: action.disabled,
2787
+ label: action.label,
2788
+ size: "S",
2789
+ onClick: handleClick(action),
2790
+ children: action.icon
2791
+ }
2792
+ ),
2793
+ action.dialog ? /* @__PURE__ */ jsxRuntime.jsx(
2794
+ HeaderActionDialog,
2795
+ {
2796
+ ...action.dialog,
2797
+ isOpen: dialogId === action.id,
2798
+ onClose: handleClose
2799
+ }
2800
+ ) : null
2801
+ ] }, action.id);
2802
+ }
2252
2803
  }
2253
2804
  }) });
2254
2805
  };
2806
+ const HeaderActionDialog = ({
2807
+ onClose,
2808
+ onCancel,
2809
+ title,
2810
+ content: Content,
2811
+ isOpen
2812
+ }) => {
2813
+ const handleClose = async () => {
2814
+ if (onCancel) {
2815
+ await onCancel();
2816
+ }
2817
+ onClose();
2818
+ };
2819
+ return /* @__PURE__ */ jsxRuntime.jsx(designSystem.Dialog.Root, { open: isOpen, onOpenChange: handleClose, children: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Dialog.Content, { children: [
2820
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Dialog.Header, { children: title }),
2821
+ typeof Content === "function" ? /* @__PURE__ */ jsxRuntime.jsx(Content, { onClose: handleClose }) : Content
2822
+ ] }) });
2823
+ };
2255
2824
  const ConfigureTheViewAction = ({ collectionType, model }) => {
2256
2825
  const navigate = reactRouterDom.useNavigate();
2257
2826
  const { formatMessage } = reactIntl.useIntl();
@@ -2260,7 +2829,7 @@ const ConfigureTheViewAction = ({ collectionType, model }) => {
2260
2829
  id: "app.links.configure-view",
2261
2830
  defaultMessage: "Configure the view"
2262
2831
  }),
2263
- icon: /* @__PURE__ */ jsxRuntime.jsx(StyledCog, {}),
2832
+ icon: /* @__PURE__ */ jsxRuntime.jsx(Icons.ListPlus, {}),
2264
2833
  onClick: () => {
2265
2834
  navigate(`../${collectionType}/${model}/configurations/edit`);
2266
2835
  },
@@ -2268,11 +2837,6 @@ const ConfigureTheViewAction = ({ collectionType, model }) => {
2268
2837
  };
2269
2838
  };
2270
2839
  ConfigureTheViewAction.type = "configure-the-view";
2271
- const StyledCog = styled__default.default(Icons.Cog)`
2272
- path {
2273
- fill: currentColor;
2274
- }
2275
- `;
2276
2840
  const EditTheModelAction = ({ model }) => {
2277
2841
  const navigate = reactRouterDom.useNavigate();
2278
2842
  const { formatMessage } = reactIntl.useIntl();
@@ -2281,20 +2845,15 @@ const EditTheModelAction = ({ model }) => {
2281
2845
  id: "content-manager.link-to-ctb",
2282
2846
  defaultMessage: "Edit the model"
2283
2847
  }),
2284
- icon: /* @__PURE__ */ jsxRuntime.jsx(StyledPencil$1, {}),
2848
+ icon: /* @__PURE__ */ jsxRuntime.jsx(Icons.Pencil, {}),
2285
2849
  onClick: () => {
2286
2850
  navigate(`/plugins/content-type-builder/content-types/${model}`);
2287
2851
  },
2288
2852
  position: "header"
2289
2853
  };
2290
- };
2291
- 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 }) => {
2854
+ };
2855
+ EditTheModelAction.type = "edit-the-model";
2856
+ const DeleteAction$1 = ({ documentId, model, collectionType, document }) => {
2298
2857
  const navigate = reactRouterDom.useNavigate();
2299
2858
  const { formatMessage } = reactIntl.useIntl();
2300
2859
  const listViewPathMatch = reactRouterDom.useMatch(LIST_PATH);
@@ -2302,13 +2861,17 @@ const DeleteAction = ({ documentId, model, collectionType, document }) => {
2302
2861
  const { delete: deleteAction } = useDocumentActions();
2303
2862
  const { toggleNotification } = strapiAdmin.useNotification();
2304
2863
  const setSubmitting = strapiAdmin.useForm("DeleteAction", (state) => state.setSubmitting);
2864
+ const isLocalized = document?.locale != null;
2305
2865
  return {
2306
2866
  disabled: !canDelete || !document,
2307
- label: formatMessage({
2308
- id: "content-manager.actions.delete.label",
2309
- defaultMessage: "Delete document"
2310
- }),
2311
- icon: /* @__PURE__ */ jsxRuntime.jsx(StyledTrash, {}),
2867
+ label: formatMessage(
2868
+ {
2869
+ id: "content-manager.actions.delete.label",
2870
+ defaultMessage: "Delete entry{isLocalized, select, true { (all locales)} other {}}"
2871
+ },
2872
+ { isLocalized }
2873
+ ),
2874
+ icon: /* @__PURE__ */ jsxRuntime.jsx(Icons.Trash, {}),
2312
2875
  dialog: {
2313
2876
  type: "dialog",
2314
2877
  title: formatMessage({
@@ -2317,7 +2880,7 @@ const DeleteAction = ({ documentId, model, collectionType, document }) => {
2317
2880
  }),
2318
2881
  content: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { direction: "column", gap: 2, children: [
2319
2882
  /* @__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({
2883
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { tag: "p", variant: "omega", textAlign: "center", children: formatMessage({
2321
2884
  id: "content-manager.actions.delete.dialog.body",
2322
2885
  defaultMessage: "Are you sure?"
2323
2886
  }) })
@@ -2362,13 +2925,8 @@ const DeleteAction = ({ documentId, model, collectionType, document }) => {
2362
2925
  position: ["header", "table-row"]
2363
2926
  };
2364
2927
  };
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];
2928
+ DeleteAction$1.type = "delete";
2929
+ const DEFAULT_HEADER_ACTIONS = [EditTheModelAction, ConfigureTheViewAction, DeleteAction$1];
2372
2930
  const Panels = () => {
2373
2931
  const isCloning = reactRouterDom.useMatch(CLONE_PATH) !== null;
2374
2932
  const [
@@ -2402,7 +2960,7 @@ const ActionsPanel = () => {
2402
2960
  return {
2403
2961
  title: formatMessage({
2404
2962
  id: "content-manager.containers.edit.panels.default.title",
2405
- defaultMessage: "Document"
2963
+ defaultMessage: "Entry"
2406
2964
  }),
2407
2965
  content: /* @__PURE__ */ jsxRuntime.jsx(ActionsPanelContent, {})
2408
2966
  };
@@ -2442,7 +3000,7 @@ const Panel = React__namespace.forwardRef(({ children, title }, ref) => {
2442
3000
  designSystem.Flex,
2443
3001
  {
2444
3002
  ref,
2445
- as: "aside",
3003
+ tag: "aside",
2446
3004
  "aria-labelledby": "additional-information",
2447
3005
  background: "neutral0",
2448
3006
  borderColor: "neutral150",
@@ -2457,13 +3015,598 @@ const Panel = React__namespace.forwardRef(({ children, title }, ref) => {
2457
3015
  justifyContent: "stretch",
2458
3016
  alignItems: "flex-start",
2459
3017
  children: [
2460
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { as: "h2", variant: "sigma", textTransform: "uppercase", children: title }),
3018
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { tag: "h2", variant: "sigma", textTransform: "uppercase", children: title }),
2461
3019
  children
2462
3020
  ]
2463
3021
  }
2464
3022
  );
2465
3023
  });
2466
- const DEFAULT_BULK_ACTIONS = [];
3024
+ const ConfirmBulkActionDialog = ({
3025
+ onToggleDialog,
3026
+ isOpen = false,
3027
+ dialogBody,
3028
+ endAction
3029
+ }) => {
3030
+ const { formatMessage } = reactIntl.useIntl();
3031
+ return /* @__PURE__ */ jsxRuntime.jsx(designSystem.Dialog.Root, { open: isOpen, children: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Dialog.Content, { children: [
3032
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Dialog.Header, { children: formatMessage({
3033
+ id: "app.components.ConfirmDialog.title",
3034
+ defaultMessage: "Confirmation"
3035
+ }) }),
3036
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Dialog.Body, { children: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { direction: "column", alignItems: "stretch", gap: 2, children: [
3037
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Flex, { justifyContent: "center", children: /* @__PURE__ */ jsxRuntime.jsx(Icons.WarningCircle, { width: "24px", height: "24px", fill: "danger600" }) }),
3038
+ dialogBody
3039
+ ] }) }),
3040
+ /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Dialog.Footer, { children: [
3041
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Dialog.Cancel, { children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Button, { fullWidth: true, onClick: onToggleDialog, variant: "tertiary", children: formatMessage({
3042
+ id: "app.components.Button.cancel",
3043
+ defaultMessage: "Cancel"
3044
+ }) }) }),
3045
+ endAction
3046
+ ] })
3047
+ ] }) });
3048
+ };
3049
+ const BoldChunk$1 = (chunks) => /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { fontWeight: "bold", children: chunks });
3050
+ const ConfirmDialogPublishAll = ({
3051
+ isOpen,
3052
+ onToggleDialog,
3053
+ isConfirmButtonLoading = false,
3054
+ onConfirm
3055
+ }) => {
3056
+ const { formatMessage } = reactIntl.useIntl();
3057
+ const selectedEntries = strapiAdmin.useTable("ConfirmDialogPublishAll", (state) => state.selectedRows);
3058
+ const { toggleNotification } = strapiAdmin.useNotification();
3059
+ const { _unstableFormatAPIError: formatAPIError } = strapiAdmin.useAPIErrorHandler(getTranslation);
3060
+ const { model, schema } = useDoc();
3061
+ const [{ query }] = strapiAdmin.useQueryParams();
3062
+ const enableDraftRelationsCount = false;
3063
+ const {
3064
+ data: countDraftRelations = 0,
3065
+ isLoading,
3066
+ error
3067
+ } = useGetManyDraftRelationCountQuery(
3068
+ {
3069
+ model,
3070
+ documentIds: selectedEntries.map((entry) => entry.documentId),
3071
+ locale: query?.plugins?.i18n?.locale
3072
+ },
3073
+ {
3074
+ skip: !enableDraftRelationsCount
3075
+ }
3076
+ );
3077
+ React__namespace.useEffect(() => {
3078
+ if (error) {
3079
+ toggleNotification({ type: "danger", message: formatAPIError(error) });
3080
+ }
3081
+ }, [error, formatAPIError, toggleNotification]);
3082
+ if (error) {
3083
+ return null;
3084
+ }
3085
+ return /* @__PURE__ */ jsxRuntime.jsx(
3086
+ ConfirmBulkActionDialog,
3087
+ {
3088
+ isOpen: isOpen && !isLoading,
3089
+ onToggleDialog,
3090
+ dialogBody: /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
3091
+ /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Typography, { id: "confirm-description", textAlign: "center", children: [
3092
+ countDraftRelations > 0 && formatMessage(
3093
+ {
3094
+ id: getTranslation(`popUpwarning.warning.bulk-has-draft-relations.message`),
3095
+ 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. "
3096
+ },
3097
+ {
3098
+ b: BoldChunk$1,
3099
+ count: countDraftRelations,
3100
+ entities: selectedEntries.length
3101
+ }
3102
+ ),
3103
+ formatMessage({
3104
+ id: getTranslation("popUpWarning.bodyMessage.contentType.publish.all"),
3105
+ defaultMessage: "Are you sure you want to publish these entries?"
3106
+ })
3107
+ ] }),
3108
+ schema?.pluginOptions && "i18n" in schema.pluginOptions && schema?.pluginOptions.i18n && /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { textColor: "danger500", textAlign: "center", children: formatMessage(
3109
+ {
3110
+ id: getTranslation("Settings.list.actions.publishAdditionalInfos"),
3111
+ defaultMessage: "This will publish the active locale versions <em>(from Internationalization)</em>"
3112
+ },
3113
+ {
3114
+ em: Emphasis
3115
+ }
3116
+ ) })
3117
+ ] }),
3118
+ endAction: /* @__PURE__ */ jsxRuntime.jsx(
3119
+ designSystem.Button,
3120
+ {
3121
+ onClick: onConfirm,
3122
+ variant: "secondary",
3123
+ startIcon: /* @__PURE__ */ jsxRuntime.jsx(Icons.Check, {}),
3124
+ loading: isConfirmButtonLoading,
3125
+ children: formatMessage({
3126
+ id: "app.utils.publish",
3127
+ defaultMessage: "Publish"
3128
+ })
3129
+ }
3130
+ )
3131
+ }
3132
+ );
3133
+ };
3134
+ const TypographyMaxWidth = styledComponents.styled(designSystem.Typography)`
3135
+ max-width: 300px;
3136
+ `;
3137
+ const formatErrorMessages = (errors, parentKey, formatMessage) => {
3138
+ const messages = [];
3139
+ Object.entries(errors).forEach(([key, value]) => {
3140
+ const currentKey = parentKey ? `${parentKey}.${key}` : key;
3141
+ if (typeof value === "object" && value !== null && !Array.isArray(value)) {
3142
+ if ("id" in value && "defaultMessage" in value) {
3143
+ messages.push(
3144
+ formatMessage(
3145
+ {
3146
+ id: `${value.id}.withField`,
3147
+ defaultMessage: value.defaultMessage
3148
+ },
3149
+ { field: currentKey }
3150
+ )
3151
+ );
3152
+ } else {
3153
+ messages.push(
3154
+ ...formatErrorMessages(
3155
+ // @ts-expect-error TODO: check why value is not compatible with FormErrors
3156
+ value,
3157
+ currentKey,
3158
+ formatMessage
3159
+ )
3160
+ );
3161
+ }
3162
+ } else {
3163
+ messages.push(
3164
+ formatMessage(
3165
+ {
3166
+ id: `${value}.withField`,
3167
+ defaultMessage: value
3168
+ },
3169
+ { field: currentKey }
3170
+ )
3171
+ );
3172
+ }
3173
+ });
3174
+ return messages;
3175
+ };
3176
+ const EntryValidationText = ({ validationErrors, status }) => {
3177
+ const { formatMessage } = reactIntl.useIntl();
3178
+ if (validationErrors) {
3179
+ const validationErrorsMessages = formatErrorMessages(validationErrors, "", formatMessage).join(
3180
+ " "
3181
+ );
3182
+ return /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { gap: 2, children: [
3183
+ /* @__PURE__ */ jsxRuntime.jsx(Icons.CrossCircle, { fill: "danger600" }),
3184
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Tooltip, { description: validationErrorsMessages, children: /* @__PURE__ */ jsxRuntime.jsx(TypographyMaxWidth, { textColor: "danger600", variant: "omega", fontWeight: "semiBold", ellipsis: true, children: validationErrorsMessages }) })
3185
+ ] });
3186
+ }
3187
+ if (status === "published") {
3188
+ return /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { gap: 2, children: [
3189
+ /* @__PURE__ */ jsxRuntime.jsx(Icons.CheckCircle, { fill: "success600" }),
3190
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { textColor: "success600", fontWeight: "bold", children: formatMessage({
3191
+ id: "content-manager.bulk-publish.already-published",
3192
+ defaultMessage: "Already Published"
3193
+ }) })
3194
+ ] });
3195
+ }
3196
+ if (status === "modified") {
3197
+ return /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { gap: 2, children: [
3198
+ /* @__PURE__ */ jsxRuntime.jsx(Icons.ArrowsCounterClockwise, { fill: "alternative600" }),
3199
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { children: formatMessage({
3200
+ id: "content-manager.bulk-publish.modified",
3201
+ defaultMessage: "Ready to publish changes"
3202
+ }) })
3203
+ ] });
3204
+ }
3205
+ return /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { gap: 2, children: [
3206
+ /* @__PURE__ */ jsxRuntime.jsx(Icons.CheckCircle, { fill: "success600" }),
3207
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { children: formatMessage({
3208
+ id: "app.utils.ready-to-publish",
3209
+ defaultMessage: "Ready to publish"
3210
+ }) })
3211
+ ] });
3212
+ };
3213
+ const TABLE_HEADERS = [
3214
+ { name: "id", label: "id" },
3215
+ { name: "name", label: "name" },
3216
+ { name: "status", label: "status" },
3217
+ { name: "publicationStatus", label: "Publication status" }
3218
+ ];
3219
+ const SelectedEntriesTableContent = ({
3220
+ isPublishing,
3221
+ rowsToDisplay = [],
3222
+ entriesToPublish = [],
3223
+ validationErrors = {}
3224
+ }) => {
3225
+ const { pathname } = reactRouterDom.useLocation();
3226
+ const { formatMessage } = reactIntl.useIntl();
3227
+ const {
3228
+ list: {
3229
+ settings: { mainField }
3230
+ }
3231
+ } = useDocLayout();
3232
+ const shouldDisplayMainField = mainField != null && mainField !== "id";
3233
+ return /* @__PURE__ */ jsxRuntime.jsxs(strapiAdmin.Table.Content, { children: [
3234
+ /* @__PURE__ */ jsxRuntime.jsxs(strapiAdmin.Table.Head, { children: [
3235
+ /* @__PURE__ */ jsxRuntime.jsx(strapiAdmin.Table.HeaderCheckboxCell, {}),
3236
+ TABLE_HEADERS.filter((head) => head.name !== "name" || shouldDisplayMainField).map(
3237
+ (head) => /* @__PURE__ */ jsxRuntime.jsx(strapiAdmin.Table.HeaderCell, { ...head }, head.name)
3238
+ )
3239
+ ] }),
3240
+ /* @__PURE__ */ jsxRuntime.jsx(strapiAdmin.Table.Loading, {}),
3241
+ /* @__PURE__ */ jsxRuntime.jsx(strapiAdmin.Table.Body, { children: rowsToDisplay.map((row, index2) => /* @__PURE__ */ jsxRuntime.jsxs(strapiAdmin.Table.Row, { children: [
3242
+ /* @__PURE__ */ jsxRuntime.jsx(strapiAdmin.Table.CheckboxCell, { id: row.id }),
3243
+ /* @__PURE__ */ jsxRuntime.jsx(strapiAdmin.Table.Cell, { children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { children: row.id }) }),
3244
+ shouldDisplayMainField && /* @__PURE__ */ jsxRuntime.jsx(strapiAdmin.Table.Cell, { children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { children: row[mainField] }) }),
3245
+ /* @__PURE__ */ jsxRuntime.jsx(strapiAdmin.Table.Cell, { children: /* @__PURE__ */ jsxRuntime.jsx(DocumentStatus, { status: row.status, maxWidth: "min-content" }) }),
3246
+ /* @__PURE__ */ jsxRuntime.jsx(strapiAdmin.Table.Cell, { children: isPublishing && entriesToPublish.includes(row.documentId) ? /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { gap: 2, children: [
3247
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { children: formatMessage({
3248
+ id: "content-manager.success.record.publishing",
3249
+ defaultMessage: "Publishing..."
3250
+ }) }),
3251
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Loader, { small: true })
3252
+ ] }) : /* @__PURE__ */ jsxRuntime.jsx(
3253
+ EntryValidationText,
3254
+ {
3255
+ validationErrors: validationErrors[row.documentId],
3256
+ status: row.status
3257
+ }
3258
+ ) }),
3259
+ /* @__PURE__ */ jsxRuntime.jsx(strapiAdmin.Table.Cell, { children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Flex, { children: /* @__PURE__ */ jsxRuntime.jsx(
3260
+ designSystem.IconButton,
3261
+ {
3262
+ tag: reactRouterDom.Link,
3263
+ to: {
3264
+ pathname: `${pathname}/${row.documentId}`,
3265
+ search: row.locale && `?plugins[i18n][locale]=${row.locale}`
3266
+ },
3267
+ state: { from: pathname },
3268
+ label: formatMessage(
3269
+ { id: "app.component.HelperPluginTable.edit", defaultMessage: "Edit {target}" },
3270
+ {
3271
+ target: formatMessage(
3272
+ {
3273
+ id: "content-manager.components.ListViewHelperPluginTable.row-line",
3274
+ defaultMessage: "item line {number}"
3275
+ },
3276
+ { number: index2 + 1 }
3277
+ )
3278
+ }
3279
+ ),
3280
+ target: "_blank",
3281
+ marginLeft: "auto",
3282
+ variant: "ghost",
3283
+ children: /* @__PURE__ */ jsxRuntime.jsx(Icons.Pencil, { width: "1.6rem", height: "1.6rem" })
3284
+ }
3285
+ ) }) })
3286
+ ] }, row.id)) })
3287
+ ] });
3288
+ };
3289
+ const BoldChunk = (chunks) => /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { fontWeight: "bold", children: chunks });
3290
+ const SelectedEntriesModalContent = ({
3291
+ listViewSelectedEntries,
3292
+ toggleModal,
3293
+ setListViewSelectedDocuments,
3294
+ model
3295
+ }) => {
3296
+ const { formatMessage } = reactIntl.useIntl();
3297
+ const { schema, components } = useContentTypeSchema(model);
3298
+ const documentIds = listViewSelectedEntries.map(({ documentId }) => documentId);
3299
+ const [{ query }] = strapiAdmin.useQueryParams();
3300
+ const params = React__namespace.useMemo(() => buildValidParams(query), [query]);
3301
+ const { data, isLoading, isFetching, refetch } = useGetAllDocumentsQuery(
3302
+ {
3303
+ model,
3304
+ params: {
3305
+ page: "1",
3306
+ pageSize: documentIds.length.toString(),
3307
+ sort: query.sort,
3308
+ filters: {
3309
+ documentId: {
3310
+ $in: documentIds
3311
+ }
3312
+ },
3313
+ locale: query.plugins?.i18n?.locale
3314
+ }
3315
+ },
3316
+ {
3317
+ selectFromResult: ({ data: data2, ...restRes }) => ({ data: data2?.results ?? [], ...restRes })
3318
+ }
3319
+ );
3320
+ const { rows, validationErrors } = React__namespace.useMemo(() => {
3321
+ if (data.length > 0 && schema) {
3322
+ const validate = createYupSchema(
3323
+ schema.attributes,
3324
+ components,
3325
+ // Since this is the "Publish" action, the validation
3326
+ // schema must enforce the rules for published entities
3327
+ { status: "published" }
3328
+ );
3329
+ const validationErrors2 = {};
3330
+ const rows2 = data.map((entry) => {
3331
+ try {
3332
+ validate.validateSync(entry, { abortEarly: false });
3333
+ return entry;
3334
+ } catch (e) {
3335
+ if (e instanceof yup.ValidationError) {
3336
+ validationErrors2[entry.documentId] = strapiAdmin.getYupValidationErrors(e);
3337
+ }
3338
+ return entry;
3339
+ }
3340
+ });
3341
+ return { rows: rows2, validationErrors: validationErrors2 };
3342
+ }
3343
+ return {
3344
+ rows: [],
3345
+ validationErrors: {}
3346
+ };
3347
+ }, [components, data, schema]);
3348
+ const [publishedCount, setPublishedCount] = React__namespace.useState(0);
3349
+ const [isDialogOpen, setIsDialogOpen] = React__namespace.useState(false);
3350
+ const { publishMany: bulkPublishAction } = useDocumentActions();
3351
+ const [, { isLoading: isSubmittingForm }] = usePublishManyDocumentsMutation();
3352
+ const selectedRows = strapiAdmin.useTable("publishAction", (state) => state.selectedRows);
3353
+ const selectedEntries = rows.filter(
3354
+ (entry) => selectedRows.some((selectedEntry) => selectedEntry.documentId === entry.documentId)
3355
+ );
3356
+ const entriesToPublish = selectedEntries.filter((entry) => !validationErrors[entry.documentId]).map((entry) => entry.documentId);
3357
+ const selectedEntriesWithErrorsCount = selectedEntries.filter(
3358
+ ({ documentId }) => validationErrors[documentId]
3359
+ ).length;
3360
+ const selectedEntriesPublished = selectedEntries.filter(
3361
+ ({ status }) => status === "published"
3362
+ ).length;
3363
+ const selectedEntriesWithNoErrorsCount = selectedEntries.length - selectedEntriesWithErrorsCount - selectedEntriesPublished;
3364
+ const toggleDialog = () => setIsDialogOpen((prev) => !prev);
3365
+ const handleConfirmBulkPublish = async () => {
3366
+ toggleDialog();
3367
+ const res = await bulkPublishAction({ model, documentIds: entriesToPublish, params });
3368
+ if (!("error" in res)) {
3369
+ setPublishedCount(res.count);
3370
+ const unpublishedEntries = rows.filter((row) => {
3371
+ return !entriesToPublish.includes(row.documentId);
3372
+ });
3373
+ setListViewSelectedDocuments(unpublishedEntries);
3374
+ }
3375
+ };
3376
+ const getFormattedCountMessage = () => {
3377
+ if (publishedCount) {
3378
+ return formatMessage(
3379
+ {
3380
+ id: getTranslation("containers.list.selectedEntriesModal.publishedCount"),
3381
+ 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."
3382
+ },
3383
+ {
3384
+ publishedCount,
3385
+ withErrorsCount: selectedEntriesWithErrorsCount,
3386
+ b: BoldChunk
3387
+ }
3388
+ );
3389
+ }
3390
+ return formatMessage(
3391
+ {
3392
+ id: getTranslation("containers.list.selectedEntriesModal.selectedCount"),
3393
+ 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."
3394
+ },
3395
+ {
3396
+ readyToPublishCount: selectedEntriesWithNoErrorsCount,
3397
+ withErrorsCount: selectedEntriesWithErrorsCount,
3398
+ alreadyPublishedCount: selectedEntriesPublished,
3399
+ b: BoldChunk
3400
+ }
3401
+ );
3402
+ };
3403
+ return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
3404
+ /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Modal.Body, { children: [
3405
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { children: getFormattedCountMessage() }),
3406
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Box, { marginTop: 5, children: /* @__PURE__ */ jsxRuntime.jsx(
3407
+ SelectedEntriesTableContent,
3408
+ {
3409
+ isPublishing: isSubmittingForm,
3410
+ rowsToDisplay: rows,
3411
+ entriesToPublish,
3412
+ validationErrors
3413
+ }
3414
+ ) })
3415
+ ] }),
3416
+ /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Modal.Footer, { children: [
3417
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Button, { onClick: toggleModal, variant: "tertiary", children: formatMessage({
3418
+ id: "app.components.Button.cancel",
3419
+ defaultMessage: "Cancel"
3420
+ }) }),
3421
+ /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { gap: 2, children: [
3422
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Button, { onClick: refetch, variant: "tertiary", loading: isFetching, children: formatMessage({ id: "app.utils.refresh", defaultMessage: "Refresh" }) }),
3423
+ /* @__PURE__ */ jsxRuntime.jsx(
3424
+ designSystem.Button,
3425
+ {
3426
+ onClick: toggleDialog,
3427
+ disabled: selectedEntries.length === 0 || selectedEntries.length === selectedEntriesWithErrorsCount || selectedEntriesPublished === selectedEntries.length || isLoading,
3428
+ loading: isSubmittingForm,
3429
+ children: formatMessage({ id: "app.utils.publish", defaultMessage: "Publish" })
3430
+ }
3431
+ )
3432
+ ] })
3433
+ ] }),
3434
+ /* @__PURE__ */ jsxRuntime.jsx(
3435
+ ConfirmDialogPublishAll,
3436
+ {
3437
+ isOpen: isDialogOpen,
3438
+ onToggleDialog: toggleDialog,
3439
+ isConfirmButtonLoading: isSubmittingForm,
3440
+ onConfirm: handleConfirmBulkPublish
3441
+ }
3442
+ )
3443
+ ] });
3444
+ };
3445
+ const PublishAction = ({ documents, model }) => {
3446
+ const { formatMessage } = reactIntl.useIntl();
3447
+ const hasPublishPermission = useDocumentRBAC("unpublishAction", (state) => state.canPublish);
3448
+ const showPublishButton = hasPublishPermission && documents.some(({ status }) => status !== "published");
3449
+ const setListViewSelectedDocuments = strapiAdmin.useTable("publishAction", (state) => state.selectRow);
3450
+ const refetchList = () => {
3451
+ contentManagerApi.util.invalidateTags([{ type: "Document", id: `${model}_LIST` }]);
3452
+ };
3453
+ if (!showPublishButton)
3454
+ return null;
3455
+ return {
3456
+ actionType: "publish",
3457
+ variant: "tertiary",
3458
+ label: formatMessage({ id: "app.utils.publish", defaultMessage: "Publish" }),
3459
+ dialog: {
3460
+ type: "modal",
3461
+ title: formatMessage({
3462
+ id: getTranslation("containers.ListPage.selectedEntriesModal.title"),
3463
+ defaultMessage: "Publish entries"
3464
+ }),
3465
+ content: ({ onClose }) => {
3466
+ return /* @__PURE__ */ jsxRuntime.jsx(strapiAdmin.Table.Root, { rows: documents, defaultSelectedRows: documents, headers: TABLE_HEADERS, children: /* @__PURE__ */ jsxRuntime.jsx(
3467
+ SelectedEntriesModalContent,
3468
+ {
3469
+ listViewSelectedEntries: documents,
3470
+ toggleModal: () => {
3471
+ onClose();
3472
+ refetchList();
3473
+ },
3474
+ setListViewSelectedDocuments,
3475
+ model
3476
+ }
3477
+ ) });
3478
+ },
3479
+ onClose: () => {
3480
+ refetchList();
3481
+ }
3482
+ }
3483
+ };
3484
+ };
3485
+ const BulkActionsRenderer = () => {
3486
+ const plugins = strapiAdmin.useStrapiApp("BulkActionsRenderer", (state) => state.plugins);
3487
+ const { model, collectionType } = useDoc();
3488
+ const { selectedRows } = strapiAdmin.useTable("BulkActionsRenderer", (state) => state);
3489
+ return /* @__PURE__ */ jsxRuntime.jsx(designSystem.Flex, { gap: 2, children: /* @__PURE__ */ jsxRuntime.jsx(
3490
+ strapiAdmin.DescriptionComponentRenderer,
3491
+ {
3492
+ props: {
3493
+ model,
3494
+ collectionType,
3495
+ documents: selectedRows
3496
+ },
3497
+ descriptions: plugins["content-manager"].apis.getBulkActions(),
3498
+ children: (actions2) => actions2.map((action) => /* @__PURE__ */ jsxRuntime.jsx(DocumentActionButton, { ...action }, action.id))
3499
+ }
3500
+ ) });
3501
+ };
3502
+ const DeleteAction = ({ documents, model }) => {
3503
+ const { formatMessage } = reactIntl.useIntl();
3504
+ const { schema: contentType } = useDoc();
3505
+ const selectRow = strapiAdmin.useTable("DeleteAction", (state) => state.selectRow);
3506
+ const hasI18nEnabled = Boolean(contentType?.pluginOptions?.i18n);
3507
+ const [{ query }] = strapiAdmin.useQueryParams();
3508
+ const params = React__namespace.useMemo(() => buildValidParams(query), [query]);
3509
+ const hasDeletePermission = useDocumentRBAC("deleteAction", (state) => state.canDelete);
3510
+ const { deleteMany: bulkDeleteAction } = useDocumentActions();
3511
+ const documentIds = documents.map(({ documentId }) => documentId);
3512
+ const handleConfirmBulkDelete = async () => {
3513
+ const res = await bulkDeleteAction({
3514
+ documentIds,
3515
+ model,
3516
+ params
3517
+ });
3518
+ if (!("error" in res)) {
3519
+ selectRow([]);
3520
+ }
3521
+ };
3522
+ if (!hasDeletePermission)
3523
+ return null;
3524
+ return {
3525
+ variant: "danger-light",
3526
+ label: formatMessage({ id: "global.delete", defaultMessage: "Delete" }),
3527
+ dialog: {
3528
+ type: "dialog",
3529
+ title: formatMessage({
3530
+ id: "app.components.ConfirmDialog.title",
3531
+ defaultMessage: "Confirmation"
3532
+ }),
3533
+ content: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { direction: "column", alignItems: "stretch", gap: 2, children: [
3534
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Flex, { justifyContent: "center", children: /* @__PURE__ */ jsxRuntime.jsx(Icons.WarningCircle, { width: "24px", height: "24px", fill: "danger600" }) }),
3535
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { id: "confirm-description", textAlign: "center", children: formatMessage({
3536
+ id: "popUpWarning.bodyMessage.contentType.delete.all",
3537
+ defaultMessage: "Are you sure you want to delete these entries?"
3538
+ }) }),
3539
+ hasI18nEnabled && /* @__PURE__ */ jsxRuntime.jsx(designSystem.Box, { textAlign: "center", padding: 3, children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { textColor: "danger500", children: formatMessage(
3540
+ {
3541
+ id: getTranslation("Settings.list.actions.deleteAdditionalInfos"),
3542
+ defaultMessage: "This will delete the active locale versions <em>(from Internationalization)</em>"
3543
+ },
3544
+ {
3545
+ em: Emphasis
3546
+ }
3547
+ ) }) })
3548
+ ] }),
3549
+ onConfirm: handleConfirmBulkDelete
3550
+ }
3551
+ };
3552
+ };
3553
+ DeleteAction.type = "delete";
3554
+ const UnpublishAction = ({ documents, model }) => {
3555
+ const { formatMessage } = reactIntl.useIntl();
3556
+ const { schema } = useDoc();
3557
+ const selectRow = strapiAdmin.useTable("UnpublishAction", (state) => state.selectRow);
3558
+ const hasPublishPermission = useDocumentRBAC("unpublishAction", (state) => state.canPublish);
3559
+ const hasI18nEnabled = Boolean(schema?.pluginOptions?.i18n);
3560
+ const hasDraftAndPublishEnabled = Boolean(schema?.options?.draftAndPublish);
3561
+ const { unpublishMany: bulkUnpublishAction } = useDocumentActions();
3562
+ const documentIds = documents.map(({ documentId }) => documentId);
3563
+ const [{ query }] = strapiAdmin.useQueryParams();
3564
+ const params = React__namespace.useMemo(() => buildValidParams(query), [query]);
3565
+ const handleConfirmBulkUnpublish = async () => {
3566
+ const data = await bulkUnpublishAction({ documentIds, model, params });
3567
+ if (!("error" in data)) {
3568
+ selectRow([]);
3569
+ }
3570
+ };
3571
+ const showUnpublishButton = hasDraftAndPublishEnabled && hasPublishPermission && documents.some((entry) => entry.status === "published" || entry.status === "modified");
3572
+ if (!showUnpublishButton)
3573
+ return null;
3574
+ return {
3575
+ variant: "tertiary",
3576
+ label: formatMessage({ id: "app.utils.unpublish", defaultMessage: "Unpublish" }),
3577
+ dialog: {
3578
+ type: "dialog",
3579
+ title: formatMessage({
3580
+ id: "app.components.ConfirmDialog.title",
3581
+ defaultMessage: "Confirmation"
3582
+ }),
3583
+ content: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { direction: "column", alignItems: "stretch", gap: 2, children: [
3584
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Flex, { justifyContent: "center", children: /* @__PURE__ */ jsxRuntime.jsx(Icons.WarningCircle, { width: "24px", height: "24px", fill: "danger600" }) }),
3585
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { id: "confirm-description", textAlign: "center", children: formatMessage({
3586
+ id: "popUpWarning.bodyMessage.contentType.unpublish.all",
3587
+ defaultMessage: "Are you sure you want to unpublish these entries?"
3588
+ }) }),
3589
+ hasI18nEnabled && /* @__PURE__ */ jsxRuntime.jsx(designSystem.Box, { textAlign: "center", padding: 3, children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { textColor: "danger500", children: formatMessage(
3590
+ {
3591
+ id: getTranslation("Settings.list.actions.unpublishAdditionalInfos"),
3592
+ defaultMessage: "This will unpublish the active locale versions <em>(from Internationalization)</em>"
3593
+ },
3594
+ {
3595
+ em: Emphasis
3596
+ }
3597
+ ) }) })
3598
+ ] }),
3599
+ confirmButton: formatMessage({
3600
+ id: "app.utils.unpublish",
3601
+ defaultMessage: "Unpublish"
3602
+ }),
3603
+ onConfirm: handleConfirmBulkUnpublish
3604
+ }
3605
+ };
3606
+ };
3607
+ UnpublishAction.type = "unpublish";
3608
+ const Emphasis = (chunks) => /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { fontWeight: "semiBold", textColor: "danger500", children: chunks });
3609
+ const DEFAULT_BULK_ACTIONS = [PublishAction, UnpublishAction, DeleteAction];
2467
3610
  const AutoCloneFailureModalBody = ({ prohibitedFields }) => {
2468
3611
  const { formatMessage } = reactIntl.useIntl();
2469
3612
  const getDefaultErrorMessage = (reason) => {
@@ -2495,7 +3638,7 @@ const AutoCloneFailureModalBody = ({ prohibitedFields }) => {
2495
3638
  hasRadius: true,
2496
3639
  padding: 6,
2497
3640
  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: [
3641
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Flex, { direction: "row", tag: "ol", children: fieldPath.map((pathSegment, index2) => /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Typography, { fontWeight: "semiBold", tag: "li", children: [
2499
3642
  pathSegment,
2500
3643
  index2 !== fieldPath.length - 1 && /* @__PURE__ */ jsxRuntime.jsx(
2501
3644
  Icons.ChevronRight,
@@ -2507,7 +3650,7 @@ const AutoCloneFailureModalBody = ({ prohibitedFields }) => {
2507
3650
  }
2508
3651
  )
2509
3652
  ] }, index2)) }),
2510
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { as: "p", textColor: "neutral600", children: formatMessage({
3653
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { tag: "p", textColor: "neutral600", children: formatMessage({
2511
3654
  id: getTranslation(`containers.list.autoCloneModal.error.${reason}`),
2512
3655
  defaultMessage: getDefaultErrorMessage(reason)
2513
3656
  }) })
@@ -2532,7 +3675,7 @@ const TableActions = ({ document }) => {
2532
3675
  strapiAdmin.DescriptionComponentRenderer,
2533
3676
  {
2534
3677
  props,
2535
- descriptions: plugins["content-manager"].apis.getDocumentActions(),
3678
+ descriptions: plugins["content-manager"].apis.getDocumentActions().filter((action) => action.name !== "PublishAction"),
2536
3679
  children: (actions2) => {
2537
3680
  const tableRowActions = actions2.filter((action) => {
2538
3681
  const positions = Array.isArray(action.position) ? action.position : [action.position];
@@ -2591,7 +3734,7 @@ const EditAction = ({ documentId }) => {
2591
3734
  };
2592
3735
  };
2593
3736
  EditAction.type = "edit";
2594
- const StyledPencil = styled__default.default(Icons.Pencil)`
3737
+ const StyledPencil = styledComponents.styled(Icons.Pencil)`
2595
3738
  path {
2596
3739
  fill: currentColor;
2597
3740
  }
@@ -2643,7 +3786,7 @@ const CloneAction = ({ model, documentId }) => {
2643
3786
  }),
2644
3787
  content: /* @__PURE__ */ jsxRuntime.jsx(AutoCloneFailureModalBody, { prohibitedFields }),
2645
3788
  footer: ({ onClose }) => {
2646
- return /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { justifyContent: "space-between", children: [
3789
+ return /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Modal.Footer, { children: [
2647
3790
  /* @__PURE__ */ jsxRuntime.jsx(designSystem.Button, { onClick: onClose, variant: "tertiary", children: formatMessage({
2648
3791
  id: "cancel",
2649
3792
  defaultMessage: "Cancel"
@@ -2651,7 +3794,7 @@ const CloneAction = ({ model, documentId }) => {
2651
3794
  /* @__PURE__ */ jsxRuntime.jsx(
2652
3795
  designSystem.LinkButton,
2653
3796
  {
2654
- as: reactRouterDom.NavLink,
3797
+ tag: reactRouterDom.NavLink,
2655
3798
  to: {
2656
3799
  pathname: `clone/${documentId}`
2657
3800
  },
@@ -2667,7 +3810,7 @@ const CloneAction = ({ model, documentId }) => {
2667
3810
  };
2668
3811
  };
2669
3812
  CloneAction.type = "clone";
2670
- const StyledDuplicate = styled__default.default(Icons.Duplicate)`
3813
+ const StyledDuplicate = styledComponents.styled(Icons.Duplicate)`
2671
3814
  path {
2672
3815
  fill: currentColor;
2673
3816
  }
@@ -2684,442 +3827,183 @@ class ContentManagerPlugin {
2684
3827
  documentActions = [
2685
3828
  ...DEFAULT_ACTIONS,
2686
3829
  ...DEFAULT_TABLE_ROW_ACTIONS,
2687
- ...DEFAULT_HEADER_ACTIONS,
2688
- HistoryAction
3830
+ ...DEFAULT_HEADER_ACTIONS
2689
3831
  ];
2690
3832
  editViewSidePanels = [ActionsPanel];
2691
3833
  headerActions = [];
2692
3834
  constructor() {
2693
3835
  }
2694
3836
  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);
3837
+ if (Array.isArray(panels)) {
3838
+ this.editViewSidePanels = [...this.editViewSidePanels, ...panels];
3839
+ } else if (typeof panels === "function") {
3840
+ this.editViewSidePanels = panels(this.editViewSidePanels);
2725
3841
  } else {
2726
3842
  throw new Error(
2727
- `Expected the \`actions\` passed to \`addDocumentHeaderAction\` to be an array or a function, but received ${getPrintableType(
2728
- actions2
3843
+ `Expected the \`panels\` passed to \`addEditViewSidePanel\` to be an array or a function, but received ${getPrintableType(
3844
+ panels
2729
3845
  )}`
2730
3846
  );
2731
3847
  }
2732
3848
  }
2733
- addBulkAction(actions2) {
3849
+ addDocumentAction(actions2) {
2734
3850
  if (Array.isArray(actions2)) {
2735
- this.bulkActions = [...this.bulkActions, ...actions2];
3851
+ this.documentActions = [...this.documentActions, ...actions2];
2736
3852
  } else if (typeof actions2 === "function") {
2737
- this.bulkActions = actions2(this.bulkActions);
3853
+ this.documentActions = actions2(this.documentActions);
2738
3854
  } else {
2739
3855
  throw new Error(
2740
- `Expected the \`actions\` passed to \`addBulkAction\` to be an array or a function, but received ${getPrintableType(
3856
+ `Expected the \`actions\` passed to \`addDocumentAction\` to be an array or a function, but received ${getPrintableType(
2741
3857
  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;
3858
+ )}`
3859
+ );
3860
+ }
3861
+ }
3862
+ addDocumentHeaderAction(actions2) {
3863
+ if (Array.isArray(actions2)) {
3864
+ this.headerActions = [...this.headerActions, ...actions2];
3865
+ } else if (typeof actions2 === "function") {
3866
+ this.headerActions = actions2(this.headerActions);
2982
3867
  } else {
2983
- if (!panels[currentPanelIndex]) {
2984
- panels.push([]);
2985
- }
2986
- panels[currentPanelIndex].push(row);
3868
+ throw new Error(
3869
+ `Expected the \`actions\` passed to \`addDocumentHeaderAction\` to be an array or a function, but received ${getPrintableType(
3870
+ actions2
3871
+ )}`
3872
+ );
2987
3873
  }
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
3874
+ }
3875
+ addBulkAction(actions2) {
3876
+ if (Array.isArray(actions2)) {
3877
+ this.bulkActions = [...this.bulkActions, ...actions2];
3878
+ } else if (typeof actions2 === "function") {
3879
+ this.bulkActions = actions2(this.bulkActions);
3880
+ } else {
3881
+ throw new Error(
3882
+ `Expected the \`actions\` passed to \`addBulkAction\` to be an array or a function, but received ${getPrintableType(
3883
+ actions2
3884
+ )}`
3885
+ );
3029
3886
  }
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;
3887
+ }
3888
+ get config() {
3889
+ return {
3890
+ id: PLUGIN_ID,
3891
+ name: "Content Manager",
3892
+ injectionZones: INJECTION_ZONES,
3893
+ apis: {
3894
+ addBulkAction: this.addBulkAction.bind(this),
3895
+ addDocumentAction: this.addDocumentAction.bind(this),
3896
+ addDocumentHeaderAction: this.addDocumentHeaderAction.bind(this),
3897
+ addEditViewSidePanel: this.addEditViewSidePanel.bind(this),
3898
+ getBulkActions: () => this.bulkActions,
3899
+ getDocumentActions: () => this.documentActions,
3900
+ getEditViewSidePanels: () => this.editViewSidePanels,
3901
+ getHeaderActions: () => this.headerActions
3038
3902
  }
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
- );
3903
+ };
3904
+ }
3905
+ }
3906
+ const getPrintableType = (value) => {
3907
+ const nativeType = typeof value;
3908
+ if (nativeType === "object") {
3909
+ if (value === null)
3910
+ return "null";
3911
+ if (Array.isArray(value))
3912
+ return "array";
3913
+ if (value instanceof Object && value.constructor.name !== "Object") {
3914
+ return value.constructor.name;
3915
+ }
3916
+ }
3917
+ return nativeType;
3061
3918
  };
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
- );
3919
+ const HistoryAction = ({ model, document }) => {
3920
+ const { formatMessage } = reactIntl.useIntl();
3921
+ const [{ query }] = strapiAdmin.useQueryParams();
3922
+ const navigate = reactRouterDom.useNavigate();
3923
+ const pluginsQueryParams = qs.stringify({ plugins: query.plugins }, { encode: false });
3924
+ if (!window.strapi.features.isEnabled("cms-content-history")) {
3925
+ return null;
3926
+ }
3083
3927
  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
- }
3928
+ icon: /* @__PURE__ */ jsxRuntime.jsx(Icons.ClockCounterClockwise, {}),
3929
+ label: formatMessage({
3930
+ id: "content-manager.history.document-action",
3931
+ defaultMessage: "Content History"
3932
+ }),
3933
+ onClick: () => navigate({ pathname: "history", search: pluginsQueryParams }),
3934
+ disabled: (
3935
+ /**
3936
+ * The user is creating a new document.
3937
+ * It hasn't been saved yet, so there's no history to go to
3938
+ */
3939
+ !document || /**
3940
+ * The document has been created but the current dimension has never been saved.
3941
+ * For example, the user is creating a new locale in an existing document,
3942
+ * so there's no history for the document in that locale
3943
+ */
3944
+ !document.id || /**
3945
+ * History is only available for content types created by the user.
3946
+ * These have the `api::` prefix, as opposed to the ones created by Strapi or plugins,
3947
+ * which start with `admin::` or `plugin::`
3948
+ */
3949
+ !model.startsWith("api::")
3950
+ ),
3951
+ position: "header"
3092
3952
  };
3093
3953
  };
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);
3954
+ HistoryAction.type = "history";
3955
+ const historyAdmin = {
3956
+ bootstrap(app) {
3957
+ const { addDocumentAction } = app.getPlugin("content-manager").apis;
3958
+ addDocumentAction((actions2) => {
3959
+ const indexOfDeleteAction = actions2.findIndex((action) => action.type === "delete");
3960
+ actions2.splice(indexOfDeleteAction, 0, HistoryAction);
3961
+ return actions2;
3962
+ });
3963
+ }
3964
+ };
3965
+ const initialState = {
3966
+ collectionTypeLinks: [],
3967
+ components: [],
3968
+ fieldSizes: {},
3969
+ models: [],
3970
+ singleTypeLinks: [],
3971
+ isLoading: true
3114
3972
  };
3973
+ const appSlice = toolkit.createSlice({
3974
+ name: "app",
3975
+ initialState,
3976
+ reducers: {
3977
+ setInitialData(state, action) {
3978
+ const {
3979
+ authorizedCollectionTypeLinks,
3980
+ authorizedSingleTypeLinks,
3981
+ components,
3982
+ contentTypeSchemas,
3983
+ fieldSizes
3984
+ } = action.payload;
3985
+ state.collectionTypeLinks = authorizedCollectionTypeLinks.filter(
3986
+ ({ isDisplayed }) => isDisplayed
3987
+ );
3988
+ state.singleTypeLinks = authorizedSingleTypeLinks.filter(({ isDisplayed }) => isDisplayed);
3989
+ state.components = components;
3990
+ state.models = contentTypeSchemas;
3991
+ state.fieldSizes = fieldSizes;
3992
+ state.isLoading = false;
3993
+ }
3994
+ }
3995
+ });
3996
+ const { actions, reducer: reducer$1 } = appSlice;
3997
+ const { setInitialData } = actions;
3998
+ const reducer = toolkit.combineReducers({
3999
+ app: reducer$1
4000
+ });
3115
4001
  const index = {
3116
4002
  register(app) {
3117
4003
  const cm = new ContentManagerPlugin();
3118
4004
  app.addReducers({
3119
- [contentManagerApi.reducerPath]: contentManagerApi.reducer,
3120
4005
  [PLUGIN_ID]: reducer
3121
4006
  });
3122
- app.addMiddlewares([() => contentManagerApi.middleware]);
3123
4007
  app.addMenuLink({
3124
4008
  to: PLUGIN_ID,
3125
4009
  icon: Icons.Feather,
@@ -3128,14 +4012,29 @@ const index = {
3128
4012
  defaultMessage: "Content Manager"
3129
4013
  },
3130
4014
  permissions: [],
3131
- Component: () => Promise.resolve().then(() => require("./layout-dBc7wN7L.js")).then((mod) => ({ default: mod.Layout }))
4015
+ position: 1
4016
+ });
4017
+ app.router.addRoute({
4018
+ path: "content-manager/*",
4019
+ lazy: async () => {
4020
+ const { Layout } = await Promise.resolve().then(() => require("./layout-CxxkX9jY.js"));
4021
+ return {
4022
+ Component: Layout
4023
+ };
4024
+ },
4025
+ children: routes
3132
4026
  });
3133
4027
  app.registerPlugin(cm.config);
3134
4028
  },
4029
+ bootstrap(app) {
4030
+ if (typeof historyAdmin.bootstrap === "function") {
4031
+ historyAdmin.bootstrap(app);
4032
+ }
4033
+ },
3135
4034
  async registerTrads({ locales }) {
3136
4035
  const importedTrads = await Promise.all(
3137
4036
  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 }) => {
4037
+ 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-BlhnxQfj.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
4038
  return {
3140
4039
  data: prefixPluginTranslations(data, PLUGIN_ID),
3141
4040
  locale
@@ -3152,6 +4051,8 @@ const index = {
3152
4051
  }
3153
4052
  };
3154
4053
  exports.ATTRIBUTE_TYPES_THAT_CANNOT_BE_MAIN_FIELD = ATTRIBUTE_TYPES_THAT_CANNOT_BE_MAIN_FIELD;
4054
+ exports.BulkActionsRenderer = BulkActionsRenderer;
4055
+ exports.CLONE_PATH = CLONE_PATH;
3155
4056
  exports.COLLECTION_TYPES = COLLECTION_TYPES;
3156
4057
  exports.CREATOR_FIELDS = CREATOR_FIELDS;
3157
4058
  exports.DEFAULT_SETTINGS = DEFAULT_SETTINGS;
@@ -3178,8 +4079,8 @@ exports.getDisplayName = getDisplayName;
3178
4079
  exports.getMainField = getMainField;
3179
4080
  exports.getTranslation = getTranslation;
3180
4081
  exports.index = index;
3181
- exports.routes = routes;
3182
4082
  exports.setInitialData = setInitialData;
4083
+ exports.useContentManagerContext = useContentManagerContext;
3183
4084
  exports.useContentTypeSchema = useContentTypeSchema;
3184
4085
  exports.useDoc = useDoc;
3185
4086
  exports.useDocLayout = useDocLayout;
@@ -3192,4 +4093,4 @@ exports.useGetAllDocumentsQuery = useGetAllDocumentsQuery;
3192
4093
  exports.useGetContentTypeConfigurationQuery = useGetContentTypeConfigurationQuery;
3193
4094
  exports.useGetInitialDataQuery = useGetInitialDataQuery;
3194
4095
  exports.useUpdateContentTypeConfigurationMutation = useUpdateContentTypeConfigurationMutation;
3195
- //# sourceMappingURL=index-X_2tafck.js.map
4096
+ //# sourceMappingURL=index-CBX6KyXv.js.map