@strapi/content-releases 0.0.0-experimental.d53e940834bf72ddc725f1d2fd36dac9abec30cb → 0.0.0-experimental.d65615a2b9130dd742d3c396674457d7971da928

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 (101) hide show
  1. package/LICENSE +17 -1
  2. package/dist/_chunks/{App-CEwOQkKT.js → App-BKB1esYS.js} +314 -264
  3. package/dist/_chunks/App-BKB1esYS.js.map +1 -0
  4. package/dist/_chunks/{App-B2R2exNT.mjs → App-Cne--1Z8.mjs} +317 -266
  5. package/dist/_chunks/App-Cne--1Z8.mjs.map +1 -0
  6. package/dist/_chunks/ReleasesSettingsPage-C1WwGWIH.mjs +178 -0
  7. package/dist/_chunks/ReleasesSettingsPage-C1WwGWIH.mjs.map +1 -0
  8. package/dist/_chunks/ReleasesSettingsPage-kuXIwpWp.js +178 -0
  9. package/dist/_chunks/ReleasesSettingsPage-kuXIwpWp.js.map +1 -0
  10. package/dist/_chunks/{en-DtFJ5ViE.js → en-CmYoEnA7.js} +9 -2
  11. package/dist/_chunks/en-CmYoEnA7.js.map +1 -0
  12. package/dist/_chunks/{en-B9Ur3VsE.mjs → en-D0yVZFqf.mjs} +9 -2
  13. package/dist/_chunks/en-D0yVZFqf.mjs.map +1 -0
  14. package/dist/_chunks/{index-BrWv-zV4.js → index-5Odi61vw.js} +793 -441
  15. package/dist/_chunks/index-5Odi61vw.js.map +1 -0
  16. package/dist/_chunks/index-Cy7qwpaU.mjs +1362 -0
  17. package/dist/_chunks/index-Cy7qwpaU.mjs.map +1 -0
  18. package/dist/_chunks/schemas-BE1LxE9J.js +62 -0
  19. package/dist/_chunks/schemas-BE1LxE9J.js.map +1 -0
  20. package/dist/_chunks/schemas-DdA2ic2U.mjs +44 -0
  21. package/dist/_chunks/schemas-DdA2ic2U.mjs.map +1 -0
  22. package/dist/admin/index.js +1 -1
  23. package/dist/admin/index.mjs +2 -2
  24. package/dist/admin/src/components/ReleaseActionMenu.d.ts +2 -2
  25. package/dist/admin/src/components/{CMReleasesContainer.d.ts → ReleaseActionModal.d.ts} +3 -1
  26. package/dist/admin/src/components/ReleaseListCell.d.ts +28 -0
  27. package/dist/admin/src/components/ReleasesPanel.d.ts +3 -0
  28. package/dist/admin/src/constants.d.ts +18 -0
  29. package/dist/admin/src/modules/hooks.d.ts +7 -0
  30. package/dist/admin/src/pages/ReleasesSettingsPage.d.ts +1 -0
  31. package/dist/admin/src/services/release.d.ts +43 -36
  32. package/dist/admin/src/utils/time.d.ts +9 -0
  33. package/dist/admin/src/validation/schemas.d.ts +6 -0
  34. package/dist/server/index.js +782 -580
  35. package/dist/server/index.js.map +1 -1
  36. package/dist/server/index.mjs +783 -581
  37. package/dist/server/index.mjs.map +1 -1
  38. package/dist/server/src/bootstrap.d.ts.map +1 -1
  39. package/dist/server/src/constants.d.ts +11 -2
  40. package/dist/server/src/constants.d.ts.map +1 -1
  41. package/dist/server/src/content-types/index.d.ts +3 -5
  42. package/dist/server/src/content-types/index.d.ts.map +1 -1
  43. package/dist/server/src/content-types/release-action/index.d.ts +3 -5
  44. package/dist/server/src/content-types/release-action/index.d.ts.map +1 -1
  45. package/dist/server/src/content-types/release-action/schema.d.ts +3 -5
  46. package/dist/server/src/content-types/release-action/schema.d.ts.map +1 -1
  47. package/dist/server/src/controllers/index.d.ts +6 -1
  48. package/dist/server/src/controllers/index.d.ts.map +1 -1
  49. package/dist/server/src/controllers/release-action.d.ts.map +1 -1
  50. package/dist/server/src/controllers/release.d.ts +7 -1
  51. package/dist/server/src/controllers/release.d.ts.map +1 -1
  52. package/dist/server/src/controllers/settings.d.ts +11 -0
  53. package/dist/server/src/controllers/settings.d.ts.map +1 -0
  54. package/dist/server/src/controllers/validation/release-action.d.ts +7 -1
  55. package/dist/server/src/controllers/validation/release-action.d.ts.map +1 -1
  56. package/dist/server/src/controllers/validation/release.d.ts +2 -0
  57. package/dist/server/src/controllers/validation/release.d.ts.map +1 -1
  58. package/dist/server/src/controllers/validation/settings.d.ts +3 -0
  59. package/dist/server/src/controllers/validation/settings.d.ts.map +1 -0
  60. package/dist/server/src/index.d.ts +68 -49
  61. package/dist/server/src/index.d.ts.map +1 -1
  62. package/dist/server/src/middlewares/documents.d.ts +6 -0
  63. package/dist/server/src/middlewares/documents.d.ts.map +1 -0
  64. package/dist/server/src/migrations/database/5.0.0-document-id-in-actions.d.ts +9 -0
  65. package/dist/server/src/migrations/database/5.0.0-document-id-in-actions.d.ts.map +1 -0
  66. package/dist/server/src/migrations/index.d.ts.map +1 -1
  67. package/dist/server/src/register.d.ts.map +1 -1
  68. package/dist/server/src/routes/index.d.ts +16 -0
  69. package/dist/server/src/routes/index.d.ts.map +1 -1
  70. package/dist/server/src/routes/release.d.ts.map +1 -1
  71. package/dist/server/src/routes/settings.d.ts +18 -0
  72. package/dist/server/src/routes/settings.d.ts.map +1 -0
  73. package/dist/server/src/services/index.d.ts +40 -38
  74. package/dist/server/src/services/index.d.ts.map +1 -1
  75. package/dist/server/src/services/release-action.d.ts +38 -0
  76. package/dist/server/src/services/release-action.d.ts.map +1 -0
  77. package/dist/server/src/services/release.d.ts +6 -41
  78. package/dist/server/src/services/release.d.ts.map +1 -1
  79. package/dist/server/src/services/settings.d.ts +13 -0
  80. package/dist/server/src/services/settings.d.ts.map +1 -0
  81. package/dist/server/src/services/validation.d.ts +1 -1
  82. package/dist/server/src/services/validation.d.ts.map +1 -1
  83. package/dist/server/src/utils/index.d.ts +29 -8
  84. package/dist/server/src/utils/index.d.ts.map +1 -1
  85. package/dist/shared/contracts/release-actions.d.ts +9 -10
  86. package/dist/shared/contracts/release-actions.d.ts.map +1 -1
  87. package/dist/shared/contracts/releases.d.ts +9 -7
  88. package/dist/shared/contracts/releases.d.ts.map +1 -1
  89. package/dist/shared/contracts/settings.d.ts +39 -0
  90. package/dist/shared/contracts/settings.d.ts.map +1 -0
  91. package/package.json +15 -13
  92. package/dist/_chunks/App-B2R2exNT.mjs.map +0 -1
  93. package/dist/_chunks/App-CEwOQkKT.js.map +0 -1
  94. package/dist/_chunks/en-B9Ur3VsE.mjs.map +0 -1
  95. package/dist/_chunks/en-DtFJ5ViE.js.map +0 -1
  96. package/dist/_chunks/index-BrWv-zV4.js.map +0 -1
  97. package/dist/_chunks/index-DbmynICx.mjs +0 -1010
  98. package/dist/_chunks/index-DbmynICx.mjs.map +0 -1
  99. package/dist/shared/validation-schemas.d.ts +0 -2
  100. package/dist/shared/validation-schemas.d.ts.map +0 -1
  101. package/strapi-server.js +0 -3
@@ -1,17 +1,16 @@
1
1
  "use strict";
2
2
  const icons = require("@strapi/icons");
3
3
  const jsxRuntime = require("react/jsx-runtime");
4
- const React = require("react");
5
- const query = require("@reduxjs/toolkit/query");
6
4
  const strapiAdmin = require("@strapi/admin/strapi-admin");
7
- const strapiAdmin$1 = require("@strapi/content-manager/strapi-admin");
8
5
  const designSystem = require("@strapi/design-system");
9
- const symbols = require("@strapi/icons/symbols");
10
6
  const formik = require("formik");
11
7
  const reactIntl = require("react-intl");
8
+ const strapiAdmin$1 = require("@strapi/content-manager/strapi-admin");
9
+ const symbols = require("@strapi/icons/symbols");
12
10
  const reactRouterDom = require("react-router-dom");
