@strapi/content-releases 0.0.0-experimental.d954d57341a6623992a0d211daaec8e245c3517d → 0.0.0-experimental.da85533897155e719d784f0271223c866d2f69ab

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 (99) hide show
  1. package/LICENSE +17 -1
  2. package/dist/_chunks/{App-Do-Rnv0A.mjs → App-B4mkcLmw.mjs} +296 -263
  3. package/dist/_chunks/App-B4mkcLmw.mjs.map +1 -0
  4. package/dist/_chunks/{App-CqbuK4M6.js → App-DpoC8s97.js} +293 -261
  5. package/dist/_chunks/App-DpoC8s97.js.map +1 -0
  6. package/dist/_chunks/ReleasesSettingsPage-B89WWWJf.js +178 -0
  7. package/dist/_chunks/ReleasesSettingsPage-B89WWWJf.js.map +1 -0
  8. package/dist/_chunks/ReleasesSettingsPage-DfL6yxLG.mjs +178 -0
  9. package/dist/_chunks/ReleasesSettingsPage-DfL6yxLG.mjs.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-D_pgdqQL.mjs → index-B3cqcIza.mjs} +780 -448
  15. package/dist/_chunks/index-B3cqcIza.mjs.map +1 -0
  16. package/dist/_chunks/{index-Tedsw4GC.js → index-sGcuP2hw.js} +763 -431
  17. package/dist/_chunks/index-sGcuP2hw.js.map +1 -0
  18. package/dist/_chunks/schemas-63pFihNF.mjs +44 -0
  19. package/dist/_chunks/schemas-63pFihNF.mjs.map +1 -0
  20. package/dist/_chunks/schemas-z5zp-_Gd.js +62 -0
  21. package/dist/_chunks/schemas-z5zp-_Gd.js.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 +796 -623
  35. package/dist/server/index.js.map +1 -1
  36. package/dist/server/index.mjs +797 -624
  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 +66 -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 +38 -38
  74. package/dist/server/src/services/index.d.ts.map +1 -1
  75. package/dist/server/src/services/release-action.d.ts +36 -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 +10 -9
  92. package/dist/_chunks/App-CqbuK4M6.js.map +0 -1
  93. package/dist/_chunks/App-Do-Rnv0A.mjs.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-D_pgdqQL.mjs.map +0 -1
  97. package/dist/_chunks/index-Tedsw4GC.js.map +0 -1
  98. package/dist/shared/validation-schemas.d.ts +0 -2
  99. package/dist/shared/validation-schemas.d.ts.map +0 -1
@@ -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"],
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
@@ -253,10 +289,10 @@ const releaseApi = strapiAdmin.adminApi.enhanceEndpoints({
253
289
  };
254
290
  },
255
291
  invalidatesTags: () => [{ type: "ReleaseAction", id: "LIST" }],
256
- async onQueryStarted({ body, params, query: query2, actionPath }, { dispatch, queryFulfilled }) {
292
+ async onQueryStarted({ body, params, query, actionPath }, { dispatch, queryFulfilled }) {
257
293
  const paramsWithoutActionId = {
258
294
  releaseId: params.releaseId,
259
- ...query2
295
+ ...query
260
296
  };
261
297
  const patchResult = dispatch(
262
298
  releaseApi.util.updateQueryData(
@@ -324,6 +360,20 @@ const releaseApi = strapiAdmin.adminApi.enhanceEndpoints({
324
360
  return response.data;
325
361
  },
326
362
  providesTags: [{ type: "EntriesInRelease" }]
363
+ }),
364
+ getReleaseSettings: build.query({
365
+ query: () => "/content-releases/settings",
366
+ providesTags: [{ type: "ReleaseSettings" }]
367
+ }),
368
+ updateReleaseSettings: build.mutation({
369
+ query(data) {
370
+ return {
371
+ url: "/content-releases/settings",
372
+ method: "PUT",
373
+ data
374
+ };
375
+ },
376
+ invalidatesTags: [{ type: "ReleaseSettings" }]
327
377
  })
328
378
  };
329
379
  }
@@ -341,184 +391,10 @@ const {
341
391
  usePublishReleaseMutation,
342
392
  useDeleteReleaseActionMutation,
343
393
  useDeleteReleaseMutation,
344
- useGetMappedEntriesInReleasesQuery
394
+ useGetMappedEntriesInReleasesQuery,
395
+ useGetReleaseSettingsQuery,
396
+ useUpdateReleaseSettingsMutation
345
397
  } = 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
398
  const getBorderLeftRadiusValue = (actionType) => {
523
399
  return actionType === "publish" ? 1 : 0;
524
400
  };
@@ -661,288 +537,714 @@ const NoReleases = () => {
661
537
  defaultMessage: "Open the list of releases"
662
538
  })
663
539
  }
664
- )
540
+ ),
541
+ shadow: "none"
665
542
  }
666
543
  );
667
544
  };
