@strapi/content-releases 0.0.0-experimental.e5740babedd53cf5b6af99d74920b6b9ef1e4c11 → 0.0.0-experimental.e60ec1829240dae21c1e1d29076681c322288813

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 (110) hide show
  1. package/dist/_chunks/{App-HVXzE3i3.mjs → App-BsUSTHVD.mjs} +243 -213
  2. package/dist/_chunks/App-BsUSTHVD.mjs.map +1 -0
  3. package/dist/_chunks/{App-l62gIUTX.js → App-CXRpb2hi.js} +258 -228
  4. package/dist/_chunks/App-CXRpb2hi.js.map +1 -0
  5. package/dist/_chunks/{PurchaseContentReleases-YhAPgpG9.js → PurchaseContentReleases-Be3acS2L.js} +8 -7
  6. package/dist/_chunks/PurchaseContentReleases-Be3acS2L.js.map +1 -0
  7. package/dist/_chunks/{PurchaseContentReleases-Clm0iACO.mjs → PurchaseContentReleases-_MxP6-Dt.mjs} +9 -8
  8. package/dist/_chunks/PurchaseContentReleases-_MxP6-Dt.mjs.map +1 -0
  9. package/dist/_chunks/{en-RdapH-9X.mjs → en-B9Ur3VsE.mjs} +11 -2
  10. package/dist/_chunks/en-B9Ur3VsE.mjs.map +1 -0
  11. package/dist/_chunks/{en-faJDuv3q.js → en-DtFJ5ViE.js} +11 -2
  12. package/dist/_chunks/en-DtFJ5ViE.js.map +1 -0
  13. package/dist/_chunks/{index-ML_b3php.js → index-B6-lic1Q.js} +340 -113
  14. package/dist/_chunks/index-B6-lic1Q.js.map +1 -0
  15. package/dist/_chunks/{index-Ys87ROOe.mjs → index-DJLIZdZv.mjs} +339 -112
  16. package/dist/_chunks/index-DJLIZdZv.mjs.map +1 -0
  17. package/dist/admin/index.js +1 -15
  18. package/dist/admin/index.js.map +1 -1
  19. package/dist/admin/index.mjs +2 -16
  20. package/dist/admin/index.mjs.map +1 -1
  21. package/dist/admin/src/components/CMReleasesContainer.d.ts +22 -0
  22. package/dist/admin/src/components/RelativeTime.d.ts +28 -0
  23. package/dist/admin/src/components/ReleaseAction.d.ts +3 -0
  24. package/dist/admin/src/components/ReleaseActionMenu.d.ts +26 -0
  25. package/dist/admin/src/components/ReleaseActionOptions.d.ts +9 -0
  26. package/dist/admin/src/components/ReleaseListCell.d.ts +0 -0
  27. package/dist/admin/src/components/ReleaseModal.d.ts +16 -0
  28. package/dist/admin/src/constants.d.ts +58 -0
  29. package/dist/admin/src/index.d.ts +3 -0
  30. package/dist/admin/src/pages/App.d.ts +1 -0
  31. package/dist/admin/src/pages/PurchaseContentReleases.d.ts +2 -0
  32. package/dist/admin/src/pages/ReleaseDetailsPage.d.ts +2 -0
  33. package/dist/admin/src/pages/ReleasesPage.d.ts +8 -0
  34. package/dist/admin/src/pages/tests/mockReleaseDetailsPageData.d.ts +181 -0
  35. package/dist/admin/src/pages/tests/mockReleasesPageData.d.ts +39 -0
  36. package/dist/admin/src/pluginId.d.ts +1 -0
  37. package/dist/admin/src/services/axios.d.ts +29 -0
  38. package/dist/admin/src/services/release.d.ts +429 -0
  39. package/dist/admin/src/store/hooks.d.ts +7 -0
  40. package/dist/admin/src/utils/prefixPluginTranslations.d.ts +3 -0
  41. package/dist/admin/src/utils/time.d.ts +1 -0
  42. package/dist/server/index.js +152 -93
  43. package/dist/server/index.js.map +1 -1
  44. package/dist/server/index.mjs +153 -93
  45. package/dist/server/index.mjs.map +1 -1
  46. package/dist/server/src/bootstrap.d.ts +5 -0
  47. package/dist/server/src/bootstrap.d.ts.map +1 -0
  48. package/dist/server/src/constants.d.ts +12 -0
  49. package/dist/server/src/constants.d.ts.map +1 -0
  50. package/dist/server/src/content-types/index.d.ts +99 -0
  51. package/dist/server/src/content-types/index.d.ts.map +1 -0
  52. package/dist/server/src/content-types/release/index.d.ts +48 -0
  53. package/dist/server/src/content-types/release/index.d.ts.map +1 -0
  54. package/dist/server/src/content-types/release/schema.d.ts +47 -0
  55. package/dist/server/src/content-types/release/schema.d.ts.map +1 -0
  56. package/dist/server/src/content-types/release-action/index.d.ts +50 -0
  57. package/dist/server/src/content-types/release-action/index.d.ts.map +1 -0
  58. package/dist/server/src/content-types/release-action/schema.d.ts +49 -0
  59. package/dist/server/src/content-types/release-action/schema.d.ts.map +1 -0
  60. package/dist/server/src/controllers/index.d.ts +20 -0
  61. package/dist/server/src/controllers/index.d.ts.map +1 -0
  62. package/dist/server/src/controllers/release-action.d.ts +10 -0
  63. package/dist/server/src/controllers/release-action.d.ts.map +1 -0
  64. package/dist/server/src/controllers/release.d.ts +12 -0
  65. package/dist/server/src/controllers/release.d.ts.map +1 -0
  66. package/dist/server/src/controllers/validation/release-action.d.ts +8 -0
  67. package/dist/server/src/controllers/validation/release-action.d.ts.map +1 -0
  68. package/dist/server/src/controllers/validation/release.d.ts +2 -0
  69. package/dist/server/src/controllers/validation/release.d.ts.map +1 -0
  70. package/dist/server/src/destroy.d.ts +5 -0
  71. package/dist/server/src/destroy.d.ts.map +1 -0
  72. package/dist/server/src/index.d.ts +2096 -0
  73. package/dist/server/src/index.d.ts.map +1 -0
  74. package/dist/server/src/migrations/index.d.ts +13 -0
  75. package/dist/server/src/migrations/index.d.ts.map +1 -0
  76. package/dist/server/src/register.d.ts +5 -0
  77. package/dist/server/src/register.d.ts.map +1 -0
  78. package/dist/server/src/routes/index.d.ts +35 -0
  79. package/dist/server/src/routes/index.d.ts.map +1 -0
  80. package/dist/server/src/routes/release-action.d.ts +18 -0
  81. package/dist/server/src/routes/release-action.d.ts.map +1 -0
  82. package/dist/server/src/routes/release.d.ts +18 -0
  83. package/dist/server/src/routes/release.d.ts.map +1 -0
  84. package/dist/server/src/services/index.d.ts +1826 -0
  85. package/dist/server/src/services/index.d.ts.map +1 -0
  86. package/dist/server/src/services/release.d.ts +66 -0
  87. package/dist/server/src/services/release.d.ts.map +1 -0
  88. package/dist/server/src/services/scheduling.d.ts +18 -0
  89. package/dist/server/src/services/scheduling.d.ts.map +1 -0
  90. package/dist/server/src/services/validation.d.ts +18 -0
  91. package/dist/server/src/services/validation.d.ts.map +1 -0
  92. package/dist/server/src/utils/index.d.ts +14 -0
  93. package/dist/server/src/utils/index.d.ts.map +1 -0
  94. package/dist/shared/contracts/release-actions.d.ts +131 -0
  95. package/dist/shared/contracts/release-actions.d.ts.map +1 -0
  96. package/dist/shared/contracts/releases.d.ts +182 -0
  97. package/dist/shared/contracts/releases.d.ts.map +1 -0
  98. package/dist/shared/types.d.ts +24 -0
  99. package/dist/shared/types.d.ts.map +1 -0
  100. package/dist/shared/validation-schemas.d.ts +2 -0
  101. package/dist/shared/validation-schemas.d.ts.map +1 -0
  102. package/package.json +26 -31
  103. package/dist/_chunks/App-HVXzE3i3.mjs.map +0 -1
  104. package/dist/_chunks/App-l62gIUTX.js.map +0 -1
  105. package/dist/_chunks/PurchaseContentReleases-Clm0iACO.mjs.map +0 -1
  106. package/dist/_chunks/PurchaseContentReleases-YhAPgpG9.js.map +0 -1
  107. package/dist/_chunks/en-RdapH-9X.mjs.map +0 -1
  108. package/dist/_chunks/en-faJDuv3q.js.map +0 -1
  109. package/dist/_chunks/index-ML_b3php.js.map +0 -1
  110. package/dist/_chunks/index-Ys87ROOe.mjs.map +0 -1
