@strapi/content-releases 0.0.0-experimental.d8a676a242377cee820b59b21a05d47290d9ac73 → 0.0.0-experimental.defd8568ae03ef8d52f86e1f3541979f953c3941

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-p8aKBitd.js → App-C0DlH0im.js} +343 -323
  2. package/dist/_chunks/App-C0DlH0im.js.map +1 -0
  3. package/dist/_chunks/{App-bpzO2Ljh.mjs → App-O0ZO-S35.mjs} +328 -308
  4. package/dist/_chunks/App-O0ZO-S35.mjs.map +1 -0
  5. package/dist/_chunks/{PurchaseContentReleases-YhAPgpG9.js → PurchaseContentReleases-DAHdUpAA.js} +5 -5
  6. package/dist/_chunks/PurchaseContentReleases-DAHdUpAA.js.map +1 -0
  7. package/dist/_chunks/{PurchaseContentReleases-Clm0iACO.mjs → PurchaseContentReleases-Ex09YpKR.mjs} +6 -6
  8. package/dist/_chunks/PurchaseContentReleases-Ex09YpKR.mjs.map +1 -0
  9. package/dist/_chunks/{en-WuuhP6Bn.mjs → en-B9Ur3VsE.mjs} +11 -3
  10. package/dist/_chunks/en-B9Ur3VsE.mjs.map +1 -0
  11. package/dist/_chunks/{en-gcJJ5htG.js → en-DtFJ5ViE.js} +11 -3
  12. package/dist/_chunks/en-DtFJ5ViE.js.map +1 -0
  13. package/dist/_chunks/{index-AECgcaDa.mjs → index-DjDPK8kb.mjs} +337 -109
  14. package/dist/_chunks/index-DjDPK8kb.mjs.map +1 -0
  15. package/dist/_chunks/{index-fP3qoWZ4.js → index-DoZNNtsb.js} +340 -112
  16. package/dist/_chunks/index-DoZNNtsb.js.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 +358 -237
  43. package/dist/server/index.js.map +1 -1
  44. package/dist/server/index.mjs +359 -237
  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-bpzO2Ljh.mjs.map +0 -1
  104. package/dist/_chunks/App-p8aKBitd.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-WuuhP6Bn.mjs.map +0 -1
  108. package/dist/_chunks/en-gcJJ5htG.js.map +0 -1
  109. package/dist/_chunks/index-AECgcaDa.mjs.map +0 -1
  110. package/dist/_chunks/index-fP3qoWZ4.js.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 { Menu, IconButton, Flex, Typography, Link, Field, FieldLabel, VisuallyHidden, FieldInput, Box, Button, EmptyStateLayout, LinkButton, ModalLayout, ModalHeader, ModalBody, SingleSelect, SingleSelectOption, ModalFooter } from "@strapi/design-system";
7
+ import { EmptyDocuments } from "@strapi/icons/symbols";
8
+ import { unstable_useDocument } from "@strapi/plugin-content-manager/strapi-admin";
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 { NavLink, useParams, Link as Link$1 } 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 {
@@ -288,9 +302,11 @@ const releaseApi = createApi({
288
302
  method: "DELETE"
289
303
  };
290
304
  },
291
- invalidatesTags: [
305
+ invalidatesTags: (result, error, arg) => [
292
306
  { type: "Release", id: "LIST" },
293
- { type: "ReleaseAction", id: "LIST" }
307
+ { type: "Release", id: arg.params.releaseId },
308
+ { type: "ReleaseAction", id: "LIST" },
309
+ { type: "EntriesInRelease" }
294
310
  ]
295
311
  }),
296
312
  publishRelease: build.mutation({
@@ -309,7 +325,22 @@ const releaseApi = createApi({
309
325
  method: "DELETE"
310
326
  };
311
327
  },
312
- 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" }]
313
344
  })
314
345
  };
315
346
  }
@@ -321,11 +352,13 @@ const {
321
352
  useGetReleaseActionsQuery,
322
353
  useCreateReleaseMutation,
323
354
  useCreateReleaseActionMutation,
355
+ useCreateManyReleaseActionsMutation,
324
356
  useUpdateReleaseMutation,
325
357
  useUpdateReleaseActionMutation,
326
358
  usePublishReleaseMutation,
327
359
  useDeleteReleaseActionMutation,
328
- useDeleteReleaseMutation
360
+ useDeleteReleaseMutation,
361
+ useGetMappedEntriesInReleasesQuery
329
362
  } = releaseApi;
