@strapi/content-releases 0.0.0-next.78ea7925e0dad75936ae2e937a041a0666e3d65a → 0.0.0-next.7f1333f1967e625c57ab16648c057aea08c9dddb

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (140) hide show
  1. package/LICENSE +17 -1
  2. package/dist/_chunks/{App-p8aKBitd.js → App-BKB1esYS.js} +600 -551
  3. package/dist/_chunks/App-BKB1esYS.js.map +1 -0
  4. package/dist/_chunks/{App-bpzO2Ljh.mjs → App-Cne--1Z8.mjs} +582 -531
  5. package/dist/_chunks/App-Cne--1Z8.mjs.map +1 -0
  6. package/dist/_chunks/{PurchaseContentReleases-YhAPgpG9.js → PurchaseContentReleases-Be3acS2L.js} +8 -7
  7. package/dist/_chunks/PurchaseContentReleases-Be3acS2L.js.map +1 -0
  8. package/dist/_chunks/{PurchaseContentReleases-Clm0iACO.mjs → PurchaseContentReleases-_MxP6-Dt.mjs} +9 -8
  9. package/dist/_chunks/PurchaseContentReleases-_MxP6-Dt.mjs.map +1 -0
  10. package/dist/_chunks/ReleasesSettingsPage-C1WwGWIH.mjs +178 -0
  11. package/dist/_chunks/ReleasesSettingsPage-C1WwGWIH.mjs.map +1 -0
  12. package/dist/_chunks/ReleasesSettingsPage-kuXIwpWp.js +178 -0
  13. package/dist/_chunks/ReleasesSettingsPage-kuXIwpWp.js.map +1 -0
  14. package/dist/_chunks/{en-gcJJ5htG.js → en-CmYoEnA7.js} +19 -4
  15. package/dist/_chunks/en-CmYoEnA7.js.map +1 -0
  16. package/dist/_chunks/{en-WuuhP6Bn.mjs → en-D0yVZFqf.mjs} +19 -4
  17. package/dist/_chunks/en-D0yVZFqf.mjs.map +1 -0
  18. package/dist/_chunks/index-5Odi61vw.js +1381 -0
  19. package/dist/_chunks/index-5Odi61vw.js.map +1 -0
  20. package/dist/_chunks/index-Cy7qwpaU.mjs +1362 -0
  21. package/dist/_chunks/index-Cy7qwpaU.mjs.map +1 -0
  22. package/dist/_chunks/schemas-BE1LxE9J.js +62 -0
  23. package/dist/_chunks/schemas-BE1LxE9J.js.map +1 -0
  24. package/dist/_chunks/schemas-DdA2ic2U.mjs +44 -0
  25. package/dist/_chunks/schemas-DdA2ic2U.mjs.map +1 -0
  26. package/dist/admin/index.js +1 -15
  27. package/dist/admin/index.js.map +1 -1
  28. package/dist/admin/index.mjs +2 -16
  29. package/dist/admin/index.mjs.map +1 -1
  30. package/dist/admin/src/components/RelativeTime.d.ts +28 -0
  31. package/dist/admin/src/components/ReleaseAction.d.ts +3 -0
  32. package/dist/admin/src/components/ReleaseActionMenu.d.ts +26 -0
  33. package/dist/admin/src/components/ReleaseActionModal.d.ts +24 -0
  34. package/dist/admin/src/components/ReleaseActionOptions.d.ts +9 -0
  35. package/dist/admin/src/components/ReleaseListCell.d.ts +28 -0
  36. package/dist/admin/src/components/ReleaseModal.d.ts +17 -0
  37. package/dist/admin/src/components/ReleasesPanel.d.ts +3 -0
  38. package/dist/admin/src/constants.d.ts +76 -0
  39. package/dist/admin/src/index.d.ts +3 -0
  40. package/dist/admin/src/modules/hooks.d.ts +7 -0
  41. package/dist/admin/src/pages/App.d.ts +1 -0
  42. package/dist/admin/src/pages/PurchaseContentReleases.d.ts +2 -0
  43. package/dist/admin/src/pages/ReleaseDetailsPage.d.ts +2 -0
  44. package/dist/admin/src/pages/ReleasesPage.d.ts +8 -0
  45. package/dist/admin/src/pages/ReleasesSettingsPage.d.ts +1 -0
  46. package/dist/admin/src/pages/tests/mockReleaseDetailsPageData.d.ts +181 -0
  47. package/dist/admin/src/pages/tests/mockReleasesPageData.d.ts +39 -0
  48. package/dist/admin/src/pluginId.d.ts +1 -0
  49. package/dist/admin/src/services/release.d.ts +112 -0
  50. package/dist/admin/src/store/hooks.d.ts +7 -0
  51. package/dist/admin/src/utils/api.d.ts +6 -0
  52. package/dist/admin/src/utils/prefixPluginTranslations.d.ts +3 -0
  53. package/dist/admin/src/utils/time.d.ts +10 -0
  54. package/dist/admin/src/validation/schemas.d.ts +6 -0
  55. package/dist/server/index.js +974 -665
  56. package/dist/server/index.js.map +1 -1
  57. package/dist/server/index.mjs +975 -665
  58. package/dist/server/index.mjs.map +1 -1
  59. package/dist/server/src/bootstrap.d.ts +5 -0
  60. package/dist/server/src/bootstrap.d.ts.map +1 -0
  61. package/dist/server/src/constants.d.ts +21 -0
  62. package/dist/server/src/constants.d.ts.map +1 -0
  63. package/dist/server/src/content-types/index.d.ts +97 -0
  64. package/dist/server/src/content-types/index.d.ts.map +1 -0
  65. package/dist/server/src/content-types/release/index.d.ts +48 -0
  66. package/dist/server/src/content-types/release/index.d.ts.map +1 -0
  67. package/dist/server/src/content-types/release/schema.d.ts +47 -0
  68. package/dist/server/src/content-types/release/schema.d.ts.map +1 -0
  69. package/dist/server/src/content-types/release-action/index.d.ts +48 -0
  70. package/dist/server/src/content-types/release-action/index.d.ts.map +1 -0
  71. package/dist/server/src/content-types/release-action/schema.d.ts +47 -0
  72. package/dist/server/src/content-types/release-action/schema.d.ts.map +1 -0
  73. package/dist/server/src/controllers/index.d.ts +25 -0
  74. package/dist/server/src/controllers/index.d.ts.map +1 -0
  75. package/dist/server/src/controllers/release-action.d.ts +10 -0
  76. package/dist/server/src/controllers/release-action.d.ts.map +1 -0
  77. package/dist/server/src/controllers/release.d.ts +18 -0
  78. package/dist/server/src/controllers/release.d.ts.map +1 -0
  79. package/dist/server/src/controllers/settings.d.ts +11 -0
  80. package/dist/server/src/controllers/settings.d.ts.map +1 -0
  81. package/dist/server/src/controllers/validation/release-action.d.ts +14 -0
  82. package/dist/server/src/controllers/validation/release-action.d.ts.map +1 -0
  83. package/dist/server/src/controllers/validation/release.d.ts +4 -0
  84. package/dist/server/src/controllers/validation/release.d.ts.map +1 -0
  85. package/dist/server/src/controllers/validation/settings.d.ts +3 -0
  86. package/dist/server/src/controllers/validation/settings.d.ts.map +1 -0
  87. package/dist/server/src/destroy.d.ts +5 -0
  88. package/dist/server/src/destroy.d.ts.map +1 -0
  89. package/dist/server/src/index.d.ts +2115 -0
  90. package/dist/server/src/index.d.ts.map +1 -0
  91. package/dist/server/src/middlewares/documents.d.ts +6 -0
  92. package/dist/server/src/middlewares/documents.d.ts.map +1 -0
  93. package/dist/server/src/migrations/database/5.0.0-document-id-in-actions.d.ts +9 -0
  94. package/dist/server/src/migrations/database/5.0.0-document-id-in-actions.d.ts.map +1 -0
  95. package/dist/server/src/migrations/index.d.ts +13 -0
  96. package/dist/server/src/migrations/index.d.ts.map +1 -0
  97. package/dist/server/src/register.d.ts +5 -0
  98. package/dist/server/src/register.d.ts.map +1 -0
  99. package/dist/server/src/routes/index.d.ts +51 -0
  100. package/dist/server/src/routes/index.d.ts.map +1 -0
  101. package/dist/server/src/routes/release-action.d.ts +18 -0
  102. package/dist/server/src/routes/release-action.d.ts.map +1 -0
  103. package/dist/server/src/routes/release.d.ts +18 -0
  104. package/dist/server/src/routes/release.d.ts.map +1 -0
  105. package/dist/server/src/routes/settings.d.ts +18 -0
  106. package/dist/server/src/routes/settings.d.ts.map +1 -0
  107. package/dist/server/src/services/index.d.ts +1828 -0
  108. package/dist/server/src/services/index.d.ts.map +1 -0
  109. package/dist/server/src/services/release-action.d.ts +38 -0
  110. package/dist/server/src/services/release-action.d.ts.map +1 -0
  111. package/dist/server/src/services/release.d.ts +31 -0
  112. package/dist/server/src/services/release.d.ts.map +1 -0
  113. package/dist/server/src/services/scheduling.d.ts +18 -0
  114. package/dist/server/src/services/scheduling.d.ts.map +1 -0
  115. package/dist/server/src/services/settings.d.ts +13 -0
  116. package/dist/server/src/services/settings.d.ts.map +1 -0
  117. package/dist/server/src/services/validation.d.ts +18 -0
  118. package/dist/server/src/services/validation.d.ts.map +1 -0
  119. package/dist/server/src/utils/index.d.ts +35 -0
  120. package/dist/server/src/utils/index.d.ts.map +1 -0
  121. package/dist/shared/contracts/release-actions.d.ts +130 -0
  122. package/dist/shared/contracts/release-actions.d.ts.map +1 -0
  123. package/dist/shared/contracts/releases.d.ts +184 -0
  124. package/dist/shared/contracts/releases.d.ts.map +1 -0
  125. package/dist/shared/contracts/settings.d.ts +39 -0
  126. package/dist/shared/contracts/settings.d.ts.map +1 -0
  127. package/dist/shared/types.d.ts +24 -0
  128. package/dist/shared/types.d.ts.map +1 -0
  129. package/package.json +33 -38
  130. package/dist/_chunks/App-bpzO2Ljh.mjs.map +0 -1
  131. package/dist/_chunks/App-p8aKBitd.js.map +0 -1
  132. package/dist/_chunks/PurchaseContentReleases-Clm0iACO.mjs.map +0 -1
  133. package/dist/_chunks/PurchaseContentReleases-YhAPgpG9.js.map +0 -1
  134. package/dist/_chunks/en-WuuhP6Bn.mjs.map +0 -1
  135. package/dist/_chunks/en-gcJJ5htG.js.map +0 -1
  136. package/dist/_chunks/index-AECgcaDa.mjs +0 -1013
  137. package/dist/_chunks/index-AECgcaDa.mjs.map +0 -1
  138. package/dist/_chunks/index-fP3qoWZ4.js +0 -1034
  139. package/dist/_chunks/index-fP3qoWZ4.js.map +0 -1
  140. package/strapi-server.js +0 -3
