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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (99) hide show
  1. package/LICENSE +17 -1
  2. package/dist/_chunks/{App-B2R2exNT.mjs → App-DMILern_.mjs} +295 -262
  3. package/dist/_chunks/App-DMILern_.mjs.map +1 -0
  4. package/dist/_chunks/{App-CEwOQkKT.js → App-fAgiijnc.js} +292 -260
  5. package/dist/_chunks/App-fAgiijnc.js.map +1 -0
  6. package/dist/_chunks/ReleasesSettingsPage-YVZJH-oN.js +178 -0
  7. package/dist/_chunks/ReleasesSettingsPage-YVZJH-oN.js.map +1 -0
  8. package/dist/_chunks/ReleasesSettingsPage-dwoRuXB-.mjs +178 -0
  9. package/dist/_chunks/ReleasesSettingsPage-dwoRuXB-.mjs.map +1 -0
  10. package/dist/_chunks/{en-DtFJ5ViE.js → en-CmYoEnA7.js} +9 -2
  11. package/dist/_chunks/en-CmYoEnA7.js.map +1 -0
  12. package/dist/_chunks/{en-B9Ur3VsE.mjs → en-D0yVZFqf.mjs} +9 -2
  13. package/dist/_chunks/en-D0yVZFqf.mjs.map +1 -0
  14. package/dist/_chunks/{index-BrWv-zV4.js → index--_NWfuDG.js} +760 -431
  15. package/dist/_chunks/index--_NWfuDG.js.map +1 -0
  16. package/dist/_chunks/{index-DbmynICx.mjs → index-CYsQToWs.mjs} +777 -448
  17. package/dist/_chunks/index-CYsQToWs.mjs.map +1 -0
  18. package/dist/_chunks/schemas-63pFihNF.mjs +44 -0
  19. package/dist/_chunks/schemas-63pFihNF.mjs.map +1 -0
  20. package/dist/_chunks/schemas-z5zp-_Gd.js +62 -0
  21. package/dist/_chunks/schemas-z5zp-_Gd.js.map +1 -0
  22. package/dist/admin/index.js +1 -1
  23. package/dist/admin/index.mjs +2 -2
  24. package/dist/admin/src/components/ReleaseActionMenu.d.ts +2 -2
  25. package/dist/admin/src/components/{CMReleasesContainer.d.ts → ReleaseActionModal.d.ts} +3 -1
  26. package/dist/admin/src/components/ReleaseListCell.d.ts +28 -0
  27. package/dist/admin/src/components/ReleasesPanel.d.ts +3 -0
  28. package/dist/admin/src/constants.d.ts +18 -0
  29. package/dist/admin/src/modules/hooks.d.ts +7 -0
  30. package/dist/admin/src/pages/ReleasesSettingsPage.d.ts +1 -0
  31. package/dist/admin/src/services/release.d.ts +43 -36
  32. package/dist/admin/src/utils/time.d.ts +9 -0
  33. package/dist/admin/src/validation/schemas.d.ts +6 -0
  34. package/dist/server/index.js +796 -623
  35. package/dist/server/index.js.map +1 -1
  36. package/dist/server/index.mjs +797 -624
  37. package/dist/server/index.mjs.map +1 -1
  38. package/dist/server/src/bootstrap.d.ts.map +1 -1
  39. package/dist/server/src/constants.d.ts +11 -2
  40. package/dist/server/src/constants.d.ts.map +1 -1
  41. package/dist/server/src/content-types/index.d.ts +3 -5
  42. package/dist/server/src/content-types/index.d.ts.map +1 -1
  43. package/dist/server/src/content-types/release-action/index.d.ts +3 -5
  44. package/dist/server/src/content-types/release-action/index.d.ts.map +1 -1
  45. package/dist/server/src/content-types/release-action/schema.d.ts +3 -5
  46. package/dist/server/src/content-types/release-action/schema.d.ts.map +1 -1
  47. package/dist/server/src/controllers/index.d.ts +6 -1
  48. package/dist/server/src/controllers/index.d.ts.map +1 -1
  49. package/dist/server/src/controllers/release-action.d.ts.map +1 -1
  50. package/dist/server/src/controllers/release.d.ts +7 -1
  51. package/dist/server/src/controllers/release.d.ts.map +1 -1
  52. package/dist/server/src/controllers/settings.d.ts +11 -0
  53. package/dist/server/src/controllers/settings.d.ts.map +1 -0
  54. package/dist/server/src/controllers/validation/release-action.d.ts +7 -1
  55. package/dist/server/src/controllers/validation/release-action.d.ts.map +1 -1
  56. package/dist/server/src/controllers/validation/release.d.ts +2 -0
  57. package/dist/server/src/controllers/validation/release.d.ts.map +1 -1
  58. package/dist/server/src/controllers/validation/settings.d.ts +3 -0
  59. package/dist/server/src/controllers/validation/settings.d.ts.map +1 -0
  60. package/dist/server/src/index.d.ts +66 -49
  61. package/dist/server/src/index.d.ts.map +1 -1
  62. package/dist/server/src/middlewares/documents.d.ts +6 -0
  63. package/dist/server/src/middlewares/documents.d.ts.map +1 -0
  64. package/dist/server/src/migrations/database/5.0.0-document-id-in-actions.d.ts +9 -0
  65. package/dist/server/src/migrations/database/5.0.0-document-id-in-actions.d.ts.map +1 -0
  66. package/dist/server/src/migrations/index.d.ts.map +1 -1
  67. package/dist/server/src/register.d.ts.map +1 -1
  68. package/dist/server/src/routes/index.d.ts +16 -0
  69. package/dist/server/src/routes/index.d.ts.map +1 -1
  70. package/dist/server/src/routes/release.d.ts.map +1 -1
  71. package/dist/server/src/routes/settings.d.ts +18 -0
  72. package/dist/server/src/routes/settings.d.ts.map +1 -0
  73. package/dist/server/src/services/index.d.ts +38 -38
  74. package/dist/server/src/services/index.d.ts.map +1 -1
  75. package/dist/server/src/services/release-action.d.ts +36 -0
  76. package/dist/server/src/services/release-action.d.ts.map +1 -0
  77. package/dist/server/src/services/release.d.ts +6 -41
  78. package/dist/server/src/services/release.d.ts.map +1 -1
  79. package/dist/server/src/services/settings.d.ts +13 -0
  80. package/dist/server/src/services/settings.d.ts.map +1 -0
  81. package/dist/server/src/services/validation.d.ts +1 -1
  82. package/dist/server/src/services/validation.d.ts.map +1 -1
  83. package/dist/server/src/utils/index.d.ts +29 -8
  84. package/dist/server/src/utils/index.d.ts.map +1 -1
  85. package/dist/shared/contracts/release-actions.d.ts +9 -10
  86. package/dist/shared/contracts/release-actions.d.ts.map +1 -1
  87. package/dist/shared/contracts/releases.d.ts +9 -7
  88. package/dist/shared/contracts/releases.d.ts.map +1 -1
  89. package/dist/shared/contracts/settings.d.ts +39 -0
  90. package/dist/shared/contracts/settings.d.ts.map +1 -0
  91. package/package.json +10 -9
  92. package/dist/_chunks/App-B2R2exNT.mjs.map +0 -1
  93. package/dist/_chunks/App-CEwOQkKT.js.map +0 -1
  94. package/dist/_chunks/en-B9Ur3VsE.mjs.map +0 -1
  95. package/dist/_chunks/en-DtFJ5ViE.js.map +0 -1
  96. package/dist/_chunks/index-BrWv-zV4.js.map +0 -1
  97. package/dist/_chunks/index-DbmynICx.mjs.map +0 -1
  98. package/dist/shared/validation-schemas.d.ts +0 -2
  99. package/dist/shared/validation-schemas.d.ts.map +0 -1