13
11
  const yup = require("yup");
14
12
  const styledComponents = require("styled-components");
13
+ const React = require("react");
15
14
  function _interopNamespace(e) {
16
15
  if (e && e.__esModule)
17
16
  return e;
@@ -30,8 +29,8 @@ function _interopNamespace(e) {
30
29
  n.default = e;
31
30
  return Object.freeze(n);
32
31
  }
33
- const React__namespace = /* @__PURE__ */ _interopNamespace(React);
34
32
  const yup__namespace = /* @__PURE__ */ _interopNamespace(yup);
33
+ const React__namespace = /* @__PURE__ */ _interopNamespace(React);
35
34
  const __variableDynamicImportRuntimeHelper = (glob, path) => {
36
35
  const v = glob[path];
37
36
  if (v) {
@@ -113,15 +112,52 @@ const PERMISSIONS = {
113
112
  }
114
113
  ]
115
114
  };
115
+ const extendInvalidatesTags = (endpoint, extraTags) => {
116
+ if (!endpoint) {
117
+ return;
118
+ }
119
+ const originalInvalidatesTags = endpoint.invalidatesTags;
120
+ const newInvalidatesTags = (result, err, args, meta) => {
121
+ const originalTags = typeof originalInvalidatesTags === "function" ? originalInvalidatesTags(result, err, args, meta) : originalInvalidatesTags;
122
+ return [...originalTags ?? [], ...extraTags];
123
+ };
124
+ Object.assign(endpoint, { invalidatesTags: newInvalidatesTags });
125
+ };
116
126
  const releaseApi = strapiAdmin.adminApi.enhanceEndpoints({
117
- addTagTypes: ["Release", "ReleaseAction", "EntriesInRelease"]
127
+ addTagTypes: ["Release", "ReleaseAction", "EntriesInRelease", "ReleaseSettings", "Document"],
128
+ endpoints: {
129
+ updateDocument(endpoint) {
130
+ extendInvalidatesTags(endpoint, [
131
+ { type: "Release", id: "LIST" },
132
+ { type: "ReleaseAction", id: "LIST" }
133
+ ]);
134
+ },
135
+ deleteDocument(endpoint) {
136
+ extendInvalidatesTags(endpoint, [
137
+ { type: "Release", id: "LIST" },
138
+ { type: "ReleaseAction", id: "LIST" }
139
+ ]);
140
+ },
141
+ deleteManyDocuments(endpoint) {
142
+ extendInvalidatesTags(endpoint, [
143
+ { type: "Release", id: "LIST" },
144
+ { type: "ReleaseAction", id: "LIST" }
145
+ ]);
146
+ },
147
+ discardDocument(endpoint) {
148
+ extendInvalidatesTags(endpoint, [
149
+ { type: "Release", id: "LIST" },
150
+ { type: "ReleaseAction", id: "LIST" }
151
+ ]);
152
+ }
153
+ }
118
154
  }).injectEndpoints({
119
155
  endpoints: (build) => {
120
156
  return {
121
157
  getReleasesForEntry: build.query({
122
158
  query(params) {
123
159
  return {
124
- url: "/content-releases",
160
+ url: "/content-releases/getByDocumentAttached",
125
161
  method: "GET",
126
162
  config: {
127
163
  params
@@ -183,7 +219,10 @@ const releaseApi = strapiAdmin.adminApi.enhanceEndpoints({
183
219
  method: "GET"
184
220
  };
185
221
  },
186
- providesTags: (result, error, arg) => [{ type: "Release", id: arg.id }]
222
+ providesTags: (result, error, arg) => [
223
+ { type: "Release", id: "LIST" },
224
+ { type: "Release", id: arg.id }
225
+ ]
187
226
  }),
188
227
  getReleaseActions: build.query({
189
228
  query({ releaseId, ...params }) {
@@ -252,11 +291,15 @@ const releaseApi = strapiAdmin.adminApi.enhanceEndpoints({
252
291
  data: body
253
292
  };
254
293
  },
255
- invalidatesTags: () => [{ type: "ReleaseAction", id: "LIST" }],
256
- async onQueryStarted({ body, params, query: query2, actionPath }, { dispatch, queryFulfilled }) {
294
+ invalidatesTags: (res, error, arg) => [
295
+ { type: "ReleaseAction", id: "LIST" },
296
+ { type: "Release", id: "LIST" },
297
+ { type: "Release", id: arg.params.releaseId }
298
+ ],
299
+ async onQueryStarted({ body, params, query, actionPath }, { dispatch, queryFulfilled }) {
257
300
  const paramsWithoutActionId = {
258
301
  releaseId: params.releaseId,
259
- ...query2
302
+ ...query
260
303
  };
261
304
  const patchResult = dispatch(
262
305
  releaseApi.util.updateQueryData(
@@ -299,7 +342,10 @@ const releaseApi = strapiAdmin.adminApi.enhanceEndpoints({
299
342
  method: "POST"
300
343
  };
301
344
  },
302
- invalidatesTags: (result, error, arg) => [{ type: "Release", id: arg.id }]
345
+ invalidatesTags: (result, error, arg) => [
346
+ { type: "Release", id: arg.id },
347
+ { type: "Document", id: `ALL_LIST` }
348
+ ]
303
349
  }),
304
350
  deleteRelease: build.mutation({
305
351
  query({ id }) {
@@ -324,6 +370,20 @@ const releaseApi = strapiAdmin.adminApi.enhanceEndpoints({
324
370
  return response.data;
325
371
  },
326
372
  providesTags: [{ type: "EntriesInRelease" }]
373
+ }),
374
+ getReleaseSettings: build.query({
375
+ query: () => "/content-releases/settings",
376
+ providesTags: [{ type: "ReleaseSettings" }]
377
+ }),
378
+ updateReleaseSettings: build.mutation({
379
+ query(data) {
380
+ return {
381
+ url: "/content-releases/settings",
382
+ method: "PUT",
383
+ data
384
+ };
385
+ },
386
+ invalidatesTags: [{ type: "ReleaseSettings" }]
327
387
  })
328
388
  };
329
389
  }
@@ -341,184 +401,10 @@ const {
341
401
  usePublishReleaseMutation,
342
402
  useDeleteReleaseActionMutation,
343
403
  useDeleteReleaseMutation,
344
- useGetMappedEntriesInReleasesQuery
404
+ useGetMappedEntriesInReleasesQuery,
405
+ useGetReleaseSettingsQuery,
406
+ useUpdateReleaseSettingsMutation
345
407
  } = releaseApi;
346
- const getTimezoneOffset = (timezone, date) => {
347
- try {
348
- const offsetPart = new Intl.DateTimeFormat("en", {
349
- timeZone: timezone,
350
- timeZoneName: "longOffset"
351
- }).formatToParts(date).find((part) => part.type === "timeZoneName");
352
- const offset = offsetPart ? offsetPart.value : "";
353
- let utcOffset = offset.replace("GMT", "UTC");
354
- if (!utcOffset.includes("+") && !utcOffset.includes("-")) {
355
- utcOffset = `${utcOffset}+00:00`;
356
- }
357
- return utcOffset;
358
- } catch (error) {
359
- return "";
360
- }
361
- };
362
- const StyledMenuItem = styledComponents.styled(designSystem.Menu.Item)`
363
- &:hover {
364
- background: ${({ theme, $variant = "neutral" }) => theme.colors[`${$variant}100`]};
365
-
366
- svg {
367
- fill: ${({ theme, $variant = "neutral" }) => theme.colors[`${$variant}600`]};
368
- }
369
-
370
- a {
371
- color: ${({ theme }) => theme.colors.neutral800};
372
- }
373
- }
374
-
375
- svg {
376
- fill: ${({ theme, $variant = "neutral" }) => theme.colors[`${$variant}600`]};
377
- }
378
-
379
- a {
380
- color: ${({ theme }) => theme.colors.neutral800};
381
- }
382
-
383
- span,
384
- a {
385
- width: 100%;
386
- }
387
- `;
388
- const DeleteReleaseActionItem = ({ releaseId, actionId }) => {
389
- const { formatMessage } = reactIntl.useIntl();
390
- const { toggleNotification } = strapiAdmin.useNotification();
391
- const { formatAPIError } = strapiAdmin.useAPIErrorHandler();
392
- const [deleteReleaseAction] = useDeleteReleaseActionMutation();
393
- const {
394
- allowedActions: { canDeleteAction }
395
- } = strapiAdmin.useRBAC(PERMISSIONS);
396
- const handleDeleteAction = async () => {
397
- const response = await deleteReleaseAction({
398
- params: { releaseId, actionId }
399
- });
400
- if ("data" in response) {
401
- toggleNotification({
402
- type: "success",
403
- message: formatMessage({
404
- id: "content-releases.content-manager-edit-view.remove-from-release.notification.success",
405
- defaultMessage: "Entry removed from release"
406
- })
407
- });
408
- return;
409
- }
410
- if ("error" in response) {
411
- if (strapiAdmin.isFetchError(response.error)) {
412
- toggleNotification({
413
- type: "danger",
414
- message: formatAPIError(response.error)
415
- });
416
- } else {
417
- toggleNotification({
418
- type: "danger",
419
- message: formatMessage({ id: "notification.error", defaultMessage: "An error occurred" })
420
- });
421
- }
422
- }
423
- };
424
- if (!canDeleteAction) {
425
- return null;
426
- }
427
- return /* @__PURE__ */ jsxRuntime.jsx(StyledMenuItem, { $variant: "danger", onSelect: handleDeleteAction, children: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { gap: 2, children: [
428
- /* @__PURE__ */ jsxRuntime.jsx(icons.Cross, { width: "1.6rem", height: "1.6rem" }),
429
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { textColor: "danger600", variant: "omega", children: formatMessage({
430
- id: "content-releases.content-manager-edit-view.remove-from-release",
431
- defaultMessage: "Remove from release"
432
- }) })
433
- ] }) });
434
- };
435
- const ReleaseActionEntryLinkItem = ({
436
- contentTypeUid,
437
- entryId,
438
- locale
439
- }) => {
440
- const { formatMessage } = reactIntl.useIntl();
441
- const userPermissions = strapiAdmin.useAuth("ReleaseActionEntryLinkItem", (state) => state.permissions);
442
- const canUpdateEntryForLocale = React__namespace.useMemo(() => {
443
- const updatePermissions = userPermissions.find(
444
- (permission) => permission.subject === contentTypeUid && permission.action === "plugin::content-manager.explorer.update"
445
- );
446
- if (!updatePermissions) {
447
- return false;
448
- }
449
- return Boolean(!locale || updatePermissions.properties?.locales?.includes(locale));
450
- }, [contentTypeUid, locale, userPermissions]);
451
- const {
452
- allowedActions: { canUpdate: canUpdateContentType }
453
- } = strapiAdmin.useRBAC({
454
- updateContentType: [
455
- {
456
- action: "plugin::content-manager.explorer.update",
457
- subject: contentTypeUid
458
- }
459
- ]
460
- });
461
- if (!canUpdateContentType || !canUpdateEntryForLocale) {
462
- return null;
463
- }
464
- return /* @__PURE__ */ jsxRuntime.jsx(
465
- StyledMenuItem,
466
- {
467
- tag: reactRouterDom.Link,
468
- isLink: true,
469
- to: {
470
- pathname: `/content-manager/collection-types/${contentTypeUid}/${entryId}`,
471
- search: locale && `?plugins[i18n][locale]=${locale}`
472
- },
473
- children: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { gap: 2, children: [
474
- /* @__PURE__ */ jsxRuntime.jsx(icons.Pencil, { width: "1.6rem", height: "1.6rem" }),
475
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "omega", children: formatMessage({
476
- id: "content-releases.content-manager-edit-view.edit-entry",
477
- defaultMessage: "Edit entry"
478
- }) })
479
- ] })
480
- }
481
- );
482
- };
483
- const EditReleaseItem = ({ releaseId }) => {
484
- const { formatMessage } = reactIntl.useIntl();
485
- return (
486
- /* @ts-expect-error inference isn't working in DS */
487
- /* @__PURE__ */ jsxRuntime.jsx(StyledMenuItem, { tag: reactRouterDom.Link, isLink: true, to: `/plugins/content-releases/${releaseId}`, children: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { gap: 2, children: [
488
- /* @__PURE__ */ jsxRuntime.jsx(icons.Pencil, { width: "1.6rem", height: "1.6rem" }),
489
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "omega", children: formatMessage({
490
- id: "content-releases.content-manager-edit-view.edit-release",
491
- defaultMessage: "Edit release"
492
- }) })
493
- ] }) })
494
- );
495
- };
496
- const Root = ({ children }) => {
497
- const { formatMessage } = reactIntl.useIntl();
498
- const { allowedActions } = strapiAdmin.useRBAC(PERMISSIONS);
499
- return (
500
- // A user can access the dropdown if they have permissions to delete a release-action OR update a release
501
- allowedActions.canDeleteAction || allowedActions.canUpdate ? /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Menu.Root, { children: [
502
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Menu.Trigger, { paddingLeft: 2, paddingRight: 2, children: /* @__PURE__ */ jsxRuntime.jsx(
503
- designSystem.AccessibleIcon,
504
- {
505
- label: formatMessage({
506
- id: "content-releases.content-manager-edit-view.release-action-menu",
507
- defaultMessage: "Release action options"
508
- }),
509
- children: /* @__PURE__ */ jsxRuntime.jsx(icons.More, {})
510
- }
511
- ) }),
512
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Menu.Content, { top: 1, popoverPlacement: "bottom-end", children })
513
- ] }) : null
514
- );
515
- };
516
- const ReleaseActionMenu = {
517
- Root,
518
- EditReleaseItem,
519
- DeleteReleaseActionItem,
520
- ReleaseActionEntryLinkItem
521
- };
522
408
  const getBorderLeftRadiusValue = (actionType) => {
523
409
  return actionType === "publish" ? 1 : 0;
524
410
  };
@@ -661,294 +547,730 @@ const NoReleases = () => {
661
547
  defaultMessage: "Open the list of releases"
662
548
  })
663
549
  }
