@strapi/content-releases 0.0.0-next.d470b4f75cf00f24f440b80300f1c833c322b871 → 0.0.0-next.e09d30edcbd16960a838997778a31d50e9c60bc4

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.
@@ -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-l-FvkQlQ.js");
6
+ const index = require("./index-mrnUzPlo.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,15 +40,26 @@ 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
48
  scheduledAt: yup__namespace.string().nullable(),
46
- timezone: yup__namespace.string().when("scheduledAt", {
47
- is: (scheduledAt) => !!scheduledAt,
48
- then: yup__namespace.string().required(),
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(),
49
63
  otherwise: yup__namespace.string().nullable()
50
64
  })
51
65
  }).required().noUnknown();
@@ -58,6 +72,24 @@ const ReleaseModal = ({
58
72
  const { formatMessage } = reactIntl.useIntl();
59
73
  const { pathname } = reactRouterDom.useLocation();
60
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
+ };
61
93
  return /* @__PURE__ */ jsxRuntime.jsxs(designSystem.ModalLayout, { onClose: handleClose, labelledBy: "title", children: [
62
94
  /* @__PURE__ */ jsxRuntime.jsx(designSystem.ModalHeader, { children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { id: "title", fontWeight: "bold", textColor: "neutral800", children: formatMessage(
63
95
  {
@@ -69,45 +101,134 @@ const ReleaseModal = ({
69
101
  /* @__PURE__ */ jsxRuntime.jsx(
70
102
  formik.Formik,
71
103
  {
72
- validateOnChange: false,
73
- onSubmit: handleSubmit,
74
- 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
+ },
75
115
  validationSchema: RELEASE_SCHEMA,
76
- children: ({ values, errors, handleChange }) => /* @__PURE__ */ jsxRuntime.jsxs(formik.Form, { children: [
77
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.ModalBody, { children: /* @__PURE__ */ jsxRuntime.jsx(
78
- designSystem.TextInput,
79
- {
80
- label: formatMessage({
81
- id: "content-releases.modal.form.input.label.release-name",
82
- defaultMessage: "Name"
83
- }),
84
- name: "name",
85
- value: values.name,
86
- error: errors.name,
87
- onChange: handleChange,
88
- required: true
89
- }
90
- ) }),
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(designSystem.Box, { width: "max-content", children: /* @__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
+ ] }) }),
91
221
  /* @__PURE__ */ jsxRuntime.jsx(
92
222
  designSystem.ModalFooter,
93
223
  {
94
224
  startActions: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Button, { onClick: handleClose, variant: "tertiary", name: "cancel", children: formatMessage({ id: "cancel", defaultMessage: "Cancel" }) }),
95
- endActions: /* @__PURE__ */ jsxRuntime.jsx(
96
- designSystem.Button,
225
+ endActions: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Button, { name: "submit", loading: isLoading, type: "submit", children: formatMessage(
97
226
  {
98
- name: "submit",
99
- loading: isLoading,
100
- disabled: !values.name || values.name === initialValues.name,
101
- type: "submit",
102
- children: formatMessage(
103
- {
104
- id: "content-releases.modal.form.button.submit",
105
- defaultMessage: "{isCreatingRelease, select, true {Continue} other {Save}}"
106
- },
107
- { isCreatingRelease }
108
- )
109
- }
110
- )
227
+ id: "content-releases.modal.form.button.submit",
228
+ defaultMessage: "{isCreatingRelease, select, true {Continue} other {Save}}"
229
+ },
230
+ { isCreatingRelease }
231
+ ) })
111
232
  }
112
233
  )
113
234
  ] })
@@ -115,6 +236,376 @@ const ReleaseModal = ({
115
236
  )
116
237
  ] });
117
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
+ autocomplete: { type: "list", filter: "contains" },
271
+ name: "timezone",
272
+ value: values.timezone || void 0,
273
+ textValue: values.timezone ? values.timezone.replace("_", " ") : void 0,
274
+ onChange: (timezone) => {
275
+ setFieldValue("timezone", timezone);
276
+ },
277
+ onTextValueChange: (timezone) => {
278
+ setFieldValue("timezone", timezone);
279
+ },
280
+ onClear: () => {
281
+ setFieldValue("timezone", "");
282
+ },
283
+ error: errors.timezone,
284
+ required: true,
285
+ children: timezoneList.map((timezone) => /* @__PURE__ */ jsxRuntime.jsx(designSystem.ComboboxOption, { value: timezone.value, children: timezone.value.replace("_", " ") }, timezone.value))
286
+ }
287
+ );
288
+ };
289
+ const LinkCard = styled__default.default(v2.Link)`
290
+ display: block;
291
+ `;
292
+ const CapitalizeRelativeTime = styled__default.default(helperPlugin.RelativeTime)`
293
+ text-transform: capitalize;
294
+ `;
295
+ const getBadgeProps = (status) => {
296
+ let color;
297
+ switch (status) {
298
+ case "ready":
299
+ color = "success";
300
+ break;
301
+ case "blocked":
302
+ color = "warning";
303
+ break;
304
+ case "failed":
305
+ color = "danger";
306
+ break;
307
+ case "done":
308
+ color = "primary";
309
+ break;
310
+ case "empty":
311
+ default:
312
+ color = "neutral";
313
+ }
314
+ return {
315
+ textColor: `${color}600`,
316
+ backgroundColor: `${color}100`,
317
+ borderColor: `${color}200`
318
+ };
319
+ };
320
+ const ReleasesGrid = ({ sectionTitle, releases = [], isError = false }) => {
321
+ const { formatMessage } = reactIntl.useIntl();
322
+ const IsSchedulingEnabled = window.strapi.future.isEnabled("contentReleasesScheduling");
323
+ if (isError) {
324
+ return /* @__PURE__ */ jsxRuntime.jsx(helperPlugin.AnErrorOccurred, {});
325
+ }
326
+ if (releases?.length === 0) {
327
+ return /* @__PURE__ */ jsxRuntime.jsx(
328
+ designSystem.EmptyStateLayout,
329
+ {
330
+ content: formatMessage(
331
+ {
332
+ id: "content-releases.page.Releases.tab.emptyEntries",
333
+ defaultMessage: "No releases"
334
+ },
335
+ {
336
+ target: sectionTitle
337
+ }
338
+ ),
339
+ icon: /* @__PURE__ */ jsxRuntime.jsx(icons.EmptyDocuments, { width: "10rem" })
340
+ }
341
+ );
342
+ }
343
+ return /* @__PURE__ */ jsxRuntime.jsx(designSystem.Grid, { gap: 4, children: releases.map(({ id, name, actions, 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(
344
+ designSystem.Flex,
345
+ {
346
+ direction: "column",
347
+ justifyContent: "space-between",
348
+ padding: 4,
349
+ hasRadius: true,
350
+ background: "neutral0",
351
+ shadow: "tableShadow",
352
+ height: "100%",
353
+ width: "100%",
354
+ alignItems: "start",
355
+ gap: 4,
356
+ children: [
357
+ /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { direction: "column", alignItems: "start", gap: 1, children: [
358
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { as: "h3", variant: "delta", fontWeight: "bold", children: name }),
359
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "pi", textColor: "neutral600", children: IsSchedulingEnabled ? scheduledAt ? /* @__PURE__ */ jsxRuntime.jsx(CapitalizeRelativeTime, { timestamp: new Date(scheduledAt) }) : formatMessage({
360
+ id: "content-releases.pages.Releases.not-scheduled",
361
+ defaultMessage: "Not scheduled"
362
+ }) : formatMessage(
363
+ {
364
+ id: "content-releases.page.Releases.release-item.entries",
365
+ defaultMessage: "{number, plural, =0 {No entries} one {# entry} other {# entries}}"
366
+ },
367
+ { number: actions.meta.count }
368
+ ) })
369
+ ] }),
370
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Badge, { ...getBadgeProps(status), children: status })
371
+ ]
372
+ }
373
+ ) }) }, id)) });
374
+ };
375
+ const StyledAlert = styled__default.default(designSystem.Alert)`
376
+ button {
377
+ display: none;
378
+ }
379
+ p + div {
380
+ margin-left: auto;
381
+ }
382
+ `;
383
+ const INITIAL_FORM_VALUES = {
384
+ name: "",
385
+ date: null,
386
+ time: "",
387
+ // Remove future flag check after Scheduling Beta release and replace with true as creating new release should include scheduling by default
388
+ isScheduled: window.strapi.future.isEnabled("contentReleasesScheduling"),
389
+ scheduledAt: null,
390
+ timezone: null
391
+ };
392
+ const ReleasesPage = () => {
393
+ const tabRef = React__namespace.useRef(null);
394
+ const location = reactRouterDom.useLocation();
395
+ const [releaseModalShown, setReleaseModalShown] = React__namespace.useState(false);
396
+ const toggleNotification = helperPlugin.useNotification();
397
+ const { formatMessage } = reactIntl.useIntl();
398
+ const { push, replace } = reactRouterDom.useHistory();
399
+ const { formatAPIError } = helperPlugin.useAPIErrorHandler();
400
+ const [{ query }, setQuery] = helperPlugin.useQueryParams();
401
+ const response = index.useGetReleasesQuery(query);
402
+ const [createRelease, { isLoading: isSubmittingForm }] = index.useCreateReleaseMutation();
403
+ const { getFeature } = strapiAdmin.useLicenseLimits();
404
+ const { maximumReleases = 3 } = getFeature("cms-content-releases");
405
+ const { trackUsage } = helperPlugin.useTracking();
406
+ const { isLoading, isSuccess, isError } = response;
407
+ const activeTab = response?.currentData?.meta?.activeTab || "pending";
408
+ const activeTabIndex = ["pending", "done"].indexOf(activeTab);
409
+ React__namespace.useEffect(() => {
410
+ if (location?.state?.errors) {
411
+ toggleNotification({
412
+ type: "warning",
413
+ title: formatMessage({
414
+ id: "content-releases.pages.Releases.notification.error.title",
415
+ defaultMessage: "Your request could not be processed."
416
+ }),
417
+ message: formatMessage({
418
+ id: "content-releases.pages.Releases.notification.error.message",
419
+ defaultMessage: "Please try again or open another release."
420
+ })
421
+ });
422
+ replace({ state: null });
423
+ }
424
+ }, [formatMessage, location?.state?.errors, replace, toggleNotification]);
425
+ React__namespace.useEffect(() => {
426
+ if (tabRef.current) {
427
+ tabRef.current._handlers.setSelectedTabIndex(activeTabIndex);
428
+ }
429
+ }, [activeTabIndex]);
430
+ const toggleAddReleaseModal = () => {
431
+ setReleaseModalShown((prev) => !prev);
432
+ };
433
+ if (isLoading) {
434
+ return /* @__PURE__ */ jsxRuntime.jsx(designSystem.Main, { "aria-busy": isLoading, children: /* @__PURE__ */ jsxRuntime.jsx(helperPlugin.LoadingIndicatorPage, {}) });
435
+ }
436
+ const totalPendingReleases = isSuccess && response.currentData?.meta?.pendingReleasesCount || 0;
437
+ const hasReachedMaximumPendingReleases = totalPendingReleases >= maximumReleases;
438
+ const handleTabChange = (index2) => {
439
+ setQuery({
440
+ ...query,
441
+ page: 1,
442
+ pageSize: response?.currentData?.meta?.pagination?.pageSize || 16,
443
+ filters: {
444
+ releasedAt: {
445
+ $notNull: index2 === 0 ? false : true
446
+ }
447
+ }
448
+ });
449
+ };
450
+ const handleAddRelease = async ({ name, scheduledAt, timezone }) => {
451
+ const response2 = await createRelease({
452
+ name,
453
+ scheduledAt,
454
+ timezone
455
+ });
456
+ if ("data" in response2) {
457
+ toggleNotification({
458
+ type: "success",
459
+ message: formatMessage({
460
+ id: "content-releases.modal.release-created-notification-success",
461
+ defaultMessage: "Release created."
462
+ })
463
+ });
464
+ trackUsage("didCreateRelease");
465
+ push(`/plugins/content-releases/${response2.data.data.id}`);
466
+ } else if (index.isAxiosError(response2.error)) {
467
+ toggleNotification({
468
+ type: "warning",
469
+ message: formatAPIError(response2.error)
470
+ });
471
+ } else {
472
+ toggleNotification({
473
+ type: "warning",
474
+ message: formatMessage({ id: "notification.error", defaultMessage: "An error occurred" })
475
+ });
476
+ }
477
+ };
478
+ return /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Main, { "aria-busy": isLoading, children: [
479
+ /* @__PURE__ */ jsxRuntime.jsx(
480
+ designSystem.HeaderLayout,
481
+ {
482
+ title: formatMessage({
483
+ id: "content-releases.pages.Releases.title",
484
+ defaultMessage: "Releases"
485
+ }),
486
+ subtitle: formatMessage({
487
+ id: "content-releases.pages.Releases.header-subtitle",
488
+ defaultMessage: "Create and manage content updates"
489
+ }),
490
+ primaryAction: /* @__PURE__ */ jsxRuntime.jsx(helperPlugin.CheckPermissions, { permissions: index.PERMISSIONS.create, children: /* @__PURE__ */ jsxRuntime.jsx(
491
+ designSystem.Button,
492
+ {
493
+ startIcon: /* @__PURE__ */ jsxRuntime.jsx(icons.Plus, {}),
494
+ onClick: toggleAddReleaseModal,
495
+ disabled: hasReachedMaximumPendingReleases,
496
+ children: formatMessage({
497
+ id: "content-releases.header.actions.add-release",
498
+ defaultMessage: "New release"
499
+ })
500
+ }
501
+ ) })
502
+ }
503
+ ),
504
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.ContentLayout, { children: /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
505
+ hasReachedMaximumPendingReleases && /* @__PURE__ */ jsxRuntime.jsx(
506
+ StyledAlert,
507
+ {
508
+ marginBottom: 6,
509
+ action: /* @__PURE__ */ jsxRuntime.jsx(v2.Link, { href: "https://strapi.io/pricing-cloud", isExternal: true, children: formatMessage({
510
+ id: "content-releases.pages.Releases.max-limit-reached.action",
511
+ defaultMessage: "Explore plans"
512
+ }) }),
513
+ title: formatMessage(
514
+ {
515
+ id: "content-releases.pages.Releases.max-limit-reached.title",
516
+ defaultMessage: "You have reached the {number} pending {number, plural, one {release} other {releases}} limit."
517
+ },
518
+ { number: maximumReleases }
519
+ ),
520
+ onClose: () => {
521
+ },
522
+ closeLabel: "",
523
+ children: formatMessage({
524
+ id: "content-releases.pages.Releases.max-limit-reached.message",
525
+ defaultMessage: "Upgrade to manage an unlimited number of releases."
526
+ })
527
+ }
528
+ ),
529
+ /* @__PURE__ */ jsxRuntime.jsxs(
530
+ designSystem.TabGroup,
531
+ {
532
+ label: formatMessage({
533
+ id: "content-releases.pages.Releases.tab-group.label",
534
+ defaultMessage: "Releases list"
535
+ }),
536
+ variant: "simple",
537
+ initialSelectedTabIndex: activeTabIndex,
538
+ onTabChange: handleTabChange,
539
+ ref: tabRef,
540
+ children: [
541
+ /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Box, { paddingBottom: 8, children: [
542
+ /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Tabs, { children: [
543
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Tab, { children: formatMessage(
544
+ {
545
+ id: "content-releases.pages.Releases.tab.pending",
546
+ defaultMessage: "Pending ({count})"
547
+ },
548
+ {
549
+ count: totalPendingReleases
550
+ }
551
+ ) }),
552
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Tab, { children: formatMessage({
553
+ id: "content-releases.pages.Releases.tab.done",
554
+ defaultMessage: "Done"
555
+ }) })
556
+ ] }),
557
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Divider, {})
558
+ ] }),
559
+ /* @__PURE__ */ jsxRuntime.jsxs(designSystem.TabPanels, { children: [
560
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.TabPanel, { children: /* @__PURE__ */ jsxRuntime.jsx(
561
+ ReleasesGrid,
562
+ {
563
+ sectionTitle: "pending",
564
+ releases: response?.currentData?.data,
565
+ isError
566
+ }
567
+ ) }),
568
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.TabPanel, { children: /* @__PURE__ */ jsxRuntime.jsx(
569
+ ReleasesGrid,
570
+ {
571
+ sectionTitle: "done",
572
+ releases: response?.currentData?.data,
573
+ isError
574
+ }
575
+ ) })
576
+ ] })
577
+ ]
578
+ }
579
+ ),
580
+ response.currentData?.meta?.pagination?.total ? /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { paddingTop: 4, alignItems: "flex-end", justifyContent: "space-between", children: [
581
+ /* @__PURE__ */ jsxRuntime.jsx(
582
+ helperPlugin.PageSizeURLQuery,
583
+ {
584
+ options: ["8", "16", "32", "64"],
585
+ defaultValue: response?.currentData?.meta?.pagination?.pageSize.toString()
586
+ }
587
+ ),
588
+ /* @__PURE__ */ jsxRuntime.jsx(
589
+ helperPlugin.PaginationURLQuery,
590
+ {
591
+ pagination: {
592
+ pageCount: response?.currentData?.meta?.pagination?.pageCount || 0
593
+ }
594
+ }
595
+ )
596
+ ] }) : null
597
+ ] }) }),
598
+ releaseModalShown && /* @__PURE__ */ jsxRuntime.jsx(
599
+ ReleaseModal,
600
+ {
601
+ handleClose: toggleAddReleaseModal,
602
+ handleSubmit: handleAddRelease,
603
+ isLoading: isSubmittingForm,
604
+ initialValues: INITIAL_FORM_VALUES
605
+ }
606
+ )
607
+ ] });
608
+ };
118
609
  const ReleaseInfoWrapper = styled__default.default(designSystem.Flex)`
119
610
  align-self: stretch;
120
611
  border-bottom-right-radius: ${({ theme }) => theme.borderRadius};
@@ -128,6 +619,10 @@ const StyledMenuItem = styled__default.default(v2.Menu.Item)`
128
619
  span {
129
620
  color: ${({ theme, disabled }) => disabled && theme.colors.neutral500};
130
621
  }
