@strapi/content-releases 0.0.0-experimental.dd3311938ac827f1fa8560c8840a9a394f5896c0 → 0.0.0-experimental.de2b94258659463e5ddc5992e9a9490d66d950dd

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 (102) hide show
  1. package/LICENSE +17 -1
  2. package/dist/_chunks/{App-D_6Y9N2F.mjs → App-BA2xDdy0.mjs} +381 -351
  3. package/dist/_chunks/App-BA2xDdy0.mjs.map +1 -0
  4. package/dist/_chunks/{App-DUmziQ17.js → App-D4Wira1X.js} +378 -349
  5. package/dist/_chunks/App-D4Wira1X.js.map +1 -0
  6. package/dist/_chunks/ReleasesSettingsPage-BAlbMWpw.mjs +178 -0
  7. package/dist/_chunks/ReleasesSettingsPage-BAlbMWpw.mjs.map +1 -0
  8. package/dist/_chunks/ReleasesSettingsPage-xhFyRXCM.js +178 -0
  9. package/dist/_chunks/ReleasesSettingsPage-xhFyRXCM.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-CCFFG3Zs.mjs +1365 -0
  15. package/dist/_chunks/index-CCFFG3Zs.mjs.map +1 -0
  16. package/dist/_chunks/{index-C5Hc767q.js → index-DxkQGp4N.js} +790 -443
  17. package/dist/_chunks/index-DxkQGp4N.js.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/ReleaseModal.d.ts +2 -1
  28. package/dist/admin/src/components/ReleasesPanel.d.ts +3 -0
  29. package/dist/admin/src/constants.d.ts +18 -0
  30. package/dist/admin/src/modules/hooks.d.ts +7 -0
  31. package/dist/admin/src/pages/ReleasesSettingsPage.d.ts +1 -0
  32. package/dist/admin/src/services/release.d.ts +43 -36
  33. package/dist/admin/src/utils/time.d.ts +9 -0
  34. package/dist/admin/src/validation/schemas.d.ts +6 -0
  35. package/dist/server/index.js +782 -580
  36. package/dist/server/index.js.map +1 -1
  37. package/dist/server/index.mjs +783 -581
  38. package/dist/server/index.mjs.map +1 -1
  39. package/dist/server/src/bootstrap.d.ts.map +1 -1
  40. package/dist/server/src/constants.d.ts +11 -2
  41. package/dist/server/src/constants.d.ts.map +1 -1
  42. package/dist/server/src/content-types/index.d.ts +3 -5
  43. package/dist/server/src/content-types/index.d.ts.map +1 -1
  44. package/dist/server/src/content-types/release-action/index.d.ts +3 -5
  45. package/dist/server/src/content-types/release-action/index.d.ts.map +1 -1
  46. package/dist/server/src/content-types/release-action/schema.d.ts +3 -5
  47. package/dist/server/src/content-types/release-action/schema.d.ts.map +1 -1
  48. package/dist/server/src/controllers/index.d.ts +6 -1
  49. package/dist/server/src/controllers/index.d.ts.map +1 -1
  50. package/dist/server/src/controllers/release-action.d.ts.map +1 -1
  51. package/dist/server/src/controllers/release.d.ts +7 -1
  52. package/dist/server/src/controllers/release.d.ts.map +1 -1
  53. package/dist/server/src/controllers/settings.d.ts +11 -0
  54. package/dist/server/src/controllers/settings.d.ts.map +1 -0
  55. package/dist/server/src/controllers/validation/release-action.d.ts +7 -1
  56. package/dist/server/src/controllers/validation/release-action.d.ts.map +1 -1
  57. package/dist/server/src/controllers/validation/release.d.ts +2 -0
  58. package/dist/server/src/controllers/validation/release.d.ts.map +1 -1
  59. package/dist/server/src/controllers/validation/settings.d.ts +3 -0
  60. package/dist/server/src/controllers/validation/settings.d.ts.map +1 -0
  61. package/dist/server/src/index.d.ts +68 -49
  62. package/dist/server/src/index.d.ts.map +1 -1
  63. package/dist/server/src/middlewares/documents.d.ts +6 -0
  64. package/dist/server/src/middlewares/documents.d.ts.map +1 -0
  65. package/dist/server/src/migrations/database/5.0.0-document-id-in-actions.d.ts +9 -0
  66. package/dist/server/src/migrations/database/5.0.0-document-id-in-actions.d.ts.map +1 -0
  67. package/dist/server/src/migrations/index.d.ts.map +1 -1
  68. package/dist/server/src/register.d.ts.map +1 -1
  69. package/dist/server/src/routes/index.d.ts +16 -0
  70. package/dist/server/src/routes/index.d.ts.map +1 -1
  71. package/dist/server/src/routes/release.d.ts.map +1 -1
  72. package/dist/server/src/routes/settings.d.ts +18 -0
  73. package/dist/server/src/routes/settings.d.ts.map +1 -0
  74. package/dist/server/src/services/index.d.ts +40 -38
  75. package/dist/server/src/services/index.d.ts.map +1 -1
  76. package/dist/server/src/services/release-action.d.ts +38 -0
  77. package/dist/server/src/services/release-action.d.ts.map +1 -0
  78. package/dist/server/src/services/release.d.ts +6 -41
  79. package/dist/server/src/services/release.d.ts.map +1 -1
  80. package/dist/server/src/services/settings.d.ts +13 -0
  81. package/dist/server/src/services/settings.d.ts.map +1 -0
  82. package/dist/server/src/services/validation.d.ts +1 -1
  83. package/dist/server/src/services/validation.d.ts.map +1 -1
  84. package/dist/server/src/utils/index.d.ts +29 -8
  85. package/dist/server/src/utils/index.d.ts.map +1 -1
  86. package/dist/shared/contracts/release-actions.d.ts +9 -10
  87. package/dist/shared/contracts/release-actions.d.ts.map +1 -1
  88. package/dist/shared/contracts/releases.d.ts +9 -7
  89. package/dist/shared/contracts/releases.d.ts.map +1 -1
  90. package/dist/shared/contracts/settings.d.ts +39 -0
  91. package/dist/shared/contracts/settings.d.ts.map +1 -0
  92. package/package.json +12 -10
  93. package/dist/_chunks/App-DUmziQ17.js.map +0 -1
  94. package/dist/_chunks/App-D_6Y9N2F.mjs.map +0 -1
  95. package/dist/_chunks/en-B9Ur3VsE.mjs.map +0 -1
  96. package/dist/_chunks/en-DtFJ5ViE.js.map +0 -1
  97. package/dist/_chunks/index-BomF0-yY.mjs +0 -1018
  98. package/dist/_chunks/index-BomF0-yY.mjs.map +0 -1
  99. package/dist/_chunks/index-C5Hc767q.js.map +0 -1
  100. package/dist/shared/validation-schemas.d.ts +0 -2
  101. package/dist/shared/validation-schemas.d.ts.map +0 -1
  102. 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,296 +547,727 @@ 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
