@strapi/content-releases 0.0.0-experimental.c3e9d4b26f9fd3d9eb530b5c11f9baa1d09b13ad → 0.0.0-experimental.c5235059f5636c4549ea2118c75c43b92e2615c8

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 (100) hide show
  1. package/LICENSE +17 -1
  2. package/dist/_chunks/{App-DUmziQ17.js → App-D2cVDqQK.js} +351 -345
  3. package/dist/_chunks/App-D2cVDqQK.js.map +1 -0
  4. package/dist/_chunks/{App-D_6Y9N2F.mjs → App-DbD5Ks8-.mjs} +354 -347
  5. package/dist/_chunks/App-DbD5Ks8-.mjs.map +1 -0
  6. package/dist/_chunks/ReleasesSettingsPage-BDinCYKz.mjs +178 -0
  7. package/dist/_chunks/ReleasesSettingsPage-BDinCYKz.mjs.map +1 -0
  8. package/dist/_chunks/ReleasesSettingsPage-CE_KqB_s.js +178 -0
  9. package/dist/_chunks/ReleasesSettingsPage-CE_KqB_s.js.map +1 -0
  10. package/dist/_chunks/{en-DtFJ5ViE.js → en-CmYoEnA7.js} +9 -2
  11. package/dist/_chunks/en-CmYoEnA7.js.map +1 -0
  12. package/dist/_chunks/{en-B9Ur3VsE.mjs → en-D0yVZFqf.mjs} +9 -2
  13. package/dist/_chunks/en-D0yVZFqf.mjs.map +1 -0
  14. package/dist/_chunks/{index-BomF0-yY.mjs → index-Bgq1X1sL.mjs} +767 -451
  15. package/dist/_chunks/index-Bgq1X1sL.mjs.map +1 -0
  16. package/dist/_chunks/{index-C5Hc767q.js → index-mECKW99O.js} +754 -438
  17. package/dist/_chunks/index-mECKW99O.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/ReleaseModal.d.ts +2 -1
  28. package/dist/admin/src/components/ReleasesPanel.d.ts +3 -0
  29. package/dist/admin/src/constants.d.ts +18 -0
  30. package/dist/admin/src/modules/hooks.d.ts +7 -0
  31. package/dist/admin/src/pages/ReleasesSettingsPage.d.ts +1 -0
  32. package/dist/admin/src/services/release.d.ts +43 -36
  33. package/dist/admin/src/utils/time.d.ts +9 -0
  34. package/dist/admin/src/validation/schemas.d.ts +6 -0
  35. package/dist/server/index.js +796 -623
  36. package/dist/server/index.js.map +1 -1
  37. package/dist/server/index.mjs +797 -624
  38. package/dist/server/index.mjs.map +1 -1
  39. package/dist/server/src/bootstrap.d.ts.map +1 -1
  40. package/dist/server/src/constants.d.ts +11 -2
  41. package/dist/server/src/constants.d.ts.map +1 -1
  42. package/dist/server/src/content-types/index.d.ts +3 -5
  43. package/dist/server/src/content-types/index.d.ts.map +1 -1
  44. package/dist/server/src/content-types/release-action/index.d.ts +3 -5
  45. package/dist/server/src/content-types/release-action/index.d.ts.map +1 -1
  46. package/dist/server/src/content-types/release-action/schema.d.ts +3 -5
  47. package/dist/server/src/content-types/release-action/schema.d.ts.map +1 -1
  48. package/dist/server/src/controllers/index.d.ts +6 -1
  49. package/dist/server/src/controllers/index.d.ts.map +1 -1
  50. package/dist/server/src/controllers/release-action.d.ts.map +1 -1
  51. package/dist/server/src/controllers/release.d.ts +7 -1
  52. package/dist/server/src/controllers/release.d.ts.map +1 -1
  53. package/dist/server/src/controllers/settings.d.ts +11 -0
  54. package/dist/server/src/controllers/settings.d.ts.map +1 -0
  55. package/dist/server/src/controllers/validation/release-action.d.ts +7 -1
  56. package/dist/server/src/controllers/validation/release-action.d.ts.map +1 -1
  57. package/dist/server/src/controllers/validation/release.d.ts +2 -0
  58. package/dist/server/src/controllers/validation/release.d.ts.map +1 -1
  59. package/dist/server/src/controllers/validation/settings.d.ts +3 -0
  60. package/dist/server/src/controllers/validation/settings.d.ts.map +1 -0
  61. package/dist/server/src/index.d.ts +66 -49
  62. package/dist/server/src/index.d.ts.map +1 -1
  63. package/dist/server/src/middlewares/documents.d.ts +6 -0
  64. package/dist/server/src/middlewares/documents.d.ts.map +1 -0
  65. package/dist/server/src/migrations/database/5.0.0-document-id-in-actions.d.ts +9 -0
  66. package/dist/server/src/migrations/database/5.0.0-document-id-in-actions.d.ts.map +1 -0
  67. package/dist/server/src/migrations/index.d.ts.map +1 -1
  68. package/dist/server/src/register.d.ts.map +1 -1
  69. package/dist/server/src/routes/index.d.ts +16 -0
  70. package/dist/server/src/routes/index.d.ts.map +1 -1
  71. package/dist/server/src/routes/release.d.ts.map +1 -1
  72. package/dist/server/src/routes/settings.d.ts +18 -0
  73. package/dist/server/src/routes/settings.d.ts.map +1 -0
  74. package/dist/server/src/services/index.d.ts +38 -38
  75. package/dist/server/src/services/index.d.ts.map +1 -1
  76. package/dist/server/src/services/release-action.d.ts +36 -0
  77. package/dist/server/src/services/release-action.d.ts.map +1 -0
  78. package/dist/server/src/services/release.d.ts +6 -41
  79. package/dist/server/src/services/release.d.ts.map +1 -1
  80. package/dist/server/src/services/settings.d.ts +13 -0
  81. package/dist/server/src/services/settings.d.ts.map +1 -0
  82. package/dist/server/src/services/validation.d.ts +1 -1
  83. package/dist/server/src/services/validation.d.ts.map +1 -1
  84. package/dist/server/src/utils/index.d.ts +29 -8
  85. package/dist/server/src/utils/index.d.ts.map +1 -1
  86. package/dist/shared/contracts/release-actions.d.ts +9 -10
  87. package/dist/shared/contracts/release-actions.d.ts.map +1 -1
  88. package/dist/shared/contracts/releases.d.ts +9 -7
  89. package/dist/shared/contracts/releases.d.ts.map +1 -1
  90. package/dist/shared/contracts/settings.d.ts +39 -0
  91. package/dist/shared/contracts/settings.d.ts.map +1 -0
  92. package/package.json +10 -9
  93. package/dist/_chunks/App-DUmziQ17.js.map +0 -1
  94. package/dist/_chunks/App-D_6Y9N2F.mjs.map +0 -1
  95. package/dist/_chunks/en-B9Ur3VsE.mjs.map +0 -1
  96. package/dist/_chunks/en-DtFJ5ViE.js.map +0 -1
  97. package/dist/_chunks/index-BomF0-yY.mjs.map +0 -1
  98. package/dist/_chunks/index-C5Hc767q.js.map +0 -1
  99. package/dist/shared/validation-schemas.d.ts +0 -2
  100. 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, ModalLayout, ModalHeader, ModalBody, SingleSelect, SingleSelectOption, ModalFooter, 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: (result, error, arg) => [{ 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,296 +516,706 @@ 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
- handleClose,
649
- contentTypeUid,
650
- entryId
525
+ contentType,
526
+ documentId,
527
+ onInputChange,
528
+ values
651
529
  }) => {
652
- const releaseHeaderId = React.useId();
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
- handleClose();
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__ */ jsxs(ModalLayout, { onClose: handleClose, labelledBy: releaseHeaderId, children: [
701
- /* @__PURE__ */ jsx(ModalHeader, { children: /* @__PURE__ */ jsx(Typography, { id: releaseHeaderId, fontWeight: "bold", textColor: "neutral800", 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,
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
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: [
707
699
  {
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(ModalBody, { 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
- }
700
+ action: "plugin::content-manager.explorer.publish",
701
+ subject,
702
+ id: "",
703
+ actionParameters: {},
704
+ properties: {},
705
+ conditions: []
706
+ }
707
+ ]
708
+ };
709
+ return permissions;
710
+ };
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();
724
+ const releases = response.data?.data;
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
+ }
730
841
  )
731
842
  ] }) }),
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__ */ jsx(
746
- ModalFooter,
747
- {
748
- startActions: /* @__PURE__ */ jsx(Button, { onClick: handleClose, variant: "tertiary", name: "cancel", children: formatMessage({
749
- id: "content-releases.content-manager-edit-view.add-to-release.cancel-button",
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",
750
846
  defaultMessage: "Cancel"
751
847
  }) }),
752
- endActions: (
753
- /**
754
- * TODO: Ideally we would use isValid from Formik to disable the button, however currently it always returns true
755
- * for yup.string().required(), even when the value is falsy (including empty string)
756
- */
757
- /* @__PURE__ */ jsx(Button, { type: "submit", disabled: !values.releaseId, loading: isLoading, children: formatMessage({
758
- id: "content-releases.content-manager-edit-view.add-to-release.continue-button",
759
- defaultMessage: "Continue"
760
- }) })
761
- )
762
- }
763
- )
764
- ] });
765
- }
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
+ );
766
856
  }