664
- )
550
+ ),
551
+ shadow: "none"
665
552
  }
666
553
  );
667
554
  };
668
555
  const AddActionToReleaseModal = ({
669
- open,
670
- onOpenChange,
671
- contentTypeUid,
672
- entryId
556
+ contentType,
557
+ documentId,
558
+ onInputChange,
559
+ values
673
560
  }) => {
674
561
  const { formatMessage } = reactIntl.useIntl();
675
- const { toggleNotification } = strapiAdmin.useNotification();
676
- const { formatAPIError } = strapiAdmin.useAPIErrorHandler();
677
- const [{ query: query2 }] = strapiAdmin.useQueryParams();
678
- const locale = query2.plugins?.i18n?.locale;
562
+ const [{ query }] = strapiAdmin.useQueryParams();
563
+ const locale = query.plugins?.i18n?.locale;
679
564
  const response = useGetReleasesForEntryQuery({
680
- contentTypeUid,
681
- entryId,
682
- hasEntryAttached: false
565
+ contentType,
566
+ entryDocumentId: documentId,
567
+ hasEntryAttached: false,
568
+ locale
683
569
  });
684
570
  const releases = response.data?.data;
571
+ if (releases?.length === 0) {
572
+ return /* @__PURE__ */ jsxRuntime.jsx(NoReleases, {});
573
+ }
574
+ return /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { direction: "column", alignItems: "stretch", gap: 2, children: [
575
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Box, { paddingBottom: 6, children: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Field.Root, { required: true, children: [
576
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Field.Label, { children: formatMessage({
577
+ id: "content-releases.content-manager-edit-view.add-to-release.select-label",
578
+ defaultMessage: "Select a release"
579
+ }) }),
580
+ /* @__PURE__ */ jsxRuntime.jsx(
581
+ designSystem.SingleSelect,
582
+ {
583
+ required: true,
584
+ placeholder: formatMessage({
585
+ id: "content-releases.content-manager-edit-view.add-to-release.select-placeholder",
586
+ defaultMessage: "Select"
587
+ }),
588
+ name: "releaseId",
589
+ onChange: (value) => onInputChange("releaseId", value),
590
+ value: values.releaseId,
591
+ children: releases?.map((release) => /* @__PURE__ */ jsxRuntime.jsx(designSystem.SingleSelectOption, { value: release.id, children: release.name }, release.id))
592
+ }
593
+ )
594
+ ] }) }),
595
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Field.Label, { children: formatMessage({
596
+ id: "content-releases.content-manager-edit-view.add-to-release.action-type-label",
597
+ defaultMessage: "What do you want to do with this entry?"
598
+ }) }),
599
+ /* @__PURE__ */ jsxRuntime.jsx(
600
+ ReleaseActionOptions,
601
+ {
602
+ selected: values.type,
603
+ handleChange: (e) => onInputChange("type", e.target.value),
604
+ name: "type"
605
+ }
606
+ )
607
+ ] });
608
+ };
609
+ const ReleaseActionModalForm = ({
610
+ documentId,
611
+ document,
612
+ model,
613
+ collectionType
614
+ }) => {
615
+ const { formatMessage } = reactIntl.useIntl();
616
+ const { allowedActions } = strapiAdmin.useRBAC(PERMISSIONS);
617
+ const { canCreateAction } = allowedActions;
685
618
  const [createReleaseAction, { isLoading }] = useCreateReleaseActionMutation();
686
- const handleSubmit = async (values) => {
687
- const releaseActionEntry = {
688
- contentType: contentTypeUid,
689
- id: entryId,
690
- locale
691
- };
692
- const response2 = await createReleaseAction({
693
- body: { type: values.type, entry: releaseActionEntry },
694
- params: { releaseId: values.releaseId }
695
- });
696
- if ("data" in response2) {
697
- toggleNotification({
698
- type: "success",
699
- message: formatMessage({
700
- id: "content-releases.content-manager-edit-view.add-to-release.notification.success",
701
- defaultMessage: "Entry added to release"
702
- })
703
- });
704
- onOpenChange();
705
- return;
706
- }
707
- if ("error" in response2) {
708
- if (strapiAdmin.isFetchError(response2.error)) {
619
+ const { toggleNotification } = strapiAdmin.useNotification();
620
+ const { formatAPIError } = strapiAdmin.useAPIErrorHandler();
621
+ const [{ query }] = strapiAdmin.useQueryParams();
622
+ const locale = query.plugins?.i18n?.locale;
623
+ const handleSubmit = async (e, onClose) => {
624
+ try {
625
+ await formik$1.handleSubmit(e);
626
+ onClose();
627
+ } catch (error) {
628
+ if (strapiAdmin.isFetchError(error)) {
709
629
  toggleNotification({
710
630
  type: "danger",
711
- message: formatAPIError(response2.error)
631
+ message: formatAPIError(error)
712
632
  });
713
633
  } else {
714
634
  toggleNotification({
715
635
  type: "danger",
716
- message: formatMessage({ id: "notification.error", defaultMessage: "An error occurred" })
636
+ message: formatMessage({
637
+ id: "notification.error",
638
+ defaultMessage: "An error occurred"
639
+ })
717
640
  });
718
641
  }
719
642
  }
720
643
  };
721
- return /* @__PURE__ */ jsxRuntime.jsx(designSystem.Modal.Root, { open, onOpenChange, children: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Modal.Content, { children: [
722
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Modal.Header, { children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Modal.Title, { fontWeight: "bold", children: formatMessage({
644
+ const formik$1 = formik.useFormik({
645
+ initialValues: INITIAL_VALUES,
646
+ validationSchema: RELEASE_ACTION_FORM_SCHEMA,
647
+ onSubmit: async (values) => {
648
+ if (collectionType === "collection-types" && !documentId) {
649
+ throw new Error("Document id is required");
650
+ }
651
+ const response = await createReleaseAction({
652
+ body: {
653
+ type: values.type,
654
+ contentType: model,
655
+ entryDocumentId: documentId,
656
+ locale
657
+ },
658
+ params: { releaseId: values.releaseId }
659
+ });
660
+ if ("data" in response) {
661
+ toggleNotification({
662
+ type: "success",
663
+ message: formatMessage({
664
+ id: "content-releases.content-manager-edit-view.add-to-release.notification.success",
665
+ defaultMessage: "Entry added to release"
666
+ })
667
+ });
668
+ return;
669
+ }
670
+ if ("error" in response) {
671
+ throw response.error;
672
+ }
673
+ }
674
+ });
675
+ const {
676
+ edit: { options }
677
+ } = strapiAdmin$1.unstable_useDocumentLayout(model);
678
+ if (!window.strapi.isEE || !options?.draftAndPublish || !canCreateAction) {
679
+ return null;
680
+ }
681
+ if (collectionType === "collection-types" && (!documentId || documentId === "create")) {
682
+ return null;
683
+ }
684
+ return {
685
+ label: formatMessage({
723
686
  id: "content-releases.content-manager-edit-view.add-to-release",
724
687
  defaultMessage: "Add to release"
725
- }) }) }),
726
- /* @__PURE__ */ jsxRuntime.jsx(
727
- formik.Formik,
728
- {
729
- onSubmit: handleSubmit,
730
- validationSchema: RELEASE_ACTION_FORM_SCHEMA,
731
- initialValues: INITIAL_VALUES,
732
- children: ({ values, setFieldValue }) => {
733
- return /* @__PURE__ */ jsxRuntime.jsxs(formik.Form, { children: [
734
- releases?.length === 0 ? /* @__PURE__ */ jsxRuntime.jsx(NoReleases, {}) : /* @__PURE__ */ jsxRuntime.jsx(designSystem.Modal.Body, { children: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { direction: "column", alignItems: "stretch", gap: 2, children: [
735
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Box, { paddingBottom: 6, children: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Field.Root, { required: true, children: [
736
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Field.Label, { children: formatMessage({
737
- id: "content-releases.content-manager-edit-view.add-to-release.select-label",
738
- defaultMessage: "Select a release"
739
- }) }),
740
- /* @__PURE__ */ jsxRuntime.jsx(
741
- designSystem.SingleSelect,
742
- {
743
- placeholder: formatMessage({
744
- id: "content-releases.content-manager-edit-view.add-to-release.select-placeholder",
745
- defaultMessage: "Select"
746
- }),
747
- onChange: (value) => setFieldValue("releaseId", value),
748
- value: values.releaseId,
749
- children: releases?.map((release) => /* @__PURE__ */ jsxRuntime.jsx(designSystem.SingleSelectOption, { value: release.id, children: release.name }, release.id))
750
- }
688
+ }),
689
+ icon: /* @__PURE__ */ jsxRuntime.jsx(icons.PaperPlane, {}),
690
+ // Entry is creating so we don't want to allow adding it to a release
691
+ disabled: !document,
692
+ position: ["panel", "table-row"],
693
+ dialog: {
694
+ type: "modal",
695
+ title: formatMessage({
696
+ id: "content-releases.content-manager-edit-view.add-to-release",
697
+ defaultMessage: "Add to release"
698
+ }),
699
+ content: /* @__PURE__ */ jsxRuntime.jsx(
700
+ AddActionToReleaseModal,
701
+ {
702
+ contentType: model,
703
+ documentId,
704
+ onInputChange: formik$1.setFieldValue,
705
+ values: formik$1.values
706
+ }
707
+ ),
708
+ footer: ({ onClose }) => /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Modal.Footer, { children: [
709
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Button, { onClick: onClose, variant: "tertiary", name: "cancel", children: formatMessage({
710
+ id: "content-releases.content-manager-edit-view.add-to-release.cancel-button",
711
+ defaultMessage: "Cancel"
712
+ }) }),
713
+ /* @__PURE__ */ jsxRuntime.jsx(
714
+ designSystem.Button,
715
+ {
716
+ type: "submit",
717
+ onClick: (e) => handleSubmit(e, onClose),
718
+ disabled: !formik$1.values.releaseId,
719
+ loading: isLoading,
720
+ children: formatMessage({
721
+ id: "content-releases.content-manager-edit-view.add-to-release.continue-button",
722
+ defaultMessage: "Continue"
723
+ })
724
+ }
725
+ )
726
+ ] })
727
+ }
728
+ };
729
+ };
730
+ const getContentPermissions = (subject) => {
731
+ const permissions = {
732
+ publish: [
733
+ {
734
+ action: "plugin::content-manager.explorer.publish",
735
+ subject,
736
+ id: "",
737
+ actionParameters: {},
738
+ properties: {},
739
+ conditions: []
740
+ }
741
+ ]
742
+ };
743
+ return permissions;
744
+ };
745
+ const ReleaseAction = ({ documents, model }) => {
746
+ const { formatMessage } = reactIntl.useIntl();
747
+ const { toggleNotification } = strapiAdmin.useNotification();
748
+ const { formatAPIError } = strapiAdmin.useAPIErrorHandler();
749
+ const [{ query }] = strapiAdmin.useQueryParams();
750
+ const contentPermissions = getContentPermissions(model);
751
+ const {
752
+ allowedActions: { canPublish }
753
+ } = strapiAdmin.useRBAC(contentPermissions);
754
+ const {
755
+ allowedActions: { canCreate }
756
+ } = strapiAdmin.useRBAC(PERMISSIONS);
757
+ const response = useGetReleasesQuery();
758
+ const releases = response.data?.data;
759
+ const [createManyReleaseActions, { isLoading }] = useCreateManyReleaseActionsMutation();
760
+ const documentIds = documents.map((doc) => doc.documentId);
761
+ const handleSubmit = async (values) => {
762
+ const locale = query.plugins?.i18n?.locale;
763
+ const releaseActionEntries = documentIds.map(
764
+ (entryDocumentId) => ({
765
+ type: values.type,
766
+ contentType: model,
767
+ entryDocumentId,
768
+ locale
769
+ })
770
+ );
771
+ const response2 = await createManyReleaseActions({
772
+ body: releaseActionEntries,
773
+ params: { releaseId: values.releaseId }
774
+ });
775
+ if ("data" in response2) {
776
+ const notificationMessage = formatMessage(
777
+ {
778
+ id: "content-releases.content-manager-list-view.add-to-release.notification.success.message",
779
+ defaultMessage: "{entriesAlreadyInRelease} out of {totalEntries} entries were already in the release."
780
+ },
781
+ {
782
+ entriesAlreadyInRelease: response2.data.meta.entriesAlreadyInRelease,
783
+ totalEntries: response2.data.meta.totalEntries
784
+ }
785
+ );
786
+ const notification = {
787
+ type: "success",
788
+ title: formatMessage(
789
+ {
790
+ id: "content-releases.content-manager-list-view.add-to-release.notification.success.title",
791
+ defaultMessage: "Successfully added to release."
792
+ },
793
+ {
794
+ entriesAlreadyInRelease: response2.data.meta.entriesAlreadyInRelease,
795
+ totalEntries: response2.data.meta.totalEntries
796
+ }
797
+ ),
798
+ message: response2.data.meta.entriesAlreadyInRelease ? notificationMessage : ""
799
+ };
800
+ toggleNotification(notification);
801
+ return true;
802
+ }
803
+ if ("error" in response2) {
804
+ if (strapiAdmin.isFetchError(response2.error)) {
805
+ toggleNotification({
806
+ type: "warning",
807
+ message: formatAPIError(response2.error)
808
+ });
809
+ } else {
810
+ toggleNotification({
811
+ type: "warning",
812
+ message: formatMessage({ id: "notification.error", defaultMessage: "An error occurred" })
813
+ });
814
+ }
815
+ }
816
+ };
817
+ if (!canCreate || !canPublish)
818
+ return null;
819
+ return {
820
+ actionType: "release",
821
+ variant: "tertiary",
822
+ label: formatMessage({
823
+ id: "content-manager-list-view.add-to-release",
824
+ defaultMessage: "Add to Release"
825
+ }),
826
+ dialog: {
827
+ type: "modal",
828
+ title: formatMessage({
829
+ id: "content-manager-list-view.add-to-release",
830
+ defaultMessage: "Add to Release"
831
+ }),
832
+ content: ({ onClose }) => {
833
+ return /* @__PURE__ */ jsxRuntime.jsx(
834
+ formik.Formik,
835
+ {
836
+ onSubmit: async (values) => {
837
+ const data = await handleSubmit(values);
838
+ if (data) {
839
+ return onClose();
840
+ }
841
+ },
842
+ validationSchema: RELEASE_ACTION_FORM_SCHEMA,
843
+ initialValues: INITIAL_VALUES,
844
+ children: ({ values, setFieldValue }) => /* @__PURE__ */ jsxRuntime.jsxs(formik.Form, { children: [
845
+ releases?.length === 0 ? /* @__PURE__ */ jsxRuntime.jsx(NoReleases, {}) : /* @__PURE__ */ jsxRuntime.jsx(designSystem.Modal.Body, { children: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { direction: "column", alignItems: "stretch", gap: 2, children: [
846
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Box, { paddingBottom: 6, children: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Field.Root, { required: true, children: [
847
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Field.Label, { children: formatMessage({
848
+ id: "content-releases.content-manager-list-view.add-to-release.select-label",
849
+ defaultMessage: "Select a release"
850
+ }) }),
851
+ /* @__PURE__ */ jsxRuntime.jsx(
852
+ designSystem.SingleSelect,
853
+ {
854
+ placeholder: formatMessage({
855
+ id: "content-releases.content-manager-list-view.add-to-release.select-placeholder",
856
+ defaultMessage: "Select"
857
+ }),
858
+ onChange: (value) => setFieldValue("releaseId", value),
859
+ value: values.releaseId,
860
+ children: releases?.map((release) => /* @__PURE__ */ jsxRuntime.jsx(designSystem.SingleSelectOption, { value: release.id, children: release.name }, release.id))
861
+ }
862
+ )
863
+ ] }) }),
864
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Field.Label, { children: formatMessage({
865
+ id: "content-releases.content-manager-list-view.add-to-release.action-type-label",
866
+ defaultMessage: "What do you want to do with these entries?"
867
+ }) }),
868
+ /* @__PURE__ */ jsxRuntime.jsx(
869
+ ReleaseActionOptions,
870
+ {
871
+ selected: values.type,
872
+ handleChange: (e) => setFieldValue("type", e.target.value),
873
+ name: "type"
874
+ }
751
875
  )
752
876
  ] }) }),
753
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Field.Label, { children: formatMessage({
754
- id: "content-releases.content-manager-edit-view.add-to-release.action-type-label",
755
- defaultMessage: "What do you want to do with this entry?"
756
- }) }),
757
- /* @__PURE__ */ jsxRuntime.jsx(
758
- ReleaseActionOptions,
759
- {
760
- selected: values.type,
761
- handleChange: (e) => setFieldValue("type", e.target.value),
762
- name: "type"
763
- }
764
- )
765
- ] }) }),
766
- /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Modal.Footer, { children: [
767
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Modal.Close, { children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Button, { variant: "tertiary", name: "cancel", children: formatMessage({
768
- id: "content-releases.content-manager-edit-view.add-to-release.cancel-button",
769
- defaultMessage: "Cancel"
770
- }) }) }),
771
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Button, { type: "submit", disabled: !values.releaseId, loading: isLoading, children: formatMessage({
772
- id: "content-releases.content-manager-edit-view.add-to-release.continue-button",
773
- defaultMessage: "Continue"
774
- }) })
877
+ /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Modal.Footer, { children: [
878
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Button, { onClick: onClose, variant: "tertiary", name: "cancel", children: formatMessage({
879
+ id: "content-releases.content-manager-list-view.add-to-release.cancel-button",
880
+ defaultMessage: "Cancel"
881
+ }) }),
882
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Button, { type: "submit", disabled: !values.releaseId, loading: isLoading, children: formatMessage({
883
+ id: "content-releases.content-manager-list-view.add-to-release.continue-button",
884
+ defaultMessage: "Continue"
885
+ }) })
886
+ ] })
775
887
  ] })
776
- ] });
777
- }
888
+ }
889
+ );
778
890
  }
