@strapi/content-releases 0.0.0-next.1168c576ca50587b1a4377082ee09d2375410204 → 0.0.0-next.171c6daa568f68cd001f5c65d22fb934cd295edf

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 (31) hide show
  1. package/LICENSE +17 -1
  2. package/dist/_chunks/{App-_20W9dYa.js → App-dLXY5ei3.js} +784 -468
  3. package/dist/_chunks/App-dLXY5ei3.js.map +1 -0
  4. package/dist/_chunks/App-jrh58sXY.mjs +1330 -0
  5. package/dist/_chunks/App-jrh58sXY.mjs.map +1 -0
  6. package/dist/_chunks/PurchaseContentReleases-3tRbmbY3.mjs +51 -0
  7. package/dist/_chunks/PurchaseContentReleases-3tRbmbY3.mjs.map +1 -0
  8. package/dist/_chunks/PurchaseContentReleases-bpIYXOfu.js +51 -0
  9. package/dist/_chunks/PurchaseContentReleases-bpIYXOfu.js.map +1 -0
  10. package/dist/_chunks/{en-gYDqKYFd.js → en-HrREghh3.js} +30 -7
  11. package/dist/_chunks/en-HrREghh3.js.map +1 -0
  12. package/dist/_chunks/{en-MyLPoISH.mjs → en-ltT1TlKQ.mjs} +30 -7
  13. package/dist/_chunks/en-ltT1TlKQ.mjs.map +1 -0
  14. package/dist/_chunks/{index-KJa1Rb5F.js → index-CVO0Rqdm.js} +469 -41
  15. package/dist/_chunks/index-CVO0Rqdm.js.map +1 -0
  16. package/dist/_chunks/{index-c4zRX_sg.mjs → index-PiOGBETy.mjs} +486 -58
  17. package/dist/_chunks/index-PiOGBETy.mjs.map +1 -0
  18. package/dist/admin/index.js +1 -1
  19. package/dist/admin/index.mjs +2 -2
  20. package/dist/server/index.js +1059 -398
  21. package/dist/server/index.js.map +1 -1
  22. package/dist/server/index.mjs +1058 -398
  23. package/dist/server/index.mjs.map +1 -1
  24. package/package.json +16 -13
  25. package/dist/_chunks/App-L1jSxCiL.mjs +0 -1015
  26. package/dist/_chunks/App-L1jSxCiL.mjs.map +0 -1
  27. package/dist/_chunks/App-_20W9dYa.js.map +0 -1
  28. package/dist/_chunks/en-MyLPoISH.mjs.map +0 -1
  29. package/dist/_chunks/en-gYDqKYFd.js.map +0 -1
  30. package/dist/_chunks/index-KJa1Rb5F.js.map +0 -1
  31. package/dist/_chunks/index-c4zRX_sg.mjs.map +0 -1