@@ -1,45 +1,54 @@
1
- import { jsxs, jsx, Fragment } from "react/jsx-runtime";
2
- import { RelativeTime, useNotification, useAPIErrorHandler, useQueryParams, useTracking, LoadingIndicatorPage, CheckPermissions, PageSizeURLQuery, PaginationURLQuery, AnErrorOccurred, ConfirmDialog, useRBAC, NoContent, Table, CheckPagePermissions } from "@strapi/helper-plugin";
3
- import { useLocation, useHistory, useParams, Redirect, Link as Link$2, Switch, Route } from "react-router-dom";
4
- import { g as getTimezoneOffset, p as pluginId, u as useGetReleasesQuery, a as useCreateReleaseMutation, P as PERMISSIONS, i as isAxiosError, b as useGetReleaseQuery, c as useUpdateReleaseMutation, d as useDeleteReleaseMutation, e as usePublishReleaseMutation, f as useTypedDispatch, h as useGetReleaseActionsQuery, j as useUpdateReleaseActionMutation, R as ReleaseActionOptions, k as ReleaseActionMenu, r as releaseApi } from "./index-AECgcaDa.mjs";
1
+ import { jsx, jsxs, Fragment } from "react/jsx-runtime";
2
+ import { useNotification, useAPIErrorHandler, useQueryParams, useTracking, useRBAC, Page, Layouts, Pagination, isFetchError, ConfirmDialog, BackButton, useStrapiApp, Table } from "@strapi/admin/strapi-admin";
3
+ import { useLocation, useNavigate, NavLink, useParams, Navigate, Link as Link$1, Routes, Route } from "react-router-dom";
4
+ import { g as getTimezones, p as pluginId, u as useGetReleasesQuery, a as useGetReleaseSettingsQuery, b as useCreateReleaseMutation, P as PERMISSIONS, c as useGetReleaseQuery, d as useUpdateReleaseMutation, e as useDeleteReleaseMutation, f as usePublishReleaseMutation, h as getTimezoneOffset, i as useGetReleaseActionsQuery, j as useUpdateReleaseActionMutation, R as ReleaseActionOptions, k as ReleaseActionMenu, r as releaseApi } from "./index-Cy7qwpaU.mjs";
5
5
  import * as React from "react";
6
- import { useLicenseLimits, unstable_useDocument } from "@strapi/admin/strapi-admin";
7
- import { ModalLayout, ModalHeader, Typography, ModalBody, Flex, TextInput, Box, Checkbox, DatePicker, TimePicker, ModalFooter, Button, Combobox, ComboboxOption, Alert, Main, HeaderLayout, ContentLayout, TabGroup, Tabs, Tab, Divider, TabPanels, TabPanel, EmptyStateLayout, Grid, GridItem, Badge, Link as Link$1, IconButton, SingleSelect, SingleSelectOption, Tr, Td, Icon, Tooltip } from "@strapi/design-system";
8
- import { Link, Menu, LinkButton } from "@strapi/design-system/v2";
9
- import { Plus, EmptyDocuments, Pencil, Trash, ArrowLeft, More, CrossCircle, CheckCircle } from "@strapi/icons";
10
- import format from "date-fns/format";
6
+ import { unstable_useDocument } from "@strapi/content-manager/strapi-admin";
7
+ import { Modal, Flex, Field, TextInput, Box, Checkbox, Typography, DatePicker, TimePicker, Button, Combobox, ComboboxOption, Link, Alert, Main, Tabs, Divider, EmptyStateLayout, Grid, Badge, MenuItem, SimpleMenu, Dialog, LinkButton, SingleSelect, SingleSelectOption, Tr, Td, Tooltip } from "@strapi/design-system";
8
+ import { Plus, Pencil, Trash, More, CrossCircle, CheckCircle, ArrowsCounterClockwise } from "@strapi/icons";
9
+ import { EmptyDocuments } from "@strapi/icons/symbols";
10
+ import format$1 from "date-fns/format";
11
11
  import { utcToZonedTime, zonedTimeToUtc } from "date-fns-tz";
12
12
  import { useIntl } from "react-intl";
13
- import styled from "styled-components";
14
- import { formatISO, parse } from "date-fns";
13
+ import { styled } from "styled-components";
14
+ import { intervalToDuration, isPast, formatISO, format } from "date-fns";
15
15
  import { Formik, Form, useFormikContext } from "formik";
