@strapi/content-releases 0.0.0-next.37dd1e3ff22e1635b69683abadd444912ae0dbff → 0.0.0-next.6a58621932ad3d83bf9d6928c1871e7906adcd59

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.
@@ -1,11 +1,12 @@
1
1
  import { jsxs, jsx, Fragment } from "react/jsx-runtime";
2
2
  import { useNotification, useAPIErrorHandler, LoadingIndicatorPage, ConfirmDialog, useRBAC, RelativeTime, CheckPermissions, useQueryParams, AnErrorOccurred, NoContent, Table, PageSizeURLQuery, PaginationURLQuery, CheckPagePermissions } from "@strapi/helper-plugin";
3
3
  import { useLocation, useParams, useHistory, Redirect, Link as Link$1, Switch, Route } from "react-router-dom";
4
- import { p as pluginId, u as useGetReleaseQuery, a as useUpdateReleaseMutation, b as useDeleteReleaseMutation, c as usePublishReleaseMutation, P as PERMISSIONS, d as useGetReleaseActionsQuery, e as useUpdateReleaseActionMutation, R as ReleaseActionOptions, f as ReleaseActionMenu, i as isAxiosError, g as useGetReleasesQuery, h as useCreateReleaseMutation } from "./index-_Zsj8MUA.mjs";
4
+ import { p as pluginId, u as useGetReleaseQuery, a as useUpdateReleaseMutation, b as useDeleteReleaseMutation, c as usePublishReleaseMutation, P as PERMISSIONS, d as useTypedDispatch, e as useGetReleaseActionsQuery, f as useUpdateReleaseActionMutation, R as ReleaseActionOptions, g as ReleaseActionMenu, i as isAxiosError, r as releaseApi, h as useGetReleasesQuery, j as useCreateReleaseMutation } from "./index-c4zRX_sg.mjs";
5
5
  import * as React from "react";
6
- import { ModalLayout, ModalHeader, Typography, ModalBody, TextInput, ModalFooter, Button, Flex, ContentLayout, Main, HeaderLayout, Link, IconButton, Popover, SingleSelect, SingleSelectOption, Badge, Tr, Td, Icon, TabGroup, Box, Tabs, Tab, Divider, TabPanels, TabPanel, EmptyStateLayout, Grid, GridItem } from "@strapi/design-system";
6
+ import { unstable_useDocument } from "@strapi/admin/strapi-admin";
7
+ import { ModalLayout, ModalHeader, Typography, ModalBody, TextInput, ModalFooter, Button, Flex, ContentLayout, Main, HeaderLayout, Link, IconButton, Popover, SingleSelect, SingleSelectOption, Badge, Tr, Td, Icon, Tooltip, TabGroup, Box, Tabs, Tab, Divider, TabPanels, TabPanel, EmptyStateLayout, Grid, GridItem } from "@strapi/design-system";
7
8
  import { LinkButton, Link as Link$2 } from "@strapi/design-system/v2";
8
- import { Pencil, Trash, ArrowLeft, More, CheckCircle, Plus, EmptyDocuments } from "@strapi/icons";
9
+ import { Pencil, Trash, ArrowLeft, More, CrossCircle, CheckCircle, Plus, EmptyDocuments } from "@strapi/icons";
9
10
  import { useIntl } from "react-intl";
10
11
  import styled from "styled-components";
11
12
  import { Formik, Form } from "formik";
@@ -13,6 +14,7 @@ import * as yup from "yup";
13
14
  import "@reduxjs/toolkit/query";
14
15
  import "axios";
15
16
  import "@reduxjs/toolkit/query/react";
17
+ import "react-redux";
16
18
  const RELEASE_SCHEMA = yup.object().shape({
17
19
  name: yup.string().trim().required()
18
20
  }).required().noUnknown();
@@ -113,6 +115,9 @@ const TrashIcon = styled(Trash)`
113
115
  fill: ${({ theme }) => theme.colors.danger600};
114
116
  }
115
117
  `;
118
+ const TypographyMaxWidth = styled(Typography)`
119
+ max-width: 300px;
120
+ `;
116
121
  const PopoverButton = ({ onClick, disabled, children }) => {
117
122
  return /* @__PURE__ */ jsx(
118
123
  StyledFlex,
@@ -131,12 +136,30 @@ const PopoverButton = ({ onClick, disabled, children }) => {
131
136
  }
132
137
  );
133
138
  };