- handleClose,
670
- contentTypeUid,
671
- entryId
556
+ contentType,
557
+ documentId,
558
+ onInputChange,
559
+ values
672
560
  }) => {
673
- const releaseHeaderId = React__namespace.useId();
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
- handleClose();
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.jsxs(designSystem.ModalLayout, { onClose: handleClose, labelledBy: releaseHeaderId, children: [
722
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.ModalHeader, { children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { id: releaseHeaderId, fontWeight: "bold", textColor: "neutral800", 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.ModalBody, { 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.jsx(
767
- designSystem.ModalFooter,
768
- {
769
- startActions: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Button, { onClick: handleClose, variant: "tertiary", name: "cancel", children: formatMessage({
770
- id: "content-releases.content-manager-edit-view.add-to-release.cancel-button",
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",
771
880
  defaultMessage: "Cancel"
772
881
  }) }),
773
- endActions: (
774
- /**
775
- * TODO: Ideally we would use isValid from Formik to disable the button, however currently it always returns true
776
- * for yup.string().required(), even when the value is falsy (including empty string)
777
- */
778
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Button, { type: "submit", disabled: !values.releaseId, loading: isLoading, children: formatMessage({
779
- id: "content-releases.content-manager-edit-view.add-to-release.continue-button",
780
- defaultMessage: "Continue"
781
- }) })
782
- )
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
+ ] })
887
+ ] })
888
+ }
889
+ );
890
+ }
891
+ }
892
+ };
893
+ };
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
783
951
  }