16
- import * as yup from "yup";
17
- import "@reduxjs/toolkit/query";
18
- import "axios";
19
- import "@reduxjs/toolkit/query/react";
20
- import "react-redux";
21
- const RELEASE_SCHEMA = yup.object().shape({
22
- name: yup.string().trim().required(),
23
- scheduledAt: yup.string().nullable(),
24
- isScheduled: yup.boolean().optional(),
25
- time: yup.string().when("isScheduled", {
26
- is: true,
27
- then: yup.string().trim().required(),
28
- otherwise: yup.string().nullable()
29
- }),
30
- timezone: yup.string().when("isScheduled", {
31
- is: true,
32
- then: yup.string().required().nullable(),
33
- otherwise: yup.string().nullable()
34
- }),
35
- date: yup.string().when("isScheduled", {
36
- is: true,
37
- then: yup.string().required().nullable(),
38
- otherwise: yup.string().nullable()
39
- })
40
- }).required().noUnknown();
16
+ import { R as RELEASE_SCHEMA } from "./schemas-DdA2ic2U.mjs";
17
+ import { useDispatch } from "react-redux";
18
+ import { useLicenseLimits } from "@strapi/admin/strapi-admin/ee";
19
+ const intervals = ["years", "months", "days", "hours", "minutes", "seconds"];
20
+ const RelativeTime$1 = React.forwardRef(
21
+ ({ timestamp, customIntervals = [], ...restProps }, forwardedRef) => {
22
+ const { formatRelativeTime, formatDate, formatTime } = useIntl();
23
+ const interval = intervalToDuration({
24
+ start: timestamp,
25
+ end: Date.now()
26
+ // see https://github.com/date-fns/date-fns/issues/2891 – No idea why it's all partial it returns it every time.
27
+ });
28
+ const unit = intervals.find((intervalUnit) => {
29
+ return interval[intervalUnit] > 0 && Object.keys(interval).includes(intervalUnit);
30
+ });
31
+ const relativeTime = isPast(timestamp) ? -interval[unit] : interval[unit];
32
+ const customInterval = customIntervals.find(
33
+ (custom) => interval[custom.unit] < custom.threshold
34
+ );
35
+ const displayText = customInterval ? customInterval.text : formatRelativeTime(relativeTime, unit, { numeric: "auto" });
36
+ return /* @__PURE__ */ jsx(
37
+ "time",
38
+ {
39
+ ref: forwardedRef,
40
+ dateTime: timestamp.toISOString(),
41
+ role: "time",
42
+ title: `${formatDate(timestamp)} ${formatTime(timestamp)}`,
43
+ ...restProps,
44
+ children: displayText
45
+ }
46
+ );
47
+ }
48
+ );
41
49
  const ReleaseModal = ({
42
50
  handleClose,
51
+ open,
43
52
  handleSubmit,
44
53
  initialValues,
45
54
  isLoading = false
@@ -47,7 +56,6 @@ const ReleaseModal = ({
47
56
  const { formatMessage } = useIntl();
48
57
  const { pathname } = useLocation();
49
58
  const isCreatingRelease = pathname === `/plugins/${pluginId}`;
50
- const IsSchedulingEnabled = window.strapi.future.isEnabled("contentReleasesScheduling");
51
59
  const { timezoneList, systemTimezone = { value: "UTC+00:00-Africa/Abidjan " } } = getTimezones(
52
60
  initialValues.scheduledAt ? new Date(initialValues.scheduledAt) : /* @__PURE__ */ new Date()
53
61
  );
@@ -55,9 +63,8 @@ const ReleaseModal = ({
55
63
  const { date, time, timezone } = values;
56
64
  if (!date || !time || !timezone)
57
65
  return null;
58
- const formattedDate = parse(time, "HH:mm", new Date(date));
59
66
  const timezoneWithoutOffset = timezone.split("&")[1];
60
- return zonedTimeToUtc(formattedDate, timezoneWithoutOffset);
67
+ return zonedTimeToUtc(`${date} ${time}`, timezoneWithoutOffset);
61
68
  };
62
69
  const getTimezoneWithOffset = () => {
63
70
  const currentTimezone = timezoneList.find(
@@ -65,8 +72,8 @@ const ReleaseModal = ({
65
72
  );
66
73
  return currentTimezone?.value || systemTimezone.value;
67
74
  };
68
- return /* @__PURE__ */ jsxs(ModalLayout, { onClose: handleClose, labelledBy: "title", children: [
69
- /* @__PURE__ */ jsx(ModalHeader, { children: /* @__PURE__ */ jsx(Typography, { id: "title", fontWeight: "bold", textColor: "neutral800", children: formatMessage(
75
+ return /* @__PURE__ */ jsx(Modal.Root, { open, onOpenChange: handleClose, children: /* @__PURE__ */ jsxs(Modal.Content, { children: [
76
+ /* @__PURE__ */ jsx(Modal.Header, { children: /* @__PURE__ */ jsx(Modal.Title, { children: formatMessage(
70
77
  {
71
78
  id: "content-releases.modal.title",
72
79
  defaultMessage: "{isCreatingRelease, select, true {New release} other {Edit release}}"
@@ -89,31 +96,33 @@ const ReleaseModal = ({
89
96
  },
90
97
  validationSchema: RELEASE_SCHEMA,
91
98
  validateOnChange: false,
92
- children: ({ values, errors, handleChange, setFieldValue }) => /* @__PURE__ */ jsxs(Form, { children: [
93
- /* @__PURE__ */ jsx(ModalBody, { children: /* @__PURE__ */ jsxs(Flex, { direction: "column", alignItems: "stretch", gap: 6, children: [
94
- /* @__PURE__ */ jsx(
95
- TextInput,
96
- {
97
- label: formatMessage({
98
- id: "content-releases.modal.form.input.label.release-name",
99
- defaultMessage: "Name"
100
- }),
101
- name: "name",
102
- value: values.name,
103
- error: errors.name,
104
- onChange: handleChange,
105
- required: true
106
- }
107
- ),
108
- IsSchedulingEnabled && /* @__PURE__ */ jsxs(Fragment, { children: [
99
+ children: ({ values, errors, handleChange, setFieldValue }) => {
100
+ return /* @__PURE__ */ jsxs(Form, { children: [
101
+ /* @__PURE__ */ jsx(Modal.Body, { children: /* @__PURE__ */ jsxs(Flex, { direction: "column", alignItems: "stretch", gap: 6, children: [
102
+ /* @__PURE__ */ jsxs(
103
+ Field.Root,
104
+ {
105
+ name: "name",
106
+ error: errors.name && formatMessage({ id: errors.name, defaultMessage: errors.name }),
107
+ required: true,
108
+ children: [
109
+ /* @__PURE__ */ jsx(Field.Label, { children: formatMessage({
110
+ id: "content-releases.modal.form.input.label.release-name",
111
+ defaultMessage: "Name"
112
+ }) }),
113
+ /* @__PURE__ */ jsx(TextInput, { value: values.name, onChange: handleChange }),
114
+ /* @__PURE__ */ jsx(Field.Error, {})
115
+ ]
116
+ }
117
+ ),
109
118
  /* @__PURE__ */ jsx(Box, { width: "max-content", children: /* @__PURE__ */ jsx(
110
119
  Checkbox,
111
120
  {
112
121
  name: "isScheduled",
113
- value: values.isScheduled,
114
- onChange: (event) => {
115
- setFieldValue("isScheduled", event.target.checked);
116
- if (!event.target.checked) {
122
+ checked: values.isScheduled,
123
+ onCheckedChange: (checked) => {
124
+ setFieldValue("isScheduled", checked);
125
+ if (!checked) {
117
126
  setFieldValue("date", null);
118
127
  setFieldValue("time", "");
119
128
  setFieldValue("timezone", null);
@@ -141,86 +150,89 @@ const ReleaseModal = ({
141
150
  ) }),
142
151
  values.isScheduled && /* @__PURE__ */ jsxs(Fragment, { children: [
143
152
  /* @__PURE__ */ jsxs(Flex, { gap: 4, alignItems: "start", children: [
144
- /* @__PURE__ */ jsx(Box, { width: "100%", children: /* @__PURE__ */ jsx(
145
- DatePicker,
153
+ /* @__PURE__ */ jsx(Box, { width: "100%", children: /* @__PURE__ */ jsxs(
154
+ Field.Root,
146
155
  {
147
- label: formatMessage({
148
- id: "content-releases.modal.form.input.label.date",
149
- defaultMessage: "Date"
150
- }),
151
156
  name: "date",
152
- error: errors.date,
153
- onChange: (date) => {
154
- const isoFormatDate = date ? formatISO(date, { representation: "date" }) : null;
155
- setFieldValue("date", isoFormatDate);
156
- },
157
- clearLabel: formatMessage({
158
- id: "content-releases.modal.form.input.clearLabel",
159
- defaultMessage: "Clear"
160
- }),
161
- onClear: () => {
162
- setFieldValue("date", null);
163
- },
164
- selectedDate: values.date || void 0,
157
+ error: errors.date && formatMessage({ id: errors.date, defaultMessage: errors.date }),
165
158
  required: true,
166
- minDate: utcToZonedTime(/* @__PURE__ */ new Date(), values.timezone.split("&")[1])
159
+ children: [
160
+ /* @__PURE__ */ jsx(Field.Label, { children: formatMessage({
161
+ id: "content-releases.modal.form.input.label.date",
162
+ defaultMessage: "Date"
163
+ }) }),
164
+ /* @__PURE__ */ jsx(
165
+ DatePicker,
166
+ {
167
+ onChange: (date) => {
168
+ const isoFormatDate = date ? formatISO(date, { representation: "date" }) : null;
169
+ setFieldValue("date", isoFormatDate);
170
+ },
171
+ clearLabel: formatMessage({
172
+ id: "content-releases.modal.form.input.clearLabel",
173
+ defaultMessage: "Clear"
174
+ }),
175
+ onClear: () => {
176
+ setFieldValue("date", null);
177
+ },
178
+ value: values.date ? new Date(values.date) : /* @__PURE__ */ new Date(),
179
+ minDate: utcToZonedTime(/* @__PURE__ */ new Date(), values.timezone.split("&")[1])
180
+ }
181
+ ),
182
+ /* @__PURE__ */ jsx(Field.Error, {})
183
+ ]
167
184
  }
168
185
  ) }),
169
- /* @__PURE__ */ jsx(Box, { width: "100%", children: /* @__PURE__ */ jsx(
170
- TimePicker,
186
+ /* @__PURE__ */ jsx(Box, { width: "100%", children: /* @__PURE__ */ jsxs(
187
+ Field.Root,
171
188
  {
172
- label: formatMessage({
173
- id: "content-releases.modal.form.input.label.time",
174
- defaultMessage: "Time"
175
- }),
176
189
  name: "time",
177
- error: errors.time,
178
- onChange: (time) => {
179
- setFieldValue("time", time);
180
- },
181
- clearLabel: formatMessage({
182
- id: "content-releases.modal.form.input.clearLabel",
183
- defaultMessage: "Clear"
184
- }),
185
- onClear: () => {
186
- setFieldValue("time", "");
187
- },
188
- value: values.time || void 0,
189
- required: true
190
+ error: errors.time && formatMessage({ id: errors.time, defaultMessage: errors.time }),
191
+ required: true,
192
+ children: [
193
+ /* @__PURE__ */ jsx(Field.Label, { children: formatMessage({
194
+ id: "content-releases.modal.form.input.label.time",
195
+ defaultMessage: "Time"
196
+ }) }),
197
+ /* @__PURE__ */ jsx(
198
+ TimePicker,
199
+ {
200
+ onChange: (time) => {
201
+ setFieldValue("time", time);
202
+ },
203
+ clearLabel: formatMessage({
204
+ id: "content-releases.modal.form.input.clearLabel",
205
+ defaultMessage: "Clear"
206
+ }),
207
+ onClear: () => {
208
+ setFieldValue("time", "");
209
+ },
210
+ value: values.time || void 0
211
+ }
212
+ ),
213
+ /* @__PURE__ */ jsx(Field.Error, {})
214
+ ]
190
215
  }
191
216
  ) })
192
217
  ] }),
193
218
  /* @__PURE__ */ jsx(TimezoneComponent, { timezoneOptions: timezoneList })
194
219
  ] })
195
- ] })
196
- ] }) }),
197
- /* @__PURE__ */ jsx(
198
- ModalFooter,
199
- {
200
- startActions: /* @__PURE__ */ jsx(Button, { onClick: handleClose, variant: "tertiary", name: "cancel", children: formatMessage({ id: "cancel", defaultMessage: "Cancel" }) }),
201
- endActions: /* @__PURE__ */ jsx(Button, { name: "submit", loading: isLoading, type: "submit", children: formatMessage(
220
+ ] }) }),
221
+ /* @__PURE__ */ jsxs(Modal.Footer, { children: [
222
+ /* @__PURE__ */ jsx(Modal.Close, { children: /* @__PURE__ */ jsx(Button, { variant: "tertiary", name: "cancel", children: formatMessage({ id: "cancel", defaultMessage: "Cancel" }) }) }),
223
+ /* @__PURE__ */ jsx(Button, { name: "submit", loading: isLoading, type: "submit", children: formatMessage(
202
224
  {
203
225
  id: "content-releases.modal.form.button.submit",
204
226
  defaultMessage: "{isCreatingRelease, select, true {Continue} other {Save}}"
205
227
  },
206
228
  { isCreatingRelease }
207
229
  ) })
208
- }
209
- )
210
- ] })
230
+ ] })
231
+ ] });
232
+ }
211
233
  }
212
234
  )
213
- ] });
214
- };
215
- const getTimezones = (selectedDate) => {
216
- const timezoneList = Intl.supportedValuesOf("timeZone").map((timezone) => {
217
- const utcOffset = getTimezoneOffset(timezone, selectedDate);
218
- return { offset: utcOffset, value: `${utcOffset}&${timezone}` };
219
- });
220
- const systemTimezone = timezoneList.find(
221
- (timezone) => timezone.value.split("&")[1] === Intl.DateTimeFormat().resolvedOptions().timeZone
222
- );
223
- return { timezoneList, systemTimezone };
235
+ ] }) });
224
236
  };
225
237
  const TimezoneComponent = ({ timezoneOptions }) => {
226
238
  const { values, errors, setFieldValue } = useFormikContext();
@@ -236,37 +248,52 @@ const TimezoneComponent = ({ timezoneOptions }) => {
236
248
  }
237
249
  }
238
250
  }, [setFieldValue, values.date, values.timezone]);
239
- return /* @__PURE__ */ jsx(
240
- Combobox,
251
+ return /* @__PURE__ */ jsxs(
252
+ Field.Root,
241
253
  {
242
- label: formatMessage({
243
- id: "content-releases.modal.form.input.label.timezone",
244
- defaultMessage: "Timezone"
245
- }),
246
- autocomplete: { type: "list", filter: "contains" },
247
254
  name: "timezone",
248
- value: values.timezone || void 0,
249
- textValue: values.timezone ? values.timezone.replace(/&/, " ") : void 0,
250
- onChange: (timezone) => {
251
- setFieldValue("timezone", timezone);
252
- },
253
- onTextValueChange: (timezone) => {
254
- setFieldValue("timezone", timezone);
255
- },
256
- onClear: () => {
257
- setFieldValue("timezone", "");
258
- },
259
- error: errors.timezone,
255
+ error: errors.timezone && formatMessage({ id: errors.timezone, defaultMessage: errors.timezone }),
260
256
  required: true,
261
- children: timezoneList.map((timezone) => /* @__PURE__ */ jsx(ComboboxOption, { value: timezone.value, children: timezone.value.replace(/&/, " ") }, timezone.value))
257
+ children: [
258
+ /* @__PURE__ */ jsx(Field.Label, { children: formatMessage({
259
+ id: "content-releases.modal.form.input.label.timezone",
260
+ defaultMessage: "Timezone"
261
+ }) }),
262
+ /* @__PURE__ */ jsx(
263
+ Combobox,
264
+ {
265
+ autocomplete: { type: "list", filter: "contains" },
266
+ value: values.timezone || void 0,
267
+ textValue: values.timezone ? values.timezone.replace(/&/, " ") : void 0,
268
+ onChange: (timezone) => {
269
+ setFieldValue("timezone", timezone);
270
+ },
271
+ onTextValueChange: (timezone) => {
272
+ setFieldValue("timezone", timezone);
273
+ },
274
+ onClear: () => {
275
+ setFieldValue("timezone", "");
276
+ },
277
+ children: timezoneList.map((timezone) => /* @__PURE__ */ jsx(ComboboxOption, { value: timezone.value, children: timezone.value.replace(/&/, " ") }, timezone.value))
278
+ }
279
+ ),
280
+ /* @__PURE__ */ jsx(Field.Error, {})
281
+ ]
262
282
  }
263
283
  );
264
284
  };
285
+ const useTypedDispatch = useDispatch;
286
+ const isBaseQueryError = (error) => {
287
+ return typeof error !== "undefined" && error.name !== void 0;
288
+ };
265
289
  const LinkCard = styled(Link)`
266
290
  display: block;
267
291
  `;
268
- const CapitalizeRelativeTime = styled(RelativeTime)`
269
- text-transform: capitalize;
292
+ const RelativeTime = styled(RelativeTime$1)`
293
+ display: inline-block;
294
+ &::first-letter {
295
+ text-transform: uppercase;
296
+ }
270
297
  `;
271
298
  const getBadgeProps = (status) => {
272
299
  let color;
@@ -295,9 +322,8 @@ const getBadgeProps = (status) => {
295
322
  };
296
323
  const ReleasesGrid = ({ sectionTitle, releases = [], isError = false }) => {
297
324
  const { formatMessage } = useIntl();
298
- const IsSchedulingEnabled = window.strapi.future.isEnabled("contentReleasesScheduling");
299
325
  if (isError) {
300
- return /* @__PURE__ */ jsx(AnErrorOccurred, {});
326
+ return /* @__PURE__ */ jsx(Page.Error, {});
301
327
  }
302
328
  if (releases?.length === 0) {
303
329
  return /* @__PURE__ */ jsx(
@@ -312,11 +338,11 @@ const ReleasesGrid = ({ sectionTitle, releases = [], isError = false }) => {
312
338
  target: sectionTitle
313
339
  }
314
340
  ),
315
- icon: /* @__PURE__ */ jsx(EmptyDocuments, { width: "10rem" })
341
+ icon: /* @__PURE__ */ jsx(EmptyDocuments, { width: "16rem" })
316
342
  }
317
343
  );
318
344
  }
319
- return /* @__PURE__ */ jsx(Grid, { gap: 4, children: releases.map(({ id, name, actions, scheduledAt, status }) => /* @__PURE__ */ jsx(GridItem, { col: 3, s: 6, xs: 12, children: /* @__PURE__ */ jsx(LinkCard, { href: `content-releases/${id}`, isExternal: false, children: /* @__PURE__ */ jsxs(
345
+ return /* @__PURE__ */ jsx(Grid.Root, { gap: 4, children: releases.map(({ id, name, scheduledAt, status }) => /* @__PURE__ */ jsx(Grid.Item, { col: 3, s: 6, xs: 12, direction: "column", alignItems: "stretch", children: /* @__PURE__ */ jsx(LinkCard, { tag: NavLink, to: `${id}`, isExternal: false, children: /* @__PURE__ */ jsxs(
320
346
  Flex,
321
347
  {
322
348
  direction: "column",
@@ -331,17 +357,11 @@ const ReleasesGrid = ({ sectionTitle, releases = [], isError = false }) => {
331
357
  gap: 4,
332
358
  children: [
333
359
  /* @__PURE__ */ jsxs(Flex, { direction: "column", alignItems: "start", gap: 1, children: [
334
- /* @__PURE__ */ jsx(Typography, { as: "h3", variant: "delta", fontWeight: "bold", children: name }),
335
- /* @__PURE__ */ jsx(Typography, { variant: "pi", textColor: "neutral600", children: IsSchedulingEnabled ? scheduledAt ? /* @__PURE__ */ jsx(CapitalizeRelativeTime, { timestamp: new Date(scheduledAt) }) : formatMessage({
360
+ /* @__PURE__ */ jsx(Typography, { textColor: "neutral800", tag: "h3", variant: "delta", fontWeight: "bold", children: name }),
361
+ /* @__PURE__ */ jsx(Typography, { variant: "pi", textColor: "neutral600", children: scheduledAt ? /* @__PURE__ */ jsx(RelativeTime, { timestamp: new Date(scheduledAt) }) : formatMessage({
336
362
  id: "content-releases.pages.Releases.not-scheduled",
337
363
  defaultMessage: "Not scheduled"
338
- }) : formatMessage(
339
- {
340
- id: "content-releases.page.Releases.release-item.entries",
341
- defaultMessage: "{number, plural, =0 {No entries} one {# entry} other {# entries}}"
342
- },
343
- { number: actions.meta.count }
344
- ) })
364
+ }) })
345
365
  ] }),
346
366
  /* @__PURE__ */ jsx(Badge, { ...getBadgeProps(status), children: status })
347
367
  ]
@@ -358,34 +378,35 @@ const StyledAlert = styled(Alert)`
358
378
  `;
359
379
  const INITIAL_FORM_VALUES = {
360
380
  name: "",
361
- date: null,
381
+ date: format(/* @__PURE__ */ new Date(), "yyyy-MM-dd"),
362
382
  time: "",
363
- // Remove future flag check after Scheduling Beta release and replace with true as creating new release should include scheduling by default
364
- isScheduled: window.strapi.future.isEnabled("contentReleasesScheduling"),
383
+ isScheduled: true,
365
384
  scheduledAt: null,
366
385
  timezone: null
367
386
  };
368
387
  const ReleasesPage = () => {
369
- const tabRef = React.useRef(null);
370
388
  const location = useLocation();
371
389
  const [releaseModalShown, setReleaseModalShown] = React.useState(false);
372
- const toggleNotification = useNotification();
390
+ const { toggleNotification } = useNotification();
373
391
  const { formatMessage } = useIntl();
374
- const { push, replace } = useHistory();
392
+ const navigate = useNavigate();
375
393
  const { formatAPIError } = useAPIErrorHandler();
376
394
  const [{ query }, setQuery] = useQueryParams();
377
395
  const response = useGetReleasesQuery(query);
396
+ const { data, isLoading: isLoadingSettings } = useGetReleaseSettingsQuery();
378
397
  const [createRelease, { isLoading: isSubmittingForm }] = useCreateReleaseMutation();
379
398
  const { getFeature } = useLicenseLimits();
380
399
  const { maximumReleases = 3 } = getFeature("cms-content-releases");
381
400
  const { trackUsage } = useTracking();
382
- const { isLoading, isSuccess, isError } = response;
401
+ const {
402
+ allowedActions: { canCreate }
403
+ } = useRBAC(PERMISSIONS);
404
+ const { isLoading: isLoadingReleases, isSuccess, isError } = response;
383
405
  const activeTab = response?.currentData?.meta?.activeTab || "pending";
384
- const activeTabIndex = ["pending", "done"].indexOf(activeTab);
385
406
  React.useEffect(() => {
386
407
  if (location?.state?.errors) {
387
408
  toggleNotification({
388
- type: "warning",
409
+ type: "danger",
389
410
  title: formatMessage({
390
411
  id: "content-releases.pages.Releases.notification.error.title",
391
412
  defaultMessage: "Your request could not be processed."
@@ -395,30 +416,25 @@ const ReleasesPage = () => {
395
416
  defaultMessage: "Please try again or open another release."
396
417
  })
397
418
  });
398
- replace({ state: null });
399
- }
400
- }, [formatMessage, location?.state?.errors, replace, toggleNotification]);
401
- React.useEffect(() => {
402
- if (tabRef.current) {
403
- tabRef.current._handlers.setSelectedTabIndex(activeTabIndex);
419
+ navigate("", { replace: true, state: null });
404
420
  }
405
- }, [activeTabIndex]);
421
+ }, [formatMessage, location?.state?.errors, navigate, toggleNotification]);
406
422
  const toggleAddReleaseModal = () => {
407
423
  setReleaseModalShown((prev) => !prev);
408
424
  };
409
- if (isLoading) {
410
- return /* @__PURE__ */ jsx(Main, { "aria-busy": isLoading, children: /* @__PURE__ */ jsx(LoadingIndicatorPage, {}) });
425
+ if (isLoadingReleases || isLoadingSettings) {
426
+ return /* @__PURE__ */ jsx(Page.Loading, {});
411
427
  }
412
428
  const totalPendingReleases = isSuccess && response.currentData?.meta?.pendingReleasesCount || 0;
413
429
  const hasReachedMaximumPendingReleases = totalPendingReleases >= maximumReleases;
414
- const handleTabChange = (index) => {
430
+ const handleTabChange = (tabValue) => {
415
431
  setQuery({
416
432
  ...query,
417
433
  page: 1,
418
434
  pageSize: response?.currentData?.meta?.pagination?.pageSize || 16,
419
435
  filters: {
420
436
  releasedAt: {
421
- $notNull: index === 0 ? false : true
437
+ $notNull: tabValue !== "pending"
422
438
  }
423
439
  }
424
440
  });
@@ -438,22 +454,22 @@ const ReleasesPage = () => {
438
454
  })
439
455
  });
440
456
  trackUsage("didCreateRelease");
441
- push(`/plugins/content-releases/${response2.data.data.id}`);
442
- } else if (isAxiosError(response2.error)) {
457
+ navigate(response2.data.data.id.toString());
458
+ } else if (isFetchError(response2.error)) {
443
459
  toggleNotification({
444
- type: "warning",
460
+ type: "danger",
445
461
  message: formatAPIError(response2.error)
446
462
  });
447
463
  } else {
448
464
  toggleNotification({
449
- type: "warning",
465
+ type: "danger",
450
466
  message: formatMessage({ id: "notification.error", defaultMessage: "An error occurred" })
451
467
  });
452
468
  }
453
469
  };
454
- return /* @__PURE__ */ jsxs(Main, { "aria-busy": isLoading, children: [
470
+ return /* @__PURE__ */ jsxs(Main, { "aria-busy": isLoadingReleases || isLoadingSettings, children: [
455
471
  /* @__PURE__ */ jsx(
456
- HeaderLayout,
472
+ Layouts.Header,
457
473
  {
458
474
  title: formatMessage({
459
475
  id: "content-releases.pages.Releases.title",
@@ -463,7 +479,7 @@ const ReleasesPage = () => {
463
479
  id: "content-releases.pages.Releases.header-subtitle",
464
480
  defaultMessage: "Create and manage content updates"
465
481
  }),
466
- primaryAction: /* @__PURE__ */ jsx(CheckPermissions, { permissions: PERMISSIONS.create, children: /* @__PURE__ */ jsx(
482
+ primaryAction: canCreate ? /* @__PURE__ */ jsx(
467
483
  Button,
468
484
  {
469
485
  startIcon: /* @__PURE__ */ jsx(Plus, {}),
@@ -474,10 +490,10 @@ const ReleasesPage = () => {
474
490
  defaultMessage: "New release"
475
491
  })
476
492
  }
477
- ) })
493
+ ) : null
478
494
  }
479
495
  ),
480
- /* @__PURE__ */ jsx(ContentLayout, { children: /* @__PURE__ */ jsxs(Fragment, { children: [
496
+ /* @__PURE__ */ jsx(Layouts.Content, { children: /* @__PURE__ */ jsxs(Fragment, { children: [
481
497
  hasReachedMaximumPendingReleases && /* @__PURE__ */ jsx(
482
498
  StyledAlert,
483
499
  {
@@ -502,21 +518,17 @@ const ReleasesPage = () => {
502
518
  })
503
519
  }
504
520
  ),
505
- /* @__PURE__ */ jsxs(
506
- TabGroup,
507
- {
508
- label: formatMessage({
509
- id: "content-releases.pages.Releases.tab-group.label",
510
- defaultMessage: "Releases list"
511
- }),
512
- variant: "simple",
513
- initialSelectedTabIndex: activeTabIndex,
514
- onTabChange: handleTabChange,
515
- ref: tabRef,
516
- children: [
517
- /* @__PURE__ */ jsxs(Box, { paddingBottom: 8, children: [
518
- /* @__PURE__ */ jsxs(Tabs, { children: [
519
- /* @__PURE__ */ jsx(Tab, { children: formatMessage(
521
+ /* @__PURE__ */ jsxs(Tabs.Root, { variant: "simple", onValueChange: handleTabChange, value: activeTab, children: [
522
+ /* @__PURE__ */ jsxs(Box, { paddingBottom: 8, children: [
523
+ /* @__PURE__ */ jsxs(
524
+ Tabs.List,
525
+ {
526
+ "aria-label": formatMessage({
527
+ id: "content-releases.pages.Releases.tab-group.label",
528
+ defaultMessage: "Releases list"
529
+ }),
530
+ children: [
531
+ /* @__PURE__ */ jsx(Tabs.Trigger, { value: "pending", children: formatMessage(
520
532
  {
521
533
  id: "content-releases.pages.Releases.tab.pending",
522
534
  defaultMessage: "Pending ({count})"
@@ -525,59 +537,55 @@ const ReleasesPage = () => {
525
537
  count: totalPendingReleases
526
538
  }
527
539
  ) }),
528
- /* @__PURE__ */ jsx(Tab, { children: formatMessage({
540
+ /* @__PURE__ */ jsx(Tabs.Trigger, { value: "done", children: formatMessage({
529
541
  id: "content-releases.pages.Releases.tab.done",
530
542
  defaultMessage: "Done"
531
543
  }) })
532
- ] }),
533
- /* @__PURE__ */ jsx(Divider, {})
534
- ] }),
535
- /* @__PURE__ */ jsxs(TabPanels, { children: [
536
- /* @__PURE__ */ jsx(TabPanel, { children: /* @__PURE__ */ jsx(
537
- ReleasesGrid,
538
- {
539
- sectionTitle: "pending",
540
- releases: response?.currentData?.data,
541
- isError
542
- }
543
- ) }),
544
- /* @__PURE__ */ jsx(TabPanel, { children: /* @__PURE__ */ jsx(
545
- ReleasesGrid,
546
- {
547
- sectionTitle: "done",
548
- releases: response?.currentData?.data,
549
- isError
550
- }
551
- ) })
552
- ] })
553
- ]
554
- }
555
- ),
556
- response.currentData?.meta?.pagination?.total ? /* @__PURE__ */ jsxs(Flex, { paddingTop: 4, alignItems: "flex-end", justifyContent: "space-between", children: [
557
- /* @__PURE__ */ jsx(
558
- PageSizeURLQuery,
544
+ ]
545
+ }
546
+ ),
547
+ /* @__PURE__ */ jsx(Divider, {})
548
+ ] }),
549
+ /* @__PURE__ */ jsx(Tabs.Content, { value: "pending", children: /* @__PURE__ */ jsx(
550
+ ReleasesGrid,
559
551
  {
560
- options: ["8", "16", "32", "64"],
561
- defaultValue: response?.currentData?.meta?.pagination?.pageSize.toString()
552
+ sectionTitle: "pending",
553
+ releases: response?.currentData?.data,
554
+ isError
562
555
  }
563
- ),
564
- /* @__PURE__ */ jsx(
565
- PaginationURLQuery,
556
+ ) }),
557
+ /* @__PURE__ */ jsx(Tabs.Content, { value: "done", children: /* @__PURE__ */ jsx(
558
+ ReleasesGrid,
566
559
  {
567
- pagination: {
568
- pageCount: response?.currentData?.meta?.pagination?.pageCount || 0
569
- }
560
+ sectionTitle: "done",
561
+ releases: response?.currentData?.data,
562
+ isError
570
563
  }
571
- )
572
- ] }) : null
564
+ ) })
565
+ ] }),
566
+ /* @__PURE__ */ jsxs(
567
+ Pagination.Root,
568
+ {
569
+ ...response?.currentData?.meta?.pagination,
570
+ defaultPageSize: response?.currentData?.meta?.pagination?.pageSize,
571
+ children: [
572
+ /* @__PURE__ */ jsx(Pagination.PageSize, { options: ["8", "16", "32", "64"] }),
573
+ /* @__PURE__ */ jsx(Pagination.Links, {})
574
+ ]
575
+ }
576
+ )
573
577
  ] }) }),
574
- releaseModalShown && /* @__PURE__ */ jsx(
578
+ /* @__PURE__ */ jsx(
575
579
  ReleaseModal,
576
580
  {
581
+ open: releaseModalShown,
577
582
  handleClose: toggleAddReleaseModal,
578
583
  handleSubmit: handleAddRelease,
579
584
  isLoading: isSubmittingForm,
580
- initialValues: INITIAL_FORM_VALUES
585
+ initialValues: {
586
+ ...INITIAL_FORM_VALUES,
587
+ timezone: data?.data.defaultTimezone ? data.data.defaultTimezone.split("&")[1] : null
588
+ }
581
589
  }
582
590
  )
583
591
  ] });
@@ -588,7 +596,7 @@ const ReleaseInfoWrapper = styled(Flex)`
588
596
  border-bottom-left-radius: ${({ theme }) => theme.borderRadius};
589
597
  border-top: 1px solid ${({ theme }) => theme.colors.neutral150};
590
598
  `;
591
- const StyledMenuItem = styled(Menu.Item)`
599
+ const StyledMenuItem = styled(MenuItem)`
592
600
  svg path {
593
601
  fill: ${({ theme, disabled }) => disabled && theme.colors.neutral500};
594
602
  }
@@ -597,19 +605,19 @@ const StyledMenuItem = styled(Menu.Item)`
597
605
  }
598
606
 
599
607
  &:hover {
600
- background: ${({ theme, variant = "neutral" }) => theme.colors[`${variant}100`]};
608
+ background: ${({ theme, $variant = "neutral" }) => theme.colors[`${$variant}100`]};
601
609
  }
602
610
  `;
603
611
  const PencilIcon = styled(Pencil)`
604
- width: ${({ theme }) => theme.spaces[3]};
605
- height: ${({ theme }) => theme.spaces[3]};
612
+ width: ${({ theme }) => theme.spaces[4]};
613
+ height: ${({ theme }) => theme.spaces[4]};
606
614
  path {
607
615
  fill: ${({ theme }) => theme.colors.neutral600};
608
616
  }
609
617
  `;
610
618
  const TrashIcon = styled(Trash)`
611
- width: ${({ theme }) => theme.spaces[3]};
612
- height: ${({ theme }) => theme.spaces[3]};
619
+ width: ${({ theme }) => theme.spaces[4]};
620
+ height: ${({ theme }) => theme.spaces[4]};
613
621
  path {
614
622
  fill: ${({ theme }) => theme.colors.danger600};
615
623
  }
@@ -617,40 +625,93 @@ const TrashIcon = styled(Trash)`
617
625
  const TypographyMaxWidth = styled(Typography)`
618
626
  max-width: 300px;
619
627
  `;
620
- const EntryValidationText = ({ action, schema, components, entry }) => {
628
+ const EntryValidationText = ({ action, schema, entry, status }) => {
621
629
  const { formatMessage } = useIntl();
622
- const { validate } = unstable_useDocument();
623
- const { errors } = validate(entry, {
624
- contentType: schema,
625
- components,
626
- isCreatingEntry: false
627
- });
628
- if (Object.keys(errors).length > 0) {
629
- const validationErrorsMessages = Object.entries(errors).map(
630
- ([key, value]) => formatMessage(
631
- { id: `${value.id}.withField`, defaultMessage: value.defaultMessage },
632
- { field: key }
633
- )
634
- ).join(" ");
635
- return /* @__PURE__ */ jsxs(Flex, { gap: 2, children: [
636
- /* @__PURE__ */ jsx(Icon, { color: "danger600", as: CrossCircle }),
637
- /* @__PURE__ */ jsx(Tooltip, { description: validationErrorsMessages, children: /* @__PURE__ */ jsx(TypographyMaxWidth, { textColor: "danger600", variant: "omega", fontWeight: "semiBold", ellipsis: true, children: validationErrorsMessages }) })
638
- ] });
630
+ const { validate, isLoading } = unstable_useDocument(
631
+ {
632
+ collectionType: schema?.kind ?? "",
633
+ model: schema?.uid ?? ""
634
+ },
635
+ {
636
+ // useDocument makes a request to get more data about the entry, but we only want to have the validation function so we skip the request
637
+ skip: true
638
+ }
639
+ );
640
+ const errorsToString = (errors2, prefix = "") => {
641
+ if (Object.keys(errors2).length === 0) {
642
+ return "";
643
+ }
644
+ return Object.entries(errors2).map(([key, value]) => {
645
+ if (value === void 0 || value === null) {
646
+ return "";
647
+ }
648
+ if (typeof value === "string") {
649
+ return formatMessage(
650
+ { id: value, defaultMessage: value },
651
+ { field: prefix ? `${prefix}.${key}` : key }
652
+ );
653
+ }
654
+ if (typeof value === "object" && value !== null && "id" in value && "defaultMessage" in value) {
655
+ return formatMessage(
656
+ // @ts-expect-error – TODO: default message will be a string
657
+ { id: `${value.id}.withField`, defaultMessage: value.defaultMessage },
658
+ { field: prefix ? `${prefix}.${key}` : key }
659
+ );
660
+ }
661
+ return errorsToString(value, key);
662
+ }).join(" ");
663
+ };
664
+ if (isLoading) {
665
+ return null;
639
666
  }
640
- if (action == "publish") {
641
- return /* @__PURE__ */ jsxs(Flex, { gap: 2, children: [
642
- /* @__PURE__ */ jsx(Icon, { color: "success600", as: CheckCircle }),
643
- entry.publishedAt ? /* @__PURE__ */ jsx(Typography, { textColor: "success600", fontWeight: "bold", children: formatMessage({
644
- id: "content-releases.pages.ReleaseDetails.entry-validation.already-published",
645
- defaultMessage: "Already published"
646
- }) }) : /* @__PURE__ */ jsx(Typography, { children: formatMessage({
647
- id: "content-releases.pages.ReleaseDetails.entry-validation.ready-to-publish",
648
- defaultMessage: "Ready to publish"
649
- }) })
650
- ] });
667
+ const errors = validate(entry) ?? {};
668
+ if (action === "publish") {
669
+ if (Object.keys(errors).length > 0) {
670
+ const validationErrorsMessages = errorsToString(errors);
671
+ return /* @__PURE__ */ jsxs(Flex, { gap: 2, children: [
672
+ /* @__PURE__ */ jsx(CrossCircle, { fill: "danger600" }),
673
+ /* @__PURE__ */ jsx(Tooltip, { description: validationErrorsMessages, children: /* @__PURE__ */ jsx(
674
+ TypographyMaxWidth,
675
+ {
676
+ textColor: "danger600",
677
+ variant: "omega",
678
+ fontWeight: "semiBold",
679
+ ellipsis: true,
680
+ children: validationErrorsMessages
681
+ }
682
+ ) })
683
+ ] });
684
+ }
685
+ if (status === "draft") {
686
+ return /* @__PURE__ */ jsxs(Flex, { gap: 2, children: [
687
+ /* @__PURE__ */ jsx(CheckCircle, { fill: "success600" }),
688
+ /* @__PURE__ */ jsx(Typography, { children: formatMessage({
689
+ id: "content-releases.pages.ReleaseDetails.entry-validation.ready-to-publish",
690
+ defaultMessage: "Ready to publish"
691
+ }) })
692
+ ] });
693
+ }
694
+ if (status === "modified") {
695
+ return /* @__PURE__ */ jsxs(Flex, { gap: 2, children: [
696
+ /* @__PURE__ */ jsx(ArrowsCounterClockwise, { fill: "alternative600" }),
697
+ /* @__PURE__ */ jsx(Typography, { children: formatMessage({
698
+ id: "content-releases.pages.ReleaseDetails.entry-validation.modified",
699
+ defaultMessage: "Ready to publish changes"
700
+ }) })
701
+ ] });
702
+ }
703
+ if (status === "published") {
704
+ return /* @__PURE__ */ jsxs(Flex, { gap: 2, children: [
705
+ /* @__PURE__ */ jsx(CheckCircle, { fill: "success600" }),
706
+ /* @__PURE__ */ jsx(Typography, { children: formatMessage({
707
+ id: "content-releases.pages.ReleaseDetails.entry-validation.already-published",
708
+ defaultMessage: "Already published"
709
+ }) })
710
+ ] });
711
+ }
651
712
  }
652
713
  return /* @__PURE__ */ jsxs(Flex, { gap: 2, children: [
653
- /* @__PURE__ */ jsx(Icon, { color: "success600", as: CheckCircle }),
714
+ /* @__PURE__ */ jsx(CheckCircle, { fill: "success600" }),
654
715
  !entry.publishedAt ? /* @__PURE__ */ jsx(Typography, { textColor: "success600", fontWeight: "bold", children: formatMessage({
655
716
  id: "content-releases.pages.ReleaseDetails.entry-validation.already-unpublished",
656
717
  defaultMessage: "Already unpublished"
@@ -670,20 +731,23 @@ const ReleaseDetailsLayout = ({
670
731
  const {
671
732
  data,
672
733
  isLoading: isLoadingDetails,
673
- isError,
674
734
  error
675
- } = useGetReleaseQuery({ id: releaseId });
735
+ } = useGetReleaseQuery(
736
+ { id: releaseId },
737
+ {
738
+ skip: !releaseId
739
+ }
740
+ );
676
741
  const [publishRelease, { isLoading: isPublishing }] = usePublishReleaseMutation();
677
- const toggleNotification = useNotification();
742
+ const { toggleNotification } = useNotification();
678
743
  const { formatAPIError } = useAPIErrorHandler();
679
- const {
680
- allowedActions: { canUpdate, canDelete }
681
- } = useRBAC(PERMISSIONS);
744
+ const { allowedActions } = useRBAC(PERMISSIONS);
745
+ const { canUpdate, canDelete, canPublish } = allowedActions;
682
746
  const dispatch = useTypedDispatch();
683
747
  const { trackUsage } = useTracking();
684
748
  const release = data?.data;
685
- const handlePublishRelease = async () => {
686
- const response = await publishRelease({ id: releaseId });
749
+ const handlePublishRelease = (id) => async () => {
750
+ const response = await publishRelease({ id });
687
751
  if ("data" in response) {
688
752
  toggleNotification({
689
753
  type: "success",
@@ -698,20 +762,25 @@ const ReleaseDetailsLayout = ({
698
762
  totalPublishedEntries,
699
763
  totalUnpublishedEntries
700
764
  });
701
- } else if (isAxiosError(response.error)) {
765
+ } else if (isFetchError(response.error)) {
702
766
  toggleNotification({
703
- type: "warning",
767
+ type: "danger",
704
768
  message: formatAPIError(response.error)
705
769
  });
706
770
  } else {
707
771
  toggleNotification({
708
- type: "warning",
772
+ type: "danger",
709
773
  message: formatMessage({ id: "notification.error", defaultMessage: "An error occurred" })
710
774
  });
711
775
  }
712
776
  };
713
777
  const handleRefresh = () => {
714
- dispatch(releaseApi.util.invalidateTags([{ type: "ReleaseAction", id: "LIST" }]));
778
+ dispatch(
779
+ releaseApi.util.invalidateTags([
780
+ { type: "ReleaseAction", id: "LIST" },
781
+ { type: "Release", id: releaseId }
782
+ ])
783
+ );
715
784
  };
716
785
  const getCreatedByUser = () => {
717
786
  if (!release?.createdBy) {
@@ -726,28 +795,26 @@ const ReleaseDetailsLayout = ({
726
795
  return release.createdBy.email;
727
796
  };
728
797
  if (isLoadingDetails) {
729
- return /* @__PURE__ */ jsx(Main, { "aria-busy": isLoadingDetails, children: /* @__PURE__ */ jsx(LoadingIndicatorPage, {}) });
798
+ return /* @__PURE__ */ jsx(Page.Loading, {});
730
799
  }
731
- if (isError || !release) {
800
+ if (isBaseQueryError(error) && "code" in error || !release) {
732
801
  return /* @__PURE__ */ jsx(
733
- Redirect,
802
+ Navigate,
734
803
  {
735
- to: {
736
- pathname: "/plugins/content-releases",
737
- state: {
738
- errors: [
739
- {
740
- code: error?.code
741
- }
742
- ]
743
- }
804
+ to: "..",
805
+ state: {
806
+ errors: [
807
+ {
808
+ // @ts-expect-error – TODO: fix this weird error flow
809
+ code: error?.code
810
+ }
811
+ ]
744
812
  }
745
813
  }
746
814
  );
747
815
  }
748
816
  const totalEntries = release.actions.meta.count || 0;
749
817
  const hasCreatedByUser = Boolean(getCreatedByUser());
750
- const IsSchedulingEnabled = window.strapi.future.isEnabled("contentReleasesScheduling");
751
818
  const isScheduled = release.scheduledAt && release.timezone;
752
819
  const numberOfEntriesText = formatMessage(
753
820
  {
@@ -778,106 +845,90 @@ const ReleaseDetailsLayout = ({
778
845
  ) : "";
779
846
  return /* @__PURE__ */ jsxs(Main, { "aria-busy": isLoadingDetails, children: [
780
847
  /* @__PURE__ */ jsx(
781
- HeaderLayout,
848
+ Layouts.Header,
782
849
  {
783
850
  title: release.name,
784
851
  subtitle: /* @__PURE__ */ jsxs(Flex, { gap: 2, lineHeight: 6, children: [
785
- /* @__PURE__ */ jsx(Typography, { textColor: "neutral600", variant: "epsilon", children: numberOfEntriesText + (IsSchedulingEnabled && isScheduled ? ` - ${scheduledText}` : "") }),
852
+ /* @__PURE__ */ jsx(Typography, { textColor: "neutral600", variant: "epsilon", children: numberOfEntriesText + (isScheduled ? ` - ${scheduledText}` : "") }),
786
853
  /* @__PURE__ */ jsx(Badge, { ...getBadgeProps(release.status), children: release.status })
787
854
  ] }),
788
- navigationAction: /* @__PURE__ */ jsx(Link$1, { startIcon: /* @__PURE__ */ jsx(ArrowLeft, {}), to: "/plugins/content-releases", children: formatMessage({
789
- id: "global.back",
790
- defaultMessage: "Back"
791
- }) }),
855
+ navigationAction: /* @__PURE__ */ jsx(BackButton, {}),
792
856
  primaryAction: !release.releasedAt && /* @__PURE__ */ jsxs(Flex, { gap: 2, children: [
793
- /* @__PURE__ */ jsxs(Menu.Root, { children: [
794
- /* @__PURE__ */ jsx(
795
- Menu.Trigger,
796
- {
797
- as: IconButton,
798
- paddingLeft: 2,
799
- paddingRight: 2,
800
- "aria-label": formatMessage({
801
- id: "content-releases.header.actions.open-release-actions",
802
- defaultMessage: "Release edit and delete menu"
803
- }),
804
- icon: /* @__PURE__ */ jsx(More, {}),
805
- variant: "tertiary"
806
- }
807
- ),
808
- /* @__PURE__ */ jsxs(Menu.Content, { top: 1, popoverPlacement: "bottom-end", children: [
809
- /* @__PURE__ */ jsxs(
810
- Flex,
811
- {
812
- alignItems: "center",
813
- justifyContent: "center",
814
- direction: "column",
815
- padding: 1,
816
- width: "100%",
817
- children: [
818
- /* @__PURE__ */ jsx(StyledMenuItem, { disabled: !canUpdate, onSelect: toggleEditReleaseModal, children: /* @__PURE__ */ jsxs(Flex, { alignItems: "center", gap: 2, hasRadius: true, width: "100%", children: [
819
- /* @__PURE__ */ jsx(PencilIcon, {}),
820
- /* @__PURE__ */ jsx(Typography, { ellipsis: true, children: formatMessage({
821
- id: "content-releases.header.actions.edit",
822
- defaultMessage: "Edit"
857
+ /* @__PURE__ */ jsxs(
858
+ SimpleMenuButton,
859
+ {
860
+ label: /* @__PURE__ */ jsx(More, {}),
861
+ variant: "tertiary",
862
+ endIcon: null,
863
+ paddingLeft: "7px",
864
+ paddingRight: "7px",
865
+ "aria-label": formatMessage({
866
+ id: "content-releases.header.actions.open-release-actions",
867
+ defaultMessage: "Release edit and delete menu"
868
+ }),
869
+ popoverPlacement: "bottom-end",
870
+ children: [
871
+ /* @__PURE__ */ jsx(StyledMenuItem, { disabled: !canUpdate, onSelect: toggleEditReleaseModal, children: /* @__PURE__ */ jsxs(Flex, { alignItems: "center", gap: 2, hasRadius: true, width: "100%", children: [
872
+ /* @__PURE__ */ jsx(PencilIcon, {}),
873
+ /* @__PURE__ */ jsx(Typography, { ellipsis: true, children: formatMessage({
874
+ id: "content-releases.header.actions.edit",
875
+ defaultMessage: "Edit"
876
+ }) })
877
+ ] }) }),
878
+ /* @__PURE__ */ jsx(
879
+ StyledMenuItem,
880
+ {
881
+ disabled: !canDelete,
882
+ onSelect: toggleWarningSubmit,
883
+ $variant: "danger",
884
+ children: /* @__PURE__ */ jsxs(Flex, { alignItems: "center", gap: 2, hasRadius: true, width: "100%", children: [
885
+ /* @__PURE__ */ jsx(TrashIcon, {}),
886
+ /* @__PURE__ */ jsx(Typography, { ellipsis: true, textColor: "danger600", children: formatMessage({
887
+ id: "content-releases.header.actions.delete",
888
+ defaultMessage: "Delete"
823
889
  }) })
824
- ] }) }),
825
- /* @__PURE__ */ jsx(
826
- StyledMenuItem,
827
- {
828
- disabled: !canDelete,
829
- onSelect: toggleWarningSubmit,
830
- variant: "danger",
831
- children: /* @__PURE__ */ jsxs(Flex, { alignItems: "center", gap: 2, hasRadius: true, width: "100%", children: [
832
- /* @__PURE__ */ jsx(TrashIcon, {}),
833
- /* @__PURE__ */ jsx(Typography, { ellipsis: true, textColor: "danger600", children: formatMessage({
834
- id: "content-releases.header.actions.delete",
835
- defaultMessage: "Delete"
836
- }) })
837
- ] })
838
- }
839
- )
840
- ]
841
- }
842
- ),
843
- /* @__PURE__ */ jsxs(
844
- ReleaseInfoWrapper,
845
- {
846
- direction: "column",
847
- justifyContent: "center",
848
- alignItems: "flex-start",
849
- gap: 1,
850
- padding: 5,
851
- children: [
852
- /* @__PURE__ */ jsx(Typography, { variant: "pi", fontWeight: "bold", children: formatMessage({
853
- id: "content-releases.header.actions.created",
854
- defaultMessage: "Created"
855
- }) }),
856
- /* @__PURE__ */ jsxs(Typography, { variant: "pi", color: "neutral300", children: [
857
- /* @__PURE__ */ jsx(RelativeTime, { timestamp: new Date(release.createdAt) }),
858
- formatMessage(
859
- {
860
- id: "content-releases.header.actions.created.description",
861
- defaultMessage: "{hasCreatedByUser, select, true { by {createdBy}} other { by deleted user}}"
862
- },
863
- { createdBy: getCreatedByUser(), hasCreatedByUser }
864
- )
865
890
  ] })
866
- ]
867
- }
868
- )
869
- ] })
870
- ] }),
891
+ }
892
+ ),
893
+ /* @__PURE__ */ jsxs(
894
+ ReleaseInfoWrapper,
895
+ {
896
+ direction: "column",
897
+ justifyContent: "center",
898
+ alignItems: "flex-start",
899
+ gap: 1,
900
+ padding: 4,
901
+ children: [
902
+ /* @__PURE__ */ jsx(Typography, { variant: "pi", fontWeight: "bold", children: formatMessage({
903
+ id: "content-releases.header.actions.created",
904
+ defaultMessage: "Created"
905
+ }) }),
906
+ /* @__PURE__ */ jsxs(Typography, { variant: "pi", color: "neutral300", children: [
907
+ /* @__PURE__ */ jsx(RelativeTime$1, { timestamp: new Date(release.createdAt) }),
908
+ formatMessage(
909
+ {
910
+ id: "content-releases.header.actions.created.description",
911
+ defaultMessage: "{hasCreatedByUser, select, true { by {createdBy}} other { by deleted user}}"
912
+ },
913
+ { createdBy: getCreatedByUser(), hasCreatedByUser }
914
+ )
915
+ ] })
916
+ ]
917
+ }
918
+ )
919
+ ]
920
+ }
921
+ ),
871
922
  /* @__PURE__ */ jsx(Button, { size: "S", variant: "tertiary", onClick: handleRefresh, children: formatMessage({
872
923
  id: "content-releases.header.actions.refresh",
873
924
  defaultMessage: "Refresh"
874
925
  }) }),
875
- /* @__PURE__ */ jsx(CheckPermissions, { permissions: PERMISSIONS.publish, children: /* @__PURE__ */ jsx(
926
+ canPublish ? /* @__PURE__ */ jsx(
876
927
  Button,
877
928
  {
878
929
  size: "S",
879
930
  variant: "default",
880
- onClick: handlePublishRelease,
931
+ onClick: handlePublishRelease(release.id.toString()),
881
932
  loading: isPublishing,
882
933
  disabled: release.actions.meta.count === 0,
883
934
  children: formatMessage({
@@ -885,14 +936,20 @@ const ReleaseDetailsLayout = ({
885
936
  defaultMessage: "Publish"
886
937
  })
887
938
  }
888
- ) })
939
+ ) : null
889
940
  ] })
890
941
  }
891
942
  ),
892
943
  children
893
944
  ] });
894
945
  };
946
+ const SimpleMenuButton = styled(SimpleMenu)`
947
+ & > span {
948
+ display: flex;
949
+ }
950
+ `;
895
951
  const GROUP_BY_OPTIONS = ["contentType", "locale", "action"];
952
+ const GROUP_BY_OPTIONS_NO_LOCALE = ["contentType", "action"];
896
953
  const getGroupByOptionLabel = (value) => {
897
954
  if (value === "locale") {
898
955
  return {
@@ -911,21 +968,32 @@ const getGroupByOptionLabel = (value) => {
911
968
  defaultMessage: "Content-Types"
912
969
  };
913
970
  };
914
- const ReleaseDetailsBody = () => {
971
+ const ReleaseDetailsBody = ({ releaseId }) => {
915
972
  const { formatMessage } = useIntl();
916
- const { releaseId } = useParams();
917
973
  const [{ query }, setQuery] = useQueryParams();
918
- const toggleNotification = useNotification();
974
+ const { toggleNotification } = useNotification();
919
975
  const { formatAPIError } = useAPIErrorHandler();
920
976
  const {
921
977
  data: releaseData,
922
978
  isLoading: isReleaseLoading,
923
- isError: isReleaseError,
924
979
  error: releaseError
925
980
  } = useGetReleaseQuery({ id: releaseId });
926
981
  const {
927
982
  allowedActions: { canUpdate }
928
983
  } = useRBAC(PERMISSIONS);
984
+ const runHookWaterfall = useStrapiApp("ReleaseDetailsPage", (state) => state.runHookWaterfall);
985
+ const { displayedHeaders, hasI18nEnabled } = runHookWaterfall("ContentReleases/pages/ReleaseDetails/add-locale-in-releases", {
986
+ displayedHeaders: [
987
+ {
988
+ label: {
989
+ id: "content-releases.page.ReleaseDetails.table.header.label.name",
990
+ defaultMessage: "name"
991
+ },
992
+ name: "name"
993
+ }
994
+ ],
995
+ hasI18nEnabled: false
996
+ });
929
997
  const release = releaseData?.data;
930
998
  const selectedGroupBy = query?.groupBy || "contentType";
931
999
  const {
@@ -954,65 +1022,59 @@ const ReleaseDetailsBody = () => {
954
1022
  // We are passing the action path to found the position in the cache of the action for optimistic updates
955
1023
  });
956
1024
  if ("error" in response) {
957
- if (isAxiosError(response.error)) {
1025
+ if (isFetchError(response.error)) {
958
1026
  toggleNotification({
959
- type: "warning",
1027
+ type: "danger",
960
1028
  message: formatAPIError(response.error)
961
1029
  });
962
1030
  } else {
963
1031
  toggleNotification({
964
- type: "warning",
1032
+ type: "danger",
965
1033
  message: formatMessage({ id: "notification.error", defaultMessage: "An error occurred" })
966
1034
  });
967
1035
  }
968
1036
  }
969
1037
  };
970
1038
  if (isLoading || isReleaseLoading) {
971
- return /* @__PURE__ */ jsx(ContentLayout, { children: /* @__PURE__ */ jsx(LoadingIndicatorPage, {}) });
1039
+ return /* @__PURE__ */ jsx(Page.Loading, {});
972
1040
  }
973
1041
  const releaseActions = data?.data;
974
1042
  const releaseMeta = data?.meta;
975
1043
  const contentTypes = releaseMeta?.contentTypes || {};
976
1044
  const components = releaseMeta?.components || {};
977
- if (isReleaseError || !release) {
1045
+ if (isBaseQueryError(releaseError) || !release) {
978
1046
  const errorsArray = [];
979
- if (releaseError) {
1047
+ if (releaseError && "code" in releaseError) {
980
1048
  errorsArray.push({
981
1049
  code: releaseError.code
982
1050
  });
983
1051
  }
984
- if (releaseActionsError) {
1052
+ if (releaseActionsError && "code" in releaseActionsError) {
985
1053
  errorsArray.push({
986
1054
  code: releaseActionsError.code
987
1055
  });
988
1056
  }
989
1057
  return /* @__PURE__ */ jsx(
990
- Redirect,
1058
+ Navigate,
991
1059
  {
992
- to: {
993
- pathname: "/plugins/content-releases",
994
- state: {
995
- errors: errorsArray
996
- }
1060
+ to: "..",
1061
+ state: {
1062
+ errors: errorsArray
997
1063
  }
998
1064
  }
999
1065
  );
1000
1066
  }
1001
1067
  if (isError || !releaseActions) {
1002
- return /* @__PURE__ */ jsx(ContentLayout, { children: /* @__PURE__ */ jsx(AnErrorOccurred, {}) });
1068
+ return /* @__PURE__ */ jsx(Page.Error, {});
1003
1069
  }
1004
1070
  if (Object.keys(releaseActions).length === 0) {
1005
- return /* @__PURE__ */ jsx(ContentLayout, { children: /* @__PURE__ */ jsx(
1006
- NoContent,
1071
+ return /* @__PURE__ */ jsx(Layouts.Content, { children: /* @__PURE__ */ jsx(
1072
+ EmptyStateLayout,
1007
1073
  {
1008
- content: {
1009
- id: "content-releases.pages.Details.tab.emptyEntries",
1010
- defaultMessage: "This release is empty. Open the Content Manager, select an entry and add it to the release."
1011
- },
1012
1074
  action: /* @__PURE__ */ jsx(
1013
1075
  LinkButton,
1014
1076
  {
1015
- as: Link$2,
1077
+ tag: Link$1,
1016
1078
  to: {
1017
1079
  pathname: "/content-manager"
1018
1080
  },
@@ -1023,18 +1085,52 @@ const ReleaseDetailsBody = () => {
1023
1085
  defaultMessage: "Open the Content Manager"
1024
1086
  })
1025
1087
  }
1026
- )
1088
+ ),
1089
+ icon: /* @__PURE__ */ jsx(EmptyDocuments, { width: "16rem" }),
1090
+ content: formatMessage({
1091
+ id: "content-releases.pages.Details.tab.emptyEntries",
1092
+ defaultMessage: "This release is empty. Open the Content Manager, select an entry and add it to the release."
1093
+ })
1027
1094
  }
1028
1095
  ) });
1029
1096
  }
1030
- return /* @__PURE__ */ jsx(ContentLayout, { children: /* @__PURE__ */ jsxs(Flex, { gap: 8, direction: "column", alignItems: "stretch", children: [
1097
+ const groupByLabel = formatMessage({
1098
+ id: "content-releases.pages.ReleaseDetails.groupBy.aria-label",
1099
+ defaultMessage: "Group by"
1100
+ });
1101
+ const headers = [
1102
+ ...displayedHeaders,
1103
+ {
1104
+ label: {
1105
+ id: "content-releases.page.ReleaseDetails.table.header.label.content-type",
1106
+ defaultMessage: "content-type"
1107
+ },
1108
+ name: "content-type"
1109
+ },
1110
+ {
1111
+ label: {
1112
+ id: "content-releases.page.ReleaseDetails.table.header.label.action",
1113
+ defaultMessage: "action"
1114
+ },
1115
+ name: "action"
1116
+ },
1117
+ ...!release.releasedAt ? [
1118
+ {
1119
+ label: {
1120
+ id: "content-releases.page.ReleaseDetails.table.header.label.status",
1121
+ defaultMessage: "status"
1122
+ },
1123
+ name: "status"
1124
+ }
1125
+ ] : []
1126
+ ];
1127
+ const options = hasI18nEnabled ? GROUP_BY_OPTIONS : GROUP_BY_OPTIONS_NO_LOCALE;
1128
+ return /* @__PURE__ */ jsx(Layouts.Content, { children: /* @__PURE__ */ jsxs(Flex, { gap: 8, direction: "column", alignItems: "stretch", children: [
1031
1129
  /* @__PURE__ */ jsx(Flex, { children: /* @__PURE__ */ jsx(
1032
1130
  SingleSelect,
1033
1131
  {
1034
- "aria-label": formatMessage({
1035
- id: "content-releases.pages.ReleaseDetails.groupBy.aria-label",
1036
- defaultMessage: "Group by"
1037
- }),
1132
+ placeholder: groupByLabel,
1133
+ "aria-label": groupByLabel,
1038
1134
  customizeContent: (value) => formatMessage(
1039
1135
  {
1040
1136
  id: `content-releases.pages.ReleaseDetails.groupBy.label`,
@@ -1046,7 +1142,7 @@ const ReleaseDetailsBody = () => {
1046
1142
  ),
1047
1143
  value: formatMessage(getGroupByOptionLabel(selectedGroupBy)),
1048
1144
  onChange: (value) => setQuery({ groupBy: value }),
1049
- children: GROUP_BY_OPTIONS.map((option) => /* @__PURE__ */ jsx(SingleSelectOption, { value: option, children: formatMessage(getGroupByOptionLabel(option)) }, option))
1145
+ children: options.map((option) => /* @__PURE__ */ jsx(SingleSelectOption, { value: option, children: formatMessage(getGroupByOptionLabel(option)) }, option))
1050
1146
  }
1051
1147
  ) }),
1052
1148
  Object.keys(releaseActions).map((key) => /* @__PURE__ */ jsxs(Flex, { gap: 4, direction: "column", alignItems: "stretch", children: [
@@ -1058,72 +1154,15 @@ const ReleaseDetailsBody = () => {
1058
1154
  ...item,
1059
1155
  id: Number(item.entry.id)
1060
1156
  })),
1061
- colCount: releaseActions[key].length,
1062
- isLoading,
1063
- isFetching,
1157
+ headers,
1158
+ isLoading: isLoading || isFetching,
1064
1159
  children: /* @__PURE__ */ jsxs(Table.Content, { children: [
1065
- /* @__PURE__ */ jsxs(Table.Head, { children: [
1066
- /* @__PURE__ */ jsx(
1067
- Table.HeaderCell,
1068
- {
1069
- fieldSchemaType: "string",
1070
- label: formatMessage({
1071
- id: "content-releases.page.ReleaseDetails.table.header.label.name",
1072
- defaultMessage: "name"
1073
- }),
1074
- name: "name"
1075
- }
1076
- ),
1077
- /* @__PURE__ */ jsx(
1078
- Table.HeaderCell,
1079
- {
1080
- fieldSchemaType: "string",
1081
- label: formatMessage({
1082
- id: "content-releases.page.ReleaseDetails.table.header.label.locale",
1083
- defaultMessage: "locale"
1084
- }),
1085
- name: "locale"
1086
- }
1087
- ),
1088
- /* @__PURE__ */ jsx(
1089
- Table.HeaderCell,
1090
- {
1091
- fieldSchemaType: "string",
1092
- label: formatMessage({
1093
- id: "content-releases.page.ReleaseDetails.table.header.label.content-type",
1094
- defaultMessage: "content-type"
1095
- }),
1096
- name: "content-type"
1097
- }
1098
- ),
1099
- /* @__PURE__ */ jsx(
1100
- Table.HeaderCell,
1101
- {
1102
- fieldSchemaType: "string",
1103
- label: formatMessage({
1104
- id: "content-releases.page.ReleaseDetails.table.header.label.action",
1105
- defaultMessage: "action"
1106
- }),
1107
- name: "action"
1108
- }
1109
- ),
1110
- !release.releasedAt && /* @__PURE__ */ jsx(
1111
- Table.HeaderCell,
1112
- {
1113
- fieldSchemaType: "string",
1114
- label: formatMessage({
1115
- id: "content-releases.page.ReleaseDetails.table.header.label.status",
1116
- defaultMessage: "status"
1117
- }),
1118
- name: "status"
1119
- }
1120
- )
1121
- ] }),
1122
- /* @__PURE__ */ jsx(Table.LoadingBody, {}),
1160
+ /* @__PURE__ */ jsx(Table.Head, { children: headers.map(({ label, name }) => /* @__PURE__ */ jsx(Table.HeaderCell, { label: formatMessage(label), name }, name)) }),
1161
+ /* @__PURE__ */ jsx(Table.Loading, {}),
1123
1162
  /* @__PURE__ */ jsx(Table.Body, { children: releaseActions[key].map(
1124
- ({ id, contentType, locale, type, entry }, actionIndex) => /* @__PURE__ */ jsxs(Tr, { children: [
1163
+ ({ id, contentType, locale, type, entry, status }, actionIndex) => /* @__PURE__ */ jsxs(Tr, { children: [
1125
1164
  /* @__PURE__ */ jsx(Td, { width: "25%", maxWidth: "200px", children: /* @__PURE__ */ jsx(Typography, { ellipsis: true, children: `${contentType.mainFieldValue || entry.id}` }) }),
1126
- /* @__PURE__ */ jsx(Td, { width: "10%", children: /* @__PURE__ */ jsx(Typography, { children: `${locale?.name ? locale.name : "-"}` }) }),
1165
+ hasI18nEnabled && /* @__PURE__ */ jsx(Td, { width: "10%", children: /* @__PURE__ */ jsx(Typography, { children: `${locale?.name ? locale.name : "-"}` }) }),
1127
1166
  /* @__PURE__ */ jsx(Td, { width: "10%", children: /* @__PURE__ */ jsx(Typography, { children: contentType.displayName || "" }) }),
1128
1167
  /* @__PURE__ */ jsx(Td, { width: "20%", children: release.releasedAt ? /* @__PURE__ */ jsx(Typography, { children: formatMessage(
1129
1168
  {
@@ -1150,7 +1189,8 @@ const ReleaseDetailsBody = () => {
1150
1189
  action: type,
1151
1190
  schema: contentTypes?.[contentType.uid],
1152
1191
  components,
1153
- entry
1192
+ entry,
1193
+ status
1154
1194
  }
1155
1195
  ) }),
1156
1196
  /* @__PURE__ */ jsx(Td, { children: /* @__PURE__ */ jsx(Flex, { justifyContent: "flex-end", children: /* @__PURE__ */ jsxs(ReleaseActionMenu.Root, { children: [
@@ -1158,7 +1198,7 @@ const ReleaseDetailsBody = () => {
1158
1198
  ReleaseActionMenu.ReleaseActionEntryLinkItem,
1159
1199
  {
1160
1200
  contentTypeUid: contentType.uid,
1161
- entryId: entry.id,
1201
+ documentId: entry.documentId,
1162
1202
  locale: locale?.code
1163
1203
  }
1164
1204
  ),
@@ -1177,54 +1217,73 @@ const ReleaseDetailsBody = () => {
1177
1217
  }
1178
1218
  )
1179
1219
  ] }, `releases-group-${key}`)),
1180
- /* @__PURE__ */ jsxs(Flex, { paddingTop: 4, alignItems: "flex-end", justifyContent: "space-between", children: [
1181
- /* @__PURE__ */ jsx(PageSizeURLQuery, { defaultValue: releaseMeta?.pagination?.pageSize.toString() }),
1182
- /* @__PURE__ */ jsx(
1183
- PaginationURLQuery,
1184
- {
1185
- pagination: {
1186
- pageCount: releaseMeta?.pagination?.pageCount || 0
1187
- }
1188
- }
1189
- )
1190
- ] })
1220
+ /* @__PURE__ */ jsxs(
1221
+ Pagination.Root,
1222
+ {
1223
+ ...releaseMeta?.pagination,
1224
+ defaultPageSize: releaseMeta?.pagination?.pageSize,
1225
+ children: [
1226
+ /* @__PURE__ */ jsx(Pagination.PageSize, {}),
1227
+ /* @__PURE__ */ jsx(Pagination.Links, {})
1228
+ ]
1229
+ }
1230
+ )
1191
1231
  ] }) });
1192
1232
  };
1193
1233
  const ReleaseDetailsPage = () => {
1194
1234
  const { formatMessage } = useIntl();
1195
1235
  const { releaseId } = useParams();
1196
- const toggleNotification = useNotification();
1236
+ const { toggleNotification } = useNotification();
1197
1237
  const { formatAPIError } = useAPIErrorHandler();
1198
- const { replace } = useHistory();
1238
+ const navigate = useNavigate();
1199
1239
  const [releaseModalShown, setReleaseModalShown] = React.useState(false);
1200
1240
  const [showWarningSubmit, setWarningSubmit] = React.useState(false);
1201
1241
  const {
1202
1242
  isLoading: isLoadingDetails,
1203
1243
  data,
1204
1244
  isSuccess: isSuccessDetails
1205
- } = useGetReleaseQuery({ id: releaseId });
1245
+ } = useGetReleaseQuery(
1246
+ { id: releaseId },
1247
+ {
1248
+ skip: !releaseId
1249
+ }
1250
+ );
1251
+ const { data: dataTimezone, isLoading: isLoadingTimezone } = useGetReleaseSettingsQuery();
1206
1252
  const [updateRelease, { isLoading: isSubmittingForm }] = useUpdateReleaseMutation();
1207
- const [deleteRelease, { isLoading: isDeletingRelease }] = useDeleteReleaseMutation();
1253
+ const [deleteRelease] = useDeleteReleaseMutation();
1208
1254
  const toggleEditReleaseModal = () => {
1209
1255
  setReleaseModalShown((prev) => !prev);
1210
1256
  };
1257
+ const getTimezoneValue = () => {
1258
+ if (releaseData?.timezone) {
1259
+ return releaseData.timezone;
1260
+ } else {
1261
+ if (dataTimezone?.data.defaultTimezone) {
1262
+ return dataTimezone.data.defaultTimezone;
1263
+ }
1264
+ return null;
1265
+ }
1266
+ };
1211
1267
  const toggleWarningSubmit = () => setWarningSubmit((prevState) => !prevState);
1212
- if (isLoadingDetails) {
1268
+ if (isLoadingDetails || isLoadingTimezone) {
1213
1269
  return /* @__PURE__ */ jsx(
1214
1270
  ReleaseDetailsLayout,
1215
1271
  {
1216
1272
  toggleEditReleaseModal,
1217
1273
  toggleWarningSubmit,
1218
- children: /* @__PURE__ */ jsx(ContentLayout, { children: /* @__PURE__ */ jsx(LoadingIndicatorPage, {}) })
1274
+ children: /* @__PURE__ */ jsx(Page.Loading, {})
1219
1275
  }
1220
1276
  );
1221
1277
  }
1278
+ if (!releaseId) {
1279
+ return /* @__PURE__ */ jsx(Navigate, { to: ".." });
1280
+ }
1222
1281
  const releaseData = isSuccessDetails && data?.data || null;
1223
1282
  const title = releaseData?.name || "";
1224
- const timezone = releaseData?.timezone ?? null;
1283
+ const timezone = getTimezoneValue();
1225
1284
  const scheduledAt = releaseData?.scheduledAt && timezone ? utcToZonedTime(releaseData.scheduledAt, timezone) : null;
1226
- const date = scheduledAt ? new Date(format(scheduledAt, "yyyy-MM-dd")) : null;
1227
- const time = scheduledAt ? format(scheduledAt, "HH:mm") : "";
1285
+ const date = scheduledAt ? format$1(scheduledAt, "yyyy-MM-dd") : void 0;
1286
+ const time = scheduledAt ? format$1(scheduledAt, "HH:mm") : "";
1228
1287
  const handleEditRelease = async (values) => {
1229
1288
  const response = await updateRelease({
1230
1289
  id: releaseId,
@@ -1240,33 +1299,33 @@ const ReleaseDetailsPage = () => {
1240
1299
  defaultMessage: "Release updated."
1241
1300
  })
1242
1301
  });
1243
- } else if (isAxiosError(response.error)) {
1302
+ toggleEditReleaseModal();
1303
+ } else if (isFetchError(response.error)) {
1244
1304
  toggleNotification({
1245
- type: "warning",
1305
+ type: "danger",
1246
1306
  message: formatAPIError(response.error)
1247
1307
  });
1248
1308
  } else {
1249
1309
  toggleNotification({
1250
- type: "warning",
1310
+ type: "danger",
1251
1311
  message: formatMessage({ id: "notification.error", defaultMessage: "An error occurred" })
1252
1312
  });
1253
1313
  }
1254
- toggleEditReleaseModal();
1255
1314
  };
1256
1315
  const handleDeleteRelease = async () => {
1257
1316
  const response = await deleteRelease({
1258
1317
  id: releaseId
1259
1318
  });
1260
1319
  if ("data" in response) {
1261
- replace("/plugins/content-releases");
1262
- } else if (isAxiosError(response.error)) {
1320
+ navigate("..");
1321
+ } else if (isFetchError(response.error)) {
1263
1322
  toggleNotification({
1264
- type: "warning",
1323
+ type: "danger",
1265
1324
  message: formatAPIError(response.error)
1266
1325
  });
1267
1326
  } else {
1268
1327
  toggleNotification({
1269
- type: "warning",
1328
+ type: "danger",
1270
1329
  message: formatMessage({ id: "notification.error", defaultMessage: "An error occurred" })
1271
1330
  });
1272
1331
  }
@@ -1277,10 +1336,11 @@ const ReleaseDetailsPage = () => {
1277
1336
  toggleEditReleaseModal,
1278
1337
  toggleWarningSubmit,
1279
1338
  children: [
1280
- /* @__PURE__ */ jsx(ReleaseDetailsBody, {}),
1281
- releaseModalShown && /* @__PURE__ */ jsx(
1339
+ /* @__PURE__ */ jsx(ReleaseDetailsBody, { releaseId }),
1340
+ /* @__PURE__ */ jsx(
1282
1341
  ReleaseModal,
1283
1342
  {
1343
+ open: releaseModalShown,
1284
1344
  handleClose: toggleEditReleaseModal,
1285
1345
  handleSubmit: handleEditRelease,
1286
1346
  isLoading: isLoadingDetails || isSubmittingForm,
@@ -1294,30 +1354,21 @@ const ReleaseDetailsPage = () => {
1294
1354
  }
1295
1355
  }
1296
1356
  ),
1297
- /* @__PURE__ */ jsx(
1298
- ConfirmDialog,
1299
- {
1300
- bodyText: {
1301
- id: "content-releases.dialog.confirmation-message",
1302
- defaultMessage: "Are you sure you want to delete this release?"
1303
- },
1304
- isOpen: showWarningSubmit,
1305
- isConfirmButtonLoading: isDeletingRelease,
1306
- onToggleDialog: toggleWarningSubmit,
1307
- onConfirm: handleDeleteRelease
1308
- }
1309
- )
1357
+ /* @__PURE__ */ jsx(Dialog.Root, { open: showWarningSubmit, onOpenChange: toggleWarningSubmit, children: /* @__PURE__ */ jsx(ConfirmDialog, { onConfirm: handleDeleteRelease, children: formatMessage({
1358
+ id: "content-releases.dialog.confirmation-message",
1359
+ defaultMessage: "Are you sure you want to delete this release?"
1360
+ }) }) })
1310
1361
  ]
1311
1362
  }
1312
1363
  );
1313
1364
  };
1314
1365
  const App = () => {
1315
- return /* @__PURE__ */ jsx(CheckPagePermissions, { permissions: PERMISSIONS.main, children: /* @__PURE__ */ jsxs(Switch, { children: [
1316
- /* @__PURE__ */ jsx(Route, { exact: true, path: `/plugins/${pluginId}`, component: ReleasesPage }),
1317
- /* @__PURE__ */ jsx(Route, { exact: true, path: `/plugins/${pluginId}/:releaseId`, component: ReleaseDetailsPage })
1366
+ return /* @__PURE__ */ jsx(Page.Protect, { permissions: PERMISSIONS.main, children: /* @__PURE__ */ jsxs(Routes, { children: [
1367
+ /* @__PURE__ */ jsx(Route, { index: true, element: /* @__PURE__ */ jsx(ReleasesPage, {}) }),
1368
+ /* @__PURE__ */ jsx(Route, { path: ":releaseId", element: /* @__PURE__ */ jsx(ReleaseDetailsPage, {}) })
1318
1369
  ] }) });
1319
1370
  };
1320
1371
  export {
1321
1372
  App
1322
1373
  };
1323
- //# sourceMappingURL=App-bpzO2Ljh.mjs.map
1374
+ //# sourceMappingURL=App-Cne--1Z8.mjs.map