@strapi/content-releases 0.0.0-next.09b9d36b22a205d90c9303f2e37134938cf76c90 → 0.0.0-next.0a8a7f1e0ee2fb410eeffb9eb1943d28f1f24705

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 (32) hide show
  1. package/dist/_chunks/App-HVXzE3i3.mjs +1313 -0
  2. package/dist/_chunks/App-HVXzE3i3.mjs.map +1 -0
  3. package/dist/_chunks/{App-8384e404.js → App-l62gIUTX.js} +790 -421
  4. package/dist/_chunks/App-l62gIUTX.js.map +1 -0
  5. package/dist/_chunks/PurchaseContentReleases-Clm0iACO.mjs +51 -0
  6. package/dist/_chunks/PurchaseContentReleases-Clm0iACO.mjs.map +1 -0
  7. package/dist/_chunks/PurchaseContentReleases-YhAPgpG9.js +51 -0
  8. package/dist/_chunks/PurchaseContentReleases-YhAPgpG9.js.map +1 -0
  9. package/dist/_chunks/{en-142f336a.mjs → en-RdapH-9X.mjs} +22 -7
  10. package/dist/_chunks/en-RdapH-9X.mjs.map +1 -0
  11. package/dist/_chunks/{en-f235921e.js → en-faJDuv3q.js} +22 -7
  12. package/dist/_chunks/en-faJDuv3q.js.map +1 -0
  13. package/dist/_chunks/{index-7250b0a5.js → index-ML_b3php.js} +248 -48
  14. package/dist/_chunks/index-ML_b3php.js.map +1 -0
  15. package/dist/_chunks/{index-e14e1ea9.mjs → index-Ys87ROOe.mjs} +263 -63
  16. package/dist/_chunks/index-Ys87ROOe.mjs.map +1 -0
  17. package/dist/admin/index.js +2 -1
  18. package/dist/admin/index.js.map +1 -1
  19. package/dist/admin/index.mjs +3 -2
  20. package/dist/admin/index.mjs.map +1 -1
  21. package/dist/server/index.js +1130 -299
  22. package/dist/server/index.js.map +1 -1
  23. package/dist/server/index.mjs +1129 -300
  24. package/dist/server/index.mjs.map +1 -1
  25. package/package.json +15 -11
  26. package/dist/_chunks/App-8384e404.js.map +0 -1
  27. package/dist/_chunks/App-c3fca40f.mjs +0 -945
  28. package/dist/_chunks/App-c3fca40f.mjs.map +0 -1
  29. package/dist/_chunks/en-142f336a.mjs.map +0 -1
  30. package/dist/_chunks/en-f235921e.js.map +0 -1
  31. package/dist/_chunks/index-7250b0a5.js.map +0 -1
  32. package/dist/_chunks/index-e14e1ea9.mjs.map +0 -1
@@ -3,18 +3,23 @@ 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-7250b0a5.js");
6
+ const index = require("./index-ML_b3php.js");
7
7
  const React = require("react");
8
+ const strapiAdmin = require("@strapi/admin/strapi-admin");
8
9
  const designSystem = require("@strapi/design-system");
9
10
  const v2 = require("@strapi/design-system/v2");
10
11
  const icons = require("@strapi/icons");
12
+ const format = require("date-fns/format");
13
+ const dateFnsTz = require("date-fns-tz");
11
14
  const reactIntl = require("react-intl");
12
15
  const styled = require("styled-components");
16
+ const dateFns = require("date-fns");
13
17
  const formik = require("formik");
14
18
  const yup = require("yup");
15
19
  require("@reduxjs/toolkit/query");
16
20
  require("axios");
17
21
  require("@reduxjs/toolkit/query/react");
22
+ require("react-redux");
18
23
  const _interopDefault = (e) => e && e.__esModule ? e : { default: e };