@@ -159,7 +159,7 @@ const isAxiosError = (err) => {
159
159
  const releaseApi = react.createApi({
160
160
  reducerPath: pluginId,
161
161
  baseQuery: axiosBaseQuery,
162
- tagTypes: ["Release", "ReleaseAction"],
162
+ tagTypes: ["Release", "ReleaseAction", "EntriesInRelease"],
163
163
  endpoints: (build) => {
164
164
  return {
165
165
  getReleasesForEntry: build.query({
@@ -274,6 +274,20 @@ const releaseApi = react.createApi({
274
274
  { type: "ReleaseAction", id: "LIST" }
275
275
  ]
276
276
  }),
277
+ createManyReleaseActions: build.mutation({
278
+ query({ body, params }) {
279
+ return {
280
+ url: `/content-releases/${params.releaseId}/actions/bulk`,
281
+ method: "POST",
282
+ data: body
283
+ };
284
+ },
285
+ invalidatesTags: [
286
+ { type: "Release", id: "LIST" },
287
+ { type: "ReleaseAction", id: "LIST" },
288
+ { type: "EntriesInRelease" }
289
+ ]
290
+ }),
277
291
  updateReleaseAction: build.mutation({
278
292
  query({ body, params }) {
279
293
  return {
@@ -282,7 +296,27 @@ const releaseApi = react.createApi({
282
296
  data: body
283
297
  };
284
298
  },
285
- invalidatesTags: () => [{ type: "ReleaseAction", id: "LIST" }]
299
+ invalidatesTags: () => [{ type: "ReleaseAction", id: "LIST" }],
300
+ async onQueryStarted({ body, params, query: query2, actionPath }, { dispatch, queryFulfilled }) {
301
+ const paramsWithoutActionId = {
302
+ releaseId: params.releaseId,
303
+ ...query2
304
+ };
305
+ const patchResult = dispatch(
306
+ releaseApi.util.updateQueryData("getReleaseActions", paramsWithoutActionId, (draft) => {
307
+ const [key, index] = actionPath;
308
+ const action = draft.data[key][index];
309
+ if (action) {
310
+ action.type = body.type;
311
+ }
312
+ })
313
+ );
314
+ try {
315
+ await queryFulfilled;
316
+ } catch {
317
+ patchResult.undo();
318
+ }
319
+ }
286
320
  }),
287
321
  deleteReleaseAction: build.mutation({
288
322
  query({ params }) {
@@ -291,9 +325,11 @@ const releaseApi = react.createApi({
291
325
  method: "DELETE"
292
326
  };
293
327
  },
294
- invalidatesTags: [
328
+ invalidatesTags: (result, error, arg) => [
295
329
  { type: "Release", id: "LIST" },
296
- { type: "ReleaseAction", id: "LIST" }
330
+ { type: "Release", id: arg.params.releaseId },
331
+ { type: "ReleaseAction", id: "LIST" },
332
+ { type: "EntriesInRelease" }
297
333
  ]
298
334
  }),
299
335
  publishRelease: build.mutation({
@@ -312,7 +348,22 @@ const releaseApi = react.createApi({
312
348
  method: "DELETE"
313
349
  };
314
350
  },
315
- invalidatesTags: (result, error, arg) => [{ type: "Release", id: arg.id }]
351
+ invalidatesTags: () => [{ type: "Release", id: "LIST" }, { type: "EntriesInRelease" }]
352
+ }),
353
+ getMappedEntriesInReleases: build.query({
354
+ query(params) {
355
+ return {
356
+ url: "/content-releases/mapEntriesToReleases",
357
+ method: "GET",
358
+ config: {
359
+ params
360
+ }
361
+ };
362
+ },
363
+ transformResponse(response) {
364
+ return response.data;
365
+ },
366
+ providesTags: [{ type: "EntriesInRelease" }]
316
367
  })
317
368
  };
318
369
  }
@@ -324,12 +375,30 @@ const {
324
375
  useGetReleaseActionsQuery,
325
376
  useCreateReleaseMutation,
326
377
  useCreateReleaseActionMutation,
378
+ useCreateManyReleaseActionsMutation,
327
379
  useUpdateReleaseMutation,
328
380
  useUpdateReleaseActionMutation,
329
381
  usePublishReleaseMutation,
330
382
  useDeleteReleaseActionMutation,
331
- useDeleteReleaseMutation
383
+ useDeleteReleaseMutation,
384
+ useGetMappedEntriesInReleasesQuery
332
385
  } = releaseApi;
386
+ const getTimezoneOffset = (timezone, date) => {
387
+ try {
388
+ const offsetPart = new Intl.DateTimeFormat("en", {
389
+ timeZone: timezone,
390
+ timeZoneName: "longOffset"
391
+ }).formatToParts(date).find((part) => part.type === "timeZoneName");
392
+ const offset = offsetPart ? offsetPart.value : "";
393
+ let utcOffset = offset.replace("GMT", "UTC");
394
+ if (!utcOffset.includes("+") && !utcOffset.includes("-")) {
395
+ utcOffset = `${utcOffset}+00:00`;
396
+ }
397
+ return utcOffset;
398
+ } catch (error) {
399
+ return "";
400
+ }
401
+ };
333
402
  const useTypedDispatch = reactRedux.useDispatch;
334
403
  const useTypedSelector = reactRedux.useSelector;
335
404
  const StyledMenuItem = styled__default.default(v2.Menu.Item)`
@@ -400,7 +469,7 @@ const DeleteReleaseActionItem = ({ releaseId, actionId }) => {
400
469
  }
401
470
  };
402
471
  return /* @__PURE__ */ jsxRuntime.jsx(helperPlugin.CheckPermissions, { permissions: PERMISSIONS.deleteAction, children: /* @__PURE__ */ jsxRuntime.jsx(StyledMenuItem, { variant: "danger", onSelect: handleDeleteAction, children: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { gap: 2, children: [
403
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Icon, { as: icons.Cross, padding: 1 }),
472
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Icon, { as: icons.Cross, width: 3, height: 3 }),
404
473
  /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { textColor: "danger600", variant: "omega", children: formatMessage({
405
474
  id: "content-releases.content-manager-edit-view.remove-from-release",
406
475
  defaultMessage: "Remove from release"
@@ -439,7 +508,7 @@ const ReleaseActionEntryLinkItem = ({
439
508
  pathname: `/content-manager/collection-types/${contentTypeUid}/${entryId}`,
440
509
  search: locale && `?plugins[i18n][locale]=${locale}`
441
510
  },
442
- startIcon: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Icon, { as: icons.Pencil, padding: 1 }),
511
+ startIcon: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Icon, { as: icons.Pencil, width: 3, height: 3 }),
443
512
  children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "omega", children: formatMessage({
444
513
  id: "content-releases.content-manager-edit-view.edit-entry",
445
514
  defaultMessage: "Edit entry"
@@ -449,6 +518,21 @@ const ReleaseActionEntryLinkItem = ({
449
518
  }
450
519
  );
451
520
  };
521
+ const EditReleaseItem = ({ releaseId }) => {
522
+ const { formatMessage } = reactIntl.useIntl();
523
+ return /* @__PURE__ */ jsxRuntime.jsx(StyledMenuItem, { children: /* @__PURE__ */ jsxRuntime.jsx(
524
+ v2.Link,
525
+ {
526
+ href: `/admin/plugins/content-releases/${releaseId}`,
527
+ startIcon: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Icon, { as: icons.Pencil, width: 3, height: 3 }),
528
+ isExternal: false,
529
+ children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "omega", children: formatMessage({
530
+ id: "content-releases.content-manager-edit-view.edit-release",
531
+ defaultMessage: "Edit release"
532
+ }) })
533
+ }
534
+ ) });
535
+ };
452
536
  const Root = ({ children, hasTriggerBorder = false }) => {
453
537
  const { formatMessage } = reactIntl.useIntl();
454
538
  return (
@@ -473,6 +557,7 @@ const Root = ({ children, hasTriggerBorder = false }) => {
473
557
  };
474
558
  const ReleaseActionMenu = {
475
559
  Root,
560
+ EditReleaseItem,
476
561
  DeleteReleaseActionItem,
477
562
  ReleaseActionEntryLinkItem
478
563
  };
@@ -496,19 +581,40 @@ const FieldWrapper = styled__default.default(designSystem.Field)`
496
581
  text-transform: capitalize;
497
582
  }
498
583
 
499
- &:active,
500
584
  &[data-checked='true'] {
501
- color: ${({ theme }) => theme.colors.primary700};
502
- background-color: ${({ theme }) => theme.colors.primary100};
503
- border-color: ${({ theme }) => theme.colors.primary700};
585
+ color: ${({ theme, actionType }) => actionType === "publish" ? theme.colors.primary700 : theme.colors.danger600};
586
+ background-color: ${({ theme, actionType }) => actionType === "publish" ? theme.colors.primary100 : theme.colors.danger100};
587
+ border-color: ${({ theme, actionType }) => actionType === "publish" ? theme.colors.primary700 : theme.colors.danger600};
504
588
  }
505
589
 
506
590
  &[data-checked='false'] {
507
591
  border-left: ${({ actionType }) => actionType === "unpublish" && "none"};
508
592
  border-right: ${({ actionType }) => actionType === "publish" && "none"};
509
593
  }
594
+
595
+ &[data-checked='false'][data-disabled='false']:hover {
596
+ color: ${({ theme }) => theme.colors.neutral700};
597
+ background-color: ${({ theme }) => theme.colors.neutral100};
598
+ border-color: ${({ theme }) => theme.colors.neutral200};
599
+
600
+ & > label {
601
+ cursor: pointer;
602
+ }
603
+ }
604
+
605
+ &[data-disabled='true'] {
606
+ color: ${({ theme }) => theme.colors.neutral600};
607
+ background-color: ${({ theme }) => theme.colors.neutral150};
608
+ border-color: ${({ theme }) => theme.colors.neutral300};
609
+ }
510
610
  `;
511
- const ActionOption = ({ selected, actionType, handleChange, name }) => {
611
+ const ActionOption = ({
612
+ selected,
613
+ actionType,
614
+ handleChange,
615
+ name,
616
+ disabled = false
617
+ }) => {
512
618
  return /* @__PURE__ */ jsxRuntime.jsx(
513
619
  FieldWrapper,
514
620
  {
@@ -519,6 +625,7 @@ const ActionOption = ({ selected, actionType, handleChange, name }) => {
519
625
  position: "relative",
520
626
  cursor: "pointer",
521
627
  "data-checked": selected === actionType,
628
+ "data-disabled": disabled && selected !== actionType,
522
629
  children: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.FieldLabel, { htmlFor: `${name}-${actionType}`, children: [
523
630
  /* @__PURE__ */ jsxRuntime.jsx(designSystem.VisuallyHidden, { children: /* @__PURE__ */ jsxRuntime.jsx(
524
631
  designSystem.FieldInput,
@@ -528,7 +635,8 @@ const ActionOption = ({ selected, actionType, handleChange, name }) => {
528
635
  name,
529
636
  checked: selected === actionType,
530
637
  onChange: handleChange,
531
- value: actionType
638
+ value: actionType,
639
+ disabled
532
640
  }
533
641
  ) }),
534
642
  actionType
@@ -536,7 +644,12 @@ const ActionOption = ({ selected, actionType, handleChange, name }) => {
536
644
  }
537
645
  );
538
646
  };
539
- const ReleaseActionOptions = ({ selected, handleChange, name }) => {
647
+ const ReleaseActionOptions = ({
648
+ selected,
649
+ handleChange,
650
+ name,
651
+ disabled = false
652
+ }) => {
540
653
  return /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { children: [
541
654
  /* @__PURE__ */ jsxRuntime.jsx(
542
655
  ActionOption,
@@ -544,7 +657,8 @@ const ReleaseActionOptions = ({ selected, handleChange, name }) => {
544
657
  actionType: "publish",
545
658
  selected,
546
659
  handleChange,
547
- name
660
+ name,
661
+ disabled
548
662
  }
549
663
  ),
550
664
  /* @__PURE__ */ jsxRuntime.jsx(
@@ -553,7 +667,8 @@ const ReleaseActionOptions = ({ selected, handleChange, name }) => {
553
667
  actionType: "unpublish",
554
668
  selected,
555
669
  handleChange,
556
- name
670
+ name,
671
+ disabled
557
672
  }
558
673
  )
559
674
  ] });
@@ -597,6 +712,7 @@ const AddActionToReleaseModal = ({
597
712
  contentTypeUid,
598
713
  entryId
599
714
  }) => {
715
+ const releaseHeaderId = React__namespace.useId();
600
716
  const { formatMessage } = reactIntl.useIntl();
601
717
  const toggleNotification = helperPlugin.useNotification();
602
718
  const { formatAPIError } = helperPlugin.useAPIErrorHandler();
@@ -644,8 +760,8 @@ const AddActionToReleaseModal = ({
644
760
  }
645
761
  }
646
762
  };
647
- return /* @__PURE__ */ jsxRuntime.jsxs(designSystem.ModalLayout, { onClose: handleClose, labelledBy: "title", children: [
648
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.ModalHeader, { children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { id: "title", fontWeight: "bold", textColor: "neutral800", children: formatMessage({
763
+ return /* @__PURE__ */ jsxRuntime.jsxs(designSystem.ModalLayout, { onClose: handleClose, labelledBy: releaseHeaderId, children: [
764
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.ModalHeader, { children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { id: releaseHeaderId, fontWeight: "bold", textColor: "neutral800", children: formatMessage({
649
765
  id: "content-releases.content-manager-edit-view.add-to-release",
650
766
  defaultMessage: "Add to release"
651
767
  }) }) }),
@@ -715,16 +831,18 @@ const AddActionToReleaseModal = ({
715
831
  };
716
832
  const CMReleasesContainer = () => {
717
833
  const [isModalOpen, setIsModalOpen] = React__namespace.useState(false);
718
- const { formatMessage } = reactIntl.useIntl();
834
+ const { formatMessage, formatDate, formatTime } = reactIntl.useIntl();
719
835
  const {
720
836
  isCreatingEntry,
721
- allLayoutData: { contentType }
837
+ hasDraftAndPublish,
838
+ initialData: { id: entryId },
839
+ slug
722
840
  } = helperPlugin.useCMEditViewDataManager();
723
- const params = reactRouterDom.useParams();
724
- const canFetch = params?.id != null && contentType?.uid != null;
841
+ const contentTypeUid = slug;
842
+ const canFetch = entryId != null && contentTypeUid != null;
725
843
  const fetchParams = canFetch ? {
726
- contentTypeUid: contentType.uid,
727
- entryId: params.id,
844
+ contentTypeUid,
845
+ entryId,
728
846
  hasEntryAttached: true
729
847
  } : query.skipToken;
730
848
  const response = useGetReleasesForEntryQuery(fetchParams);
@@ -732,7 +850,7 @@ const CMReleasesContainer = () => {
732
850
  if (!canFetch) {
733
851
  return null;
734
852
  }
735
- if (isCreatingEntry || !contentType?.options?.draftAndPublish) {
853
+ if (isCreatingEntry || !hasDraftAndPublish) {
736
854
  return null;
737
855
  }
738
856
  const toggleModal = () => setIsModalOpen((prev) => !prev);
@@ -769,7 +887,7 @@ const CMReleasesContainer = () => {
769
887
  alignItems: "start",
770
888
  borderWidth: "1px",
771
889
  borderStyle: "solid",
772
- borderColor: getReleaseColorVariant(release.action.type, "200"),
890
+ borderColor: getReleaseColorVariant(release.actions[0].type, "200"),
773
891
  overflow: "hidden",
774
892
  hasRadius: true,
775
893
  children: [
@@ -780,34 +898,59 @@ const CMReleasesContainer = () => {
780
898
  paddingBottom: 3,
781
899
  paddingLeft: 4,
782
900
  paddingRight: 4,
783
- background: getReleaseColorVariant(release.action.type, "100"),
901
+ background: getReleaseColorVariant(release.actions[0].type, "100"),
784
902
  width: "100%",
785
903
  children: /* @__PURE__ */ jsxRuntime.jsx(
786
904
  designSystem.Typography,
787
905
  {
788
906
  fontSize: 1,
789
907
  variant: "pi",
790
- textColor: getReleaseColorVariant(release.action.type, "600"),
908
+ textColor: getReleaseColorVariant(release.actions[0].type, "600"),
791
909
  children: formatMessage(
792
910
  {
793
911
  id: "content-releases.content-manager-edit-view.list-releases.title",
794
912
  defaultMessage: "{isPublish, select, true {Will be published in} other {Will be unpublished in}}"
795
913
  },
796
- { isPublish: release.action.type === "publish" }
914
+ { isPublish: release.actions[0].type === "publish" }
797
915
  )
798
916
  }
799
917
  )
800
918
  }
801
919
  ),
802
- /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { padding: 4, direction: "column", gap: 3, width: "100%", alignItems: "flex-start", children: [
920
+ /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { padding: 4, direction: "column", gap: 2, width: "100%", alignItems: "flex-start", children: [
803
921
  /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { fontSize: 2, fontWeight: "bold", variant: "omega", textColor: "neutral700", children: release.name }),
804
- /* @__PURE__ */ jsxRuntime.jsx(helperPlugin.CheckPermissions, { permissions: PERMISSIONS.deleteAction, children: /* @__PURE__ */ jsxRuntime.jsx(ReleaseActionMenu.Root, { hasTriggerBorder: true, children: /* @__PURE__ */ jsxRuntime.jsx(
805
- ReleaseActionMenu.DeleteReleaseActionItem,
922
+ release.scheduledAt && release.timezone && /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "pi", textColor: "neutral600", children: formatMessage(
806
923
  {
807
- releaseId: release.id,
808
- actionId: release.action.id
924
+ id: "content-releases.content-manager-edit-view.scheduled.date",
925
+ defaultMessage: "{date} at {time} ({offset})"
926
+ },
927
+ {
928
+ date: formatDate(new Date(release.scheduledAt), {
929
+ day: "2-digit",
930
+ month: "2-digit",
931
+ year: "numeric",
932
+ timeZone: release.timezone
933
+ }),
934
+ time: formatTime(new Date(release.scheduledAt), {
935
+ hourCycle: "h23",
936
+ timeZone: release.timezone
937
+ }),
938
+ offset: getTimezoneOffset(
939
+ release.timezone,
940
+ new Date(release.scheduledAt)
941
+ )
809
942
  }
810
- ) }) })
943
+ ) }),
944
+ /* @__PURE__ */ jsxRuntime.jsx(helperPlugin.CheckPermissions, { permissions: PERMISSIONS.deleteAction, children: /* @__PURE__ */ jsxRuntime.jsxs(ReleaseActionMenu.Root, { hasTriggerBorder: true, children: [
945
+ /* @__PURE__ */ jsxRuntime.jsx(ReleaseActionMenu.EditReleaseItem, { releaseId: release.id }),
946
+ /* @__PURE__ */ jsxRuntime.jsx(
947
+ ReleaseActionMenu.DeleteReleaseActionItem,
948
+ {
949
+ releaseId: release.id,
950
+ actionId: release.actions[0].id
951
+ }
952
+ )
953
+ ] }) })
811
954
  ] })
812
955
  ]
813
956
  },
@@ -835,17 +978,280 @@ const CMReleasesContainer = () => {
835
978
  AddActionToReleaseModal,
836
979
  {
837
980
  handleClose: toggleModal,
838
- contentTypeUid: contentType.uid,
839
- entryId: params.id
981
+ contentTypeUid,
982
+ entryId
840
983
  }
841
984
  )
842
985
  ]
843
986
  }
844
987
  ) });
845
988
  };
989
+ const getContentPermissions = (subject) => {
990
+ const permissions = {
991
+ publish: [
992
+ {
993
+ action: "plugin::content-manager.explorer.publish",
994
+ subject,
995
+ id: "",
996
+ actionParameters: {},
997
+ properties: {},
998
+ conditions: []
999
+ }
1000
+ ]
1001
+ };
1002
+ return permissions;
1003
+ };
1004
+ const ReleaseAction = ({ ids, model }) => {
1005
+ const { formatMessage } = reactIntl.useIntl();
1006
+ const toggleNotification = helperPlugin.useNotification();
1007
+ const { formatAPIError } = helperPlugin.useAPIErrorHandler();
1008
+ const { modifiedData } = helperPlugin.useCMEditViewDataManager();
1009
+ const contentPermissions = getContentPermissions(model);
1010
+ const {
1011
+ allowedActions: { canPublish }
1012
+ } = helperPlugin.useRBAC(contentPermissions);
1013
+ const {
1014
+ allowedActions: { canCreate }
1015
+ } = helperPlugin.useRBAC(PERMISSIONS);
1016
+ const response = useGetReleasesQuery();
1017
+ const releases = response.data?.data;
1018
+ const [createManyReleaseActions, { isLoading }] = useCreateManyReleaseActionsMutation();
1019
+ const handleSubmit = async (values) => {
1020
+ const locale = modifiedData.locale;
1021
+ const releaseActionEntries = ids.map((id) => ({
1022
+ type: values.type,
1023
+ entry: {
1024
+ contentType: model,
1025
+ id,
1026
+ locale
1027
+ }
1028
+ }));
1029
+ const response2 = await createManyReleaseActions({
1030
+ body: releaseActionEntries,
1031
+ params: { releaseId: values.releaseId }
1032
+ });
1033
+ if ("data" in response2) {
1034
+ const notificationMessage = formatMessage(
1035
+ {
1036
+ id: "content-releases.content-manager-list-view.add-to-release.notification.success.message",
1037
+ defaultMessage: "{entriesAlreadyInRelease} out of {totalEntries} entries were already in the release."
1038
+ },
1039
+ {
1040
+ entriesAlreadyInRelease: response2.data.meta.entriesAlreadyInRelease,
1041
+ totalEntries: response2.data.meta.totalEntries
1042
+ }
1043
+ );
1044
+ const notification = {
1045
+ type: "success",
1046
+ title: formatMessage(
1047
+ {
1048
+ id: "content-releases.content-manager-list-view.add-to-release.notification.success.title",
1049
+ defaultMessage: "Successfully added to release."
1050
+ },
1051
+ {
1052
+ entriesAlreadyInRelease: response2.data.meta.entriesAlreadyInRelease,
1053
+ totalEntries: response2.data.meta.totalEntries
1054
+ }
1055
+ ),
1056
+ message: response2.data.meta.entriesAlreadyInRelease ? notificationMessage : ""
1057
+ };
1058
+ toggleNotification(notification);
1059
+ return true;
1060
+ }
1061
+ if ("error" in response2) {
1062
+ if (axios.isAxiosError(response2.error)) {
1063
+ toggleNotification({
1064
+ type: "warning",
1065
+ message: formatAPIError(response2.error)
1066
+ });
1067
+ } else {
1068
+ toggleNotification({
1069
+ type: "warning",
1070
+ message: formatMessage({ id: "notification.error", defaultMessage: "An error occurred" })
1071
+ });
1072
+ }
1073
+ }
1074
+ };
1075
+ if (!canCreate || !canPublish)
1076
+ return null;
1077
+ return {
1078
+ actionType: "release",
1079
+ variant: "tertiary",
1080
+ label: formatMessage({
1081
+ id: "content-manager-list-view.add-to-release",
1082
+ defaultMessage: "Add to Release"
1083
+ }),
1084
+ dialog: {
1085
+ type: "modal",
1086
+ title: formatMessage({
1087
+ id: "content-manager-list-view.add-to-release",
1088
+ defaultMessage: "Add to Release"
1089
+ }),
1090
+ content: ({ onClose }) => {
1091
+ return /* @__PURE__ */ jsxRuntime.jsx(
1092
+ formik.Formik,
1093
+ {
1094
+ onSubmit: async (values) => {
1095
+ const data = await handleSubmit(values);
1096
+ if (data) {
1097
+ return onClose();
1098
+ }
1099
+ },
1100
+ validationSchema: RELEASE_ACTION_FORM_SCHEMA,
1101
+ initialValues: INITIAL_VALUES,
1102
+ children: ({ values, setFieldValue }) => /* @__PURE__ */ jsxRuntime.jsxs(formik.Form, { children: [
1103
+ releases?.length === 0 ? /* @__PURE__ */ jsxRuntime.jsx(NoReleases, {}) : /* @__PURE__ */ jsxRuntime.jsx(designSystem.ModalBody, { children: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { direction: "column", alignItems: "stretch", gap: 2, children: [
1104
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Box, { paddingBottom: 6, children: /* @__PURE__ */ jsxRuntime.jsx(
1105
+ designSystem.SingleSelect,
1106
+ {
1107
+ required: true,
1108
+ label: formatMessage({
1109
+ id: "content-releases.content-manager-list-view.add-to-release.select-label",
1110
+ defaultMessage: "Select a release"
1111
+ }),
1112
+ placeholder: formatMessage({
1113
+ id: "content-releases.content-manager-list-view.add-to-release.select-placeholder",
1114
+ defaultMessage: "Select"
1115
+ }),
1116
+ onChange: (value) => setFieldValue("releaseId", value),
1117
+ value: values.releaseId,
1118
+ children: releases?.map((release) => /* @__PURE__ */ jsxRuntime.jsx(designSystem.SingleSelectOption, { value: release.id, children: release.name }, release.id))
1119
+ }
1120
+ ) }),
1121
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.FieldLabel, { children: formatMessage({
1122
+ id: "content-releases.content-manager-list-view.add-to-release.action-type-label",
1123
+ defaultMessage: "What do you want to do with these entries?"
1124
+ }) }),
1125
+ /* @__PURE__ */ jsxRuntime.jsx(
1126
+ ReleaseActionOptions,
1127
+ {
1128
+ selected: values.type,
1129
+ handleChange: (e) => setFieldValue("type", e.target.value),
1130
+ name: "type"
1131
+ }
1132
+ )
1133
+ ] }) }),
1134
+ /* @__PURE__ */ jsxRuntime.jsx(
1135
+ designSystem.ModalFooter,
1136
+ {
1137
+ startActions: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Button, { onClick: onClose, variant: "tertiary", name: "cancel", children: formatMessage({
1138
+ id: "content-releases.content-manager-list-view.add-to-release.cancel-button",
1139
+ defaultMessage: "Cancel"
1140
+ }) }),
1141
+ endActions: (
1142
+ /**
1143
+ * TODO: Ideally we would use isValid from Formik to disable the button, however currently it always returns true
1144
+ * for yup.string().required(), even when the value is falsy (including empty string)
1145
+ */
1146
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Button, { type: "submit", disabled: !values.releaseId, loading: isLoading, children: formatMessage({
1147
+ id: "content-releases.content-manager-list-view.add-to-release.continue-button",
1148
+ defaultMessage: "Continue"
1149
+ }) })
1150
+ )
1151
+ }
1152
+ )
1153
+ ] })
1154
+ }
1155
+ );
1156
+ }
1157
+ }
1158
+ };
1159
+ };
1160
+ const Button = styled__default.default.button`
1161
+ svg {
1162
+ > g,
1163
+ path {
1164
+ fill: ${({ theme }) => theme.colors.neutral500};
1165
+ }
1166
+ }
1167
+ &:hover {
1168
+ svg {
1169
+ > g,
1170
+ path {
1171
+ fill: ${({ theme }) => theme.colors.neutral600};
1172
+ }
1173
+ }
1174
+ }
1175
+ &:active {
1176
+ svg {
1177
+ > g,
1178
+ path {
1179
+ fill: ${({ theme }) => theme.colors.neutral400};
1180
+ }
1181
+ }
1182
+ }
1183
+ `;
1184
+ const ActionWrapper = styled__default.default(designSystem.Flex)`
1185
+ svg {
1186
+ height: ${4 / 16}rem;
1187
+ }
1188
+ `;
1189
+ const useReleasesList = (entryId) => {
1190
+ const { uid: contentTypeUid } = useTypedSelector(
1191
+ (state) => state["content-manager_listView"].contentType
1192
+ );
1193
+ const listViewData = useTypedSelector((state) => state["content-manager_listView"].data);
1194
+ const entriesIds = listViewData.map((entry) => entry.id);
1195
+ const response = useGetMappedEntriesInReleasesQuery(
1196
+ { contentTypeUid, entriesIds },
1197
+ { skip: !entriesIds || !contentTypeUid || entriesIds.length === 0 }
1198
+ );
1199
+ const mappedEntriesInReleases = response.data || {};
1200
+ return mappedEntriesInReleases?.[entryId] || [];
1201
+ };
1202
+ const addColumnToTableHook = ({ displayedHeaders, layout }) => {
1203
+ const { contentType } = layout;
1204
+ if (!contentType.options?.draftAndPublish) {
1205
+ return { displayedHeaders, layout };
1206
+ }
1207
+ return {
1208
+ displayedHeaders: [
1209
+ ...displayedHeaders,
1210
+ {
1211
+ key: "__release_key__",
1212
+ fieldSchema: { type: "string" },
1213
+ metadatas: { label: "To be released in", searchable: true, sortable: false },
1214
+ name: "releasedAt",
1215
+ cellFormatter: (props) => /* @__PURE__ */ jsxRuntime.jsx(ReleaseListCell, { ...props })
1216
+ }
1217
+ ],
1218
+ layout
1219
+ };
1220
+ };
1221
+ const ReleaseListCell = ({ id }) => {
1222
+ const releases = useReleasesList(id);
1223
+ const [visible, setVisible] = React__namespace.useState(false);
1224
+ const buttonRef = React__namespace.useRef(null);
1225
+ const { formatMessage } = reactIntl.useIntl();
1226
+ const handleTogglePopover = () => setVisible((prev) => !prev);
1227
+ return /* @__PURE__ */ jsxRuntime.jsx(designSystem.Flex, { onClick: (e) => e.stopPropagation(), children: /* @__PURE__ */ jsxRuntime.jsx(Button, { type: "button", onClick: handleTogglePopover, ref: buttonRef, children: /* @__PURE__ */ jsxRuntime.jsxs(ActionWrapper, { height: "2rem", width: "2rem", children: [
1228
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { style: { maxWidth: "252px", cursor: "pointer" }, textColor: "neutral800", children: releases.length > 0 ? formatMessage(
1229
+ {
1230
+ id: "content-releases.content-manager.list-view.releases-number",
1231
+ defaultMessage: "{number} {number, plural, one {release} other {releases}}"
1232
+ },
1233
+ {
1234
+ number: releases.length
1235
+ }
1236
+ ) : "-" }),
1237
+ /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { children: [
1238
+ releases.length > 0 && /* @__PURE__ */ jsxRuntime.jsx(helperPlugin.SortIcon, {}),
1239
+ visible && /* @__PURE__ */ jsxRuntime.jsx(
1240
+ designSystem.Popover,
1241
+ {
1242
+ onDismiss: handleTogglePopover,
1243
+ source: buttonRef,
1244
+ spacing: 16,
1245
+ children: /* @__PURE__ */ jsxRuntime.jsx("ul", { children: releases.map(({ id: id2, name }) => /* @__PURE__ */ jsxRuntime.jsx(designSystem.Box, { padding: 3, as: "li", children: /* @__PURE__ */ jsxRuntime.jsx(v2.Link, { href: `/admin/plugins/content-releases/${id2}`, isExternal: false, children: name }) }, id2)) })
1246
+ }
1247
+ )
1248
+ ] })
1249
+ ] }) }) });
1250
+ };
846
1251
  const admin = {
847
1252
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
848
1253
  register(app) {
1254
+ app.createHook("ContentReleases/pages/ReleaseDetails/add-locale-in-releases");
849
1255
  if (window.strapi.features.isEnabled("cms-content-releases")) {
850
1256
  app.addMenuLink({
851
1257
  to: `/plugins/${pluginId}`,
@@ -855,7 +1261,7 @@ const admin = {
855
1261
  defaultMessage: "Releases"
856
1262
  },
857
1263
  async Component() {
858
- const { App } = await Promise.resolve().then(() => require("./App-_20W9dYa.js"));
1264
+ const { App } = await Promise.resolve().then(() => require("./App-dLXY5ei3.js"));
859
1265
  return App;
860
1266
  },
861
1267
  permissions: PERMISSIONS.main
@@ -868,12 +1274,33 @@ const admin = {
868
1274
  name: `${pluginId}-link`,
869
1275
  Component: CMReleasesContainer
870
1276
  });
1277
+ app.plugins["content-manager"].apis.addBulkAction((actions) => {
1278
+ const deleteActionIndex = actions.findIndex((action) => action.name === "DeleteAction");
1279
+ actions.splice(deleteActionIndex, 0, ReleaseAction);
1280
+ return actions;
1281
+ });
1282
+ app.registerHook("Admin/CM/pages/ListView/inject-column-in-table", addColumnToTableHook);
1283
+ } else if (!window.strapi.features.isEnabled("cms-content-releases") && window.strapi?.flags?.promoteEE) {
1284
+ app.addMenuLink({
1285
+ to: `/plugins/purchase-content-releases`,
1286
+ icon: icons.PaperPlane,
1287
+ intlLabel: {
1288
+ id: `${pluginId}.plugin.name`,
1289
+ defaultMessage: "Releases"
1290
+ },
1291
+ async Component() {
1292
+ const { PurchaseContentReleases } = await Promise.resolve().then(() => require("./PurchaseContentReleases-bpIYXOfu.js"));
1293
+ return PurchaseContentReleases;
1294
+ },
1295
+ lockIcon: true
1296
+ // TODO: to replace with another name in v5
1297
+ });
871
1298
  }
872
1299
  },
873
1300
  async registerTrads({ locales }) {
874
1301
  const importedTrads = await Promise.all(
875
1302
  locales.map((locale) => {
876
- return __variableDynamicImportRuntimeHelper(/* @__PURE__ */ Object.assign({ "./translations/en.json": () => Promise.resolve().then(() => require("./en-gYDqKYFd.js")) }), `./translations/${locale}.json`).then(({ default: data }) => {
1303
+ return __variableDynamicImportRuntimeHelper(/* @__PURE__ */ Object.assign({ "./translations/en.json": () => Promise.resolve().then(() => require("./en-HrREghh3.js")) }), `./translations/${locale}.json`).then(({ default: data }) => {
877
1304
  return {
878
1305
  data: helperPlugin.prefixPluginTranslations(data, "content-releases"),
879
1306
  locale
@@ -893,6 +1320,7 @@ exports.PERMISSIONS = PERMISSIONS;
893
1320
  exports.ReleaseActionMenu = ReleaseActionMenu;
894
1321
  exports.ReleaseActionOptions = ReleaseActionOptions;
895
1322
  exports.admin = admin;
1323
+ exports.getTimezoneOffset = getTimezoneOffset;
896
1324
  exports.isAxiosError = isAxiosError;
897
1325
  exports.pluginId = pluginId;
898
1326
  exports.releaseApi = releaseApi;
@@ -905,4 +1333,4 @@ exports.usePublishReleaseMutation = usePublishReleaseMutation;
905
1333
  exports.useTypedDispatch = useTypedDispatch;
906
1334
  exports.useUpdateReleaseActionMutation = useUpdateReleaseActionMutation;
907
1335
  exports.useUpdateReleaseMutation = useUpdateReleaseMutation;
908
- //# sourceMappingURL=index-KJa1Rb5F.js.map
1336
+ //# sourceMappingURL=index-CVO0Rqdm.js.map