779
- )
780
- ] }) });
891
+ }
892
+ };
781
893
  };
782
- const CMReleasesContainer = () => {
783
- const [isModalOpen, setIsModalOpen] = React__namespace.useState(false);
784
- const { formatMessage, formatDate, formatTime } = reactIntl.useIntl();
785
- const { id, slug, collectionType } = reactRouterDom.useParams();
786
- const isCreatingEntry = id === "create";
787
- const entryId = parseInt(id, 10);
788
- const { allowedActions } = strapiAdmin.useRBAC(PERMISSIONS);
789
- const { canCreateAction, canRead: canMain, canDeleteAction } = allowedActions;
790
- const { schema } = strapiAdmin$1.unstable_useDocument({
791
- collectionType,
792
- model: slug
894
+ const useReleasesList = (contentTypeUid, documentId) => {
895
+ const listViewData = strapiAdmin.useTable("ListView", (state) => state.rows);
896
+ const documentIds = listViewData.map((entry) => entry.documentId);
897
+ const [{ query }] = strapiAdmin.useQueryParams();
898
+ const locale = query?.plugins?.i18n?.locale || void 0;
899
+ const response = useGetMappedEntriesInReleasesQuery(
900
+ { contentTypeUid, documentIds, locale },
901
+ { skip: !documentIds || !contentTypeUid || documentIds.length === 0 }
902
+ );
903
+ const mappedEntriesInReleases = response.data || {};
904
+ return mappedEntriesInReleases?.[documentId] || [];
905
+ };
906
+ const addColumnToTableHook = ({ displayedHeaders, layout }) => {
907
+ const { options } = layout;
908
+ if (!options?.draftAndPublish) {
909
+ return { displayedHeaders, layout };
910
+ }
911
+ return {
912
+ displayedHeaders: [
913
+ ...displayedHeaders,
914
+ {
915
+ searchable: false,
916
+ sortable: false,
917
+ name: "releases",
918
+ label: {
919
+ id: "content-releases.content-manager.list-view.releases.header",
920
+ defaultMessage: "To be released in"
921
+ },
922
+ cellFormatter: (props, _, { model }) => /* @__PURE__ */ jsxRuntime.jsx(ReleaseListCell, { ...props, model })
923
+ }
924
+ ],
925
+ layout
926
+ };
927
+ };
928
+ const ReleaseListCell = ({ documentId, model }) => {
929
+ const releases = useReleasesList(model, documentId);
930
+ const { formatMessage } = reactIntl.useIntl();
931
+ return /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Popover.Root, { children: [
932
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Popover.Trigger, { children: /* @__PURE__ */ jsxRuntime.jsx(
933
+ designSystem.Button,
934
+ {
935
+ variant: "ghost",
936
+ onClick: (e) => e.stopPropagation(),
937
+ endIcon: releases.length > 0 ? /* @__PURE__ */ jsxRuntime.jsx(icons.CaretDown, { width: "1.2rem", height: "1.2rem" }) : null,
938
+ children: /* @__PURE__ */ jsxRuntime.jsx(
939
+ designSystem.Typography,
940
+ {
941
+ style: { maxWidth: "252px", cursor: "pointer" },
942
+ textColor: "neutral800",
943
+ fontWeight: "regular",
944
+ children: releases.length > 0 ? formatMessage(
945
+ {
946
+ id: "content-releases.content-manager.list-view.releases-number",
947
+ defaultMessage: "{number} {number, plural, one {release} other {releases}}"
948
+ },
949
+ {
950
+ number: releases.length
951
+ }
952
+ ) : "-"
953
+ }
954
+ )
955
+ }
956
+ ) }),
957
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Popover.Content, { children: /* @__PURE__ */ jsxRuntime.jsx("ul", { children: releases.map(({ id, name }) => /* @__PURE__ */ jsxRuntime.jsx(designSystem.Box, { padding: 3, tag: "li", children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Link, { href: `/admin/plugins/content-releases/${id}`, isExternal: false, children: name }) }, id)) }) })
958
+ ] });
959
+ };
960
+ const getTimezoneOffset = (timezone, date) => {
961
+ try {
962
+ const offsetPart = new Intl.DateTimeFormat("en", {
963
+ timeZone: timezone,
964
+ timeZoneName: "longOffset"
965
+ }).formatToParts(date).find((part) => part.type === "timeZoneName");
966
+ const offset = offsetPart ? offsetPart.value : "";
967
+ let utcOffset = offset.replace("GMT", "UTC");
968
+ if (!utcOffset.includes("+") && !utcOffset.includes("-")) {
969
+ utcOffset = `${utcOffset}+00:00`;
970
+ }
971
+ return utcOffset;
972
+ } catch (error) {
973
+ return "";
974
+ }
975
+ };
976
+ const getTimezones = (selectedDate) => {
977
+ const timezoneList = Intl.supportedValuesOf("timeZone").map((timezone) => {
978
+ const utcOffset = getTimezoneOffset(timezone, selectedDate);
979
+ return { offset: utcOffset, value: `${utcOffset}&${timezone}` };
793
980
  });
794
- const hasDraftAndPublish = schema?.options?.draftAndPublish;
795
- const contentTypeUid = slug;
796
- const canFetch = id != null && contentTypeUid != null;
797
- const fetchParams = canFetch ? {
798
- contentTypeUid,
799
- entryId,
800
- hasEntryAttached: true
801
- } : query.skipToken;
802
- const response = useGetReleasesForEntryQuery(fetchParams);
803
- const releases = response.data?.data;
804
- if (!canFetch) {
981
+ const systemTimezone = timezoneList.find(
982
+ (timezone) => timezone.value.split("&")[1] === Intl.DateTimeFormat().resolvedOptions().timeZone
983
+ );
984
+ return { timezoneList, systemTimezone };
985
+ };
986
+ const StyledMenuItem = styledComponents.styled(designSystem.Menu.Item)`
987
+ &:hover {
988
+ background: ${({ theme, $variant = "neutral" }) => theme.colors[`${$variant}100`]};
989
+
990
+ svg {
991
+ fill: ${({ theme, $variant = "neutral" }) => theme.colors[`${$variant}600`]};
992
+ }
993
+
994
+ a {
995
+ color: ${({ theme }) => theme.colors.neutral800};
996
+ }
997
+ }
998
+
999
+ svg {
1000
+ color: ${({ theme, $variant = "neutral" }) => theme.colors[`${$variant}500`]};
1001
+ }
1002
+
1003
+ span {
1004
+ color: ${({ theme, $variant = "neutral" }) => theme.colors[`${$variant}800`]};
1005
+ }
1006
+
1007
+ span,
1008
+ a {
1009
+ width: 100%;
1010
+ }
1011
+ `;
1012
+ const DeleteReleaseActionItem = ({ releaseId, actionId }) => {
1013
+ const { formatMessage } = reactIntl.useIntl();
1014
+ const { toggleNotification } = strapiAdmin.useNotification();
1015
+ const { formatAPIError } = strapiAdmin.useAPIErrorHandler();
1016
+ const [deleteReleaseAction] = useDeleteReleaseActionMutation();
1017
+ const {
1018
+ allowedActions: { canDeleteAction }
1019
+ } = strapiAdmin.useRBAC(PERMISSIONS);
1020
+ const handleDeleteAction = async () => {
1021
+ const response = await deleteReleaseAction({
1022
+ params: { releaseId, actionId }
1023
+ });
1024
+ if ("data" in response) {
1025
+ toggleNotification({
1026
+ type: "success",
1027
+ message: formatMessage({
1028
+ id: "content-releases.content-manager-edit-view.remove-from-release.notification.success",
1029
+ defaultMessage: "Entry removed from release"
1030
+ })
1031
+ });
1032
+ return;
1033
+ }
1034
+ if ("error" in response) {
1035
+ if (strapiAdmin.isFetchError(response.error)) {
1036
+ toggleNotification({
1037
+ type: "danger",
1038
+ message: formatAPIError(response.error)
1039
+ });
1040
+ } else {
1041
+ toggleNotification({
1042
+ type: "danger",
1043
+ message: formatMessage({ id: "notification.error", defaultMessage: "An error occurred" })
1044
+ });
1045
+ }
1046
+ }
1047
+ };
1048
+ if (!canDeleteAction) {
805
1049
  return null;
806
1050
  }
807
- if (isCreatingEntry || !hasDraftAndPublish) {
1051
+ return /* @__PURE__ */ jsxRuntime.jsx(StyledMenuItem, { $variant: "danger", onSelect: handleDeleteAction, children: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { gap: 2, children: [
1052
+ /* @__PURE__ */ jsxRuntime.jsx(icons.Cross, { width: "1.6rem", height: "1.6rem" }),
1053
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { textColor: "danger600", variant: "omega", children: formatMessage({
1054
+ id: "content-releases.content-manager-edit-view.remove-from-release",
1055
+ defaultMessage: "Remove from release"
1056
+ }) })
1057
+ ] }) });
1058
+ };
1059
+ const ReleaseActionEntryLinkItem = ({
1060
+ contentTypeUid,
1061
+ documentId,
1062
+ locale
1063
+ }) => {
1064
+ const { formatMessage } = reactIntl.useIntl();
1065
+ const userPermissions = strapiAdmin.useAuth("ReleaseActionEntryLinkItem", (state) => state.permissions);
1066
+ const canUpdateEntryForLocale = React__namespace.useMemo(() => {
1067
+ const updatePermissions = userPermissions.find(
1068
+ (permission) => permission.subject === contentTypeUid && permission.action === "plugin::content-manager.explorer.update"
1069
+ );
1070
+ if (!updatePermissions) {
1071
+ return false;
1072
+ }
1073
+ return Boolean(!locale || updatePermissions.properties?.locales?.includes(locale));
1074
+ }, [contentTypeUid, locale, userPermissions]);
1075
+ const {
1076
+ allowedActions: { canUpdate: canUpdateContentType }
1077
+ } = strapiAdmin.useRBAC({
1078
+ updateContentType: [
1079
+ {
1080
+ action: "plugin::content-manager.explorer.update",
1081
+ subject: contentTypeUid
1082
+ }
1083
+ ]
1084
+ });
1085
+ if (!canUpdateContentType || !canUpdateEntryForLocale) {
808
1086
  return null;
809
1087
  }
810
- const toggleModal = () => setIsModalOpen((prev) => !prev);
1088
+ return /* @__PURE__ */ jsxRuntime.jsx(
1089
+ StyledMenuItem,
1090
+ {
1091
+ tag: reactRouterDom.NavLink,
1092
+ isLink: true,
1093
+ to: {
1094
+ pathname: `/content-manager/collection-types/${contentTypeUid}/${documentId}`,
1095
+ search: locale && `?plugins[i18n][locale]=${locale}`
1096
+ },
1097
+ children: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { gap: 2, children: [
1098
+ /* @__PURE__ */ jsxRuntime.jsx(icons.Pencil, { width: "1.6rem", height: "1.6rem" }),
1099
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "omega", children: formatMessage({
1100
+ id: "content-releases.content-manager-edit-view.edit-entry",
1101
+ defaultMessage: "Edit entry"
1102
+ }) })
1103
+ ] })
1104
+ }
1105
+ );
1106
+ };
1107
+ const EditReleaseItem = ({ releaseId }) => {
1108
+ const { formatMessage } = reactIntl.useIntl();
1109
+ return (
1110
+ /* @ts-expect-error inference isn't working in DS */
1111
+ /* @__PURE__ */ jsxRuntime.jsx(StyledMenuItem, { tag: reactRouterDom.NavLink, isLink: true, to: `/plugins/content-releases/${releaseId}`, children: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { gap: 2, children: [
1112
+ /* @__PURE__ */ jsxRuntime.jsx(icons.Pencil, { width: "1.6rem", height: "1.6rem" }),
1113
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { textColor: "neutral800", variant: "omega", children: formatMessage({
1114
+ id: "content-releases.content-manager-edit-view.edit-release",
1115
+ defaultMessage: "Edit release"
1116
+ }) })
1117
+ ] }) })
1118
+ );
1119
+ };
1120
+ const Root = ({ children }) => {
1121
+ const { formatMessage } = reactIntl.useIntl();
1122
+ const { allowedActions } = strapiAdmin.useRBAC(PERMISSIONS);
1123
+ return (
1124
+ // A user can access the dropdown if they have permissions to delete a release-action OR update a release
1125
+ allowedActions.canDeleteAction || allowedActions.canUpdate ? /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Menu.Root, { children: [
1126
+ /* @__PURE__ */ jsxRuntime.jsx(StyledMoreButton, { variant: "tertiary", endIcon: null, paddingLeft: "7px", paddingRight: "7px", children: /* @__PURE__ */ jsxRuntime.jsx(
1127
+ designSystem.AccessibleIcon,
1128
+ {
1129
+ label: formatMessage({
1130
+ id: "content-releases.content-manager-edit-view.release-action-menu",
1131
+ defaultMessage: "Release action options"
1132
+ }),
1133
+ children: /* @__PURE__ */ jsxRuntime.jsx(icons.More, {})
1134
+ }
1135
+ ) }),
1136
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Menu.Content, { top: 1, popoverPlacement: "bottom-end", children })
1137
+ ] }) : null
1138
+ );
1139
+ };
1140
+ const StyledMoreButton = styledComponents.styled(designSystem.Menu.Trigger)`
1141
+ & > span {
1142
+ display: flex;
1143
+ }
1144
+ `;
1145
+ const ReleaseActionMenu = {
1146
+ Root,
1147
+ EditReleaseItem,
1148
+ DeleteReleaseActionItem,
1149
+ ReleaseActionEntryLinkItem
1150
+ };
1151
+ const Panel = ({
1152
+ model,
1153
+ document,
1154
+ documentId,
1155
+ collectionType
1156
+ }) => {
1157
+ const [{ query }] = strapiAdmin.useQueryParams();
1158
+ const locale = query.plugins?.i18n?.locale;
1159
+ const {
1160
+ edit: { options }
1161
+ } = strapiAdmin$1.unstable_useDocumentLayout(model);
1162
+ const { formatMessage, formatDate, formatTime } = reactIntl.useIntl();
1163
+ const { allowedActions } = strapiAdmin.useRBAC(PERMISSIONS);
1164
+ const { canRead, canDeleteAction } = allowedActions;
1165
+ const response = useGetReleasesForEntryQuery(
1166
+ {
1167
+ contentType: model,
1168
+ entryDocumentId: documentId,
1169
+ locale,
1170
+ hasEntryAttached: true
1171
+ },
1172
+ {
1173
+ skip: !document
1174
+ }
1175
+ );
1176
+ const releases = response.data?.data;
811
1177
  const getReleaseColorVariant = (actionType, shade) => {
812
1178
  if (actionType === "unpublish") {
813
1179
  return `secondary${shade}`;
814
1180
  }
815
1181
  return `success${shade}`;
816
1182
  };
817
- if (!canMain) {
1183
+ if (!window.strapi.isEE || !options?.draftAndPublish || !canRead) {
818
1184
  return null;
819
1185
  }
820
- return /* @__PURE__ */ jsxRuntime.jsxs(
821
- designSystem.Box,
822
- {
823
- tag: "aside",
824
- "aria-label": formatMessage({
825
- id: "content-releases.plugin.name",
826
- defaultMessage: "Releases"
827
- }),
828
- background: "neutral0",
829
- borderColor: "neutral150",
830
- hasRadius: true,
831
- padding: 4,
832
- shadow: "tableShadow",
833
- children: [
834
- /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { direction: "column", alignItems: "stretch", gap: 3, children: [
835
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "sigma", textColor: "neutral600", textTransform: "uppercase", children: formatMessage({
836
- id: "content-releases.plugin.name",
837
- defaultMessage: "Releases"
838
- }) }),
839
- releases?.map((release) => {
840
- return /* @__PURE__ */ jsxRuntime.jsxs(
841
- designSystem.Flex,
842
- {
843
- direction: "column",
844
- alignItems: "start",
845
- borderWidth: "1px",
846
- borderStyle: "solid",
847
- borderColor: getReleaseColorVariant(release.actions[0].type, "200"),
848
- overflow: "hidden",
849
- hasRadius: true,
850
- children: [
851
- /* @__PURE__ */ jsxRuntime.jsx(
852
- designSystem.Box,
853
- {
854
- paddingTop: 3,
855
- paddingBottom: 3,
856
- paddingLeft: 4,
857
- paddingRight: 4,
858
- background: getReleaseColorVariant(release.actions[0].type, "100"),
859
- width: "100%",
860
- children: /* @__PURE__ */ jsxRuntime.jsx(
861
- designSystem.Typography,
862
- {
863
- fontSize: 1,
864
- variant: "pi",
865
- textColor: getReleaseColorVariant(release.actions[0].type, "600"),
866
- children: formatMessage(
867
- {
868
- id: "content-releases.content-manager-edit-view.list-releases.title",
869
- defaultMessage: "{isPublish, select, true {Will be published in} other {Will be unpublished in}}"
870
- },
871
- { isPublish: release.actions[0].type === "publish" }
872
- )
873
- }
874
- )
875
- }
876
- ),
877
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Flex, { padding: 4, direction: "column", gap: 2, width: "100%", alignItems: "flex-start", children: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { padding: 4, direction: "column", gap: 2, width: "100%", alignItems: "flex-start", children: [
878
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { fontSize: 2, fontWeight: "bold", variant: "omega", textColor: "neutral700", children: release.name }),
879
- release.scheduledAt && release.timezone && /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "pi", textColor: "neutral600", children: formatMessage(
880
- {
881
- id: "content-releases.content-manager-edit-view.scheduled.date",
882
- defaultMessage: "{date} at {time} ({offset})"
883
- },
884
- {
885
- date: formatDate(new Date(release.scheduledAt), {
886
- day: "2-digit",
887
- month: "2-digit",
888
- year: "numeric",
889
- timeZone: release.timezone
890
- }),
891
- time: formatTime(new Date(release.scheduledAt), {
892
- hourCycle: "h23",
893
- timeZone: release.timezone
894
- }),
895
- offset: getTimezoneOffset(
896
- release.timezone,
897
- new Date(release.scheduledAt)
898
- )
899
- }
900
- ) }),
901
- canDeleteAction ? /* @__PURE__ */ jsxRuntime.jsxs(ReleaseActionMenu.Root, { hasTriggerBorder: true, children: [
902
- /* @__PURE__ */ jsxRuntime.jsx(ReleaseActionMenu.EditReleaseItem, { releaseId: release.id }),
903
- /* @__PURE__ */ jsxRuntime.jsx(
904
- ReleaseActionMenu.DeleteReleaseActionItem,
905
- {
906
- releaseId: release.id,
907
- actionId: release.actions[0].id
908
- }
909
- )
910
- ] }) : null
911
- ] }) })
912
- ]
913
- },
914
- release.id
915
- );
916
- }),
917
- canCreateAction ? /* @__PURE__ */ jsxRuntime.jsx(
918
- designSystem.Button,
1186
+ if (collectionType === "collection-types" && (!documentId || documentId === "create")) {
1187
+ return null;
1188
+ }
1189
+ if (!releases || releases.length === 0) {
1190
+ return null;
1191
+ }
1192
+ return {
1193
+ title: formatMessage({
1194
+ id: "content-releases.plugin.name",
1195
+ defaultMessage: "Releases"
1196
+ }),
1197
+ content: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Flex, { direction: "column", alignItems: "stretch", gap: 3, width: "100%", children: releases?.map((release) => /* @__PURE__ */ jsxRuntime.jsxs(
1198
+ designSystem.Flex,
1199
+ {
1200
+ direction: "column",
1201
+ alignItems: "start",
1202
+ borderWidth: "1px",
1203
+ borderStyle: "solid",
1204
+ borderColor: getReleaseColorVariant(release.actions[0].type, "200"),
1205
+ overflow: "hidden",
1206
+ hasRadius: true,
1207
+ children: [
1208
+ /* @__PURE__ */ jsxRuntime.jsx(
1209
+ designSystem.Box,
919
1210
  {
920
- justifyContent: "center",
1211
+ paddingTop: 3,
1212
+ paddingBottom: 3,
921
1213
  paddingLeft: 4,
922
1214
  paddingRight: 4,
923
- color: "neutral700",
924
- variant: "tertiary",
925
- startIcon: /* @__PURE__ */ jsxRuntime.jsx(icons.Plus, {}),
926
- onClick: toggleModal,
927
- children: formatMessage({
928
- id: "content-releases.content-manager-edit-view.add-to-release",
929
- defaultMessage: "Add to release"
930
- })
1215
+ background: getReleaseColorVariant(release.actions[0].type, "100"),
1216
+ width: "100%",
1217
+ children: /* @__PURE__ */ jsxRuntime.jsx(
1218
+ designSystem.Typography,
1219
+ {
1220
+ fontSize: 1,
1221
+ variant: "pi",
1222
+ textColor: getReleaseColorVariant(release.actions[0].type, "600"),
1223
+ children: formatMessage(
1224
+ {
1225
+ id: "content-releases.content-manager-edit-view.list-releases.title",
1226
+ defaultMessage: "{isPublish, select, true {Will be published in} other {Will be unpublished in}}"
1227
+ },
1228
+ { isPublish: release.actions[0].type === "publish" }
1229
+ )
1230
+ }
1231
+ )
931
1232
  }
932
- ) : null
933
- ] }),
934
- /* @__PURE__ */ jsxRuntime.jsx(
935
- AddActionToReleaseModal,
936
- {
937
- open: isModalOpen,
938
- onOpenChange: toggleModal,
939
- contentTypeUid,
940
- entryId
941
- }
942
- )
943
- ]
944
- }
945
- );
1233
+ ),
1234
+ /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { padding: 4, direction: "column", gap: 2, width: "100%", alignItems: "flex-start", children: [
1235
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { fontSize: 2, fontWeight: "bold", variant: "omega", textColor: "neutral700", children: release.name }),
1236
+ release.scheduledAt && release.timezone && /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "pi", textColor: "neutral600", children: formatMessage(
1237
+ {
1238
+ id: "content-releases.content-manager-edit-view.scheduled.date",
1239
+ defaultMessage: "{date} at {time} ({offset})"
1240
+ },
1241
+ {
1242
+ date: formatDate(new Date(release.scheduledAt), {
1243
+ day: "2-digit",
1244
+ month: "2-digit",
1245
+ year: "numeric",
1246
+ timeZone: release.timezone
1247
+ }),
1248
+ time: formatTime(new Date(release.scheduledAt), {
1249
+ hourCycle: "h23",
1250
+ timeZone: release.timezone
1251
+ }),
1252
+ offset: getTimezoneOffset(release.timezone, new Date(release.scheduledAt))
1253
+ }
1254
+ ) }),
1255
+ canDeleteAction ? /* @__PURE__ */ jsxRuntime.jsxs(ReleaseActionMenu.Root, { hasTriggerBorder: true, children: [
1256
+ /* @__PURE__ */ jsxRuntime.jsx(ReleaseActionMenu.EditReleaseItem, { releaseId: release.id }),
1257
+ /* @__PURE__ */ jsxRuntime.jsx(
1258
+ ReleaseActionMenu.DeleteReleaseActionItem,
1259
+ {
1260
+ releaseId: release.id,
1261
+ actionId: release.actions[0].id
1262
+ }
1263
+ )
1264
+ ] }) : null
1265
+ ] })
1266
+ ]
1267
+ },
1268
+ release.id
1269
+ )) })
1270
+ };
946
1271
  };