622
+
623
+ &:hover {
624
+ background: ${({ theme, variant = "neutral" }) => theme.colors[`${variant}100`]};
625
+ }
131
626
  `;
132
627
  const PencilIcon = styled__default.default(icons.Pencil)`
133
628
  width: ${({ theme }) => theme.spaces[3]};
@@ -194,7 +689,7 @@ const ReleaseDetailsLayout = ({
194
689
  toggleWarningSubmit,
195
690
  children
196
691
  }) => {
197
- const { formatMessage } = reactIntl.useIntl();
692
+ const { formatMessage, formatDate, formatTime } = reactIntl.useIntl();
198
693
  const { releaseId } = reactRouterDom.useParams();
199
694
  const {
200
695
  data,
@@ -276,18 +771,44 @@ const ReleaseDetailsLayout = ({
276
771
  }
277
772
  const totalEntries = release.actions.meta.count || 0;
278
773
  const hasCreatedByUser = Boolean(getCreatedByUser());
774
+ const IsSchedulingEnabled = window.strapi.future.isEnabled("contentReleasesScheduling");
775
+ const isScheduled = release.scheduledAt && release.timezone;
776
+ const numberOfEntriesText = formatMessage(
777
+ {
778
+ id: "content-releases.pages.Details.header-subtitle",
779
+ defaultMessage: "{number, plural, =0 {No entries} one {# entry} other {# entries}}"
780
+ },
781
+ { number: totalEntries }
782
+ );
783
+ const scheduledText = isScheduled ? formatMessage(
784
+ {
785
+ id: "content-releases.pages.ReleaseDetails.header-subtitle.scheduled",
786
+ defaultMessage: "Scheduled for {date} at {time} ({offset})"
787
+ },
788
+ {
789
+ date: formatDate(new Date(release.scheduledAt), {
790
+ weekday: "long",
791
+ day: "numeric",
792
+ month: "long",
793
+ year: "numeric",
794
+ timeZone: release.timezone
795
+ }),
796
+ time: formatTime(new Date(release.scheduledAt), {
797
+ timeZone: release.timezone,
798
+ hourCycle: "h23"
799
+ }),
800
+ offset: index.getTimezoneOffset(release.timezone, new Date(release.scheduledAt))
801
+ }
802
+ ) : "";
279
803
  return /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Main, { "aria-busy": isLoadingDetails, children: [
280
804
  /* @__PURE__ */ jsxRuntime.jsx(
281
805
  designSystem.HeaderLayout,
282
806
  {
283
807
  title: release.name,
284
- subtitle: formatMessage(
285
- {
286
- id: "content-releases.pages.Details.header-subtitle",
287
- defaultMessage: "{number, plural, =0 {No entries} one {# entry} other {# entries}}"
288
- },
289
- { number: totalEntries }
290
- ),
808
+ subtitle: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { gap: 2, lineHeight: 6, children: [
809
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { textColor: "neutral600", variant: "epsilon", children: numberOfEntriesText + (IsSchedulingEnabled && isScheduled ? ` - ${scheduledText}` : "") }),
810
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Badge, { ...getBadgeProps(release.status), children: release.status })
811
+ ] }),
291
812
  navigationAction: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Link, { startIcon: /* @__PURE__ */ jsxRuntime.jsx(icons.ArrowLeft, {}), to: "/plugins/content-releases", children: formatMessage({
292
813
  id: "global.back",
293
814
  defaultMessage: "Back"
@@ -318,42 +839,28 @@ const ReleaseDetailsLayout = ({
318
839
  padding: 1,
319
840
  width: "100%",
320
841
  children: [
321
- /* @__PURE__ */ jsxRuntime.jsx(StyledMenuItem, { disabled: !canUpdate, onSelect: toggleEditReleaseModal, children: /* @__PURE__ */ jsxRuntime.jsxs(
322
- designSystem.Flex,
323
- {
324
- paddingTop: 2,
325
- paddingBottom: 2,
326
- alignItems: "center",
327
- gap: 2,
328
- hasRadius: true,
329
- width: "100%",
330
- children: [
331
- /* @__PURE__ */ jsxRuntime.jsx(PencilIcon, {}),
332
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { ellipsis: true, children: formatMessage({
333
- id: "content-releases.header.actions.edit",
334
- defaultMessage: "Edit"
335
- }) })
336
- ]
337
- }
338
- ) }),
339
- /* @__PURE__ */ jsxRuntime.jsx(StyledMenuItem, { disabled: !canDelete, onSelect: toggleWarningSubmit, children: /* @__PURE__ */ jsxRuntime.jsxs(
340
- designSystem.Flex,
842
+ /* @__PURE__ */ jsxRuntime.jsx(StyledMenuItem, { disabled: !canUpdate, onSelect: toggleEditReleaseModal, children: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { alignItems: "center", gap: 2, hasRadius: true, width: "100%", children: [
843
+ /* @__PURE__ */ jsxRuntime.jsx(PencilIcon, {}),
844
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { ellipsis: true, children: formatMessage({
845
+ id: "content-releases.header.actions.edit",
846
+ defaultMessage: "Edit"
847
+ }) })
848
+ ] }) }),
849
+ /* @__PURE__ */ jsxRuntime.jsx(
850
+ StyledMenuItem,
341
851
  {
342
- paddingTop: 2,
343
- paddingBottom: 2,
344
- alignItems: "center",
345
- gap: 2,
346
- hasRadius: true,
347
- width: "100%",
348
- children: [
852
+ disabled: !canDelete,
853
+ onSelect: toggleWarningSubmit,
854
+ variant: "danger",
855
+ children: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { alignItems: "center", gap: 2, hasRadius: true, width: "100%", children: [
349
856
  /* @__PURE__ */ jsxRuntime.jsx(TrashIcon, {}),
350
857
  /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { ellipsis: true, textColor: "danger600", children: formatMessage({
351
858
  id: "content-releases.header.actions.delete",
352
859
  defaultMessage: "Delete"
353
860
  }) })
354
- ]
861
+ ] })
355
862
  }
356
- ) })
863
+ )
357
864
  ]
358
865
  }
359
866
  ),
@@ -736,11 +1243,18 @@ const ReleaseDetailsPage = () => {
736
1243
  }
737
1244
  );
738
1245
  }