668
545
  const AddActionToReleaseModal = ({
669
- open,
670
- onOpenChange,
671
- contentTypeUid,
672
- entryId
546
+ contentType,
547
+ documentId,
548
+ onInputChange,
549
+ values
673
550
  }) => {
674
551
  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;
552
+ const [{ query }] = strapiAdmin.useQueryParams();
553
+ const locale = query.plugins?.i18n?.locale;
679
554
  const response = useGetReleasesForEntryQuery({
680
- contentTypeUid,
681
- entryId,
682
- hasEntryAttached: false
555
+ contentType,
556
+ entryDocumentId: documentId,
557
+ hasEntryAttached: false,
558
+ locale
683
559
  });
684
560
  const releases = response.data?.data;
561
+ if (releases?.length === 0) {
562
+ return /* @__PURE__ */ jsxRuntime.jsx(NoReleases, {});
563
+ }
564
+ return /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { direction: "column", alignItems: "stretch", gap: 2, children: [
565
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Box, { paddingBottom: 6, children: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Field.Root, { required: true, children: [
566
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Field.Label, { children: formatMessage({
567
+ id: "content-releases.content-manager-edit-view.add-to-release.select-label",
568
+ defaultMessage: "Select a release"
569
+ }) }),
570
+ /* @__PURE__ */ jsxRuntime.jsx(
571
+ designSystem.SingleSelect,
572
+ {
573
+ required: true,
574
+ placeholder: formatMessage({
575
+ id: "content-releases.content-manager-edit-view.add-to-release.select-placeholder",
576
+ defaultMessage: "Select"
577
+ }),
578
+ name: "releaseId",
579
+ onChange: (value) => onInputChange("releaseId", value),
580
+ value: values.releaseId,
581
+ children: releases?.map((release) => /* @__PURE__ */ jsxRuntime.jsx(designSystem.SingleSelectOption, { value: release.id, children: release.name }, release.id))
582
+ }
583
+ )
584
+ ] }) }),
585
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Field.Label, { children: formatMessage({
586
+ id: "content-releases.content-manager-edit-view.add-to-release.action-type-label",
587
+ defaultMessage: "What do you want to do with this entry?"
588
+ }) }),
589
+ /* @__PURE__ */ jsxRuntime.jsx(
590
+ ReleaseActionOptions,
591
+ {
592
+ selected: values.type,
593
+ handleChange: (e) => onInputChange("type", e.target.value),
594
+ name: "type"
595
+ }
596
+ )
597
+ ] });
598
+ };
599
+ const ReleaseActionModalForm = ({
600
+ documentId,
601
+ model,
602
+ collectionType
603
+ }) => {
604
+ const { formatMessage } = reactIntl.useIntl();
605
+ const { allowedActions } = strapiAdmin.useRBAC(PERMISSIONS);
606
+ const { canCreateAction } = allowedActions;
685
607
  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)) {
608
+ const { toggleNotification } = strapiAdmin.useNotification();
609
+ const { formatAPIError } = strapiAdmin.useAPIErrorHandler();
610
+ const [{ query }] = strapiAdmin.useQueryParams();
611
+ const locale = query.plugins?.i18n?.locale;
612
+ const handleSubmit = async (e, onClose) => {
613
+ try {
614
+ await formik$1.handleSubmit(e);
615
+ onClose();
616
+ } catch (error) {
617
+ if (strapiAdmin.isFetchError(error)) {
709
618
  toggleNotification({
710
619
  type: "danger",
711
- message: formatAPIError(response2.error)
620
+ message: formatAPIError(error)
712
621
  });
713
622
  } else {
714
623
  toggleNotification({
715
624
  type: "danger",
716
- message: formatMessage({ id: "notification.error", defaultMessage: "An error occurred" })
625
+ message: formatMessage({
626
+ id: "notification.error",
627
+ defaultMessage: "An error occurred"
628
+ })
717
629
  });
718
630
  }
719
631
  }
720
632
  };
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({
633
+ const formik$1 = formik.useFormik({
634
+ initialValues: INITIAL_VALUES,
635
+ validationSchema: RELEASE_ACTION_FORM_SCHEMA,
636
+ onSubmit: async (values) => {
637
+ if (collectionType === "collection-types" && !documentId) {
638
+ throw new Error("Document id is required");
639
+ }
640
+ const response = await createReleaseAction({
641
+ body: {
642
+ type: values.type,
643
+ contentType: model,
644
+ entryDocumentId: documentId,
645
+ locale
646
+ },
647
+ params: { releaseId: values.releaseId }
648
+ });
649
+ if ("data" in response) {
650
+ toggleNotification({
651
+ type: "success",
652
+ message: formatMessage({
653
+ id: "content-releases.content-manager-edit-view.add-to-release.notification.success",
654
+ defaultMessage: "Entry added to release"
655
+ })
656
+ });
657
+ return;
658
+ }
659
+ if ("error" in response) {
660
+ throw response.error;
661
+ }
662
+ }
663
+ });
664
+ const {
665
+ edit: { options }
666
+ } = strapiAdmin$1.unstable_useDocumentLayout(model);
667
+ if (!window.strapi.isEE || !options?.draftAndPublish || !canCreateAction) {
668
+ return null;
669
+ }
670
+ if (collectionType === "collection-types" && (!documentId || documentId === "create")) {
671
+ return null;
672
+ }
673
+ return {
674
+ label: formatMessage({
723
675
  id: "content-releases.content-manager-edit-view.add-to-release",
724
676
  defaultMessage: "Add to release"
725
- }) }) }),
726
- /* @__PURE__ */ jsxRuntime.jsx(
727
- formik.Formik,
677
+ }),
678
+ icon: /* @__PURE__ */ jsxRuntime.jsx(icons.PaperPlane, {}),
679
+ position: ["panel", "table-row"],
680
+ dialog: {
681
+ type: "modal",
682
+ title: formatMessage({
683
+ id: "content-releases.content-manager-edit-view.add-to-release",
684
+ defaultMessage: "Add to release"
685
+ }),
686
+ content: /* @__PURE__ */ jsxRuntime.jsx(
687
+ AddActionToReleaseModal,
688
+ {
689
+ contentType: model,
690
+ documentId,
691
+ onInputChange: formik$1.setFieldValue,
692
+ values: formik$1.values
693
+ }
694
+ ),
695
+ footer: ({ onClose }) => /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Modal.Footer, { children: [
696
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Button, { onClick: onClose, variant: "tertiary", name: "cancel", children: formatMessage({
697
+ id: "content-releases.content-manager-edit-view.add-to-release.cancel-button",
698
+ defaultMessage: "Cancel"
699
+ }) }),
700
+ /* @__PURE__ */ jsxRuntime.jsx(
701
+ designSystem.Button,
702
+ {
703
+ type: "submit",
704
+ onClick: (e) => handleSubmit(e, onClose),
705
+ disabled: !formik$1.values.releaseId,
706
+ loading: isLoading,
707
+ children: formatMessage({
708
+ id: "content-releases.content-manager-edit-view.add-to-release.continue-button",
709
+ defaultMessage: "Continue"
710
+ })
711
+ }
712
+ )
713
+ ] })
714
+ }
715
+ };
716
+ };
717
+ const getContentPermissions = (subject) => {
718
+ const permissions = {
719
+ publish: [
728
720
  {
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
- }) }),
721
+ action: "plugin::content-manager.explorer.publish",
722
+ subject,
723
+ id: "",
724
+ actionParameters: {},
725
+ properties: {},
726
+ conditions: []
727
+ }
728
+ ]
729
+ };
730
+ return permissions;
731
+ };
732
+ const ReleaseAction = ({ documents, model }) => {
733
+ const { formatMessage } = reactIntl.useIntl();
734
+ const { toggleNotification } = strapiAdmin.useNotification();
735
+ const { formatAPIError } = strapiAdmin.useAPIErrorHandler();
736
+ const [{ query }] = strapiAdmin.useQueryParams();
737
+ const contentPermissions = getContentPermissions(model);
738
+ const {
739
+ allowedActions: { canPublish }
740
+ } = strapiAdmin.useRBAC(contentPermissions);
741
+ const {
742
+ allowedActions: { canCreate }
743
+ } = strapiAdmin.useRBAC(PERMISSIONS);
744
+ const response = useGetReleasesQuery();
745
+ const releases = response.data?.data;
746
+ const [createManyReleaseActions, { isLoading }] = useCreateManyReleaseActionsMutation();
747
+ const documentIds = documents.map((doc) => doc.documentId);
748
+ const handleSubmit = async (values) => {
749
+ const locale = query.plugins?.i18n?.locale;
750
+ const releaseActionEntries = documentIds.map(
751
+ (entryDocumentId) => ({
752
+ type: values.type,
753
+ contentType: model,
754
+ entryDocumentId,
755
+ locale
756
+ })
757
+ );
758
+ const response2 = await createManyReleaseActions({
759
+ body: releaseActionEntries,
760
+ params: { releaseId: values.releaseId }
761
+ });
762
+ if ("data" in response2) {
763
+ const notificationMessage = formatMessage(
764
+ {
765
+ id: "content-releases.content-manager-list-view.add-to-release.notification.success.message",
766
+ defaultMessage: "{entriesAlreadyInRelease} out of {totalEntries} entries were already in the release."
767
+ },
768
+ {
769
+ entriesAlreadyInRelease: response2.data.meta.entriesAlreadyInRelease,
770
+ totalEntries: response2.data.meta.totalEntries
771
+ }
772
+ );
773
+ const notification = {
774
+ type: "success",
775
+ title: formatMessage(
776
+ {
777
+ id: "content-releases.content-manager-list-view.add-to-release.notification.success.title",
778
+ defaultMessage: "Successfully added to release."
779
+ },
780
+ {
781
+ entriesAlreadyInRelease: response2.data.meta.entriesAlreadyInRelease,
782
+ totalEntries: response2.data.meta.totalEntries
783
+ }
784
+ ),
785
+ message: response2.data.meta.entriesAlreadyInRelease ? notificationMessage : ""
786
+ };
787
+ toggleNotification(notification);
788
+ return true;
789
+ }
790
+ if ("error" in response2) {
791
+ if (strapiAdmin.isFetchError(response2.error)) {
792
+ toggleNotification({
793
+ type: "warning",
794
+ message: formatAPIError(response2.error)
795
+ });
796
+ } else {
797
+ toggleNotification({
798
+ type: "warning",
799
+ message: formatMessage({ id: "notification.error", defaultMessage: "An error occurred" })
800
+ });
801
+ }
802
+ }
803
+ };
804
+ if (!canCreate || !canPublish)
805
+ return null;
806
+ return {
807
+ actionType: "release",
808
+ variant: "tertiary",
809
+ label: formatMessage({
810
+ id: "content-manager-list-view.add-to-release",
811
+ defaultMessage: "Add to Release"
812
+ }),
813
+ dialog: {
814
+ type: "modal",
815
+ title: formatMessage({
816
+ id: "content-manager-list-view.add-to-release",
817
+ defaultMessage: "Add to Release"
818
+ }),
819
+ content: ({ onClose }) => {
820
+ return /* @__PURE__ */ jsxRuntime.jsx(
821
+ formik.Formik,
822
+ {
823
+ onSubmit: async (values) => {
824
+ const data = await handleSubmit(values);
825
+ if (data) {
826
+ return onClose();
827
+ }
828
+ },
829
+ validationSchema: RELEASE_ACTION_FORM_SCHEMA,
830
+ initialValues: INITIAL_VALUES,
831
+ children: ({ values, setFieldValue }) => /* @__PURE__ */ jsxRuntime.jsxs(formik.Form, { children: [
832
+ 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: [
833
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Box, { paddingBottom: 6, children: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Field.Root, { required: true, children: [
834
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Field.Label, { children: formatMessage({
835
+ id: "content-releases.content-manager-list-view.add-to-release.select-label",
836
+ defaultMessage: "Select a release"
837
+ }) }),
838
+ /* @__PURE__ */ jsxRuntime.jsx(
839
+ designSystem.SingleSelect,
840
+ {
841
+ placeholder: formatMessage({
842
+ id: "content-releases.content-manager-list-view.add-to-release.select-placeholder",
843
+ defaultMessage: "Select"
844
+ }),
845
+ onChange: (value) => setFieldValue("releaseId", value),
846
+ value: values.releaseId,
847
+ children: releases?.map((release) => /* @__PURE__ */ jsxRuntime.jsx(designSystem.SingleSelectOption, { value: release.id, children: release.name }, release.id))
848
+ }
849
+ )
850
+ ] }) }),
851
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Field.Label, { children: formatMessage({
852
+ id: "content-releases.content-manager-list-view.add-to-release.action-type-label",
853
+ defaultMessage: "What do you want to do with these entries?"
854
+ }) }),
740
855
  /* @__PURE__ */ jsxRuntime.jsx(
741
- designSystem.SingleSelect,
856
+ ReleaseActionOptions,
742
857
  {
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))
858
+ selected: values.type,
859
+ handleChange: (e) => setFieldValue("type", e.target.value),
860
+ name: "type"
750
861
  }
751
862
  )
752
863
  ] }) }),
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
- }) })
864
+ /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Modal.Footer, { children: [
865
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Button, { onClick: onClose, variant: "tertiary", name: "cancel", children: formatMessage({
866
+ id: "content-releases.content-manager-list-view.add-to-release.cancel-button",
867
+ defaultMessage: "Cancel"
868
+ }) }),
869
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Button, { type: "submit", disabled: !values.releaseId, loading: isLoading, children: formatMessage({
870
+ id: "content-releases.content-manager-list-view.add-to-release.continue-button",
871
+ defaultMessage: "Continue"
872
+ }) })
873
+ ] })
775
874
  ] })