767
- )
857
+ }
858
+ };
859
+ };
860
+ const StyledButton = styled(Button)`
861
+ span {
862
+ font-weight: 400;
863
+ }
864
+ `;
865
+ const useReleasesList = (contentTypeUid, documentId) => {
866
+ const listViewData = useTable("ListView", (state) => state.rows);
867
+ const documentIds = listViewData.map((entry) => entry.documentId);
868
+ const [{ query }] = useQueryParams();
869
+ const locale = query?.plugins?.i18n?.locale || void 0;
870
+ const response = useGetMappedEntriesInReleasesQuery(
871
+ { contentTypeUid, documentIds, locale },
872
+ { skip: !documentIds || !contentTypeUid || documentIds.length === 0 }
873
+ );
874
+ const mappedEntriesInReleases = response.data || {};
875
+ return mappedEntriesInReleases?.[documentId] || [];
876
+ };
877
+ const addColumnToTableHook = ({ displayedHeaders, layout }) => {
878
+ const { options } = layout;
879
+ if (!options?.draftAndPublish) {
880
+ return { displayedHeaders, layout };
881
+ }
882
+ return {
883
+ displayedHeaders: [
884
+ ...displayedHeaders,
885
+ {
886
+ searchable: false,
887
+ sortable: false,
888
+ name: "releases",
889
+ label: {
890
+ id: "content-releases.content-manager.list-view.releases.header",
891
+ defaultMessage: "To be released in"
892
+ },
893
+ cellFormatter: (props, _, { model }) => /* @__PURE__ */ jsx(ReleaseListCell, { ...props, model })
894
+ }
895
+ ],
896
+ layout
897
+ };
898
+ };
899
+ const ReleaseListCell = ({ documentId, model }) => {
900
+ const releases = useReleasesList(model, documentId);
901
+ const { formatMessage } = useIntl();
902
+ return /* @__PURE__ */ jsxs(Popover.Root, { children: [
903
+ /* @__PURE__ */ jsx(Popover.Trigger, { children: /* @__PURE__ */ jsx(
904
+ StyledButton,
905
+ {
906
+ variant: "ghost",
907
+ onClick: (e) => e.stopPropagation(),
908
+ endIcon: /* @__PURE__ */ jsx(CaretDown, {}),
909
+ children: /* @__PURE__ */ jsx(Typography, { style: { maxWidth: "252px", cursor: "pointer" }, textColor: "neutral800", children: releases.length > 0 ? formatMessage(
910
+ {
911
+ id: "content-releases.content-manager.list-view.releases-number",
912
+ defaultMessage: "{number} {number, plural, one {release} other {releases}}"
913
+ },
914
+ {
915
+ number: releases.length
916
+ }
917
+ ) : "-" })
918
+ }
919
+ ) }),
920
+ /* @__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)) }) })
768
921
  ] });
769
922
  };
770
- const CMReleasesContainer = () => {
771
- const [isModalOpen, setIsModalOpen] = React.useState(false);
772
- const { formatMessage, formatDate, formatTime } = useIntl();
773
- const { id, slug, collectionType } = useParams();
774
- const isCreatingEntry = id === "create";
775
- const entryId = parseInt(id, 10);
776
- const { allowedActions } = useRBAC(PERMISSIONS);
777
- const { canCreateAction, canRead: canMain, canDeleteAction } = allowedActions;
778
- const { schema } = unstable_useDocument({
779
- collectionType,
780
- model: slug
923
+ const getTimezoneOffset = (timezone, date) => {
924
+ try {
925
+ const offsetPart = new Intl.DateTimeFormat("en", {
926
+ timeZone: timezone,
927
+ timeZoneName: "longOffset"
928
+ }).formatToParts(date).find((part) => part.type === "timeZoneName");
929
+ const offset = offsetPart ? offsetPart.value : "";
930
+ let utcOffset = offset.replace("GMT", "UTC");
931
+ if (!utcOffset.includes("+") && !utcOffset.includes("-")) {
932
+ utcOffset = `${utcOffset}+00:00`;
933
+ }
934
+ return utcOffset;
935
+ } catch (error) {
936
+ return "";
937
+ }
938
+ };
939
+ const getTimezones = (selectedDate) => {
940
+ const timezoneList = Intl.supportedValuesOf("timeZone").map((timezone) => {
941
+ const utcOffset = getTimezoneOffset(timezone, selectedDate);
942
+ return { offset: utcOffset, value: `${utcOffset}&${timezone}` };
781
943
  });
782
- const hasDraftAndPublish = schema?.options?.draftAndPublish;
783
- const contentTypeUid = slug;
784
- const canFetch = id != null && contentTypeUid != null;
785
- const fetchParams = canFetch ? {
786
- contentTypeUid,
787
- entryId,
788
- hasEntryAttached: true
789
- } : skipToken;
790
- const response = useGetReleasesForEntryQuery(fetchParams);
791
- const releases = response.data?.data;
792
- if (!canFetch) {
944
+ const systemTimezone = timezoneList.find(
945
+ (timezone) => timezone.value.split("&")[1] === Intl.DateTimeFormat().resolvedOptions().timeZone
946
+ );
947
+ return { timezoneList, systemTimezone };
948
+ };
949
+ const StyledMenuItem = styled(Menu.Item)`
950
+ &:hover {
951
+ background: ${({ theme, $variant = "neutral" }) => theme.colors[`${$variant}100`]};
952
+
953
+ svg {
954
+ fill: ${({ theme, $variant = "neutral" }) => theme.colors[`${$variant}600`]};
955
+ }
956
+
957
+ a {
958
+ color: ${({ theme }) => theme.colors.neutral800};
959
+ }
960
+ }
961
+
962
+ svg {
963
+ color: ${({ theme, $variant = "neutral" }) => theme.colors[`${$variant}500`]};
964
+ }
965
+
966
+ span {
967
+ color: ${({ theme, $variant = "neutral" }) => theme.colors[`${$variant}800`]};
968
+ }
969
+
970
+ span,
971
+ a {
972
+ width: 100%;
973
+ }
974
+ `;
975
+ const DeleteReleaseActionItem = ({ releaseId, actionId }) => {
976
+ const { formatMessage } = useIntl();
977
+ const { toggleNotification } = useNotification();
978
+ const { formatAPIError } = useAPIErrorHandler();
979
+ const [deleteReleaseAction] = useDeleteReleaseActionMutation();
980
+ const {
981
+ allowedActions: { canDeleteAction }
982
+ } = useRBAC(PERMISSIONS);
983
+ const handleDeleteAction = async () => {
984
+ const response = await deleteReleaseAction({
985
+ params: { releaseId, actionId }
986
+ });
987
+ if ("data" in response) {
988
+ toggleNotification({
989
+ type: "success",
990
+ message: formatMessage({
991
+ id: "content-releases.content-manager-edit-view.remove-from-release.notification.success",
992
+ defaultMessage: "Entry removed from release"
993
+ })
994
+ });
995
+ return;
996
+ }
997
+ if ("error" in response) {
998
+ if (isFetchError(response.error)) {
999
+ toggleNotification({
1000
+ type: "danger",
1001
+ message: formatAPIError(response.error)
1002
+ });
1003
+ } else {
1004
+ toggleNotification({
1005
+ type: "danger",
1006
+ message: formatMessage({ id: "notification.error", defaultMessage: "An error occurred" })
1007
+ });
1008
+ }
1009
+ }
1010
+ };
1011
+ if (!canDeleteAction) {
793
1012
  return null;
794
1013
  }
795
- if (isCreatingEntry || !hasDraftAndPublish) {
1014
+ return /* @__PURE__ */ jsx(StyledMenuItem, { $variant: "danger", onSelect: handleDeleteAction, children: /* @__PURE__ */ jsxs(Flex, { gap: 2, children: [
1015
+ /* @__PURE__ */ jsx(Cross, { width: "1.6rem", height: "1.6rem" }),
1016
+ /* @__PURE__ */ jsx(Typography, { textColor: "danger600", variant: "omega", children: formatMessage({
1017
+ id: "content-releases.content-manager-edit-view.remove-from-release",
1018
+ defaultMessage: "Remove from release"
1019
+ }) })
1020
+ ] }) });
1021
+ };
1022
+ const ReleaseActionEntryLinkItem = ({
1023
+ contentTypeUid,
1024
+ documentId,
1025
+ locale
1026
+ }) => {
1027
+ const { formatMessage } = useIntl();
1028
+ const userPermissions = useAuth("ReleaseActionEntryLinkItem", (state) => state.permissions);
1029
+ const canUpdateEntryForLocale = React.useMemo(() => {
1030
+ const updatePermissions = userPermissions.find(
1031
+ (permission) => permission.subject === contentTypeUid && permission.action === "plugin::content-manager.explorer.update"
1032
+ );
1033
+ if (!updatePermissions) {
1034
+ return false;
1035
+ }
1036
+ return Boolean(!locale || updatePermissions.properties?.locales?.includes(locale));
1037
+ }, [contentTypeUid, locale, userPermissions]);
1038
+ const {
1039
+ allowedActions: { canUpdate: canUpdateContentType }
1040
+ } = useRBAC({
1041
+ updateContentType: [
1042
+ {
1043
+ action: "plugin::content-manager.explorer.update",
1044
+ subject: contentTypeUid
1045
+ }
1046
+ ]
1047
+ });
1048
+ if (!canUpdateContentType || !canUpdateEntryForLocale) {
796
1049
  return null;
797
1050
  }
798
- const toggleModal = () => setIsModalOpen((prev) => !prev);
1051
+ return /* @__PURE__ */ jsx(
1052
+ StyledMenuItem,
1053
+ {
1054
+ tag: NavLink,
1055
+ isLink: true,
1056
+ to: {
1057
+ pathname: `/content-manager/collection-types/${contentTypeUid}/${documentId}`,
1058
+ search: locale && `?plugins[i18n][locale]=${locale}`
1059
+ },
1060
+ children: /* @__PURE__ */ jsxs(Flex, { gap: 2, children: [
1061
+ /* @__PURE__ */ jsx(Pencil, { width: "1.6rem", height: "1.6rem" }),
1062
+ /* @__PURE__ */ jsx(Typography, { variant: "omega", children: formatMessage({
1063
+ id: "content-releases.content-manager-edit-view.edit-entry",
1064
+ defaultMessage: "Edit entry"
1065
+ }) })
1066
+ ] })
1067
+ }
1068
+ );
1069
+ };
1070
+ const EditReleaseItem = ({ releaseId }) => {
1071
+ const { formatMessage } = useIntl();
1072
+ return (
1073
+ /* @ts-expect-error inference isn't working in DS */
1074
+ /* @__PURE__ */ jsx(StyledMenuItem, { tag: NavLink, isLink: true, to: `/plugins/content-releases/${releaseId}`, children: /* @__PURE__ */ jsxs(Flex, { gap: 2, children: [
1075
+ /* @__PURE__ */ jsx(Pencil, { width: "1.6rem", height: "1.6rem" }),
1076
+ /* @__PURE__ */ jsx(Typography, { textColor: "neutral800", variant: "omega", children: formatMessage({
1077
+ id: "content-releases.content-manager-edit-view.edit-release",
1078
+ defaultMessage: "Edit release"
1079
+ }) })
1080
+ ] }) })
1081
+ );
1082
+ };
1083
+ const Root = ({ children }) => {
1084
+ const { formatMessage } = useIntl();
1085
+ const { allowedActions } = useRBAC(PERMISSIONS);
1086
+ return (
1087
+ // A user can access the dropdown if they have permissions to delete a release-action OR update a release
1088
+ allowedActions.canDeleteAction || allowedActions.canUpdate ? /* @__PURE__ */ jsxs(Menu.Root, { children: [
1089
+ /* @__PURE__ */ jsx(Menu.Trigger, { variant: "tertiary", endIcon: null, paddingLeft: "7px", paddingRight: "7px", children: /* @__PURE__ */ jsx(
1090
+ AccessibleIcon,
1091
+ {
1092
+ label: formatMessage({
1093
+ id: "content-releases.content-manager-edit-view.release-action-menu",
1094
+ defaultMessage: "Release action options"
1095
+ }),
1096
+ children: /* @__PURE__ */ jsx(More, {})
1097
+ }
1098
+ ) }),
1099
+ /* @__PURE__ */ jsx(Menu.Content, { top: 1, popoverPlacement: "bottom-end", children })
1100
+ ] }) : null
1101
+ );
1102
+ };
1103
+ const ReleaseActionMenu = {
1104
+ Root,
1105
+ EditReleaseItem,
1106
+ DeleteReleaseActionItem,
1107
+ ReleaseActionEntryLinkItem
1108
+ };
1109
+ const Panel = ({ model, documentId, collectionType }) => {
1110
+ const [{ query }] = useQueryParams();
1111
+ const locale = query.plugins?.i18n?.locale;
1112
+ const {
1113
+ edit: { options }
1114
+ } = unstable_useDocumentLayout(model);
1115
+ const { formatMessage, formatDate, formatTime } = useIntl();
1116
+ const { allowedActions } = useRBAC(PERMISSIONS);
1117
+ const { canRead, canDeleteAction } = allowedActions;
1118
+ const response = useGetReleasesForEntryQuery({
1119
+ contentType: model,
1120
+ entryDocumentId: documentId,
1121
+ locale,
1122
+ hasEntryAttached: true
1123
+ });
1124
+ const releases = response.data?.data;
799
1125
  const getReleaseColorVariant = (actionType, shade) => {
800
1126
  if (actionType === "unpublish") {
801
1127
  return `secondary${shade}`;
802
1128
  }
803
1129
  return `success${shade}`;
804
1130
  };
805
- if (!canMain) {
1131
+ if (!window.strapi.isEE || !options?.draftAndPublish || !canRead) {
806
1132
  return null;
807
1133
  }
808
- return /* @__PURE__ */ jsxs(
809
- Box,
810
- {
811
- tag: "aside",
812
- "aria-label": formatMessage({
813
- id: "content-releases.plugin.name",
814
- defaultMessage: "Releases"
815
- }),
816
- background: "neutral0",
817
- borderColor: "neutral150",
818
- hasRadius: true,
819
- padding: 4,
820
- shadow: "tableShadow",
821
- children: [
822
- /* @__PURE__ */ jsxs(Flex, { direction: "column", alignItems: "stretch", gap: 3, children: [
823
- /* @__PURE__ */ jsx(Typography, { variant: "sigma", textColor: "neutral600", textTransform: "uppercase", children: formatMessage({
824
- id: "content-releases.plugin.name",
825
- defaultMessage: "Releases"
826
- }) }),
827
- releases?.map((release) => {
828
- return /* @__PURE__ */ jsxs(
829
- Flex,
830
- {
831
- direction: "column",
832
- alignItems: "start",
833
- borderWidth: "1px",
834
- borderStyle: "solid",
835
- borderColor: getReleaseColorVariant(release.actions[0].type, "200"),
836
- overflow: "hidden",
837
- hasRadius: true,
838
- children: [
839
- /* @__PURE__ */ jsx(
840
- Box,
841
- {
842
- paddingTop: 3,
843
- paddingBottom: 3,
844
- paddingLeft: 4,
845
- paddingRight: 4,
846
- background: getReleaseColorVariant(release.actions[0].type, "100"),
847
- width: "100%",
848
- children: /* @__PURE__ */ jsx(
849
- Typography,
850
- {
851
- fontSize: 1,
852
- variant: "pi",
853
- textColor: getReleaseColorVariant(release.actions[0].type, "600"),
854
- children: formatMessage(
855
- {
856
- id: "content-releases.content-manager-edit-view.list-releases.title",
857
- defaultMessage: "{isPublish, select, true {Will be published in} other {Will be unpublished in}}"
858
- },
859
- { isPublish: release.actions[0].type === "publish" }
860
- )
861
- }
862
- )
863
- }
864
- ),
865
- /* @__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: [
866
- /* @__PURE__ */ jsx(Typography, { fontSize: 2, fontWeight: "bold", variant: "omega", textColor: "neutral700", children: release.name }),
867
- release.scheduledAt && release.timezone && /* @__PURE__ */ jsx(Typography, { variant: "pi", textColor: "neutral600", children: formatMessage(
868
- {
869
- id: "content-releases.content-manager-edit-view.scheduled.date",
870
- defaultMessage: "{date} at {time} ({offset})"
871
- },
872
- {
873
- date: formatDate(new Date(release.scheduledAt), {
874
- day: "2-digit",
875
- month: "2-digit",
876
- year: "numeric",
877
- timeZone: release.timezone
878
- }),
879
- time: formatTime(new Date(release.scheduledAt), {
880
- hourCycle: "h23",
881
- timeZone: release.timezone
882
- }),
883
- offset: getTimezoneOffset(
884
- release.timezone,
885
- new Date(release.scheduledAt)
886
- )
887
- }
888
- ) }),
889
- canDeleteAction ? /* @__PURE__ */ jsxs(ReleaseActionMenu.Root, { hasTriggerBorder: true, children: [
890
- /* @__PURE__ */ jsx(ReleaseActionMenu.EditReleaseItem, { releaseId: release.id }),
891
- /* @__PURE__ */ jsx(
892
- ReleaseActionMenu.DeleteReleaseActionItem,
893
- {
894
- releaseId: release.id,
895
- actionId: release.actions[0].id
896
- }
897
- )
898
- ] }) : null
899
- ] }) })
900
- ]
901
- },
902
- release.id
903
- );
904
- }),
905
- canCreateAction ? /* @__PURE__ */ jsx(
906
- Button,
1134
+ if (collectionType === "collection-types" && (!documentId || documentId === "create")) {
1135
+ return null;
1136
+ }
1137
+ if (releases && releases.length === 0) {
1138
+ return null;
1139
+ }
1140
+ return {
1141
+ title: formatMessage({
1142
+ id: "content-releases.plugin.name",
1143
+ defaultMessage: "Releases"
1144
+ }),
1145
+ content: /* @__PURE__ */ jsx(Flex, { direction: "column", alignItems: "stretch", gap: 3, width: "100%", children: releases?.map((release) => /* @__PURE__ */ jsxs(
1146
+ Flex,
1147
+ {
1148
+ direction: "column",
1149
+ alignItems: "start",
1150
+ borderWidth: "1px",
1151
+ borderStyle: "solid",
1152
+ borderColor: getReleaseColorVariant(release.actions[0].type, "200"),
1153
+ overflow: "hidden",
1154
+ hasRadius: true,
1155
+ children: [
1156
+ /* @__PURE__ */ jsx(
1157
+ Box,
907
1158
  {
908
- justifyContent: "center",
1159
+ paddingTop: 3,
1160
+ paddingBottom: 3,
909
1161
  paddingLeft: 4,
910
1162
  paddingRight: 4,
911
- color: "neutral700",
912
- variant: "tertiary",
913
- startIcon: /* @__PURE__ */ jsx(Plus, {}),
914
- onClick: toggleModal,
915
- children: formatMessage({
916
- id: "content-releases.content-manager-edit-view.add-to-release",
917
- defaultMessage: "Add to release"
918
- })
1163
+ background: getReleaseColorVariant(release.actions[0].type, "100"),
1164
+ width: "100%",
1165
+ children: /* @__PURE__ */ jsx(
1166
+ Typography,
1167
+ {
1168
+ fontSize: 1,
1169
+ variant: "pi",
1170
+ textColor: getReleaseColorVariant(release.actions[0].type, "600"),
1171
+ children: formatMessage(
1172
+ {
1173
+ id: "content-releases.content-manager-edit-view.list-releases.title",
1174
+ defaultMessage: "{isPublish, select, true {Will be published in} other {Will be unpublished in}}"
1175
+ },
1176
+ { isPublish: release.actions[0].type === "publish" }
1177
+ )
1178
+ }
1179
+ )
919
1180
  }
920
- ) : null
921
- ] }),
922
- isModalOpen && /* @__PURE__ */ jsx(
923
- AddActionToReleaseModal,
924
- {
925
- handleClose: toggleModal,
926
- contentTypeUid,
927
- entryId
928
- }
929
- )
930
- ]
931
- }
932
- );
1181
+ ),
1182
+ /* @__PURE__ */ jsxs(Flex, { padding: 4, direction: "column", gap: 2, width: "100%", alignItems: "flex-start", children: [
1183
+ /* @__PURE__ */ jsx(Typography, { fontSize: 2, fontWeight: "bold", variant: "omega", textColor: "neutral700", children: release.name }),
1184
+ release.scheduledAt && release.timezone && /* @__PURE__ */ jsx(Typography, { variant: "pi", textColor: "neutral600", children: formatMessage(
1185
+ {
1186
+ id: "content-releases.content-manager-edit-view.scheduled.date",
1187
+ defaultMessage: "{date} at {time} ({offset})"
1188
+ },
1189
+ {
1190
+ date: formatDate(new Date(release.scheduledAt), {
1191
+ day: "2-digit",
1192
+ month: "2-digit",
1193
+ year: "numeric",
1194
+ timeZone: release.timezone
1195
+ }),
1196
+ time: formatTime(new Date(release.scheduledAt), {
1197
+ hourCycle: "h23",
1198
+ timeZone: release.timezone
1199
+ }),
1200
+ offset: getTimezoneOffset(release.timezone, new Date(release.scheduledAt))
1201
+ }
1202
+ ) }),
1203
+ canDeleteAction ? /* @__PURE__ */ jsxs(ReleaseActionMenu.Root, { hasTriggerBorder: true, children: [
1204
+ /* @__PURE__ */ jsx(ReleaseActionMenu.EditReleaseItem, { releaseId: release.id }),
1205
+ /* @__PURE__ */ jsx(
1206
+ ReleaseActionMenu.DeleteReleaseActionItem,
1207
+ {
1208
+ releaseId: release.id,
1209
+ actionId: release.actions[0].id
1210
+ }
1211
+ )
1212
+ ] }) : null
1213
+ ] })
1214
+ ]
1215
+ },
1216
+ release.id
1217
+ )) })
1218
+ };
933
1219
  };