19
24
  function _interopNamespace(e) {
20
25
  if (e && e.__esModule)
@@ -35,10 +40,28 @@ function _interopNamespace(e) {
35
40
  return Object.freeze(n);
36
41
  }
37
42
  const React__namespace = /* @__PURE__ */ _interopNamespace(React);
43
+ const format__default = /* @__PURE__ */ _interopDefault(format);
38
44
  const styled__default = /* @__PURE__ */ _interopDefault(styled);
39
45
  const yup__namespace = /* @__PURE__ */ _interopNamespace(yup);
40
46
  const RELEASE_SCHEMA = yup__namespace.object().shape({
41
- name: yup__namespace.string().trim().required()
47
+ name: yup__namespace.string().trim().required(),
48
+ scheduledAt: yup__namespace.string().nullable(),
49
+ isScheduled: yup__namespace.boolean().optional(),
50
+ time: yup__namespace.string().when("isScheduled", {
51
+ is: true,
52
+ then: yup__namespace.string().trim().required(),
53
+ otherwise: yup__namespace.string().nullable()
54
+ }),
55
+ timezone: yup__namespace.string().when("isScheduled", {
56
+ is: true,
57
+ then: yup__namespace.string().required().nullable(),
58
+ otherwise: yup__namespace.string().nullable()
59
+ }),
60
+ date: yup__namespace.string().when("isScheduled", {
61
+ is: true,
62
+ then: yup__namespace.string().required().nullable(),
63
+ otherwise: yup__namespace.string().nullable()
64
+ })
42
65
  }).required().noUnknown();
43
66
  const ReleaseModal = ({
44
67
  handleClose,
@@ -49,6 +72,23 @@ const ReleaseModal = ({
49
72
  const { formatMessage } = reactIntl.useIntl();
50
73
  const { pathname } = reactRouterDom.useLocation();
51
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 formattedDate = dateFns.parse(time, "HH:mm", new Date(date));
83
+ const timezoneWithoutOffset = timezone.split("&")[1];
84
+ return dateFnsTz.zonedTimeToUtc(formattedDate, timezoneWithoutOffset);
85
+ };
86
+ const getTimezoneWithOffset = () => {
87
+ const currentTimezone = timezoneList.find(
88
+ (timezone) => timezone.value.split("&")[1] === initialValues.timezone
89
+ );
90
+ return currentTimezone?.value || systemTimezone.value;
91
+ };
52
92
  return /* @__PURE__ */ jsxRuntime.jsxs(designSystem.ModalLayout, { onClose: handleClose, labelledBy: "title", children: [
53
93
  /* @__PURE__ */ jsxRuntime.jsx(designSystem.ModalHeader, { children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { id: "title", fontWeight: "bold", textColor: "neutral800", children: formatMessage(
54
94
  {
@@ -60,45 +100,130 @@ const ReleaseModal = ({
60
100
  /* @__PURE__ */ jsxRuntime.jsx(
61
101
  formik.Formik,
62
102
  {
63
- validateOnChange: false,
64
- onSubmit: handleSubmit,
65
- initialValues,
103
+ onSubmit: (values) => {
104
+ handleSubmit({
105
+ ...values,
106
+ timezone: values.timezone ? values.timezone.split("&")[1] : null,
107
+ scheduledAt: values.isScheduled ? getScheduledTimestamp(values) : null
108
+ });
109
+ },
110
+ initialValues: {
111
+ ...initialValues,
112
+ timezone: initialValues.timezone ? getTimezoneWithOffset() : systemTimezone.value
113
+ },
66
114
  validationSchema: RELEASE_SCHEMA,
67
- children: ({ values, errors, handleChange }) => /* @__PURE__ */ jsxRuntime.jsxs(formik.Form, { children: [
68
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.ModalBody, { children: /* @__PURE__ */ jsxRuntime.jsx(
69
- designSystem.TextInput,
70
- {
71
- label: formatMessage({
72
- id: "content-releases.modal.form.input.label.release-name",
73
- defaultMessage: "Name"
74
- }),
75
- name: "name",
76
- value: values.name,
77
- error: errors.name,
78
- onChange: handleChange,
79
- required: true
80
- }
81
- ) }),
115
+ validateOnChange: false,
116
+ children: ({ values, errors, handleChange, setFieldValue }) => /* @__PURE__ */ jsxRuntime.jsxs(formik.Form, { children: [
117
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.ModalBody, { children: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { direction: "column", alignItems: "stretch", gap: 6, children: [
118
+ /* @__PURE__ */ jsxRuntime.jsx(
119
+ designSystem.TextInput,
120
+ {
121
+ label: formatMessage({
122
+ id: "content-releases.modal.form.input.label.release-name",
123
+ defaultMessage: "Name"
124
+ }),
125
+ name: "name",
126
+ value: values.name,
127
+ error: errors.name,
128
+ onChange: handleChange,
129
+ required: true
130
+ }
131
+ ),
132
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Box, { width: "max-content", children: /* @__PURE__ */ jsxRuntime.jsx(
133
+ designSystem.Checkbox,
134
+ {
135
+ name: "isScheduled",
136
+ value: values.isScheduled,
137
+ onChange: (event) => {
138
+ setFieldValue("isScheduled", event.target.checked);
139
+ if (!event.target.checked) {
140
+ setFieldValue("date", null);
141
+ setFieldValue("time", "");
142
+ setFieldValue("timezone", null);
143
+ } else {
144
+ setFieldValue("date", initialValues.date);
145
+ setFieldValue("time", initialValues.time);
146
+ setFieldValue("timezone", initialValues.timezone ?? systemTimezone?.value);
147
+ }
148
+ },
149
+ children: /* @__PURE__ */ jsxRuntime.jsx(
150
+ designSystem.Typography,
151
+ {
152
+ textColor: values.isScheduled ? "primary600" : "neutral800",
153
+ fontWeight: values.isScheduled ? "semiBold" : "regular",
154
+ children: formatMessage({
155
+ id: "modal.form.input.label.schedule-release",
156
+ defaultMessage: "Schedule release"
157
+ })
158
+ }
159
+ )
160
+ }
161
+ ) }),
162
+ values.isScheduled && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
163
+ /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { gap: 4, alignItems: "start", children: [
164
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Box, { width: "100%", children: /* @__PURE__ */ jsxRuntime.jsx(
165
+ designSystem.DatePicker,
166
+ {
167
+ label: formatMessage({
168
+ id: "content-releases.modal.form.input.label.date",
169
+ defaultMessage: "Date"
170
+ }),
171
+ name: "date",
172
+ error: errors.date,
173
+ onChange: (date) => {
174
+ const isoFormatDate = date ? dateFns.formatISO(date, { representation: "date" }) : null;
175
+ setFieldValue("date", isoFormatDate);
176
+ },
177
+ clearLabel: formatMessage({
178
+ id: "content-releases.modal.form.input.clearLabel",
179
+ defaultMessage: "Clear"
180
+ }),
181
+ onClear: () => {
182
+ setFieldValue("date", null);
183
+ },
184
+ selectedDate: values.date || void 0,
185
+ required: true,
186
+ minDate: dateFnsTz.utcToZonedTime(/* @__PURE__ */ new Date(), values.timezone.split("&")[1])
187
+ }
188
+ ) }),
189
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Box, { width: "100%", children: /* @__PURE__ */ jsxRuntime.jsx(
190
+ designSystem.TimePicker,
191
+ {
192
+ label: formatMessage({
193
+ id: "content-releases.modal.form.input.label.time",
194
+ defaultMessage: "Time"
195
+ }),
196
+ name: "time",
197
+ error: errors.time,
198
+ onChange: (time) => {
199
+ setFieldValue("time", time);
200
+ },
201
+ clearLabel: formatMessage({
202
+ id: "content-releases.modal.form.input.clearLabel",
203
+ defaultMessage: "Clear"
204
+ }),
205
+ onClear: () => {
206
+ setFieldValue("time", "");
207
+ },
208
+ value: values.time || void 0,
209
+ required: true
210
+ }
211
+ ) })
212
+ ] }),
213
+ /* @__PURE__ */ jsxRuntime.jsx(TimezoneComponent, { timezoneOptions: timezoneList })
214
+ ] })
215
+ ] }) }),
82
216
  /* @__PURE__ */ jsxRuntime.jsx(
83
217
  designSystem.ModalFooter,
84
218
  {
85
219
  startActions: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Button, { onClick: handleClose, variant: "tertiary", name: "cancel", children: formatMessage({ id: "cancel", defaultMessage: "Cancel" }) }),
86
- endActions: /* @__PURE__ */ jsxRuntime.jsx(
87
- designSystem.Button,
220
+ endActions: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Button, { name: "submit", loading: isLoading, type: "submit", children: formatMessage(
88
221
  {
89
- name: "submit",
90
- loading: isLoading,
91
- disabled: !values.name || values.name === initialValues.name,
92
- type: "submit",
93
- children: formatMessage(
94
- {
95
- id: "content-releases.modal.form.button.submit",
96
- defaultMessage: "{isCreatingRelease, select, true {Continue} other {Save}}"
97
- },
98
- { isCreatingRelease }
99
- )
100
- }
101
- )
222
+ id: "content-releases.modal.form.button.submit",
223
+ defaultMessage: "{isCreatingRelease, select, true {Continue} other {Save}}"
224
+ },
225
+ { isCreatingRelease }
226
+ ) })
102
227
  }
103
228
  )
104
229
  ] })
@@ -106,61 +231,427 @@ const ReleaseModal = ({
106
231
  )
107
232
  ] });
108
233
  };
234
+ const getTimezones = (selectedDate) => {
235
+ const timezoneList = Intl.supportedValuesOf("timeZone").map((timezone) => {
236
+ const utcOffset = index.getTimezoneOffset(timezone, selectedDate);
237
+ return { offset: utcOffset, value: `${utcOffset}&${timezone}` };
238
+ });
239
+ const systemTimezone = timezoneList.find(
240
+ (timezone) => timezone.value.split("&")[1] === Intl.DateTimeFormat().resolvedOptions().timeZone
241
+ );
242
+ return { timezoneList, systemTimezone };
243
+ };
244
+ const TimezoneComponent = ({ timezoneOptions }) => {
245
+ const { values, errors, setFieldValue } = formik.useFormikContext();
246
+ const { formatMessage } = reactIntl.useIntl();
247
+ const [timezoneList, setTimezoneList] = React__namespace.useState(timezoneOptions);
248
+ React__namespace.useEffect(() => {
249
+ if (values.date) {
250
+ const { timezoneList: timezoneList2 } = getTimezones(new Date(values.date));
251
+ setTimezoneList(timezoneList2);
252
+ const updatedTimezone = values.timezone && timezoneList2.find((tz) => tz.value.split("&")[1] === values.timezone.split("&")[1]);
253
+ if (updatedTimezone) {
254
+ setFieldValue("timezone", updatedTimezone.value);
255
+ }
256
+ }
257
+ }, [setFieldValue, values.date, values.timezone]);
258
+ return /* @__PURE__ */ jsxRuntime.jsx(
259
+ designSystem.Combobox,
260
+ {
261
+ label: formatMessage({
262
+ id: "content-releases.modal.form.input.label.timezone",
263
+ defaultMessage: "Timezone"
264
+ }),
265
+ autocomplete: { type: "list", filter: "contains" },
266
+ name: "timezone",
267
+ value: values.timezone || void 0,
268
+ textValue: values.timezone ? values.timezone.replace(/&/, " ") : void 0,
269
+ onChange: (timezone) => {
270
+ setFieldValue("timezone", timezone);
271
+ },
272
+ onTextValueChange: (timezone) => {
273
+ setFieldValue("timezone", timezone);
274
+ },
275
+ onClear: () => {
276
+ setFieldValue("timezone", "");
277
+ },
278
+ error: errors.timezone,
279
+ required: true,
280
+ children: timezoneList.map((timezone) => /* @__PURE__ */ jsxRuntime.jsx(designSystem.ComboboxOption, { value: timezone.value, children: timezone.value.replace(/&/, " ") }, timezone.value))
281
+ }
282
+ );
283
+ };
284
+ const LinkCard = styled__default.default(v2.Link)`
285
+ display: block;
286
+ `;
287
+ const CapitalizeRelativeTime = styled__default.default(helperPlugin.RelativeTime)`
288
+ text-transform: capitalize;
289
+ `;
290
+ const getBadgeProps = (status) => {
291
+ let color;
292
+ switch (status) {
293
+ case "ready":
294
+ color = "success";
295
+ break;
296
+ case "blocked":
297
+ color = "warning";
298
+ break;
299
+ case "failed":
300
+ color = "danger";
301
+ break;
302
+ case "done":
303
+ color = "primary";
304
+ break;
305
+ case "empty":
306
+ default:
307
+ color = "neutral";
308
+ }
309
+ return {
310
+ textColor: `${color}600`,
311
+ backgroundColor: `${color}100`,
312
+ borderColor: `${color}200`
313
+ };
314
+ };
315
+ const ReleasesGrid = ({ sectionTitle, releases = [], isError = false }) => {
316
+ const { formatMessage } = reactIntl.useIntl();
317
+ if (isError) {
318
+ return /* @__PURE__ */ jsxRuntime.jsx(helperPlugin.AnErrorOccurred, {});
319
+ }
320
+ if (releases?.length === 0) {
321
+ return /* @__PURE__ */ jsxRuntime.jsx(
322
+ designSystem.EmptyStateLayout,
323
+ {
324
+ content: formatMessage(
325
+ {
326
+ id: "content-releases.page.Releases.tab.emptyEntries",
327
+ defaultMessage: "No releases"
328
+ },
329
+ {
330
+ target: sectionTitle
331
+ }
332
+ ),
333
+ icon: /* @__PURE__ */ jsxRuntime.jsx(icons.EmptyDocuments, { width: "10rem" })
334
+ }
335
+ );
336
+ }
337
+ 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(
338
+ designSystem.Flex,
339
+ {
340
+ direction: "column",
341
+ justifyContent: "space-between",
342
+ padding: 4,
343
+ hasRadius: true,
344
+ background: "neutral0",
345
+ shadow: "tableShadow",
346
+ height: "100%",
347
+ width: "100%",
348
+ alignItems: "start",
349
+ gap: 4,
350
+ children: [
351
+ /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { direction: "column", alignItems: "start", gap: 1, children: [
352
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { as: "h3", variant: "delta", fontWeight: "bold", children: name }),
353
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "pi", textColor: "neutral600", children: scheduledAt ? /* @__PURE__ */ jsxRuntime.jsx(CapitalizeRelativeTime, { timestamp: new Date(scheduledAt) }) : formatMessage({
354
+ id: "content-releases.pages.Releases.not-scheduled",
355
+ defaultMessage: "Not scheduled"
356
+ }) })
357
+ ] }),
358
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Badge, { ...getBadgeProps(status), children: status })
359
+ ]
360
+ }
361
+ ) }) }, id)) });
362
+ };
363
+ const StyledAlert = styled__default.default(designSystem.Alert)`
364
+ button {
365
+ display: none;
366
+ }
367
+ p + div {
368
+ margin-left: auto;
369
+ }
370
+ `;
371
+ const INITIAL_FORM_VALUES = {
372
+ name: "",
373
+ date: null,
374
+ time: "",
375
+ isScheduled: true,
376
+ scheduledAt: null,
377
+ timezone: null
378
+ };
379
+ const ReleasesPage = () => {
380
+ const tabRef = React__namespace.useRef(null);
381
+ const location = reactRouterDom.useLocation();
382
+ const [releaseModalShown, setReleaseModalShown] = React__namespace.useState(false);
383
+ const toggleNotification = helperPlugin.useNotification();
384
+ const { formatMessage } = reactIntl.useIntl();
385
+ const { push, replace } = reactRouterDom.useHistory();
386
+ const { formatAPIError } = helperPlugin.useAPIErrorHandler();
387
+ const [{ query }, setQuery] = helperPlugin.useQueryParams();
388
+ const response = index.useGetReleasesQuery(query);
389
+ const [createRelease, { isLoading: isSubmittingForm }] = index.useCreateReleaseMutation();
390
+ const { getFeature } = strapiAdmin.useLicenseLimits();
391
+ const { maximumReleases = 3 } = getFeature("cms-content-releases");
392
+ const { trackUsage } = helperPlugin.useTracking();
393
+ const { isLoading, isSuccess, isError } = response;
394
+ const activeTab = response?.currentData?.meta?.activeTab || "pending";
395
+ const activeTabIndex = ["pending", "done"].indexOf(activeTab);
396
+ React__namespace.useEffect(() => {
397
+ if (location?.state?.errors) {
398
+ toggleNotification({
399
+ type: "warning",
400
+ title: formatMessage({
401
+ id: "content-releases.pages.Releases.notification.error.title",
402
+ defaultMessage: "Your request could not be processed."
403
+ }),
404
+ message: formatMessage({
405
+ id: "content-releases.pages.Releases.notification.error.message",
406
+ defaultMessage: "Please try again or open another release."
407
+ })
408
+ });
409
+ replace({ state: null });
410
+ }
411
+ }, [formatMessage, location?.state?.errors, replace, toggleNotification]);
412
+ React__namespace.useEffect(() => {
413
+ if (tabRef.current) {
414
+ tabRef.current._handlers.setSelectedTabIndex(activeTabIndex);
415
+ }
416
+ }, [activeTabIndex]);
417
+ const toggleAddReleaseModal = () => {
418
+ setReleaseModalShown((prev) => !prev);
419
+ };
420
+ if (isLoading) {
421
+ return /* @__PURE__ */ jsxRuntime.jsx(designSystem.Main, { "aria-busy": isLoading, children: /* @__PURE__ */ jsxRuntime.jsx(helperPlugin.LoadingIndicatorPage, {}) });
422
+ }
423
+ const totalPendingReleases = isSuccess && response.currentData?.meta?.pendingReleasesCount || 0;
424
+ const hasReachedMaximumPendingReleases = totalPendingReleases >= maximumReleases;
425
+ const handleTabChange = (index2) => {
426
+ setQuery({
427
+ ...query,
428
+ page: 1,
429
+ pageSize: response?.currentData?.meta?.pagination?.pageSize || 16,
430
+ filters: {
431
+ releasedAt: {
432
+ $notNull: index2 === 0 ? false : true
433
+ }
434
+ }
435
+ });
436
+ };
437
+ const handleAddRelease = async ({ name, scheduledAt, timezone }) => {
438
+ const response2 = await createRelease({
439
+ name,
440
+ scheduledAt,
441
+ timezone
442
+ });
443
+ if ("data" in response2) {
444
+ toggleNotification({
445
+ type: "success",
446
+ message: formatMessage({
447
+ id: "content-releases.modal.release-created-notification-success",
448
+ defaultMessage: "Release created."
449
+ })
450
+ });
451
+ trackUsage("didCreateRelease");
452
+ push(`/plugins/content-releases/${response2.data.data.id}`);
453
+ } else if (index.isAxiosError(response2.error)) {
454
+ toggleNotification({
455
+ type: "warning",
456
+ message: formatAPIError(response2.error)
457
+ });
458
+ } else {
459
+ toggleNotification({
460
+ type: "warning",
461
+ message: formatMessage({ id: "notification.error", defaultMessage: "An error occurred" })
462
+ });
463
+ }
464
+ };
465
+ return /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Main, { "aria-busy": isLoading, children: [
466
+ /* @__PURE__ */ jsxRuntime.jsx(
467
+ designSystem.HeaderLayout,
468
+ {
469
+ title: formatMessage({
470
+ id: "content-releases.pages.Releases.title",
471
+ defaultMessage: "Releases"
472
+ }),
473
+ subtitle: formatMessage({
474
+ id: "content-releases.pages.Releases.header-subtitle",
475
+ defaultMessage: "Create and manage content updates"
476
+ }),
477
+ primaryAction: /* @__PURE__ */ jsxRuntime.jsx(helperPlugin.CheckPermissions, { permissions: index.PERMISSIONS.create, children: /* @__PURE__ */ jsxRuntime.jsx(
478
+ designSystem.Button,
479
+ {
480
+ startIcon: /* @__PURE__ */ jsxRuntime.jsx(icons.Plus, {}),
481
+ onClick: toggleAddReleaseModal,
482
+ disabled: hasReachedMaximumPendingReleases,
483
+ children: formatMessage({
484
+ id: "content-releases.header.actions.add-release",
485
+ defaultMessage: "New release"
486
+ })
487
+ }
488
+ ) })
489
+ }
490
+ ),
491
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.ContentLayout, { children: /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
492
+ hasReachedMaximumPendingReleases && /* @__PURE__ */ jsxRuntime.jsx(
493
+ StyledAlert,
494
+ {
495
+ marginBottom: 6,
496
+ action: /* @__PURE__ */ jsxRuntime.jsx(v2.Link, { href: "https://strapi.io/pricing-cloud", isExternal: true, children: formatMessage({
497
+ id: "content-releases.pages.Releases.max-limit-reached.action",
498
+ defaultMessage: "Explore plans"
499
+ }) }),
500
+ title: formatMessage(
501
+ {
502
+ id: "content-releases.pages.Releases.max-limit-reached.title",
503
+ defaultMessage: "You have reached the {number} pending {number, plural, one {release} other {releases}} limit."
504
+ },
505
+ { number: maximumReleases }
506
+ ),
507
+ onClose: () => {
508
+ },
509
+ closeLabel: "",
510
+ children: formatMessage({
511
+ id: "content-releases.pages.Releases.max-limit-reached.message",
512
+ defaultMessage: "Upgrade to manage an unlimited number of releases."
513
+ })
514
+ }
515
+ ),
516
+ /* @__PURE__ */ jsxRuntime.jsxs(
517
+ designSystem.TabGroup,
518
+ {
519
+ label: formatMessage({
520
+ id: "content-releases.pages.Releases.tab-group.label",
521
+ defaultMessage: "Releases list"
522
+ }),
523
+ variant: "simple",
524
+ initialSelectedTabIndex: activeTabIndex,
525
+ onTabChange: handleTabChange,
526
+ ref: tabRef,
527
+ children: [
528
+ /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Box, { paddingBottom: 8, children: [
529
+ /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Tabs, { children: [
530
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Tab, { children: formatMessage(
531
+ {
532
+ id: "content-releases.pages.Releases.tab.pending",
533
+ defaultMessage: "Pending ({count})"
534
+ },
535
+ {
536
+ count: totalPendingReleases
537
+ }
538
+ ) }),
539
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Tab, { children: formatMessage({
540
+ id: "content-releases.pages.Releases.tab.done",
541
+ defaultMessage: "Done"
542
+ }) })
543
+ ] }),
544
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Divider, {})
545
+ ] }),
546
+ /* @__PURE__ */ jsxRuntime.jsxs(designSystem.TabPanels, { children: [
547
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.TabPanel, { children: /* @__PURE__ */ jsxRuntime.jsx(
548
+ ReleasesGrid,
549
+ {
550
+ sectionTitle: "pending",
551
+ releases: response?.currentData?.data,
552
+ isError
553
+ }
554
+ ) }),
555
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.TabPanel, { children: /* @__PURE__ */ jsxRuntime.jsx(
556
+ ReleasesGrid,
557
+ {
558
+ sectionTitle: "done",
559
+ releases: response?.currentData?.data,
560
+ isError
561
+ }
562
+ ) })
563
+ ] })
564
+ ]
565
+ }
566
+ ),
567
+ response.currentData?.meta?.pagination?.total ? /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { paddingTop: 4, alignItems: "flex-end", justifyContent: "space-between", children: [
568
+ /* @__PURE__ */ jsxRuntime.jsx(
569
+ helperPlugin.PageSizeURLQuery,
570
+ {
571
+ options: ["8", "16", "32", "64"],
572
+ defaultValue: response?.currentData?.meta?.pagination?.pageSize.toString()
573
+ }
574
+ ),
575
+ /* @__PURE__ */ jsxRuntime.jsx(
576
+ helperPlugin.PaginationURLQuery,
577
+ {
578
+ pagination: {
579
+ pageCount: response?.currentData?.meta?.pagination?.pageCount || 0
580
+ }
581
+ }
582
+ )
583
+ ] }) : null
584
+ ] }) }),
585
+ releaseModalShown && /* @__PURE__ */ jsxRuntime.jsx(
586
+ ReleaseModal,
587
+ {
588
+ handleClose: toggleAddReleaseModal,
589
+ handleSubmit: handleAddRelease,
590
+ isLoading: isSubmittingForm,
591
+ initialValues: INITIAL_FORM_VALUES
592
+ }
593
+ )
594
+ ] });
595
+ };
109
596
  const ReleaseInfoWrapper = styled__default.default(designSystem.Flex)`
110
597
  align-self: stretch;
111
598
  border-bottom-right-radius: ${({ theme }) => theme.borderRadius};
112
599
  border-bottom-left-radius: ${({ theme }) => theme.borderRadius};
113
600
  border-top: 1px solid ${({ theme }) => theme.colors.neutral150};
114
601
  `;