947
1272
  const pluginId = "content-releases";
948
1273
  const prefixPluginTranslations = (trad, pluginId2) => {
949
- if (!pluginId2) {
950
- throw new TypeError("pluginId can't be empty");
951
- }
952
1274
  return Object.keys(trad).reduce((acc, current) => {
953
1275
  acc[`${pluginId2}.${current}`] = trad[current];
954
1276
  return acc;
@@ -966,18 +1288,46 @@ const admin = {
966
1288
  id: `${pluginId}.plugin.name`,
967
1289
  defaultMessage: "Releases"
968
1290
  },
969
- Component: () => Promise.resolve().then(() => require("./App-CEwOQkKT.js")).then((mod) => ({ default: mod.App })),
1291
+ Component: () => Promise.resolve().then(() => require("./App-BKB1esYS.js")).then((mod) => ({ default: mod.App })),
970
1292
  permissions: PERMISSIONS.main,
971
1293
  position: 2
972
1294
  });
973
- app.getPlugin("content-manager").injectComponent("editView", "right-links", {
974
- name: `${pluginId}-link`,
975
- Component: CMReleasesContainer
1295
+ const contentManagerPluginApis = app.getPlugin("content-manager").apis;
1296
+ if ("addEditViewSidePanel" in contentManagerPluginApis && typeof contentManagerPluginApis.addEditViewSidePanel === "function") {
1297
+ contentManagerPluginApis.addEditViewSidePanel([Panel]);
1298
+ }
1299
+ if ("addDocumentAction" in contentManagerPluginApis && typeof contentManagerPluginApis.addDocumentAction === "function") {
1300
+ contentManagerPluginApis.addDocumentAction((actions) => {
1301
+ const indexOfDeleteAction = actions.findIndex((action) => action.type === "unpublish");
1302
+ actions.splice(indexOfDeleteAction, 0, ReleaseActionModalForm);
1303
+ return actions;
1304
+ });
1305
+ }
1306
+ app.addSettingsLink("global", {
1307
+ id: pluginId,
1308
+ to: "releases",
1309
+ intlLabel: {
1310
+ id: `${pluginId}.plugin.name`,
1311
+ defaultMessage: "Releases"
1312
+ },
1313
+ permissions: [],
1314
+ async Component() {
1315
+ const { ProtectedReleasesSettingsPage } = await Promise.resolve().then(() => require("./ReleasesSettingsPage-kuXIwpWp.js"));
1316
+ return { default: ProtectedReleasesSettingsPage };
1317
+ }
976
1318
  });
1319
+ if ("addBulkAction" in contentManagerPluginApis && typeof contentManagerPluginApis.addBulkAction === "function") {
1320
+ contentManagerPluginApis.addBulkAction((actions) => {
1321
+ const deleteActionIndex = actions.findIndex((action) => action.type === "delete");
1322
+ actions.splice(deleteActionIndex, 0, ReleaseAction);
1323
+ return actions;
1324
+ });
1325
+ }
1326
+ app.registerHook("Admin/CM/pages/ListView/inject-column-in-table", addColumnToTableHook);
977
1327
  } else if (!window.strapi.features.isEnabled("cms-content-releases") && window.strapi?.flags?.promoteEE) {
978
- app.addMenuLink({
979
- to: `/plugins/purchase-content-releases`,
980
- icon: icons.PaperPlane,
1328
+ app.addSettingsLink("global", {
1329
+ id: pluginId,
1330
+ to: "/plugins/purchase-content-releases",
981
1331
  intlLabel: {
982
1332
  id: `${pluginId}.plugin.name`,
983
1333
  defaultMessage: "Releases"
@@ -987,15 +1337,14 @@ const admin = {
987
1337
  const { PurchaseContentReleases } = await Promise.resolve().then(() => require("./PurchaseContentReleases-Be3acS2L.js"));
988
1338
  return { default: PurchaseContentReleases };
989
1339
  },
990
- licenseOnly: true,
991
- position: 2
1340
+ licenseOnly: true
992
1341
  });
993
1342
  }
994
1343
  },
995
1344
  async registerTrads({ locales }) {
996
1345
  const importedTrads = await Promise.all(
997
1346
  locales.map((locale) => {
998
- return __variableDynamicImportRuntimeHelper(/* @__PURE__ */ Object.assign({ "./translations/en.json": () => Promise.resolve().then(() => require("./en-DtFJ5ViE.js")) }), `./translations/${locale}.json`).then(({ default: data }) => {
1347
+ return __variableDynamicImportRuntimeHelper(/* @__PURE__ */ Object.assign({ "./translations/en.json": () => Promise.resolve().then(() => require("./en-CmYoEnA7.js")) }), `./translations/${locale}.json`).then(({ default: data }) => {
999
1348
  return {
1000
1349
  data: prefixPluginTranslations(data, "content-releases"),
1001
1350
  locale
@@ -1016,14 +1365,17 @@ exports.ReleaseActionMenu = ReleaseActionMenu;
1016
1365
  exports.ReleaseActionOptions = ReleaseActionOptions;
1017
1366
  exports.admin = admin;
1018
1367
  exports.getTimezoneOffset = getTimezoneOffset;
1368
+ exports.getTimezones = getTimezones;
1019
1369
  exports.pluginId = pluginId;
1020
1370
  exports.releaseApi = releaseApi;
1021
1371
  exports.useCreateReleaseMutation = useCreateReleaseMutation;
1022
1372
  exports.useDeleteReleaseMutation = useDeleteReleaseMutation;
1023
1373
  exports.useGetReleaseActionsQuery = useGetReleaseActionsQuery;
1024
1374
  exports.useGetReleaseQuery = useGetReleaseQuery;
1375
+ exports.useGetReleaseSettingsQuery = useGetReleaseSettingsQuery;
1025
1376
  exports.useGetReleasesQuery = useGetReleasesQuery;
1026
1377
  exports.usePublishReleaseMutation = usePublishReleaseMutation;
1027
1378
  exports.useUpdateReleaseActionMutation = useUpdateReleaseActionMutation;
1028
1379
  exports.useUpdateReleaseMutation = useUpdateReleaseMutation;
1029
- //# sourceMappingURL=index-BrWv-zV4.js.map
1380
+ exports.useUpdateReleaseSettingsMutation = useUpdateReleaseSettingsMutation;
1381
+ //# sourceMappingURL=index-5Odi61vw.js.map