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