@strapi/content-releases 0.0.0-experimental.fc1ac2acd58c8a5a858679956b6d102ac5ee4011 → 0.0.0-experimental.fea7af0bd6b406e4648e4c6669829249f73eb60f

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 (105) hide show
  1. package/dist/_chunks/{App-C768ulk4.js → App-HjWtUYmc.js} +233 -261
  2. package/dist/_chunks/App-HjWtUYmc.js.map +1 -0
  3. package/dist/_chunks/{App-0Er6xxcq.mjs → App-gu1aiP6i.mjs} +237 -265
  4. package/dist/_chunks/App-gu1aiP6i.mjs.map +1 -0
  5. package/dist/_chunks/{PurchaseContentReleases-Clm0iACO.mjs → PurchaseContentReleases-3tRbmbY3.mjs} +2 -2
  6. package/dist/_chunks/PurchaseContentReleases-3tRbmbY3.mjs.map +1 -0
  7. package/dist/_chunks/{PurchaseContentReleases-YhAPgpG9.js → PurchaseContentReleases-bpIYXOfu.js} +2 -2
  8. package/dist/_chunks/PurchaseContentReleases-bpIYXOfu.js.map +1 -0
  9. package/dist/_chunks/{en-gcJJ5htG.js → en-HrREghh3.js} +11 -3
  10. package/dist/_chunks/en-HrREghh3.js.map +1 -0
  11. package/dist/_chunks/{en-WuuhP6Bn.mjs → en-ltT1TlKQ.mjs} +11 -3
  12. package/dist/_chunks/en-ltT1TlKQ.mjs.map +1 -0
  13. package/dist/_chunks/{index-BLSMpbpZ.js → index-ZNwxYN8H.js} +338 -31
  14. package/dist/_chunks/index-ZNwxYN8H.js.map +1 -0
  15. package/dist/_chunks/{index-fJx1up7m.mjs → index-mvj9PSKd.mjs} +345 -38
  16. package/dist/_chunks/index-mvj9PSKd.mjs.map +1 -0
  17. package/dist/admin/index.js +1 -1
  18. package/dist/admin/index.mjs +1 -1
  19. package/dist/server/index.js +380 -172
  20. package/dist/server/index.js.map +1 -1
  21. package/dist/server/index.mjs +380 -173
  22. package/dist/server/index.mjs.map +1 -1
  23. package/package.json +22 -15
  24. package/dist/_chunks/App-0Er6xxcq.mjs.map +0 -1
  25. package/dist/_chunks/App-C768ulk4.js.map +0 -1
  26. package/dist/_chunks/PurchaseContentReleases-Clm0iACO.mjs.map +0 -1
  27. package/dist/_chunks/PurchaseContentReleases-YhAPgpG9.js.map +0 -1
  28. package/dist/_chunks/en-WuuhP6Bn.mjs.map +0 -1
  29. package/dist/_chunks/en-gcJJ5htG.js.map +0 -1
  30. package/dist/_chunks/index-BLSMpbpZ.js.map +0 -1
  31. package/dist/_chunks/index-fJx1up7m.mjs.map +0 -1
  32. package/dist/admin/src/components/CMReleasesContainer.d.ts +0 -1
  33. package/dist/admin/src/components/RelativeTime.d.ts +0 -28
  34. package/dist/admin/src/components/ReleaseActionMenu.d.ts +0 -26
  35. package/dist/admin/src/components/ReleaseActionOptions.d.ts +0 -9
  36. package/dist/admin/src/components/ReleaseModal.d.ts +0 -16
  37. package/dist/admin/src/constants.d.ts +0 -58
  38. package/dist/admin/src/index.d.ts +0 -3
  39. package/dist/admin/src/pages/App.d.ts +0 -1
  40. package/dist/admin/src/pages/PurchaseContentReleases.d.ts +0 -2
  41. package/dist/admin/src/pages/ReleaseDetailsPage.d.ts +0 -2
  42. package/dist/admin/src/pages/ReleasesPage.d.ts +0 -8
  43. package/dist/admin/src/pages/tests/mockReleaseDetailsPageData.d.ts +0 -181
  44. package/dist/admin/src/pages/tests/mockReleasesPageData.d.ts +0 -39
  45. package/dist/admin/src/pluginId.d.ts +0 -1
  46. package/dist/admin/src/services/axios.d.ts +0 -29
  47. package/dist/admin/src/services/release.d.ts +0 -369
  48. package/dist/admin/src/store/hooks.d.ts +0 -7
  49. package/dist/admin/src/utils/time.d.ts +0 -1
  50. package/dist/server/src/bootstrap.d.ts +0 -5
  51. package/dist/server/src/bootstrap.d.ts.map +0 -1
  52. package/dist/server/src/constants.d.ts +0 -12
  53. package/dist/server/src/constants.d.ts.map +0 -1
  54. package/dist/server/src/content-types/index.d.ts +0 -99
  55. package/dist/server/src/content-types/index.d.ts.map +0 -1
  56. package/dist/server/src/content-types/release/index.d.ts +0 -48
  57. package/dist/server/src/content-types/release/index.d.ts.map +0 -1
  58. package/dist/server/src/content-types/release/schema.d.ts +0 -47
  59. package/dist/server/src/content-types/release/schema.d.ts.map +0 -1
  60. package/dist/server/src/content-types/release-action/index.d.ts +0 -50
  61. package/dist/server/src/content-types/release-action/index.d.ts.map +0 -1
  62. package/dist/server/src/content-types/release-action/schema.d.ts +0 -49
  63. package/dist/server/src/content-types/release-action/schema.d.ts.map +0 -1
  64. package/dist/server/src/controllers/index.d.ts +0 -18
  65. package/dist/server/src/controllers/index.d.ts.map +0 -1
  66. package/dist/server/src/controllers/release-action.d.ts +0 -9
  67. package/dist/server/src/controllers/release-action.d.ts.map +0 -1
  68. package/dist/server/src/controllers/release.d.ts +0 -11
  69. package/dist/server/src/controllers/release.d.ts.map +0 -1
  70. package/dist/server/src/controllers/validation/release-action.d.ts +0 -3
  71. package/dist/server/src/controllers/validation/release-action.d.ts.map +0 -1
  72. package/dist/server/src/controllers/validation/release.d.ts +0 -2
  73. package/dist/server/src/controllers/validation/release.d.ts.map +0 -1
  74. package/dist/server/src/destroy.d.ts +0 -5
  75. package/dist/server/src/destroy.d.ts.map +0 -1
  76. package/dist/server/src/index.d.ts +0 -3838
  77. package/dist/server/src/index.d.ts.map +0 -1
  78. package/dist/server/src/migrations/index.d.ts +0 -10
  79. package/dist/server/src/migrations/index.d.ts.map +0 -1
  80. package/dist/server/src/register.d.ts +0 -5
  81. package/dist/server/src/register.d.ts.map +0 -1
  82. package/dist/server/src/routes/index.d.ts +0 -35
  83. package/dist/server/src/routes/index.d.ts.map +0 -1
  84. package/dist/server/src/routes/release-action.d.ts +0 -18
  85. package/dist/server/src/routes/release-action.d.ts.map +0 -1
  86. package/dist/server/src/routes/release.d.ts +0 -18
  87. package/dist/server/src/routes/release.d.ts.map +0 -1
  88. package/dist/server/src/services/index.d.ts +0 -3572
  89. package/dist/server/src/services/index.d.ts.map +0 -1
  90. package/dist/server/src/services/release.d.ts +0 -1812
  91. package/dist/server/src/services/release.d.ts.map +0 -1
  92. package/dist/server/src/services/scheduling.d.ts +0 -18
  93. package/dist/server/src/services/scheduling.d.ts.map +0 -1
  94. package/dist/server/src/services/validation.d.ts +0 -14
  95. package/dist/server/src/services/validation.d.ts.map +0 -1
  96. package/dist/server/src/utils/index.d.ts +0 -18
  97. package/dist/server/src/utils/index.d.ts.map +0 -1
  98. package/dist/shared/contracts/release-actions.d.ts +0 -105
  99. package/dist/shared/contracts/release-actions.d.ts.map +0 -1
  100. package/dist/shared/contracts/releases.d.ts +0 -166
  101. package/dist/shared/contracts/releases.d.ts.map +0 -1
  102. package/dist/shared/types.d.ts +0 -24
  103. package/dist/shared/types.d.ts.map +0 -1
  104. package/dist/shared/validation-schemas.d.ts +0 -2
  105. package/dist/shared/validation-schemas.d.ts.map +0 -1