115
- const StyledFlex = styled__default.default(designSystem.Flex)`
116
- align-self: stretch;
117
- cursor: ${({ disabled }) => disabled ? "not-allowed" : "pointer"};
118
-
602
+ const StyledMenuItem = styled__default.default(v2.Menu.Item)`
119
603
  svg path {
120
604
  fill: ${({ theme, disabled }) => disabled && theme.colors.neutral500};
121
605
  }
122
606
  span {
123
607
  color: ${({ theme, disabled }) => disabled && theme.colors.neutral500};
124
608
  }
609
+
610
+ &:hover {
611
+ background: ${({ theme, variant = "neutral" }) => theme.colors[`${variant}100`]};
612
+ }
125
613
  `;
126
614
  const PencilIcon = styled__default.default(icons.Pencil)`
127
- width: ${({ theme }) => theme.spaces[4]};
128
- height: ${({ theme }) => theme.spaces[4]};
615
+ width: ${({ theme }) => theme.spaces[3]};
616
+ height: ${({ theme }) => theme.spaces[3]};
129
617
  path {
130
618
  fill: ${({ theme }) => theme.colors.neutral600};
131
619
  }
132
620
  `;
133
621
  const TrashIcon = styled__default.default(icons.Trash)`
134
- width: ${({ theme }) => theme.spaces[4]};
135
- height: ${({ theme }) => theme.spaces[4]};
622
+ width: ${({ theme }) => theme.spaces[3]};
623
+ height: ${({ theme }) => theme.spaces[3]};
136
624
  path {
137
625
  fill: ${({ theme }) => theme.colors.danger600};
138
626
  }
