@strapi/content-releases 0.0.0-next.287aae0bb4a682fba312332372895dbf8e032bf1 → 0.0.0-next.2a816cdadd2ece37767550b2a249c03ef2b53aeb

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-M11U5GPh.mjs → App-eVYKuxUc.mjs} +377 -159
  2. package/dist/_chunks/App-eVYKuxUc.mjs.map +1 -0
  3. package/dist/_chunks/{App-x6I6piPB.js → App-oGnTffWo.js} +375 -156
  4. package/dist/_chunks/App-oGnTffWo.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--WvbU-_H.js → en-r0otWaln.js} +13 -2
  10. package/dist/_chunks/en-r0otWaln.js.map +1 -0
  11. package/dist/_chunks/{en-oREbrNEq.mjs → en-veqvqeEr.mjs} +13 -2
  12. package/dist/_chunks/en-veqvqeEr.mjs.map +1 -0
  13. package/dist/_chunks/{index-Ls9Qc5Tg.mjs → index-8XT9UxC5.mjs} +101 -20
  14. package/dist/_chunks/index-8XT9UxC5.mjs.map +1 -0
  15. package/dist/_chunks/{index-M4gICzzI.js → index-ABxBBqzg.js} +97 -16
  16. package/dist/_chunks/index-ABxBBqzg.js.map +1 -0
  17. package/dist/admin/index.js +1 -1
  18. package/dist/admin/index.mjs +2 -2
  19. package/dist/server/index.js +566 -395
  20. package/dist/server/index.js.map +1 -1
  21. package/dist/server/index.mjs +566 -395
  22. package/dist/server/index.mjs.map +1 -1
  23. package/package.json +12 -9
  24. package/dist/_chunks/App-M11U5GPh.mjs.map +0 -1
  25. package/dist/_chunks/App-x6I6piPB.js.map +0 -1
  26. package/dist/_chunks/en--WvbU-_H.js.map +0 -1
  27. package/dist/_chunks/en-oREbrNEq.mjs.map +0 -1
  28. package/dist/_chunks/index-Ls9Qc5Tg.mjs.map +0 -1
  29. package/dist/_chunks/index-M4gICzzI.js.map +0 -1
@@ -3,14 +3,17 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
3
3
  const jsxRuntime = require("react/jsx-runtime");
4
4
  const helperPlugin = require("@strapi/helper-plugin");
5
5
  const reactRouterDom = require("react-router-dom");
6
- const index = require("./index-M4gICzzI.js");
6
+ const index = require("./index-ABxBBqzg.js");
7
7
  const React = require("react");
8
8
  const strapiAdmin = require("@strapi/admin/strapi-admin");
9
9
  const designSystem = require("@strapi/design-system");
10
10
  const v2 = require("@strapi/design-system/v2");
11
11
  const icons = require("@strapi/icons");
12
+ const format = require("date-fns/format");
13
+ const dateFnsTz = require("date-fns-tz");
12
14
  const reactIntl = require("react-intl");
13
15
  const styled = require("styled-components");
16
+ const dateFns = require("date-fns");
14
17
  const formik = require("formik");
15
18
  const yup = require("yup");
16
19
  require("@reduxjs/toolkit/query");
@@ -37,10 +40,28 @@ function _interopNamespace(e) {
37
40
  return Object.freeze(n);
38
41
  }
39
42
  const React__namespace = /* @__PURE__ */ _interopNamespace(React);
43
+ const format__default = /* @__PURE__ */ _interopDefault(format);
40
44
  const styled__default = /* @__PURE__ */ _interopDefault(styled);
41
45
  const yup__namespace = /* @__PURE__ */ _interopNamespace(yup);
42
46
  const RELEASE_SCHEMA = yup__namespace.object().shape({
43
- name: yup__namespace.string().trim().required()
47
+ name: yup__namespace.string().trim().required(),
48
+ scheduledAt: yup__namespace.string().nullable(),
49
+ isScheduled: yup__namespace.boolean().optional(),
50
+ time: yup__namespace.string().when("isScheduled", {
51
+ is: true,
52
+ then: yup__namespace.string().trim().required(),
53
+ otherwise: yup__namespace.string().nullable()
54
+ }),
55
+ timezone: yup__namespace.string().when("isScheduled", {
56
+ is: true,
57
+ then: yup__namespace.string().required().nullable(),
58
+ otherwise: yup__namespace.string().nullable()
59
+ }),
60
+ date: yup__namespace.string().when("isScheduled", {
61
+ is: true,
62
+ then: yup__namespace.string().required().nullable(),
63
+ otherwise: yup__namespace.string().nullable()
64
+ })
44
65
  }).required().noUnknown();
