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

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-B2R2exNT.mjs → App-DMILern_.mjs} +295 -262
  3. package/dist/_chunks/App-DMILern_.mjs.map +1 -0
  4. package/dist/_chunks/{App-CEwOQkKT.js → App-fAgiijnc.js} +292 -260
  5. package/dist/_chunks/App-fAgiijnc.js.map +1 -0
  6. package/dist/_chunks/ReleasesSettingsPage-YVZJH-oN.js +178 -0
  7. package/dist/_chunks/ReleasesSettingsPage-YVZJH-oN.js.map +1 -0
  8. package/dist/_chunks/ReleasesSettingsPage-dwoRuXB-.mjs +178 -0
  9. package/dist/_chunks/ReleasesSettingsPage-dwoRuXB-.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-BrWv-zV4.js → index--_NWfuDG.js} +760 -431
  15. package/dist/_chunks/index--_NWfuDG.js.map +1 -0
  16. package/dist/_chunks/{index-DbmynICx.mjs → index-CYsQToWs.mjs} +777 -448
  17. package/dist/_chunks/index-CYsQToWs.mjs.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-B2R2exNT.mjs.map +0 -1
  93. package/dist/_chunks/App-CEwOQkKT.js.map +0 -1
  94. package/dist/_chunks/en-B9Ur3VsE.mjs.map +0 -1
  95. package/dist/_chunks/en-DtFJ5ViE.js.map +0 -1
  96. package/dist/_chunks/index-BrWv-zV4.js.map +0 -1
  97. package/dist/_chunks/index-DbmynICx.mjs.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,711 @@ 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 StyledButton = styledComponents.styled(designSystem.Button)`
882
+ span {
883
+ font-weight: 400;
884
+ }
885
+ `;
886
+ const useReleasesList = (contentTypeUid, documentId) => {
887
+ const listViewData = strapiAdmin.useTable("ListView", (state) => state.rows);
888
+ const documentIds = listViewData.map((entry) => entry.documentId);
889
+ const [{ query }] = strapiAdmin.useQueryParams();
890
+ const locale = query?.plugins?.i18n?.locale || void 0;
891
+ const response = useGetMappedEntriesInReleasesQuery(
892
+ { contentTypeUid, documentIds, locale },
893
+ { skip: !documentIds || !contentTypeUid || documentIds.length === 0 }
894
+ );
895
+ const mappedEntriesInReleases = response.data || {};
896
+ return mappedEntriesInReleases?.[documentId] || [];
897
+ };
898
+ const addColumnToTableHook = ({ displayedHeaders, layout }) => {
899
+ const { options } = layout;
900
+ if (!options?.draftAndPublish) {
901
+ return { displayedHeaders, layout };
902
+ }
903
+ return {
904
+ displayedHeaders: [
905
+ ...displayedHeaders,
906
+ {
907
+ searchable: false,
908
+ sortable: false,
909
+ name: "releases",
910
+ label: {
911
+ id: "content-releases.content-manager.list-view.releases.header",
912
+ defaultMessage: "To be released in"
913
+ },
914
+ cellFormatter: (props, _, { model }) => /* @__PURE__ */ jsxRuntime.jsx(ReleaseListCell, { ...props, model })
915
+ }
916
+ ],
917
+ layout
918
+ };
919
+ };
920
+ const ReleaseListCell = ({ documentId, model }) => {
921
+ const releases = useReleasesList(model, documentId);
922
+ const { formatMessage } = reactIntl.useIntl();
923
+ return /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Popover.Root, { children: [
924
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Popover.Trigger, { children: /* @__PURE__ */ jsxRuntime.jsx(
925
+ StyledButton,
926
+ {
927
+ variant: "ghost",
928
+ onClick: (e) => e.stopPropagation(),
929
+ endIcon: /* @__PURE__ */ jsxRuntime.jsx(icons.CaretDown, {}),
930
+ children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { style: { maxWidth: "252px", cursor: "pointer" }, textColor: "neutral800", children: releases.length > 0 ? formatMessage(
931
+ {
932
+ id: "content-releases.content-manager.list-view.releases-number",
933
+ defaultMessage: "{number} {number, plural, one {release} other {releases}}"
934
+ },
935
+ {
936
+ number: releases.length
937
+ }
938
+ ) : "-" })
939
+ }
940
+ ) }),
941
+ /* @__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)) }) })
942
+ ] });
943
+ };
944
+ const getTimezoneOffset = (timezone, date) => {
945
+ try {
946
+ const offsetPart = new Intl.DateTimeFormat("en", {
947
+ timeZone: timezone,
948
+ timeZoneName: "longOffset"
949
+ }).formatToParts(date).find((part) => part.type === "timeZoneName");
950
+ const offset = offsetPart ? offsetPart.value : "";
951
+ let utcOffset = offset.replace("GMT", "UTC");
952
+ if (!utcOffset.includes("+") && !utcOffset.includes("-")) {
953
+ utcOffset = `${utcOffset}+00:00`;
954
+ }
955
+ return utcOffset;
956
+ } catch (error) {
957
+ return "";
958
+ }
959
+ };
960
+ const getTimezones = (selectedDate) => {
961
+ const timezoneList = Intl.supportedValuesOf("timeZone").map((timezone) => {
962
+ const utcOffset = getTimezoneOffset(timezone, selectedDate);
963
+ return { offset: utcOffset, value: `${utcOffset}&${timezone}` };
793
964
  });
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) {
965
+ const systemTimezone = timezoneList.find(
966
+ (timezone) => timezone.value.split("&")[1] === Intl.DateTimeFormat().resolvedOptions().timeZone
967
+ );
968
+ return { timezoneList, systemTimezone };
969
+ };
970
+ const StyledMenuItem = styledComponents.styled(designSystem.Menu.Item)`
971
+ &:hover {
972
+ background: ${({ theme, $variant = "neutral" }) => theme.colors[`${$variant}100`]};
973
+
974
+ svg {
975
+ fill: ${({ theme, $variant = "neutral" }) => theme.colors[`${$variant}600`]};
976
+ }
977
+
978
+ a {
979
+ color: ${({ theme }) => theme.colors.neutral800};
980
+ }
981
+ }
982
+
983
+ svg {
984
+ color: ${({ theme, $variant = "neutral" }) => theme.colors[`${$variant}500`]};
985
+ }
986
+
987
+ span {
988
+ color: ${({ theme, $variant = "neutral" }) => theme.colors[`${$variant}800`]};
989
+ }
990
+
991
+ span,
992
+ a {
993
+ width: 100%;
994
+ }
995
+ `;
996
+ const DeleteReleaseActionItem = ({ releaseId, actionId }) => {
997
+ const { formatMessage } = reactIntl.useIntl();
998
+ const { toggleNotification } = strapiAdmin.useNotification();
999
+ const { formatAPIError } = strapiAdmin.useAPIErrorHandler();
1000
+ const [deleteReleaseAction] = useDeleteReleaseActionMutation();
1001
+ const {
1002
+ allowedActions: { canDeleteAction }
1003
+ } = strapiAdmin.useRBAC(PERMISSIONS);
1004
+ const handleDeleteAction = async () => {
1005
+ const response = await deleteReleaseAction({
1006
+ params: { releaseId, actionId }
1007
+ });
1008
+ if ("data" in response) {
1009
+ toggleNotification({
1010
+ type: "success",
1011
+ message: formatMessage({
1012
+ id: "content-releases.content-manager-edit-view.remove-from-release.notification.success",
1013
+ defaultMessage: "Entry removed from release"
1014
+ })
1015
+ });
1016
+ return;
1017
+ }
1018
+ if ("error" in response) {
1019
+ if (strapiAdmin.isFetchError(response.error)) {
1020
+ toggleNotification({
1021
+ type: "danger",
1022
+ message: formatAPIError(response.error)
1023
+ });
1024
+ } else {
1025
+ toggleNotification({
1026
+ type: "danger",
1027
+ message: formatMessage({ id: "notification.error", defaultMessage: "An error occurred" })
1028
+ });
1029
+ }
1030
+ }
1031
+ };
1032
+ if (!canDeleteAction) {
805
1033
  return null;
806
1034
  }
807
- if (isCreatingEntry || !hasDraftAndPublish) {
1035
+ return /* @__PURE__ */ jsxRuntime.jsx(StyledMenuItem, { $variant: "danger", onSelect: handleDeleteAction, children: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { gap: 2, children: [
1036
+ /* @__PURE__ */ jsxRuntime.jsx(icons.Cross, { width: "1.6rem", height: "1.6rem" }),
1037
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { textColor: "danger600", variant: "omega", children: formatMessage({
1038
+ id: "content-releases.content-manager-edit-view.remove-from-release",
1039
+ defaultMessage: "Remove from release"
1040
+ }) })
1041
+ ] }) });
1042
+ };
1043
+ const ReleaseActionEntryLinkItem = ({
1044
+ contentTypeUid,
1045
+ documentId,
1046
+ locale
1047
+ }) => {
1048
+ const { formatMessage } = reactIntl.useIntl();
1049
+ const userPermissions = strapiAdmin.useAuth("ReleaseActionEntryLinkItem", (state) => state.permissions);
1050
+ const canUpdateEntryForLocale = React__namespace.useMemo(() => {
1051
+ const updatePermissions = userPermissions.find(
1052
+ (permission) => permission.subject === contentTypeUid && permission.action === "plugin::content-manager.explorer.update"
1053
+ );
1054
+ if (!updatePermissions) {
1055
+ return false;
1056
+ }
1057
+ return Boolean(!locale || updatePermissions.properties?.locales?.includes(locale));
1058
+ }, [contentTypeUid, locale, userPermissions]);
1059
+ const {
1060
+ allowedActions: { canUpdate: canUpdateContentType }
1061
+ } = strapiAdmin.useRBAC({
1062
+ updateContentType: [
1063
+ {
1064
+ action: "plugin::content-manager.explorer.update",
1065
+ subject: contentTypeUid
1066
+ }
1067
+ ]
1068
+ });
1069
+ if (!canUpdateContentType || !canUpdateEntryForLocale) {
808
1070
  return null;
809
1071
  }
810
- const toggleModal = () => setIsModalOpen((prev) => !prev);
1072
+ return /* @__PURE__ */ jsxRuntime.jsx(
1073
+ StyledMenuItem,
1074
+ {
1075
+ tag: reactRouterDom.NavLink,
1076
+ isLink: true,
1077
+ to: {
1078
+ pathname: `/content-manager/collection-types/${contentTypeUid}/${documentId}`,
1079
+ search: locale && `?plugins[i18n][locale]=${locale}`
1080
+ },
1081
+ children: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { gap: 2, children: [
1082
+ /* @__PURE__ */ jsxRuntime.jsx(icons.Pencil, { width: "1.6rem", height: "1.6rem" }),
1083
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "omega", children: formatMessage({
1084
+ id: "content-releases.content-manager-edit-view.edit-entry",
1085
+ defaultMessage: "Edit entry"
1086
+ }) })
1087
+ ] })
1088
+ }
1089
+ );
1090
+ };
1091
+ const EditReleaseItem = ({ releaseId }) => {
1092
+ const { formatMessage } = reactIntl.useIntl();
1093
+ return (
1094
+ /* @ts-expect-error inference isn't working in DS */
1095
+ /* @__PURE__ */ jsxRuntime.jsx(StyledMenuItem, { tag: reactRouterDom.NavLink, isLink: true, to: `/plugins/content-releases/${releaseId}`, children: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { gap: 2, children: [
1096
+ /* @__PURE__ */ jsxRuntime.jsx(icons.Pencil, { width: "1.6rem", height: "1.6rem" }),
1097
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { textColor: "neutral800", variant: "omega", children: formatMessage({
1098
+ id: "content-releases.content-manager-edit-view.edit-release",
1099
+ defaultMessage: "Edit release"
1100
+ }) })
1101
+ ] }) })
1102
+ );
1103
+ };
1104
+ const Root = ({ children }) => {
1105
+ const { formatMessage } = reactIntl.useIntl();
1106
+ const { allowedActions } = strapiAdmin.useRBAC(PERMISSIONS);
1107
+ return (
1108
+ // A user can access the dropdown if they have permissions to delete a release-action OR update a release
1109
+ allowedActions.canDeleteAction || allowedActions.canUpdate ? /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Menu.Root, { children: [
1110
+ /* @__PURE__ */ jsxRuntime.jsx(StyledMoreButton, { variant: "tertiary", endIcon: null, paddingLeft: "7px", paddingRight: "7px", children: /* @__PURE__ */ jsxRuntime.jsx(
1111
+ designSystem.AccessibleIcon,
1112
+ {
1113
+ label: formatMessage({
1114
+ id: "content-releases.content-manager-edit-view.release-action-menu",
1115
+ defaultMessage: "Release action options"
1116
+ }),
1117
+ children: /* @__PURE__ */ jsxRuntime.jsx(icons.More, {})
1118
+ }
1119
+ ) }),
1120
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Menu.Content, { top: 1, popoverPlacement: "bottom-end", children })
1121
+ ] }) : null
1122
+ );
1123
+ };
1124
+ const StyledMoreButton = styledComponents.styled(designSystem.Menu.Trigger)`
1125
+ & > span {
1126
+ display: flex;
1127
+ }
1128
+ `;
1129
+ const ReleaseActionMenu = {
1130
+ Root,
1131
+ EditReleaseItem,
1132
+ DeleteReleaseActionItem,
1133
+ ReleaseActionEntryLinkItem
1134
+ };
1135
+ const Panel = ({ model, documentId, collectionType }) => {
1136
+ const [{ query }] = strapiAdmin.useQueryParams();
1137
+ const locale = query.plugins?.i18n?.locale;
1138
+ const {
1139
+ edit: { options }
1140
+ } = strapiAdmin$1.unstable_useDocumentLayout(model);
1141
+ const { formatMessage, formatDate, formatTime } = reactIntl.useIntl();
1142
+ const { allowedActions } = strapiAdmin.useRBAC(PERMISSIONS);
1143
+ const { canRead, canDeleteAction } = allowedActions;
1144
+ const response = useGetReleasesForEntryQuery({
1145
+ contentType: model,
1146
+ entryDocumentId: documentId,
1147
+ locale,
1148
+ hasEntryAttached: true
1149
+ });
1150
+ const releases = response.data?.data;
811
1151
  const getReleaseColorVariant = (actionType, shade) => {
812
1152
  if (actionType === "unpublish") {
813
1153
  return `secondary${shade}`;
814
1154
  }
815
1155
  return `success${shade}`;
816
1156
  };
817
- if (!canMain) {
1157
+ if (!window.strapi.isEE || !options?.draftAndPublish || !canRead) {
818
1158
  return null;
819
1159
  }
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,
1160
+ if (collectionType === "collection-types" && (!documentId || documentId === "create")) {
1161
+ return null;
1162
+ }
1163
+ if (releases && releases.length === 0) {
1164
+ return null;
1165
+ }
1166
+ return {
1167
+ title: formatMessage({
1168
+ id: "content-releases.plugin.name",
1169
+ defaultMessage: "Releases"
1170
+ }),
1171
+ content: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Flex, { direction: "column", alignItems: "stretch", gap: 3, width: "100%", children: releases?.map((release) => /* @__PURE__ */ jsxRuntime.jsxs(
1172
+ designSystem.Flex,
1173
+ {
1174
+ direction: "column",
1175
+ alignItems: "start",
1176
+ borderWidth: "1px",
1177
+ borderStyle: "solid",
1178
+ borderColor: getReleaseColorVariant(release.actions[0].type, "200"),
1179
+ overflow: "hidden",
1180
+ hasRadius: true,
1181
+ children: [
1182
+ /* @__PURE__ */ jsxRuntime.jsx(
1183
+ designSystem.Box,
919
1184
  {
920
- justifyContent: "center",
1185
+ paddingTop: 3,
1186
+ paddingBottom: 3,
921
1187
  paddingLeft: 4,
922
1188
  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
- })
1189
+ background: getReleaseColorVariant(release.actions[0].type, "100"),
1190
+ width: "100%",
1191
+ children: /* @__PURE__ */ jsxRuntime.jsx(
1192
+ designSystem.Typography,
1193
+ {
1194
+ fontSize: 1,
1195
+ variant: "pi",
1196
+ textColor: getReleaseColorVariant(release.actions[0].type, "600"),
1197
+ children: formatMessage(
1198
+ {
1199
+ id: "content-releases.content-manager-edit-view.list-releases.title",
1200
+ defaultMessage: "{isPublish, select, true {Will be published in} other {Will be unpublished in}}"
1201
+ },
1202
+ { isPublish: release.actions[0].type === "publish" }
1203
+ )
1204
+ }
1205
+ )
931
1206
  }
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
- );
1207
+ ),
1208
+ /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { padding: 4, direction: "column", gap: 2, width: "100%", alignItems: "flex-start", children: [
1209
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { fontSize: 2, fontWeight: "bold", variant: "omega", textColor: "neutral700", children: release.name }),
1210
+ release.scheduledAt && release.timezone && /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "pi", textColor: "neutral600", children: formatMessage(
1211
+ {
1212
+ id: "content-releases.content-manager-edit-view.scheduled.date",
1213
+ defaultMessage: "{date} at {time} ({offset})"
1214
+ },
1215
+ {
1216
+ date: formatDate(new Date(release.scheduledAt), {
1217
+ day: "2-digit",
1218
+ month: "2-digit",
1219
+ year: "numeric",
1220
+ timeZone: release.timezone
1221
+ }),
1222
+ time: formatTime(new Date(release.scheduledAt), {
1223
+ hourCycle: "h23",
1224
+ timeZone: release.timezone
1225
+ }),
1226
+ offset: getTimezoneOffset(release.timezone, new Date(release.scheduledAt))
1227
+ }
1228
+ ) }),
1229
+ canDeleteAction ? /* @__PURE__ */ jsxRuntime.jsxs(ReleaseActionMenu.Root, { hasTriggerBorder: true, children: [
1230
+ /* @__PURE__ */ jsxRuntime.jsx(ReleaseActionMenu.EditReleaseItem, { releaseId: release.id }),
1231
+ /* @__PURE__ */ jsxRuntime.jsx(
1232
+ ReleaseActionMenu.DeleteReleaseActionItem,
1233
+ {
1234
+ releaseId: release.id,
1235
+ actionId: release.actions[0].id
1236
+ }
1237
+ )
1238
+ ] }) : null
1239
+ ] })
1240
+ ]
1241
+ },
1242
+ release.id
1243
+ )) })
1244
+ };
946
1245
  };