776
- ] });
777
- }
875
+ }
876
+ );
778
877
  }
779
- )
780
- ] }) });
878
+ }
879
+ };
781
880
  };
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
881
+ const useReleasesList = (contentTypeUid, documentId) => {
882
+ const listViewData = strapiAdmin.useTable("ListView", (state) => state.rows);
883
+ const documentIds = listViewData.map((entry) => entry.documentId);
884
+ const [{ query }] = strapiAdmin.useQueryParams();
885
+ const locale = query?.plugins?.i18n?.locale || void 0;
886
+ const response = useGetMappedEntriesInReleasesQuery(
887
+ { contentTypeUid, documentIds, locale },
888
+ { skip: !documentIds || !contentTypeUid || documentIds.length === 0 }
889
+ );
890
+ const mappedEntriesInReleases = response.data || {};
891
+ return mappedEntriesInReleases?.[documentId] || [];
892
+ };
893
+ const addColumnToTableHook = ({ displayedHeaders, layout }) => {
894
+ const { options } = layout;
895
+ if (!options?.draftAndPublish) {
896
+ return { displayedHeaders, layout };
897
+ }
898
+ return {
899
+ displayedHeaders: [
900
+ ...displayedHeaders,
901
+ {
902
+ searchable: false,
903
+ sortable: false,
904
+ name: "releases",
905
+ label: {
906
+ id: "content-releases.content-manager.list-view.releases.header",
907
+ defaultMessage: "To be released in"
908
+ },
909
+ cellFormatter: (props, _, { model }) => /* @__PURE__ */ jsxRuntime.jsx(ReleaseListCell, { ...props, model })
910
+ }
911
+ ],
912
+ layout
913
+ };
914
+ };
915
+ const ReleaseListCell = ({ documentId, model }) => {
916
+ const releases = useReleasesList(model, documentId);
917
+ const { formatMessage } = reactIntl.useIntl();
918
+ return /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Popover.Root, { children: [
919
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Popover.Trigger, { children: /* @__PURE__ */ jsxRuntime.jsx(
920
+ designSystem.Button,
921
+ {
922
+ variant: "ghost",
923
+ onClick: (e) => e.stopPropagation(),
924
+ endIcon: releases.length > 0 ? /* @__PURE__ */ jsxRuntime.jsx(icons.CaretDown, { width: "1.2rem", height: "1.2rem" }) : null,
925
+ children: /* @__PURE__ */ jsxRuntime.jsx(
926
+ designSystem.Typography,
927
+ {
928
+ style: { maxWidth: "252px", cursor: "pointer" },
929
+ textColor: "neutral800",
930
+ fontWeight: "regular",
931
+ children: releases.length > 0 ? formatMessage(
932
+ {
933
+ id: "content-releases.content-manager.list-view.releases-number",
934
+ defaultMessage: "{number} {number, plural, one {release} other {releases}}"
935
+ },
936
+ {
937
+ number: releases.length
938
+ }
939
+ ) : "-"
940
+ }
941
+ )
942
+ }
943
+ ) }),
944
+ /* @__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)) }) })
945
+ ] });
946
+ };
947
+ const getTimezoneOffset = (timezone, date) => {
948
+ try {
949
+ const offsetPart = new Intl.DateTimeFormat("en", {
950
+ timeZone: timezone,
951
+ timeZoneName: "longOffset"
952
+ }).formatToParts(date).find((part) => part.type === "timeZoneName");
953
+ const offset = offsetPart ? offsetPart.value : "";
954
+ let utcOffset = offset.replace("GMT", "UTC");
955
+ if (!utcOffset.includes("+") && !utcOffset.includes("-")) {
956
+ utcOffset = `${utcOffset}+00:00`;
957
+ }
958
+ return utcOffset;
959
+ } catch (error) {
960
+ return "";
961
+ }
962
+ };
963
+ const getTimezones = (selectedDate) => {
964
+ const timezoneList = Intl.supportedValuesOf("timeZone").map((timezone) => {
965
+ const utcOffset = getTimezoneOffset(timezone, selectedDate);
966
+ return { offset: utcOffset, value: `${utcOffset}&${timezone}` };
793
967
  });
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) {
968
+ const systemTimezone = timezoneList.find(
969
+ (timezone) => timezone.value.split("&")[1] === Intl.DateTimeFormat().resolvedOptions().timeZone
970
+ );
971
+ return { timezoneList, systemTimezone };
972
+ };
973
+ const StyledMenuItem = styledComponents.styled(designSystem.Menu.Item)`
974
+ &:hover {
975
+ background: ${({ theme, $variant = "neutral" }) => theme.colors[`${$variant}100`]};
976
+
977
+ svg {
978
+ fill: ${({ theme, $variant = "neutral" }) => theme.colors[`${$variant}600`]};
979
+ }
980
+
981
+ a {
982
+ color: ${({ theme }) => theme.colors.neutral800};
983
+ }
984
+ }
985
+
986
+ svg {
987
+ color: ${({ theme, $variant = "neutral" }) => theme.colors[`${$variant}500`]};
988
+ }
989
+
990
+ span {
991
+ color: ${({ theme, $variant = "neutral" }) => theme.colors[`${$variant}800`]};
992
+ }
993
+
994
+ span,
995
+ a {
996
+ width: 100%;
997
+ }
998
+ `;
999
+ const DeleteReleaseActionItem = ({ releaseId, actionId }) => {
1000
+ const { formatMessage } = reactIntl.useIntl();
1001
+ const { toggleNotification } = strapiAdmin.useNotification();
1002
+ const { formatAPIError } = strapiAdmin.useAPIErrorHandler();
1003
+ const [deleteReleaseAction] = useDeleteReleaseActionMutation();
1004
+ const {
1005
+ allowedActions: { canDeleteAction }
1006
+ } = strapiAdmin.useRBAC(PERMISSIONS);
1007
+ const handleDeleteAction = async () => {
1008
+ const response = await deleteReleaseAction({
1009
+ params: { releaseId, actionId }
1010
+ });
1011
+ if ("data" in response) {
1012
+ toggleNotification({
1013
+ type: "success",
1014
+ message: formatMessage({
1015
+ id: "content-releases.content-manager-edit-view.remove-from-release.notification.success",
1016
+ defaultMessage: "Entry removed from release"
1017
+ })
1018
+ });
1019
+ return;
1020
+ }
1021
+ if ("error" in response) {
1022
+ if (strapiAdmin.isFetchError(response.error)) {
1023
+ toggleNotification({
1024
+ type: "danger",
1025
+ message: formatAPIError(response.error)
1026
+ });
1027
+ } else {
1028
+ toggleNotification({
1029
+ type: "danger",
1030
+ message: formatMessage({ id: "notification.error", defaultMessage: "An error occurred" })
1031
+ });
1032
+ }
1033
+ }
1034
+ };
1035
+ if (!canDeleteAction) {
805
1036
  return null;
806
1037
  }
807
- if (isCreatingEntry || !hasDraftAndPublish) {
1038
+ return /* @__PURE__ */ jsxRuntime.jsx(StyledMenuItem, { $variant: "danger", onSelect: handleDeleteAction, children: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { gap: 2, children: [
1039
+ /* @__PURE__ */ jsxRuntime.jsx(icons.Cross, { width: "1.6rem", height: "1.6rem" }),
1040
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { textColor: "danger600", variant: "omega", children: formatMessage({
1041
+ id: "content-releases.content-manager-edit-view.remove-from-release",
1042
+ defaultMessage: "Remove from release"
1043
+ }) })
1044
+ ] }) });
1045
+ };
1046
+ const ReleaseActionEntryLinkItem = ({
1047
+ contentTypeUid,
1048
+ documentId,
1049
+ locale
1050
+ }) => {
1051
+ const { formatMessage } = reactIntl.useIntl();
1052
+ const userPermissions = strapiAdmin.useAuth("ReleaseActionEntryLinkItem", (state) => state.permissions);
1053
+ const canUpdateEntryForLocale = React__namespace.useMemo(() => {
1054
+ const updatePermissions = userPermissions.find(
1055
+ (permission) => permission.subject === contentTypeUid && permission.action === "plugin::content-manager.explorer.update"
1056
+ );
1057
+ if (!updatePermissions) {
1058
+ return false;
1059
+ }
1060
+ return Boolean(!locale || updatePermissions.properties?.locales?.includes(locale));
1061
+ }, [contentTypeUid, locale, userPermissions]);
1062
+ const {
1063
+ allowedActions: { canUpdate: canUpdateContentType }
1064
+ } = strapiAdmin.useRBAC({
1065
+ updateContentType: [
1066
+ {
1067
+ action: "plugin::content-manager.explorer.update",
1068
+ subject: contentTypeUid
1069
+ }
1070
+ ]
1071
+ });
1072
+ if (!canUpdateContentType || !canUpdateEntryForLocale) {
808
1073
  return null;
809
1074
  }
810
- const toggleModal = () => setIsModalOpen((prev) => !prev);
1075
+ return /* @__PURE__ */ jsxRuntime.jsx(
1076
+ StyledMenuItem,
1077
+ {
1078
+ tag: reactRouterDom.NavLink,
1079
+ isLink: true,
1080
+ to: {
1081
+ pathname: `/content-manager/collection-types/${contentTypeUid}/${documentId}`,
1082
+ search: locale && `?plugins[i18n][locale]=${locale}`
1083
+ },
1084
+ children: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { gap: 2, children: [
1085
+ /* @__PURE__ */ jsxRuntime.jsx(icons.Pencil, { width: "1.6rem", height: "1.6rem" }),
1086
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "omega", children: formatMessage({
1087
+ id: "content-releases.content-manager-edit-view.edit-entry",
1088
+ defaultMessage: "Edit entry"
1089
+ }) })
1090
+ ] })
1091
+ }
1092
+ );
1093
+ };
1094
+ const EditReleaseItem = ({ releaseId }) => {
1095
+ const { formatMessage } = reactIntl.useIntl();
1096
+ return (
1097
+ /* @ts-expect-error inference isn't working in DS */
1098
+ /* @__PURE__ */ jsxRuntime.jsx(StyledMenuItem, { tag: reactRouterDom.NavLink, isLink: true, to: `/plugins/content-releases/${releaseId}`, children: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { gap: 2, children: [
1099
+ /* @__PURE__ */ jsxRuntime.jsx(icons.Pencil, { width: "1.6rem", height: "1.6rem" }),
1100
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { textColor: "neutral800", variant: "omega", children: formatMessage({
1101
+ id: "content-releases.content-manager-edit-view.edit-release",
1102
+ defaultMessage: "Edit release"
1103
+ }) })
1104
+ ] }) })
1105
+ );
1106
+ };
1107
+ const Root = ({ children }) => {
1108
+ const { formatMessage } = reactIntl.useIntl();
1109
+ const { allowedActions } = strapiAdmin.useRBAC(PERMISSIONS);
1110
+ return (
1111
+ // A user can access the dropdown if they have permissions to delete a release-action OR update a release
1112
+ allowedActions.canDeleteAction || allowedActions.canUpdate ? /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Menu.Root, { children: [
1113
+ /* @__PURE__ */ jsxRuntime.jsx(StyledMoreButton, { variant: "tertiary", endIcon: null, paddingLeft: "7px", paddingRight: "7px", children: /* @__PURE__ */ jsxRuntime.jsx(
1114
+ designSystem.AccessibleIcon,
1115
+ {
1116
+ label: formatMessage({
1117
+ id: "content-releases.content-manager-edit-view.release-action-menu",
1118
+ defaultMessage: "Release action options"
1119
+ }),
1120
+ children: /* @__PURE__ */ jsxRuntime.jsx(icons.More, {})
1121
+ }
1122
+ ) }),
1123
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Menu.Content, { top: 1, popoverPlacement: "bottom-end", children })
1124
+ ] }) : null
1125
+ );
1126
+ };
1127
+ const StyledMoreButton = styledComponents.styled(designSystem.Menu.Trigger)`
1128
+ & > span {
1129
+ display: flex;
1130
+ }
1131
+ `;
1132
+ const ReleaseActionMenu = {
1133
+ Root,
1134
+ EditReleaseItem,
1135
+ DeleteReleaseActionItem,
1136
+ ReleaseActionEntryLinkItem
1137
+ };
1138
+ const Panel = ({ model, documentId, collectionType }) => {
1139
+ const [{ query }] = strapiAdmin.useQueryParams();
1140
+ const locale = query.plugins?.i18n?.locale;
1141
+ const {
1142
+ edit: { options }
1143
+ } = strapiAdmin$1.unstable_useDocumentLayout(model);
1144
+ const { formatMessage, formatDate, formatTime } = reactIntl.useIntl();
1145
+ const { allowedActions } = strapiAdmin.useRBAC(PERMISSIONS);
1146
+ const { canRead, canDeleteAction } = allowedActions;
1147
+ const response = useGetReleasesForEntryQuery({
1148
+ contentType: model,
1149
+ entryDocumentId: documentId,
1150
+ locale,
1151
+ hasEntryAttached: true
1152
+ });
1153
+ const releases = response.data?.data;
811
1154
  const getReleaseColorVariant = (actionType, shade) => {
812
1155
  if (actionType === "unpublish") {
813
1156
  return `secondary${shade}`;
814
1157
  }
815
1158
  return `success${shade}`;
816
1159
  };
817
- if (!canMain) {
1160
+ if (!window.strapi.isEE || !options?.draftAndPublish || !canRead) {
818
1161
  return null;
819
1162
  }
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,
1163
+ if (collectionType === "collection-types" && (!documentId || documentId === "create")) {
1164
+ return null;
1165
+ }
1166
+ if (releases && releases.length === 0) {
1167
+ return null;
1168
+ }
1169
+ return {
1170
+ title: formatMessage({
1171
+ id: "content-releases.plugin.name",
1172
+ defaultMessage: "Releases"
1173
+ }),
1174
+ content: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Flex, { direction: "column", alignItems: "stretch", gap: 3, width: "100%", children: releases?.map((release) => /* @__PURE__ */ jsxRuntime.jsxs(
1175
+ designSystem.Flex,
1176
+ {
1177
+ direction: "column",
1178
+ alignItems: "start",
1179
+ borderWidth: "1px",
1180
+ borderStyle: "solid",
1181
+ borderColor: getReleaseColorVariant(release.actions[0].type, "200"),
1182
+ overflow: "hidden",
1183
+ hasRadius: true,
1184
+ children: [
1185
+ /* @__PURE__ */ jsxRuntime.jsx(
1186
+ designSystem.Box,
919
1187
  {
920
- justifyContent: "center",
1188
+ paddingTop: 3,
1189
+ paddingBottom: 3,
921
1190
  paddingLeft: 4,
922
1191
  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
- })
1192
+ background: getReleaseColorVariant(release.actions[0].type, "100"),
1193
+ width: "100%",
1194
+ children: /* @__PURE__ */ jsxRuntime.jsx(
1195
+ designSystem.Typography,
1196
+ {
1197
+ fontSize: 1,
1198
+ variant: "pi",
1199
+ textColor: getReleaseColorVariant(release.actions[0].type, "600"),
1200
+ children: formatMessage(
1201
+ {
1202
+ id: "content-releases.content-manager-edit-view.list-releases.title",
1203
+ defaultMessage: "{isPublish, select, true {Will be published in} other {Will be unpublished in}}"
1204
+ },
1205
+ { isPublish: release.actions[0].type === "publish" }
1206
+ )
1207
+ }
1208
+ )
931
1209
  }
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
- );
1210
+ ),
1211
+ /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { padding: 4, direction: "column", gap: 2, width: "100%", alignItems: "flex-start", children: [
1212
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { fontSize: 2, fontWeight: "bold", variant: "omega", textColor: "neutral700", children: release.name }),
1213
+ release.scheduledAt && release.timezone && /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "pi", textColor: "neutral600", children: formatMessage(
1214
+ {
1215
+ id: "content-releases.content-manager-edit-view.scheduled.date",
1216
+ defaultMessage: "{date} at {time} ({offset})"
1217
+ },
1218
+ {
1219
+ date: formatDate(new Date(release.scheduledAt), {
1220
+ day: "2-digit",
1221
+ month: "2-digit",
1222
+ year: "numeric",
1223
+ timeZone: release.timezone
1224
+ }),
1225
+ time: formatTime(new Date(release.scheduledAt), {
1226
+ hourCycle: "h23",
1227
+ timeZone: release.timezone
1228
+ }),
1229
+ offset: getTimezoneOffset(release.timezone, new Date(release.scheduledAt))
1230
+ }
1231
+ ) }),
1232
+ canDeleteAction ? /* @__PURE__ */ jsxRuntime.jsxs(ReleaseActionMenu.Root, { hasTriggerBorder: true, children: [
1233
+ /* @__PURE__ */ jsxRuntime.jsx(ReleaseActionMenu.EditReleaseItem, { releaseId: release.id }),
1234
+ /* @__PURE__ */ jsxRuntime.jsx(
1235
+ ReleaseActionMenu.DeleteReleaseActionItem,
1236
+ {
1237
+ releaseId: release.id,
1238
+ actionId: release.actions[0].id
1239
+ }
1240
+ )
1241
+ ] }) : null
1242
+ ] })
1243
+ ]
1244
+ },
1245
+ release.id
1246
+ )) })
1247
+ };
946
1248
  };
