@strapi/content-releases 0.0.0-experimental.d954d57341a6623992a0d211daaec8e245c3517d → 0.0.0-experimental.da0467de7eccc163e893e9b332505a79a5d52ec7

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