330
363
  const getTimezoneOffset = (timezone, date) => {
331
364
  try {
@@ -343,16 +376,12 @@ const getTimezoneOffset = (timezone, date) => {
343
376
  return "";
344
377
  }
345
378
  };
346
- const useTypedDispatch = useDispatch;
347
- const useTypedSelector = useSelector;
348
379
  const StyledMenuItem = styled(Menu.Item)`
349
380
  &:hover {
350
381
  background: ${({ theme, variant = "neutral" }) => theme.colors[`${variant}100`]};
351
382
 
352
383
  svg {
353
- path {
354
- fill: ${({ theme, variant = "neutral" }) => theme.colors[`${variant}600`]};
355
- }
384
+ fill: ${({ theme, variant = "neutral" }) => theme.colors[`${variant}600`]};
356
385
  }
357
386
 
358
387
  a {
@@ -361,9 +390,7 @@ const StyledMenuItem = styled(Menu.Item)`
361
390
  }
362
391
 
363
392
  svg {
364
- path {
365
- fill: ${({ theme, variant = "neutral" }) => theme.colors[`${variant}600`]};
366
- }
393
+ fill: ${({ theme, variant = "neutral" }) => theme.colors[`${variant}600`]};
367
394
  }
368
395
 
369
396
  a {
@@ -381,9 +408,12 @@ const StyledIconButton = styled(IconButton)`
381
408
  `;
382
409
  const DeleteReleaseActionItem = ({ releaseId, actionId }) => {
383
410
  const { formatMessage } = useIntl();
384
- const toggleNotification = useNotification();
411
+ const { toggleNotification } = useNotification();
385
412
  const { formatAPIError } = useAPIErrorHandler();
386
413
  const [deleteReleaseAction] = useDeleteReleaseActionMutation();
414
+ const {
415
+ allowedActions: { canDeleteAction }
416
+ } = useRBAC(PERMISSIONS);
387
417
  const handleDeleteAction = async () => {
388
418
  const response = await deleteReleaseAction({
389
419
  params: { releaseId, actionId }
@@ -401,24 +431,27 @@ const DeleteReleaseActionItem = ({ releaseId, actionId }) => {
401
431
  if ("error" in response) {
402
432
  if (isAxiosError$1(response.error)) {
403
433
  toggleNotification({
404
- type: "warning",
434
+ type: "danger",
405
435
  message: formatAPIError(response.error)
406
436
  });
407
437
  } else {
408
438
  toggleNotification({
409
- type: "warning",
439
+ type: "danger",
410
440
  message: formatMessage({ id: "notification.error", defaultMessage: "An error occurred" })
411
441
  });
412
442
  }
413
443
  }
414
444
  };
415
- return /* @__PURE__ */ jsx(CheckPermissions, { permissions: PERMISSIONS.deleteAction, children: /* @__PURE__ */ jsx(StyledMenuItem, { variant: "danger", onSelect: handleDeleteAction, children: /* @__PURE__ */ jsxs(Flex, { gap: 2, children: [
416
- /* @__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.2rem", height: "1.2rem" }),
417
450
  /* @__PURE__ */ jsx(Typography, { textColor: "danger600", variant: "omega", children: formatMessage({
418
451
  id: "content-releases.content-manager-edit-view.remove-from-release",
419
452
  defaultMessage: "Remove from release"
420
453
  }) })
421
- ] }) }) });
454
+ ] }) });
422
455
  };