45
66
  const ReleaseModal = ({
46
67
  handleClose,
@@ -51,6 +72,24 @@ const ReleaseModal = ({
51
72
  const { formatMessage } = reactIntl.useIntl();
52
73
  const { pathname } = reactRouterDom.useLocation();
53
74
  const isCreatingRelease = pathname === `/plugins/${index.pluginId}`;
75
+ const IsSchedulingEnabled = window.strapi.future.isEnabled("contentReleasesScheduling");
76
+ const { timezoneList, systemTimezone = { value: "UTC+00:00-Africa/Abidjan " } } = getTimezones(
77
+ initialValues.scheduledAt ? new Date(initialValues.scheduledAt) : /* @__PURE__ */ new Date()
78
+ );
79
+ const getScheduledTimestamp = (values) => {
80
+ const { date, time, timezone } = values;
81
+ if (!date || !time || !timezone)
82
+ return null;
83
+ const formattedDate = dateFns.parse(time, "HH:mm", new Date(date));
84
+ const timezoneWithoutOffset = timezone.split("-")[1];
85
+ return dateFnsTz.zonedTimeToUtc(formattedDate, timezoneWithoutOffset);
86
+ };
87
+ const getTimezoneWithOffset = () => {
88
+ const currentTimezone = timezoneList.find(
89
+ (timezone) => timezone.value.split("-")[1] === initialValues.timezone
90
+ );
91
+ return currentTimezone?.value || systemTimezone.value;
92
+ };
54
93
  return /* @__PURE__ */ jsxRuntime.jsxs(designSystem.ModalLayout, { onClose: handleClose, labelledBy: "title", children: [
55
94
  /* @__PURE__ */ jsxRuntime.jsx(designSystem.ModalHeader, { children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { id: "title", fontWeight: "bold", textColor: "neutral800", children: formatMessage(
56
95
  {
@@ -62,45 +101,134 @@ const ReleaseModal = ({
62
101
  /* @__PURE__ */ jsxRuntime.jsx(
63
102
  formik.Formik,
64
103
  {
65
- validateOnChange: false,
66
- onSubmit: handleSubmit,
67
- initialValues,
104
+ onSubmit: (values) => {
105
+ handleSubmit({
106
+ ...values,
107
+ timezone: values.timezone ? values.timezone.split("-")[1] : null,
108
+ scheduledAt: values.isScheduled ? getScheduledTimestamp(values) : null
109
+ });
110
+ },
111
+ initialValues: {
112
+ ...initialValues,
113
+ timezone: initialValues.timezone ? getTimezoneWithOffset() : systemTimezone.value
114
+ },
68
115
  validationSchema: RELEASE_SCHEMA,
69
- children: ({ values, errors, handleChange }) => /* @__PURE__ */ jsxRuntime.jsxs(formik.Form, { children: [
70
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.ModalBody, { children: /* @__PURE__ */ jsxRuntime.jsx(
71
- designSystem.TextInput,
72
- {
73
- label: formatMessage({
74
- id: "content-releases.modal.form.input.label.release-name",
75
- defaultMessage: "Name"
76
- }),
77
- name: "name",
78
- value: values.name,
79
- error: errors.name,
80
- onChange: handleChange,
81
- required: true
82
- }
83
- ) }),
116
+ validateOnChange: false,
117
+ children: ({ values, errors, handleChange, setFieldValue }) => /* @__PURE__ */ jsxRuntime.jsxs(formik.Form, { children: [
118
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.ModalBody, { children: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { direction: "column", alignItems: "stretch", gap: 6, children: [
119
+ /* @__PURE__ */ jsxRuntime.jsx(
120
+ designSystem.TextInput,
121
+ {
122
+ label: formatMessage({
123
+ id: "content-releases.modal.form.input.label.release-name",
124
+ defaultMessage: "Name"
125
+ }),
126
+ name: "name",
127
+ value: values.name,
128
+ error: errors.name,
129
+ onChange: handleChange,
130
+ required: true
131
+ }
132
+ ),
133
+ IsSchedulingEnabled && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
134
+ /* @__PURE__ */ jsxRuntime.jsx(
135
+ designSystem.Checkbox,
136
+ {
137
+ name: "isScheduled",
138
+ value: values.isScheduled,
139
+ onChange: (event) => {
140
+ setFieldValue("isScheduled", event.target.checked);
141
+ if (!event.target.checked) {
142
+ setFieldValue("date", null);
143
+ setFieldValue("time", "");
144
+ setFieldValue("timezone", null);
145
+ } else {
146
+ setFieldValue("date", initialValues.date);
147
+ setFieldValue("time", initialValues.time);
148
+ setFieldValue(
149
+ "timezone",
150
+ initialValues.timezone ?? systemTimezone?.value
151
+ );
152
+ }
153
+ },
154
+ children: /* @__PURE__ */ jsxRuntime.jsx(
155
+ designSystem.Typography,
156
+ {
157
+ textColor: values.isScheduled ? "primary600" : "neutral800",
158
+ fontWeight: values.isScheduled ? "semiBold" : "regular",
159
+ children: formatMessage({
160
+ id: "modal.form.input.label.schedule-release",
161
+ defaultMessage: "Schedule release"
162
+ })
163
+ }
164
+ )
165
+ }
166
+ ),
167
+ values.isScheduled && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
168
+ /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { gap: 4, alignItems: "start", children: [
169
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Box, { width: "100%", children: /* @__PURE__ */ jsxRuntime.jsx(
170
+ designSystem.DatePicker,
171
+ {
172
+ label: formatMessage({
173
+ id: "content-releases.modal.form.input.label.date",
174
+ defaultMessage: "Date"
175
+ }),
176
+ name: "date",
177
+ error: errors.date,
178
+ onChange: (date) => {
179
+ const isoFormatDate = date ? dateFns.formatISO(date, { representation: "date" }) : null;
180
+ setFieldValue("date", isoFormatDate);
181
+ },
182
+ clearLabel: formatMessage({
183
+ id: "content-releases.modal.form.input.clearLabel",
184
+ defaultMessage: "Clear"
185
+ }),
186
+ onClear: () => {
187
+ setFieldValue("date", null);
188
+ },
189
+ selectedDate: values.date || void 0,
190
+ required: true
191
+ }
192
+ ) }),
193
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Box, { width: "100%", children: /* @__PURE__ */ jsxRuntime.jsx(
194
+ designSystem.TimePicker,
195
+ {
196
+ label: formatMessage({
197
+ id: "content-releases.modal.form.input.label.time",
198
+ defaultMessage: "Time"
199
+ }),
200
+ name: "time",
201
+ error: errors.time,
202
+ onChange: (time) => {
203
+ setFieldValue("time", time);
204
+ },
205
+ clearLabel: formatMessage({
206
+ id: "content-releases.modal.form.input.clearLabel",
207
+ defaultMessage: "Clear"
208
+ }),
209
+ onClear: () => {
210
+ setFieldValue("time", "");
211
+ },
212
+ value: values.time || void 0,
213
+ required: true
214
+ }
215
+ ) })
216
+ ] }),
217
+ /* @__PURE__ */ jsxRuntime.jsx(TimezoneComponent, { timezoneOptions: timezoneList })
218
+ ] })
219
+ ] })
220
+ ] }) }),
84
221
  /* @__PURE__ */ jsxRuntime.jsx(
85
222
  designSystem.ModalFooter,
86
223
  {
87
224
  startActions: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Button, { onClick: handleClose, variant: "tertiary", name: "cancel", children: formatMessage({ id: "cancel", defaultMessage: "Cancel" }) }),
88
- endActions: /* @__PURE__ */ jsxRuntime.jsx(
89
- designSystem.Button,
225
+ endActions: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Button, { name: "submit", loading: isLoading, type: "submit", children: formatMessage(
90
226
  {
91
- name: "submit",
92
- loading: isLoading,
93
- disabled: !values.name || values.name === initialValues.name,
94
- type: "submit",
95
- children: formatMessage(
96
- {
97
- id: "content-releases.modal.form.button.submit",
98
- defaultMessage: "{isCreatingRelease, select, true {Continue} other {Save}}"
99
- },
100
- { isCreatingRelease }
101
- )
102
- }
103
- )
227
+ id: "content-releases.modal.form.button.submit",
228
+ defaultMessage: "{isCreatingRelease, select, true {Continue} other {Save}}"
229
+ },
230
+ { isCreatingRelease }
231
+ ) })
104
232
  }
105
233
  )
106
234
  ] })
@@ -108,16 +236,59 @@ const ReleaseModal = ({
108
236
  )
109
237
  ] });
110
238
  };
239
+ const getTimezones = (selectedDate) => {
240
+ const timezoneList = Intl.supportedValuesOf("timeZone").map((timezone) => {
241
+ const utcOffset = index.getTimezoneOffset(timezone, selectedDate);
242
+ return { offset: utcOffset, value: `${utcOffset}-${timezone}` };
243
+ });
244
+ const systemTimezone = timezoneList.find(
245
+ (timezone) => timezone.value.split("-")[1] === Intl.DateTimeFormat().resolvedOptions().timeZone
246
+ );
247
+ return { timezoneList, systemTimezone };
248
+ };
249
+ const TimezoneComponent = ({ timezoneOptions }) => {
250
+ const { values, errors, setFieldValue } = formik.useFormikContext();
251
+ const { formatMessage } = reactIntl.useIntl();
252
+ const [timezoneList, setTimezoneList] = React__namespace.useState(timezoneOptions);
253
+ React__namespace.useEffect(() => {
254
+ if (values.date) {
255
+ const { timezoneList: timezoneList2 } = getTimezones(new Date(values.date));
256
+ setTimezoneList(timezoneList2);
257
+ const updatedTimezone = values.timezone && timezoneList2.find((tz) => tz.value.split("-")[1] === values.timezone.split("-")[1]);
258
+ if (updatedTimezone) {
259
+ setFieldValue("timezone", updatedTimezone.value);
260
+ }
261
+ }
262
+ }, [setFieldValue, values.date, values.timezone]);
263
+ return /* @__PURE__ */ jsxRuntime.jsx(
264
+ designSystem.Combobox,
265
+ {
266
+ label: formatMessage({
267
+ id: "content-releases.modal.form.input.label.timezone",
268
+ defaultMessage: "Timezone"
269
+ }),
270
+ name: "timezone",
271
+ value: values.timezone || void 0,
272
+ textValue: values.timezone ? values.timezone.replace("-", " ") : void 0,
273
+ onChange: (timezone) => {
274
+ setFieldValue("timezone", timezone);
275
+ },
276
+ onClear: () => {
277
+ setFieldValue("timezone", "");
278
+ },
279
+ error: errors.timezone,
280
+ required: true,
281
+ children: timezoneList.map((timezone) => /* @__PURE__ */ jsxRuntime.jsx(designSystem.ComboboxOption, { value: timezone.value, children: timezone.value.replace("-", " ") }, timezone.value))
282
+ }
283
+ );
284
+ };
111
285
  const ReleaseInfoWrapper = styled__default.default(designSystem.Flex)`
112
286
  align-self: stretch;
113
287
  border-bottom-right-radius: ${({ theme }) => theme.borderRadius};
114
288
  border-bottom-left-radius: ${({ theme }) => theme.borderRadius};
115
289
  border-top: 1px solid ${({ theme }) => theme.colors.neutral150};
116
290
  `;
117
- const StyledFlex = styled__default.default(designSystem.Flex)`
118
- align-self: stretch;
119
- cursor: ${({ disabled }) => disabled ? "not-allowed" : "pointer"};
120
-
291
+ const StyledMenuItem = styled__default.default(v2.Menu.Item)`
121
292
  svg path {
122
293
  fill: ${({ theme, disabled }) => disabled && theme.colors.neutral500};
123
294
  }
@@ -142,24 +313,6 @@ const TrashIcon = styled__default.default(icons.Trash)`
142
313
  const TypographyMaxWidth = styled__default.default(designSystem.Typography)`
143
314
  max-width: 300px;
144
315
  `;
145
- const PopoverButton = ({ onClick, disabled, children }) => {
146
- return /* @__PURE__ */ jsxRuntime.jsx(
147
- StyledFlex,
148
- {
149
- paddingTop: 2,
150
- paddingBottom: 2,
151
- paddingLeft: 4,
152
- paddingRight: 4,
153
- alignItems: "center",
154
- gap: 2,
155
- as: "button",
156
- hasRadius: true,
157
- onClick,
158
- disabled,
159
- children
160
- }
161
- );
162
- };
163
316
  const EntryValidationText = ({ action, schema, components, entry }) => {
164
317
  const { formatMessage } = reactIntl.useIntl();
165
318
  const { validate } = strapiAdmin.unstable_useDocument();
@@ -208,10 +361,8 @@ const ReleaseDetailsLayout = ({
208
361
  toggleWarningSubmit,
209
362
  children
210
363
  }) => {
211
- const { formatMessage } = reactIntl.useIntl();
364
+ const { formatMessage, formatDate, formatTime } = reactIntl.useIntl();
212
365
  const { releaseId } = reactRouterDom.useParams();
213
- const [isPopoverVisible, setIsPopoverVisible] = React__namespace.useState(false);
214
- const moreButtonRef = React__namespace.useRef(null);
215
366
  const {
216
367
  data,
217
368
  isLoading: isLoadingDetails,
@@ -227,13 +378,6 @@ const ReleaseDetailsLayout = ({
227
378
  const dispatch = index.useTypedDispatch();
228
379
  const { trackUsage } = helperPlugin.useTracking();
229
380
  const release = data?.data;
230
- const handleTogglePopover = () => {
231
- setIsPopoverVisible((prev) => !prev);
232
- };
233
- const openReleaseModal = () => {
234
- toggleEditReleaseModal();
235
- handleTogglePopover();
236
- };
237
381
  const handlePublishRelease = async () => {
238
382
  const response = await publishRelease({ id: releaseId });
239
383
  if ("data" in response) {
@@ -262,10 +406,6 @@ const ReleaseDetailsLayout = ({
262
406
  });
263
407
  }
264
408
  };
265
- const openWarningConfirmDialog = () => {
266
- toggleWarningSubmit();
267
- handleTogglePopover();
268
- };
269
409
  const handleRefresh = () => {
270
410
  dispatch(index.releaseApi.util.invalidateTags([{ type: "ReleaseAction", id: "LIST" }]));
271
411
  };
@@ -303,89 +443,138 @@ const ReleaseDetailsLayout = ({
303
443
  }
304
444
  const totalEntries = release.actions.meta.count || 0;
305
445
  const hasCreatedByUser = Boolean(getCreatedByUser());
446
+ const IsSchedulingEnabled = window.strapi.future.isEnabled("contentReleasesScheduling");
447
+ const isScheduled = release.scheduledAt && release.timezone;
448
+ const numberOfEntriesText = formatMessage(
449
+ {
450
+ id: "content-releases.pages.Details.header-subtitle",
451
+ defaultMessage: "{number, plural, =0 {No entries} one {# entry} other {# entries}}"
452
+ },
453
+ { number: totalEntries }
454
+ );
455
+ const scheduledText = isScheduled ? formatMessage(
456
+ {
457
+ id: "content-releases.pages.ReleaseDetails.header-subtitle.scheduled",
458
+ defaultMessage: "Scheduled for {date} at {time} ({offset})"
459
+ },
460
+ {
461
+ date: formatDate(new Date(release.scheduledAt), {
462
+ weekday: "long",
463
+ day: "numeric",
464
+ month: "long",
465
+ year: "numeric",
466
+ timeZone: release.timezone
467
+ }),
468
+ time: formatTime(new Date(release.scheduledAt), {
469
+ hour12: false,
470
+ timeZone: release.timezone
471
+ }),
472
+ offset: index.getTimezoneOffset(release.timezone, new Date(release.scheduledAt))
473
+ }
474
+ ) : "";
306
475
  return /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Main, { "aria-busy": isLoadingDetails, children: [
307
476
  /* @__PURE__ */ jsxRuntime.jsx(
308
477
  designSystem.HeaderLayout,
309
478
  {
310
479
  title: release.name,
311
- subtitle: formatMessage(
312
- {
313
- id: "content-releases.pages.Details.header-subtitle",
314
- defaultMessage: "{number, plural, =0 {No entries} one {# entry} other {# entries}}"
315
- },
316
- { number: totalEntries }
317
- ),
480
+ subtitle: numberOfEntriesText + (IsSchedulingEnabled && isScheduled ? `- ${scheduledText}` : ""),
318
481
  navigationAction: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Link, { startIcon: /* @__PURE__ */ jsxRuntime.jsx(icons.ArrowLeft, {}), to: "/plugins/content-releases", children: formatMessage({
319
482
  id: "global.back",
320
483
  defaultMessage: "Back"
321
484
  }) }),
322
485
  primaryAction: !release.releasedAt && /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { gap: 2, children: [
323
- /* @__PURE__ */ jsxRuntime.jsx(
324
- designSystem.IconButton,
325
- {
326
- label: formatMessage({
327
- id: "content-releases.header.actions.open-release-actions",
328
- defaultMessage: "Release edit and delete menu"
329
- }),
330
- ref: moreButtonRef,
331
- onClick: handleTogglePopover,
332
- children: /* @__PURE__ */ jsxRuntime.jsx(icons.More, {})
333
- }
334
- ),
335
- isPopoverVisible && /* @__PURE__ */ jsxRuntime.jsxs(
336
- designSystem.Popover,
337
- {
338
- source: moreButtonRef,
339
- placement: "bottom-end",
340
- onDismiss: handleTogglePopover,
341
- spacing: 4,
342
- minWidth: "242px",
343
- children: [
344
- /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { alignItems: "center", justifyContent: "center", direction: "column", padding: 1, children: [
345
- /* @__PURE__ */ jsxRuntime.jsxs(PopoverButton, { disabled: !canUpdate, onClick: openReleaseModal, children: [
346
- /* @__PURE__ */ jsxRuntime.jsx(PencilIcon, {}),
347
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { ellipsis: true, children: formatMessage({
348
- id: "content-releases.header.actions.edit",
349
- defaultMessage: "Edit"
350
- }) })
351
- ] }),
352
- /* @__PURE__ */ jsxRuntime.jsxs(PopoverButton, { disabled: !canDelete, onClick: openWarningConfirmDialog, children: [
353
- /* @__PURE__ */ jsxRuntime.jsx(TrashIcon, {}),
354
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { ellipsis: true, textColor: "danger600", children: formatMessage({
355
- id: "content-releases.header.actions.delete",
356
- defaultMessage: "Delete"
357
- }) })
358
- ] })
359
- ] }),
360
- /* @__PURE__ */ jsxRuntime.jsxs(
361
- ReleaseInfoWrapper,
362
- {
363
- direction: "column",
364
- justifyContent: "center",
365
- alignItems: "flex-start",
366
- gap: 1,
367
- padding: 5,
368
- children: [
369
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "pi", fontWeight: "bold", children: formatMessage({
370
- id: "content-releases.header.actions.created",
371
- defaultMessage: "Created"
372
- }) }),
373
- /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Typography, { variant: "pi", color: "neutral300", children: [
374
- /* @__PURE__ */ jsxRuntime.jsx(helperPlugin.RelativeTime, { timestamp: new Date(release.createdAt) }),
375
- formatMessage(
376
- {
377
- id: "content-releases.header.actions.created.description",
378
- defaultMessage: "{hasCreatedByUser, select, true { by {createdBy}} other { by deleted user}}"
379
- },
380
- { createdBy: getCreatedByUser(), hasCreatedByUser }
381
- )
382
- ] })
383
- ]
384
- }
385
- )
386
- ]
387
- }
388
- ),
486
+ /* @__PURE__ */ jsxRuntime.jsxs(v2.Menu.Root, { children: [
487
+ /* @__PURE__ */ jsxRuntime.jsx(
488
+ v2.Menu.Trigger,
489
+ {
490
+ as: designSystem.IconButton,
491
+ paddingLeft: 2,
492
+ paddingRight: 2,
493
+ "aria-label": formatMessage({
494
+ id: "content-releases.header.actions.open-release-actions",
495
+ defaultMessage: "Release edit and delete menu"
496
+ }),
497
+ icon: /* @__PURE__ */ jsxRuntime.jsx(icons.More, {}),
498
+ variant: "tertiary"
499
+ }
500
+ ),
501
+ /* @__PURE__ */ jsxRuntime.jsxs(v2.Menu.Content, { top: 1, popoverPlacement: "bottom-end", children: [
502
+ /* @__PURE__ */ jsxRuntime.jsxs(
503
+ designSystem.Flex,
504
+ {
505
+ alignItems: "center",
506
+ justifyContent: "center",
507
+ direction: "column",
508
+ padding: 1,
509
+ width: "100%",
510
+ children: [
511
+ /* @__PURE__ */ jsxRuntime.jsx(StyledMenuItem, { disabled: !canUpdate, onSelect: toggleEditReleaseModal, children: /* @__PURE__ */ jsxRuntime.jsxs(
512
+ designSystem.Flex,
513
+ {
514
+ paddingTop: 2,
515
+ paddingBottom: 2,
516
+ alignItems: "center",
517
+ gap: 2,
518
+ hasRadius: true,
519
+ width: "100%",
520
+ children: [
521
+ /* @__PURE__ */ jsxRuntime.jsx(PencilIcon, {}),
522
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { ellipsis: true, children: formatMessage({
523
+ id: "content-releases.header.actions.edit",
524
+ defaultMessage: "Edit"
525
+ }) })
526
+ ]
527
+ }
528
+ ) }),
529
+ /* @__PURE__ */ jsxRuntime.jsx(StyledMenuItem, { disabled: !canDelete, onSelect: toggleWarningSubmit, children: /* @__PURE__ */ jsxRuntime.jsxs(
530
+ designSystem.Flex,
531
+ {
532
+ paddingTop: 2,
533
+ paddingBottom: 2,
534
+ alignItems: "center",
535
+ gap: 2,
536
+ hasRadius: true,
537
+ width: "100%",
538
+ children: [
539
+ /* @__PURE__ */ jsxRuntime.jsx(TrashIcon, {}),
540
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { ellipsis: true, textColor: "danger600", children: formatMessage({
541
+ id: "content-releases.header.actions.delete",
542
+ defaultMessage: "Delete"
543
+ }) })
544
+ ]
545
+ }
546
+ ) })
547
+ ]
548
+ }
549
+ ),
550
+ /* @__PURE__ */ jsxRuntime.jsxs(
551
+ ReleaseInfoWrapper,
552
+ {
553
+ direction: "column",
554
+ justifyContent: "center",
555
+ alignItems: "flex-start",
556
+ gap: 1,
557
+ padding: 5,
558
+ children: [
559
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "pi", fontWeight: "bold", children: formatMessage({
560
+ id: "content-releases.header.actions.created",
561
+ defaultMessage: "Created"
562
+ }) }),
563
+ /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Typography, { variant: "pi", color: "neutral300", children: [
564
+ /* @__PURE__ */ jsxRuntime.jsx(helperPlugin.RelativeTime, { timestamp: new Date(release.createdAt) }),
565
+ formatMessage(
566
+ {
567
+ id: "content-releases.header.actions.created.description",
568
+ defaultMessage: "{hasCreatedByUser, select, true { by {createdBy}} other { by deleted user}}"
569
+ },
570
+ { createdBy: getCreatedByUser(), hasCreatedByUser }
571
+ )
572
+ ] })
573
+ ]
574
+ }
575
+ )
576
+ ] })
577
+ ] }),
389
578
  /* @__PURE__ */ jsxRuntime.jsx(designSystem.Button, { size: "S", variant: "tertiary", onClick: handleRefresh, children: formatMessage({
390
579
  id: "content-releases.header.actions.refresh",
391
580
  defaultMessage: "Refresh"
@@ -441,6 +630,9 @@ const ReleaseDetailsBody = () => {
441
630
  isError: isReleaseError,
442
631
  error: releaseError
443
632
  } = index.useGetReleaseQuery({ id: releaseId });
633
+ const {
634
+ allowedActions: { canUpdate }
635
+ } = helperPlugin.useRBAC(index.PERMISSIONS);
444
636
  const release = releaseData?.data;
445
637
  const selectedGroupBy = query?.groupBy || "contentType";
446
638
  const {
@@ -547,7 +739,7 @@ const ReleaseDetailsBody = () => {
547
739
  designSystem.SingleSelect,
548
740
  {
549
741
  "aria-label": formatMessage({
550
- id: "content-releases.pages.ReleaseDetails.groupBy.label",
742
+ id: "content-releases.pages.ReleaseDetails.groupBy.aria-label",
551
743
  defaultMessage: "Group by"
552
744
  }),
553
745
  customizeContent: (value) => formatMessage(
@@ -565,7 +757,7 @@ const ReleaseDetailsBody = () => {
565
757
  }
566
758
  ) }),
567
759
  Object.keys(releaseActions).map((key) => /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { gap: 4, direction: "column", alignItems: "stretch", children: [
568
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Flex, { children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Badge, { children: key }) }),
760
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Flex, { role: "separator", "aria-label": key, children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Badge, { children: key }) }),
569
761
  /* @__PURE__ */ jsxRuntime.jsx(
570
762
  helperPlugin.Table.Root,
571
763
  {
@@ -654,7 +846,8 @@ const ReleaseDetailsBody = () => {
654
846
  {
655
847
  selected: type,
656
848
  handleChange: (e) => handleChangeType(e, id, [key, actionIndex]),
657
- name: `release-action-${id}-type`
849
+ name: `release-action-${id}-type`,
850
+ disabled: !canUpdate
658
851
  }
659
852
  ) }),
660
853
  !release.releasedAt && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
@@ -733,11 +926,18 @@ const ReleaseDetailsPage = () => {
733
926
  }
734
927
  );
735
928
  }
736
- const title = isSuccessDetails && data?.data?.name || "";
929
+ const releaseData = isSuccessDetails && data?.data || null;
930
+ const title = releaseData?.name || "";
931
+ const timezone = releaseData?.timezone ?? null;
932
+ const scheduledAt = releaseData?.scheduledAt && timezone ? dateFnsTz.utcToZonedTime(releaseData.scheduledAt, timezone) : null;
933
+ const date = scheduledAt ? new Date(format__default.default(scheduledAt, "yyyy-MM-dd")) : null;
934
+ const time = scheduledAt ? format__default.default(scheduledAt, "HH:mm") : "";
737
935
  const handleEditRelease = async (values) => {
738
936
  const response = await updateRelease({
739
937
  id: releaseId,
740
- name: values.name
938
+ name: values.name,
939
+ scheduledAt: values.scheduledAt,
940
+ timezone: values.timezone
741
941
  });
742
942
  if ("data" in response) {
743
943
  toggleNotification({
@@ -791,7 +991,14 @@ const ReleaseDetailsPage = () => {
791
991
  handleClose: toggleEditReleaseModal,
792
992
  handleSubmit: handleEditRelease,
793
993
  isLoading: isLoadingDetails || isSubmittingForm,
794
- initialValues: { name: title || "" }
994
+ initialValues: {
995
+ name: title || "",
996
+ scheduledAt,
997
+ date,
998
+ time,
999
+ isScheduled: Boolean(scheduledAt),
1000
+ timezone
1001
+ }
795
1002
  }
796
1003
  ),
797
1004
  /* @__PURE__ */ jsxRuntime.jsx(
@@ -816,6 +1023,7 @@ const LinkCard = styled__default.default(v2.Link)`
816
1023
  `;
817
1024
  const ReleasesGrid = ({ sectionTitle, releases = [], isError = false }) => {
818
1025
  const { formatMessage } = reactIntl.useIntl();
1026
+ const IsSchedulingEnabled = window.strapi.future.isEnabled("contentReleasesScheduling");
819
1027
  if (isError) {
820
1028
  return /* @__PURE__ */ jsxRuntime.jsx(helperPlugin.AnErrorOccurred, {});
821
1029
  }
@@ -836,7 +1044,7 @@ const ReleasesGrid = ({ sectionTitle, releases = [], isError = false }) => {
836
1044
  }
837
1045
  );
838
1046
  }
839
- return /* @__PURE__ */ jsxRuntime.jsx(designSystem.Grid, { gap: 4, children: releases.map(({ id, name, actions }) => /* @__PURE__ */ jsxRuntime.jsx(designSystem.GridItem, { col: 3, s: 6, xs: 12, children: /* @__PURE__ */ jsxRuntime.jsx(LinkCard, { href: `content-releases/${id}`, isExternal: false, children: /* @__PURE__ */ jsxRuntime.jsxs(
1047
+ return /* @__PURE__ */ jsxRuntime.jsx(designSystem.Grid, { gap: 4, children: releases.map(({ id, name, actions, scheduledAt }) => /* @__PURE__ */ jsxRuntime.jsx(designSystem.GridItem, { col: 3, s: 6, xs: 12, children: /* @__PURE__ */ jsxRuntime.jsx(LinkCard, { href: `content-releases/${id}`, isExternal: false, children: /* @__PURE__ */ jsxRuntime.jsxs(
840
1048
  designSystem.Flex,
841
1049
  {
842
1050
  direction: "column",
@@ -851,7 +1059,10 @@ const ReleasesGrid = ({ sectionTitle, releases = [], isError = false }) => {
851
1059
  gap: 2,
852
1060
  children: [
853
1061
  /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { as: "h3", variant: "delta", fontWeight: "bold", children: name }),
854
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "pi", children: formatMessage(
1062
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "pi", textColor: "neutral600", children: IsSchedulingEnabled ? scheduledAt ? /* @__PURE__ */ jsxRuntime.jsx(helperPlugin.RelativeTime, { timestamp: new Date(scheduledAt) }) : formatMessage({
1063
+ id: "content-releases.pages.Releases.not-scheduled",
1064
+ defaultMessage: "Not scheduled"
1065
+ }) : formatMessage(
855
1066
  {
856
1067
  id: "content-releases.page.Releases.release-item.entries",
857
1068
  defaultMessage: "{number, plural, =0 {No entries} one {# entry} other {# entries}}"
@@ -871,7 +1082,13 @@ const StyledAlert = styled__default.default(designSystem.Alert)`
871
1082
  }
