@strapi/content-releases 0.0.0-next.44f19b3d2f81d983c343a219aa2781ee0deecb5f → 0.0.0-next.4af8963f6880c5fb9fae32ecd580f5cd33eaddda

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 (29) hide show
  1. package/dist/_chunks/{App-3ycH2d3s.mjs → App-ise7GunC.mjs} +365 -154
  2. package/dist/_chunks/App-ise7GunC.mjs.map +1 -0
  3. package/dist/_chunks/{App-5PsAyVt2.js → App-w2Zq-wj5.js} +363 -151
  4. package/dist/_chunks/App-w2Zq-wj5.js.map +1 -0
  5. package/dist/_chunks/PurchaseContentReleases-Clm0iACO.mjs +51 -0
  6. package/dist/_chunks/PurchaseContentReleases-Clm0iACO.mjs.map +1 -0
  7. package/dist/_chunks/PurchaseContentReleases-YhAPgpG9.js +51 -0
  8. package/dist/_chunks/PurchaseContentReleases-YhAPgpG9.js.map +1 -0
  9. package/dist/_chunks/{en-2DuPv5k0.js → en-7P4i1cWH.js} +11 -3
  10. package/dist/_chunks/en-7P4i1cWH.js.map +1 -0
  11. package/dist/_chunks/{en-SOqjCdyh.mjs → en-pb1wUzhy.mjs} +11 -3
  12. package/dist/_chunks/en-pb1wUzhy.mjs.map +1 -0
  13. package/dist/_chunks/{index-4gUWuCQV.mjs → index-D-Yjf60c.mjs} +57 -16
  14. package/dist/_chunks/index-D-Yjf60c.mjs.map +1 -0
  15. package/dist/_chunks/{index-D57Rztnc.js → index-Q8Pv7enO.js} +57 -16
  16. package/dist/_chunks/index-Q8Pv7enO.js.map +1 -0
  17. package/dist/admin/index.js +1 -1
  18. package/dist/admin/index.mjs +1 -1
  19. package/dist/server/index.js +573 -403
  20. package/dist/server/index.js.map +1 -1
  21. package/dist/server/index.mjs +573 -403
  22. package/dist/server/index.mjs.map +1 -1
  23. package/package.json +12 -9
  24. package/dist/_chunks/App-3ycH2d3s.mjs.map +0 -1
  25. package/dist/_chunks/App-5PsAyVt2.js.map +0 -1
  26. package/dist/_chunks/en-2DuPv5k0.js.map +0 -1
  27. package/dist/_chunks/en-SOqjCdyh.mjs.map +0 -1
  28. package/dist/_chunks/index-4gUWuCQV.mjs.map +0 -1
  29. package/dist/_chunks/index-D57Rztnc.js.map +0 -1
@@ -1,22 +1,42 @@
1
1
  import { jsxs, jsx, Fragment } from "react/jsx-runtime";
2
2
  import { useNotification, useAPIErrorHandler, LoadingIndicatorPage, ConfirmDialog, useRBAC, useTracking, RelativeTime, CheckPermissions, useQueryParams, AnErrorOccurred, NoContent, Table, PageSizeURLQuery, PaginationURLQuery, CheckPagePermissions } from "@strapi/helper-plugin";
3
3
  import { useLocation, useParams, useHistory, Redirect, Link as Link$1, Switch, Route } from "react-router-dom";
4
- import { p as pluginId, u as useGetReleaseQuery, a as useUpdateReleaseMutation, b as useDeleteReleaseMutation, c as usePublishReleaseMutation, P as PERMISSIONS, d as useTypedDispatch, e as useGetReleaseActionsQuery, f as useUpdateReleaseActionMutation, R as ReleaseActionOptions, g as ReleaseActionMenu, i as isAxiosError, r as releaseApi, h as useGetReleasesQuery, j as useCreateReleaseMutation } from "./index-4gUWuCQV.mjs";
4
+ import { p as pluginId, u as useGetReleaseQuery, a as useUpdateReleaseMutation, b as useDeleteReleaseMutation, c as usePublishReleaseMutation, P as PERMISSIONS, d as useTypedDispatch, e as useGetReleaseActionsQuery, f as useUpdateReleaseActionMutation, R as ReleaseActionOptions, g as ReleaseActionMenu, i as isAxiosError, r as releaseApi, h as useGetReleasesQuery, j as useCreateReleaseMutation } from "./index-D-Yjf60c.mjs";
5
5
  import * as React from "react";