739
- const title = isSuccessDetails && data?.data?.name || "";
1246
+ const releaseData = isSuccessDetails && data?.data || null;
1247
+ const title = releaseData?.name || "";
1248
+ const timezone = releaseData?.timezone ?? null;
1249
+ const scheduledAt = releaseData?.scheduledAt && timezone ? dateFnsTz.utcToZonedTime(releaseData.scheduledAt, timezone) : null;
1250
+ const date = scheduledAt ? new Date(format__default.default(scheduledAt, "yyyy-MM-dd")) : null;
1251
+ const time = scheduledAt ? format__default.default(scheduledAt, "HH:mm") : "";
740
1252
  const handleEditRelease = async (values) => {
741
1253
  const response = await updateRelease({
742
1254
  id: releaseId,
743
- name: values.name
1255
+ name: values.name,
1256
+ scheduledAt: values.scheduledAt,
1257
+ timezone: values.timezone
744
1258
  });
745
1259
  if ("data" in response) {
746
1260
  toggleNotification({
@@ -794,7 +1308,14 @@ const ReleaseDetailsPage = () => {
794
1308
  handleClose: toggleEditReleaseModal,
795
1309
  handleSubmit: handleEditRelease,
796
1310
  isLoading: isLoadingDetails || isSubmittingForm,
797
- initialValues: { name: title || "" }
1311
+ initialValues: {
1312
+ name: title || "",
1313
+ scheduledAt,
1314
+ date,
1315
+ time,
1316
+ isScheduled: Boolean(scheduledAt),
1317
+ timezone
1318
+ }
798
1319
  }
799
1320
  ),
800
1321
  /* @__PURE__ */ jsxRuntime.jsx(
@@ -814,281 +1335,6 @@ const ReleaseDetailsPage = () => {
814
1335
  }
815
1336
  );
816
1337
  };
817
- const LinkCard = styled__default.default(v2.Link)`
818
- display: block;
819
- `;
820
- const ReleasesGrid = ({ sectionTitle, releases = [], isError = false }) => {
821
- const { formatMessage } = reactIntl.useIntl();
822
- if (isError) {
823
- return /* @__PURE__ */ jsxRuntime.jsx(helperPlugin.AnErrorOccurred, {});
824
- }
825
- if (releases?.length === 0) {
826
- return /* @__PURE__ */ jsxRuntime.jsx(
827
- designSystem.EmptyStateLayout,
828
- {
829
- content: formatMessage(
830
- {
831
- id: "content-releases.page.Releases.tab.emptyEntries",
832
- defaultMessage: "No releases"
833
- },
834
- {
835
- target: sectionTitle
836
- }
837
- ),
838
- icon: /* @__PURE__ */ jsxRuntime.jsx(icons.EmptyDocuments, { width: "10rem" })
839
- }
840
- );
841
- }
842
- 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(
843
- designSystem.Flex,
844
- {
845
- direction: "column",
846
- justifyContent: "space-between",
847
- padding: 4,
848
- hasRadius: true,
849
- background: "neutral0",
850
- shadow: "tableShadow",
851
- height: "100%",
852
- width: "100%",
853
- alignItems: "start",
854
- gap: 2,
855
- children: [
856
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { as: "h3", variant: "delta", fontWeight: "bold", children: name }),
857
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "pi", children: formatMessage(
858
- {
859
- id: "content-releases.page.Releases.release-item.entries",
860
- defaultMessage: "{number, plural, =0 {No entries} one {# entry} other {# entries}}"
861
- },
862
- { number: actions.meta.count }
863
- ) })
864
- ]
865
- }
866
- ) }) }, id)) });
867
- };
868
- const StyledAlert = styled__default.default(designSystem.Alert)`
869
- button {
870
- display: none;
871
- }
872
- p + div {
873
- margin-left: auto;
874
- }
875
- `;
876
- const INITIAL_FORM_VALUES = {
877
- name: ""
878
- };
879
- const ReleasesPage = () => {
880
- const tabRef = React__namespace.useRef(null);
881
- const location = reactRouterDom.useLocation();
882
- const [releaseModalShown, setReleaseModalShown] = React__namespace.useState(false);
883
- const toggleNotification = helperPlugin.useNotification();
884
- const { formatMessage } = reactIntl.useIntl();
885
- const { push, replace } = reactRouterDom.useHistory();
886
- const { formatAPIError } = helperPlugin.useAPIErrorHandler();
887
- const [{ query }, setQuery] = helperPlugin.useQueryParams();
888
- const response = index.useGetReleasesQuery(query);
889
- const [createRelease, { isLoading: isSubmittingForm }] = index.useCreateReleaseMutation();
890
- const { getFeature } = strapiAdmin.useLicenseLimits();
891
- const { maximumReleases = 3 } = getFeature("cms-content-releases");
892
- const { trackUsage } = helperPlugin.useTracking();
893
- const { isLoading, isSuccess, isError } = response;
894
- const activeTab = response?.currentData?.meta?.activeTab || "pending";
895
- const activeTabIndex = ["pending", "done"].indexOf(activeTab);
896
- React__namespace.useEffect(() => {
897
- if (location?.state?.errors) {
898
- toggleNotification({
899
- type: "warning",
900
- title: formatMessage({
901
- id: "content-releases.pages.Releases.notification.error.title",
902
- defaultMessage: "Your request could not be processed."
903
- }),
904
- message: formatMessage({
905
- id: "content-releases.pages.Releases.notification.error.message",
906
- defaultMessage: "Please try again or open another release."
907
- })
908
- });
909
- replace({ state: null });
910
- }
911
- }, [formatMessage, location?.state?.errors, replace, toggleNotification]);
912
- React__namespace.useEffect(() => {
913
- if (tabRef.current) {
914
- tabRef.current._handlers.setSelectedTabIndex(activeTabIndex);
915
- }
916
- }, [activeTabIndex]);
917
- const toggleAddReleaseModal = () => {
918
- setReleaseModalShown((prev) => !prev);
919
- };
920
- if (isLoading) {
921
- return /* @__PURE__ */ jsxRuntime.jsx(designSystem.Main, { "aria-busy": isLoading, children: /* @__PURE__ */ jsxRuntime.jsx(helperPlugin.LoadingIndicatorPage, {}) });
922
- }
923
- const totalReleases = isSuccess && response.currentData?.meta?.pagination?.total || 0;
924
- const hasReachedMaximumPendingReleases = totalReleases >= maximumReleases;
925
- const handleTabChange = (index2) => {
926
- setQuery({
927
- ...query,
928
- page: 1,
929
- pageSize: response?.currentData?.meta?.pagination?.pageSize || 16,
930
- filters: {
931
- releasedAt: {
932
- $notNull: index2 === 0 ? false : true
933
- }
934
- }
935
- });
936
- };
937
- const handleAddRelease = async (values) => {
938
- const response2 = await createRelease({
939
- name: values.name
940
- });
941
- if ("data" in response2) {
942
- toggleNotification({
943
- type: "success",
944
- message: formatMessage({
945
- id: "content-releases.modal.release-created-notification-success",
946
- defaultMessage: "Release created."
947
- })
948
- });
949
- trackUsage("didCreateRelease");
950
- push(`/plugins/content-releases/${response2.data.data.id}`);
951
- } else if (index.isAxiosError(response2.error)) {
952
- toggleNotification({
953
- type: "warning",
954
- message: formatAPIError(response2.error)
955
- });
956
- } else {
957
- toggleNotification({
958
- type: "warning",
959
- message: formatMessage({ id: "notification.error", defaultMessage: "An error occurred" })
960
- });
961
- }
962
- };
963
- return /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Main, { "aria-busy": isLoading, children: [
964
- /* @__PURE__ */ jsxRuntime.jsx(
965
- designSystem.HeaderLayout,
966
- {
967
- title: formatMessage({
968
- id: "content-releases.pages.Releases.title",
969
- defaultMessage: "Releases"
970
- }),
971
- subtitle: formatMessage(
972
- {
973
- id: "content-releases.pages.Releases.header-subtitle",
974
- defaultMessage: "{number, plural, =0 {No releases} one {# release} other {# releases}}"
975
- },
976
- { number: totalReleases }
977
- ),
978
- primaryAction: /* @__PURE__ */ jsxRuntime.jsx(helperPlugin.CheckPermissions, { permissions: index.PERMISSIONS.create, children: /* @__PURE__ */ jsxRuntime.jsx(
979
- designSystem.Button,
980
- {
981
- startIcon: /* @__PURE__ */ jsxRuntime.jsx(icons.Plus, {}),
982
- onClick: toggleAddReleaseModal,
983
- disabled: hasReachedMaximumPendingReleases,
984
- children: formatMessage({
985
- id: "content-releases.header.actions.add-release",
986
- defaultMessage: "New release"
987
- })
988
- }
989
- ) })
990
- }
991
- ),
992
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.ContentLayout, { children: /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
993
- activeTab === "pending" && hasReachedMaximumPendingReleases && /* @__PURE__ */ jsxRuntime.jsx(
994
- StyledAlert,
995
- {
996
- marginBottom: 6,
997
- action: /* @__PURE__ */ jsxRuntime.jsx(v2.Link, { href: "https://strapi.io/pricing-cloud", isExternal: true, children: formatMessage({
998
- id: "content-releases.pages.Releases.max-limit-reached.action",
999
- defaultMessage: "Explore plans"
1000
- }) }),
1001
- title: formatMessage(
1002
- {
1003
- id: "content-releases.pages.Releases.max-limit-reached.title",
1004
- defaultMessage: "You have reached the {number} pending {number, plural, one {release} other {releases}} limit."
1005
- },
1006
- { number: maximumReleases }
1007
- ),
1008
- onClose: () => {
1009
- },
1010
- closeLabel: "",
1011
- children: formatMessage({
1012
- id: "content-releases.pages.Releases.max-limit-reached.message",
1013
- defaultMessage: "Upgrade to manage an unlimited number of releases."
1014
- })
1015
- }
1016
- ),
1017
- /* @__PURE__ */ jsxRuntime.jsxs(
1018
- designSystem.TabGroup,
1019
- {
1020
- label: formatMessage({
1021
- id: "content-releases.pages.Releases.tab-group.label",
1022
- defaultMessage: "Releases list"
1023
- }),
1024
- variant: "simple",
1025
- initialSelectedTabIndex: activeTabIndex,
1026
- onTabChange: handleTabChange,
1027
- ref: tabRef,
1028
- children: [
1029
- /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Box, { paddingBottom: 8, children: [
1030
- /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Tabs, { children: [
1031
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Tab, { children: formatMessage({
1032
- id: "content-releases.pages.Releases.tab.pending",
1033
- defaultMessage: "Pending"
1034
- }) }),
1035
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Tab, { children: formatMessage({
1036
- id: "content-releases.pages.Releases.tab.done",
1037
- defaultMessage: "Done"
1038
- }) })
1039
- ] }),
1040
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Divider, {})
1041
- ] }),
1042
- /* @__PURE__ */ jsxRuntime.jsxs(designSystem.TabPanels, { children: [
1043
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.TabPanel, { children: /* @__PURE__ */ jsxRuntime.jsx(
1044
- ReleasesGrid,
1045
- {
1046
- sectionTitle: "pending",
1047
- releases: response?.currentData?.data,
1048
- isError
1049
- }
1050
- ) }),
1051
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.TabPanel, { children: /* @__PURE__ */ jsxRuntime.jsx(
1052
- ReleasesGrid,
1053
- {
1054
- sectionTitle: "done",
1055
- releases: response?.currentData?.data,
1056
- isError
1057
- }
1058
- ) })
1059
- ] })
1060
- ]
1061
- }
1062
- ),
1063
- totalReleases > 0 && /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { paddingTop: 4, alignItems: "flex-end", justifyContent: "space-between", children: [
1064
- /* @__PURE__ */ jsxRuntime.jsx(
1065
- helperPlugin.PageSizeURLQuery,
1066
- {
1067
- options: ["8", "16", "32", "64"],
1068
- defaultValue: response?.currentData?.meta?.pagination?.pageSize.toString()
1069
- }
1070
- ),
1071
- /* @__PURE__ */ jsxRuntime.jsx(
1072
- helperPlugin.PaginationURLQuery,
1073
- {
1074
- pagination: {
1075
- pageCount: response?.currentData?.meta?.pagination?.pageCount || 0
1076
- }
1077
- }
1078
- )
1079
- ] })
1080
- ] }) }),
1081
- releaseModalShown && /* @__PURE__ */ jsxRuntime.jsx(
1082
- ReleaseModal,
1083
- {
1084
- handleClose: toggleAddReleaseModal,
1085
- handleSubmit: handleAddRelease,
1086
- isLoading: isSubmittingForm,
1087
- initialValues: INITIAL_FORM_VALUES
1088
- }
1089
- )
1090
- ] });
1091
- };
1092
1338
  const App = () => {
1093
1339
  return /* @__PURE__ */ jsxRuntime.jsx(helperPlugin.CheckPagePermissions, { permissions: index.PERMISSIONS.main, children: /* @__PURE__ */ jsxRuntime.jsxs(reactRouterDom.Switch, { children: [
1094
1340
  /* @__PURE__ */ jsxRuntime.jsx(reactRouterDom.Route, { exact: true, path: `/plugins/${index.pluginId}`, component: ReleasesPage }),
@@ -1096,4 +1342,4 @@ const App = () => {
1096
1342
  ] }) });
1097
1343
  };
1098
1344
  exports.App = App;
1099
- //# sourceMappingURL=App-1hHIqUoZ.js.map
1345
+ //# sourceMappingURL=App-ODHUuKJ5.js.map