947
1249
  const pluginId = "content-releases";
948
1250
  const prefixPluginTranslations = (trad, pluginId2) => {
@@ -966,18 +1268,46 @@ const admin = {
966
1268
  id: `${pluginId}.plugin.name`,
967
1269
  defaultMessage: "Releases"
968
1270
  },
969
- Component: () => Promise.resolve().then(() => require("./App-CqbuK4M6.js")).then((mod) => ({ default: mod.App })),
1271
+ Component: () => Promise.resolve().then(() => require("./App-DpoC8s97.js")).then((mod) => ({ default: mod.App })),
970
1272
  permissions: PERMISSIONS.main,
971
1273
  position: 2
972
1274
  });
973
- app.getPlugin("content-manager").injectComponent("editView", "right-links", {
974
- name: `${pluginId}-link`,
975
- Component: CMReleasesContainer
1275
+ const contentManagerPluginApis = app.getPlugin("content-manager").apis;
1276
+ if ("addEditViewSidePanel" in contentManagerPluginApis && typeof contentManagerPluginApis.addEditViewSidePanel === "function") {
1277
+ contentManagerPluginApis.addEditViewSidePanel([Panel]);
1278
+ }
1279
+ if ("addDocumentAction" in contentManagerPluginApis && typeof contentManagerPluginApis.addDocumentAction === "function") {
1280
+ contentManagerPluginApis.addDocumentAction((actions) => {
1281
+ const indexOfDeleteAction = actions.findIndex((action) => action.type === "unpublish");
1282
+ actions.splice(indexOfDeleteAction, 0, ReleaseActionModalForm);
1283
+ return actions;
1284
+ });
1285
+ }
1286
+ app.addSettingsLink("global", {
1287
+ id: pluginId,
1288
+ to: "releases",
1289
+ intlLabel: {
1290
+ id: `${pluginId}.plugin.name`,
1291
+ defaultMessage: "Releases"
1292
+ },
1293
+ permissions: [],
1294
+ async Component() {
1295
+ const { ProtectedReleasesSettingsPage } = await Promise.resolve().then(() => require("./ReleasesSettingsPage-B89WWWJf.js"));
1296
+ return { default: ProtectedReleasesSettingsPage };
1297
+ }
976
1298
  });
1299
+ if ("addBulkAction" in contentManagerPluginApis && typeof contentManagerPluginApis.addBulkAction === "function") {
1300
+ contentManagerPluginApis.addBulkAction((actions) => {
1301
+ const deleteActionIndex = actions.findIndex((action) => action.type === "delete");
1302
+ actions.splice(deleteActionIndex, 0, ReleaseAction);
1303
+ return actions;
1304
+ });
1305
+ }
1306
+ app.registerHook("Admin/CM/pages/ListView/inject-column-in-table", addColumnToTableHook);
977
1307
  } 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,
1308
+ app.addSettingsLink("global", {
1309
+ id: pluginId,
1310
+ to: "/plugins/purchase-content-releases",
981
1311
  intlLabel: {
982
1312
  id: `${pluginId}.plugin.name`,
983
1313
  defaultMessage: "Releases"
@@ -987,15 +1317,14 @@ const admin = {
987
1317
  const { PurchaseContentReleases } = await Promise.resolve().then(() => require("./PurchaseContentReleases-Be3acS2L.js"));
988
1318
  return { default: PurchaseContentReleases };
989
1319
  },
990
- lockIcon: true,
991
- position: 2
1320
+ licenseOnly: true
992
1321
  });
993
1322
  }
994
1323
  },