@@ -1,18 +1,18 @@
1
- import { getFetchClient, useNotification, useAPIErrorHandler, CheckPermissions, useCMEditViewDataManager, NoContent, prefixPluginTranslations } from "@strapi/helper-plugin";
2
1
  import { Cross, Pencil, More, Plus, PaperPlane } from "@strapi/icons";
3
2
  import { jsx, jsxs } from "react/jsx-runtime";
4
3
  import * as React from "react";
5
4
  import { skipToken } from "@reduxjs/toolkit/query";
6
- import { IconButton, Flex, Icon, Typography, Field, FieldLabel, VisuallyHidden, FieldInput, Box, Button, ModalLayout, ModalHeader, ModalBody, SingleSelect, SingleSelectOption, ModalFooter } from "@strapi/design-system";
7
- import { Menu, Link, LinkButton } from "@strapi/design-system/v2";
5
+ import { getFetchClient, useNotification, useAPIErrorHandler, useRBAC, useAuth, useQueryParams } from "@strapi/admin/strapi-admin";
6
+ import { unstable_useDocument } from "@strapi/content-manager/strapi-admin";
7
+ import { Menu, IconButton, Flex, Typography, Field, FieldLabel, VisuallyHidden, FieldInput, Box, Button, EmptyStateLayout, LinkButton, ModalLayout, ModalHeader, ModalBody, SingleSelect, SingleSelectOption, ModalFooter } from "@strapi/design-system";
8
+ import { EmptyDocuments } from "@strapi/icons/symbols";
8
9
  import { isAxiosError as isAxiosError$1 } from "axios";
9
10
  import { Formik, Form } from "formik";
10
11
  import { useIntl } from "react-intl";
11
- import { NavLink, Link as Link$1 } from "react-router-dom";
12
+ import { Link, useParams } from "react-router-dom";
12
13
  import * as yup from "yup";
13
14
  import { createApi } from "@reduxjs/toolkit/query/react";
14
15
  import styled from "styled-components";