@@ -1,14 +1,14 @@
1
- import { getFetchClient, useNotification, useAPIErrorHandler, CheckPermissions, useQueryParams, prefixPluginTranslations } from "@strapi/helper-plugin";
2
- import { Cross, Pencil, More, Plus, EmptyDocuments, PaperPlane } from "@strapi/icons";
1
+ import { getFetchClient, useNotification, useAPIErrorHandler, CheckPermissions, useCMEditViewDataManager, NoContent, useRBAC, SortIcon, prefixPluginTranslations } from "@strapi/helper-plugin";
2
+ import { Cross, Pencil, More, Plus, PaperPlane } from "@strapi/icons";
3
3
  import { jsx, jsxs } from "react/jsx-runtime";
4
4
  import * as React from "react";
5
5
  import { skipToken } from "@reduxjs/toolkit/query";
6
- import { IconButton, Flex, Icon, Typography, Field, FieldLabel, VisuallyHidden, FieldInput, Box, Button, ModalLayout, ModalHeader, ModalBody, SingleSelect, SingleSelectOption, ModalFooter, EmptyStateLayout } from "@strapi/design-system";
6
+ import { IconButton, Flex, Icon, Typography, Field, FieldLabel, VisuallyHidden, FieldInput, Box, Button as Button$1, ModalLayout, ModalHeader, ModalBody, SingleSelect, SingleSelectOption, ModalFooter, Popover } from "@strapi/design-system";
7
7
  import { Menu, Link, LinkButton } from "@strapi/design-system/v2";