139
627
  `;
140
- const PopoverButton = ({ onClick, disabled, children }) => {
141
- return /* @__PURE__ */ jsxRuntime.jsx(
142
- StyledFlex,
143
- {
144
- paddingTop: 2,
145
- paddingBottom: 2,
146
- paddingLeft: 4,
147
- paddingRight: 4,
148
- alignItems: "center",
149
- gap: 2,
150
- as: "button",
151
- hasRadius: true,
152
- onClick,
153
- disabled,
154
- children
155
- }
156
- );
157
- };
158
- const EntryValidationText = ({ status, action }) => {
628
+ const TypographyMaxWidth = styled__default.default(designSystem.Typography)`
629
+ max-width: 300px;
630
+ `;
631
+ const EntryValidationText = ({ action, schema, components, entry }) => {
159
632
  const { formatMessage } = reactIntl.useIntl();
633
+ const { validate } = strapiAdmin.unstable_useDocument();
634
+ const { errors } = validate(entry, {
635
+ contentType: schema,
636
+ components,
637
+ isCreatingEntry: false
638
+ });
639
+ if (Object.keys(errors).length > 0) {
640
+ const validationErrorsMessages = Object.entries(errors).map(
641
+ ([key, value]) => formatMessage(
642
+ { id: `${value.id}.withField`, defaultMessage: value.defaultMessage },
643
+ { field: key }
644
+ )
645
+ ).join(" ");
646
+ return /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { gap: 2, children: [
647
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Icon, { color: "danger600", as: icons.CrossCircle }),
648
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Tooltip, { description: validationErrorsMessages, children: /* @__PURE__ */ jsxRuntime.jsx(TypographyMaxWidth, { textColor: "danger600", variant: "omega", fontWeight: "semiBold", ellipsis: true, children: validationErrorsMessages }) })
649
+ ] });
650
+ }
160
651
  if (action == "publish") {
161
652
  return /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { gap: 2, children: [
162
653
  /* @__PURE__ */ jsxRuntime.jsx(designSystem.Icon, { color: "success600", as: icons.CheckCircle }),
163
- status === "published" ? /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { textColor: "success600", fontWeight: "bold", children: formatMessage({
654
+ entry.publishedAt ? /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { textColor: "success600", fontWeight: "bold", children: formatMessage({
164
655
  id: "content-releases.pages.ReleaseDetails.entry-validation.already-published",
165
656
  defaultMessage: "Already published"
166
657
  }) }) : /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { children: formatMessage({
@@ -171,7 +662,7 @@ const EntryValidationText = ({ status, action }) => {
171
662
  }
172
663
  return /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { gap: 2, children: [
173
664
  /* @__PURE__ */ jsxRuntime.jsx(designSystem.Icon, { color: "success600", as: icons.CheckCircle }),
174
- status === "draft" ? /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { textColor: "success600", fontWeight: "bold", children: formatMessage({
665
+ !entry.publishedAt ? /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { textColor: "success600", fontWeight: "bold", children: formatMessage({
175
666
  id: "content-releases.pages.ReleaseDetails.entry-validation.already-unpublished",
176
667
  defaultMessage: "Already unpublished"
177
668
  }) }) : /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { children: formatMessage({
@@ -185,10 +676,8 @@ const ReleaseDetailsLayout = ({
185
676
  toggleWarningSubmit,
186
677
  children
187
678
  }) => {
188
- const { formatMessage } = reactIntl.useIntl();
679
+ const { formatMessage, formatDate, formatTime } = reactIntl.useIntl();
189
680
  const { releaseId } = reactRouterDom.useParams();
190
- const [isPopoverVisible, setIsPopoverVisible] = React__namespace.useState(false);
191
- const moreButtonRef = React__namespace.useRef(null);
192
681
  const {
193
682
  data,
194
683
  isLoading: isLoadingDetails,
@@ -200,15 +689,10 @@ const ReleaseDetailsLayout = ({
200
689
  const { formatAPIError } = helperPlugin.useAPIErrorHandler();
201
690
  const {
202
691
  allowedActions: { canUpdate, canDelete }
203
- } = helperPlugin.useRBAC(index.PERMISSIONS);
204
- const release = data?.data;
205
- const handleTogglePopover = () => {
206
- setIsPopoverVisible((prev) => !prev);
207
- };
208
- const openReleaseModal = () => {
209
- toggleEditReleaseModal();
210
- handleTogglePopover();
211
- };
692
+ } = helperPlugin.useRBAC(index.PERMISSIONS);
693
+ const dispatch = index.useTypedDispatch();
694
+ const { trackUsage } = helperPlugin.useTracking();
695
+ const release = data?.data;
212
696
  const handlePublishRelease = async () => {
213
697
  const response = await publishRelease({ id: releaseId });
214
698
  if ("data" in response) {
@@ -219,6 +703,12 @@ const ReleaseDetailsLayout = ({
219
703
  defaultMessage: "Release was published successfully."
220
704
  })
221
705
  });
706
+ const { totalEntries: totalEntries2, totalPublishedEntries, totalUnpublishedEntries } = response.data.meta;
707
+ trackUsage("didPublishRelease", {
708
+ totalEntries: totalEntries2,
709
+ totalPublishedEntries,
710
+ totalUnpublishedEntries
711
+ });
222
712
  } else if (index.isAxiosError(response.error)) {
223
713
  toggleNotification({
224
714
  type: "warning",
@@ -231,9 +721,25 @@ const ReleaseDetailsLayout = ({
231
721
  });
232
722
  }
233
723
  };
234
- const openWarningConfirmDialog = () => {
235
- toggleWarningSubmit();
236
- handleTogglePopover();
724
+ const handleRefresh = () => {
725
+ dispatch(
726
+ index.releaseApi.util.invalidateTags([
727
+ { type: "ReleaseAction", id: "LIST" },
728
+ { type: "Release", id: releaseId }
729
+ ])
730
+ );
731
+ };
732
+ const getCreatedByUser = () => {
733
+ if (!release?.createdBy) {
734
+ return null;
735
+ }
736
+ if (release.createdBy.username) {
737
+ return release.createdBy.username;
738
+ }
739
+ if (release.createdBy.firstname) {
740
+ return `${release.createdBy.firstname} ${release.createdBy.lastname || ""}`.trim();
741
+ }
742
+ return release.createdBy.email;
237
743
  };
238
744
  if (isLoadingDetails) {
239
745
  return /* @__PURE__ */ jsxRuntime.jsx(designSystem.Main, { "aria-busy": isLoadingDetails, children: /* @__PURE__ */ jsxRuntime.jsx(helperPlugin.LoadingIndicatorPage, {}) });
@@ -256,90 +762,131 @@ const ReleaseDetailsLayout = ({
256
762
  );
257
763
  }
258
764
  const totalEntries = release.actions.meta.count || 0;
259
- const createdBy = release.createdBy.lastname ? `${release.createdBy.firstname} ${release.createdBy.lastname}` : `${release.createdBy.firstname}`;
765
+ const hasCreatedByUser = Boolean(getCreatedByUser());
766
+ const isScheduled = release.scheduledAt && release.timezone;
767
+ const numberOfEntriesText = formatMessage(
768
+ {
769
+ id: "content-releases.pages.Details.header-subtitle",
770
+ defaultMessage: "{number, plural, =0 {No entries} one {# entry} other {# entries}}"
771
+ },
772
+ { number: totalEntries }
773
+ );
774
+ const scheduledText = isScheduled ? formatMessage(
775
+ {
776
+ id: "content-releases.pages.ReleaseDetails.header-subtitle.scheduled",
777
+ defaultMessage: "Scheduled for {date} at {time} ({offset})"
778
+ },
779
+ {
780
+ date: formatDate(new Date(release.scheduledAt), {
781
+ weekday: "long",
782
+ day: "numeric",
783
+ month: "long",
784
+ year: "numeric",
785
+ timeZone: release.timezone
786
+ }),
787
+ time: formatTime(new Date(release.scheduledAt), {
788
+ timeZone: release.timezone,
789
+ hourCycle: "h23"
790
+ }),
791
+ offset: index.getTimezoneOffset(release.timezone, new Date(release.scheduledAt))
792
+ }
793
+ ) : "";
260
794
  return /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Main, { "aria-busy": isLoadingDetails, children: [
261
795
  /* @__PURE__ */ jsxRuntime.jsx(
262
796
  designSystem.HeaderLayout,
263
797
  {
264
798
  title: release.name,
265
- subtitle: formatMessage(
266
- {
267
- id: "content-releases.pages.Details.header-subtitle",
268
- defaultMessage: "{number, plural, =0 {No entries} one {# entry} other {# entries}}"
269
- },
270
- { number: totalEntries }
271
- ),
799
+ subtitle: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { gap: 2, lineHeight: 6, children: [
800
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { textColor: "neutral600", variant: "epsilon", children: numberOfEntriesText + (isScheduled ? ` - ${scheduledText}` : "") }),
801
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Badge, { ...getBadgeProps(release.status), children: release.status })
802
+ ] }),
272
803
  navigationAction: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Link, { startIcon: /* @__PURE__ */ jsxRuntime.jsx(icons.ArrowLeft, {}), to: "/plugins/content-releases", children: formatMessage({
273
804
  id: "global.back",
274
805
  defaultMessage: "Back"
275
806
  }) }),
276
807
  primaryAction: !release.releasedAt && /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { gap: 2, children: [
277
- /* @__PURE__ */ jsxRuntime.jsx(
278
- designSystem.IconButton,
279
- {
280
- label: formatMessage({
281
- id: "content-releases.header.actions.open-release-actions",
282
- defaultMessage: "Release actions"
283
- }),
284
- ref: moreButtonRef,
285
- onClick: handleTogglePopover,
286
- children: /* @__PURE__ */ jsxRuntime.jsx(icons.More, {})
287
- }
288
- ),
289
- isPopoverVisible && /* @__PURE__ */ jsxRuntime.jsxs(
290
- designSystem.Popover,
291
- {
292
- source: moreButtonRef,
293
- placement: "bottom-end",
294
- onDismiss: handleTogglePopover,
295
- spacing: 4,
296
- minWidth: "242px",
297
- children: [
298
- /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { alignItems: "center", justifyContent: "center", direction: "column", padding: 1, children: [
299
- /* @__PURE__ */ jsxRuntime.jsxs(PopoverButton, { disabled: !canUpdate, onClick: openReleaseModal, children: [
300
- /* @__PURE__ */ jsxRuntime.jsx(PencilIcon, {}),
301
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { ellipsis: true, children: formatMessage({
302
- id: "content-releases.header.actions.edit",
303
- defaultMessage: "Edit"
304
- }) })
305
- ] }),
306
- /* @__PURE__ */ jsxRuntime.jsxs(PopoverButton, { disabled: !canDelete, onClick: openWarningConfirmDialog, children: [
307
- /* @__PURE__ */ jsxRuntime.jsx(TrashIcon, {}),
308
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { ellipsis: true, textColor: "danger600", children: formatMessage({
309
- id: "content-releases.header.actions.delete",
310
- defaultMessage: "Delete"
311
- }) })
312
- ] })
313
- ] }),
314
- /* @__PURE__ */ jsxRuntime.jsxs(
315
- ReleaseInfoWrapper,
316
- {
317
- direction: "column",
318
- justifyContent: "center",
319
- alignItems: "flex-start",
320
- gap: 1,
321
- padding: 5,
322
- children: [
323
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "pi", fontWeight: "bold", children: formatMessage({
324
- id: "content-releases.header.actions.created",
325
- defaultMessage: "Created"
326
- }) }),
327
- /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Typography, { variant: "pi", color: "neutral300", children: [
328
- /* @__PURE__ */ jsxRuntime.jsx(helperPlugin.RelativeTime, { timestamp: new Date(release.createdAt) }),
329
- formatMessage(
330
- {
331
- id: "content-releases.header.actions.created.description",
332
- defaultMessage: " by {createdBy}"
333
- },
334
- { createdBy }
335
- )
336
- ] })
337
- ]
338
- }
339
- )
340
- ]
341
- }
342
- ),
808
+ /* @__PURE__ */ jsxRuntime.jsxs(v2.Menu.Root, { children: [
809
+ /* @__PURE__ */ jsxRuntime.jsx(
810
+ v2.Menu.Trigger,
811
+ {
812
+ as: designSystem.IconButton,
813
+ paddingLeft: 2,
814
+ paddingRight: 2,
815
+ "aria-label": formatMessage({
816
+ id: "content-releases.header.actions.open-release-actions",
817
+ defaultMessage: "Release edit and delete menu"
818
+ }),
819
+ icon: /* @__PURE__ */ jsxRuntime.jsx(icons.More, {}),
820
+ variant: "tertiary"
821
+ }
822
+ ),
823
+ /* @__PURE__ */ jsxRuntime.jsxs(v2.Menu.Content, { top: 1, popoverPlacement: "bottom-end", children: [
824
+ /* @__PURE__ */ jsxRuntime.jsxs(
825
+ designSystem.Flex,
826
+ {
827
+ alignItems: "center",
828
+ justifyContent: "center",
829
+ direction: "column",
830
+ padding: 1,
831
+ width: "100%",
832
+ children: [
833
+ /* @__PURE__ */ jsxRuntime.jsx(StyledMenuItem, { disabled: !canUpdate, onSelect: toggleEditReleaseModal, children: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { alignItems: "center", gap: 2, hasRadius: true, width: "100%", children: [
834
+ /* @__PURE__ */ jsxRuntime.jsx(PencilIcon, {}),
835
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { ellipsis: true, children: formatMessage({
836
+ id: "content-releases.header.actions.edit",
837
+ defaultMessage: "Edit"
838
+ }) })
839
+ ] }) }),
840
+ /* @__PURE__ */ jsxRuntime.jsx(
841
+ StyledMenuItem,
842
+ {
843
+ disabled: !canDelete,
844
+ onSelect: toggleWarningSubmit,
845
+ variant: "danger",
846
+ children: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { alignItems: "center", gap: 2, hasRadius: true, width: "100%", children: [
847
+ /* @__PURE__ */ jsxRuntime.jsx(TrashIcon, {}),
848
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { ellipsis: true, textColor: "danger600", children: formatMessage({
849
+ id: "content-releases.header.actions.delete",
850
+ defaultMessage: "Delete"
851
+ }) })
852
+ ] })
853
+ }
854
+ )
855
+ ]
856
+ }
857
+ ),
858
+ /* @__PURE__ */ jsxRuntime.jsxs(
859
+ ReleaseInfoWrapper,
860
+ {
861
+ direction: "column",
862
+ justifyContent: "center",
863
+ alignItems: "flex-start",
864
+ gap: 1,
865
+ padding: 5,
866
+ children: [
867
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "pi", fontWeight: "bold", children: formatMessage({
868
+ id: "content-releases.header.actions.created",
869
+ defaultMessage: "Created"
870
+ }) }),
871
+ /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Typography, { variant: "pi", color: "neutral300", children: [
872
+ /* @__PURE__ */ jsxRuntime.jsx(helperPlugin.RelativeTime, { timestamp: new Date(release.createdAt) }),
873
+ formatMessage(
874
+ {
875
+ id: "content-releases.header.actions.created.description",
876
+ defaultMessage: "{hasCreatedByUser, select, true { by {createdBy}} other { by deleted user}}"
877
+ },
878
+ { createdBy: getCreatedByUser(), hasCreatedByUser }
879
+ )
880
+ ] })
881
+ ]
882
+ }
883
+ )
884
+ ] })
885
+ ] }),
886
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Button, { size: "S", variant: "tertiary", onClick: handleRefresh, children: formatMessage({
887
+ id: "content-releases.header.actions.refresh",
888
+ defaultMessage: "Refresh"
889
+ }) }),
343
890
  /* @__PURE__ */ jsxRuntime.jsx(helperPlugin.CheckPermissions, { permissions: index.PERMISSIONS.publish, children: /* @__PURE__ */ jsxRuntime.jsx(
344
891
  designSystem.Button,
345
892
  {
@@ -391,6 +938,9 @@ const ReleaseDetailsBody = () => {
391
938
  isError: isReleaseError,
392
939
  error: releaseError
393
940
  } = index.useGetReleaseQuery({ id: releaseId });
941
+ const {
942
+ allowedActions: { canUpdate }
943
+ } = helperPlugin.useRBAC(index.PERMISSIONS);
394
944
  const release = releaseData?.data;
395
945
  const selectedGroupBy = query?.groupBy || "contentType";
396
946
  const {
@@ -404,7 +954,7 @@ const ReleaseDetailsBody = () => {
404
954
  releaseId
405
955
  });
406
956
  const [updateReleaseAction] = index.useUpdateReleaseActionMutation();
407
- const handleChangeType = async (e, actionId) => {
957
+ const handleChangeType = async (e, actionId, actionPath) => {
408
958
  const response = await updateReleaseAction({
409
959
  params: {
410
960
  releaseId,
@@ -412,7 +962,11 @@ const ReleaseDetailsBody = () => {
412
962
  },
413
963
  body: {
414
964
  type: e.target.value
415
- }
965
+ },
966
+ query,
967
+ // We are passing the query params to make optimistic updates
968
+ actionPath
969
+ // We are passing the action path to found the position in the cache of the action for optimistic updates
416
970
  });
417
971
  if ("error" in response) {
418
972
  if (index.isAxiosError(response.error)) {
@@ -433,7 +987,9 @@ const ReleaseDetailsBody = () => {
433
987
  }
434
988
  const releaseActions = data?.data;
435
989
  const releaseMeta = data?.meta;
436
- if (isError || isReleaseError || !release || !releaseActions) {
990
+ const contentTypes = releaseMeta?.contentTypes || {};
991
+ const components = releaseMeta?.components || {};
992
+ if (isReleaseError || !release) {
437
993
  const errorsArray = [];
438
994
  if (releaseError) {
439
995
  errorsArray.push({
@@ -457,6 +1013,9 @@ const ReleaseDetailsBody = () => {
457
1013
  }
458
1014
  );
459
1015
  }
1016
+ if (isError || !releaseActions) {
1017
+ return /* @__PURE__ */ jsxRuntime.jsx(designSystem.ContentLayout, { children: /* @__PURE__ */ jsxRuntime.jsx(helperPlugin.AnErrorOccurred, {}) });
1018
+ }
460
1019
  if (Object.keys(releaseActions).length === 0) {
461
1020
  return /* @__PURE__ */ jsxRuntime.jsx(designSystem.ContentLayout, { children: /* @__PURE__ */ jsxRuntime.jsx(
462
1021
  helperPlugin.NoContent,
@@ -488,7 +1047,7 @@ const ReleaseDetailsBody = () => {
488
1047
  designSystem.SingleSelect,
489
1048
  {
490
1049
  "aria-label": formatMessage({
491
- id: "content-releases.pages.ReleaseDetails.groupBy.label",
1050
+ id: "content-releases.pages.ReleaseDetails.groupBy.aria-label",
492
1051
  defaultMessage: "Group by"
493
1052
  }),
494
1053
  customizeContent: (value) => formatMessage(
@@ -506,7 +1065,7 @@ const ReleaseDetailsBody = () => {
506
1065
  }
507
1066
  ) }),
508
1067
  Object.keys(releaseActions).map((key) => /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { gap: 4, direction: "column", alignItems: "stretch", children: [
509
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Flex, { children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Badge, { children: key }) }),
1068
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Flex, { role: "separator", "aria-label": key, children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Badge, { children: key }) }),
510
1069
  /* @__PURE__ */ jsxRuntime.jsx(
511
1070
  helperPlugin.Table.Root,
512
1071
  {
@@ -576,30 +1135,59 @@ const ReleaseDetailsBody = () => {
576
1135
  )
577
1136
  ] }),
578
1137
  /* @__PURE__ */ jsxRuntime.jsx(helperPlugin.Table.LoadingBody, {}),
579
- /* @__PURE__ */ jsxRuntime.jsx(helperPlugin.Table.Body, { children: releaseActions[key].map(({ id, type, entry }) => /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Tr, { children: [
580
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Td, { width: "25%", children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { ellipsis: true, children: `${entry.contentType.mainFieldValue || entry.id}` }) }),
581
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Td, { children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { children: `${entry?.locale?.name ? entry.locale.name : "-"}` }) }),
582
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Td, { children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { children: entry.contentType.displayName || "" }) }),
583
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Td, { children: release.releasedAt ? /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { children: formatMessage(
584
- {
585
- id: "content-releases.page.ReleaseDetails.table.action-published",
586
- defaultMessage: "This entry was <b>{isPublish, select, true {published} other {unpublished}}</b>."
587
- },
588
- {
589
- isPublish: type === "publish",
590
- b: (children) => /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { fontWeight: "bold", children })
591
- }
592
- ) }) : /* @__PURE__ */ jsxRuntime.jsx(
593
- index.ReleaseActionOptions,
594
- {
595
- selected: type,
596
- handleChange: (e) => handleChangeType(e, id),
597
- name: `release-action-${id}-type`
598
- }
599
- ) }),
600
- !release.releasedAt && /* @__PURE__ */ jsxRuntime.jsx(designSystem.Td, { children: /* @__PURE__ */ jsxRuntime.jsx(EntryValidationText, { status: entry.status, action: type }) }),
601
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Td, { children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Flex, { justifyContent: "flex-end", children: /* @__PURE__ */ jsxRuntime.jsx(index.ReleaseActionMenu, { releaseId, actionId: id }) }) })
602
- ] }, id)) })
1138
+ /* @__PURE__ */ jsxRuntime.jsx(helperPlugin.Table.Body, { children: releaseActions[key].map(
1139
+ ({ id, contentType, locale, type, entry }, actionIndex) => /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Tr, { children: [
1140
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Td, { width: "25%", maxWidth: "200px", children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { ellipsis: true, children: `${contentType.mainFieldValue || entry.id}` }) }),
1141
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Td, { width: "10%", children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { children: `${locale?.name ? locale.name : "-"}` }) }),
1142
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Td, { width: "10%", children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { children: contentType.displayName || "" }) }),
1143
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Td, { width: "20%", children: release.releasedAt ? /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { children: formatMessage(
1144
+ {
1145
+ id: "content-releases.page.ReleaseDetails.table.action-published",
1146
+ defaultMessage: "This entry was <b>{isPublish, select, true {published} other {unpublished}}</b>."
1147
+ },
1148
+ {
1149
+ isPublish: type === "publish",
1150
+ b: (children) => /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { fontWeight: "bold", children })
1151
+ }
1152
+ ) }) : /* @__PURE__ */ jsxRuntime.jsx(
1153
+ index.ReleaseActionOptions,
1154
+ {
1155
+ selected: type,
1156
+ handleChange: (e) => handleChangeType(e, id, [key, actionIndex]),
1157
+ name: `release-action-${id}-type`,
1158
+ disabled: !canUpdate
1159
+ }
1160
+ ) }),
1161
+ !release.releasedAt && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
1162
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Td, { width: "20%", minWidth: "200px", children: /* @__PURE__ */ jsxRuntime.jsx(
1163
+ EntryValidationText,
1164
+ {
1165
+ action: type,
1166
+ schema: contentTypes?.[contentType.uid],
1167
+ components,
1168
+ entry
1169
+ }
1170
+ ) }),
1171
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Td, { children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Flex, { justifyContent: "flex-end", children: /* @__PURE__ */ jsxRuntime.jsxs(index.ReleaseActionMenu.Root, { children: [
1172
+ /* @__PURE__ */ jsxRuntime.jsx(
1173
+ index.ReleaseActionMenu.ReleaseActionEntryLinkItem,
1174
+ {
1175
+ contentTypeUid: contentType.uid,
1176
+ entryId: entry.id,
1177
+ locale: locale?.code
1178
+ }
1179
+ ),
1180
+ /* @__PURE__ */ jsxRuntime.jsx(
1181
+ index.ReleaseActionMenu.DeleteReleaseActionItem,
1182
+ {
1183
+ releaseId: release.id,
1184
+ actionId: id
1185
+ }
1186
+ )
1187
+ ] }) }) })
1188
+ ] })
1189
+ ] }, id)
1190
+ ) })
603
1191
  ] })
604
1192
  }
605
1193
  )
@@ -622,7 +1210,7 @@ const ReleaseDetailsPage = () => {
622
1210
  const { releaseId } = reactRouterDom.useParams();
623
1211
  const toggleNotification = helperPlugin.useNotification();
624
1212
  const { formatAPIError } = helperPlugin.useAPIErrorHandler();
625
- const { push } = reactRouterDom.useHistory();
1213
+ const { replace } = reactRouterDom.useHistory();
626
1214
  const [releaseModalShown, setReleaseModalShown] = React__namespace.useState(false);
627
1215
  const [showWarningSubmit, setWarningSubmit] = React__namespace.useState(false);
628
1216
  const {
@@ -646,11 +1234,18 @@ const ReleaseDetailsPage = () => {
646
1234
  }
647
1235
  );
648
1236
  }
649
- const title = isSuccessDetails && data?.data?.name || "";
1237
+ const releaseData = isSuccessDetails && data?.data || null;
1238
+ const title = releaseData?.name || "";
1239
+ const timezone = releaseData?.timezone ?? null;
1240
+ const scheduledAt = releaseData?.scheduledAt && timezone ? dateFnsTz.utcToZonedTime(releaseData.scheduledAt, timezone) : null;
1241
+ const date = scheduledAt ? new Date(format__default.default(scheduledAt, "yyyy-MM-dd")) : null;
1242
+ const time = scheduledAt ? format__default.default(scheduledAt, "HH:mm") : "";
650
1243
  const handleEditRelease = async (values) => {
651
1244
  const response = await updateRelease({
652
1245
  id: releaseId,
653
- name: values.name
1246
+ name: values.name,
1247
+ scheduledAt: values.scheduledAt,
1248
+ timezone: values.timezone
654
1249
  });
655
1250
  if ("data" in response) {
656
1251
  toggleNotification({
@@ -678,7 +1273,7 @@ const ReleaseDetailsPage = () => {
678
1273
  id: releaseId
679
1274
  });
680
1275
  if ("data" in response) {
681
- push("/plugins/content-releases");
1276
+ replace("/plugins/content-releases");
682
1277
  } else if (index.isAxiosError(response.error)) {
683
1278
  toggleNotification({
684
1279
  type: "warning",
@@ -704,7 +1299,14 @@ const ReleaseDetailsPage = () => {
704
1299
  handleClose: toggleEditReleaseModal,
705
1300
  handleSubmit: handleEditRelease,
706
1301
  isLoading: isLoadingDetails || isSubmittingForm,
707
- initialValues: { name: title || "" }
1302
+ initialValues: {
1303
+ name: title || "",
1304
+ scheduledAt,
1305
+ date,
1306
+ time,
1307
+ isScheduled: Boolean(scheduledAt),
1308
+ timezone
1309
+ }
708
1310
  }
709
1311
  ),
710
1312
  /* @__PURE__ */ jsxRuntime.jsx(
@@ -724,239 +1326,6 @@ const ReleaseDetailsPage = () => {
724
1326
  }
725
1327
  );
726
1328
  };
727
- const ReleasesLayout = ({
728
- isLoading,
729
- totalReleases,
730
- onClickAddRelease,
731
- children
732
- }) => {
733
- const { formatMessage } = reactIntl.useIntl();
734
- return /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Main, { "aria-busy": isLoading, children: [
735
- /* @__PURE__ */ jsxRuntime.jsx(
736
- designSystem.HeaderLayout,
737
- {
738
- title: formatMessage({
739
- id: "content-releases.pages.Releases.title",
740
- defaultMessage: "Releases"
741
- }),
742
- subtitle: !isLoading && formatMessage(
743
- {
744
- id: "content-releases.pages.Releases.header-subtitle",
745
- defaultMessage: "{number, plural, =0 {No releases} one {# release} other {# releases}}"
746
- },
747
- { number: totalReleases }
748
- ),
749
- primaryAction: /* @__PURE__ */ jsxRuntime.jsx(helperPlugin.CheckPermissions, { permissions: index.PERMISSIONS.create, children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Button, { startIcon: /* @__PURE__ */ jsxRuntime.jsx(icons.Plus, {}), onClick: onClickAddRelease, children: formatMessage({
750
- id: "content-releases.header.actions.add-release",
751
- defaultMessage: "New release"
752
- }) }) })
753
- }
754
- ),
755
- children
756
- ] });
757
- };
758
- const LinkCard = styled__default.default(v2.Link)`
759
- display: block;
760
- `;
761
- const ReleasesGrid = ({ sectionTitle, releases = [], isError = false }) => {
762
- const { formatMessage } = reactIntl.useIntl();
763
- if (isError) {
764
- return /* @__PURE__ */ jsxRuntime.jsx(helperPlugin.AnErrorOccurred, {});
765
- }
766
- if (releases?.length === 0) {
767
- return /* @__PURE__ */ jsxRuntime.jsx(
768
- designSystem.EmptyStateLayout,
769
- {
770
- content: formatMessage(
771
- {
772
- id: "content-releases.page.Releases.tab.emptyEntries",
773
- defaultMessage: "No releases"
774
- },
775
- {
776
- target: sectionTitle
777
- }
778
- ),
779
- icon: /* @__PURE__ */ jsxRuntime.jsx(icons.EmptyDocuments, { width: "10rem" })
780
- }
781
- );
782
- }
783
- 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(
784
- designSystem.Flex,
785
- {
786
- direction: "column",
787
- justifyContent: "space-between",
788
- padding: 4,
789
- hasRadius: true,
790
- background: "neutral0",
791
- shadow: "tableShadow",
792
- height: "100%",
793
- width: "100%",
794
- alignItems: "start",
795
- gap: 2,
796
- children: [
797
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { as: "h3", variant: "delta", fontWeight: "bold", children: name }),
798
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "pi", children: formatMessage(
799
- {
800
- id: "content-releases.page.Releases.release-item.entries",
801
- defaultMessage: "{number, plural, =0 {No entries} one {# entry} other {# entries}}"
802
- },
803
- { number: actions.meta.count }
804
- ) })
805
- ]
806
- }
807
- ) }) }, id)) });
808
- };
809
- const INITIAL_FORM_VALUES = {
810
- name: ""
811
- };
812
- const ReleasesPage = () => {
813
- const location = reactRouterDom.useLocation();
814
- const [releaseModalShown, setReleaseModalShown] = React__namespace.useState(false);
815
- const toggleNotification = helperPlugin.useNotification();
816
- const { formatMessage } = reactIntl.useIntl();
817
- const { push, replace } = reactRouterDom.useHistory();
818
- const { formatAPIError } = helperPlugin.useAPIErrorHandler();
819
- const [{ query }, setQuery] = helperPlugin.useQueryParams();
820
- const response = index.useGetReleasesQuery(query);
821
- const [createRelease, { isLoading: isSubmittingForm }] = index.useCreateReleaseMutation();
822
- const { isLoading, isSuccess, isError } = response;
823
- React__namespace.useEffect(() => {
824
- if (location?.state?.errors) {
825
- toggleNotification({
826
- type: "warning",
827
- title: formatMessage({
828
- id: "content-releases.pages.Releases.notification.error.title",
829
- defaultMessage: "Your request could not be processed."
830
- }),
831
- message: formatMessage({
832
- id: "content-releases.pages.Releases.notification.error.message",
833
- defaultMessage: "Please try again or open another release."
834
- })
835
- });
836
- replace({ state: null });
837
- }
838
- }, [formatMessage, location?.state?.errors, replace, toggleNotification]);
839
- const toggleAddReleaseModal = () => {
840
- setReleaseModalShown((prev) => !prev);
841
- };
842
- if (isLoading) {
843
- return /* @__PURE__ */ jsxRuntime.jsx(ReleasesLayout, { onClickAddRelease: toggleAddReleaseModal, isLoading: true, children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.ContentLayout, { children: /* @__PURE__ */ jsxRuntime.jsx(helperPlugin.LoadingIndicatorPage, {}) }) });
844
- }
845
- const totalReleases = isSuccess && response.currentData?.meta?.pagination?.total || 0;
846
- const handleTabChange = (index2) => {
847
- setQuery({
848
- ...query,
849
- page: 1,
850
- pageSize: response?.currentData?.meta?.pagination?.pageSize || 16,
851
- filters: {
852
- releasedAt: {
853
- $notNull: index2 === 0 ? false : true
854
- }
855
- }
856
- });
857
- };
858
- const activeTab = response?.currentData?.meta?.activeTab || "pending";
859
- const handleAddRelease = async (values) => {
860
- const response2 = await createRelease({
861
- name: values.name
862
- });
863
- if ("data" in response2) {
864
- toggleNotification({
865
- type: "success",
866
- message: formatMessage({
867
- id: "content-releases.modal.release-created-notification-success",
868
- defaultMessage: "Release created."
869
- })
870
- });
871
- push(`/plugins/content-releases/${response2.data.data.id}`);
872
- } else if (index.isAxiosError(response2.error)) {
873
- toggleNotification({
874
- type: "warning",
875
- message: formatAPIError(response2.error)
876
- });
877
- } else {
878
- toggleNotification({
879
- type: "warning",
880
- message: formatMessage({ id: "notification.error", defaultMessage: "An error occurred" })
881
- });
882
- }
883
- };
884
- return /* @__PURE__ */ jsxRuntime.jsxs(ReleasesLayout, { onClickAddRelease: toggleAddReleaseModal, totalReleases, children: [
885
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.ContentLayout, { children: /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
886
- /* @__PURE__ */ jsxRuntime.jsxs(
887
- designSystem.TabGroup,
888
- {
889
- label: formatMessage({
890
- id: "content-releases.pages.Releases.tab-group.label",
891
- defaultMessage: "Releases list"
892
- }),
893
- variant: "simple",
894
- initialSelectedTabIndex: ["pending", "done"].indexOf(activeTab),
895
- onTabChange: handleTabChange,
896
- children: [
897
- /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Box, { paddingBottom: 8, children: [
898
- /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Tabs, { children: [
899
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Tab, { children: formatMessage({
900
- id: "content-releases.pages.Releases.tab.pending",
901
- defaultMessage: "Pending"
902
- }) }),
903
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Tab, { children: formatMessage({
904
- id: "content-releases.pages.Releases.tab.done",
905
- defaultMessage: "Done"
906
- }) })
907
- ] }),
908
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Divider, {})
909
- ] }),
910
- /* @__PURE__ */ jsxRuntime.jsxs(designSystem.TabPanels, { children: [
911
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.TabPanel, { children: /* @__PURE__ */ jsxRuntime.jsx(
912
- ReleasesGrid,
913
- {
914
- sectionTitle: "pending",
915
- releases: response?.currentData?.data,
916
- isError
917
- }
918
- ) }),
919
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.TabPanel, { children: /* @__PURE__ */ jsxRuntime.jsx(
920
- ReleasesGrid,
921
- {
922
- sectionTitle: "done",
923
- releases: response?.currentData?.data,
924
- isError
925
- }
926
- ) })
927
- ] })
928
- ]
929
- }
930
- ),
931
- totalReleases > 0 && /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { paddingTop: 4, alignItems: "flex-end", justifyContent: "space-between", children: [
932
- /* @__PURE__ */ jsxRuntime.jsx(
933
- helperPlugin.PageSizeURLQuery,
934
- {
935
- options: ["8", "16", "32", "64"],
936
- defaultValue: response?.currentData?.meta?.pagination?.pageSize.toString()
937
- }
938
- ),
939
- /* @__PURE__ */ jsxRuntime.jsx(
940
- helperPlugin.PaginationURLQuery,
941
- {
942
- pagination: {
943
- pageCount: response?.currentData?.meta?.pagination?.pageCount || 0
944
- }
945
- }
946
- )
947
- ] })
948
- ] }) }),
949
- releaseModalShown && /* @__PURE__ */ jsxRuntime.jsx(
950
- ReleaseModal,
951
- {
952
- handleClose: toggleAddReleaseModal,
953
- handleSubmit: handleAddRelease,
954
- isLoading: isSubmittingForm,
955
- initialValues: INITIAL_FORM_VALUES
956
- }
957
- )
958
- ] });
959
- };
960
1329
  const App = () => {
961
1330
  return /* @__PURE__ */ jsxRuntime.jsx(helperPlugin.CheckPagePermissions, { permissions: index.PERMISSIONS.main, children: /* @__PURE__ */ jsxRuntime.jsxs(reactRouterDom.Switch, { children: [
962
1331
  /* @__PURE__ */ jsxRuntime.jsx(reactRouterDom.Route, { exact: true, path: `/plugins/${index.pluginId}`, component: ReleasesPage }),
@@ -964,4 +1333,4 @@ const App = () => {
964
1333
  ] }) });
965
1334
  };
966
1335
  exports.App = App;
967
- //# sourceMappingURL=App-8384e404.js.map
1336
+ //# sourceMappingURL=App-l62gIUTX.js.map