15
- import { useDispatch, useSelector } from "react-redux";
16
16
  const __variableDynamicImportRuntimeHelper = (glob, path) => {
17
17
  const v = glob[path];
18
18
  if (v) {
@@ -136,7 +136,7 @@ const isAxiosError = (err) => {
136
136
  const releaseApi = createApi({
137
137
  reducerPath: pluginId,
138
138
  baseQuery: axiosBaseQuery,
139
- tagTypes: ["Release", "ReleaseAction"],
139
+ tagTypes: ["Release", "ReleaseAction", "EntriesInRelease"],
140
140
  endpoints: (build) => {
141
141
  return {
142
142
  getReleasesForEntry: build.query({
@@ -251,6 +251,20 @@ const releaseApi = createApi({
251
251
  { type: "ReleaseAction", id: "LIST" }
252
252
  ]
253
253
  }),
254
+ createManyReleaseActions: build.mutation({
255
+ query({ body, params }) {
256
+ return {
257
+ url: `/content-releases/${params.releaseId}/actions/bulk`,
258
+ method: "POST",
259
+ data: body
260
+ };
261
+ },
262
+ invalidatesTags: [
263
+ { type: "Release", id: "LIST" },
264
+ { type: "ReleaseAction", id: "LIST" },
265
+ { type: "EntriesInRelease" }
266
+ ]
267
+ }),
254
268
  updateReleaseAction: build.mutation({
255
269
  query({ body, params }) {
256
270
  return {
@@ -291,7 +305,8 @@ const releaseApi = createApi({
291
305
  invalidatesTags: (result, error, arg) => [
292
306
  { type: "Release", id: "LIST" },
293
307
  { type: "Release", id: arg.params.releaseId },
294
- { type: "ReleaseAction", id: "LIST" }
308
+ { type: "ReleaseAction", id: "LIST" },
309
+ { type: "EntriesInRelease" }
295
310
  ]
296
311
  }),
297
312
  publishRelease: build.mutation({
@@ -310,7 +325,22 @@ const releaseApi = createApi({
310
325
  method: "DELETE"
311
326
  };
312
327
  },
313
- invalidatesTags: () => [{ type: "Release", id: "LIST" }]
328
+ invalidatesTags: () => [{ type: "Release", id: "LIST" }, { type: "EntriesInRelease" }]
329
+ }),
330
+ getMappedEntriesInReleases: build.query({
331
+ query(params) {
332
+ return {
333
+ url: "/content-releases/mapEntriesToReleases",
334
+ method: "GET",
335
+ config: {
336
+ params
337
+ }
338
+ };
339
+ },
340
+ transformResponse(response) {
341
+ return response.data;
342
+ },
343
+ providesTags: [{ type: "EntriesInRelease" }]
314
344
  })
315
345
  };
316
346
  }
@@ -322,11 +352,13 @@ const {
322
352
  useGetReleaseActionsQuery,
323
353
  useCreateReleaseMutation,
324
354
  useCreateReleaseActionMutation,
355
+ useCreateManyReleaseActionsMutation,
325
356
  useUpdateReleaseMutation,
326
357
  useUpdateReleaseActionMutation,
327
358
  usePublishReleaseMutation,
328
359
  useDeleteReleaseActionMutation,
329
- useDeleteReleaseMutation
360
+ useDeleteReleaseMutation,
361
+ useGetMappedEntriesInReleasesQuery
330
362
  } = releaseApi;
331
363
  const getTimezoneOffset = (timezone, date) => {
332
364
  try {
@@ -344,16 +376,12 @@ const getTimezoneOffset = (timezone, date) => {
344
376
  return "";
345
377
  }
346
378
  };
347
- const useTypedDispatch = useDispatch;
348
- const useTypedSelector = useSelector;
349
379
  const StyledMenuItem = styled(Menu.Item)`
350
380
  &:hover {
351
381
  background: ${({ theme, variant = "neutral" }) => theme.colors[`${variant}100`]};
352
382
 
353
383
  svg {
354
- path {
355
- fill: ${({ theme, variant = "neutral" }) => theme.colors[`${variant}600`]};
356
- }
384
+ fill: ${({ theme, variant = "neutral" }) => theme.colors[`${variant}600`]};
357
385
  }
358
386
 
359
387
  a {
@@ -362,9 +390,7 @@ const StyledMenuItem = styled(Menu.Item)`
362
390
  }
363
391
 
364
392
  svg {
365
- path {
366
- fill: ${({ theme, variant = "neutral" }) => theme.colors[`${variant}600`]};
367
- }
393
+ fill: ${({ theme, variant = "neutral" }) => theme.colors[`${variant}600`]};
368
394
  }
369
395
 
370
396
  a {
@@ -382,9 +408,12 @@ const StyledIconButton = styled(IconButton)`
382
408
  `;
383
409
  const DeleteReleaseActionItem = ({ releaseId, actionId }) => {
384
410
  const { formatMessage } = useIntl();
385
- const toggleNotification = useNotification();
411
+ const { toggleNotification } = useNotification();
386
412
  const { formatAPIError } = useAPIErrorHandler();
387
413
  const [deleteReleaseAction] = useDeleteReleaseActionMutation();
414
+ const {
415
+ allowedActions: { canDeleteAction }
416
+ } = useRBAC(PERMISSIONS);
388
417
  const handleDeleteAction = async () => {
389
418
  const response = await deleteReleaseAction({
390
419
  params: { releaseId, actionId }
@@ -402,24 +431,27 @@ const DeleteReleaseActionItem = ({ releaseId, actionId }) => {
402
431
  if ("error" in response) {
403
432
  if (isAxiosError$1(response.error)) {
404
433
  toggleNotification({
405
- type: "warning",
434
+ type: "danger",
406
435
  message: formatAPIError(response.error)
407
436
  });
408
437
  } else {
409
438
  toggleNotification({
410
- type: "warning",
439
+ type: "danger",
411
440
  message: formatMessage({ id: "notification.error", defaultMessage: "An error occurred" })
412
441
  });
413
442
  }
414
443
  }
415
444
  };
416
- return /* @__PURE__ */ jsx(CheckPermissions, { permissions: PERMISSIONS.deleteAction, children: /* @__PURE__ */ jsx(StyledMenuItem, { variant: "danger", onSelect: handleDeleteAction, children: /* @__PURE__ */ jsxs(Flex, { gap: 2, children: [
417
- /* @__PURE__ */ jsx(Icon, { as: Cross, width: 3, height: 3 }),
445
+ if (!canDeleteAction) {
446
+ return null;
447
+ }
448
+ return /* @__PURE__ */ jsx(StyledMenuItem, { variant: "danger", onSelect: handleDeleteAction, children: /* @__PURE__ */ jsxs(Flex, { gap: 2, children: [
449
+ /* @__PURE__ */ jsx(Cross, { width: "1.6rem", height: "1.6rem" }),
418
450
  /* @__PURE__ */ jsx(Typography, { textColor: "danger600", variant: "omega", children: formatMessage({
419
451
  id: "content-releases.content-manager-edit-view.remove-from-release",
420
452
  defaultMessage: "Remove from release"
421
453
  }) })
422
- ] }) }) });
454
+ ] }) });
423
455
  };
424
456
  const ReleaseActionEntryLinkItem = ({
425
457
  contentTypeUid,
@@ -427,62 +459,64 @@ const ReleaseActionEntryLinkItem = ({
427
459
  locale
428
460
  }) => {
429
461
  const { formatMessage } = useIntl();
430
- const collectionTypePermissions = useTypedSelector(
431
- (state) => state.rbacProvider.collectionTypesRelatedPermissions
432
- );
433
- const updatePermissions = contentTypeUid ? collectionTypePermissions[contentTypeUid]?.["plugin::content-manager.explorer.update"] : [];
434
- const canUpdateEntryForLocale = Boolean(
435
- !locale || updatePermissions?.find(
436
- (permission) => permission.properties?.locales?.includes(locale)
437
- )
438
- );
462
+ const userPermissions = useAuth("ReleaseActionEntryLinkItem", (state) => state.permissions);
463
+ const canUpdateEntryForLocale = React.useMemo(() => {
464
+ const updatePermissions = userPermissions.find(
465
+ (permission) => permission.subject === contentTypeUid && permission.action === "plugin::content-manager.explorer.update"
466
+ );
467
+ if (!updatePermissions) {
468
+ return false;
469
+ }
470
+ return Boolean(!locale || updatePermissions.properties?.locales?.includes(locale));
471
+ }, [contentTypeUid, locale, userPermissions]);
472
+ const {
473
+ allowedActions: { canUpdate: canUpdateContentType }
474
+ } = useRBAC({
475
+ updateContentType: [
476
+ {
477
+ action: "plugin::content-manager.explorer.update",
478
+ subject: contentTypeUid
479
+ }
480
+ ]
481
+ });
482
+ if (!canUpdateContentType || !canUpdateEntryForLocale) {
483
+ return null;
484
+ }
439
485
  return /* @__PURE__ */ jsx(
440
- CheckPermissions,
486
+ StyledMenuItem,
441
487
  {
442
- permissions: [
443
- {
444
- action: "plugin::content-manager.explorer.update",
445
- subject: contentTypeUid
446
- }
447
- ],
448
- children: canUpdateEntryForLocale && /* @__PURE__ */ jsx(StyledMenuItem, { children: /* @__PURE__ */ jsx(
449
- Link,
450
- {
451
- as: NavLink,
452
- to: {
453
- pathname: `/content-manager/collection-types/${contentTypeUid}/${entryId}`,
454
- search: locale && `?plugins[i18n][locale]=${locale}`
455
- },
456
- startIcon: /* @__PURE__ */ jsx(Icon, { as: Pencil, width: 3, height: 3 }),
457
- children: /* @__PURE__ */ jsx(Typography, { variant: "omega", children: formatMessage({
458
- id: "content-releases.content-manager-edit-view.edit-entry",
459
- defaultMessage: "Edit entry"
460
- }) })
461
- }
462
- ) })
488
+ forwardedAs: Link,
489
+ isLink: true,
490
+ to: {
491
+ pathname: `/content-manager/collection-types/${contentTypeUid}/${entryId}`,
492
+ search: locale && `?plugins[i18n][locale]=${locale}`
493
+ },
494
+ children: /* @__PURE__ */ jsxs(Flex, { gap: 2, children: [
495
+ /* @__PURE__ */ jsx(Pencil, { width: "1.6rem", height: "1.6rem" }),
496
+ /* @__PURE__ */ jsx(Typography, { variant: "omega", children: formatMessage({
497
+ id: "content-releases.content-manager-edit-view.edit-entry",
498
+ defaultMessage: "Edit entry"
499
+ }) })
500
+ ] })
463
501
  }
464
502
  );
465
503
  };
466
504
  const EditReleaseItem = ({ releaseId }) => {
467
505
  const { formatMessage } = useIntl();
468
- return /* @__PURE__ */ jsx(StyledMenuItem, { children: /* @__PURE__ */ jsx(
469
- Link,
470
- {
471
- href: `/admin/plugins/content-releases/${releaseId}`,
472
- startIcon: /* @__PURE__ */ jsx(Icon, { as: Pencil, width: 3, height: 3 }),
473
- isExternal: false,
474
- children: /* @__PURE__ */ jsx(Typography, { variant: "omega", children: formatMessage({
475
- id: "content-releases.content-manager-edit-view.edit-release",
476
- defaultMessage: "Edit release"
477
- }) })
478
- }
479
- ) });
506
+ return /* @__PURE__ */ jsx(StyledMenuItem, { forwardedAs: Link, isLink: true, to: `/plugins/content-releases/${releaseId}`, children: /* @__PURE__ */ jsxs(Flex, { gap: 2, children: [
507
+ /* @__PURE__ */ jsx(Pencil, { width: "1.6rem", height: "1.6rem" }),
508
+ /* @__PURE__ */ jsx(Typography, { variant: "omega", children: formatMessage({
509
+ id: "content-releases.content-manager-edit-view.edit-release",
510
+ defaultMessage: "Edit release"
511
+ }) })
512
+ ] }) });
480
513
  };
481
514
  const Root = ({ children, hasTriggerBorder = false }) => {
482
515
  const { formatMessage } = useIntl();
516
+ const { allowedActions } = useRBAC(PERMISSIONS);
483
517
  return (
484
518
  // A user can access the dropdown if they have permissions to delete a release-action OR update a release
485
- /* @__PURE__ */ jsx(CheckPermissions, { permissions: [...PERMISSIONS.deleteAction, ...PERMISSIONS.update], children: /* @__PURE__ */ jsxs(Menu.Root, { children: [
519
+ allowedActions.canDeleteAction || allowedActions.canUpdate ? /* @__PURE__ */ jsxs(Menu.Root, { children: [
486
520
  /* @__PURE__ */ jsx(
487
521
  Menu.Trigger,
488
522
  {
@@ -497,7 +531,7 @@ const Root = ({ children, hasTriggerBorder = false }) => {
497
531
  }
498
532
  ),
499
533
  /* @__PURE__ */ jsx(Menu.Content, { top: 1, popoverPlacement: "bottom-end", children })
500
- ] }) })
534
+ ] }) : null
501
535
  );
502
536
  };
503
537
  const ReleaseActionMenu = {
@@ -629,19 +663,20 @@ const INITIAL_VALUES = {
629
663
  const NoReleases = () => {
630
664
  const { formatMessage } = useIntl();
631
665
  return /* @__PURE__ */ jsx(
632
- NoContent,
666
+ EmptyStateLayout,
633
667
  {
634
- content: {
668
+ icon: /* @__PURE__ */ jsx(EmptyDocuments, { width: "16rem" }),
669
+ content: formatMessage({
635
670
  id: "content-releases.content-manager-edit-view.add-to-release.no-releases-message",
636
671
  defaultMessage: "No available releases. Open the list of releases and create a new one from there."
637
- },
672
+ }),
638
673
  action: /* @__PURE__ */ jsx(
639
674
  LinkButton,
640
675
  {
641
676
  to: {
642
677
  pathname: "/plugins/content-releases"
643
678
  },
644
- as: Link$1,
679
+ as: Link,
645
680
  variant: "secondary",
646
681
  children: formatMessage({
647
682
  id: "content-releases.content-manager-edit-view.add-to-release.redirect-button",
@@ -659,9 +694,10 @@ const AddActionToReleaseModal = ({
659
694
  }) => {
660
695
  const releaseHeaderId = React.useId();
661
696
  const { formatMessage } = useIntl();
662
- const toggleNotification = useNotification();
697
+ const { toggleNotification } = useNotification();
663
698
  const { formatAPIError } = useAPIErrorHandler();
664
- const { modifiedData } = useCMEditViewDataManager();
699
+ const [{ query }] = useQueryParams();
700
+ const locale = query.plugins?.i18n?.locale;
665
701
  const response = useGetReleasesForEntryQuery({
666
702
  contentTypeUid,
667
703
  entryId,
@@ -670,7 +706,6 @@ const AddActionToReleaseModal = ({
670
706
  const releases = response.data?.data;
671
707
  const [createReleaseAction, { isLoading }] = useCreateReleaseActionMutation();
672
708
  const handleSubmit = async (values) => {
673
- const locale = modifiedData.locale;
674
709
  const releaseActionEntry = {
675
710
  contentType: contentTypeUid,
676
711
  id: entryId,
@@ -694,12 +729,12 @@ const AddActionToReleaseModal = ({
694
729
  if ("error" in response2) {
695
730
  if (isAxiosError$1(response2.error)) {
696
731
  toggleNotification({
697
- type: "warning",
732
+ type: "danger",
698
733
  message: formatAPIError(response2.error)
699
734
  });
700
735
  } else {
701
736
  toggleNotification({
702
- type: "warning",
737
+ type: "danger",
703
738
  message: formatMessage({ id: "notification.error", defaultMessage: "An error occurred" })
704
739
  });
705
740
  }
@@ -777,14 +812,18 @@ const AddActionToReleaseModal = ({
777
812
  const CMReleasesContainer = () => {
778
813
  const [isModalOpen, setIsModalOpen] = React.useState(false);
779
814
  const { formatMessage, formatDate, formatTime } = useIntl();
780
- const {
781
- isCreatingEntry,
782
- hasDraftAndPublish,
783
- initialData: { id: entryId },
784
- slug
785
- } = useCMEditViewDataManager();
815
+ const { id, slug, collectionType } = useParams();
816
+ const isCreatingEntry = id === "create";
817
+ const entryId = parseInt(id, 10);
818
+ const { allowedActions } = useRBAC(PERMISSIONS);
819
+ const { canCreateAction, canRead: canMain, canDeleteAction } = allowedActions;
820
+ const { schema } = unstable_useDocument({
821
+ collectionType,
822
+ model: slug
823
+ });
824
+ const hasDraftAndPublish = schema?.options?.draftAndPublish;
786
825
  const contentTypeUid = slug;
787
- const canFetch = entryId != null && contentTypeUid != null;
826
+ const canFetch = id != null && contentTypeUid != null;
788
827
  const fetchParams = canFetch ? {
789
828
  contentTypeUid,
790
829
  entryId,
@@ -805,7 +844,10 @@ const CMReleasesContainer = () => {
805
844
  }
806
845
  return `success${shade}`;
807
846
  };
808
- return /* @__PURE__ */ jsx(CheckPermissions, { permissions: PERMISSIONS.main, children: /* @__PURE__ */ jsxs(
847
+ if (!canMain) {
848
+ return null;
849
+ }
850
+ return /* @__PURE__ */ jsxs(
809
851
  Box,
810
852
  {
811
853
  as: "aside",
@@ -832,7 +874,7 @@ const CMReleasesContainer = () => {
832
874
  alignItems: "start",
833
875
  borderWidth: "1px",
834
876
  borderStyle: "solid",
835
- borderColor: getReleaseColorVariant(release.action.type, "200"),
877
+ borderColor: getReleaseColorVariant(release.actions[0].type, "200"),
836
878
  overflow: "hidden",
837
879
  hasRadius: true,
838
880
  children: [
@@ -843,26 +885,26 @@ const CMReleasesContainer = () => {
843
885
  paddingBottom: 3,
844
886
  paddingLeft: 4,
845
887
  paddingRight: 4,
846
- background: getReleaseColorVariant(release.action.type, "100"),
888
+ background: getReleaseColorVariant(release.actions[0].type, "100"),
847
889
  width: "100%",
848
890
  children: /* @__PURE__ */ jsx(
849
891
  Typography,
850
892
  {
851
893
  fontSize: 1,
852
894
  variant: "pi",
853
- textColor: getReleaseColorVariant(release.action.type, "600"),
895
+ textColor: getReleaseColorVariant(release.actions[0].type, "600"),
854
896
  children: formatMessage(
855
897
  {
856
898
  id: "content-releases.content-manager-edit-view.list-releases.title",
857
899
  defaultMessage: "{isPublish, select, true {Will be published in} other {Will be unpublished in}}"
858
900
  },
859
- { isPublish: release.action.type === "publish" }
901
+ { isPublish: release.actions[0].type === "publish" }
860
902
  )
861
903
  }
862
904
  )
863
905
  }
864
906
  ),
865
- /* @__PURE__ */ jsxs(Flex, { padding: 4, direction: "column", gap: 2, width: "100%", alignItems: "flex-start", children: [
907
+ /* @__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
908
  /* @__PURE__ */ jsx(Typography, { fontSize: 2, fontWeight: "bold", variant: "omega", textColor: "neutral700", children: release.name }),
867
909
  release.scheduledAt && release.timezone && /* @__PURE__ */ jsx(Typography, { variant: "pi", textColor: "neutral600", children: formatMessage(
868
910
  {
@@ -886,23 +928,23 @@ const CMReleasesContainer = () => {
886
928
  )
887
929
  }
888
930
  ) }),
889
- /* @__PURE__ */ jsx(CheckPermissions, { permissions: PERMISSIONS.deleteAction, children: /* @__PURE__ */ jsxs(ReleaseActionMenu.Root, { hasTriggerBorder: true, children: [
931
+ canDeleteAction ? /* @__PURE__ */ jsxs(ReleaseActionMenu.Root, { hasTriggerBorder: true, children: [
890
932
  /* @__PURE__ */ jsx(ReleaseActionMenu.EditReleaseItem, { releaseId: release.id }),
891
933
  /* @__PURE__ */ jsx(
892
934
  ReleaseActionMenu.DeleteReleaseActionItem,
893
935
  {
894
936
  releaseId: release.id,
895
- actionId: release.action.id
937
+ actionId: release.actions[0].id
896
938
  }
897
939
  )
898
- ] }) })
899
- ] })
940
+ ] }) : null
941
+ ] }) })
900
942
  ]
901
943
  },
902
944
  release.id
903
945
  );
904
946
  }),
905
- /* @__PURE__ */ jsx(CheckPermissions, { permissions: PERMISSIONS.createAction, children: /* @__PURE__ */ jsx(
947
+ canCreateAction ? /* @__PURE__ */ jsx(
906
948
  Button,
907
949
  {
908
950
  justifyContent: "center",
@@ -917,7 +959,7 @@ const CMReleasesContainer = () => {
917
959
  defaultMessage: "Add to release"
918
960
  })
919
961
  }
920
- ) })
962
+ ) : null
921
963
  ] }),
922
964
  isModalOpen && /* @__PURE__ */ jsx(
923
965
  AddActionToReleaseModal,
@@ -929,33 +971,218 @@ const CMReleasesContainer = () => {
929
971
  )
930
972
  ]
931
973
  }
932
- ) });
974
+ );
975
+ };
976
+ const getContentPermissions = (subject) => {
977
+ const permissions = {
978
+ publish: [
979
+ {
980
+ action: "plugin::content-manager.explorer.publish",
981
+ subject,
982
+ id: "",
983
+ actionParameters: {},
984
+ properties: {},
985
+ conditions: []
986
+ }
987
+ ]
988
+ };
989
+ return permissions;
990
+ };
991
+ const ReleaseAction = ({ documentIds, model }) => {
992
+ const { formatMessage } = useIntl();
993
+ const { toggleNotification } = useNotification();
994
+ const { formatAPIError } = useAPIErrorHandler();
995
+ const [{ query }] = useQueryParams();
996
+ const contentPermissions = getContentPermissions(model);
997
+ const {
998
+ allowedActions: { canPublish }
999
+ } = useRBAC(contentPermissions);
1000
+ const {
1001
+ allowedActions: { canCreate }
1002
+ } = useRBAC(PERMISSIONS);
1003
+ const response = useGetReleasesQuery();
1004
+ const releases = response.data?.data;
1005
+ const [createManyReleaseActions, { isLoading }] = useCreateManyReleaseActionsMutation();
1006
+ const handleSubmit = async (values) => {
1007
+ const locale = query.plugins?.i18n?.locale;
1008
+ const releaseActionEntries = documentIds.map(
1009
+ (id) => ({
1010
+ type: values.type,
1011
+ entry: {
1012
+ contentType: model,
1013
+ id,
1014
+ locale
1015
+ }
1016
+ })
1017
+ );
1018
+ const response2 = await createManyReleaseActions({
1019
+ body: releaseActionEntries,
1020
+ params: { releaseId: values.releaseId }
1021
+ });
1022
+ if ("data" in response2) {
1023
+ const notificationMessage = formatMessage(
1024
+ {
1025
+ id: "content-releases.content-manager-list-view.add-to-release.notification.success.message",
1026
+ defaultMessage: "{entriesAlreadyInRelease} out of {totalEntries} entries were already in the release."
1027
+ },
1028
+ {
1029
+ entriesAlreadyInRelease: response2.data.meta.entriesAlreadyInRelease,
1030
+ totalEntries: response2.data.meta.totalEntries
1031
+ }
1032
+ );
1033
+ const notification = {
1034
+ type: "success",
1035
+ title: formatMessage(
1036
+ {
1037
+ id: "content-releases.content-manager-list-view.add-to-release.notification.success.title",
1038
+ defaultMessage: "Successfully added to release."
1039
+ },
1040
+ {
1041
+ entriesAlreadyInRelease: response2.data.meta.entriesAlreadyInRelease,
1042
+ totalEntries: response2.data.meta.totalEntries
1043
+ }
1044
+ ),
1045
+ message: response2.data.meta.entriesAlreadyInRelease ? notificationMessage : ""
1046
+ };
1047
+ toggleNotification(notification);
1048
+ return true;
1049
+ }
1050
+ if ("error" in response2) {
1051
+ if (isAxiosError$1(response2.error)) {
1052
+ toggleNotification({
1053
+ type: "warning",
1054
+ message: formatAPIError(response2.error)
1055
+ });
1056
+ } else {
1057
+ toggleNotification({
1058
+ type: "warning",
1059
+ message: formatMessage({ id: "notification.error", defaultMessage: "An error occurred" })
1060
+ });
1061
+ }
1062
+ }
1063
+ };
1064
+ if (!canCreate || !canPublish)
1065
+ return null;
1066
+ return {
1067
+ actionType: "release",
1068
+ variant: "tertiary",
1069
+ label: formatMessage({
1070
+ id: "content-manager-list-view.add-to-release",
1071
+ defaultMessage: "Add to Release"
1072
+ }),
1073
+ dialog: {
1074
+ type: "modal",
1075
+ title: formatMessage({
1076
+ id: "content-manager-list-view.add-to-release",
1077
+ defaultMessage: "Add to Release"
1078
+ }),
1079
+ content: ({ onClose }) => {
1080
+ return /* @__PURE__ */ jsx(
1081
+ Formik,
1082
+ {
1083
+ onSubmit: async (values) => {
1084
+ const data = await handleSubmit(values);
1085
+ if (data) {
1086
+ return onClose();
1087
+ }
1088
+ },
1089
+ validationSchema: RELEASE_ACTION_FORM_SCHEMA,
1090
+ initialValues: INITIAL_VALUES,
1091
+ children: ({ values, setFieldValue }) => /* @__PURE__ */ jsxs(Form, { children: [
1092
+ releases?.length === 0 ? /* @__PURE__ */ jsx(NoReleases, {}) : /* @__PURE__ */ jsx(ModalBody, { children: /* @__PURE__ */ jsxs(Flex, { direction: "column", alignItems: "stretch", gap: 2, children: [
1093
+ /* @__PURE__ */ jsx(Box, { paddingBottom: 6, children: /* @__PURE__ */ jsx(
1094
+ SingleSelect,
1095
+ {
1096
+ required: true,
1097
+ label: formatMessage({
1098
+ id: "content-releases.content-manager-list-view.add-to-release.select-label",
1099
+ defaultMessage: "Select a release"
1100
+ }),
1101
+ placeholder: formatMessage({
1102
+ id: "content-releases.content-manager-list-view.add-to-release.select-placeholder",
1103
+ defaultMessage: "Select"
1104
+ }),
1105
+ onChange: (value) => setFieldValue("releaseId", value),
1106
+ value: values.releaseId,
1107
+ children: releases?.map((release) => /* @__PURE__ */ jsx(SingleSelectOption, { value: release.id, children: release.name }, release.id))
1108
+ }
1109
+ ) }),
1110
+ /* @__PURE__ */ jsx(FieldLabel, { children: formatMessage({
1111
+ id: "content-releases.content-manager-list-view.add-to-release.action-type-label",
1112
+ defaultMessage: "What do you want to do with these entries?"
1113
+ }) }),
1114
+ /* @__PURE__ */ jsx(
1115
+ ReleaseActionOptions,
1116
+ {
1117
+ selected: values.type,
1118
+ handleChange: (e) => setFieldValue("type", e.target.value),
1119
+ name: "type"
1120
+ }
1121
+ )
1122
+ ] }) }),
1123
+ /* @__PURE__ */ jsx(
1124
+ ModalFooter,
1125
+ {
1126
+ startActions: /* @__PURE__ */ jsx(Button, { onClick: onClose, variant: "tertiary", name: "cancel", children: formatMessage({
1127
+ id: "content-releases.content-manager-list-view.add-to-release.cancel-button",
1128
+ defaultMessage: "Cancel"
1129
+ }) }),
1130
+ endActions: (
1131
+ /**
1132
+ * TODO: Ideally we would use isValid from Formik to disable the button, however currently it always returns true
1133
+ * for yup.string().required(), even when the value is falsy (including empty string)
1134
+ */
1135
+ /* @__PURE__ */ jsx(Button, { type: "submit", disabled: !values.releaseId, loading: isLoading, children: formatMessage({
1136
+ id: "content-releases.content-manager-list-view.add-to-release.continue-button",
1137
+ defaultMessage: "Continue"
1138
+ }) })
1139
+ )
1140
+ }
1141
+ )
1142
+ ] })
1143
+ }
1144
+ );
1145
+ }
1146
+ }
1147
+ };
1148
+ };
1149
+ const prefixPluginTranslations = (trad, pluginId2) => {
1150
+ if (!pluginId2) {
1151
+ throw new TypeError("pluginId can't be empty");
1152
+ }
1153
+ return Object.keys(trad).reduce((acc, current) => {
1154
+ acc[`${pluginId2}.${current}`] = trad[current];
1155
+ return acc;
1156
+ }, {});
933
1157
  };
934
1158
  const admin = {
935
1159
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
936
1160
  register(app) {
1161
+ app.createHook("ContentReleases/pages/ReleaseDetails/add-locale-in-releases");
937
1162
  if (window.strapi.features.isEnabled("cms-content-releases")) {
938
1163
  app.addMenuLink({
939
- to: `/plugins/${pluginId}`,
1164
+ to: `plugins/${pluginId}`,
940
1165
  icon: PaperPlane,
941
1166
  intlLabel: {
942
1167
  id: `${pluginId}.plugin.name`,
943
1168
  defaultMessage: "Releases"
944
1169
  },
945
- async Component() {
946
- const { App } = await import("./App-HVXzE3i3.mjs");
947
- return App;
948
- },
1170
+ Component: () => import("./App-BsUSTHVD.mjs").then((mod) => ({ default: mod.App })),
949
1171
  permissions: PERMISSIONS.main
950
1172
  });
951
1173
  app.addMiddlewares([() => releaseApi.middleware]);
952
1174
  app.addReducers({
953
1175
  [releaseApi.reducerPath]: releaseApi.reducer
954
1176
  });
955
- app.injectContentManagerComponent("editView", "right-links", {
1177
+ app.getPlugin("content-manager").injectComponent("editView", "right-links", {
956
1178
  name: `${pluginId}-link`,
957
1179
  Component: CMReleasesContainer
958
1180
  });
1181
+ app.plugins["content-manager"].apis.addBulkAction((actions) => {
1182
+ const deleteActionIndex = actions.findIndex((action) => action.name === "DeleteAction");
1183
+ actions.splice(deleteActionIndex, 0, ReleaseAction);
1184
+ return actions;
1185
+ });
959
1186
  } else if (!window.strapi.features.isEnabled("cms-content-releases") && window.strapi?.flags?.promoteEE) {
960
1187
  app.addMenuLink({
961
1188
  to: `/plugins/purchase-content-releases`,
@@ -964,9 +1191,10 @@ const admin = {
964
1191
  id: `${pluginId}.plugin.name`,
965
1192
  defaultMessage: "Releases"
966
1193
  },
1194
+ permissions: [],
967
1195
  async Component() {
968
- const { PurchaseContentReleases } = await import("./PurchaseContentReleases-Clm0iACO.mjs");
969
- return PurchaseContentReleases;
1196
+ const { PurchaseContentReleases } = await import("./PurchaseContentReleases-_MxP6-Dt.mjs");
1197
+ return { default: PurchaseContentReleases };
970
1198
  },
971
1199
  lockIcon: true
972
1200
  });
@@ -975,7 +1203,7 @@ const admin = {
975
1203
  async registerTrads({ locales }) {
976
1204
  const importedTrads = await Promise.all(
977
1205
  locales.map((locale) => {
978
- return __variableDynamicImportRuntimeHelper(/* @__PURE__ */ Object.assign({ "./translations/en.json": () => import("./en-RdapH-9X.mjs") }), `./translations/${locale}.json`).then(({ default: data }) => {
1206
+ return __variableDynamicImportRuntimeHelper(/* @__PURE__ */ Object.assign({ "./translations/en.json": () => import("./en-B9Ur3VsE.mjs") }), `./translations/${locale}.json`).then(({ default: data }) => {
979
1207
  return {
980
1208
  data: prefixPluginTranslations(data, "content-releases"),
981
1209
  locale
@@ -999,15 +1227,14 @@ export {
999
1227
  useUpdateReleaseMutation as c,
1000
1228
  useDeleteReleaseMutation as d,
1001
1229
  usePublishReleaseMutation as e,
1002
- useTypedDispatch as f,
1230
+ useGetReleaseActionsQuery as f,
1003
1231
  getTimezoneOffset as g,
1004
- useGetReleaseActionsQuery as h,
1232
+ useUpdateReleaseActionMutation as h,
1005
1233
  isAxiosError as i,
1006
- useUpdateReleaseActionMutation as j,
1007
- ReleaseActionMenu as k,
1008
- admin as l,
1234
+ ReleaseActionMenu as j,
1235
+ admin as k,
1009
1236
  pluginId as p,
1010
1237
  releaseApi as r,
1011
1238
  useGetReleasesQuery as u
1012
1239
  };
1013
- //# sourceMappingURL=index-Ys87ROOe.mjs.map
1240
+ //# sourceMappingURL=index-DJLIZdZv.mjs.map