995
1324
  async registerTrads({ locales }) {
996
1325
  const importedTrads = await Promise.all(
997
1326
  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 }) => {
1327
+ return __variableDynamicImportRuntimeHelper(/* @__PURE__ */ Object.assign({ "./translations/en.json": () => Promise.resolve().then(() => require("./en-CmYoEnA7.js")) }), `./translations/${locale}.json`).then(({ default: data }) => {
999
1328
  return {
1000
1329
  data: prefixPluginTranslations(data, "content-releases"),
1001
1330
  locale
@@ -1016,14 +1345,17 @@ exports.ReleaseActionMenu = ReleaseActionMenu;
1016
1345
  exports.ReleaseActionOptions = ReleaseActionOptions;
1017
1346
  exports.admin = admin;
1018
1347
  exports.getTimezoneOffset = getTimezoneOffset;
1348
+ exports.getTimezones = getTimezones;
1019
1349
  exports.pluginId = pluginId;
1020
1350
  exports.releaseApi = releaseApi;
1021
1351
  exports.useCreateReleaseMutation = useCreateReleaseMutation;
1022
1352
  exports.useDeleteReleaseMutation = useDeleteReleaseMutation;
1023
1353
  exports.useGetReleaseActionsQuery = useGetReleaseActionsQuery;
1024
1354
  exports.useGetReleaseQuery = useGetReleaseQuery;
1355
+ exports.useGetReleaseSettingsQuery = useGetReleaseSettingsQuery;
1025
1356
  exports.useGetReleasesQuery = useGetReleasesQuery;
1026
1357
  exports.usePublishReleaseMutation = usePublishReleaseMutation;
1027
1358
  exports.useUpdateReleaseActionMutation = useUpdateReleaseActionMutation;
1028
1359
  exports.useUpdateReleaseMutation = useUpdateReleaseMutation;
1029
- //# sourceMappingURL=index-Tedsw4GC.js.map
1360
+ exports.useUpdateReleaseSettingsMutation = useUpdateReleaseSettingsMutation;
1361
+ //# sourceMappingURL=index-sGcuP2hw.js.map