134
- const EntryValidationText = ({ status, action }) => {
139
+ const EntryValidationText = ({ action, schema, components, entry }) => {
135
140
  const { formatMessage } = useIntl();
141
+ const { validate } = unstable_useDocument();
142
+ const { errors } = validate(entry, {
143
+ contentType: schema,
144
+ components,
145
+ isCreatingEntry: false
146
+ });
147
+ if (Object.keys(errors).length > 0) {
148
+ const validationErrorsMessages = Object.entries(errors).map(
149
+ ([key, value]) => formatMessage(
150
+ { id: `${value.id}.withField`, defaultMessage: value.defaultMessage },
151
+ { field: key }
152
+ )
153
+ ).join(" ");
154
+ return /* @__PURE__ */ jsxs(Flex, { gap: 2, children: [
155
+ /* @__PURE__ */ jsx(Icon, { color: "danger600", as: CrossCircle }),
156
+ /* @__PURE__ */ jsx(Tooltip, { description: validationErrorsMessages, children: /* @__PURE__ */ jsx(TypographyMaxWidth, { textColor: "danger600", variant: "omega", fontWeight: "semiBold", ellipsis: true, children: validationErrorsMessages }) })
157
+ ] });
158
+ }
136
159
  if (action == "publish") {
137
160
  return /* @__PURE__ */ jsxs(Flex, { gap: 2, children: [
138
161
  /* @__PURE__ */ jsx(Icon, { color: "success600", as: CheckCircle }),
139
- status === "published" ? /* @__PURE__ */ jsx(Typography, { textColor: "success600", fontWeight: "bold", children: formatMessage({
162
+ entry.publishedAt ? /* @__PURE__ */ jsx(Typography, { textColor: "success600", fontWeight: "bold", children: formatMessage({
140
163
  id: "content-releases.pages.ReleaseDetails.entry-validation.already-published",
141
164
  defaultMessage: "Already published"
142
165
  }) }) : /* @__PURE__ */ jsx(Typography, { children: formatMessage({
@@ -147,7 +170,7 @@ const EntryValidationText = ({ status, action }) => {
147
170
  }
148
171
  return /* @__PURE__ */ jsxs(Flex, { gap: 2, children: [
149
172
  /* @__PURE__ */ jsx(Icon, { color: "success600", as: CheckCircle }),
150
- status === "draft" ? /* @__PURE__ */ jsx(Typography, { textColor: "success600", fontWeight: "bold", children: formatMessage({
173
+ !entry.publishedAt ? /* @__PURE__ */ jsx(Typography, { textColor: "success600", fontWeight: "bold", children: formatMessage({
151
174
  id: "content-releases.pages.ReleaseDetails.entry-validation.already-unpublished",
152
175
  defaultMessage: "Already unpublished"
153
176
  }) }) : /* @__PURE__ */ jsx(Typography, { children: formatMessage({
@@ -177,6 +200,7 @@ const ReleaseDetailsLayout = ({
177
200
  const {
178
201
  allowedActions: { canUpdate, canDelete }
179
202
  } = useRBAC(PERMISSIONS);
203
+ const dispatch = useTypedDispatch();
180
204
  const release = data?.data;
181
205
  const handleTogglePopover = () => {
182
206
  setIsPopoverVisible((prev) => !prev);
@@ -211,6 +235,9 @@ const ReleaseDetailsLayout = ({
211
235
  toggleWarningSubmit();
212
236
  handleTogglePopover();
213
237
  };
238
+ const handleRefresh = () => {
239
+ dispatch(releaseApi.util.invalidateTags([{ type: "ReleaseAction", id: "LIST" }]));
240
+ };
214
241
  if (isLoadingDetails) {
215
242
  return /* @__PURE__ */ jsx(Main, { "aria-busy": isLoadingDetails, children: /* @__PURE__ */ jsx(LoadingIndicatorPage, {}) });
216
243
  }
@@ -316,6 +343,10 @@ const ReleaseDetailsLayout = ({
316
343
  ]
317
344
  }
318
345
  ),
346
+ /* @__PURE__ */ jsx(Button, { size: "S", variant: "tertiary", onClick: handleRefresh, children: formatMessage({
347
+ id: "content-releases.header.actions.refresh",
348
+ defaultMessage: "Refresh"
349
+ }) }),
319
350
  /* @__PURE__ */ jsx(CheckPermissions, { permissions: PERMISSIONS.publish, children: /* @__PURE__ */ jsx(
320
351
  Button,
321
352
  {
@@ -409,6 +440,8 @@ const ReleaseDetailsBody = () => {
409
440
  }
410
441
  const releaseActions = data?.data;
411
442
  const releaseMeta = data?.meta;
443
+ const contentTypes = releaseMeta?.contentTypes || {};
444
+ const components = releaseMeta?.components || {};
412
445
  if (isReleaseError || !release) {
413
446
  const errorsArray = [];
414
447
  if (releaseError) {
@@ -555,11 +588,11 @@ const ReleaseDetailsBody = () => {
555
588
  )
556
589
  ] }),
557
590
  /* @__PURE__ */ jsx(Table.LoadingBody, {}),
558
- /* @__PURE__ */ jsx(Table.Body, { children: releaseActions[key].map(({ id, type, entry }) => /* @__PURE__ */ jsxs(Tr, { children: [
559
- /* @__PURE__ */ jsx(Td, { width: "25%", children: /* @__PURE__ */ jsx(Typography, { ellipsis: true, children: `${entry.contentType.mainFieldValue || entry.id}` }) }),
560
- /* @__PURE__ */ jsx(Td, { children: /* @__PURE__ */ jsx(Typography, { children: `${entry?.locale?.name ? entry.locale.name : "-"}` }) }),
561
- /* @__PURE__ */ jsx(Td, { children: /* @__PURE__ */ jsx(Typography, { children: entry.contentType.displayName || "" }) }),
562
- /* @__PURE__ */ jsx(Td, { children: release.releasedAt ? /* @__PURE__ */ jsx(Typography, { children: formatMessage(
591
+ /* @__PURE__ */ jsx(Table.Body, { children: releaseActions[key].map(({ id, contentType, locale, type, entry }) => /* @__PURE__ */ jsxs(Tr, { children: [
592
+ /* @__PURE__ */ jsx(Td, { width: "25%", maxWidth: "200px", children: /* @__PURE__ */ jsx(Typography, { ellipsis: true, children: `${contentType.mainFieldValue || entry.id}` }) }),
593
+ /* @__PURE__ */ jsx(Td, { width: "10%", children: /* @__PURE__ */ jsx(Typography, { children: `${locale?.name ? locale.name : "-"}` }) }),
594
+ /* @__PURE__ */ jsx(Td, { width: "10%", children: /* @__PURE__ */ jsx(Typography, { children: contentType.displayName || "" }) }),
595
+ /* @__PURE__ */ jsx(Td, { width: "20%", children: release.releasedAt ? /* @__PURE__ */ jsx(Typography, { children: formatMessage(
563
596
  {
564
597
  id: "content-releases.page.ReleaseDetails.table.action-published",
565
598
  defaultMessage: "This entry was <b>{isPublish, select, true {published} other {unpublished}}</b>."
@@ -577,8 +610,32 @@ const ReleaseDetailsBody = () => {
577
610
  }
578
611
  ) }),
579
612
  !release.releasedAt && /* @__PURE__ */ jsxs(Fragment, { children: [
580
- /* @__PURE__ */ jsx(Td, { children: /* @__PURE__ */ jsx(EntryValidationText, { status: entry.status, action: type }) }),
581
- /* @__PURE__ */ jsx(Td, { children: /* @__PURE__ */ jsx(Flex, { justifyContent: "flex-end", children: /* @__PURE__ */ jsx(ReleaseActionMenu, { releaseId, actionId: id }) }) })
613
+ /* @__PURE__ */ jsx(Td, { width: "20%", minWidth: "200px", children: /* @__PURE__ */ jsx(
614
+ EntryValidationText,
615
+ {
616
+ action: type,
617
+ schema: contentTypes?.[contentType.uid],
618
+ components,
619
+ entry
620
+ }
621
+ ) }),
622
+ /* @__PURE__ */ jsx(Td, { children: /* @__PURE__ */ jsx(Flex, { justifyContent: "flex-end", children: /* @__PURE__ */ jsxs(ReleaseActionMenu.Root, { children: [
623
+ /* @__PURE__ */ jsx(
624
+ ReleaseActionMenu.ReleaseActionEntryLinkItem,
625
+ {
626
+ contentTypeUid: contentType.uid,
627
+ entryId: entry.id,
628
+ locale: locale?.code
629
+ }
630
+ ),
631
+ /* @__PURE__ */ jsx(
632
+ ReleaseActionMenu.DeleteReleaseActionItem,
633
+ {
634
+ releaseId: release.id,
635
+ actionId: id
636
+ }
637
+ )
638
+ ] }) }) })
582
639
  ] })
583
640
  ] }, id)) })
584
641
  ] })
@@ -791,6 +848,7 @@ const INITIAL_FORM_VALUES = {
791
848
  name: ""
792
849
  };
793
850
  const ReleasesPage = () => {
851
+ const tabRef = React.useRef(null);
794
852
  const location = useLocation();
795
853
  const [releaseModalShown, setReleaseModalShown] = React.useState(false);
796
854
  const toggleNotification = useNotification();
@@ -801,6 +859,8 @@ const ReleasesPage = () => {
801
859
  const response = useGetReleasesQuery(query);
802
860
  const [createRelease, { isLoading: isSubmittingForm }] = useCreateReleaseMutation();
803
861
  const { isLoading, isSuccess, isError } = response;
862
+ const activeTab = response?.currentData?.meta?.activeTab || "pending";
863
+ const activeTabIndex = ["pending", "done"].indexOf(activeTab);
804
864
  React.useEffect(() => {
805
865
  if (location?.state?.errors) {
806
866
  toggleNotification({
@@ -817,6 +877,11 @@ const ReleasesPage = () => {
817
877
  replace({ state: null });
818
878
  }
819
879
  }, [formatMessage, location?.state?.errors, replace, toggleNotification]);
880
+ React.useEffect(() => {
881
+ if (tabRef.current) {
882
+ tabRef.current._handlers.setSelectedTabIndex(activeTabIndex);
883
+ }
884
+ }, [activeTabIndex]);
820
885
  const toggleAddReleaseModal = () => {
821
886
  setReleaseModalShown((prev) => !prev);
822
887
  };
@@ -836,7 +901,6 @@ const ReleasesPage = () => {
836
901
  }
837
902
  });
838
903
  };
839
- const activeTab = response?.currentData?.meta?.activeTab || "pending";
840
904
  const handleAddRelease = async (values) => {
841
905
  const response2 = await createRelease({
842
906
  name: values.name
@@ -872,8 +936,9 @@ const ReleasesPage = () => {
872
936
  defaultMessage: "Releases list"
873
937
  }),
874
938
  variant: "simple",
875
- initialSelectedTabIndex: ["pending", "done"].indexOf(activeTab),
939
+ initialSelectedTabIndex: activeTabIndex,
876
940
  onTabChange: handleTabChange,
941
+ ref: tabRef,
877
942
  children: [
878
943
  /* @__PURE__ */ jsxs(Box, { paddingBottom: 8, children: [
879
944
  /* @__PURE__ */ jsxs(Tabs, { children: [
@@ -947,4 +1012,4 @@ const App = () => {
947
1012
  export {
948
1013
  App
949
1014
  };
950
- //# sourceMappingURL=App-J4jrthEu.mjs.map
1015
+ //# sourceMappingURL=App-L1jSxCiL.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"App-L1jSxCiL.mjs","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 })\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} 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[4]};\n height: ${({ theme }) => theme.spaces[4]};\n path {\n fill: ${({ theme }) => theme.colors.neutral600};\n }\n`;\n\nconst TrashIcon = styled(Trash)`\n width: ${({ theme }) => theme.spaces[4]};\n height: ${({ theme }) => theme.spaces[4]};\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\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 } 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 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 createdBy = release.createdBy.lastname\n ? `${release.createdBy.firstname} ${release.createdBy.lastname}`\n : `${release.createdBy.firstname}`;\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 actions',\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: ' by {createdBy}',\n },\n { createdBy }\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 ) => {\n const response = await updateReleaseAction({\n params: {\n releaseId,\n actionId,\n },\n body: {\n type: e.target.value as ReleaseAction['type'],\n },\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.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>\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(({ id, contentType, locale, type, entry }) => (\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)}\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 </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\nimport {\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} 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 * ReleasesLayout\n * -----------------------------------------------------------------------------------------------*/\ninterface ReleasesLayoutProps {\n isLoading?: boolean;\n totalReleases?: number;\n onClickAddRelease: () => void;\n children: React.ReactNode;\n}\n\nexport const ReleasesLayout = ({\n isLoading,\n totalReleases,\n onClickAddRelease,\n children,\n}: ReleasesLayoutProps) => {\n const { formatMessage } = useIntl();\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={\n !isLoading &&\n formatMessage(\n {\n id: 'content-releases.pages.Releases.header-subtitle',\n defaultMessage:\n '{number, plural, =0 {No releases} one {# release} other {# releases}}',\n },\n { number: totalReleases }\n )\n }\n primaryAction={\n <CheckPermissions permissions={PERMISSIONS.create}>\n <Button startIcon={<Plus />} onClick={onClickAddRelease}>\n {formatMessage({\n id: 'content-releases.header.actions.add-release',\n defaultMessage: 'New release',\n })}\n </Button>\n </CheckPermissions>\n }\n />\n {children}\n </Main>\n );\n};\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 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\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 <ReleasesLayout onClickAddRelease={toggleAddReleaseModal} isLoading>\n <ContentLayout>\n <LoadingIndicatorPage />\n </ContentLayout>\n </ReleasesLayout>\n );\n }\n\n const totalReleases = (isSuccess && response.currentData?.meta?.pagination?.total) || 0;\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 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 <ReleasesLayout onClickAddRelease={toggleAddReleaseModal} totalReleases={totalReleases}>\n <ContentLayout>\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 </ReleasesLayout>\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":["ReactRouterLink","Link","response"],"mappings":"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"}
@@ -3,8 +3,9 @@ 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-PEkKIRyJ.js");
6
+ const index = require("./index-KJa1Rb5F.js");
7
7
  const React = require("react");
8
+ const strapiAdmin = require("@strapi/admin/strapi-admin");
8
9
  const designSystem = require("@strapi/design-system");
9
10
  const v2 = require("@strapi/design-system/v2");
10
11
  const icons = require("@strapi/icons");
@@ -15,6 +16,7 @@ const yup = require("yup");
15
16
  require("@reduxjs/toolkit/query");
16
17
  require("axios");
17
18
  require("@reduxjs/toolkit/query/react");
19
+ require("react-redux");
18
20
  const _interopDefault = (e) => e && e.__esModule ? e : { default: e };
19
21
  function _interopNamespace(e) {
20
22
  if (e && e.__esModule)
@@ -137,6 +139,9 @@ const TrashIcon = styled__default.default(icons.Trash)`
137
139
  fill: ${({ theme }) => theme.colors.danger600};
138
140
  }
139
141
  `;
142
+ const TypographyMaxWidth = styled__default.default(designSystem.Typography)`
143
+ max-width: 300px;
144
+ `;
140
145
  const PopoverButton = ({ onClick, disabled, children }) => {
141
146
  return /* @__PURE__ */ jsxRuntime.jsx(
142
147
  StyledFlex,
@@ -155,12 +160,30 @@ const PopoverButton = ({ onClick, disabled, children }) => {
155
160
  }
156
161
  );
157
162
  };
158
- const EntryValidationText = ({ status, action }) => {
163
+ const EntryValidationText = ({ action, schema, components, entry }) => {
159
164
  const { formatMessage } = reactIntl.useIntl();
165
+ const { validate } = strapiAdmin.unstable_useDocument();
166
+ const { errors } = validate(entry, {
167
+ contentType: schema,
168
+ components,
169
+ isCreatingEntry: false
170
+ });
171
+ if (Object.keys(errors).length > 0) {
172
+ const validationErrorsMessages = Object.entries(errors).map(
173
+ ([key, value]) => formatMessage(
174
+ { id: `${value.id}.withField`, defaultMessage: value.defaultMessage },
175
+ { field: key }
176
+ )
177
+ ).join(" ");
178
+ return /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { gap: 2, children: [
179
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Icon, { color: "danger600", as: icons.CrossCircle }),
180
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Tooltip, { description: validationErrorsMessages, children: /* @__PURE__ */ jsxRuntime.jsx(TypographyMaxWidth, { textColor: "danger600", variant: "omega", fontWeight: "semiBold", ellipsis: true, children: validationErrorsMessages }) })
181
+ ] });
182
+ }
160
183
  if (action == "publish") {
161
184
  return /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { gap: 2, children: [
162
185
  /* @__PURE__ */ jsxRuntime.jsx(designSystem.Icon, { color: "success600", as: icons.CheckCircle }),
163
- status === "published" ? /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { textColor: "success600", fontWeight: "bold", children: formatMessage({
186
+ entry.publishedAt ? /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { textColor: "success600", fontWeight: "bold", children: formatMessage({
164
187
  id: "content-releases.pages.ReleaseDetails.entry-validation.already-published",
165
188
  defaultMessage: "Already published"
166
189
  }) }) : /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { children: formatMessage({
@@ -171,7 +194,7 @@ const EntryValidationText = ({ status, action }) => {
171
194
  }
172
195
  return /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { gap: 2, children: [
173
196
  /* @__PURE__ */ jsxRuntime.jsx(designSystem.Icon, { color: "success600", as: icons.CheckCircle }),
174
- status === "draft" ? /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { textColor: "success600", fontWeight: "bold", children: formatMessage({
197
+ !entry.publishedAt ? /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { textColor: "success600", fontWeight: "bold", children: formatMessage({
175
198
  id: "content-releases.pages.ReleaseDetails.entry-validation.already-unpublished",
176
199
  defaultMessage: "Already unpublished"
177
200
  }) }) : /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { children: formatMessage({
@@ -201,6 +224,7 @@ const ReleaseDetailsLayout = ({
201
224
  const {
202
225
  allowedActions: { canUpdate, canDelete }
203
226
  } = helperPlugin.useRBAC(index.PERMISSIONS);
227
+ const dispatch = index.useTypedDispatch();
204
228
  const release = data?.data;
205
229
  const handleTogglePopover = () => {
206
230
  setIsPopoverVisible((prev) => !prev);
@@ -235,6 +259,9 @@ const ReleaseDetailsLayout = ({
235
259
  toggleWarningSubmit();
236
260
  handleTogglePopover();
237
261
  };
262
+ const handleRefresh = () => {
263
+ dispatch(index.releaseApi.util.invalidateTags([{ type: "ReleaseAction", id: "LIST" }]));
264
+ };
238
265
  if (isLoadingDetails) {
239
266
  return /* @__PURE__ */ jsxRuntime.jsx(designSystem.Main, { "aria-busy": isLoadingDetails, children: /* @__PURE__ */ jsxRuntime.jsx(helperPlugin.LoadingIndicatorPage, {}) });
240
267
  }
@@ -340,6 +367,10 @@ const ReleaseDetailsLayout = ({
340
367
  ]
341
368
  }
342
369
  ),
370
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Button, { size: "S", variant: "tertiary", onClick: handleRefresh, children: formatMessage({
371
+ id: "content-releases.header.actions.refresh",
372
+ defaultMessage: "Refresh"
373
+ }) }),
343
374
  /* @__PURE__ */ jsxRuntime.jsx(helperPlugin.CheckPermissions, { permissions: index.PERMISSIONS.publish, children: /* @__PURE__ */ jsxRuntime.jsx(
344
375
  designSystem.Button,
345
376
  {
@@ -433,6 +464,8 @@ const ReleaseDetailsBody = () => {
433
464
  }
434
465
  const releaseActions = data?.data;
435
466
  const releaseMeta = data?.meta;
467
+ const contentTypes = releaseMeta?.contentTypes || {};
468
+ const components = releaseMeta?.components || {};
436
469
  if (isReleaseError || !release) {
437
470
  const errorsArray = [];
438
471
  if (releaseError) {
@@ -579,11 +612,11 @@ const ReleaseDetailsBody = () => {
579
612
  )
580
613
  ] }),
581
614
  /* @__PURE__ */ jsxRuntime.jsx(helperPlugin.Table.LoadingBody, {}),
582
- /* @__PURE__ */ jsxRuntime.jsx(helperPlugin.Table.Body, { children: releaseActions[key].map(({ id, type, entry }) => /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Tr, { children: [
583
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Td, { width: "25%", children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { ellipsis: true, children: `${entry.contentType.mainFieldValue || entry.id}` }) }),
584
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Td, { children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { children: `${entry?.locale?.name ? entry.locale.name : "-"}` }) }),
585
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Td, { children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { children: entry.contentType.displayName || "" }) }),
586
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Td, { children: release.releasedAt ? /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { children: formatMessage(
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(
587
620
  {
588
621
  id: "content-releases.page.ReleaseDetails.table.action-published",
589
622
  defaultMessage: "This entry was <b>{isPublish, select, true {published} other {unpublished}}</b>."
@@ -601,8 +634,32 @@ const ReleaseDetailsBody = () => {
601
634
  }
602
635
  ) }),
603
636
  !release.releasedAt && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
604
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Td, { children: /* @__PURE__ */ jsxRuntime.jsx(EntryValidationText, { status: entry.status, action: type }) }),
605
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Td, { children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Flex, { justifyContent: "flex-end", children: /* @__PURE__ */ jsxRuntime.jsx(index.ReleaseActionMenu, { releaseId, actionId: id }) }) })
637
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Td, { width: "20%", minWidth: "200px", children: /* @__PURE__ */ jsxRuntime.jsx(
638
+ EntryValidationText,
639
+ {
640
+ action: type,
641
+ schema: contentTypes?.[contentType.uid],
642
+ components,
643
+ entry
644
+ }
645
+ ) }),
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,
657
+ {
658
+ releaseId: release.id,
659
+ actionId: id
660
+ }
661
+ )
662
+ ] }) }) })
606
663
  ] })
607
664
  ] }, id)) })
608
665
  ] })
@@ -815,6 +872,7 @@ const INITIAL_FORM_VALUES = {
815
872
  name: ""
816
873
  };
817
874
  const ReleasesPage = () => {
875
+ const tabRef = React__namespace.useRef(null);
818
876
  const location = reactRouterDom.useLocation();
819
877
  const [releaseModalShown, setReleaseModalShown] = React__namespace.useState(false);
820
878
  const toggleNotification = helperPlugin.useNotification();
@@ -825,6 +883,8 @@ const ReleasesPage = () => {
825
883
  const response = index.useGetReleasesQuery(query);
826
884
  const [createRelease, { isLoading: isSubmittingForm }] = index.useCreateReleaseMutation();
827
885
  const { isLoading, isSuccess, isError } = response;
886
+ const activeTab = response?.currentData?.meta?.activeTab || "pending";
887
+ const activeTabIndex = ["pending", "done"].indexOf(activeTab);
828
888
  React__namespace.useEffect(() => {
829
889
  if (location?.state?.errors) {
830
890
  toggleNotification({
@@ -841,6 +901,11 @@ const ReleasesPage = () => {
841
901
  replace({ state: null });
842
902
  }
843
903
  }, [formatMessage, location?.state?.errors, replace, toggleNotification]);
904
+ React__namespace.useEffect(() => {
905
+ if (tabRef.current) {
906
+ tabRef.current._handlers.setSelectedTabIndex(activeTabIndex);
907
+ }
908
+ }, [activeTabIndex]);
844
909
  const toggleAddReleaseModal = () => {
845
910
  setReleaseModalShown((prev) => !prev);
846
911
  };
@@ -860,7 +925,6 @@ const ReleasesPage = () => {
860
925
  }
861
926
  });
862
927
  };
863
- const activeTab = response?.currentData?.meta?.activeTab || "pending";
864
928
  const handleAddRelease = async (values) => {
865
929
  const response2 = await createRelease({
866
930
  name: values.name
@@ -896,8 +960,9 @@ const ReleasesPage = () => {
896
960
  defaultMessage: "Releases list"
897
961
  }),
898
962
  variant: "simple",
899
- initialSelectedTabIndex: ["pending", "done"].indexOf(activeTab),
963
+ initialSelectedTabIndex: activeTabIndex,
900
964
  onTabChange: handleTabChange,
965
+ ref: tabRef,
901
966
  children: [
902
967
  /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Box, { paddingBottom: 8, children: [
903
968
  /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Tabs, { children: [
@@ -969,4 +1034,4 @@ const App = () => {
969
1034
  ] }) });
970
1035
  };
971
1036
  exports.App = App;
972
- //# sourceMappingURL=App-5PRKHpa2.js.map
1037
+ //# sourceMappingURL=App-_20W9dYa.js.map