947
1246
  const pluginId = "content-releases";
948
1247
  const prefixPluginTranslations = (trad, pluginId2) => {
@@ -966,18 +1265,46 @@ const admin = {
966
1265
  id: `${pluginId}.plugin.name`,
967
1266
  defaultMessage: "Releases"
968
1267
  },
969
- Component: () => Promise.resolve().then(() => require("./App-CEwOQkKT.js")).then((mod) => ({ default: mod.App })),
1268
+ Component: () => Promise.resolve().then(() => require("./App-fAgiijnc.js")).then((mod) => ({ default: mod.App })),
970
1269
  permissions: PERMISSIONS.main,
971
1270
  position: 2
972
1271
  });
973
- app.getPlugin("content-manager").injectComponent("editView", "right-links", {
974
- name: `${pluginId}-link`,
975
- Component: CMReleasesContainer
1272
+ const contentManagerPluginApis = app.getPlugin("content-manager").apis;
1273
+ if ("addEditViewSidePanel" in contentManagerPluginApis && typeof contentManagerPluginApis.addEditViewSidePanel === "function") {
1274
+ contentManagerPluginApis.addEditViewSidePanel([Panel]);
1275
+ }
1276
+ if ("addDocumentAction" in contentManagerPluginApis && typeof contentManagerPluginApis.addDocumentAction === "function") {
1277
+ contentManagerPluginApis.addDocumentAction((actions) => {
1278
+ const indexOfDeleteAction = actions.findIndex((action) => action.type === "unpublish");
1279
+ actions.splice(indexOfDeleteAction, 0, ReleaseActionModalForm);
1280
+ return actions;
1281
+ });
1282
+ }
1283
+ app.addSettingsLink("global", {
1284
+ id: pluginId,
1285
+ to: "releases",
1286
+ intlLabel: {
1287
+ id: `${pluginId}.plugin.name`,
1288
+ defaultMessage: "Releases"
1289
+ },
1290
+ permissions: [],
1291
+ async Component() {
1292
+ const { ProtectedReleasesSettingsPage } = await Promise.resolve().then(() => require("./ReleasesSettingsPage-YVZJH-oN.js"));
1293
+ return { default: ProtectedReleasesSettingsPage };
1294
+ }
976
1295
  });
1296
+ if ("addBulkAction" in contentManagerPluginApis && typeof contentManagerPluginApis.addBulkAction === "function") {
1297
+ contentManagerPluginApis.addBulkAction((actions) => {
1298
+ const deleteActionIndex = actions.findIndex((action) => action.type === "delete");
1299
+ actions.splice(deleteActionIndex, 0, ReleaseAction);
1300
+ return actions;
1301
+ });
1302
+ }
1303
+ app.registerHook("Admin/CM/pages/ListView/inject-column-in-table", addColumnToTableHook);
977
1304
  } 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,
1305
+ app.addSettingsLink("global", {
1306
+ id: pluginId,
1307
+ to: "/plugins/purchase-content-releases",
981
1308
  intlLabel: {
982
1309
  id: `${pluginId}.plugin.name`,
983
1310
  defaultMessage: "Releases"
@@ -987,15 +1314,14 @@ const admin = {
987
1314
  const { PurchaseContentReleases } = await Promise.resolve().then(() => require("./PurchaseContentReleases-Be3acS2L.js"));
988
1315
  return { default: PurchaseContentReleases };
989
1316
  },
990
- licenseOnly: true,
991
- position: 2
1317
+ licenseOnly: true
992
1318
  });
993
1319
  }
994
1320
  },