@@ -1,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,711 @@ 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
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 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)) }) })
921
+ ] });
922
+ };
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}` };
943
+ });
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%;
785
973
  }
786
- if (isCreatingEntry || !hasDraftAndPublish) {
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) {
1012
+ return null;
1013
+ }
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) {
787
1049
  return null;
788
1050
  }
789
- 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(StyledMoreButton, { 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 StyledMoreButton = styled(Menu.Trigger)`
1104
+ & > span {
1105
+ display: flex;
1106
+ }
1107
+ `;
1108
+ const ReleaseActionMenu = {
1109
+ Root,
1110
+ EditReleaseItem,
1111
+ DeleteReleaseActionItem,
1112
+ ReleaseActionEntryLinkItem
1113
+ };
1114
+ const Panel = ({ model, documentId, collectionType }) => {
1115
+ const [{ query }] = useQueryParams();
1116
+ const locale = query.plugins?.i18n?.locale;
1117
+ const {
1118
+ edit: { options }
1119
+ } = unstable_useDocumentLayout(model);
1120
+ const { formatMessage, formatDate, formatTime } = useIntl();
1121
+ const { allowedActions } = useRBAC(PERMISSIONS);
1122
+ const { canRead, canDeleteAction } = allowedActions;
1123
+ const response = useGetReleasesForEntryQuery({
1124
+ contentType: model,
1125
+ entryDocumentId: documentId,
1126
+ locale,
1127
+ hasEntryAttached: true
1128
+ });
1129
+ const releases = response.data?.data;
790
1130
  const getReleaseColorVariant = (actionType, shade) => {
791
1131
  if (actionType === "unpublish") {
792
1132
  return `secondary${shade}`;
793
1133
  }
794
1134
  return `success${shade}`;
795
1135
  };
796
- if (!canMain) {
1136
+ if (!window.strapi.isEE || !options?.draftAndPublish || !canRead) {
797
1137
  return null;
798
1138
  }
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,
1139
+ if (collectionType === "collection-types" && (!documentId || documentId === "create")) {
1140
+ return null;
1141
+ }
1142
+ if (releases && releases.length === 0) {
1143
+ return null;
1144
+ }
1145
+ return {
1146
+ title: formatMessage({
1147
+ id: "content-releases.plugin.name",
1148
+ defaultMessage: "Releases"
1149
+ }),
1150
+ content: /* @__PURE__ */ jsx(Flex, { direction: "column", alignItems: "stretch", gap: 3, width: "100%", children: releases?.map((release) => /* @__PURE__ */ jsxs(
1151
+ Flex,
1152
+ {
1153
+ direction: "column",
1154
+ alignItems: "start",
1155
+ borderWidth: "1px",
1156
+ borderStyle: "solid",
1157
+ borderColor: getReleaseColorVariant(release.actions[0].type, "200"),
1158
+ overflow: "hidden",
1159
+ hasRadius: true,
1160
+ children: [
1161
+ /* @__PURE__ */ jsx(
1162
+ Box,
898
1163
  {
899
- justifyContent: "center",
1164
+ paddingTop: 3,
1165
+ paddingBottom: 3,
900
1166
  paddingLeft: 4,
901
1167
  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
- })
1168
+ background: getReleaseColorVariant(release.actions[0].type, "100"),
1169
+ width: "100%",
1170
+ children: /* @__PURE__ */ jsx(
1171
+ Typography,
1172
+ {
1173
+ fontSize: 1,
1174
+ variant: "pi",
1175
+ textColor: getReleaseColorVariant(release.actions[0].type, "600"),
1176
+ children: formatMessage(
1177
+ {
1178
+ id: "content-releases.content-manager-edit-view.list-releases.title",
1179
+ defaultMessage: "{isPublish, select, true {Will be published in} other {Will be unpublished in}}"
1180
+ },
1181
+ { isPublish: release.actions[0].type === "publish" }
1182
+ )
1183
+ }
1184
+ )
910
1185
  }
911
- ) : null
912
- ] }),
913
- /* @__PURE__ */ jsx(
914
- AddActionToReleaseModal,
915
- {
916
- open: isModalOpen,
917
- onOpenChange: toggleModal,
918
- contentTypeUid,
919
- entryId
920
- }
921
- )
922
- ]
923
- }
924
- );
1186
+ ),
1187
+ /* @__PURE__ */ jsxs(Flex, { padding: 4, direction: "column", gap: 2, width: "100%", alignItems: "flex-start", children: [
1188
+ /* @__PURE__ */ jsx(Typography, { fontSize: 2, fontWeight: "bold", variant: "omega", textColor: "neutral700", children: release.name }),
1189
+ release.scheduledAt && release.timezone && /* @__PURE__ */ jsx(Typography, { variant: "pi", textColor: "neutral600", children: formatMessage(
1190
+ {
1191
+ id: "content-releases.content-manager-edit-view.scheduled.date",
1192
+ defaultMessage: "{date} at {time} ({offset})"
1193
+ },
1194
+ {
1195
+ date: formatDate(new Date(release.scheduledAt), {
1196
+ day: "2-digit",
1197
+ month: "2-digit",
1198
+ year: "numeric",
1199
+ timeZone: release.timezone
1200
+ }),
1201
+ time: formatTime(new Date(release.scheduledAt), {
1202
+ hourCycle: "h23",
1203
+ timeZone: release.timezone
1204
+ }),
1205
+ offset: getTimezoneOffset(release.timezone, new Date(release.scheduledAt))
1206
+ }
1207
+ ) }),
1208
+ canDeleteAction ? /* @__PURE__ */ jsxs(ReleaseActionMenu.Root, { hasTriggerBorder: true, children: [
1209
+ /* @__PURE__ */ jsx(ReleaseActionMenu.EditReleaseItem, { releaseId: release.id }),
1210
+ /* @__PURE__ */ jsx(
1211
+ ReleaseActionMenu.DeleteReleaseActionItem,
1212
+ {
1213
+ releaseId: release.id,
1214
+ actionId: release.actions[0].id
1215
+ }
1216
+ )
1217
+ ] }) : null
1218
+ ] })
1219
+ ]
1220
+ },
1221
+ release.id
1222
+ )) })
1223
+ };
925
1224
  };
926
1225
  const pluginId = "content-releases";
927
1226
  const prefixPluginTranslations = (trad, pluginId2) => {
@@ -945,18 +1244,46 @@ const admin = {
945
1244
  id: `${pluginId}.plugin.name`,
946
1245
  defaultMessage: "Releases"
947
1246
  },
948
- Component: () => import("./App-B2R2exNT.mjs").then((mod) => ({ default: mod.App })),
1247
+ Component: () => import("./App-DMILern_.mjs").then((mod) => ({ default: mod.App })),
949
1248
  permissions: PERMISSIONS.main,
950
1249
  position: 2
951
1250
  });
952
- app.getPlugin("content-manager").injectComponent("editView", "right-links", {
953
- name: `${pluginId}-link`,
954
- Component: CMReleasesContainer
1251
+ const contentManagerPluginApis = app.getPlugin("content-manager").apis;
1252
+ if ("addEditViewSidePanel" in contentManagerPluginApis && typeof contentManagerPluginApis.addEditViewSidePanel === "function") {
1253
+ contentManagerPluginApis.addEditViewSidePanel([Panel]);
1254
+ }
1255
+ if ("addDocumentAction" in contentManagerPluginApis && typeof contentManagerPluginApis.addDocumentAction === "function") {
1256
+ contentManagerPluginApis.addDocumentAction((actions) => {
1257
+ const indexOfDeleteAction = actions.findIndex((action) => action.type === "unpublish");
1258
+ actions.splice(indexOfDeleteAction, 0, ReleaseActionModalForm);
1259
+ return actions;
1260
+ });
1261
+ }
1262
+ app.addSettingsLink("global", {
1263
+ id: pluginId,
1264
+ to: "releases",
1265
+ intlLabel: {
1266
+ id: `${pluginId}.plugin.name`,
1267
+ defaultMessage: "Releases"
1268
+ },
1269
+ permissions: [],
1270
+ async Component() {
1271
+ const { ProtectedReleasesSettingsPage } = await import("./ReleasesSettingsPage-dwoRuXB-.mjs");
1272
+ return { default: ProtectedReleasesSettingsPage };
1273
+ }
955
1274
  });
1275
+ if ("addBulkAction" in contentManagerPluginApis && typeof contentManagerPluginApis.addBulkAction === "function") {
1276
+ contentManagerPluginApis.addBulkAction((actions) => {
1277
+ const deleteActionIndex = actions.findIndex((action) => action.type === "delete");
1278
+ actions.splice(deleteActionIndex, 0, ReleaseAction);
1279
+ return actions;
1280
+ });
1281
+ }
1282
+ app.registerHook("Admin/CM/pages/ListView/inject-column-in-table", addColumnToTableHook);
956
1283
  } 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,
1284
+ app.addSettingsLink("global", {
1285
+ id: pluginId,
1286
+ to: "/plugins/purchase-content-releases",
960
1287
  intlLabel: {
961
1288
  id: `${pluginId}.plugin.name`,
962
1289
  defaultMessage: "Releases"
@@ -966,15 +1293,14 @@ const admin = {
966
1293
  const { PurchaseContentReleases } = await import("./PurchaseContentReleases-_MxP6-Dt.mjs");
967
1294
  return { default: PurchaseContentReleases };
968
1295
  },
969
- licenseOnly: true,
970
- position: 2
1296
+ licenseOnly: true
971
1297
  });
972
1298
  }
973
1299
  },
974
1300
  async registerTrads({ locales }) {
975
1301
  const importedTrads = await Promise.all(
976
1302
  locales.map((locale) => {
977
- return __variableDynamicImportRuntimeHelper(/* @__PURE__ */ Object.assign({ "./translations/en.json": () => import("./en-B9Ur3VsE.mjs") }), `./translations/${locale}.json`).then(({ default: data }) => {
1303
+ return __variableDynamicImportRuntimeHelper(/* @__PURE__ */ Object.assign({ "./translations/en.json": () => import("./en-D0yVZFqf.mjs") }), `./translations/${locale}.json`).then(({ default: data }) => {
978
1304
  return {
979
1305
  data: prefixPluginTranslations(data, "content-releases"),
980
1306
  locale
@@ -993,18 +1319,21 @@ const admin = {
993
1319
  export {
994
1320
  PERMISSIONS as P,
995
1321
  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,
1322
+ useGetReleaseSettingsQuery as a,
1323
+ useCreateReleaseMutation as b,
1324
+ useGetReleaseQuery as c,
1325
+ useUpdateReleaseMutation as d,
1326
+ useDeleteReleaseMutation as e,
1327
+ usePublishReleaseMutation as f,
1328
+ getTimezones as g,
1329
+ getTimezoneOffset as h,
1330
+ useGetReleaseActionsQuery as i,
1331
+ useUpdateReleaseActionMutation as j,
1332
+ ReleaseActionMenu as k,
1333
+ useUpdateReleaseSettingsMutation as l,
1334
+ admin as m,
1006
1335
  pluginId as p,
1007
1336
  releaseApi as r,
1008
1337
  useGetReleasesQuery as u
1009
1338
  };
1010
- //# sourceMappingURL=index-DbmynICx.mjs.map
1339
+ //# sourceMappingURL=index-CYsQToWs.mjs.map