934
1220
  const pluginId = "content-releases";
935
1221
  const prefixPluginTranslations = (trad, pluginId2) => {
@@ -953,18 +1239,46 @@ const admin = {
953
1239
  id: `${pluginId}.plugin.name`,
954
1240
  defaultMessage: "Releases"
955
1241
  },
956
- Component: () => import("./App-D_6Y9N2F.mjs").then((mod) => ({ default: mod.App })),
1242
+ Component: () => import("./App-DbD5Ks8-.mjs").then((mod) => ({ default: mod.App })),
957
1243
  permissions: PERMISSIONS.main,
958
1244
  position: 2
959
1245
  });
960
- app.getPlugin("content-manager").injectComponent("editView", "right-links", {
961
- name: `${pluginId}-link`,
962
- Component: CMReleasesContainer
1246
+ const contentManagerPluginApis = app.getPlugin("content-manager").apis;
1247
+ if ("addEditViewSidePanel" in contentManagerPluginApis && typeof contentManagerPluginApis.addEditViewSidePanel === "function") {
1248
+ contentManagerPluginApis.addEditViewSidePanel([Panel]);
1249
+ }
1250
+ if ("addDocumentAction" in contentManagerPluginApis && typeof contentManagerPluginApis.addDocumentAction === "function") {
1251
+ contentManagerPluginApis.addDocumentAction((actions) => {
1252
+ const indexOfDeleteAction = actions.findIndex((action) => action.type === "unpublish");
1253
+ actions.splice(indexOfDeleteAction, 0, ReleaseActionModalForm);
1254
+ return actions;
1255
+ });
1256
+ }
1257
+ app.addSettingsLink("global", {
1258
+ id: pluginId,
1259
+ to: "releases",
1260
+ intlLabel: {
1261
+ id: `${pluginId}.plugin.name`,
1262
+ defaultMessage: "Releases"
1263
+ },
1264
+ permissions: [],
1265
+ async Component() {
1266
+ const { ProtectedReleasesSettingsPage } = await import("./ReleasesSettingsPage-BDinCYKz.mjs");
1267
+ return { default: ProtectedReleasesSettingsPage };
1268
+ }
963
1269
  });
1270
+ if ("addBulkAction" in contentManagerPluginApis && typeof contentManagerPluginApis.addBulkAction === "function") {
1271
+ contentManagerPluginApis.addBulkAction((actions) => {
1272
+ const deleteActionIndex = actions.findIndex((action) => action.type === "delete");
1273
+ actions.splice(deleteActionIndex, 0, ReleaseAction);
1274
+ return actions;
1275
+ });
1276
+ }
1277
+ app.registerHook("Admin/CM/pages/ListView/inject-column-in-table", addColumnToTableHook);
964
1278
  } else if (!window.strapi.features.isEnabled("cms-content-releases") && window.strapi?.flags?.promoteEE) {
965
- app.addMenuLink({
966
- to: `/plugins/purchase-content-releases`,
967
- icon: PaperPlane,
1279
+ app.addSettingsLink("global", {
1280
+ id: pluginId,
1281
+ to: "/plugins/purchase-content-releases",
968
1282
  intlLabel: {
969
1283
  id: `${pluginId}.plugin.name`,
970
1284
  defaultMessage: "Releases"
@@ -974,15 +1288,14 @@ const admin = {
974
1288
  const { PurchaseContentReleases } = await import("./PurchaseContentReleases-_MxP6-Dt.mjs");
975
1289
  return { default: PurchaseContentReleases };
976
1290
  },
977
- lockIcon: true,
978
- position: 2
1291
+ licenseOnly: true
979
1292
  });
980
1293
  }
981
1294
  },
982
1295
  async registerTrads({ locales }) {
983
1296
  const importedTrads = await Promise.all(
984
1297
  locales.map((locale) => {
985
- return __variableDynamicImportRuntimeHelper(/* @__PURE__ */ Object.assign({ "./translations/en.json": () => import("./en-B9Ur3VsE.mjs") }), `./translations/${locale}.json`).then(({ default: data }) => {
1298
+ return __variableDynamicImportRuntimeHelper(/* @__PURE__ */ Object.assign({ "./translations/en.json": () => import("./en-D0yVZFqf.mjs") }), `./translations/${locale}.json`).then(({ default: data }) => {
986
1299
  return {
987
1300
  data: prefixPluginTranslations(data, "content-releases"),
988
1301
  locale
@@ -1001,18 +1314,21 @@ const admin = {
1001
1314
  export {
1002
1315
  PERMISSIONS as P,
1003
1316
  ReleaseActionOptions as R,
1004
- useCreateReleaseMutation as a,
1005
- useGetReleaseQuery as b,
1006
- useUpdateReleaseMutation as c,
1007
- useDeleteReleaseMutation as d,
1008
- usePublishReleaseMutation as e,
1009
- useGetReleaseActionsQuery as f,
1010
- getTimezoneOffset as g,
1011
- useUpdateReleaseActionMutation as h,
1012
- ReleaseActionMenu as i,
1013
- admin as j,
1317
+ useGetReleaseSettingsQuery as a,
1318
+ useCreateReleaseMutation as b,
1319
+ useGetReleaseQuery as c,
1320
+ useUpdateReleaseMutation as d,
1321
+ useDeleteReleaseMutation as e,
1322
+ usePublishReleaseMutation as f,
1323
+ getTimezones as g,
1324
+ getTimezoneOffset as h,
1325
+ useGetReleaseActionsQuery as i,
1326
+ useUpdateReleaseActionMutation as j,
1327
+ ReleaseActionMenu as k,
1328
+ useUpdateReleaseSettingsMutation as l,
1329
+ admin as m,
1014
1330
  pluginId as p,
1015
1331
  releaseApi as r,
1016
1332
  useGetReleasesQuery as u
1017
1333
  };
1018
- //# sourceMappingURL=index-BomF0-yY.mjs.map
1334
+ //# sourceMappingURL=index-Bgq1X1sL.mjs.map