995
1321
  async registerTrads({ locales }) {
996
1322
  const importedTrads = await Promise.all(
997
1323
  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 }) => {
1324
+ return __variableDynamicImportRuntimeHelper(/* @__PURE__ */ Object.assign({ "./translations/en.json": () => Promise.resolve().then(() => require("./en-CmYoEnA7.js")) }), `./translations/${locale}.json`).then(({ default: data }) => {
999
1325
  return {
1000
1326
  data: prefixPluginTranslations(data, "content-releases"),
1001
1327
  locale
@@ -1016,14 +1342,17 @@ exports.ReleaseActionMenu = ReleaseActionMenu;
1016
1342
  exports.ReleaseActionOptions = ReleaseActionOptions;
1017
1343
  exports.admin = admin;
1018
1344
  exports.getTimezoneOffset = getTimezoneOffset;
1345
+ exports.getTimezones = getTimezones;
1019
1346
  exports.pluginId = pluginId;
1020
1347
  exports.releaseApi = releaseApi;
1021
1348
  exports.useCreateReleaseMutation = useCreateReleaseMutation;
1022
1349
  exports.useDeleteReleaseMutation = useDeleteReleaseMutation;
1023
1350
  exports.useGetReleaseActionsQuery = useGetReleaseActionsQuery;
1024
1351
  exports.useGetReleaseQuery = useGetReleaseQuery;
1352
+ exports.useGetReleaseSettingsQuery = useGetReleaseSettingsQuery;
1025
1353
  exports.useGetReleasesQuery = useGetReleasesQuery;
1026
1354
  exports.usePublishReleaseMutation = usePublishReleaseMutation;
1027
1355
  exports.useUpdateReleaseActionMutation = useUpdateReleaseActionMutation;
1028
1356
  exports.useUpdateReleaseMutation = useUpdateReleaseMutation;
1029
- //# sourceMappingURL=index-BrWv-zV4.js.map
1357
+ exports.useUpdateReleaseSettingsMutation = useUpdateReleaseSettingsMutation;
1358
+ //# sourceMappingURL=index--_NWfuDG.js.map