6
6
  import { unstable_useDocument, useLicenseLimits } from "@strapi/admin/strapi-admin";
7
- import { ModalLayout, ModalHeader, Typography, ModalBody, TextInput, ModalFooter, Button, Flex, ContentLayout, Main, HeaderLayout, Link, IconButton, Popover, SingleSelect, SingleSelectOption, Badge, Tr, Td, Icon, Tooltip, Alert, TabGroup, Box, Tabs, Tab, Divider, TabPanels, TabPanel, EmptyStateLayout, Grid, GridItem } from "@strapi/design-system";
8
- import { LinkButton, Link as Link$2 } from "@strapi/design-system/v2";
7
+ import { ModalLayout, ModalHeader, Typography, ModalBody, Flex, TextInput, Checkbox, Box, DatePicker, TimePicker, ModalFooter, Button, Combobox, ComboboxOption, ContentLayout, Main, HeaderLayout, Link, IconButton, SingleSelect, SingleSelectOption, Badge, Tr, Td, Icon, Tooltip, Alert, TabGroup, Tabs, Tab, Divider, TabPanels, TabPanel, EmptyStateLayout, Grid, GridItem } from "@strapi/design-system";
8
+ import { Menu, LinkButton, Link as Link$2 } from "@strapi/design-system/v2";
9
9
  import { Pencil, Trash, ArrowLeft, More, CrossCircle, CheckCircle, Plus, EmptyDocuments } from "@strapi/icons";
10
+ import format from "date-fns/format";
11
+ import { zonedTimeToUtc, utcToZonedTime } from "date-fns-tz";
10
12
  import { useIntl } from "react-intl";
11
13
  import styled from "styled-components";
12
- import { Formik, Form } from "formik";
14
+ import { formatISO, parse } from "date-fns";
15
+ import { Formik, Form, useFormikContext } from "formik";
13
16
  import * as yup from "yup";
14
17
  import "@reduxjs/toolkit/query";
15
18
  import "axios";
16
19
  import "@reduxjs/toolkit/query/react";
17
20
  import "react-redux";
18
21
  const RELEASE_SCHEMA = yup.object().shape({
19
- name: yup.string().trim().required()
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
+ })
20
40
  }).required().noUnknown();