872
1083
  `;
873
1084
  const INITIAL_FORM_VALUES = {
874
- name: ""
1085
+ name: "",
1086
+ date: null,
1087
+ time: "",
1088
+ // Remove future flag check after Scheduling Beta release and replace with true as creating new release should include scheduling by default
1089
+ isScheduled: window.strapi.future.isEnabled("contentReleasesScheduling"),
1090
+ scheduledAt: null,
1091
+ timezone: null
875
1092
  };
876
1093
  const ReleasesPage = () => {
877
1094
  const tabRef = React__namespace.useRef(null);
@@ -931,9 +1148,11 @@ const ReleasesPage = () => {
931
1148
  }
932
1149
  });
933
1150
  };
934
- const handleAddRelease = async (values) => {
1151
+ const handleAddRelease = async ({ name, scheduledAt, timezone }) => {
935
1152
  const response2 = await createRelease({
936
- name: values.name
1153
+ name,
1154
+ scheduledAt,
1155
+ timezone
937
1156
  });
938
1157
  if ("data" in response2) {
939
1158
  toggleNotification({
@@ -1093,4 +1312,4 @@ const App = () => {
1093
1312
  ] }) });
1094
1313
  };
1095
1314
  exports.App = App;
1096
- //# sourceMappingURL=App-x6I6piPB.js.map
1315
+ //# sourceMappingURL=App-oGnTffWo.js.map