@strapi/content-releases 0.0.0-next.90a86f595c31de9a89f4255318bfb0cccb30ceed → 0.0.0-next.9bff6e6b8e2a2c7445d3650f1b3459f1b0366db8

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-pspKUC-W.js → App-c5uGEz9O.js} +596 -355
  2. package/dist/_chunks/App-c5uGEz9O.js.map +1 -0
  3. package/dist/_chunks/{App-8FCxPK8-.mjs → App-xQ5ljY7-.mjs} +606 -366
  4. package/dist/_chunks/App-xQ5ljY7-.mjs.map +1 -0
  5. package/dist/_chunks/PurchaseContentReleases-3tRbmbY3.mjs +51 -0
  6. package/dist/_chunks/PurchaseContentReleases-3tRbmbY3.mjs.map +1 -0
  7. package/dist/_chunks/PurchaseContentReleases-bpIYXOfu.js +51 -0
  8. package/dist/_chunks/PurchaseContentReleases-bpIYXOfu.js.map +1 -0
  9. package/dist/_chunks/{en-r9YocBH0.js → en-3SGjiVyR.js} +23 -5
  10. package/dist/_chunks/en-3SGjiVyR.js.map +1 -0
  11. package/dist/_chunks/{en-m9eTk4UF.mjs → en-bpHsnU0n.mjs} +23 -5
  12. package/dist/_chunks/en-bpHsnU0n.mjs.map +1 -0
  13. package/dist/_chunks/{index-nGaPcY9m.js → index-4U0Q_Fgd.js} +279 -12
  14. package/dist/_chunks/index-4U0Q_Fgd.js.map +1 -0
  15. package/dist/_chunks/{index-8aK7GzI5.mjs → index-ifoPtgmH.mjs} +291 -24
  16. package/dist/_chunks/index-ifoPtgmH.mjs.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 +885 -437
  20. package/dist/server/index.js.map +1 -1
  21. package/dist/server/index.mjs +884 -437
  22. package/dist/server/index.mjs.map +1 -1
  23. package/package.json +13 -11
  24. package/dist/_chunks/App-8FCxPK8-.mjs.map +0 -1
  25. package/dist/_chunks/App-pspKUC-W.js.map +0 -1
  26. package/dist/_chunks/en-m9eTk4UF.mjs.map +0 -1
  27. package/dist/_chunks/en-r9YocBH0.js.map +0 -1
  28. package/dist/_chunks/index-8aK7GzI5.mjs.map +0 -1
  29. package/dist/_chunks/index-nGaPcY9m.js.map +0 -1
@@ -1,15 +1,18 @@
1
1
  import { jsxs, jsx, Fragment } from "react/jsx-runtime";
2
- import { useNotification, useAPIErrorHandler, LoadingIndicatorPage, ConfirmDialog, useRBAC, useTracking, RelativeTime, CheckPermissions, useQueryParams, AnErrorOccurred, NoContent, Table, PageSizeURLQuery, PaginationURLQuery, CheckPagePermissions } from "@strapi/helper-plugin";
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-8aK7GzI5.mjs";
2
+ import { RelativeTime, useNotification, useAPIErrorHandler, useQueryParams, useTracking, LoadingIndicatorPage, CheckPermissions, PageSizeURLQuery, PaginationURLQuery, AnErrorOccurred, ConfirmDialog, useRBAC, NoContent, Table, CheckPagePermissions } from "@strapi/helper-plugin";
3
+ import { useLocation, useHistory, useParams, Redirect, Link as Link$2, Switch, Route } from "react-router-dom";
4
+ import { g as getTimezoneOffset, p as pluginId, u as useGetReleasesQuery, a as useCreateReleaseMutation, P as PERMISSIONS, i as isAxiosError, b as useGetReleaseQuery, c as useUpdateReleaseMutation, d as useDeleteReleaseMutation, e as usePublishReleaseMutation, f as useTypedDispatch, h as useGetReleaseActionsQuery, j as useUpdateReleaseActionMutation, R as ReleaseActionOptions, k as ReleaseActionMenu, r as releaseApi } from "./index-ifoPtgmH.mjs";
5
5
  import * as React from "react";
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, SingleSelect, SingleSelectOption, Badge, Tr, Td, Icon, Tooltip, Alert, TabGroup, Box, 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
- import { Pencil, Trash, ArrowLeft, More, CrossCircle, CheckCircle, Plus, EmptyDocuments } from "@strapi/icons";
6
+ import { useLicenseLimits, unstable_useDocument } from "@strapi/admin/strapi-admin";
7
+ import { ModalLayout, ModalHeader, Typography, ModalBody, Flex, TextInput, Box, Checkbox, DatePicker, TimePicker, ModalFooter, Button, Combobox, ComboboxOption, Alert, Main, HeaderLayout, ContentLayout, TabGroup, Tabs, Tab, Divider, TabPanels, TabPanel, EmptyStateLayout, Grid, GridItem, Badge, Link as Link$1, IconButton, SingleSelect, SingleSelectOption, Tr, Td, Icon, Tooltip } from "@strapi/design-system";
8
+ import { Link, Menu, LinkButton } from "@strapi/design-system/v2";
9
+ import { Plus, EmptyDocuments, Pencil, Trash, ArrowLeft, More, CrossCircle, CheckCircle } from "@strapi/icons";
10
+ import format from "date-fns/format";
11
+ import { utcToZonedTime, zonedTimeToUtc } 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 } 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";
@@ -17,8 +20,23 @@ import "@reduxjs/toolkit/query/react";
17
20
  import "react-redux";
18
21
  const RELEASE_SCHEMA = yup.object().shape({
19
22
  name: yup.string().trim().required(),
20
- // scheduledAt is a date, but we always receive strings from the client
21
- scheduledAt: yup.string().nullable()
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
+ })
22
40
  }).required().noUnknown();
