@strapi/content-releases 0.0.0-experimental.e1ede8c55a0e1e22ce20137bf238fc374bd5dd51 → 0.0.0-experimental.e47108ccbbc4ad1bfaf4526fa6b70d6ace1ca7a9

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