@strapi/content-releases 0.0.0-next.56199ab7a5f3320e0debcbe4a24fe0b8cd599e21 → 0.0.0-next.6d384ed205b7f0792d9bea79195f01b30463cfa0

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.
@@ -3,7 +3,7 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
3
3
  const jsxRuntime = require("react/jsx-runtime");
4
4
  const helperPlugin = require("@strapi/helper-plugin");
5
5
  const reactRouterDom = require("react-router-dom");
6
- const index = require("./index-vxli-E-l.js");
6
+ const index = require("./index-u_da7WHb.js");
7
7
  const React = require("react");
8
8
  const strapiAdmin = require("@strapi/admin/strapi-admin");
9
9
  const designSystem = require("@strapi/design-system");
@@ -40,7 +40,9 @@ const React__namespace = /* @__PURE__ */ _interopNamespace(React);
40
40
  const styled__default = /* @__PURE__ */ _interopDefault(styled);
41
41
  const yup__namespace = /* @__PURE__ */ _interopNamespace(yup);
42
42
  const RELEASE_SCHEMA = yup__namespace.object().shape({
43
- name: yup__namespace.string().trim().required()
43
+ name: yup__namespace.string().trim().required(),
44
+ // scheduledAt is a date, but we always receive strings from the client
45
+ scheduledAt: yup__namespace.string()
44
46
  }).required().noUnknown();
