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