8
8
  import { isAxiosError as isAxiosError$1 } from "axios";
9
9
  import { Formik, Form } from "formik";
10
10
  import { useIntl } from "react-intl";
11
- import { NavLink, useParams, Link as Link$1 } from "react-router-dom";
11
+ import { NavLink, Link as Link$1 } from "react-router-dom";
12
12
  import * as yup from "yup";
13
13
  import { createApi } from "@reduxjs/toolkit/query/react";
14
14
  import styled from "styled-components";
@@ -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: (result, error, arg) => [{ type: "Release", id: arg.id }]
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 {
@@ -467,9 +500,9 @@ const EditReleaseItem = ({ releaseId }) => {
467
500
  return /* @__PURE__ */ jsx(StyledMenuItem, { children: /* @__PURE__ */ jsx(
468
501
  Link,
469
502
  {
470
- as: NavLink,
471
- to: `/plugins/content-releases/${releaseId}`,
503
+ href: `/admin/plugins/content-releases/${releaseId}`,
472
504
  startIcon: /* @__PURE__ */ jsx(Icon, { as: Pencil, width: 3, height: 3 }),
505
+ isExternal: false,
473
506
  children: /* @__PURE__ */ jsx(Typography, { variant: "omega", children: formatMessage({
474
507
  id: "content-releases.content-manager-edit-view.edit-release",
475
508
  defaultMessage: "Edit release"
@@ -628,13 +661,12 @@ const INITIAL_VALUES = {
628
661
  const NoReleases = () => {
629
662
  const { formatMessage } = useIntl();
630
663
  return /* @__PURE__ */ jsx(
631
- EmptyStateLayout,
664
+ NoContent,
632
665
  {
633
- icon: /* @__PURE__ */ jsx(EmptyDocuments, { width: "10rem" }),
634
- content: formatMessage({
666
+ content: {
635
667
  id: "content-releases.content-manager-edit-view.add-to-release.no-releases-message",
636
668
  defaultMessage: "No available releases. Open the list of releases and create a new one from there."
637
- }),
669
+ },
638
670
  action: /* @__PURE__ */ jsx(
639
671
  LinkButton,
640
672
  {
@@ -661,8 +693,7 @@ const AddActionToReleaseModal = ({
661
693
  const { formatMessage } = useIntl();
662
694
  const toggleNotification = useNotification();
663
695
  const { formatAPIError } = useAPIErrorHandler();
664
- const [{ query }] = useQueryParams();
665
- const locale = query.plugins?.i18n?.locale;
696
+ const { modifiedData } = useCMEditViewDataManager();
666
697
  const response = useGetReleasesForEntryQuery({
667
698
  contentTypeUid,
668
699
  entryId,
@@ -671,6 +702,7 @@ const AddActionToReleaseModal = ({
671
702
  const releases = response.data?.data;
672
703
  const [createReleaseAction, { isLoading }] = useCreateReleaseActionMutation();
673
704
  const handleSubmit = async (values) => {
705
+ const locale = modifiedData.locale;
674
706
  const releaseActionEntry = {
675
707
  contentType: contentTypeUid,
676
708
  id: entryId,
@@ -752,7 +784,7 @@ const AddActionToReleaseModal = ({
752
784
  /* @__PURE__ */ jsx(
753
785
  ModalFooter,
754
786
  {
755
- startActions: /* @__PURE__ */ jsx(Button, { onClick: handleClose, variant: "tertiary", name: "cancel", children: formatMessage({
787
+ startActions: /* @__PURE__ */ jsx(Button$1, { onClick: handleClose, variant: "tertiary", name: "cancel", children: formatMessage({
756
788
  id: "content-releases.content-manager-edit-view.add-to-release.cancel-button",
757
789
  defaultMessage: "Cancel"
758
790
  }) }),
@@ -761,7 +793,7 @@ const AddActionToReleaseModal = ({
761
793
  * TODO: Ideally we would use isValid from Formik to disable the button, however currently it always returns true
762
794
  * for yup.string().required(), even when the value is falsy (including empty string)
763
795
  */
764
- /* @__PURE__ */ jsx(Button, { type: "submit", disabled: !values.releaseId, loading: isLoading, children: formatMessage({
796
+ /* @__PURE__ */ jsx(Button$1, { type: "submit", disabled: !values.releaseId, loading: isLoading, children: formatMessage({
765
797
  id: "content-releases.content-manager-edit-view.add-to-release.continue-button",
766
798
  defaultMessage: "Continue"
767
799
  }) })
@@ -777,14 +809,17 @@ const AddActionToReleaseModal = ({
777
809
  const CMReleasesContainer = () => {
778
810
  const [isModalOpen, setIsModalOpen] = React.useState(false);
779
811
  const { formatMessage, formatDate, formatTime } = useIntl();
780
- const { id, slug } = useParams();
781
- const isCreatingEntry = id === "create";
812
+ const {
813
+ isCreatingEntry,
814
+ hasDraftAndPublish,
815
+ initialData: { id: entryId },
816
+ slug
817
+ } = useCMEditViewDataManager();
782
818
  const contentTypeUid = slug;
783
- const IsSchedulingEnabled = window.strapi.future.isEnabled("contentReleasesScheduling");
784
- const canFetch = id != null && contentTypeUid != null;
819
+ const canFetch = entryId != null && contentTypeUid != null;
785
820
  const fetchParams = canFetch ? {
786
821
  contentTypeUid,
787
- entryId: id,
822
+ entryId,
788
823
  hasEntryAttached: true
789
824
  } : skipToken;
790
825
  const response = useGetReleasesForEntryQuery(fetchParams);
@@ -792,7 +827,7 @@ const CMReleasesContainer = () => {
792
827
  if (!canFetch) {
793
828
  return null;
794
829
  }
795
- if (isCreatingEntry) {
830
+ if (isCreatingEntry || !hasDraftAndPublish) {
796
831
  return null;
797
832
  }
798
833
  const toggleModal = () => setIsModalOpen((prev) => !prev);
@@ -829,7 +864,7 @@ const CMReleasesContainer = () => {
829
864
  alignItems: "start",
830
865
  borderWidth: "1px",
831
866
  borderStyle: "solid",
832
- borderColor: getReleaseColorVariant(release.action.type, "200"),
867
+ borderColor: getReleaseColorVariant(release.actions[0].type, "200"),
833
868
  overflow: "hidden",
834
869
  hasRadius: true,
835
870
  children: [
@@ -840,20 +875,20 @@ const CMReleasesContainer = () => {
840
875
  paddingBottom: 3,
841
876
  paddingLeft: 4,
842
877
  paddingRight: 4,
843
- background: getReleaseColorVariant(release.action.type, "100"),
878
+ background: getReleaseColorVariant(release.actions[0].type, "100"),
844
879
  width: "100%",
845
880
  children: /* @__PURE__ */ jsx(
846
881
  Typography,
847
882
  {
848
883
  fontSize: 1,
849
884
  variant: "pi",
850
- textColor: getReleaseColorVariant(release.action.type, "600"),
885
+ textColor: getReleaseColorVariant(release.actions[0].type, "600"),
851
886
  children: formatMessage(
852
887
  {
853
888
  id: "content-releases.content-manager-edit-view.list-releases.title",
854
889
  defaultMessage: "{isPublish, select, true {Will be published in} other {Will be unpublished in}}"
855
890
  },
856
- { isPublish: release.action.type === "publish" }
891
+ { isPublish: release.actions[0].type === "publish" }
857
892
  )
858
893
  }
859
894
  )
@@ -861,7 +896,7 @@ const CMReleasesContainer = () => {
861
896
  ),
862
897
  /* @__PURE__ */ jsxs(Flex, { padding: 4, direction: "column", gap: 2, width: "100%", alignItems: "flex-start", children: [
863
898
  /* @__PURE__ */ jsx(Typography, { fontSize: 2, fontWeight: "bold", variant: "omega", textColor: "neutral700", children: release.name }),
864
- IsSchedulingEnabled && release.scheduledAt && release.timezone && /* @__PURE__ */ jsx(Typography, { variant: "pi", textColor: "neutral600", children: formatMessage(
899
+ release.scheduledAt && release.timezone && /* @__PURE__ */ jsx(Typography, { variant: "pi", textColor: "neutral600", children: formatMessage(
865
900
  {
866
901
  id: "content-releases.content-manager-edit-view.scheduled.date",
867
902
  defaultMessage: "{date} at {time} ({offset})"
@@ -889,7 +924,7 @@ const CMReleasesContainer = () => {
889
924
  ReleaseActionMenu.DeleteReleaseActionItem,
890
925
  {
891
926
  releaseId: release.id,
892
- actionId: release.action.id
927
+ actionId: release.actions[0].id
893
928
  }
894
929
  )
895
930
  ] }) })
@@ -900,7 +935,7 @@ const CMReleasesContainer = () => {
900
935
  );
901
936
  }),
902
937
  /* @__PURE__ */ jsx(CheckPermissions, { permissions: PERMISSIONS.createAction, children: /* @__PURE__ */ jsx(
903
- Button,
938
+ Button$1,
904
939
  {
905
940
  justifyContent: "center",
906
941
  paddingLeft: 4,
@@ -921,25 +956,291 @@ const CMReleasesContainer = () => {
921
956
  {
922
957
  handleClose: toggleModal,
923
958
  contentTypeUid,
924
- entryId: id
959
+ entryId
925
960
  }
926
961
  )
927
962
  ]
928
963
  }
929
964
  ) });
930
965
  };
966
+ const getContentPermissions = (subject) => {
967
+ const permissions = {
968
+ publish: [
969
+ {
970
+ action: "plugin::content-manager.explorer.publish",
971
+ subject,
972
+ id: "",
973
+ actionParameters: {},
974
+ properties: {},
975
+ conditions: []
976
+ }
977
+ ]
978
+ };
979
+ return permissions;
980
+ };
981
+ const ReleaseAction = ({ ids, model }) => {
982
+ const { formatMessage } = useIntl();
983
+ const toggleNotification = useNotification();
984
+ const { formatAPIError } = useAPIErrorHandler();
985
+ const { modifiedData } = useCMEditViewDataManager();
986
+ const contentPermissions = getContentPermissions(model);
987
+ const {
988
+ allowedActions: { canPublish }
989
+ } = useRBAC(contentPermissions);
990
+ const {
991
+ allowedActions: { canCreate }
992
+ } = useRBAC(PERMISSIONS);
993
+ const response = useGetReleasesQuery();
994
+ const releases = response.data?.data;
995
+ const [createManyReleaseActions, { isLoading }] = useCreateManyReleaseActionsMutation();
996
+ const handleSubmit = async (values) => {
997
+ const locale = modifiedData.locale;
998
+ const releaseActionEntries = ids.map((id) => ({
999
+ type: values.type,
1000
+ entry: {
1001
+ contentType: model,
1002
+ id,
1003
+ locale
1004
+ }
1005
+ }));
1006
+ const response2 = await createManyReleaseActions({
1007
+ body: releaseActionEntries,
1008
+ params: { releaseId: values.releaseId }
1009
+ });
1010
+ if ("data" in response2) {
1011
+ const notificationMessage = formatMessage(
1012
+ {
1013
+ id: "content-releases.content-manager-list-view.add-to-release.notification.success.message",
1014
+ defaultMessage: "{entriesAlreadyInRelease} out of {totalEntries} entries were already in the release."
1015
+ },
1016
+ {
1017
+ entriesAlreadyInRelease: response2.data.meta.entriesAlreadyInRelease,
1018
+ totalEntries: response2.data.meta.totalEntries
1019
+ }
1020
+ );
1021
+ const notification = {
1022
+ type: "success",
1023
+ title: formatMessage(
1024
+ {
1025
+ id: "content-releases.content-manager-list-view.add-to-release.notification.success.title",
1026
+ defaultMessage: "Successfully added to release."
1027
+ },
1028
+ {
1029
+ entriesAlreadyInRelease: response2.data.meta.entriesAlreadyInRelease,
1030
+ totalEntries: response2.data.meta.totalEntries
1031
+ }
1032
+ ),
1033
+ message: response2.data.meta.entriesAlreadyInRelease ? notificationMessage : ""
1034
+ };
1035
+ toggleNotification(notification);
1036
+ return true;
1037
+ }
1038
+ if ("error" in response2) {
1039
+ if (isAxiosError$1(response2.error)) {
1040
+ toggleNotification({
1041
+ type: "warning",
1042
+ message: formatAPIError(response2.error)
1043
+ });
1044
+ } else {
1045
+ toggleNotification({
1046
+ type: "warning",
1047
+ message: formatMessage({ id: "notification.error", defaultMessage: "An error occurred" })
1048
+ });
1049
+ }
1050
+ }
1051
+ };
1052
+ if (!canCreate || !canPublish)
1053
+ return null;
1054
+ return {
1055
+ actionType: "release",
1056
+ variant: "tertiary",
1057
+ label: formatMessage({
1058
+ id: "content-manager-list-view.add-to-release",
1059
+ defaultMessage: "Add to Release"
1060
+ }),
1061
+ dialog: {
1062
+ type: "modal",
1063
+ title: formatMessage({
1064
+ id: "content-manager-list-view.add-to-release",
1065
+ defaultMessage: "Add to Release"
1066
+ }),
1067
+ content: ({ onClose }) => {
1068
+ return /* @__PURE__ */ jsx(
1069
+ Formik,
1070
+ {
1071
+ onSubmit: async (values) => {
1072
+ const data = await handleSubmit(values);
1073
+ if (data) {
1074
+ return onClose();
1075
+ }
1076
+ },
1077
+ validationSchema: RELEASE_ACTION_FORM_SCHEMA,
1078
+ initialValues: INITIAL_VALUES,
1079
+ children: ({ values, setFieldValue }) => /* @__PURE__ */ jsxs(Form, { children: [
1080
+ releases?.length === 0 ? /* @__PURE__ */ jsx(NoReleases, {}) : /* @__PURE__ */ jsx(ModalBody, { children: /* @__PURE__ */ jsxs(Flex, { direction: "column", alignItems: "stretch", gap: 2, children: [
1081
+ /* @__PURE__ */ jsx(Box, { paddingBottom: 6, children: /* @__PURE__ */ jsx(
1082
+ SingleSelect,
1083
+ {
1084
+ required: true,
1085
+ label: formatMessage({
1086
+ id: "content-releases.content-manager-list-view.add-to-release.select-label",
1087
+ defaultMessage: "Select a release"
1088
+ }),
1089
+ placeholder: formatMessage({
1090
+ id: "content-releases.content-manager-list-view.add-to-release.select-placeholder",
1091
+ defaultMessage: "Select"
1092
+ }),
1093
+ onChange: (value) => setFieldValue("releaseId", value),
1094
+ value: values.releaseId,
1095
+ children: releases?.map((release) => /* @__PURE__ */ jsx(SingleSelectOption, { value: release.id, children: release.name }, release.id))
1096
+ }
1097
+ ) }),
1098
+ /* @__PURE__ */ jsx(FieldLabel, { children: formatMessage({
1099
+ id: "content-releases.content-manager-list-view.add-to-release.action-type-label",
1100
+ defaultMessage: "What do you want to do with these entries?"
1101
+ }) }),
1102
+ /* @__PURE__ */ jsx(
1103
+ ReleaseActionOptions,
1104
+ {
1105
+ selected: values.type,
1106
+ handleChange: (e) => setFieldValue("type", e.target.value),
1107
+ name: "type"
1108
+ }
1109
+ )
1110
+ ] }) }),
1111
+ /* @__PURE__ */ jsx(
1112
+ ModalFooter,
1113
+ {
1114
+ startActions: /* @__PURE__ */ jsx(Button$1, { onClick: onClose, variant: "tertiary", name: "cancel", children: formatMessage({
1115
+ id: "content-releases.content-manager-list-view.add-to-release.cancel-button",
1116
+ defaultMessage: "Cancel"
1117
+ }) }),
1118
+ endActions: (
1119
+ /**
1120
+ * TODO: Ideally we would use isValid from Formik to disable the button, however currently it always returns true
1121
+ * for yup.string().required(), even when the value is falsy (including empty string)
1122
+ */
1123
+ /* @__PURE__ */ jsx(Button$1, { type: "submit", disabled: !values.releaseId, loading: isLoading, children: formatMessage({
1124
+ id: "content-releases.content-manager-list-view.add-to-release.continue-button",
1125
+ defaultMessage: "Continue"
1126
+ }) })
1127
+ )
1128
+ }
1129
+ )
1130
+ ] })
1131
+ }
1132
+ );
1133
+ }
1134
+ }
1135
+ };
1136
+ };
1137
+ const Button = styled.button`
1138
+ svg {
1139
+ > g,
1140
+ path {
1141
+ fill: ${({ theme }) => theme.colors.neutral500};
1142
+ }
1143
+ }
1144
+ &:hover {
1145
+ svg {
1146
+ > g,
1147
+ path {
1148
+ fill: ${({ theme }) => theme.colors.neutral600};
1149
+ }
1150
+ }
1151
+ }
1152
+ &:active {
1153
+ svg {
1154
+ > g,
1155
+ path {
1156
+ fill: ${({ theme }) => theme.colors.neutral400};
1157
+ }
1158
+ }
1159
+ }
1160
+ `;
1161
+ const ActionWrapper = styled(Flex)`
1162
+ svg {
1163
+ height: ${4 / 16}rem;
1164
+ }
1165
+ `;
1166
+ const useReleasesList = (entryId) => {
1167
+ const { uid: contentTypeUid } = useTypedSelector(
1168
+ (state) => state["content-manager_listView"].contentType
1169
+ );
1170
+ const listViewData = useTypedSelector((state) => state["content-manager_listView"].data);
1171
+ const entriesIds = listViewData.map((entry) => entry.id);
1172
+ const response = useGetMappedEntriesInReleasesQuery(
1173
+ { contentTypeUid, entriesIds },
1174
+ { skip: !entriesIds || !contentTypeUid || entriesIds.length === 0 }
1175
+ );
1176
+ const mappedEntriesInReleases = response.data || {};
1177
+ return mappedEntriesInReleases?.[entryId] || [];
1178
+ };
1179
+ const addColumnToTableHook = ({ displayedHeaders, layout }) => {
1180
+ const { contentType } = layout;
1181
+ if (!contentType.options?.draftAndPublish) {
1182
+ return { displayedHeaders, layout };
1183
+ }
1184
+ return {
1185
+ displayedHeaders: [
1186
+ ...displayedHeaders,
1187
+ {
1188
+ key: "__release_key__",
1189
+ fieldSchema: { type: "string" },
1190
+ metadatas: { label: "To be released in", searchable: true, sortable: false },
1191
+ name: "releasedAt",
1192
+ cellFormatter: (props) => /* @__PURE__ */ jsx(ReleaseListCell, { ...props })
1193
+ }
1194
+ ],
1195
+ layout
1196
+ };
1197
+ };
1198
+ const ReleaseListCell = ({ id }) => {
1199
+ const releases = useReleasesList(id);
1200
+ const [visible, setVisible] = React.useState(false);
1201
+ const buttonRef = React.useRef(null);
1202
+ const { formatMessage } = useIntl();
1203
+ const handleTogglePopover = () => setVisible((prev) => !prev);
1204
+ return /* @__PURE__ */ jsx(Flex, { onClick: (e) => e.stopPropagation(), children: /* @__PURE__ */ jsx(Button, { type: "button", onClick: handleTogglePopover, ref: buttonRef, children: /* @__PURE__ */ jsxs(ActionWrapper, { height: "2rem", width: "2rem", children: [
1205
+ /* @__PURE__ */ jsx(Typography, { style: { maxWidth: "252px", cursor: "pointer" }, textColor: "neutral800", children: releases.length > 0 ? formatMessage(
1206
+ {
1207
+ id: "content-releases.content-manager.list-view.releases-number",
1208
+ defaultMessage: "{number} {number, plural, one {release} other {releases}}"
1209
+ },
1210
+ {
1211
+ number: releases.length
1212
+ }
1213
+ ) : "-" }),
1214
+ /* @__PURE__ */ jsxs(Flex, { children: [
1215
+ releases.length > 0 && /* @__PURE__ */ jsx(SortIcon, {}),
1216
+ visible && /* @__PURE__ */ jsx(
1217
+ Popover,
1218
+ {
1219
+ onDismiss: handleTogglePopover,
1220
+ source: buttonRef,
1221
+ spacing: 16,
1222
+ children: /* @__PURE__ */ jsx("ul", { children: releases.map(({ id: id2, name }) => /* @__PURE__ */ jsx(Box, { padding: 3, as: "li", children: /* @__PURE__ */ jsx(Link, { href: `/admin/plugins/content-releases/${id2}`, isExternal: false, children: name }) }, id2)) })
1223
+ }
1224
+ )
1225
+ ] })
1226
+ ] }) }) });
1227
+ };
931
1228
  const admin = {
932
1229
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
933
1230
  register(app) {
1231
+ app.createHook("ContentReleases/pages/ReleaseDetails/add-locale-in-releases");
934
1232
  if (window.strapi.features.isEnabled("cms-content-releases")) {
935
1233
  app.addMenuLink({
936
- to: `plugins/${pluginId}`,
1234
+ to: `/plugins/${pluginId}`,
937
1235
  icon: PaperPlane,
938
1236
  intlLabel: {
939
1237
  id: `${pluginId}.plugin.name`,
940
1238
  defaultMessage: "Releases"
941
1239
  },
942
- Component: () => import("./App-0Er6xxcq.mjs").then((mod) => ({ default: mod.App })),
1240
+ async Component() {
1241
+ const { App } = await import("./App-gu1aiP6i.mjs");
1242
+ return App;
1243
+ },
943
1244
  permissions: PERMISSIONS.main
944
1245
  });
945
1246
  app.addMiddlewares([() => releaseApi.middleware]);
@@ -950,6 +1251,12 @@ const admin = {
950
1251
  name: `${pluginId}-link`,
951
1252
  Component: CMReleasesContainer
952
1253
  });
1254
+ app.plugins["content-manager"].apis.addBulkAction((actions) => {
1255
+ const deleteActionIndex = actions.findIndex((action) => action.name === "DeleteAction");
1256
+ actions.splice(deleteActionIndex, 0, ReleaseAction);
1257
+ return actions;
1258
+ });
1259
+ app.registerHook("Admin/CM/pages/ListView/inject-column-in-table", addColumnToTableHook);
953
1260
  } else if (!window.strapi.features.isEnabled("cms-content-releases") && window.strapi?.flags?.promoteEE) {
954
1261
  app.addMenuLink({
955
1262
  to: `/plugins/purchase-content-releases`,
@@ -959,7 +1266,7 @@ const admin = {
959
1266
  defaultMessage: "Releases"
960
1267
  },
961
1268
  async Component() {
962
- const { PurchaseContentReleases } = await import("./PurchaseContentReleases-Clm0iACO.mjs");
1269
+ const { PurchaseContentReleases } = await import("./PurchaseContentReleases-3tRbmbY3.mjs");
963
1270
  return PurchaseContentReleases;
964
1271
  },
965
1272
  lockIcon: true
@@ -969,7 +1276,7 @@ const admin = {
969
1276
  async registerTrads({ locales }) {
970
1277
  const importedTrads = await Promise.all(
971
1278
  locales.map((locale) => {
972
- return __variableDynamicImportRuntimeHelper(/* @__PURE__ */ Object.assign({ "./translations/en.json": () => import("./en-WuuhP6Bn.mjs") }), `./translations/${locale}.json`).then(({ default: data }) => {
1279
+ return __variableDynamicImportRuntimeHelper(/* @__PURE__ */ Object.assign({ "./translations/en.json": () => import("./en-ltT1TlKQ.mjs") }), `./translations/${locale}.json`).then(({ default: data }) => {
973
1280
  return {
974
1281
  data: prefixPluginTranslations(data, "content-releases"),
975
1282
  locale
@@ -1004,4 +1311,4 @@ export {
1004
1311
  releaseApi as r,
1005
1312
  useGetReleasesQuery as u
1006
1313
  };
1007
- //# sourceMappingURL=index-fJx1up7m.mjs.map
1314
+ //# sourceMappingURL=index-mvj9PSKd.mjs.map