23
41
  const ReleaseModal = ({
24
42
  handleClose,
@@ -29,6 +47,22 @@ const ReleaseModal = ({
29
47
  const { formatMessage } = useIntl();
30
48
  const { pathname } = useLocation();
31
49
  const isCreatingRelease = pathname === `/plugins/${pluginId}`;
50
+ const { timezoneList, systemTimezone = { value: "UTC+00:00-Africa/Abidjan " } } = getTimezones(
51
+ initialValues.scheduledAt ? new Date(initialValues.scheduledAt) : /* @__PURE__ */ new Date()
52
+ );
53
+ const getScheduledTimestamp = (values) => {
54
+ const { date, time, timezone } = values;
55
+ if (!date || !time || !timezone)
56
+ return null;
57
+ const timezoneWithoutOffset = timezone.split("&")[1];
58
+ return zonedTimeToUtc(`${date} ${time}`, timezoneWithoutOffset);
59
+ };
60
+ const getTimezoneWithOffset = () => {
61
+ const currentTimezone = timezoneList.find(
62
+ (timezone) => timezone.value.split("&")[1] === initialValues.timezone
63
+ );
64
+ return currentTimezone?.value || systemTimezone.value;
65
+ };
32
66
  return /* @__PURE__ */ jsxs(ModalLayout, { onClose: handleClose, labelledBy: "title", children: [
33
67
  /* @__PURE__ */ jsx(ModalHeader, { children: /* @__PURE__ */ jsx(Typography, { id: "title", fontWeight: "bold", textColor: "neutral800", children: formatMessage(
34
68
  {
@@ -40,45 +74,130 @@ const ReleaseModal = ({
40
74
  /* @__PURE__ */ jsx(
41
75
  Formik,
42
76
  {
43
- validateOnChange: false,
44
- onSubmit: handleSubmit,
45
- initialValues,
77
+ onSubmit: (values) => {
78
+ handleSubmit({
79
+ ...values,
80
+ timezone: values.timezone ? values.timezone.split("&")[1] : null,
81
+ scheduledAt: values.isScheduled ? getScheduledTimestamp(values) : null
82
+ });
83
+ },
84
+ initialValues: {
85
+ ...initialValues,
86
+ timezone: initialValues.timezone ? getTimezoneWithOffset() : systemTimezone.value
87
+ },
46
88
  validationSchema: RELEASE_SCHEMA,
47
- children: ({ values, errors, handleChange }) => /* @__PURE__ */ jsxs(Form, { children: [
48
- /* @__PURE__ */ jsx(ModalBody, { children: /* @__PURE__ */ jsx(
49
- TextInput,
50
- {
51
- label: formatMessage({
52
- id: "content-releases.modal.form.input.label.release-name",
53
- defaultMessage: "Name"
54
- }),
55
- name: "name",
56
- value: values.name,
57
- error: errors.name,
58
- onChange: handleChange,
59
- required: true
60
- }
61
- ) }),
89
+ validateOnChange: false,
90
+ children: ({ values, errors, handleChange, setFieldValue }) => /* @__PURE__ */ jsxs(Form, { children: [
91
+ /* @__PURE__ */ jsx(ModalBody, { children: /* @__PURE__ */ jsxs(Flex, { direction: "column", alignItems: "stretch", gap: 6, children: [
92
+ /* @__PURE__ */ jsx(
93
+ TextInput,
94
+ {
95
+ label: formatMessage({
96
+ id: "content-releases.modal.form.input.label.release-name",
97
+ defaultMessage: "Name"
98
+ }),
99
+ name: "name",
100
+ value: values.name,
101
+ error: errors.name,
102
+ onChange: handleChange,
103
+ required: true
104
+ }
105
+ ),
106
+ /* @__PURE__ */ jsx(Box, { width: "max-content", children: /* @__PURE__ */ jsx(
107
+ Checkbox,
108
+ {
109
+ name: "isScheduled",
110
+ value: values.isScheduled,
111
+ onChange: (event) => {
112
+ setFieldValue("isScheduled", event.target.checked);
113
+ if (!event.target.checked) {
114
+ setFieldValue("date", null);
115
+ setFieldValue("time", "");
116
+ setFieldValue("timezone", null);
117
+ } else {
118
+ setFieldValue("date", initialValues.date);
119
+ setFieldValue("time", initialValues.time);
120
+ setFieldValue("timezone", initialValues.timezone ?? systemTimezone?.value);
121
+ }
122
+ },
123
+ children: /* @__PURE__ */ jsx(
124
+ Typography,
125
+ {
126
+ textColor: values.isScheduled ? "primary600" : "neutral800",
127
+ fontWeight: values.isScheduled ? "semiBold" : "regular",
128
+ children: formatMessage({
129
+ id: "modal.form.input.label.schedule-release",
130
+ defaultMessage: "Schedule release"
131
+ })
132
+ }
133
+ )
134
+ }
135
+ ) }),
136
+ values.isScheduled && /* @__PURE__ */ jsxs(Fragment, { children: [
137
+ /* @__PURE__ */ jsxs(Flex, { gap: 4, alignItems: "start", children: [
138
+ /* @__PURE__ */ jsx(Box, { width: "100%", children: /* @__PURE__ */ jsx(
139
+ DatePicker,
140
+ {
141
+ label: formatMessage({
142
+ id: "content-releases.modal.form.input.label.date",
143
+ defaultMessage: "Date"
144
+ }),
145
+ name: "date",
146
+ error: errors.date,
147
+ onChange: (date) => {
148
+ const isoFormatDate = date ? formatISO(date, { representation: "date" }) : null;
149
+ setFieldValue("date", isoFormatDate);
150
+ },
151
+ clearLabel: formatMessage({
152
+ id: "content-releases.modal.form.input.clearLabel",
153
+ defaultMessage: "Clear"
154
+ }),
155
+ onClear: () => {
156
+ setFieldValue("date", null);
157
+ },
158
+ selectedDate: values.date || void 0,
159
+ required: true,
160
+ minDate: utcToZonedTime(/* @__PURE__ */ new Date(), values.timezone.split("&")[1])
161
+ }
162
+ ) }),
163
+ /* @__PURE__ */ jsx(Box, { width: "100%", children: /* @__PURE__ */ jsx(
164
+ TimePicker,
165
+ {
166
+ label: formatMessage({
167
+ id: "content-releases.modal.form.input.label.time",
168
+ defaultMessage: "Time"
169
+ }),
170
+ name: "time",
171
+ error: errors.time,
172
+ onChange: (time) => {
173
+ setFieldValue("time", time);
174
+ },
175
+ clearLabel: formatMessage({
176
+ id: "content-releases.modal.form.input.clearLabel",
177
+ defaultMessage: "Clear"
178
+ }),
179
+ onClear: () => {
180
+ setFieldValue("time", "");
181
+ },
182
+ value: values.time || void 0,
183
+ required: true
184
+ }
185
+ ) })
186
+ ] }),
187
+ /* @__PURE__ */ jsx(TimezoneComponent, { timezoneOptions: timezoneList })
188
+ ] })
189
+ ] }) }),
62
190
  /* @__PURE__ */ jsx(
63
191
  ModalFooter,
64
192
  {
65
193
  startActions: /* @__PURE__ */ jsx(Button, { onClick: handleClose, variant: "tertiary", name: "cancel", children: formatMessage({ id: "cancel", defaultMessage: "Cancel" }) }),
66
- endActions: /* @__PURE__ */ jsx(
67
- Button,
194
+ endActions: /* @__PURE__ */ jsx(Button, { name: "submit", loading: isLoading, type: "submit", children: formatMessage(
68
195
  {
69
- name: "submit",
70
- loading: isLoading,
71
- disabled: !values.name || values.name === initialValues.name,
72
- type: "submit",
73
- children: formatMessage(
74
- {
75
- id: "content-releases.modal.form.button.submit",
76
- defaultMessage: "{isCreatingRelease, select, true {Continue} other {Save}}"
77
- },
78
- { isCreatingRelease }
79
- )
80
- }
81
- )
196
+ id: "content-releases.modal.form.button.submit",
197
+ defaultMessage: "{isCreatingRelease, select, true {Continue} other {Save}}"
198
+ },
199
+ { isCreatingRelease }
200
+ ) })
82
201
  }
83
202
  )
84
203
  ] })
@@ -86,6 +205,368 @@ const ReleaseModal = ({
86
205
  )
87
206
  ] });
88
207
  };
208
+ const getTimezones = (selectedDate) => {
209
+ const timezoneList = Intl.supportedValuesOf("timeZone").map((timezone) => {
210
+ const utcOffset = getTimezoneOffset(timezone, selectedDate);
211
+ return { offset: utcOffset, value: `${utcOffset}&${timezone}` };
212
+ });
213
+ const systemTimezone = timezoneList.find(
214
+ (timezone) => timezone.value.split("&")[1] === Intl.DateTimeFormat().resolvedOptions().timeZone
215
+ );
216
+ return { timezoneList, systemTimezone };
217
+ };
218
+ const TimezoneComponent = ({ timezoneOptions }) => {
219
+ const { values, errors, setFieldValue } = useFormikContext();
220
+ const { formatMessage } = useIntl();
221
+ const [timezoneList, setTimezoneList] = React.useState(timezoneOptions);
222
+ React.useEffect(() => {
223
+ if (values.date) {
224
+ const { timezoneList: timezoneList2 } = getTimezones(new Date(values.date));
225
+ setTimezoneList(timezoneList2);
226
+ const updatedTimezone = values.timezone && timezoneList2.find((tz) => tz.value.split("&")[1] === values.timezone.split("&")[1]);
227
+ if (updatedTimezone) {
228
+ setFieldValue("timezone", updatedTimezone.value);
229
+ }
230
+ }
231
+ }, [setFieldValue, values.date, values.timezone]);
232
+ return /* @__PURE__ */ jsx(
233
+ Combobox,
234
+ {
235
+ label: formatMessage({
236
+ id: "content-releases.modal.form.input.label.timezone",
237
+ defaultMessage: "Timezone"
238
+ }),
239
+ autocomplete: { type: "list", filter: "contains" },
240
+ name: "timezone",
241
+ value: values.timezone || void 0,
242
+ textValue: values.timezone ? values.timezone.replace(/&/, " ") : void 0,
243
+ onChange: (timezone) => {
244
+ setFieldValue("timezone", timezone);
245
+ },
246
+ onTextValueChange: (timezone) => {
247
+ setFieldValue("timezone", timezone);
248
+ },
249
+ onClear: () => {
250
+ setFieldValue("timezone", "");
251
+ },
252
+ error: errors.timezone,
253
+ required: true,
254
+ children: timezoneList.map((timezone) => /* @__PURE__ */ jsx(ComboboxOption, { value: timezone.value, children: timezone.value.replace(/&/, " ") }, timezone.value))
255
+ }
256
+ );
257
+ };
258
+ const LinkCard = styled(Link)`
259
+ display: block;
260
+ `;
261
+ const CapitalizeRelativeTime = styled(RelativeTime)`
262
+ text-transform: capitalize;
263
+ `;
264
+ const getBadgeProps = (status) => {
265
+ let color;
266
+ switch (status) {
267
+ case "ready":
268
+ color = "success";
269
+ break;
270
+ case "blocked":
271
+ color = "warning";
272
+ break;
273
+ case "failed":
274
+ color = "danger";
275
+ break;
276
+ case "done":
277
+ color = "primary";
278
+ break;
279
+ case "empty":
280
+ default:
281
+ color = "neutral";
282
+ }
283
+ return {
284
+ textColor: `${color}600`,
285
+ backgroundColor: `${color}100`,
286
+ borderColor: `${color}200`
287
+ };
288
+ };
289
+ const ReleasesGrid = ({ sectionTitle, releases = [], isError = false }) => {
290
+ const { formatMessage } = useIntl();
291
+ if (isError) {
292
+ return /* @__PURE__ */ jsx(AnErrorOccurred, {});
293
+ }
294
+ if (releases?.length === 0) {
295
+ return /* @__PURE__ */ jsx(
296
+ EmptyStateLayout,
297
+ {
298
+ content: formatMessage(
299
+ {
300
+ id: "content-releases.page.Releases.tab.emptyEntries",
301
+ defaultMessage: "No releases"
302
+ },
303
+ {
304
+ target: sectionTitle
305
+ }
306
+ ),
307
+ icon: /* @__PURE__ */ jsx(EmptyDocuments, { width: "10rem" })
308
+ }
309
+ );
310
+ }
311
+ return /* @__PURE__ */ jsx(Grid, { gap: 4, children: releases.map(({ id, name, scheduledAt, status }) => /* @__PURE__ */ jsx(GridItem, { col: 3, s: 6, xs: 12, children: /* @__PURE__ */ jsx(LinkCard, { href: `content-releases/${id}`, isExternal: false, children: /* @__PURE__ */ jsxs(
312
+ Flex,
313
+ {
314
+ direction: "column",
315
+ justifyContent: "space-between",
316
+ padding: 4,
317
+ hasRadius: true,
318
+ background: "neutral0",
319
+ shadow: "tableShadow",
320
+ height: "100%",
321
+ width: "100%",
322
+ alignItems: "start",
323
+ gap: 4,
324
+ children: [
325
+ /* @__PURE__ */ jsxs(Flex, { direction: "column", alignItems: "start", gap: 1, children: [
326
+ /* @__PURE__ */ jsx(Typography, { as: "h3", variant: "delta", fontWeight: "bold", children: name }),
327
+ /* @__PURE__ */ jsx(Typography, { variant: "pi", textColor: "neutral600", children: scheduledAt ? /* @__PURE__ */ jsx(CapitalizeRelativeTime, { timestamp: new Date(scheduledAt) }) : formatMessage({
328
+ id: "content-releases.pages.Releases.not-scheduled",
329
+ defaultMessage: "Not scheduled"
330
+ }) })
331
+ ] }),
332
+ /* @__PURE__ */ jsx(Badge, { ...getBadgeProps(status), children: status })
333
+ ]
334
+ }
335
+ ) }) }, id)) });
336
+ };
337
+ const StyledAlert = styled(Alert)`
338
+ button {
339
+ display: none;
340
+ }
341
+ p + div {
342
+ margin-left: auto;
343
+ }
344
+ `;
345
+ const INITIAL_FORM_VALUES = {
346
+ name: "",
347
+ date: null,
348
+ time: "",
349
+ isScheduled: true,
350
+ scheduledAt: null,
351
+ timezone: null
352
+ };
353
+ const ReleasesPage = () => {
354
+ const tabRef = React.useRef(null);
355
+ const location = useLocation();
356
+ const [releaseModalShown, setReleaseModalShown] = React.useState(false);
357
+ const toggleNotification = useNotification();
358
+ const { formatMessage } = useIntl();
359
+ const { push, replace } = useHistory();
360
+ const { formatAPIError } = useAPIErrorHandler();
361
+ const [{ query }, setQuery] = useQueryParams();
362
+ const response = useGetReleasesQuery(query);
363
+ const [createRelease, { isLoading: isSubmittingForm }] = useCreateReleaseMutation();
364
+ const { getFeature } = useLicenseLimits();
365
+ const { maximumReleases = 3 } = getFeature("cms-content-releases");
366
+ const { trackUsage } = useTracking();
367
+ const { isLoading, isSuccess, isError } = response;
368
+ const activeTab = response?.currentData?.meta?.activeTab || "pending";
369
+ const activeTabIndex = ["pending", "done"].indexOf(activeTab);
370
+ React.useEffect(() => {
371
+ if (location?.state?.errors) {
372
+ toggleNotification({
373
+ type: "warning",
374
+ title: formatMessage({
375
+ id: "content-releases.pages.Releases.notification.error.title",
376
+ defaultMessage: "Your request could not be processed."
377
+ }),
378
+ message: formatMessage({
379
+ id: "content-releases.pages.Releases.notification.error.message",
380
+ defaultMessage: "Please try again or open another release."
381
+ })
382
+ });
383
+ replace({ state: null });
384
+ }
385
+ }, [formatMessage, location?.state?.errors, replace, toggleNotification]);
386
+ React.useEffect(() => {
387
+ if (tabRef.current) {
388
+ tabRef.current._handlers.setSelectedTabIndex(activeTabIndex);
389
+ }
390
+ }, [activeTabIndex]);
391
+ const toggleAddReleaseModal = () => {
392
+ setReleaseModalShown((prev) => !prev);
393
+ };
394
+ if (isLoading) {
395
+ return /* @__PURE__ */ jsx(Main, { "aria-busy": isLoading, children: /* @__PURE__ */ jsx(LoadingIndicatorPage, {}) });
396
+ }
397
+ const totalPendingReleases = isSuccess && response.currentData?.meta?.pendingReleasesCount || 0;
398
+ const hasReachedMaximumPendingReleases = totalPendingReleases >= maximumReleases;
399
+ const handleTabChange = (index) => {
400
+ setQuery({
401
+ ...query,
402
+ page: 1,
403
+ pageSize: response?.currentData?.meta?.pagination?.pageSize || 16,
404
+ filters: {
405
+ releasedAt: {
406
+ $notNull: index === 0 ? false : true
407
+ }
408
+ }
409
+ });
410
+ };
411
+ const handleAddRelease = async ({ name, scheduledAt, timezone }) => {
412
+ const response2 = await createRelease({
413
+ name,
414
+ scheduledAt,
415
+ timezone
416
+ });
417
+ if ("data" in response2) {
418
+ toggleNotification({
419
+ type: "success",
420
+ message: formatMessage({
421
+ id: "content-releases.modal.release-created-notification-success",
422
+ defaultMessage: "Release created."
423
+ })
424
+ });
425
+ trackUsage("didCreateRelease");
426
+ push(`/plugins/content-releases/${response2.data.data.id}`);
427
+ } else if (isAxiosError(response2.error)) {
428
+ toggleNotification({
429
+ type: "warning",
430
+ message: formatAPIError(response2.error)
431
+ });
432
+ } else {
433
+ toggleNotification({
434
+ type: "warning",
435
+ message: formatMessage({ id: "notification.error", defaultMessage: "An error occurred" })
436
+ });
437
+ }
438
+ };
439
+ return /* @__PURE__ */ jsxs(Main, { "aria-busy": isLoading, children: [
440
+ /* @__PURE__ */ jsx(
441
+ HeaderLayout,
442
+ {
443
+ title: formatMessage({
444
+ id: "content-releases.pages.Releases.title",
445
+ defaultMessage: "Releases"
446
+ }),
447
+ subtitle: formatMessage({
448
+ id: "content-releases.pages.Releases.header-subtitle",
449
+ defaultMessage: "Create and manage content updates"
450
+ }),
451
+ primaryAction: /* @__PURE__ */ jsx(CheckPermissions, { permissions: PERMISSIONS.create, children: /* @__PURE__ */ jsx(
452
+ Button,
453
+ {
454
+ startIcon: /* @__PURE__ */ jsx(Plus, {}),
455
+ onClick: toggleAddReleaseModal,
456
+ disabled: hasReachedMaximumPendingReleases,
457
+ children: formatMessage({
458
+ id: "content-releases.header.actions.add-release",
459
+ defaultMessage: "New release"
460
+ })
461
+ }
462
+ ) })
463
+ }
464
+ ),
465
+ /* @__PURE__ */ jsx(ContentLayout, { children: /* @__PURE__ */ jsxs(Fragment, { children: [
466
+ hasReachedMaximumPendingReleases && /* @__PURE__ */ jsx(
467
+ StyledAlert,
468
+ {
469
+ marginBottom: 6,
470
+ action: /* @__PURE__ */ jsx(Link, { href: "https://strapi.io/pricing-cloud", isExternal: true, children: formatMessage({
471
+ id: "content-releases.pages.Releases.max-limit-reached.action",
472
+ defaultMessage: "Explore plans"
473
+ }) }),
474
+ title: formatMessage(
475
+ {
476
+ id: "content-releases.pages.Releases.max-limit-reached.title",
477
+ defaultMessage: "You have reached the {number} pending {number, plural, one {release} other {releases}} limit."
478
+ },
479
+ { number: maximumReleases }
480
+ ),
481
+ onClose: () => {
482
+ },
483
+ closeLabel: "",
484
+ children: formatMessage({
485
+ id: "content-releases.pages.Releases.max-limit-reached.message",
486
+ defaultMessage: "Upgrade to manage an unlimited number of releases."
487
+ })
488
+ }
489
+ ),
490
+ /* @__PURE__ */ jsxs(
491
+ TabGroup,
492
+ {
493
+ label: formatMessage({
494
+ id: "content-releases.pages.Releases.tab-group.label",
495
+ defaultMessage: "Releases list"
496
+ }),
497
+ variant: "simple",
498
+ initialSelectedTabIndex: activeTabIndex,
499
+ onTabChange: handleTabChange,
500
+ ref: tabRef,
501
+ children: [
502
+ /* @__PURE__ */ jsxs(Box, { paddingBottom: 8, children: [
503
+ /* @__PURE__ */ jsxs(Tabs, { children: [
504
+ /* @__PURE__ */ jsx(Tab, { children: formatMessage(
505
+ {
506
+ id: "content-releases.pages.Releases.tab.pending",
507
+ defaultMessage: "Pending ({count})"
508
+ },
509
+ {
510
+ count: totalPendingReleases
511
+ }
512
+ ) }),
513
+ /* @__PURE__ */ jsx(Tab, { children: formatMessage({
514
+ id: "content-releases.pages.Releases.tab.done",
515
+ defaultMessage: "Done"
516
+ }) })
517
+ ] }),
518
+ /* @__PURE__ */ jsx(Divider, {})
519
+ ] }),
520
+ /* @__PURE__ */ jsxs(TabPanels, { children: [
521
+ /* @__PURE__ */ jsx(TabPanel, { children: /* @__PURE__ */ jsx(
522
+ ReleasesGrid,
523
+ {
524
+ sectionTitle: "pending",
525
+ releases: response?.currentData?.data,
526
+ isError
527
+ }
528
+ ) }),
529
+ /* @__PURE__ */ jsx(TabPanel, { children: /* @__PURE__ */ jsx(
530
+ ReleasesGrid,
531
+ {
532
+ sectionTitle: "done",
533
+ releases: response?.currentData?.data,
534
+ isError
535
+ }
536
+ ) })
537
+ ] })
538
+ ]
539
+ }
540
+ ),
541
+ response.currentData?.meta?.pagination?.total ? /* @__PURE__ */ jsxs(Flex, { paddingTop: 4, alignItems: "flex-end", justifyContent: "space-between", children: [
542
+ /* @__PURE__ */ jsx(
543
+ PageSizeURLQuery,
544
+ {
545
+ options: ["8", "16", "32", "64"],
546
+ defaultValue: response?.currentData?.meta?.pagination?.pageSize.toString()
547
+ }
548
+ ),
549
+ /* @__PURE__ */ jsx(
550
+ PaginationURLQuery,
551
+ {
552
+ pagination: {
553
+ pageCount: response?.currentData?.meta?.pagination?.pageCount || 0
554
+ }
555
+ }
556
+ )
557
+ ] }) : null
558
+ ] }) }),
559
+ releaseModalShown && /* @__PURE__ */ jsx(
560
+ ReleaseModal,
561
+ {
562
+ handleClose: toggleAddReleaseModal,
563
+ handleSubmit: handleAddRelease,
564
+ isLoading: isSubmittingForm,
565
+ initialValues: INITIAL_FORM_VALUES
566
+ }
567
+ )
568
+ ] });
569
+ };
89
570
  const ReleaseInfoWrapper = styled(Flex)`
90
571
  align-self: stretch;
91
572
  border-bottom-right-radius: ${({ theme }) => theme.borderRadius};
@@ -99,6 +580,10 @@ const StyledMenuItem = styled(Menu.Item)`
99
580
  span {
100
581
  color: ${({ theme, disabled }) => disabled && theme.colors.neutral500};
101
582
  }
583
+
584
+ &:hover {
585
+ background: ${({ theme, variant = "neutral" }) => theme.colors[`${variant}100`]};
586
+ }
102
587
  `;
103
588
  const PencilIcon = styled(Pencil)`
104
589
  width: ${({ theme }) => theme.spaces[3]};
@@ -165,7 +650,7 @@ const ReleaseDetailsLayout = ({
165
650
  toggleWarningSubmit,
166
651
  children
167
652
  }) => {
168
- const { formatMessage } = useIntl();
653
+ const { formatMessage, formatDate, formatTime } = useIntl();
169
654
  const { releaseId } = useParams();
170
655
  const {
171
656
  data,
@@ -211,7 +696,12 @@ const ReleaseDetailsLayout = ({
211
696
  }
212
697
  };
213
698
  const handleRefresh = () => {
214
- dispatch(releaseApi.util.invalidateTags([{ type: "ReleaseAction", id: "LIST" }]));
699
+ dispatch(
700
+ releaseApi.util.invalidateTags([
701
+ { type: "ReleaseAction", id: "LIST" },
702
+ { type: "Release", id: releaseId }
703
+ ])
704
+ );
215
705
  };
216
706
  const getCreatedByUser = () => {
217
707
  if (!release?.createdBy) {
@@ -247,19 +737,44 @@ const ReleaseDetailsLayout = ({
247
737
  }
248
738
  const totalEntries = release.actions.meta.count || 0;
249
739
  const hasCreatedByUser = Boolean(getCreatedByUser());
740
+ const isScheduled = release.scheduledAt && release.timezone;
741
+ const numberOfEntriesText = formatMessage(
742
+ {
743
+ id: "content-releases.pages.Details.header-subtitle",
744
+ defaultMessage: "{number, plural, =0 {No entries} one {# entry} other {# entries}}"
745
+ },
746
+ { number: totalEntries }
747
+ );
748
+ const scheduledText = isScheduled ? formatMessage(
749
+ {
750
+ id: "content-releases.pages.ReleaseDetails.header-subtitle.scheduled",
751
+ defaultMessage: "Scheduled for {date} at {time} ({offset})"
752
+ },
753
+ {
754
+ date: formatDate(new Date(release.scheduledAt), {
755
+ weekday: "long",
756
+ day: "numeric",
757
+ month: "long",
758
+ year: "numeric",
759
+ timeZone: release.timezone
760
+ }),
761
+ time: formatTime(new Date(release.scheduledAt), {
762
+ timeZone: release.timezone,
763
+ hourCycle: "h23"
764
+ }),
765
+ offset: getTimezoneOffset(release.timezone, new Date(release.scheduledAt))
766
+ }
767
+ ) : "";
250
768
  return /* @__PURE__ */ jsxs(Main, { "aria-busy": isLoadingDetails, children: [
251
769
  /* @__PURE__ */ jsx(
252
770
  HeaderLayout,
253
771
  {
254
772
  title: release.name,
255
- subtitle: formatMessage(
256
- {
257
- id: "content-releases.pages.Details.header-subtitle",
258
- defaultMessage: "{number, plural, =0 {No entries} one {# entry} other {# entries}}"
259
- },
260
- { number: totalEntries }
261
- ),
262
- navigationAction: /* @__PURE__ */ jsx(Link, { startIcon: /* @__PURE__ */ jsx(ArrowLeft, {}), to: "/plugins/content-releases", children: formatMessage({
773
+ subtitle: /* @__PURE__ */ jsxs(Flex, { gap: 2, lineHeight: 6, children: [
774
+ /* @__PURE__ */ jsx(Typography, { textColor: "neutral600", variant: "epsilon", children: numberOfEntriesText + (isScheduled ? ` - ${scheduledText}` : "") }),
775
+ /* @__PURE__ */ jsx(Badge, { ...getBadgeProps(release.status), children: release.status })
776
+ ] }),
777
+ navigationAction: /* @__PURE__ */ jsx(Link$1, { startIcon: /* @__PURE__ */ jsx(ArrowLeft, {}), to: "/plugins/content-releases", children: formatMessage({
263
778
  id: "global.back",
264
779
  defaultMessage: "Back"
265
780
  }) }),
@@ -287,44 +802,30 @@ const ReleaseDetailsLayout = ({
287
802
  justifyContent: "center",
288
803
  direction: "column",
289
804
  padding: 1,
290
- width: "100%",
291
- children: [
292
- /* @__PURE__ */ jsx(StyledMenuItem, { disabled: !canUpdate, onSelect: toggleEditReleaseModal, children: /* @__PURE__ */ jsxs(
293
- Flex,
294
- {
295
- paddingTop: 2,
296
- paddingBottom: 2,
297
- alignItems: "center",
298
- gap: 2,
299
- hasRadius: true,
300
- width: "100%",
301
- children: [
302
- /* @__PURE__ */ jsx(PencilIcon, {}),
303
- /* @__PURE__ */ jsx(Typography, { ellipsis: true, children: formatMessage({
304
- id: "content-releases.header.actions.edit",
305
- defaultMessage: "Edit"
306
- }) })
307
- ]
308
- }
309
- ) }),
310
- /* @__PURE__ */ jsx(StyledMenuItem, { disabled: !canDelete, onSelect: toggleWarningSubmit, children: /* @__PURE__ */ jsxs(
311
- Flex,
805
+ width: "100%",
806
+ children: [
807
+ /* @__PURE__ */ jsx(StyledMenuItem, { disabled: !canUpdate, onSelect: toggleEditReleaseModal, children: /* @__PURE__ */ jsxs(Flex, { alignItems: "center", gap: 2, hasRadius: true, width: "100%", children: [
808
+ /* @__PURE__ */ jsx(PencilIcon, {}),
809
+ /* @__PURE__ */ jsx(Typography, { ellipsis: true, children: formatMessage({
810
+ id: "content-releases.header.actions.edit",
811
+ defaultMessage: "Edit"
812
+ }) })
813
+ ] }) }),
814
+ /* @__PURE__ */ jsx(
815
+ StyledMenuItem,
312
816
  {
313
- paddingTop: 2,
314
- paddingBottom: 2,
315
- alignItems: "center",
316
- gap: 2,
317
- hasRadius: true,
318
- width: "100%",
319
- children: [
817
+ disabled: !canDelete,
818
+ onSelect: toggleWarningSubmit,
819
+ variant: "danger",
820
+ children: /* @__PURE__ */ jsxs(Flex, { alignItems: "center", gap: 2, hasRadius: true, width: "100%", children: [
320
821
  /* @__PURE__ */ jsx(TrashIcon, {}),
321
822
  /* @__PURE__ */ jsx(Typography, { ellipsis: true, textColor: "danger600", children: formatMessage({
322
823
  id: "content-releases.header.actions.delete",
323
824
  defaultMessage: "Delete"
324
825
  }) })
325
- ]
826
+ ] })
326
827
  }
327
- ) })
828
+ )
328
829
  ]
329
830
  }
330
831
  ),
@@ -500,7 +1001,7 @@ const ReleaseDetailsBody = () => {
500
1001
  action: /* @__PURE__ */ jsx(
501
1002
  LinkButton,
502
1003
  {
503
- as: Link$1,
1004
+ as: Link$2,
504
1005
  to: {
505
1006
  pathname: "/content-manager"
506
1007
  },
@@ -683,7 +1184,7 @@ const ReleaseDetailsPage = () => {
683
1184
  const { releaseId } = useParams();
684
1185
  const toggleNotification = useNotification();
685
1186
  const { formatAPIError } = useAPIErrorHandler();
686
- const { push } = useHistory();
1187
+ const { replace } = useHistory();
687
1188
  const [releaseModalShown, setReleaseModalShown] = React.useState(false);
688
1189
  const [showWarningSubmit, setWarningSubmit] = React.useState(false);
689
1190
  const {
@@ -707,11 +1208,18 @@ const ReleaseDetailsPage = () => {
707
1208
  }
708
1209
  );
709
1210
  }
710
- const title = isSuccessDetails && data?.data?.name || "";
1211
+ const releaseData = isSuccessDetails && data?.data || null;
1212
+ const title = releaseData?.name || "";
1213
+ const timezone = releaseData?.timezone ?? null;
1214
+ const scheduledAt = releaseData?.scheduledAt && timezone ? utcToZonedTime(releaseData.scheduledAt, timezone) : null;
1215
+ const date = scheduledAt ? format(scheduledAt, "yyyy-MM-dd") : null;
1216
+ const time = scheduledAt ? format(scheduledAt, "HH:mm") : "";
711
1217
  const handleEditRelease = async (values) => {
712
1218
  const response = await updateRelease({
713
1219
  id: releaseId,
714
- name: values.name
1220
+ name: values.name,
1221
+ scheduledAt: values.scheduledAt,
1222
+ timezone: values.timezone
715
1223
  });
716
1224
  if ("data" in response) {
717
1225
  toggleNotification({
@@ -739,7 +1247,7 @@ const ReleaseDetailsPage = () => {
739
1247
  id: releaseId
740
1248
  });
741
1249
  if ("data" in response) {
742
- push("/plugins/content-releases");
1250
+ replace("/plugins/content-releases");
743
1251
  } else if (isAxiosError(response.error)) {
744
1252
  toggleNotification({
745
1253
  type: "warning",
@@ -765,7 +1273,14 @@ const ReleaseDetailsPage = () => {
765
1273
  handleClose: toggleEditReleaseModal,
766
1274
  handleSubmit: handleEditRelease,
767
1275
  isLoading: isLoadingDetails || isSubmittingForm,
768
- initialValues: { name: title || "" }
1276
+ initialValues: {
1277
+ name: title || "",
1278
+ scheduledAt,
1279
+ date,
1280
+ time,
1281
+ isScheduled: Boolean(scheduledAt),
1282
+ timezone
1283
+ }
769
1284
  }
770
1285
  ),
771
1286
  /* @__PURE__ */ jsx(
@@ -785,281 +1300,6 @@ const ReleaseDetailsPage = () => {
785
1300
  }
786
1301
  );
787
1302
  };
788
- const LinkCard = styled(Link$2)`
789
- display: block;
790
- `;
791
- const ReleasesGrid = ({ sectionTitle, releases = [], isError = false }) => {
792
- const { formatMessage } = useIntl();
793
- if (isError) {
794
- return /* @__PURE__ */ jsx(AnErrorOccurred, {});
795
- }
796
- if (releases?.length === 0) {
797
- return /* @__PURE__ */ jsx(
798
- EmptyStateLayout,
799
- {
800
- content: formatMessage(
801
- {
802
- id: "content-releases.page.Releases.tab.emptyEntries",
803
- defaultMessage: "No releases"
804
- },
805
- {
806
- target: sectionTitle
807
- }
808
- ),
809
- icon: /* @__PURE__ */ jsx(EmptyDocuments, { width: "10rem" })
810
- }
811
- );
812
- }
813
- return /* @__PURE__ */ jsx(Grid, { gap: 4, children: releases.map(({ id, name, actions }) => /* @__PURE__ */ jsx(GridItem, { col: 3, s: 6, xs: 12, children: /* @__PURE__ */ jsx(LinkCard, { href: `content-releases/${id}`, isExternal: false, children: /* @__PURE__ */ jsxs(
814
- Flex,
815
- {
816
- direction: "column",
817
- justifyContent: "space-between",
818
- padding: 4,
819
- hasRadius: true,
820
- background: "neutral0",
821
- shadow: "tableShadow",
822
- height: "100%",
823
- width: "100%",
824
- alignItems: "start",
825
- gap: 2,
826
- children: [
827
- /* @__PURE__ */ jsx(Typography, { as: "h3", variant: "delta", fontWeight: "bold", children: name }),
828
- /* @__PURE__ */ jsx(Typography, { variant: "pi", children: formatMessage(
829
- {
830
- id: "content-releases.page.Releases.release-item.entries",
831
- defaultMessage: "{number, plural, =0 {No entries} one {# entry} other {# entries}}"
832
- },
833
- { number: actions.meta.count }
834
- ) })
835
- ]
836
- }
837
- ) }) }, id)) });
838
- };
839
- const StyledAlert = styled(Alert)`
840
- button {
841
- display: none;
842
- }
843
- p + div {
844
- margin-left: auto;
845
- }
846
- `;
847
- const INITIAL_FORM_VALUES = {
848
- name: ""
849
- };
850
- const ReleasesPage = () => {
851
- const tabRef = React.useRef(null);
852
- const location = useLocation();
853
- const [releaseModalShown, setReleaseModalShown] = React.useState(false);
854
- const toggleNotification = useNotification();
855
- const { formatMessage } = useIntl();
856
- const { push, replace } = useHistory();
857
- const { formatAPIError } = useAPIErrorHandler();
858
- const [{ query }, setQuery] = useQueryParams();
859
- const response = useGetReleasesQuery(query);
860
- const [createRelease, { isLoading: isSubmittingForm }] = useCreateReleaseMutation();
861
- const { getFeature } = useLicenseLimits();
862
- const { maximumReleases = 3 } = getFeature("cms-content-releases");
863
- const { trackUsage } = useTracking();
864
- const { isLoading, isSuccess, isError } = response;
865
- const activeTab = response?.currentData?.meta?.activeTab || "pending";
866
- const activeTabIndex = ["pending", "done"].indexOf(activeTab);
867
- React.useEffect(() => {
868
- if (location?.state?.errors) {
869
- toggleNotification({
870
- type: "warning",
871
- title: formatMessage({
872
- id: "content-releases.pages.Releases.notification.error.title",
873
- defaultMessage: "Your request could not be processed."
874
- }),
875
- message: formatMessage({
876
- id: "content-releases.pages.Releases.notification.error.message",
877
- defaultMessage: "Please try again or open another release."
878
- })
879
- });
880
- replace({ state: null });
881
- }
882
- }, [formatMessage, location?.state?.errors, replace, toggleNotification]);
883
- React.useEffect(() => {
884
- if (tabRef.current) {
885
- tabRef.current._handlers.setSelectedTabIndex(activeTabIndex);
886
- }
887
- }, [activeTabIndex]);
888
- const toggleAddReleaseModal = () => {
889
- setReleaseModalShown((prev) => !prev);
890
- };
891
- if (isLoading) {
892
- return /* @__PURE__ */ jsx(Main, { "aria-busy": isLoading, children: /* @__PURE__ */ jsx(LoadingIndicatorPage, {}) });
893
- }
894
- const totalReleases = isSuccess && response.currentData?.meta?.pagination?.total || 0;
895
- const hasReachedMaximumPendingReleases = totalReleases >= maximumReleases;
896
- const handleTabChange = (index) => {
897
- setQuery({
898
- ...query,
899
- page: 1,
900
- pageSize: response?.currentData?.meta?.pagination?.pageSize || 16,
901
- filters: {
902
- releasedAt: {
903
- $notNull: index === 0 ? false : true
904
- }
905
- }
906
- });
907
- };
908
- const handleAddRelease = async (values) => {
909
- const response2 = await createRelease({
910
- name: values.name
911
- });
912
- if ("data" in response2) {
913
- toggleNotification({
914
- type: "success",
915
- message: formatMessage({
916
- id: "content-releases.modal.release-created-notification-success",
917
- defaultMessage: "Release created."
918
- })
919
- });
920
- trackUsage("didCreateRelease");
921
- push(`/plugins/content-releases/${response2.data.data.id}`);
922
- } else if (isAxiosError(response2.error)) {
923
- toggleNotification({
924
- type: "warning",
925
- message: formatAPIError(response2.error)
926
- });
927
- } else {
928
- toggleNotification({
929
- type: "warning",
930
- message: formatMessage({ id: "notification.error", defaultMessage: "An error occurred" })
931
- });
932
- }
933
- };
934
- return /* @__PURE__ */ jsxs(Main, { "aria-busy": isLoading, children: [
935
- /* @__PURE__ */ jsx(
936
- HeaderLayout,
937
- {
938
- title: formatMessage({
939
- id: "content-releases.pages.Releases.title",
940
- defaultMessage: "Releases"
941
- }),
942
- subtitle: formatMessage(
943
- {
944
- id: "content-releases.pages.Releases.header-subtitle",
945
- defaultMessage: "{number, plural, =0 {No releases} one {# release} other {# releases}}"
946
- },
947
- { number: totalReleases }
948
- ),
949
- primaryAction: /* @__PURE__ */ jsx(CheckPermissions, { permissions: PERMISSIONS.create, children: /* @__PURE__ */ jsx(
950
- Button,
951
- {
952
- startIcon: /* @__PURE__ */ jsx(Plus, {}),
953
- onClick: toggleAddReleaseModal,
954
- disabled: hasReachedMaximumPendingReleases,
955
- children: formatMessage({
956
- id: "content-releases.header.actions.add-release",
957
- defaultMessage: "New release"
958
- })
959
- }
960
- ) })
961
- }
962
- ),
963
- /* @__PURE__ */ jsx(ContentLayout, { children: /* @__PURE__ */ jsxs(Fragment, { children: [
964
- activeTab === "pending" && hasReachedMaximumPendingReleases && /* @__PURE__ */ jsx(
965
- StyledAlert,
966
- {
967
- marginBottom: 6,
968
- action: /* @__PURE__ */ jsx(Link$2, { href: "https://strapi.io/pricing-cloud", isExternal: true, children: formatMessage({
969
- id: "content-releases.pages.Releases.max-limit-reached.action",
970
- defaultMessage: "Explore plans"
971
- }) }),
972
- title: formatMessage(
973
- {
974
- id: "content-releases.pages.Releases.max-limit-reached.title",
975
- defaultMessage: "You have reached the {number} pending {number, plural, one {release} other {releases}} limit."
976
- },
977
- { number: maximumReleases }
978
- ),
979
- onClose: () => {
980
- },
981
- closeLabel: "",
982
- children: formatMessage({
983
- id: "content-releases.pages.Releases.max-limit-reached.message",
984
- defaultMessage: "Upgrade to manage an unlimited number of releases."
985
- })
986
- }
987
- ),
988
- /* @__PURE__ */ jsxs(
989
- TabGroup,
990
- {
991
- label: formatMessage({
992
- id: "content-releases.pages.Releases.tab-group.label",
993
- defaultMessage: "Releases list"
994
- }),
995
- variant: "simple",
996
- initialSelectedTabIndex: activeTabIndex,
997
- onTabChange: handleTabChange,
998
- ref: tabRef,
999
- children: [
1000
- /* @__PURE__ */ jsxs(Box, { paddingBottom: 8, children: [
1001
- /* @__PURE__ */ jsxs(Tabs, { children: [
1002
- /* @__PURE__ */ jsx(Tab, { children: formatMessage({
1003
- id: "content-releases.pages.Releases.tab.pending",
1004
- defaultMessage: "Pending"
1005
- }) }),
1006
- /* @__PURE__ */ jsx(Tab, { children: formatMessage({
1007
- id: "content-releases.pages.Releases.tab.done",
1008
- defaultMessage: "Done"
1009
- }) })
1010
- ] }),
1011
- /* @__PURE__ */ jsx(Divider, {})
1012
- ] }),
1013
- /* @__PURE__ */ jsxs(TabPanels, { children: [
1014
- /* @__PURE__ */ jsx(TabPanel, { children: /* @__PURE__ */ jsx(
1015
- ReleasesGrid,
1016
- {
1017
- sectionTitle: "pending",
1018
- releases: response?.currentData?.data,
1019
- isError
1020
- }
1021
- ) }),
1022
- /* @__PURE__ */ jsx(TabPanel, { children: /* @__PURE__ */ jsx(
1023
- ReleasesGrid,
1024
- {
1025
- sectionTitle: "done",
1026
- releases: response?.currentData?.data,
1027
- isError
1028
- }
1029
- ) })
1030
- ] })
1031
- ]
1032
- }
1033
- ),
1034
- totalReleases > 0 && /* @__PURE__ */ jsxs(Flex, { paddingTop: 4, alignItems: "flex-end", justifyContent: "space-between", children: [
1035
- /* @__PURE__ */ jsx(
1036
- PageSizeURLQuery,
1037
- {
1038
- options: ["8", "16", "32", "64"],
1039
- defaultValue: response?.currentData?.meta?.pagination?.pageSize.toString()
1040
- }
1041
- ),
1042
- /* @__PURE__ */ jsx(
1043
- PaginationURLQuery,
1044
- {
1045
- pagination: {
1046
- pageCount: response?.currentData?.meta?.pagination?.pageCount || 0
1047
- }
1048
- }
1049
- )
1050
- ] })
1051
- ] }) }),
1052
- releaseModalShown && /* @__PURE__ */ jsx(
1053
- ReleaseModal,
1054
- {
1055
- handleClose: toggleAddReleaseModal,
1056
- handleSubmit: handleAddRelease,
1057
- isLoading: isSubmittingForm,
1058
- initialValues: INITIAL_FORM_VALUES
1059
- }
1060
- )
1061
- ] });
1062
- };
1063
1303
  const App = () => {
1064
1304
  return /* @__PURE__ */ jsx(CheckPagePermissions, { permissions: PERMISSIONS.main, children: /* @__PURE__ */ jsxs(Switch, { children: [
1065
1305
  /* @__PURE__ */ jsx(Route, { exact: true, path: `/plugins/${pluginId}`, component: ReleasesPage }),
@@ -1069,4 +1309,4 @@ const App = () => {
1069
1309
  export {
1070
1310
  App
1071
1311
  };
1072
- //# sourceMappingURL=App-8FCxPK8-.mjs.map
1312
+ //# sourceMappingURL=App-xQ5ljY7-.mjs.map