423
456
  const ReleaseActionEntryLinkItem = ({
424
457
  contentTypeUid,
@@ -426,50 +459,53 @@ const ReleaseActionEntryLinkItem = ({
426
459
  locale
427
460
  }) => {
428
461
  const { formatMessage } = useIntl();
429
- const collectionTypePermissions = useTypedSelector(
430
- (state) => state.rbacProvider.collectionTypesRelatedPermissions
431
- );
432
- const updatePermissions = contentTypeUid ? collectionTypePermissions[contentTypeUid]?.["plugin::content-manager.explorer.update"] : [];
433
- const canUpdateEntryForLocale = Boolean(
434
- !locale || updatePermissions?.find(
435
- (permission) => permission.properties?.locales?.includes(locale)
436
- )
437
- );
438
- return /* @__PURE__ */ jsx(
439
- CheckPermissions,
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
+ }
485
+ return /* @__PURE__ */ jsx(StyledMenuItem, { children: /* @__PURE__ */ jsx(
486
+ Link,
440
487
  {
441
- permissions: [
442
- {
443
- action: "plugin::content-manager.explorer.update",
444
- subject: contentTypeUid
445
- }
446
- ],
447
- children: canUpdateEntryForLocale && /* @__PURE__ */ jsx(StyledMenuItem, { children: /* @__PURE__ */ jsx(
448
- Link,
449
- {
450
- as: NavLink,
451
- to: {
452
- pathname: `/content-manager/collection-types/${contentTypeUid}/${entryId}`,
453
- search: locale && `?plugins[i18n][locale]=${locale}`
454
- },
455
- startIcon: /* @__PURE__ */ jsx(Icon, { as: Pencil, width: 3, height: 3 }),
456
- children: /* @__PURE__ */ jsx(Typography, { variant: "omega", children: formatMessage({
457
- id: "content-releases.content-manager-edit-view.edit-entry",
458
- defaultMessage: "Edit entry"
459
- }) })
460
- }
461
- ) })
488
+ as: NavLink,
489
+ to: {
490
+ pathname: `/content-manager/collection-types/${contentTypeUid}/${entryId}`,
491
+ search: locale && `?plugins[i18n][locale]=${locale}`
492
+ },
493
+ startIcon: /* @__PURE__ */ jsx(Pencil, { width: "1.2rem", height: "1.2rem" }),
494
+ children: /* @__PURE__ */ jsx(Typography, { variant: "omega", children: formatMessage({
495
+ id: "content-releases.content-manager-edit-view.edit-entry",
496
+ defaultMessage: "Edit entry"
497
+ }) })
462
498
  }
463
- );
499
+ ) });
464
500
  };
465
501
  const EditReleaseItem = ({ releaseId }) => {
466
502
  const { formatMessage } = useIntl();
467
503
  return /* @__PURE__ */ jsx(StyledMenuItem, { children: /* @__PURE__ */ jsx(
468
504
  Link,
469
505
  {
470
- as: NavLink,
471
- to: `/plugins/content-releases/${releaseId}`,
472
- startIcon: /* @__PURE__ */ jsx(Icon, { as: Pencil, width: 3, height: 3 }),
506
+ href: `/admin/plugins/content-releases/${releaseId}`,
507
+ startIcon: /* @__PURE__ */ jsx(Pencil, { width: "1.2rem", height: "1.2rem" }),
508
+ isExternal: false,
473
509
  children: /* @__PURE__ */ jsx(Typography, { variant: "omega", children: formatMessage({
474
510
  id: "content-releases.content-manager-edit-view.edit-release",
475
511
  defaultMessage: "Edit release"
@@ -479,9 +515,10 @@ const EditReleaseItem = ({ releaseId }) => {
479
515
  };
480
516
  const Root = ({ children, hasTriggerBorder = false }) => {
481
517
  const { formatMessage } = useIntl();
518
+ const { allowedActions } = useRBAC(PERMISSIONS);
482
519
  return (
483
520
  // A user can access the dropdown if they have permissions to delete a release-action OR update a release
484
- /* @__PURE__ */ jsx(CheckPermissions, { permissions: [...PERMISSIONS.deleteAction, ...PERMISSIONS.update], children: /* @__PURE__ */ jsxs(Menu.Root, { children: [
521
+ allowedActions.canDeleteAction || allowedActions.canUpdate ? /* @__PURE__ */ jsxs(Menu.Root, { children: [
485
522
  /* @__PURE__ */ jsx(
486
523
  Menu.Trigger,
487
524
  {
@@ -496,7 +533,7 @@ const Root = ({ children, hasTriggerBorder = false }) => {
496
533
  }
497
534
  ),
498
535
  /* @__PURE__ */ jsx(Menu.Content, { top: 1, popoverPlacement: "bottom-end", children })
499
- ] }) })
536
+ ] }) : null
500
537
  );
501
538
  };
502
539
  const ReleaseActionMenu = {
@@ -628,12 +665,13 @@ const INITIAL_VALUES = {
628
665
  const NoReleases = () => {
629
666
  const { formatMessage } = useIntl();
630
667
  return /* @__PURE__ */ jsx(
631
- NoContent,
668
+ EmptyStateLayout,
632
669
  {
633
- content: {
670
+ icon: /* @__PURE__ */ jsx(EmptyDocuments, { width: "16rem" }),
671
+ content: formatMessage({
634
672
  id: "content-releases.content-manager-edit-view.add-to-release.no-releases-message",
635
673
  defaultMessage: "No available releases. Open the list of releases and create a new one from there."
636
- },
674
+ }),
637
675
  action: /* @__PURE__ */ jsx(
638
676
  LinkButton,
639
677
  {
@@ -658,9 +696,10 @@ const AddActionToReleaseModal = ({
658
696
  }) => {
659
697
  const releaseHeaderId = React.useId();
660
698
  const { formatMessage } = useIntl();
661
- const toggleNotification = useNotification();
699
+ const { toggleNotification } = useNotification();
662
700
  const { formatAPIError } = useAPIErrorHandler();
663
- const { modifiedData } = useCMEditViewDataManager();
701
+ const [{ query }] = useQueryParams();
702
+ const locale = query.plugins?.i18n?.locale;
664
703
  const response = useGetReleasesForEntryQuery({
665
704
  contentTypeUid,
666
705
  entryId,
@@ -669,7 +708,6 @@ const AddActionToReleaseModal = ({
669
708
  const releases = response.data?.data;
670
709
  const [createReleaseAction, { isLoading }] = useCreateReleaseActionMutation();
671
710
  const handleSubmit = async (values) => {
672
- const locale = modifiedData.locale;
673
711
  const releaseActionEntry = {
674
712
  contentType: contentTypeUid,
675
713
  id: entryId,
@@ -693,12 +731,12 @@ const AddActionToReleaseModal = ({
693
731
  if ("error" in response2) {
694
732
  if (isAxiosError$1(response2.error)) {
695
733
  toggleNotification({
696
- type: "warning",
734
+ type: "danger",
697
735
  message: formatAPIError(response2.error)
698
736
  });
699
737
  } else {
700
738
  toggleNotification({
701
- type: "warning",
739
+ type: "danger",
702
740
  message: formatMessage({ id: "notification.error", defaultMessage: "An error occurred" })
703
741
  });
704
742
  }
@@ -776,18 +814,20 @@ const AddActionToReleaseModal = ({
776
814
  const CMReleasesContainer = () => {
777
815
  const [isModalOpen, setIsModalOpen] = React.useState(false);
778
816
  const { formatMessage, formatDate, formatTime } = useIntl();
779
- const {
780
- isCreatingEntry,
781
- hasDraftAndPublish,
782
- initialData: { id: entryId },
783
- slug
784
- } = useCMEditViewDataManager();
817
+ const { id, slug, collectionType } = useParams();
818
+ const isCreatingEntry = id === "create";
819
+ const { allowedActions } = useRBAC(PERMISSIONS);
820
+ const { canCreateAction, canRead: canMain, canDeleteAction } = allowedActions;
821
+ const { schema } = unstable_useDocument({
822
+ collectionType,
823
+ model: slug
824
+ });
825
+ const hasDraftAndPublish = schema?.options?.draftAndPublish;
785
826
  const contentTypeUid = slug;
786
- const IsSchedulingEnabled = window.strapi.future.isEnabled("contentReleasesScheduling");
787
- const canFetch = entryId != null && contentTypeUid != null;
827
+ const canFetch = id != null && contentTypeUid != null;
788
828
  const fetchParams = canFetch ? {
789
829
  contentTypeUid,
790
- entryId,
830
+ entryId: id,
791
831
  hasEntryAttached: true
792
832
  } : skipToken;
793
833
  const response = useGetReleasesForEntryQuery(fetchParams);
@@ -805,7 +845,10 @@ const CMReleasesContainer = () => {
805
845
  }
806
846
  return `success${shade}`;
807
847
  };
808
- return /* @__PURE__ */ jsx(CheckPermissions, { permissions: PERMISSIONS.main, children: /* @__PURE__ */ jsxs(
848
+ if (!canMain) {
849
+ return null;
850
+ }
851
+ return /* @__PURE__ */ jsxs(
809
852
  Box,
810
853
  {
811
854
  as: "aside",
@@ -832,7 +875,7 @@ const CMReleasesContainer = () => {
832
875
  alignItems: "start",
833
876
  borderWidth: "1px",
834
877
  borderStyle: "solid",
835
- borderColor: getReleaseColorVariant(release.action.type, "200"),
878
+ borderColor: getReleaseColorVariant(release.actions[0].type, "200"),
836
879
  overflow: "hidden",
837
880
  hasRadius: true,
838
881
  children: [
@@ -843,28 +886,28 @@ const CMReleasesContainer = () => {
843
886
  paddingBottom: 3,
844
887
  paddingLeft: 4,
845
888
  paddingRight: 4,
846
- background: getReleaseColorVariant(release.action.type, "100"),
889
+ background: getReleaseColorVariant(release.actions[0].type, "100"),
847
890
  width: "100%",
848
891
  children: /* @__PURE__ */ jsx(
849
892
  Typography,
850
893
  {
851
894
  fontSize: 1,
852
895
  variant: "pi",
853
- textColor: getReleaseColorVariant(release.action.type, "600"),
896
+ textColor: getReleaseColorVariant(release.actions[0].type, "600"),
854
897
  children: formatMessage(
855
898
  {
856
899
  id: "content-releases.content-manager-edit-view.list-releases.title",
857
900
  defaultMessage: "{isPublish, select, true {Will be published in} other {Will be unpublished in}}"
858
901
  },
859
- { isPublish: release.action.type === "publish" }
902
+ { isPublish: release.actions[0].type === "publish" }
860
903
  )
861
904
  }
862
905
  )
863
906
  }
864
907
  ),
865
- /* @__PURE__ */ jsxs(Flex, { padding: 4, direction: "column", gap: 2, width: "100%", alignItems: "flex-start", children: [
908
+ /* @__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
909
  /* @__PURE__ */ jsx(Typography, { fontSize: 2, fontWeight: "bold", variant: "omega", textColor: "neutral700", children: release.name }),
867
- IsSchedulingEnabled && release.scheduledAt && release.timezone && /* @__PURE__ */ jsx(Typography, { variant: "pi", textColor: "neutral600", children: formatMessage(
910
+ release.scheduledAt && release.timezone && /* @__PURE__ */ jsx(Typography, { variant: "pi", textColor: "neutral600", children: formatMessage(
868
911
  {
869
912
  id: "content-releases.content-manager-edit-view.scheduled.date",
870
913
  defaultMessage: "{date} at {time} ({offset})"
@@ -886,23 +929,23 @@ const CMReleasesContainer = () => {
886
929
  )
887
930
  }
888
931
  ) }),
889
- /* @__PURE__ */ jsx(CheckPermissions, { permissions: PERMISSIONS.deleteAction, children: /* @__PURE__ */ jsxs(ReleaseActionMenu.Root, { hasTriggerBorder: true, children: [
932
+ canDeleteAction ? /* @__PURE__ */ jsxs(ReleaseActionMenu.Root, { hasTriggerBorder: true, children: [
890
933
  /* @__PURE__ */ jsx(ReleaseActionMenu.EditReleaseItem, { releaseId: release.id }),
891
934
  /* @__PURE__ */ jsx(
892
935
  ReleaseActionMenu.DeleteReleaseActionItem,
893
936
  {
894
937
  releaseId: release.id,
895
- actionId: release.action.id
938
+ actionId: release.actions[0].id
896
939
  }
897
940
  )
898
- ] }) })
899
- ] })
941
+ ] }) : null
942
+ ] }) })
900
943
  ]
901
944
  },
902
945
  release.id
903
946
  );
904
947
  }),
905
- /* @__PURE__ */ jsx(CheckPermissions, { permissions: PERMISSIONS.createAction, children: /* @__PURE__ */ jsx(
948
+ canCreateAction ? /* @__PURE__ */ jsx(
906
949
  Button,
907
950
  {
908
951
  justifyContent: "center",
@@ -917,45 +960,230 @@ const CMReleasesContainer = () => {
917
960
  defaultMessage: "Add to release"
918
961
  })
919
962
  }
920
- ) })
963
+ ) : null
921
964
  ] }),
922
965
  isModalOpen && /* @__PURE__ */ jsx(
923
966
  AddActionToReleaseModal,
924
967
  {
925
968
  handleClose: toggleModal,
926
969
  contentTypeUid,
927
- entryId
970
+ entryId: id
928
971
  }
929
972
  )
930
973
  ]
931
974
  }
932
- ) });
975
+ );
976
+ };
977
+ const getContentPermissions = (subject) => {
978
+ const permissions = {
979
+ publish: [
980
+ {
981
+ action: "plugin::content-manager.explorer.publish",
982
+ subject,
983
+ id: "",
984
+ actionParameters: {},
985
+ properties: {},
986
+ conditions: []
987
+ }
988
+ ]
989
+ };
990
+ return permissions;
991
+ };
992
+ const ReleaseAction = ({ documentIds, model }) => {
993
+ const { formatMessage } = useIntl();
994
+ const { toggleNotification } = useNotification();
995
+ const { formatAPIError } = useAPIErrorHandler();
996
+ const [{ query }] = useQueryParams();
997
+ const contentPermissions = getContentPermissions(model);
998
+ const {
999
+ allowedActions: { canPublish }
1000
+ } = useRBAC(contentPermissions);
1001
+ const {
1002
+ allowedActions: { canCreate }
1003
+ } = useRBAC(PERMISSIONS);
1004
+ const response = useGetReleasesQuery();
1005
+ const releases = response.data?.data;
1006
+ const [createManyReleaseActions, { isLoading }] = useCreateManyReleaseActionsMutation();
1007
+ const handleSubmit = async (values) => {
1008
+ const locale = query.plugins?.i18n?.locale;
1009
+ const releaseActionEntries = documentIds.map(
1010
+ (id) => ({
1011
+ type: values.type,
1012
+ entry: {
1013
+ contentType: model,
1014
+ id,
1015
+ locale
1016
+ }
1017
+ })
1018
+ );
1019
+ const response2 = await createManyReleaseActions({
1020
+ body: releaseActionEntries,
1021
+ params: { releaseId: values.releaseId }
1022
+ });
1023
+ if ("data" in response2) {
1024
+ const notificationMessage = formatMessage(
1025
+ {
1026
+ id: "content-releases.content-manager-list-view.add-to-release.notification.success.message",
1027
+ defaultMessage: "{entriesAlreadyInRelease} out of {totalEntries} entries were already in the release."
1028
+ },
1029
+ {
1030
+ entriesAlreadyInRelease: response2.data.meta.entriesAlreadyInRelease,
1031
+ totalEntries: response2.data.meta.totalEntries
1032
+ }
1033
+ );
1034
+ const notification = {
1035
+ type: "success",
1036
+ title: formatMessage(
1037
+ {
1038
+ id: "content-releases.content-manager-list-view.add-to-release.notification.success.title",
1039
+ defaultMessage: "Successfully added to release."
1040
+ },
1041
+ {
1042
+ entriesAlreadyInRelease: response2.data.meta.entriesAlreadyInRelease,
1043
+ totalEntries: response2.data.meta.totalEntries
1044
+ }
1045
+ ),
1046
+ message: response2.data.meta.entriesAlreadyInRelease ? notificationMessage : ""
1047
+ };
1048
+ toggleNotification(notification);
1049
+ return true;
1050
+ }
1051
+ if ("error" in response2) {
1052
+ if (isAxiosError$1(response2.error)) {
1053
+ toggleNotification({
1054
+ type: "warning",
1055
+ message: formatAPIError(response2.error)
1056
+ });
1057
+ } else {
1058
+ toggleNotification({
1059
+ type: "warning",
1060
+ message: formatMessage({ id: "notification.error", defaultMessage: "An error occurred" })
1061
+ });
1062
+ }
1063
+ }
1064
+ };
1065
+ if (!canCreate || !canPublish)
1066
+ return null;
1067
+ return {
1068
+ actionType: "release",
1069
+ variant: "tertiary",
1070
+ label: formatMessage({
1071
+ id: "content-manager-list-view.add-to-release",
1072
+ defaultMessage: "Add to Release"
1073
+ }),
1074
+ dialog: {
1075
+ type: "modal",
1076
+ title: formatMessage({
1077
+ id: "content-manager-list-view.add-to-release",
1078
+ defaultMessage: "Add to Release"
1079
+ }),
1080
+ content: ({ onClose }) => {
1081
+ return /* @__PURE__ */ jsx(
1082
+ Formik,
1083
+ {
1084
+ onSubmit: async (values) => {
1085
+ const data = await handleSubmit(values);
1086
+ if (data) {
1087
+ return onClose();
1088
+ }
1089
+ },
1090
+ validationSchema: RELEASE_ACTION_FORM_SCHEMA,
1091
+ initialValues: INITIAL_VALUES,
1092
+ children: ({ values, setFieldValue }) => /* @__PURE__ */ jsxs(Form, { children: [
1093
+ releases?.length === 0 ? /* @__PURE__ */ jsx(NoReleases, {}) : /* @__PURE__ */ jsx(ModalBody, { children: /* @__PURE__ */ jsxs(Flex, { direction: "column", alignItems: "stretch", gap: 2, children: [
1094
+ /* @__PURE__ */ jsx(Box, { paddingBottom: 6, children: /* @__PURE__ */ jsx(
1095
+ SingleSelect,
1096
+ {
1097
+ required: true,
1098
+ label: formatMessage({
1099
+ id: "content-releases.content-manager-list-view.add-to-release.select-label",
1100
+ defaultMessage: "Select a release"
1101
+ }),
1102
+ placeholder: formatMessage({
1103
+ id: "content-releases.content-manager-list-view.add-to-release.select-placeholder",
1104
+ defaultMessage: "Select"
1105
+ }),
1106
+ onChange: (value) => setFieldValue("releaseId", value),
1107
+ value: values.releaseId,
1108
+ children: releases?.map((release) => /* @__PURE__ */ jsx(SingleSelectOption, { value: release.id, children: release.name }, release.id))
1109
+ }
1110
+ ) }),
1111
+ /* @__PURE__ */ jsx(FieldLabel, { children: formatMessage({
1112
+ id: "content-releases.content-manager-list-view.add-to-release.action-type-label",
1113
+ defaultMessage: "What do you want to do with these entries?"
1114
+ }) }),
1115
+ /* @__PURE__ */ jsx(
1116
+ ReleaseActionOptions,
1117
+ {
1118
+ selected: values.type,
1119
+ handleChange: (e) => setFieldValue("type", e.target.value),
1120
+ name: "type"
1121
+ }
1122
+ )
1123
+ ] }) }),
1124
+ /* @__PURE__ */ jsx(
1125
+ ModalFooter,
1126
+ {
1127
+ startActions: /* @__PURE__ */ jsx(Button, { onClick: onClose, variant: "tertiary", name: "cancel", children: formatMessage({
1128
+ id: "content-releases.content-manager-list-view.add-to-release.cancel-button",
1129
+ defaultMessage: "Cancel"
1130
+ }) }),
1131
+ endActions: (
1132
+ /**
1133
+ * TODO: Ideally we would use isValid from Formik to disable the button, however currently it always returns true
1134
+ * for yup.string().required(), even when the value is falsy (including empty string)
1135
+ */
1136
+ /* @__PURE__ */ jsx(Button, { type: "submit", disabled: !values.releaseId, loading: isLoading, children: formatMessage({
1137
+ id: "content-releases.content-manager-list-view.add-to-release.continue-button",
1138
+ defaultMessage: "Continue"
1139
+ }) })
1140
+ )
1141
+ }
1142
+ )
1143
+ ] })
1144
+ }
1145
+ );
1146
+ }
1147
+ }
1148
+ };
1149
+ };
1150
+ const prefixPluginTranslations = (trad, pluginId2) => {
1151
+ if (!pluginId2) {
1152
+ throw new TypeError("pluginId can't be empty");
1153
+ }
1154
+ return Object.keys(trad).reduce((acc, current) => {
1155
+ acc[`${pluginId2}.${current}`] = trad[current];
1156
+ return acc;
1157
+ }, {});
933
1158
  };
934
1159
  const admin = {
935
1160
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
936
1161
  register(app) {
1162
+ app.createHook("ContentReleases/pages/ReleaseDetails/add-locale-in-releases");
937
1163
  if (window.strapi.features.isEnabled("cms-content-releases")) {
938
1164
  app.addMenuLink({
939
- to: `/plugins/${pluginId}`,
1165
+ to: `plugins/${pluginId}`,
940
1166
  icon: PaperPlane,
941
1167
  intlLabel: {
942
1168
  id: `${pluginId}.plugin.name`,
943
1169
  defaultMessage: "Releases"
944
1170
  },
945
- async Component() {
946
- const { App } = await import("./App-bpzO2Ljh.mjs");
947
- return App;
948
- },
1171
+ Component: () => import("./App-O0ZO-S35.mjs").then((mod) => ({ default: mod.App })),
949
1172
  permissions: PERMISSIONS.main
950
1173
  });
951
1174
  app.addMiddlewares([() => releaseApi.middleware]);
952
1175
  app.addReducers({
953
1176
  [releaseApi.reducerPath]: releaseApi.reducer
954
1177
  });
955
- app.injectContentManagerComponent("editView", "right-links", {
1178
+ app.getPlugin("content-manager").injectComponent("editView", "right-links", {
956
1179
  name: `${pluginId}-link`,
957
1180
  Component: CMReleasesContainer
958
1181
  });
1182
+ app.plugins["content-manager"].apis.addBulkAction((actions) => {
1183
+ const deleteActionIndex = actions.findIndex((action) => action.name === "DeleteAction");
1184
+ actions.splice(deleteActionIndex, 0, ReleaseAction);
1185
+ return actions;
1186
+ });
959
1187
  } else if (!window.strapi.features.isEnabled("cms-content-releases") && window.strapi?.flags?.promoteEE) {
960
1188
  app.addMenuLink({
961
1189
  to: `/plugins/purchase-content-releases`,
@@ -964,9 +1192,10 @@ const admin = {
964
1192
  id: `${pluginId}.plugin.name`,
965
1193
  defaultMessage: "Releases"
966
1194
  },
1195
+ permissions: [],
967
1196
  async Component() {
968
- const { PurchaseContentReleases } = await import("./PurchaseContentReleases-Clm0iACO.mjs");
969
- return PurchaseContentReleases;
1197
+ const { PurchaseContentReleases } = await import("./PurchaseContentReleases-Ex09YpKR.mjs");
1198
+ return { default: PurchaseContentReleases };
970
1199
  },
971
1200
  lockIcon: true
972
1201
  });
@@ -975,7 +1204,7 @@ const admin = {
975
1204
  async registerTrads({ locales }) {
976
1205
  const importedTrads = await Promise.all(
977
1206
  locales.map((locale) => {
978
- return __variableDynamicImportRuntimeHelper(/* @__PURE__ */ Object.assign({ "./translations/en.json": () => import("./en-WuuhP6Bn.mjs") }), `./translations/${locale}.json`).then(({ default: data }) => {
1207
+ return __variableDynamicImportRuntimeHelper(/* @__PURE__ */ Object.assign({ "./translations/en.json": () => import("./en-B9Ur3VsE.mjs") }), `./translations/${locale}.json`).then(({ default: data }) => {
979
1208
  return {
980
1209
  data: prefixPluginTranslations(data, "content-releases"),
981
1210
  locale
@@ -999,15 +1228,14 @@ export {
999
1228
  useUpdateReleaseMutation as c,
1000
1229
  useDeleteReleaseMutation as d,
1001
1230
  usePublishReleaseMutation as e,
1002
- useTypedDispatch as f,
1231
+ useGetReleaseActionsQuery as f,
1003
1232
  getTimezoneOffset as g,
1004
- useGetReleaseActionsQuery as h,
1233
+ useUpdateReleaseActionMutation as h,
1005
1234
  isAxiosError as i,
1006
- useUpdateReleaseActionMutation as j,
1007
- ReleaseActionMenu as k,
1008
- admin as l,
1235
+ ReleaseActionMenu as j,
1236
+ admin as k,
1009
1237
  pluginId as p,
1010
1238
  releaseApi as r,
1011
1239
  useGetReleasesQuery as u
1012
1240
  };
1013
- //# sourceMappingURL=index-AECgcaDa.mjs.map
1241
+ //# sourceMappingURL=index-DjDPK8kb.mjs.map