21
41
  const ReleaseModal = ({
22
42
  handleClose,
@@ -27,6 +47,24 @@ const ReleaseModal = ({
27
47
  const { formatMessage } = useIntl();
28
48
  const { pathname } = useLocation();
29
49
  const isCreatingRelease = pathname === `/plugins/${pluginId}`;
50
+ const IsSchedulingEnabled = window.strapi.future.isEnabled("contentReleasesScheduling");
51
+ const { timezoneList, systemTimezone = { value: "UTC+00:00-Africa/Abidjan " } } = getTimezones(
52
+ initialValues.scheduledAt ? new Date(initialValues.scheduledAt) : /* @__PURE__ */ new Date()
53
+ );
54
+ const getScheduledTimestamp = (values) => {
55
+ const { date, time, timezone } = values;
56
+ if (!date || !time || !timezone)
57
+ return null;
58
+ const formattedDate = parse(time, "HH:mm", new Date(date));
59
+ const timezoneWithoutOffset = timezone.split("-")[1];
60
+ return zonedTimeToUtc(formattedDate, timezoneWithoutOffset);
61
+ };
62
+ const getTimezoneWithOffset = () => {
63
+ const currentTimezone = timezoneList.find(
64
+ (timezone) => timezone.value.split("-")[1] === initialValues.timezone
65
+ );
66
+ return currentTimezone?.value || systemTimezone.value;
67
+ };
30
68
  return /* @__PURE__ */ jsxs(ModalLayout, { onClose: handleClose, labelledBy: "title", children: [
31
69
  /* @__PURE__ */ jsx(ModalHeader, { children: /* @__PURE__ */ jsx(Typography, { id: "title", fontWeight: "bold", textColor: "neutral800", children: formatMessage(
32
70
  {
@@ -38,45 +76,134 @@ const ReleaseModal = ({
38
76
  /* @__PURE__ */ jsx(
39
77
  Formik,
40
78
  {
41
- validateOnChange: false,
42
- onSubmit: handleSubmit,
43
- initialValues,
79
+ onSubmit: (values) => {
80
+ handleSubmit({
81
+ ...values,
82
+ timezone: values.timezone ? values.timezone.split("-")[1] : null,
83
+ scheduledAt: values.isScheduled ? getScheduledTimestamp(values) : null
84
+ });
85
+ },
86
+ initialValues: {
87
+ ...initialValues,
88
+ timezone: initialValues.timezone ? getTimezoneWithOffset() : systemTimezone.value
89
+ },
44
90
  validationSchema: RELEASE_SCHEMA,
45
- children: ({ values, errors, handleChange }) => /* @__PURE__ */ jsxs(Form, { children: [
46
- /* @__PURE__ */ jsx(ModalBody, { children: /* @__PURE__ */ jsx(
47
- TextInput,
48
- {
49
- label: formatMessage({
50
- id: "content-releases.modal.form.input.label.release-name",
51
- defaultMessage: "Name"
52
- }),
53
- name: "name",
54
- value: values.name,
55
- error: errors.name,
56
- onChange: handleChange,
57
- required: true
58
- }
59
- ) }),
91
+ 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: [
109
+ /* @__PURE__ */ jsx(
110
+ Checkbox,
111
+ {
112
+ name: "isScheduled",
113
+ value: values.isScheduled,
114
+ onChange: (event) => {
115
+ setFieldValue("isScheduled", event.target.checked);
116
+ if (!event.target.checked) {
117
+ setFieldValue("date", null);
118
+ setFieldValue("time", "");
119
+ setFieldValue("timezone", null);
120
+ } else {
121
+ setFieldValue("date", initialValues.date);
122
+ setFieldValue("time", initialValues.time);
123
+ setFieldValue(
124
+ "timezone",
125
+ initialValues.timezone ?? systemTimezone?.value
126
+ );
127
+ }
128
+ },
129
+ children: /* @__PURE__ */ jsx(
130
+ Typography,
131
+ {
132
+ textColor: values.isScheduled ? "primary600" : "neutral800",
133
+ fontWeight: values.isScheduled ? "semiBold" : "regular",
134
+ children: formatMessage({
135
+ id: "modal.form.input.label.schedule-release",
136
+ defaultMessage: "Schedule release"
137
+ })
138
+ }
139
+ )
140
+ }
141
+ ),
142
+ values.isScheduled && /* @__PURE__ */ jsxs(Fragment, { children: [
143
+ /* @__PURE__ */ jsxs(Flex, { gap: 4, alignItems: "start", children: [
144
+ /* @__PURE__ */ jsx(Box, { width: "100%", children: /* @__PURE__ */ jsx(
145
+ DatePicker,
146
+ {
147
+ label: formatMessage({
148
+ id: "content-releases.modal.form.input.label.date",
149
+ defaultMessage: "Date"
150
+ }),
151
+ 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,
165
+ required: true
166
+ }
167
+ ) }),
168
+ /* @__PURE__ */ jsx(Box, { width: "100%", children: /* @__PURE__ */ jsx(
169
+ TimePicker,
170
+ {
171
+ label: formatMessage({
172
+ id: "content-releases.modal.form.input.label.time",
173
+ defaultMessage: "Time"
174
+ }),
175
+ name: "time",
176
+ error: errors.time,
177
+ onChange: (time) => {
178
+ setFieldValue("time", time);
179
+ },
180
+ clearLabel: formatMessage({
181
+ id: "content-releases.modal.form.input.clearLabel",
182
+ defaultMessage: "Clear"
183
+ }),
184
+ onClear: () => {
185
+ setFieldValue("time", "");
186
+ },
187
+ value: values.time || void 0,
188
+ required: true
189
+ }
190
+ ) })
191
+ ] }),
192
+ /* @__PURE__ */ jsx(TimezoneComponent, { timezoneOptions: timezoneList })
193
+ ] })
194
+ ] })
195
+ ] }) }),
60
196
  /* @__PURE__ */ jsx(
61
197
  ModalFooter,
62
198
  {
63
199
  startActions: /* @__PURE__ */ jsx(Button, { onClick: handleClose, variant: "tertiary", name: "cancel", children: formatMessage({ id: "cancel", defaultMessage: "Cancel" }) }),
64
- endActions: /* @__PURE__ */ jsx(
65
- Button,
200
+ endActions: /* @__PURE__ */ jsx(Button, { name: "submit", loading: isLoading, type: "submit", children: formatMessage(
66
201
  {
67
- name: "submit",
68
- loading: isLoading,
69
- disabled: !values.name || values.name === initialValues.name,
70
- type: "submit",
71
- children: formatMessage(
72
- {
73
- id: "content-releases.modal.form.button.submit",
74
- defaultMessage: "{isCreatingRelease, select, true {Continue} other {Save}}"
75
- },
76
- { isCreatingRelease }
77
- )
78
- }
79
- )
202
+ id: "content-releases.modal.form.button.submit",
203
+ defaultMessage: "{isCreatingRelease, select, true {Continue} other {Save}}"
204
+ },
205
+ { isCreatingRelease }
206
+ ) })
80
207
  }
81
208
  )
82
209
  ] })
@@ -84,16 +211,67 @@ const ReleaseModal = ({
84
211
  )
85
212
  ] });
86
213
  };
214
+ const getTimezones = (selectedDate) => {
215
+ const timezoneList = Intl.supportedValuesOf("timeZone").map((timezone) => {
216
+ const offsetPart = new Intl.DateTimeFormat("en", {
217
+ timeZone: timezone,
218
+ timeZoneName: "longOffset"
219
+ }).formatToParts(selectedDate).find((part) => part.type === "timeZoneName");
220
+ const offset = offsetPart ? offsetPart.value : "";
221
+ let utcOffset = offset.replace("GMT", "UTC");
222
+ if (!utcOffset.includes("+") && !utcOffset.includes("-")) {
223
+ utcOffset = `${utcOffset}+00:00`;
224
+ }
225
+ return { offset: utcOffset, value: `${utcOffset}-${timezone}` };
226
+ });
227
+ const systemTimezone = timezoneList.find(
228
+ (timezone) => timezone.value.split("-")[1] === Intl.DateTimeFormat().resolvedOptions().timeZone
229
+ );
230
+ return { timezoneList, systemTimezone };
231
+ };
232
+ const TimezoneComponent = ({ timezoneOptions }) => {
233
+ const { values, errors, setFieldValue } = useFormikContext();
234
+ const { formatMessage } = useIntl();
235
+ const [timezoneList, setTimezoneList] = React.useState(timezoneOptions);
236
+ React.useEffect(() => {
237
+ if (values.date) {
238
+ const { timezoneList: timezoneList2 } = getTimezones(new Date(values.date));
239
+ setTimezoneList(timezoneList2);
240
+ const updatedTimezone = values.timezone && timezoneList2.find((tz) => tz.value.split("-")[1] === values.timezone.split("-")[1]);
241
+ if (updatedTimezone) {
242
+ setFieldValue("timezone", updatedTimezone.value);
243
+ }
244
+ }
245
+ }, [setFieldValue, values.date, values.timezone]);
246
+ return /* @__PURE__ */ jsx(
247
+ Combobox,
248
+ {
249
+ label: formatMessage({
250
+ id: "content-releases.modal.form.input.label.timezone",
251
+ defaultMessage: "Timezone"
252
+ }),
253
+ name: "timezone",
254
+ value: values.timezone || void 0,
255
+ textValue: values.timezone ? values.timezone.replace("-", " ") : void 0,
256
+ onChange: (timezone) => {
257
+ setFieldValue("timezone", timezone);
258
+ },
259
+ onClear: () => {
260
+ setFieldValue("timezone", "");
261
+ },
262
+ error: errors.timezone,
263
+ required: true,
264
+ children: timezoneList.map((timezone) => /* @__PURE__ */ jsx(ComboboxOption, { value: timezone.value, children: timezone.value.replace("-", " ") }, timezone.value))
265
+ }
266
+ );
267
+ };
87
268
  const ReleaseInfoWrapper = styled(Flex)`
88
269
  align-self: stretch;
89
270
  border-bottom-right-radius: ${({ theme }) => theme.borderRadius};
90
271
  border-bottom-left-radius: ${({ theme }) => theme.borderRadius};
91
272
  border-top: 1px solid ${({ theme }) => theme.colors.neutral150};
92
273
  `;
93
- const StyledFlex = styled(Flex)`
94
- align-self: stretch;
95
- cursor: ${({ disabled }) => disabled ? "not-allowed" : "pointer"};
96
-
274
+ const StyledMenuItem = styled(Menu.Item)`
97
275
  svg path {
98
276
  fill: ${({ theme, disabled }) => disabled && theme.colors.neutral500};
99
277
  }
@@ -102,15 +280,15 @@ const StyledFlex = styled(Flex)`
102
280
  }
103
281
  `;
104
282
  const PencilIcon = styled(Pencil)`
105
- width: ${({ theme }) => theme.spaces[4]};
106
- height: ${({ theme }) => theme.spaces[4]};
283
+ width: ${({ theme }) => theme.spaces[3]};
284
+ height: ${({ theme }) => theme.spaces[3]};
107
285
  path {
108
286
  fill: ${({ theme }) => theme.colors.neutral600};
109
287
  }
110
288
  `;
111
289
  const TrashIcon = styled(Trash)`
112
- width: ${({ theme }) => theme.spaces[4]};
113
- height: ${({ theme }) => theme.spaces[4]};
290
+ width: ${({ theme }) => theme.spaces[3]};
291
+ height: ${({ theme }) => theme.spaces[3]};
114
292
  path {
115
293
  fill: ${({ theme }) => theme.colors.danger600};
116
294
  }
@@ -118,24 +296,6 @@ const TrashIcon = styled(Trash)`
118
296
  const TypographyMaxWidth = styled(Typography)`
119
297
  max-width: 300px;
120
298
  `;
121
- const PopoverButton = ({ onClick, disabled, children }) => {
122
- return /* @__PURE__ */ jsx(
123
- StyledFlex,
124
- {
125
- paddingTop: 2,
126
- paddingBottom: 2,
127
- paddingLeft: 4,
128
- paddingRight: 4,
129
- alignItems: "center",
130
- gap: 2,
131
- as: "button",
132
- hasRadius: true,
133
- onClick,
134
- disabled,
135
- children
136
- }
137
- );
138
- };
139
299
  const EntryValidationText = ({ action, schema, components, entry }) => {
140
300
  const { formatMessage } = useIntl();
141
301
  const { validate } = unstable_useDocument();
@@ -186,8 +346,6 @@ const ReleaseDetailsLayout = ({
186
346
  }) => {
187
347
  const { formatMessage } = useIntl();
188
348
  const { releaseId } = useParams();
189
- const [isPopoverVisible, setIsPopoverVisible] = React.useState(false);
190
- const moreButtonRef = React.useRef(null);
191
349
  const {
192
350
  data,
193
351
  isLoading: isLoadingDetails,
@@ -203,13 +361,6 @@ const ReleaseDetailsLayout = ({
203
361
  const dispatch = useTypedDispatch();
204
362
  const { trackUsage } = useTracking();
205
363
  const release = data?.data;
206
- const handleTogglePopover = () => {
207
- setIsPopoverVisible((prev) => !prev);
208
- };
209
- const openReleaseModal = () => {
210
- toggleEditReleaseModal();
211
- handleTogglePopover();
212
- };
213
364
  const handlePublishRelease = async () => {
214
365
  const response = await publishRelease({ id: releaseId });
215
366
  if ("data" in response) {
@@ -238,13 +389,21 @@ const ReleaseDetailsLayout = ({
238
389
  });
239
390
  }
240
391
  };
241
- const openWarningConfirmDialog = () => {
242
- toggleWarningSubmit();
243
- handleTogglePopover();
244
- };
245
392
  const handleRefresh = () => {
246
393
  dispatch(releaseApi.util.invalidateTags([{ type: "ReleaseAction", id: "LIST" }]));
247
394
  };
395
+ const getCreatedByUser = () => {
396
+ if (!release?.createdBy) {
397
+ return null;
398
+ }
399
+ if (release.createdBy.username) {
400
+ return release.createdBy.username;
401
+ }
402
+ if (release.createdBy.firstname) {
403
+ return `${release.createdBy.firstname} ${release.createdBy.lastname || ""}`.trim();
404
+ }
405
+ return release.createdBy.email;
406
+ };
248
407
  if (isLoadingDetails) {
249
408
  return /* @__PURE__ */ jsx(Main, { "aria-busy": isLoadingDetails, children: /* @__PURE__ */ jsx(LoadingIndicatorPage, {}) });
250
409
  }
@@ -266,7 +425,7 @@ const ReleaseDetailsLayout = ({
266
425
  );
267
426
  }
268
427
  const totalEntries = release.actions.meta.count || 0;
269
- const createdBy = release.createdBy.lastname ? `${release.createdBy.firstname} ${release.createdBy.lastname}` : `${release.createdBy.firstname}`;
428
+ const hasCreatedByUser = Boolean(getCreatedByUser());
270
429
  return /* @__PURE__ */ jsxs(Main, { "aria-busy": isLoadingDetails, children: [
271
430
  /* @__PURE__ */ jsx(
272
431
  HeaderLayout,
@@ -284,72 +443,98 @@ const ReleaseDetailsLayout = ({
284
443
  defaultMessage: "Back"
285
444
  }) }),
286
445
  primaryAction: !release.releasedAt && /* @__PURE__ */ jsxs(Flex, { gap: 2, children: [
287
- /* @__PURE__ */ jsx(
288
- IconButton,
289
- {
290
- label: formatMessage({
291
- id: "content-releases.header.actions.open-release-actions",
292
- defaultMessage: "Release actions"
293
- }),
294
- ref: moreButtonRef,
295
- onClick: handleTogglePopover,
296
- children: /* @__PURE__ */ jsx(More, {})
297
- }
298
- ),
299
- isPopoverVisible && /* @__PURE__ */ jsxs(
300
- Popover,
301
- {
302
- source: moreButtonRef,
303
- placement: "bottom-end",
304
- onDismiss: handleTogglePopover,
305
- spacing: 4,
306
- minWidth: "242px",
307
- children: [
308
- /* @__PURE__ */ jsxs(Flex, { alignItems: "center", justifyContent: "center", direction: "column", padding: 1, children: [
309
- /* @__PURE__ */ jsxs(PopoverButton, { disabled: !canUpdate, onClick: openReleaseModal, children: [
310
- /* @__PURE__ */ jsx(PencilIcon, {}),
311
- /* @__PURE__ */ jsx(Typography, { ellipsis: true, children: formatMessage({
312
- id: "content-releases.header.actions.edit",
313
- defaultMessage: "Edit"
314
- }) })
315
- ] }),
316
- /* @__PURE__ */ jsxs(PopoverButton, { disabled: !canDelete, onClick: openWarningConfirmDialog, children: [
317
- /* @__PURE__ */ jsx(TrashIcon, {}),
318
- /* @__PURE__ */ jsx(Typography, { ellipsis: true, textColor: "danger600", children: formatMessage({
319
- id: "content-releases.header.actions.delete",
320
- defaultMessage: "Delete"
321
- }) })
322
- ] })
323
- ] }),
324
- /* @__PURE__ */ jsxs(
325
- ReleaseInfoWrapper,
326
- {
327
- direction: "column",
328
- justifyContent: "center",
329
- alignItems: "flex-start",
330
- gap: 1,
331
- padding: 5,
332
- children: [
333
- /* @__PURE__ */ jsx(Typography, { variant: "pi", fontWeight: "bold", children: formatMessage({
334
- id: "content-releases.header.actions.created",
335
- defaultMessage: "Created"
336
- }) }),
337
- /* @__PURE__ */ jsxs(Typography, { variant: "pi", color: "neutral300", children: [
338
- /* @__PURE__ */ jsx(RelativeTime, { timestamp: new Date(release.createdAt) }),
339
- formatMessage(
340
- {
341
- id: "content-releases.header.actions.created.description",
342
- defaultMessage: " by {createdBy}"
343
- },
344
- { createdBy }
345
- )
346
- ] })
347
- ]
348
- }
349
- )
350
- ]
351
- }
352
- ),
446
+ /* @__PURE__ */ jsxs(Menu.Root, { children: [
447
+ /* @__PURE__ */ jsx(
448
+ Menu.Trigger,
449
+ {
450
+ as: IconButton,
451
+ paddingLeft: 2,
452
+ paddingRight: 2,
453
+ "aria-label": formatMessage({
454
+ id: "content-releases.header.actions.open-release-actions",
455
+ defaultMessage: "Release edit and delete menu"
456
+ }),
457
+ icon: /* @__PURE__ */ jsx(More, {}),
458
+ variant: "tertiary"
459
+ }
460
+ ),
461
+ /* @__PURE__ */ jsxs(Menu.Content, { top: 1, popoverPlacement: "bottom-end", children: [
462
+ /* @__PURE__ */ jsxs(
463
+ Flex,
464
+ {
465
+ alignItems: "center",
466
+ justifyContent: "center",
467
+ direction: "column",
468
+ padding: 1,
469
+ width: "100%",
470
+ children: [
471
+ /* @__PURE__ */ jsx(StyledMenuItem, { disabled: !canUpdate, onSelect: toggleEditReleaseModal, children: /* @__PURE__ */ jsxs(
472
+ Flex,
473
+ {
474
+ paddingTop: 2,
475
+ paddingBottom: 2,
476
+ alignItems: "center",
477
+ gap: 2,
478
+ hasRadius: true,
479
+ width: "100%",
480
+ children: [
481
+ /* @__PURE__ */ jsx(PencilIcon, {}),
482
+ /* @__PURE__ */ jsx(Typography, { ellipsis: true, children: formatMessage({
483
+ id: "content-releases.header.actions.edit",
484
+ defaultMessage: "Edit"
485
+ }) })
486
+ ]
487
+ }
488
+ ) }),
489
+ /* @__PURE__ */ jsx(StyledMenuItem, { disabled: !canDelete, onSelect: toggleWarningSubmit, children: /* @__PURE__ */ jsxs(
490
+ Flex,
491
+ {
492
+ paddingTop: 2,
493
+ paddingBottom: 2,
494
+ alignItems: "center",
495
+ gap: 2,
496
+ hasRadius: true,
497
+ width: "100%",
498
+ children: [
499
+ /* @__PURE__ */ jsx(TrashIcon, {}),
500
+ /* @__PURE__ */ jsx(Typography, { ellipsis: true, textColor: "danger600", children: formatMessage({
501
+ id: "content-releases.header.actions.delete",
502
+ defaultMessage: "Delete"
503
+ }) })
504
+ ]
505
+ }
506
+ ) })
507
+ ]
508
+ }
509
+ ),
510
+ /* @__PURE__ */ jsxs(
511
+ ReleaseInfoWrapper,
512
+ {
513
+ direction: "column",
514
+ justifyContent: "center",
515
+ alignItems: "flex-start",
516
+ gap: 1,
517
+ padding: 5,
518
+ children: [
519
+ /* @__PURE__ */ jsx(Typography, { variant: "pi", fontWeight: "bold", children: formatMessage({
520
+ id: "content-releases.header.actions.created",
521
+ defaultMessage: "Created"
522
+ }) }),
523
+ /* @__PURE__ */ jsxs(Typography, { variant: "pi", color: "neutral300", children: [
524
+ /* @__PURE__ */ jsx(RelativeTime, { timestamp: new Date(release.createdAt) }),
525
+ formatMessage(
526
+ {
527
+ id: "content-releases.header.actions.created.description",
528
+ defaultMessage: "{hasCreatedByUser, select, true { by {createdBy}} other { by deleted user}}"
529
+ },
530
+ { createdBy: getCreatedByUser(), hasCreatedByUser }
531
+ )
532
+ ] })
533
+ ]
534
+ }
535
+ )
536
+ ] })
537
+ ] }),
353
538
  /* @__PURE__ */ jsx(Button, { size: "S", variant: "tertiary", onClick: handleRefresh, children: formatMessage({
354
539
  id: "content-releases.header.actions.refresh",
355
540
  defaultMessage: "Refresh"
@@ -405,6 +590,9 @@ const ReleaseDetailsBody = () => {
405
590
  isError: isReleaseError,
406
591
  error: releaseError
407
592
  } = useGetReleaseQuery({ id: releaseId });
593
+ const {
594
+ allowedActions: { canUpdate }
595
+ } = useRBAC(PERMISSIONS);
408
596
  const release = releaseData?.data;
409
597
  const selectedGroupBy = query?.groupBy || "contentType";
410
598
  const {
@@ -511,7 +699,7 @@ const ReleaseDetailsBody = () => {
511
699
  SingleSelect,
512
700
  {
513
701
  "aria-label": formatMessage({
514
- id: "content-releases.pages.ReleaseDetails.groupBy.label",
702
+ id: "content-releases.pages.ReleaseDetails.groupBy.aria-label",
515
703
  defaultMessage: "Group by"
516
704
  }),
517
705
  customizeContent: (value) => formatMessage(
@@ -529,7 +717,7 @@ const ReleaseDetailsBody = () => {
529
717
  }
530
718
  ) }),
531
719
  Object.keys(releaseActions).map((key) => /* @__PURE__ */ jsxs(Flex, { gap: 4, direction: "column", alignItems: "stretch", children: [
532
- /* @__PURE__ */ jsx(Flex, { children: /* @__PURE__ */ jsx(Badge, { children: key }) }),
720
+ /* @__PURE__ */ jsx(Flex, { role: "separator", "aria-label": key, children: /* @__PURE__ */ jsx(Badge, { children: key }) }),
533
721
  /* @__PURE__ */ jsx(
534
722
  Table.Root,
535
723
  {
@@ -618,7 +806,8 @@ const ReleaseDetailsBody = () => {
618
806
  {
619
807
  selected: type,
620
808
  handleChange: (e) => handleChangeType(e, id, [key, actionIndex]),
621
- name: `release-action-${id}-type`
809
+ name: `release-action-${id}-type`,
810
+ disabled: !canUpdate
622
811
  }
623
812
  ) }),
624
813
  !release.releasedAt && /* @__PURE__ */ jsxs(Fragment, { children: [
@@ -697,11 +886,18 @@ const ReleaseDetailsPage = () => {
697
886
  }
698
887
  );
699
888
  }
700
- const title = isSuccessDetails && data?.data?.name || "";
889
+ const releaseData = isSuccessDetails && data?.data || null;
890
+ const title = releaseData?.name || "";
891
+ const timezone = releaseData?.timezone ?? null;
892
+ const scheduledAt = releaseData?.scheduledAt && timezone ? utcToZonedTime(releaseData.scheduledAt, timezone) : null;
893
+ const date = scheduledAt ? new Date(format(scheduledAt, "yyyy-MM-dd")) : null;
894
+ const time = scheduledAt ? format(scheduledAt, "HH:mm") : "";
701
895
  const handleEditRelease = async (values) => {
702
896
  const response = await updateRelease({
703
897
  id: releaseId,
704
- name: values.name
898
+ name: values.name,
899
+ scheduledAt: values.scheduledAt,
900
+ timezone: values.timezone
705
901
  });
706
902
  if ("data" in response) {
707
903
  toggleNotification({
@@ -755,7 +951,14 @@ const ReleaseDetailsPage = () => {
755
951
  handleClose: toggleEditReleaseModal,
756
952
  handleSubmit: handleEditRelease,
757
953
  isLoading: isLoadingDetails || isSubmittingForm,
758
- initialValues: { name: title || "" }
954
+ initialValues: {
955
+ name: title || "",
956
+ scheduledAt,
957
+ date,
958
+ time,
959
+ isScheduled: Boolean(scheduledAt),
960
+ timezone
961
+ }
759
962
  }
760
963
  ),
761
964
  /* @__PURE__ */ jsx(
@@ -835,7 +1038,13 @@ const StyledAlert = styled(Alert)`
835
1038
  }
836
1039
  `;
837
1040
  const INITIAL_FORM_VALUES = {
838
- name: ""
1041
+ name: "",
1042
+ date: null,
1043
+ time: "",
1044
+ // Remove future flag check after Scheduling Beta release and replace with true as creating new release should include scheduling by default
1045
+ isScheduled: window.strapi.future.isEnabled("contentReleasesScheduling"),
1046
+ scheduledAt: null,
1047
+ timezone: null
839
1048
  };
840
1049
  const ReleasesPage = () => {
841
1050
  const tabRef = React.useRef(null);
@@ -895,9 +1104,11 @@ const ReleasesPage = () => {
895
1104
  }
896
1105
  });
897
1106
  };
898
- const handleAddRelease = async (values) => {
1107
+ const handleAddRelease = async ({ name, scheduledAt, timezone }) => {
899
1108
  const response2 = await createRelease({
900
- name: values.name
1109
+ name,
1110
+ scheduledAt,
1111
+ timezone
901
1112
  });
902
1113
  if ("data" in response2) {
903
1114
  toggleNotification({
@@ -1059,4 +1270,4 @@ const App = () => {
1059
1270
  export {
1060
1271
  App
1061
1272
  };
1062
- //# sourceMappingURL=App-3ycH2d3s.mjs.map
1273
+ //# sourceMappingURL=App-ise7GunC.mjs.map