784
- )
785
- ] });
786
- }
952
+ ) : "-"
953
+ }
954
+ )
787
955
  }
788
- )
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)) }) })
789
958
  ] });
790
959
  };
791
- const CMReleasesContainer = () => {
792
- const [isModalOpen, setIsModalOpen] = React__namespace.useState(false);
793
- const { formatMessage, formatDate, formatTime } = reactIntl.useIntl();
794
- const { id, slug, collectionType } = reactRouterDom.useParams();
795
- const isCreatingEntry = id === "create";
796
- const entryId = parseInt(id, 10);
797
- const { allowedActions } = strapiAdmin.useRBAC(PERMISSIONS);
798
- const { canCreateAction, canRead: canMain, canDeleteAction } = allowedActions;
799
- const { schema } = strapiAdmin$1.unstable_useDocument({
800
- collectionType,
801
- model: slug
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}` };
802
980
  });
803
- const hasDraftAndPublish = schema?.options?.draftAndPublish;
804
- const contentTypeUid = slug;
805
- const canFetch = id != null && contentTypeUid != null;
806
- const fetchParams = canFetch ? {
807
- contentTypeUid,
808
- entryId,
809
- hasEntryAttached: true
810
- } : query.skipToken;
811
- const response = useGetReleasesForEntryQuery(fetchParams);
812
- const releases = response.data?.data;
813
- 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) {
814
1049
  return null;
815
1050
  }
816
- 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) {
817
1086
  return null;
818
1087
  }
819
- 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;
820
1177
  const getReleaseColorVariant = (actionType, shade) => {
821
1178
  if (actionType === "unpublish") {
822
1179
  return `secondary${shade}`;
823
1180
  }
824
1181
  return `success${shade}`;
825
1182
  };
826
- if (!canMain) {
1183
+ if (!window.strapi.isEE || !options?.draftAndPublish || !canRead) {
827
1184
  return null;
828
1185
  }
829
- return /* @__PURE__ */ jsxRuntime.jsxs(
830
- designSystem.Box,
831
- {
832
- tag: "aside",
833
- "aria-label": formatMessage({
834
- id: "content-releases.plugin.name",
835
- defaultMessage: "Releases"
836
- }),
837
- background: "neutral0",
838
- borderColor: "neutral150",
839
- hasRadius: true,
840
- padding: 4,
841
- shadow: "tableShadow",
842
- children: [
843
- /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { direction: "column", alignItems: "stretch", gap: 3, children: [
844
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "sigma", textColor: "neutral600", textTransform: "uppercase", children: formatMessage({
845
- id: "content-releases.plugin.name",
846
- defaultMessage: "Releases"
847
- }) }),
848
- releases?.map((release) => {
849
- return /* @__PURE__ */ jsxRuntime.jsxs(
850
- designSystem.Flex,
851
- {
852
- direction: "column",
853
- alignItems: "start",
854
- borderWidth: "1px",
855
- borderStyle: "solid",
856
- borderColor: getReleaseColorVariant(release.actions[0].type, "200"),
857
- overflow: "hidden",
858
- hasRadius: true,
859
- children: [
860
- /* @__PURE__ */ jsxRuntime.jsx(
861
- designSystem.Box,
862
- {
863
- paddingTop: 3,
864
- paddingBottom: 3,
865
- paddingLeft: 4,
866
- paddingRight: 4,
867
- background: getReleaseColorVariant(release.actions[0].type, "100"),
868
- width: "100%",
869
- children: /* @__PURE__ */ jsxRuntime.jsx(
870
- designSystem.Typography,
871
- {
872
- fontSize: 1,
873
- variant: "pi",
874
- textColor: getReleaseColorVariant(release.actions[0].type, "600"),
875
- children: formatMessage(
876
- {
877
- id: "content-releases.content-manager-edit-view.list-releases.title",
878
- defaultMessage: "{isPublish, select, true {Will be published in} other {Will be unpublished in}}"
879
- },
880
- { isPublish: release.actions[0].type === "publish" }
881
- )
882
- }
883
- )
884
- }
885
- ),
886
- /* @__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: [
887
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { fontSize: 2, fontWeight: "bold", variant: "omega", textColor: "neutral700", children: release.name }),
888
- release.scheduledAt && release.timezone && /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "pi", textColor: "neutral600", children: formatMessage(
889
- {
890
- id: "content-releases.content-manager-edit-view.scheduled.date",
891
- defaultMessage: "{date} at {time} ({offset})"
892
- },
893
- {
894
- date: formatDate(new Date(release.scheduledAt), {
895
- day: "2-digit",
896
- month: "2-digit",
897
- year: "numeric",
898
- timeZone: release.timezone
899
- }),
900
- time: formatTime(new Date(release.scheduledAt), {
901
- hourCycle: "h23",
902
- timeZone: release.timezone
903
- }),
904
- offset: getTimezoneOffset(
905
- release.timezone,
906
- new Date(release.scheduledAt)
907
- )
908
- }
909
- ) }),
910
- canDeleteAction ? /* @__PURE__ */ jsxRuntime.jsxs(ReleaseActionMenu.Root, { hasTriggerBorder: true, children: [
911
- /* @__PURE__ */ jsxRuntime.jsx(ReleaseActionMenu.EditReleaseItem, { releaseId: release.id }),
912
- /* @__PURE__ */ jsxRuntime.jsx(
913
- ReleaseActionMenu.DeleteReleaseActionItem,
914
- {
915
- releaseId: release.id,
916
- actionId: release.actions[0].id
917
- }
918
- )
919
- ] }) : null
920
- ] }) })
921
- ]
922
- },
923
- release.id
924
- );
925
- }),
926
- canCreateAction ? /* @__PURE__ */ jsxRuntime.jsx(
927
- 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,
928
1210
  {
929
- justifyContent: "center",
1211
+ paddingTop: 3,
1212
+ paddingBottom: 3,
930
1213
  paddingLeft: 4,
931
1214
  paddingRight: 4,
932
- color: "neutral700",
933
- variant: "tertiary",
934
- startIcon: /* @__PURE__ */ jsxRuntime.jsx(icons.Plus, {}),
935
- onClick: toggleModal,
936
- children: formatMessage({
937
- id: "content-releases.content-manager-edit-view.add-to-release",
938
- defaultMessage: "Add to release"
939
- })
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
+ )
940
1232
  }
941
- ) : null
942
- ] }),
943
- isModalOpen && /* @__PURE__ */ jsxRuntime.jsx(
944
- AddActionToReleaseModal,
945
- {
946
- handleClose: toggleModal,
947
- contentTypeUid,
948
- entryId
949
- }
950
- )
951
- ]
952
- }
953
- );
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
+ };
954
1271
  };
955
1272
  const pluginId = "content-releases";
956
1273
  const prefixPluginTranslations = (trad, pluginId2) => {
@@ -974,18 +1291,46 @@ const admin = {
974
1291
  id: `${pluginId}.plugin.name`,
975
1292
  defaultMessage: "Releases"
976
1293
  },
977
- Component: () => Promise.resolve().then(() => require("./App-DUmziQ17.js")).then((mod) => ({ default: mod.App })),
1294
+ Component: () => Promise.resolve().then(() => require("./App-D4Wira1X.js")).then((mod) => ({ default: mod.App })),
978
1295
  permissions: PERMISSIONS.main,
979
1296
  position: 2
980
1297
  });
981
- app.getPlugin("content-manager").injectComponent("editView", "right-links", {
982
- name: `${pluginId}-link`,
983
- Component: CMReleasesContainer
1298
+ const contentManagerPluginApis = app.getPlugin("content-manager").apis;
1299
+ if ("addEditViewSidePanel" in contentManagerPluginApis && typeof contentManagerPluginApis.addEditViewSidePanel === "function") {
1300
+ contentManagerPluginApis.addEditViewSidePanel([Panel]);
1301
+ }
1302
+ if ("addDocumentAction" in contentManagerPluginApis && typeof contentManagerPluginApis.addDocumentAction === "function") {
1303
+ contentManagerPluginApis.addDocumentAction((actions) => {
1304
+ const indexOfDeleteAction = actions.findIndex((action) => action.type === "unpublish");
1305
+ actions.splice(indexOfDeleteAction, 0, ReleaseActionModalForm);
1306
+ return actions;
1307
+ });
1308
+ }
1309
+ app.addSettingsLink("global", {
1310
+ id: pluginId,
1311
+ to: "releases",
1312
+ intlLabel: {
1313
+ id: `${pluginId}.plugin.name`,
1314
+ defaultMessage: "Releases"
1315
+ },
1316
+ permissions: [],
1317
+ async Component() {
1318
+ const { ProtectedReleasesSettingsPage } = await Promise.resolve().then(() => require("./ReleasesSettingsPage-xhFyRXCM.js"));
1319
+ return { default: ProtectedReleasesSettingsPage };
1320
+ }
984
1321
  });
1322
+ if ("addBulkAction" in contentManagerPluginApis && typeof contentManagerPluginApis.addBulkAction === "function") {
1323
+ contentManagerPluginApis.addBulkAction((actions) => {
1324
+ const deleteActionIndex = actions.findIndex((action) => action.type === "delete");
1325
+ actions.splice(deleteActionIndex, 0, ReleaseAction);
1326
+ return actions;
1327
+ });
1328
+ }
1329
+ app.registerHook("Admin/CM/pages/ListView/inject-column-in-table", addColumnToTableHook);
985
1330
  } else if (!window.strapi.features.isEnabled("cms-content-releases") && window.strapi?.flags?.promoteEE) {
986
- app.addMenuLink({
987
- to: `/plugins/purchase-content-releases`,
988
- icon: icons.PaperPlane,
1331
+ app.addSettingsLink("global", {
1332
+ id: pluginId,
1333
+ to: "/plugins/purchase-content-releases",
989
1334
  intlLabel: {
990
1335
  id: `${pluginId}.plugin.name`,
991
1336
  defaultMessage: "Releases"
@@ -995,15 +1340,14 @@ const admin = {
995
1340
  const { PurchaseContentReleases } = await Promise.resolve().then(() => require("./PurchaseContentReleases-Be3acS2L.js"));
996
1341
  return { default: PurchaseContentReleases };
997
1342
  },
998
- lockIcon: true,
999
- position: 2
1343
+ licenseOnly: true
1000
1344
  });
1001
1345
  }
1002
1346
  },
1003
1347
  async registerTrads({ locales }) {
1004
1348
  const importedTrads = await Promise.all(
1005
1349
  locales.map((locale) => {
1006
- return __variableDynamicImportRuntimeHelper(/* @__PURE__ */ Object.assign({ "./translations/en.json": () => Promise.resolve().then(() => require("./en-DtFJ5ViE.js")) }), `./translations/${locale}.json`).then(({ default: data }) => {
1350
+ return __variableDynamicImportRuntimeHelper(/* @__PURE__ */ Object.assign({ "./translations/en.json": () => Promise.resolve().then(() => require("./en-CmYoEnA7.js")) }), `./translations/${locale}.json`).then(({ default: data }) => {
1007
1351
  return {
1008
1352
  data: prefixPluginTranslations(data, "content-releases"),
1009
1353
  locale
@@ -1024,14 +1368,17 @@ exports.ReleaseActionMenu = ReleaseActionMenu;
1024
1368
  exports.ReleaseActionOptions = ReleaseActionOptions;
1025
1369
  exports.admin = admin;
1026
1370
  exports.getTimezoneOffset = getTimezoneOffset;
1371
+ exports.getTimezones = getTimezones;
1027
1372
  exports.pluginId = pluginId;
1028
1373
  exports.releaseApi = releaseApi;
1029
1374
  exports.useCreateReleaseMutation = useCreateReleaseMutation;
1030
1375
  exports.useDeleteReleaseMutation = useDeleteReleaseMutation;
1031
1376
  exports.useGetReleaseActionsQuery = useGetReleaseActionsQuery;
1032
1377
  exports.useGetReleaseQuery = useGetReleaseQuery;
1378
+ exports.useGetReleaseSettingsQuery = useGetReleaseSettingsQuery;
1033
1379
  exports.useGetReleasesQuery = useGetReleasesQuery;
1034
1380
  exports.usePublishReleaseMutation = usePublishReleaseMutation;
1035
1381
  exports.useUpdateReleaseActionMutation = useUpdateReleaseActionMutation;
1036
1382
  exports.useUpdateReleaseMutation = useUpdateReleaseMutation;
1037
- //# sourceMappingURL=index-C5Hc767q.js.map
1383
+ exports.useUpdateReleaseSettingsMutation = useUpdateReleaseSettingsMutation;
1384
+ //# sourceMappingURL=index-DxkQGp4N.js.map