45
47
  const ReleaseModal = ({
46
48
  handleClose,
@@ -126,15 +128,15 @@ const StyledFlex = styled__default.default(designSystem.Flex)`
126
128
  }
127
129
  `;
128
130
  const PencilIcon = styled__default.default(icons.Pencil)`
129
- width: ${({ theme }) => theme.spaces[4]};
130
- height: ${({ theme }) => theme.spaces[4]};
131
+ width: ${({ theme }) => theme.spaces[3]};
132
+ height: ${({ theme }) => theme.spaces[3]};
131
133
  path {
132
134
  fill: ${({ theme }) => theme.colors.neutral600};
133
135
  }
134
136
  `;
135
137
  const TrashIcon = styled__default.default(icons.Trash)`
136
- width: ${({ theme }) => theme.spaces[4]};
137
- height: ${({ theme }) => theme.spaces[4]};
138
+ width: ${({ theme }) => theme.spaces[3]};
139
+ height: ${({ theme }) => theme.spaces[3]};
138
140
  path {
139
141
  fill: ${({ theme }) => theme.colors.danger600};
140
142
  }
@@ -225,6 +227,7 @@ const ReleaseDetailsLayout = ({
225
227
  allowedActions: { canUpdate, canDelete }
226
228
  } = helperPlugin.useRBAC(index.PERMISSIONS);
227
229
  const dispatch = index.useTypedDispatch();
230
+ const { trackUsage } = helperPlugin.useTracking();
228
231
  const release = data?.data;
229
232
  const handleTogglePopover = () => {
230
233
  setIsPopoverVisible((prev) => !prev);
@@ -243,6 +246,12 @@ const ReleaseDetailsLayout = ({
243
246
  defaultMessage: "Release was published successfully."
244
247
  })
245
248
  });
249
+ const { totalEntries: totalEntries2, totalPublishedEntries, totalUnpublishedEntries } = response.data.meta;
250
+ trackUsage("didPublishRelease", {
251
+ totalEntries: totalEntries2,
252
+ totalPublishedEntries,
253
+ totalUnpublishedEntries
254
+ });
246
255
  } else if (index.isAxiosError(response.error)) {
247
256
  toggleNotification({
248
257
  type: "warning",
@@ -262,6 +271,18 @@ const ReleaseDetailsLayout = ({
262
271
  const handleRefresh = () => {
263
272
  dispatch(index.releaseApi.util.invalidateTags([{ type: "ReleaseAction", id: "LIST" }]));
264
273
  };
274
+ const getCreatedByUser = () => {
275
+ if (!release?.createdBy) {
276
+ return null;
277
+ }
278
+ if (release.createdBy.username) {
279
+ return release.createdBy.username;
280
+ }
281
+ if (release.createdBy.firstname) {
282
+ return `${release.createdBy.firstname} ${release.createdBy.lastname || ""}`.trim();
283
+ }
284
+ return release.createdBy.email;
285
+ };
265
286
  if (isLoadingDetails) {
266
287
  return /* @__PURE__ */ jsxRuntime.jsx(designSystem.Main, { "aria-busy": isLoadingDetails, children: /* @__PURE__ */ jsxRuntime.jsx(helperPlugin.LoadingIndicatorPage, {}) });
267
288
  }
@@ -283,7 +304,7 @@ const ReleaseDetailsLayout = ({
283
304
  );
284
305
  }
285
306
  const totalEntries = release.actions.meta.count || 0;
286
- const createdBy = release.createdBy.lastname ? `${release.createdBy.firstname} ${release.createdBy.lastname}` : `${release.createdBy.firstname}`;
307
+ const hasCreatedByUser = Boolean(getCreatedByUser());
287
308
  return /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Main, { "aria-busy": isLoadingDetails, children: [
288
309
  /* @__PURE__ */ jsxRuntime.jsx(
289
310
  designSystem.HeaderLayout,
@@ -306,7 +327,7 @@ const ReleaseDetailsLayout = ({
306
327
  {
307
328
  label: formatMessage({
308
329
  id: "content-releases.header.actions.open-release-actions",
309
- defaultMessage: "Release actions"
330
+ defaultMessage: "Release edit and delete menu"
310
331
  }),
311
332
  ref: moreButtonRef,
312
333
  onClick: handleTogglePopover,
@@ -356,9 +377,9 @@ const ReleaseDetailsLayout = ({
356
377
  formatMessage(
357
378
  {
358
379
  id: "content-releases.header.actions.created.description",
359
- defaultMessage: " by {createdBy}"
380
+ defaultMessage: "{hasCreatedByUser, select, true { by {createdBy}} other { by deleted user}}"
360
381
  },
361
- { createdBy }
382
+ { createdBy: getCreatedByUser(), hasCreatedByUser }
362
383
  )
363
384
  ] })
364
385
  ]
@@ -435,7 +456,7 @@ const ReleaseDetailsBody = () => {
435
456
  releaseId
436
457
  });
437
458
  const [updateReleaseAction] = index.useUpdateReleaseActionMutation();
438
- const handleChangeType = async (e, actionId) => {
459
+ const handleChangeType = async (e, actionId, actionPath) => {
439
460
  const response = await updateReleaseAction({
440
461
  params: {
441
462
  releaseId,
@@ -443,7 +464,11 @@ const ReleaseDetailsBody = () => {
443
464
  },
444
465
  body: {
445
466
  type: e.target.value
446
- }
467
+ },
468
+ query,
469
+ // We are passing the query params to make optimistic updates
470
+ actionPath
471
+ // We are passing the action path to found the position in the cache of the action for optimistic updates
447
472
  });
448
473
  if ("error" in response) {
449
474
  if (index.isAxiosError(response.error)) {
@@ -524,7 +549,7 @@ const ReleaseDetailsBody = () => {
524
549
  designSystem.SingleSelect,
525
550
  {
526
551
  "aria-label": formatMessage({
527
- id: "content-releases.pages.ReleaseDetails.groupBy.label",
552
+ id: "content-releases.pages.ReleaseDetails.groupBy.aria-label",
528
553
  defaultMessage: "Group by"
529
554
  }),
530
555
  customizeContent: (value) => formatMessage(
@@ -542,7 +567,7 @@ const ReleaseDetailsBody = () => {
542
567
  }
543
568
  ) }),
544
569
  Object.keys(releaseActions).map((key) => /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { gap: 4, direction: "column", alignItems: "stretch", children: [
545
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Flex, { children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Badge, { children: key }) }),
570
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Flex, { role: "separator", "aria-label": key, children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Badge, { children: key }) }),
546
571
  /* @__PURE__ */ jsxRuntime.jsx(
547
572
  helperPlugin.Table.Root,
548
573
  {
@@ -612,56 +637,58 @@ const ReleaseDetailsBody = () => {
612
637
  )
613
638
  ] }),
614
639
  /* @__PURE__ */ jsxRuntime.jsx(helperPlugin.Table.LoadingBody, {}),
615
- /* @__PURE__ */ jsxRuntime.jsx(helperPlugin.Table.Body, { children: releaseActions[key].map(({ id, contentType, locale, type, entry }) => /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Tr, { children: [
616
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Td, { width: "25%", maxWidth: "200px", children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { ellipsis: true, children: `${contentType.mainFieldValue || entry.id}` }) }),
617
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Td, { width: "10%", children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { children: `${locale?.name ? locale.name : "-"}` }) }),
618
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Td, { width: "10%", children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { children: contentType.displayName || "" }) }),
619
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Td, { width: "20%", children: release.releasedAt ? /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { children: formatMessage(
620
- {
621
- id: "content-releases.page.ReleaseDetails.table.action-published",
622
- defaultMessage: "This entry was <b>{isPublish, select, true {published} other {unpublished}}</b>."
623
- },
624
- {
625
- isPublish: type === "publish",
626
- b: (children) => /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { fontWeight: "bold", children })
627
- }
628
- ) }) : /* @__PURE__ */ jsxRuntime.jsx(
629
- index.ReleaseActionOptions,
630
- {
631
- selected: type,
632
- handleChange: (e) => handleChangeType(e, id),
633
- name: `release-action-${id}-type`
634
- }
635
- ) }),
636
- !release.releasedAt && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
637
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Td, { width: "20%", minWidth: "200px", children: /* @__PURE__ */ jsxRuntime.jsx(
638
- EntryValidationText,
640
+ /* @__PURE__ */ jsxRuntime.jsx(helperPlugin.Table.Body, { children: releaseActions[key].map(
641
+ ({ id, contentType, locale, type, entry }, actionIndex) => /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Tr, { children: [
642
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Td, { width: "25%", maxWidth: "200px", children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { ellipsis: true, children: `${contentType.mainFieldValue || entry.id}` }) }),
643
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Td, { width: "10%", children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { children: `${locale?.name ? locale.name : "-"}` }) }),
644
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Td, { width: "10%", children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { children: contentType.displayName || "" }) }),
645
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Td, { width: "20%", children: release.releasedAt ? /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { children: formatMessage(
639
646
  {
640
- action: type,
641
- schema: contentTypes?.[contentType.uid],
642
- components,
643
- entry
647
+ id: "content-releases.page.ReleaseDetails.table.action-published",
648
+ defaultMessage: "This entry was <b>{isPublish, select, true {published} other {unpublished}}</b>."
649
+ },
650
+ {
651
+ isPublish: type === "publish",
652
+ b: (children) => /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { fontWeight: "bold", children })
653
+ }
654
+ ) }) : /* @__PURE__ */ jsxRuntime.jsx(
655
+ index.ReleaseActionOptions,
656
+ {
657
+ selected: type,
658
+ handleChange: (e) => handleChangeType(e, id, [key, actionIndex]),
659
+ name: `release-action-${id}-type`
644
660
  }
645
661
  ) }),
646
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Td, { children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Flex, { justifyContent: "flex-end", children: /* @__PURE__ */ jsxRuntime.jsxs(index.ReleaseActionMenu.Root, { children: [
647
- /* @__PURE__ */ jsxRuntime.jsx(
648
- index.ReleaseActionMenu.ReleaseActionEntryLinkItem,
649
- {
650
- contentTypeUid: contentType.uid,
651
- entryId: entry.id,
652
- locale: locale?.code
653
- }
654
- ),
655
- /* @__PURE__ */ jsxRuntime.jsx(
656
- index.ReleaseActionMenu.DeleteReleaseActionItem,
662
+ !release.releasedAt && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
663
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Td, { width: "20%", minWidth: "200px", children: /* @__PURE__ */ jsxRuntime.jsx(
664
+ EntryValidationText,
657
665
  {
658
- releaseId: release.id,
659
- actionId: id
666
+ action: type,
667
+ schema: contentTypes?.[contentType.uid],
668
+ components,
669
+ entry
660
670
  }
661
- )
662
- ] }) }) })
663
- ] })
664
- ] }, id)) })
671
+ ) }),
672
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Td, { children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Flex, { justifyContent: "flex-end", children: /* @__PURE__ */ jsxRuntime.jsxs(index.ReleaseActionMenu.Root, { children: [
673
+ /* @__PURE__ */ jsxRuntime.jsx(
674
+ index.ReleaseActionMenu.ReleaseActionEntryLinkItem,
675
+ {
676
+ contentTypeUid: contentType.uid,
677
+ entryId: entry.id,
678
+ locale: locale?.code
679
+ }
680
+ ),
681
+ /* @__PURE__ */ jsxRuntime.jsx(
682
+ index.ReleaseActionMenu.DeleteReleaseActionItem,
683
+ {
684
+ releaseId: release.id,
685
+ actionId: id
686
+ }
687
+ )
688
+ ] }) }) })
689
+ ] })
690
+ ] }, id)
691
+ ) })
665
692
  ] })
666
693
  }
667
694
  )
@@ -786,37 +813,6 @@ const ReleaseDetailsPage = () => {
786
813
  }
787
814
  );
788
815
  };
789
- const ReleasesLayout = ({
790
- isLoading,
791
- totalReleases,
792
- onClickAddRelease,
793
- children
794
- }) => {
795
- const { formatMessage } = reactIntl.useIntl();
796
- return /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Main, { "aria-busy": isLoading, children: [
797
- /* @__PURE__ */ jsxRuntime.jsx(
798
- designSystem.HeaderLayout,
799
- {
800
- title: formatMessage({
801
- id: "content-releases.pages.Releases.title",
802
- defaultMessage: "Releases"
803
- }),
804
- subtitle: !isLoading && formatMessage(
805
- {
806
- id: "content-releases.pages.Releases.header-subtitle",
807
- defaultMessage: "{number, plural, =0 {No releases} one {# release} other {# releases}}"
808
- },
809
- { number: totalReleases }
810
- ),
811
- primaryAction: /* @__PURE__ */ jsxRuntime.jsx(helperPlugin.CheckPermissions, { permissions: index.PERMISSIONS.create, children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Button, { startIcon: /* @__PURE__ */ jsxRuntime.jsx(icons.Plus, {}), onClick: onClickAddRelease, children: formatMessage({
812
- id: "content-releases.header.actions.add-release",
813
- defaultMessage: "New release"
814
- }) }) })
815
- }
816
- ),
817
- children
818
- ] });
819
- };
820
816
  const LinkCard = styled__default.default(v2.Link)`
821
817
  display: block;
822
818
  `;
@@ -868,6 +864,14 @@ const ReleasesGrid = ({ sectionTitle, releases = [], isError = false }) => {
868
864
  }
869
865
  ) }) }, id)) });
870
866
  };
867
+ const StyledAlert = styled__default.default(designSystem.Alert)`
868
+ button {
869
+ display: none;
870
+ }
871
+ p + div {
872
+ margin-left: auto;
873
+ }
874
+ `;
871
875
  const INITIAL_FORM_VALUES = {
872
876
  name: ""
873
877
  };
@@ -882,6 +886,9 @@ const ReleasesPage = () => {
882
886
  const [{ query }, setQuery] = helperPlugin.useQueryParams();
883
887
  const response = index.useGetReleasesQuery(query);
884
888
  const [createRelease, { isLoading: isSubmittingForm }] = index.useCreateReleaseMutation();
889
+ const { getFeature } = strapiAdmin.useLicenseLimits();
890
+ const { maximumReleases = 3 } = getFeature("cms-content-releases");
891
+ const { trackUsage } = helperPlugin.useTracking();
885
892
  const { isLoading, isSuccess, isError } = response;
886
893
  const activeTab = response?.currentData?.meta?.activeTab || "pending";
887
894
  const activeTabIndex = ["pending", "done"].indexOf(activeTab);
@@ -910,9 +917,10 @@ const ReleasesPage = () => {
910
917
  setReleaseModalShown((prev) => !prev);
911
918
  };
912
919
  if (isLoading) {
913
- return /* @__PURE__ */ jsxRuntime.jsx(ReleasesLayout, { onClickAddRelease: toggleAddReleaseModal, isLoading: true, children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.ContentLayout, { children: /* @__PURE__ */ jsxRuntime.jsx(helperPlugin.LoadingIndicatorPage, {}) }) });
920
+ return /* @__PURE__ */ jsxRuntime.jsx(designSystem.Main, { "aria-busy": isLoading, children: /* @__PURE__ */ jsxRuntime.jsx(helperPlugin.LoadingIndicatorPage, {}) });
914
921
  }
915
922
  const totalReleases = isSuccess && response.currentData?.meta?.pagination?.total || 0;
923
+ const hasReachedMaximumPendingReleases = totalReleases >= maximumReleases;
916
924
  const handleTabChange = (index2) => {
917
925
  setQuery({
918
926
  ...query,
@@ -937,6 +945,7 @@ const ReleasesPage = () => {
937
945
  defaultMessage: "Release created."
938
946
  })
939
947
  });
948
+ trackUsage("didCreateRelease");
940
949
  push(`/plugins/content-releases/${response2.data.data.id}`);
941
950
  } else if (index.isAxiosError(response2.error)) {
942
951
  toggleNotification({
@@ -950,8 +959,60 @@ const ReleasesPage = () => {
950
959
  });
951
960
  }
952
961
  };
953
- return /* @__PURE__ */ jsxRuntime.jsxs(ReleasesLayout, { onClickAddRelease: toggleAddReleaseModal, totalReleases, children: [
962
+ return /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Main, { "aria-busy": isLoading, children: [
963
+ /* @__PURE__ */ jsxRuntime.jsx(
964
+ designSystem.HeaderLayout,
965
+ {
966
+ title: formatMessage({
967
+ id: "content-releases.pages.Releases.title",
968
+ defaultMessage: "Releases"
969
+ }),
970
+ subtitle: formatMessage(
971
+ {
972
+ id: "content-releases.pages.Releases.header-subtitle",
973
+ defaultMessage: "{number, plural, =0 {No releases} one {# release} other {# releases}}"
974
+ },
975
+ { number: totalReleases }
976
+ ),
977
+ primaryAction: /* @__PURE__ */ jsxRuntime.jsx(helperPlugin.CheckPermissions, { permissions: index.PERMISSIONS.create, children: /* @__PURE__ */ jsxRuntime.jsx(
978
+ designSystem.Button,
979
+ {
980
+ startIcon: /* @__PURE__ */ jsxRuntime.jsx(icons.Plus, {}),
981
+ onClick: toggleAddReleaseModal,
982
+ disabled: hasReachedMaximumPendingReleases,
983
+ children: formatMessage({
984
+ id: "content-releases.header.actions.add-release",
985
+ defaultMessage: "New release"
986
+ })
987
+ }
988
+ ) })
989
+ }
990
+ ),
954
991
  /* @__PURE__ */ jsxRuntime.jsx(designSystem.ContentLayout, { children: /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
992
+ activeTab === "pending" && hasReachedMaximumPendingReleases && /* @__PURE__ */ jsxRuntime.jsx(
993
+ StyledAlert,
994
+ {
995
+ marginBottom: 6,
996
+ action: /* @__PURE__ */ jsxRuntime.jsx(v2.Link, { href: "https://strapi.io/pricing-cloud", isExternal: true, children: formatMessage({
997
+ id: "content-releases.pages.Releases.max-limit-reached.action",
998
+ defaultMessage: "Explore plans"
999
+ }) }),
1000
+ title: formatMessage(
1001
+ {
1002
+ id: "content-releases.pages.Releases.max-limit-reached.title",
1003
+ defaultMessage: "You have reached the {number} pending {number, plural, one {release} other {releases}} limit."
1004
+ },
1005
+ { number: maximumReleases }
1006
+ ),
1007
+ onClose: () => {
1008
+ },
1009
+ closeLabel: "",
1010
+ children: formatMessage({
1011
+ id: "content-releases.pages.Releases.max-limit-reached.message",
1012
+ defaultMessage: "Upgrade to manage an unlimited number of releases."
1013
+ })
1014
+ }
1015
+ ),
955
1016
  /* @__PURE__ */ jsxRuntime.jsxs(
956
1017
  designSystem.TabGroup,
957
1018
  {
@@ -1034,4 +1095,4 @@ const App = () => {
1034
1095
  ] }) });
1035
1096
  };
1036
1097
  exports.App = App;
1037
- //# sourceMappingURL=App-YFvVMqB8.js.map
1098
+ //# sourceMappingURL=App-IQIHCiSO.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"App-IQIHCiSO.js","sources":["../../shared/validation-schemas.ts","../../admin/src/components/ReleaseModal.tsx","../../admin/src/pages/ReleaseDetailsPage.tsx","../../admin/src/pages/ReleasesPage.tsx","../../admin/src/pages/App.tsx"],"sourcesContent":["import * as yup from 'yup';\n\nexport const RELEASE_SCHEMA = yup\n .object()\n .shape({\n name: yup.string().trim().required(),\n // scheduledAt is a date, but we always receive strings from the client\n scheduledAt: yup.string(),\n })\n .required()\n .noUnknown();\n","import {\n Button,\n ModalBody,\n ModalFooter,\n ModalLayout,\n ModalHeader,\n TextInput,\n Typography,\n} from '@strapi/design-system';\nimport { Formik, Form } from 'formik';\nimport { useIntl } from 'react-intl';\nimport { useLocation } from 'react-router-dom';\n\nimport { RELEASE_SCHEMA } from '../../../shared/validation-schemas';\nimport { pluginId } from '../pluginId';\n\nexport interface FormValues {\n name: string;\n}\n\ninterface ReleaseModalProps {\n handleClose: () => void;\n handleSubmit: (values: FormValues) => void;\n isLoading?: boolean;\n initialValues: FormValues;\n}\n\nexport const ReleaseModal = ({\n handleClose,\n handleSubmit,\n initialValues,\n isLoading = false,\n}: ReleaseModalProps) => {\n const { formatMessage } = useIntl();\n const { pathname } = useLocation();\n const isCreatingRelease = pathname === `/plugins/${pluginId}`;\n\n return (\n <ModalLayout onClose={handleClose} labelledBy=\"title\">\n <ModalHeader>\n <Typography id=\"title\" fontWeight=\"bold\" textColor=\"neutral800\">\n {formatMessage(\n {\n id: 'content-releases.modal.title',\n defaultMessage:\n '{isCreatingRelease, select, true {New release} other {Edit release}}',\n },\n { isCreatingRelease: isCreatingRelease }\n )}\n </Typography>\n </ModalHeader>\n <Formik\n validateOnChange={false}\n onSubmit={handleSubmit}\n initialValues={initialValues}\n validationSchema={RELEASE_SCHEMA}\n >\n {({ values, errors, handleChange }) => (\n <Form>\n <ModalBody>\n <TextInput\n label={formatMessage({\n id: 'content-releases.modal.form.input.label.release-name',\n defaultMessage: 'Name',\n })}\n name=\"name\"\n value={values.name}\n error={errors.name}\n onChange={handleChange}\n required\n />\n </ModalBody>\n <ModalFooter\n startActions={\n <Button onClick={handleClose} variant=\"tertiary\" name=\"cancel\">\n {formatMessage({ id: 'cancel', defaultMessage: 'Cancel' })}\n </Button>\n }\n endActions={\n <Button\n name=\"submit\"\n loading={isLoading}\n disabled={!values.name || values.name === initialValues.name}\n type=\"submit\"\n >\n {formatMessage(\n {\n id: 'content-releases.modal.form.button.submit',\n defaultMessage: '{isCreatingRelease, select, true {Continue} other {Save}}',\n },\n { isCreatingRelease: isCreatingRelease }\n )}\n </Button>\n }\n />\n </Form>\n )}\n </Formik>\n </ModalLayout>\n );\n};\n","import * as React from 'react';\n\nimport { unstable_useDocument } from '@strapi/admin/strapi-admin';\nimport {\n Button,\n ContentLayout,\n Flex,\n HeaderLayout,\n IconButton,\n Link,\n Main,\n Popover,\n Tr,\n Td,\n Typography,\n Badge,\n SingleSelect,\n SingleSelectOption,\n Icon,\n Tooltip,\n} from '@strapi/design-system';\nimport { LinkButton } from '@strapi/design-system/v2';\nimport {\n CheckPermissions,\n LoadingIndicatorPage,\n NoContent,\n PageSizeURLQuery,\n PaginationURLQuery,\n RelativeTime,\n Table,\n useAPIErrorHandler,\n useNotification,\n useQueryParams,\n ConfirmDialog,\n useRBAC,\n AnErrorOccurred,\n useTracking,\n} from '@strapi/helper-plugin';\nimport { ArrowLeft, CheckCircle, More, Pencil, Trash, CrossCircle } from '@strapi/icons';\nimport { useIntl } from 'react-intl';\nimport { useParams, useHistory, Link as ReactRouterLink, Redirect } from 'react-router-dom';\nimport styled from 'styled-components';\n\nimport { ReleaseActionMenu } from '../components/ReleaseActionMenu';\nimport { ReleaseActionOptions } from '../components/ReleaseActionOptions';\nimport { ReleaseModal, FormValues } from '../components/ReleaseModal';\nimport { PERMISSIONS } from '../constants';\nimport { isAxiosError } from '../services/axios';\nimport {\n GetReleaseActionsQueryParams,\n useGetReleaseActionsQuery,\n useGetReleaseQuery,\n useUpdateReleaseMutation,\n useUpdateReleaseActionMutation,\n usePublishReleaseMutation,\n useDeleteReleaseMutation,\n releaseApi,\n} from '../services/release';\nimport { useTypedDispatch } from '../store/hooks';\n\nimport type {\n ReleaseAction,\n ReleaseActionGroupBy,\n ReleaseActionEntry,\n} from '../../../shared/contracts/release-actions';\nimport type { Schema } from '@strapi/types';\n\n/* -------------------------------------------------------------------------------------------------\n * ReleaseDetailsLayout\n * -----------------------------------------------------------------------------------------------*/\n// @ts-expect-error – issue with styled-components types.\nconst ReleaseInfoWrapper = styled(Flex)`\n align-self: stretch;\n border-bottom-right-radius: ${({ theme }) => theme.borderRadius};\n border-bottom-left-radius: ${({ theme }) => theme.borderRadius};\n border-top: 1px solid ${({ theme }) => theme.colors.neutral150};\n`;\n\nconst StyledFlex = styled(Flex)<{ disabled?: boolean }>`\n align-self: stretch;\n cursor: ${({ disabled }) => (disabled ? 'not-allowed' : 'pointer')};\n\n svg path {\n fill: ${({ theme, disabled }) => disabled && theme.colors.neutral500};\n }\n span {\n color: ${({ theme, disabled }) => disabled && theme.colors.neutral500};\n }\n`;\n\nconst PencilIcon = styled(Pencil)`\n width: ${({ theme }) => theme.spaces[3]};\n height: ${({ theme }) => theme.spaces[3]};\n path {\n fill: ${({ theme }) => theme.colors.neutral600};\n }\n`;\n\nconst TrashIcon = styled(Trash)`\n width: ${({ theme }) => theme.spaces[3]};\n height: ${({ theme }) => theme.spaces[3]};\n path {\n fill: ${({ theme }) => theme.colors.danger600};\n }\n`;\n\nconst TypographyMaxWidth = styled(Typography)`\n max-width: 300px;\n`;\n\ninterface PopoverButtonProps {\n onClick?: (event: React.MouseEvent<HTMLElement>) => void;\n disabled?: boolean;\n children: React.ReactNode;\n}\n\nconst PopoverButton = ({ onClick, disabled, children }: PopoverButtonProps) => {\n return (\n <StyledFlex\n paddingTop={2}\n paddingBottom={2}\n paddingLeft={4}\n paddingRight={4}\n alignItems=\"center\"\n gap={2}\n as=\"button\"\n hasRadius\n onClick={onClick}\n disabled={disabled}\n >\n {children}\n </StyledFlex>\n );\n};\n\ninterface EntryValidationTextProps {\n action: ReleaseAction['type'];\n schema: Schema.ContentType;\n components: { [key: Schema.Component['uid']]: Schema.Component };\n entry: ReleaseActionEntry;\n}\n\nconst EntryValidationText = ({ action, schema, components, entry }: EntryValidationTextProps) => {\n const { formatMessage } = useIntl();\n const { validate } = unstable_useDocument();\n\n const { errors } = validate(entry, {\n contentType: schema,\n components,\n isCreatingEntry: false,\n });\n\n if (Object.keys(errors).length > 0) {\n const validationErrorsMessages = Object.entries(errors)\n .map(([key, value]) =>\n formatMessage(\n { id: `${value.id}.withField`, defaultMessage: value.defaultMessage },\n { field: key }\n )\n )\n .join(' ');\n\n return (\n <Flex gap={2}>\n <Icon color=\"danger600\" as={CrossCircle} />\n <Tooltip description={validationErrorsMessages}>\n <TypographyMaxWidth textColor=\"danger600\" variant=\"omega\" fontWeight=\"semiBold\" ellipsis>\n {validationErrorsMessages}\n </TypographyMaxWidth>\n </Tooltip>\n </Flex>\n );\n }\n\n if (action == 'publish') {\n return (\n <Flex gap={2}>\n <Icon color=\"success600\" as={CheckCircle} />\n {entry.publishedAt ? (\n <Typography textColor=\"success600\" fontWeight=\"bold\">\n {formatMessage({\n id: 'content-releases.pages.ReleaseDetails.entry-validation.already-published',\n defaultMessage: 'Already published',\n })}\n </Typography>\n ) : (\n <Typography>\n {formatMessage({\n id: 'content-releases.pages.ReleaseDetails.entry-validation.ready-to-publish',\n defaultMessage: 'Ready to publish',\n })}\n </Typography>\n )}\n </Flex>\n );\n }\n\n return (\n <Flex gap={2}>\n <Icon color=\"success600\" as={CheckCircle} />\n {!entry.publishedAt ? (\n <Typography textColor=\"success600\" fontWeight=\"bold\">\n {formatMessage({\n id: 'content-releases.pages.ReleaseDetails.entry-validation.already-unpublished',\n defaultMessage: 'Already unpublished',\n })}\n </Typography>\n ) : (\n <Typography>\n {formatMessage({\n id: 'content-releases.pages.ReleaseDetails.entry-validation.ready-to-unpublish',\n defaultMessage: 'Ready to unpublish',\n })}\n </Typography>\n )}\n </Flex>\n );\n};\ninterface ReleaseDetailsLayoutProps {\n toggleEditReleaseModal: () => void;\n toggleWarningSubmit: () => void;\n children: React.ReactNode;\n}\n\nexport const ReleaseDetailsLayout = ({\n toggleEditReleaseModal,\n toggleWarningSubmit,\n children,\n}: ReleaseDetailsLayoutProps) => {\n const { formatMessage } = useIntl();\n const { releaseId } = useParams<{ releaseId: string }>();\n const [isPopoverVisible, setIsPopoverVisible] = React.useState(false);\n const moreButtonRef = React.useRef<HTMLButtonElement>(null!);\n const {\n data,\n isLoading: isLoadingDetails,\n isError,\n error,\n } = useGetReleaseQuery({ id: releaseId });\n const [publishRelease, { isLoading: isPublishing }] = usePublishReleaseMutation();\n const toggleNotification = useNotification();\n const { formatAPIError } = useAPIErrorHandler();\n const {\n allowedActions: { canUpdate, canDelete },\n } = useRBAC(PERMISSIONS);\n const dispatch = useTypedDispatch();\n const { trackUsage } = useTracking();\n\n const release = data?.data;\n\n const handleTogglePopover = () => {\n setIsPopoverVisible((prev) => !prev);\n };\n\n const openReleaseModal = () => {\n toggleEditReleaseModal();\n handleTogglePopover();\n };\n\n const handlePublishRelease = async () => {\n const response = await publishRelease({ id: releaseId });\n\n if ('data' in response) {\n // When the response returns an object with 'data', handle success\n toggleNotification({\n type: 'success',\n message: formatMessage({\n id: 'content-releases.pages.ReleaseDetails.publish-notification-success',\n defaultMessage: 'Release was published successfully.',\n }),\n });\n\n const { totalEntries, totalPublishedEntries, totalUnpublishedEntries } = response.data.meta;\n\n trackUsage('didPublishRelease', {\n totalEntries,\n totalPublishedEntries,\n totalUnpublishedEntries,\n });\n } else if (isAxiosError(response.error)) {\n // When the response returns an object with 'error', handle axios error\n toggleNotification({\n type: 'warning',\n message: formatAPIError(response.error),\n });\n } else {\n // Otherwise, the response returns an object with 'error', handle a generic error\n toggleNotification({\n type: 'warning',\n message: formatMessage({ id: 'notification.error', defaultMessage: 'An error occurred' }),\n });\n }\n };\n\n const openWarningConfirmDialog = () => {\n toggleWarningSubmit();\n handleTogglePopover();\n };\n\n const handleRefresh = () => {\n dispatch(releaseApi.util.invalidateTags([{ type: 'ReleaseAction', id: 'LIST' }]));\n };\n\n const getCreatedByUser = () => {\n if (!release?.createdBy) {\n return null;\n }\n\n // Favor the username\n if (release.createdBy.username) {\n return release.createdBy.username;\n }\n\n // Firstname may not exist if created with SSO\n if (release.createdBy.firstname) {\n return `${release.createdBy.firstname} ${release.createdBy.lastname || ''}`.trim();\n }\n\n // All users must have at least an email\n return release.createdBy.email;\n };\n\n if (isLoadingDetails) {\n return (\n <Main aria-busy={isLoadingDetails}>\n <LoadingIndicatorPage />\n </Main>\n );\n }\n\n if (isError || !release) {\n return (\n <Redirect\n to={{\n pathname: '/plugins/content-releases',\n state: {\n errors: [\n {\n code: error?.code,\n },\n ],\n },\n }}\n />\n );\n }\n\n const totalEntries = release.actions.meta.count || 0;\n const hasCreatedByUser = Boolean(getCreatedByUser());\n\n return (\n <Main aria-busy={isLoadingDetails}>\n <HeaderLayout\n title={release.name}\n subtitle={formatMessage(\n {\n id: 'content-releases.pages.Details.header-subtitle',\n defaultMessage: '{number, plural, =0 {No entries} one {# entry} other {# entries}}',\n },\n { number: totalEntries }\n )}\n navigationAction={\n <Link startIcon={<ArrowLeft />} to=\"/plugins/content-releases\">\n {formatMessage({\n id: 'global.back',\n defaultMessage: 'Back',\n })}\n </Link>\n }\n primaryAction={\n !release.releasedAt && (\n <Flex gap={2}>\n <IconButton\n label={formatMessage({\n id: 'content-releases.header.actions.open-release-actions',\n defaultMessage: 'Release edit and delete menu',\n })}\n ref={moreButtonRef}\n onClick={handleTogglePopover}\n >\n <More />\n </IconButton>\n {isPopoverVisible && (\n <Popover\n source={moreButtonRef}\n placement=\"bottom-end\"\n onDismiss={handleTogglePopover}\n spacing={4}\n minWidth=\"242px\"\n >\n <Flex alignItems=\"center\" justifyContent=\"center\" direction=\"column\" padding={1}>\n <PopoverButton disabled={!canUpdate} onClick={openReleaseModal}>\n <PencilIcon />\n <Typography ellipsis>\n {formatMessage({\n id: 'content-releases.header.actions.edit',\n defaultMessage: 'Edit',\n })}\n </Typography>\n </PopoverButton>\n <PopoverButton disabled={!canDelete} onClick={openWarningConfirmDialog}>\n <TrashIcon />\n <Typography ellipsis textColor=\"danger600\">\n {formatMessage({\n id: 'content-releases.header.actions.delete',\n defaultMessage: 'Delete',\n })}\n </Typography>\n </PopoverButton>\n </Flex>\n <ReleaseInfoWrapper\n direction=\"column\"\n justifyContent=\"center\"\n alignItems=\"flex-start\"\n gap={1}\n padding={5}\n >\n <Typography variant=\"pi\" fontWeight=\"bold\">\n {formatMessage({\n id: 'content-releases.header.actions.created',\n defaultMessage: 'Created',\n })}\n </Typography>\n <Typography variant=\"pi\" color=\"neutral300\">\n <RelativeTime timestamp={new Date(release.createdAt)} />\n {formatMessage(\n {\n id: 'content-releases.header.actions.created.description',\n defaultMessage:\n '{hasCreatedByUser, select, true { by {createdBy}} other { by deleted user}}',\n },\n { createdBy: getCreatedByUser(), hasCreatedByUser }\n )}\n </Typography>\n </ReleaseInfoWrapper>\n </Popover>\n )}\n <Button size=\"S\" variant=\"tertiary\" onClick={handleRefresh}>\n {formatMessage({\n id: 'content-releases.header.actions.refresh',\n defaultMessage: 'Refresh',\n })}\n </Button>\n <CheckPermissions permissions={PERMISSIONS.publish}>\n <Button\n size=\"S\"\n variant=\"default\"\n onClick={handlePublishRelease}\n loading={isPublishing}\n disabled={release.actions.meta.count === 0}\n >\n {formatMessage({\n id: 'content-releases.header.actions.publish',\n defaultMessage: 'Publish',\n })}\n </Button>\n </CheckPermissions>\n </Flex>\n )\n }\n />\n {children}\n </Main>\n );\n};\n\n/* -------------------------------------------------------------------------------------------------\n * ReleaseDetailsBody\n * -----------------------------------------------------------------------------------------------*/\nconst GROUP_BY_OPTIONS = ['contentType', 'locale', 'action'] as const;\nconst getGroupByOptionLabel = (value: (typeof GROUP_BY_OPTIONS)[number]) => {\n if (value === 'locale') {\n return {\n id: 'content-releases.pages.ReleaseDetails.groupBy.option.locales',\n defaultMessage: 'Locales',\n };\n }\n\n if (value === 'action') {\n return {\n id: 'content-releases.pages.ReleaseDetails.groupBy.option.actions',\n defaultMessage: 'Actions',\n };\n }\n\n return {\n id: 'content-releases.pages.ReleaseDetails.groupBy.option.content-type',\n defaultMessage: 'Content-Types',\n };\n};\n\nconst ReleaseDetailsBody = () => {\n const { formatMessage } = useIntl();\n const { releaseId } = useParams<{ releaseId: string }>();\n const [{ query }, setQuery] = useQueryParams<GetReleaseActionsQueryParams>();\n const toggleNotification = useNotification();\n const { formatAPIError } = useAPIErrorHandler();\n const {\n data: releaseData,\n isLoading: isReleaseLoading,\n isError: isReleaseError,\n error: releaseError,\n } = useGetReleaseQuery({ id: releaseId });\n\n const release = releaseData?.data;\n const selectedGroupBy = query?.groupBy || 'contentType';\n\n const {\n isLoading,\n isFetching,\n isError,\n data,\n error: releaseActionsError,\n } = useGetReleaseActionsQuery({\n ...query,\n releaseId,\n });\n\n const [updateReleaseAction] = useUpdateReleaseActionMutation();\n\n const handleChangeType = async (\n e: React.ChangeEvent<HTMLInputElement>,\n actionId: ReleaseAction['id'],\n actionPath: [string, number]\n ) => {\n const response = await updateReleaseAction({\n params: {\n releaseId,\n actionId,\n },\n body: {\n type: e.target.value as ReleaseAction['type'],\n },\n query, // We are passing the query params to make optimistic updates\n actionPath, // We are passing the action path to found the position in the cache of the action for optimistic updates\n });\n\n if ('error' in response) {\n if (isAxiosError(response.error)) {\n // When the response returns an object with 'error', handle axios error\n toggleNotification({\n type: 'warning',\n message: formatAPIError(response.error),\n });\n } else {\n // Otherwise, the response returns an object with 'error', handle a generic error\n toggleNotification({\n type: 'warning',\n message: formatMessage({ id: 'notification.error', defaultMessage: 'An error occurred' }),\n });\n }\n }\n };\n\n if (isLoading || isReleaseLoading) {\n return (\n <ContentLayout>\n <LoadingIndicatorPage />\n </ContentLayout>\n );\n }\n\n const releaseActions = data?.data;\n const releaseMeta = data?.meta;\n const contentTypes = releaseMeta?.contentTypes || {};\n const components = releaseMeta?.components || {};\n\n if (isReleaseError || !release) {\n const errorsArray = [];\n if (releaseError) {\n errorsArray.push({\n code: releaseError.code,\n });\n }\n if (releaseActionsError) {\n errorsArray.push({\n code: releaseActionsError.code,\n });\n }\n return (\n <Redirect\n to={{\n pathname: '/plugins/content-releases',\n state: {\n errors: errorsArray,\n },\n }}\n />\n );\n }\n\n if (isError || !releaseActions) {\n return (\n <ContentLayout>\n <AnErrorOccurred />\n </ContentLayout>\n );\n }\n\n if (Object.keys(releaseActions).length === 0) {\n return (\n <ContentLayout>\n <NoContent\n content={{\n id: 'content-releases.pages.Details.tab.emptyEntries',\n defaultMessage:\n 'This release is empty. Open the Content Manager, select an entry and add it to the release.',\n }}\n action={\n <LinkButton\n as={ReactRouterLink}\n // @ts-expect-error - types are not inferred correctly through the as prop.\n to={{\n pathname: '/content-manager',\n }}\n style={{ textDecoration: 'none' }}\n variant=\"secondary\"\n >\n {formatMessage({\n id: 'content-releases.page.Details.button.openContentManager',\n defaultMessage: 'Open the Content Manager',\n })}\n </LinkButton>\n }\n />\n </ContentLayout>\n );\n }\n\n return (\n <ContentLayout>\n <Flex gap={8} direction=\"column\" alignItems=\"stretch\">\n <Flex>\n <SingleSelect\n aria-label={formatMessage({\n id: 'content-releases.pages.ReleaseDetails.groupBy.aria-label',\n defaultMessage: 'Group by',\n })}\n customizeContent={(value) =>\n formatMessage(\n {\n id: `content-releases.pages.ReleaseDetails.groupBy.label`,\n defaultMessage: `Group by {groupBy}`,\n },\n {\n groupBy: value,\n }\n )\n }\n value={formatMessage(getGroupByOptionLabel(selectedGroupBy))}\n onChange={(value) => setQuery({ groupBy: value as ReleaseActionGroupBy })}\n >\n {GROUP_BY_OPTIONS.map((option) => (\n <SingleSelectOption key={option} value={option}>\n {formatMessage(getGroupByOptionLabel(option))}\n </SingleSelectOption>\n ))}\n </SingleSelect>\n </Flex>\n {Object.keys(releaseActions).map((key) => (\n <Flex key={`releases-group-${key}`} gap={4} direction=\"column\" alignItems=\"stretch\">\n <Flex role=\"separator\" aria-label={key}>\n <Badge>{key}</Badge>\n </Flex>\n <Table.Root\n rows={releaseActions[key].map((item) => ({\n ...item,\n id: Number(item.entry.id),\n }))}\n colCount={releaseActions[key].length}\n isLoading={isLoading}\n isFetching={isFetching}\n >\n <Table.Content>\n <Table.Head>\n <Table.HeaderCell\n fieldSchemaType=\"string\"\n label={formatMessage({\n id: 'content-releases.page.ReleaseDetails.table.header.label.name',\n defaultMessage: 'name',\n })}\n name=\"name\"\n />\n <Table.HeaderCell\n fieldSchemaType=\"string\"\n label={formatMessage({\n id: 'content-releases.page.ReleaseDetails.table.header.label.locale',\n defaultMessage: 'locale',\n })}\n name=\"locale\"\n />\n <Table.HeaderCell\n fieldSchemaType=\"string\"\n label={formatMessage({\n id: 'content-releases.page.ReleaseDetails.table.header.label.content-type',\n defaultMessage: 'content-type',\n })}\n name=\"content-type\"\n />\n <Table.HeaderCell\n fieldSchemaType=\"string\"\n label={formatMessage({\n id: 'content-releases.page.ReleaseDetails.table.header.label.action',\n defaultMessage: 'action',\n })}\n name=\"action\"\n />\n {!release.releasedAt && (\n <Table.HeaderCell\n fieldSchemaType=\"string\"\n label={formatMessage({\n id: 'content-releases.page.ReleaseDetails.table.header.label.status',\n defaultMessage: 'status',\n })}\n name=\"status\"\n />\n )}\n </Table.Head>\n <Table.LoadingBody />\n <Table.Body>\n {releaseActions[key].map(\n ({ id, contentType, locale, type, entry }, actionIndex) => (\n <Tr key={id}>\n <Td width=\"25%\" maxWidth=\"200px\">\n <Typography ellipsis>{`${\n contentType.mainFieldValue || entry.id\n }`}</Typography>\n </Td>\n <Td width=\"10%\">\n <Typography>{`${locale?.name ? locale.name : '-'}`}</Typography>\n </Td>\n <Td width=\"10%\">\n <Typography>{contentType.displayName || ''}</Typography>\n </Td>\n <Td width=\"20%\">\n {release.releasedAt ? (\n <Typography>\n {formatMessage(\n {\n id: 'content-releases.page.ReleaseDetails.table.action-published',\n defaultMessage:\n 'This entry was <b>{isPublish, select, true {published} other {unpublished}}</b>.',\n },\n {\n isPublish: type === 'publish',\n b: (children: React.ReactNode) => (\n <Typography fontWeight=\"bold\">{children}</Typography>\n ),\n }\n )}\n </Typography>\n ) : (\n <ReleaseActionOptions\n selected={type}\n handleChange={(e) => handleChangeType(e, id, [key, actionIndex])}\n name={`release-action-${id}-type`}\n />\n )}\n </Td>\n {!release.releasedAt && (\n <>\n <Td width=\"20%\" minWidth=\"200px\">\n <EntryValidationText\n action={type}\n schema={contentTypes?.[contentType.uid]}\n components={components}\n entry={entry}\n />\n </Td>\n <Td>\n <Flex justifyContent=\"flex-end\">\n <ReleaseActionMenu.Root>\n <ReleaseActionMenu.ReleaseActionEntryLinkItem\n contentTypeUid={contentType.uid}\n entryId={entry.id}\n locale={locale?.code}\n />\n <ReleaseActionMenu.DeleteReleaseActionItem\n releaseId={release.id}\n actionId={id}\n />\n </ReleaseActionMenu.Root>\n </Flex>\n </Td>\n </>\n )}\n </Tr>\n )\n )}\n </Table.Body>\n </Table.Content>\n </Table.Root>\n </Flex>\n ))}\n <Flex paddingTop={4} alignItems=\"flex-end\" justifyContent=\"space-between\">\n <PageSizeURLQuery defaultValue={releaseMeta?.pagination?.pageSize.toString()} />\n <PaginationURLQuery\n pagination={{\n pageCount: releaseMeta?.pagination?.pageCount || 0,\n }}\n />\n </Flex>\n </Flex>\n </ContentLayout>\n );\n};\n\n/* -------------------------------------------------------------------------------------------------\n * ReleaseDetailsPage\n * -----------------------------------------------------------------------------------------------*/\nconst ReleaseDetailsPage = () => {\n const { formatMessage } = useIntl();\n const { releaseId } = useParams<{ releaseId: string }>();\n const toggleNotification = useNotification();\n const { formatAPIError } = useAPIErrorHandler();\n const { push } = useHistory();\n const [releaseModalShown, setReleaseModalShown] = React.useState(false);\n const [showWarningSubmit, setWarningSubmit] = React.useState(false);\n\n const {\n isLoading: isLoadingDetails,\n data,\n isSuccess: isSuccessDetails,\n } = useGetReleaseQuery({ id: releaseId });\n const [updateRelease, { isLoading: isSubmittingForm }] = useUpdateReleaseMutation();\n const [deleteRelease, { isLoading: isDeletingRelease }] = useDeleteReleaseMutation();\n\n const toggleEditReleaseModal = () => {\n setReleaseModalShown((prev) => !prev);\n };\n\n const toggleWarningSubmit = () => setWarningSubmit((prevState) => !prevState);\n\n if (isLoadingDetails) {\n return (\n <ReleaseDetailsLayout\n toggleEditReleaseModal={toggleEditReleaseModal}\n toggleWarningSubmit={toggleWarningSubmit}\n >\n <ContentLayout>\n <LoadingIndicatorPage />\n </ContentLayout>\n </ReleaseDetailsLayout>\n );\n }\n\n const title = (isSuccessDetails && data?.data?.name) || '';\n\n const handleEditRelease = async (values: FormValues) => {\n const response = await updateRelease({\n id: releaseId,\n name: values.name,\n });\n\n if ('data' in response) {\n // When the response returns an object with 'data', handle success\n toggleNotification({\n type: 'success',\n message: formatMessage({\n id: 'content-releases.modal.release-updated-notification-success',\n defaultMessage: 'Release updated.',\n }),\n });\n } else if (isAxiosError(response.error)) {\n // When the response returns an object with 'error', handle axios error\n toggleNotification({\n type: 'warning',\n message: formatAPIError(response.error),\n });\n } else {\n // Otherwise, the response returns an object with 'error', handle a generic error\n toggleNotification({\n type: 'warning',\n message: formatMessage({ id: 'notification.error', defaultMessage: 'An error occurred' }),\n });\n }\n\n toggleEditReleaseModal();\n };\n\n const handleDeleteRelease = async () => {\n const response = await deleteRelease({\n id: releaseId,\n });\n\n if ('data' in response) {\n push('/plugins/content-releases');\n } else if (isAxiosError(response.error)) {\n // When the response returns an object with 'error', handle axios error\n toggleNotification({\n type: 'warning',\n message: formatAPIError(response.error),\n });\n } else {\n // Otherwise, the response returns an object with 'error', handle a generic error\n toggleNotification({\n type: 'warning',\n message: formatMessage({ id: 'notification.error', defaultMessage: 'An error occurred' }),\n });\n }\n };\n\n return (\n <ReleaseDetailsLayout\n toggleEditReleaseModal={toggleEditReleaseModal}\n toggleWarningSubmit={toggleWarningSubmit}\n >\n <ReleaseDetailsBody />\n {releaseModalShown && (\n <ReleaseModal\n handleClose={toggleEditReleaseModal}\n handleSubmit={handleEditRelease}\n isLoading={isLoadingDetails || isSubmittingForm}\n initialValues={{ name: title || '' }}\n />\n )}\n <ConfirmDialog\n bodyText={{\n id: 'content-releases.dialog.confirmation-message',\n defaultMessage: 'Are you sure you want to delete this release?',\n }}\n isOpen={showWarningSubmit}\n isConfirmButtonLoading={isDeletingRelease}\n onToggleDialog={toggleWarningSubmit}\n onConfirm={handleDeleteRelease}\n />\n </ReleaseDetailsLayout>\n );\n};\n\nexport { ReleaseDetailsPage };\n","import * as React from 'react';\n\n// TODO: Replace this import with the same hook exported from the @strapi/admin/strapi-admin/ee in another iteration of this solution\nimport { useLicenseLimits } from '@strapi/admin/strapi-admin';\nimport {\n Alert,\n Box,\n Button,\n ContentLayout,\n Divider,\n EmptyStateLayout,\n Flex,\n Grid,\n GridItem,\n HeaderLayout,\n Main,\n Tab,\n TabGroup,\n TabPanel,\n TabPanels,\n Tabs,\n Typography,\n} from '@strapi/design-system';\nimport { Link } from '@strapi/design-system/v2';\nimport {\n AnErrorOccurred,\n CheckPermissions,\n LoadingIndicatorPage,\n PageSizeURLQuery,\n PaginationURLQuery,\n useQueryParams,\n useAPIErrorHandler,\n useNotification,\n useTracking,\n} from '@strapi/helper-plugin';\nimport { EmptyDocuments, Plus } from '@strapi/icons';\nimport { useIntl } from 'react-intl';\nimport { useHistory, useLocation } from 'react-router-dom';\nimport styled from 'styled-components';\n\nimport { GetReleases } from '../../../shared/contracts/releases';\nimport { ReleaseModal, FormValues } from '../components/ReleaseModal';\nimport { PERMISSIONS } from '../constants';\nimport { isAxiosError } from '../services/axios';\nimport {\n useGetReleasesQuery,\n GetReleasesQueryParams,\n useCreateReleaseMutation,\n} from '../services/release';\n\n/* -------------------------------------------------------------------------------------------------\n * ReleasesGrid\n * -----------------------------------------------------------------------------------------------*/\ninterface ReleasesGridProps {\n sectionTitle: 'pending' | 'done';\n releases?: GetReleases.Response['data'];\n isError?: boolean;\n}\n\nconst LinkCard = styled(Link)`\n display: block;\n`;\n\nconst ReleasesGrid = ({ sectionTitle, releases = [], isError = false }: ReleasesGridProps) => {\n const { formatMessage } = useIntl();\n\n if (isError) {\n return <AnErrorOccurred />;\n }\n\n if (releases?.length === 0) {\n return (\n <EmptyStateLayout\n content={formatMessage(\n {\n id: 'content-releases.page.Releases.tab.emptyEntries',\n defaultMessage: 'No releases',\n },\n {\n target: sectionTitle,\n }\n )}\n icon={<EmptyDocuments width=\"10rem\" />}\n />\n );\n }\n\n return (\n <Grid gap={4}>\n {releases.map(({ id, name, actions }) => (\n <GridItem col={3} s={6} xs={12} key={id}>\n <LinkCard href={`content-releases/${id}`} isExternal={false}>\n <Flex\n direction=\"column\"\n justifyContent=\"space-between\"\n padding={4}\n hasRadius\n background=\"neutral0\"\n shadow=\"tableShadow\"\n height=\"100%\"\n width=\"100%\"\n alignItems=\"start\"\n gap={2}\n >\n <Typography as=\"h3\" variant=\"delta\" fontWeight=\"bold\">\n {name}\n </Typography>\n <Typography variant=\"pi\">\n {formatMessage(\n {\n id: 'content-releases.page.Releases.release-item.entries',\n defaultMessage:\n '{number, plural, =0 {No entries} one {# entry} other {# entries}}',\n },\n { number: actions.meta.count }\n )}\n </Typography>\n </Flex>\n </LinkCard>\n </GridItem>\n ))}\n </Grid>\n );\n};\n\n/* -------------------------------------------------------------------------------------------------\n * ReleasesPage\n * -----------------------------------------------------------------------------------------------*/\ninterface CustomLocationState {\n errors?: Record<'code', string>[];\n}\n\nconst StyledAlert = styled(Alert)`\n button {\n display: none;\n }\n p + div {\n margin-left: auto;\n }\n`;\n\nconst INITIAL_FORM_VALUES = {\n name: '',\n} satisfies FormValues;\n\nconst ReleasesPage = () => {\n const tabRef = React.useRef<any>(null);\n const location = useLocation<CustomLocationState>();\n const [releaseModalShown, setReleaseModalShown] = React.useState(false);\n const toggleNotification = useNotification();\n const { formatMessage } = useIntl();\n const { push, replace } = useHistory();\n const { formatAPIError } = useAPIErrorHandler();\n const [{ query }, setQuery] = useQueryParams<GetReleasesQueryParams>();\n const response = useGetReleasesQuery(query);\n const [createRelease, { isLoading: isSubmittingForm }] = useCreateReleaseMutation();\n const { getFeature } = useLicenseLimits();\n const { maximumReleases = 3 } = getFeature('cms-content-releases') as {\n maximumReleases: number;\n };\n const { trackUsage } = useTracking();\n\n const { isLoading, isSuccess, isError } = response;\n const activeTab = response?.currentData?.meta?.activeTab || 'pending';\n const activeTabIndex = ['pending', 'done'].indexOf(activeTab);\n\n // Check if we have some errors and show a notification to the user to explain the error\n React.useEffect(() => {\n if (location?.state?.errors) {\n toggleNotification({\n type: 'warning',\n title: formatMessage({\n id: 'content-releases.pages.Releases.notification.error.title',\n defaultMessage: 'Your request could not be processed.',\n }),\n message: formatMessage({\n id: 'content-releases.pages.Releases.notification.error.message',\n defaultMessage: 'Please try again or open another release.',\n }),\n });\n replace({ state: null });\n }\n }, [formatMessage, location?.state?.errors, replace, toggleNotification]);\n\n // TODO: Replace this solution with v2 of the Design System\n // Check if the active tab index changes and call the handler of the ref to update the tab group component\n React.useEffect(() => {\n if (tabRef.current) {\n tabRef.current._handlers.setSelectedTabIndex(activeTabIndex);\n }\n }, [activeTabIndex]);\n\n const toggleAddReleaseModal = () => {\n setReleaseModalShown((prev) => !prev);\n };\n\n if (isLoading) {\n return (\n <Main aria-busy={isLoading}>\n <LoadingIndicatorPage />\n </Main>\n );\n }\n\n const totalReleases = (isSuccess && response.currentData?.meta?.pagination?.total) || 0;\n const hasReachedMaximumPendingReleases = totalReleases >= maximumReleases;\n\n const handleTabChange = (index: number) => {\n setQuery({\n ...query,\n page: 1,\n pageSize: response?.currentData?.meta?.pagination?.pageSize || 16,\n filters: {\n releasedAt: {\n $notNull: index === 0 ? false : true,\n },\n },\n });\n };\n\n const handleAddRelease = async (values: FormValues) => {\n const response = await createRelease({\n name: values.name,\n });\n if ('data' in response) {\n // When the response returns an object with 'data', handle success\n toggleNotification({\n type: 'success',\n message: formatMessage({\n id: 'content-releases.modal.release-created-notification-success',\n defaultMessage: 'Release created.',\n }),\n });\n\n trackUsage('didCreateRelease');\n\n push(`/plugins/content-releases/${response.data.data.id}`);\n } else if (isAxiosError(response.error)) {\n // When the response returns an object with 'error', handle axios error\n toggleNotification({\n type: 'warning',\n message: formatAPIError(response.error),\n });\n } else {\n // Otherwise, the response returns an object with 'error', handle a generic error\n toggleNotification({\n type: 'warning',\n message: formatMessage({ id: 'notification.error', defaultMessage: 'An error occurred' }),\n });\n }\n };\n\n return (\n <Main aria-busy={isLoading}>\n <HeaderLayout\n title={formatMessage({\n id: 'content-releases.pages.Releases.title',\n defaultMessage: 'Releases',\n })}\n subtitle={formatMessage(\n {\n id: 'content-releases.pages.Releases.header-subtitle',\n defaultMessage: '{number, plural, =0 {No releases} one {# release} other {# releases}}',\n },\n { number: totalReleases }\n )}\n primaryAction={\n <CheckPermissions permissions={PERMISSIONS.create}>\n <Button\n startIcon={<Plus />}\n onClick={toggleAddReleaseModal}\n disabled={hasReachedMaximumPendingReleases}\n >\n {formatMessage({\n id: 'content-releases.header.actions.add-release',\n defaultMessage: 'New release',\n })}\n </Button>\n </CheckPermissions>\n }\n />\n <ContentLayout>\n <>\n {activeTab === 'pending' && hasReachedMaximumPendingReleases && (\n <StyledAlert\n marginBottom={6}\n action={\n <Link href=\"https://strapi.io/pricing-cloud\" isExternal>\n {formatMessage({\n id: 'content-releases.pages.Releases.max-limit-reached.action',\n defaultMessage: 'Explore plans',\n })}\n </Link>\n }\n title={formatMessage(\n {\n id: 'content-releases.pages.Releases.max-limit-reached.title',\n defaultMessage:\n 'You have reached the {number} pending {number, plural, one {release} other {releases}} limit.',\n },\n { number: maximumReleases }\n )}\n onClose={() => {}}\n closeLabel=\"\"\n >\n {formatMessage({\n id: 'content-releases.pages.Releases.max-limit-reached.message',\n defaultMessage: 'Upgrade to manage an unlimited number of releases.',\n })}\n </StyledAlert>\n )}\n <TabGroup\n label={formatMessage({\n id: 'content-releases.pages.Releases.tab-group.label',\n defaultMessage: 'Releases list',\n })}\n variant=\"simple\"\n initialSelectedTabIndex={activeTabIndex}\n onTabChange={handleTabChange}\n ref={tabRef}\n >\n <Box paddingBottom={8}>\n <Tabs>\n <Tab>\n {formatMessage({\n id: 'content-releases.pages.Releases.tab.pending',\n defaultMessage: 'Pending',\n })}\n </Tab>\n <Tab>\n {formatMessage({\n id: 'content-releases.pages.Releases.tab.done',\n defaultMessage: 'Done',\n })}\n </Tab>\n </Tabs>\n <Divider />\n </Box>\n <TabPanels>\n {/* Pending releases */}\n <TabPanel>\n <ReleasesGrid\n sectionTitle=\"pending\"\n releases={response?.currentData?.data}\n isError={isError}\n />\n </TabPanel>\n {/* Done releases */}\n <TabPanel>\n <ReleasesGrid\n sectionTitle=\"done\"\n releases={response?.currentData?.data}\n isError={isError}\n />\n </TabPanel>\n </TabPanels>\n </TabGroup>\n {totalReleases > 0 && (\n <Flex paddingTop={4} alignItems=\"flex-end\" justifyContent=\"space-between\">\n <PageSizeURLQuery\n options={['8', '16', '32', '64']}\n defaultValue={response?.currentData?.meta?.pagination?.pageSize.toString()}\n />\n <PaginationURLQuery\n pagination={{\n pageCount: response?.currentData?.meta?.pagination?.pageCount || 0,\n }}\n />\n </Flex>\n )}\n </>\n </ContentLayout>\n {releaseModalShown && (\n <ReleaseModal\n handleClose={toggleAddReleaseModal}\n handleSubmit={handleAddRelease}\n isLoading={isSubmittingForm}\n initialValues={INITIAL_FORM_VALUES}\n />\n )}\n </Main>\n );\n};\n\nexport { ReleasesPage };\n","import { CheckPagePermissions } from '@strapi/helper-plugin';\nimport { Route, Switch } from 'react-router-dom';\n\nimport { PERMISSIONS } from '../constants';\nimport { pluginId } from '../pluginId';\n\nimport { ReleaseDetailsPage } from './ReleaseDetailsPage';\nimport { ReleasesPage } from './ReleasesPage';\n\nexport const App = () => {\n return (\n <CheckPagePermissions permissions={PERMISSIONS.main}>\n <Switch>\n <Route exact path={`/plugins/${pluginId}`} component={ReleasesPage} />\n <Route exact path={`/plugins/${pluginId}/:releaseId`} component={ReleaseDetailsPage} />\n </Switch>\n </CheckPagePermissions>\n );\n};\n"],"names":["yup","useIntl","useLocation","pluginId","jsxs","ModalLayout","jsx","ModalHeader","Typography","Formik","Form","ModalBody","TextInput","ModalFooter","Button","styled","Flex","Pencil","Trash","unstable_useDocument","Icon","CrossCircle","Tooltip","CheckCircle","useParams","React","useGetReleaseQuery","usePublishReleaseMutation","useNotification","useAPIErrorHandler","useRBAC","PERMISSIONS","useTypedDispatch","useTracking","totalEntries","isAxiosError","releaseApi","Main","LoadingIndicatorPage","Redirect","HeaderLayout","Link","ArrowLeft","IconButton","More","Popover","RelativeTime","CheckPermissions","useQueryParams","useGetReleaseActionsQuery","useUpdateReleaseActionMutation","ContentLayout","AnErrorOccurred","NoContent","LinkButton","ReactRouterLink","SingleSelect","SingleSelectOption","Badge","Table","Tr","Td","ReleaseActionOptions","Fragment","ReleaseActionMenu","PageSizeURLQuery","PaginationURLQuery","useHistory","useUpdateReleaseMutation","useDeleteReleaseMutation","ConfirmDialog","EmptyStateLayout","EmptyDocuments","Grid","GridItem","Alert","useGetReleasesQuery","useCreateReleaseMutation","useLicenseLimits","index","response","Plus","TabGroup","Box","Tabs","Tab","Divider","TabPanels","TabPanel","CheckPagePermissions","Switch","Route"],"mappings":"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"}