@strapi/content-releases 0.0.0-next.e1ede8c55a0e1e22ce20137bf238fc374bd5dd51 → 0.0.0-next.e6eaa3d0563c85f80fd88b258df70a55c057096e

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-R-kksTW7.mjs +1308 -0
  2. package/dist/_chunks/App-R-kksTW7.mjs.map +1 -0
  3. package/dist/_chunks/{App-o5_WfqR-.js → App-WZHc_d3m.js} +783 -419
  4. package/dist/_chunks/App-WZHc_d3m.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-ngTk74JV.mjs → en-RdapH-9X.mjs} +22 -7
  10. package/dist/_chunks/en-RdapH-9X.mjs.map +1 -0
  11. package/dist/_chunks/{en-haKSQIo8.js → en-faJDuv3q.js} +22 -7
  12. package/dist/_chunks/en-faJDuv3q.js.map +1 -0
  13. package/dist/_chunks/{index-EdBmRHRU.js → index-k6fw6RYi.js} +240 -56
  14. package/dist/_chunks/index-k6fw6RYi.js.map +1 -0
  15. package/dist/_chunks/{index-XAQOX_IB.mjs → index-vpSczx8v.mjs} +255 -71
  16. package/dist/_chunks/index-vpSczx8v.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-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-k6fw6RYi.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,
@@ -201,14 +690,9 @@ const ReleaseDetailsLayout = ({
201
690
  const {
202
691
  allowedActions: { canUpdate, canDelete }
203
692
  } = helperPlugin.useRBAC(index.PERMISSIONS);
693
+ const dispatch = index.useTypedDispatch();
694
+ const { trackUsage } = helperPlugin.useTracking();
204
695
  const release = data?.data;
205
- const handleTogglePopover = () => {
206
- setIsPopoverVisible((prev) => !prev);
207
- };
208
- const openReleaseModal = () => {
209
- toggleEditReleaseModal();
210
- handleTogglePopover();
211
- };
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,20 @@ const ReleaseDetailsLayout = ({
231
721
  });
232
722
  }
233
723
  };
234
- const openWarningConfirmDialog = () => {
235
- toggleWarningSubmit();
236
- handleTogglePopover();
724
+ const handleRefresh = () => {
725
+ dispatch(index.releaseApi.util.invalidateTags([{ type: "ReleaseAction", id: "LIST" }]));
726
+ };
727
+ const getCreatedByUser = () => {
728
+ if (!release?.createdBy) {
729
+ return null;
730
+ }
731
+ if (release.createdBy.username) {
732
+ return release.createdBy.username;
733
+ }
734
+ if (release.createdBy.firstname) {
735
+ return `${release.createdBy.firstname} ${release.createdBy.lastname || ""}`.trim();
736
+ }
737
+ return release.createdBy.email;
237
738
  };
238
739
  if (isLoadingDetails) {
239
740
  return /* @__PURE__ */ jsxRuntime.jsx(designSystem.Main, { "aria-busy": isLoadingDetails, children: /* @__PURE__ */ jsxRuntime.jsx(helperPlugin.LoadingIndicatorPage, {}) });
@@ -256,90 +757,131 @@ const ReleaseDetailsLayout = ({
256
757
  );
257
758
  }
258
759
  const totalEntries = release.actions.meta.count || 0;
259
- const createdBy = release.createdBy.lastname ? `${release.createdBy.firstname} ${release.createdBy.lastname}` : `${release.createdBy.firstname}`;
760
+ const hasCreatedByUser = Boolean(getCreatedByUser());
761
+ const isScheduled = release.scheduledAt && release.timezone;
762
+ const numberOfEntriesText = formatMessage(
763
+ {
764
+ id: "content-releases.pages.Details.header-subtitle",
765
+ defaultMessage: "{number, plural, =0 {No entries} one {# entry} other {# entries}}"
766
+ },
767
+ { number: totalEntries }
768
+ );
769
+ const scheduledText = isScheduled ? formatMessage(
770
+ {
771
+ id: "content-releases.pages.ReleaseDetails.header-subtitle.scheduled",
772
+ defaultMessage: "Scheduled for {date} at {time} ({offset})"
773
+ },
774
+ {
775
+ date: formatDate(new Date(release.scheduledAt), {
776
+ weekday: "long",
777
+ day: "numeric",
778
+ month: "long",
779
+ year: "numeric",
780
+ timeZone: release.timezone
781
+ }),
782
+ time: formatTime(new Date(release.scheduledAt), {
783
+ timeZone: release.timezone,
784
+ hourCycle: "h23"
785
+ }),
786
+ offset: index.getTimezoneOffset(release.timezone, new Date(release.scheduledAt))
787
+ }
788
+ ) : "";
260
789
  return /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Main, { "aria-busy": isLoadingDetails, children: [
261
790
  /* @__PURE__ */ jsxRuntime.jsx(
262
791
  designSystem.HeaderLayout,
263
792
  {
264
793
  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
- ),
794
+ subtitle: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { gap: 2, lineHeight: 6, children: [
795
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { textColor: "neutral600", variant: "epsilon", children: numberOfEntriesText + (isScheduled ? ` - ${scheduledText}` : "") }),
796
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Badge, { ...getBadgeProps(release.status), children: release.status })
797
+ ] }),
272
798
  navigationAction: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Link, { startIcon: /* @__PURE__ */ jsxRuntime.jsx(icons.ArrowLeft, {}), to: "/plugins/content-releases", children: formatMessage({
273
799
  id: "global.back",
274
800
  defaultMessage: "Back"
275
801
  }) }),
276
802
  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
- ),
803
+ /* @__PURE__ */ jsxRuntime.jsxs(v2.Menu.Root, { children: [
804
+ /* @__PURE__ */ jsxRuntime.jsx(
805
+ v2.Menu.Trigger,
806
+ {
807
+ as: designSystem.IconButton,
808
+ paddingLeft: 2,
809
+ paddingRight: 2,
810
+ "aria-label": formatMessage({
811
+ id: "content-releases.header.actions.open-release-actions",
812
+ defaultMessage: "Release edit and delete menu"
813
+ }),
814
+ icon: /* @__PURE__ */ jsxRuntime.jsx(icons.More, {}),
815
+ variant: "tertiary"
816
+ }
817
+ ),
818
+ /* @__PURE__ */ jsxRuntime.jsxs(v2.Menu.Content, { top: 1, popoverPlacement: "bottom-end", children: [
819
+ /* @__PURE__ */ jsxRuntime.jsxs(
820
+ designSystem.Flex,
821
+ {
822
+ alignItems: "center",
823
+ justifyContent: "center",
824
+ direction: "column",
825
+ padding: 1,
826
+ width: "100%",
827
+ children: [
828
+ /* @__PURE__ */ jsxRuntime.jsx(StyledMenuItem, { disabled: !canUpdate, onSelect: toggleEditReleaseModal, children: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { alignItems: "center", gap: 2, hasRadius: true, width: "100%", children: [
829
+ /* @__PURE__ */ jsxRuntime.jsx(PencilIcon, {}),
830
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { ellipsis: true, children: formatMessage({
831
+ id: "content-releases.header.actions.edit",
832
+ defaultMessage: "Edit"
833
+ }) })
834
+ ] }) }),
835
+ /* @__PURE__ */ jsxRuntime.jsx(
836
+ StyledMenuItem,
837
+ {
838
+ disabled: !canDelete,
839
+ onSelect: toggleWarningSubmit,
840
+ variant: "danger",
841
+ children: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { alignItems: "center", gap: 2, hasRadius: true, width: "100%", children: [
842
+ /* @__PURE__ */ jsxRuntime.jsx(TrashIcon, {}),
843
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { ellipsis: true, textColor: "danger600", children: formatMessage({
844
+ id: "content-releases.header.actions.delete",
845
+ defaultMessage: "Delete"
846
+ }) })
847
+ ] })
848
+ }
849
+ )
850
+ ]
851
+ }
852
+ ),
853
+ /* @__PURE__ */ jsxRuntime.jsxs(
854
+ ReleaseInfoWrapper,
855
+ {
856
+ direction: "column",
857
+ justifyContent: "center",
858
+ alignItems: "flex-start",
859
+ gap: 1,
860
+ padding: 5,
861
+ children: [
862
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "pi", fontWeight: "bold", children: formatMessage({
863
+ id: "content-releases.header.actions.created",
864
+ defaultMessage: "Created"
865
+ }) }),
866
+ /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Typography, { variant: "pi", color: "neutral300", children: [
867
+ /* @__PURE__ */ jsxRuntime.jsx(helperPlugin.RelativeTime, { timestamp: new Date(release.createdAt) }),
868
+ formatMessage(
869
+ {
870
+ id: "content-releases.header.actions.created.description",
871
+ defaultMessage: "{hasCreatedByUser, select, true { by {createdBy}} other { by deleted user}}"
872
+ },
873
+ { createdBy: getCreatedByUser(), hasCreatedByUser }
874
+ )
875
+ ] })
876
+ ]
877
+ }
878
+ )
879
+ ] })
880
+ ] }),
881
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Button, { size: "S", variant: "tertiary", onClick: handleRefresh, children: formatMessage({
882
+ id: "content-releases.header.actions.refresh",
883
+ defaultMessage: "Refresh"
884
+ }) }),
343
885
  /* @__PURE__ */ jsxRuntime.jsx(helperPlugin.CheckPermissions, { permissions: index.PERMISSIONS.publish, children: /* @__PURE__ */ jsxRuntime.jsx(
344
886
  designSystem.Button,
345
887
  {
@@ -391,6 +933,9 @@ const ReleaseDetailsBody = () => {
391
933
  isError: isReleaseError,
392
934
  error: releaseError
393
935
  } = index.useGetReleaseQuery({ id: releaseId });
936
+ const {
937
+ allowedActions: { canUpdate }
938
+ } = helperPlugin.useRBAC(index.PERMISSIONS);
394
939
  const release = releaseData?.data;
395
940
  const selectedGroupBy = query?.groupBy || "contentType";
396
941
  const {
@@ -404,7 +949,7 @@ const ReleaseDetailsBody = () => {
404
949
  releaseId
405
950
  });
406
951
  const [updateReleaseAction] = index.useUpdateReleaseActionMutation();
407
- const handleChangeType = async (e, actionId) => {
952
+ const handleChangeType = async (e, actionId, actionPath) => {
408
953
  const response = await updateReleaseAction({
409
954
  params: {
410
955
  releaseId,
@@ -412,7 +957,11 @@ const ReleaseDetailsBody = () => {
412
957
  },
413
958
  body: {
414
959
  type: e.target.value
415
- }
960
+ },
961
+ query,
962
+ // We are passing the query params to make optimistic updates
963
+ actionPath
964
+ // We are passing the action path to found the position in the cache of the action for optimistic updates
416
965
  });
417
966
  if ("error" in response) {
418
967
  if (index.isAxiosError(response.error)) {
@@ -433,7 +982,9 @@ const ReleaseDetailsBody = () => {
433
982
  }
434
983
  const releaseActions = data?.data;
435
984
  const releaseMeta = data?.meta;
436
- if (isError || isReleaseError || !release || !releaseActions) {
985
+ const contentTypes = releaseMeta?.contentTypes || {};
986
+ const components = releaseMeta?.components || {};
987
+ if (isReleaseError || !release) {
437
988
  const errorsArray = [];
438
989
  if (releaseError) {
439
990
  errorsArray.push({
@@ -457,6 +1008,9 @@ const ReleaseDetailsBody = () => {
457
1008
  }
458
1009
  );
459
1010
  }
1011
+ if (isError || !releaseActions) {
1012
+ return /* @__PURE__ */ jsxRuntime.jsx(designSystem.ContentLayout, { children: /* @__PURE__ */ jsxRuntime.jsx(helperPlugin.AnErrorOccurred, {}) });
1013
+ }
460
1014
  if (Object.keys(releaseActions).length === 0) {
461
1015
  return /* @__PURE__ */ jsxRuntime.jsx(designSystem.ContentLayout, { children: /* @__PURE__ */ jsxRuntime.jsx(
462
1016
  helperPlugin.NoContent,
@@ -488,7 +1042,7 @@ const ReleaseDetailsBody = () => {
488
1042
  designSystem.SingleSelect,
489
1043
  {
490
1044
  "aria-label": formatMessage({
491
- id: "content-releases.pages.ReleaseDetails.groupBy.label",
1045
+ id: "content-releases.pages.ReleaseDetails.groupBy.aria-label",
492
1046
  defaultMessage: "Group by"
493
1047
  }),
494
1048
  customizeContent: (value) => formatMessage(
@@ -506,7 +1060,7 @@ const ReleaseDetailsBody = () => {
506
1060
  }
507
1061
  ) }),
508
1062
  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 }) }),
1063
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Flex, { role: "separator", "aria-label": key, children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Badge, { children: key }) }),
510
1064
  /* @__PURE__ */ jsxRuntime.jsx(
511
1065
  helperPlugin.Table.Root,
512
1066
  {
@@ -576,30 +1130,59 @@ const ReleaseDetailsBody = () => {
576
1130
  )
577
1131
  ] }),
578
1132
  /* @__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)) })
1133
+ /* @__PURE__ */ jsxRuntime.jsx(helperPlugin.Table.Body, { children: releaseActions[key].map(
1134
+ ({ id, contentType, locale, type, entry }, actionIndex) => /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Tr, { children: [
1135
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Td, { width: "25%", maxWidth: "200px", children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { ellipsis: true, children: `${contentType.mainFieldValue || entry.id}` }) }),
1136
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Td, { width: "10%", children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { children: `${locale?.name ? locale.name : "-"}` }) }),
1137
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Td, { width: "10%", children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { children: contentType.displayName || "" }) }),
1138
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Td, { width: "20%", children: release.releasedAt ? /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { children: formatMessage(
1139
+ {
1140
+ id: "content-releases.page.ReleaseDetails.table.action-published",
1141
+ defaultMessage: "This entry was <b>{isPublish, select, true {published} other {unpublished}}</b>."
1142
+ },
1143
+ {
1144
+ isPublish: type === "publish",
1145
+ b: (children) => /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { fontWeight: "bold", children })
1146
+ }
1147
+ ) }) : /* @__PURE__ */ jsxRuntime.jsx(
1148
+ index.ReleaseActionOptions,
1149
+ {
1150
+ selected: type,
1151
+ handleChange: (e) => handleChangeType(e, id, [key, actionIndex]),
1152
+ name: `release-action-${id}-type`,
1153
+ disabled: !canUpdate
1154
+ }
1155
+ ) }),
1156
+ !release.releasedAt && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
1157
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Td, { width: "20%", minWidth: "200px", children: /* @__PURE__ */ jsxRuntime.jsx(
1158
+ EntryValidationText,
1159
+ {
1160
+ action: type,
1161
+ schema: contentTypes?.[contentType.uid],
1162
+ components,
1163
+ entry
1164
+ }
1165
+ ) }),
1166
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Td, { children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Flex, { justifyContent: "flex-end", children: /* @__PURE__ */ jsxRuntime.jsxs(index.ReleaseActionMenu.Root, { children: [
1167
+ /* @__PURE__ */ jsxRuntime.jsx(
1168
+ index.ReleaseActionMenu.ReleaseActionEntryLinkItem,
1169
+ {
1170
+ contentTypeUid: contentType.uid,
1171
+ entryId: entry.id,
1172
+ locale: locale?.code
1173
+ }
1174
+ ),
1175
+ /* @__PURE__ */ jsxRuntime.jsx(
1176
+ index.ReleaseActionMenu.DeleteReleaseActionItem,
1177
+ {
1178
+ releaseId: release.id,
1179
+ actionId: id
1180
+ }
1181
+ )
1182
+ ] }) }) })
1183
+ ] })
1184
+ ] }, id)
1185
+ ) })
603
1186
  ] })
604
1187
  }
605
1188
  )
@@ -622,7 +1205,7 @@ const ReleaseDetailsPage = () => {
622
1205
  const { releaseId } = reactRouterDom.useParams();
623
1206
  const toggleNotification = helperPlugin.useNotification();
624
1207
  const { formatAPIError } = helperPlugin.useAPIErrorHandler();
625
- const { push } = reactRouterDom.useHistory();
1208
+ const { replace } = reactRouterDom.useHistory();
626
1209
  const [releaseModalShown, setReleaseModalShown] = React__namespace.useState(false);
627
1210
  const [showWarningSubmit, setWarningSubmit] = React__namespace.useState(false);
628
1211
  const {
@@ -646,11 +1229,18 @@ const ReleaseDetailsPage = () => {
646
1229
  }
647
1230
  );
648
1231
  }
649
- const title = isSuccessDetails && data?.data?.name || "";
1232
+ const releaseData = isSuccessDetails && data?.data || null;
1233
+ const title = releaseData?.name || "";
1234
+ const timezone = releaseData?.timezone ?? null;
1235
+ const scheduledAt = releaseData?.scheduledAt && timezone ? dateFnsTz.utcToZonedTime(releaseData.scheduledAt, timezone) : null;
1236
+ const date = scheduledAt ? new Date(format__default.default(scheduledAt, "yyyy-MM-dd")) : null;
1237
+ const time = scheduledAt ? format__default.default(scheduledAt, "HH:mm") : "";
650
1238
  const handleEditRelease = async (values) => {
651
1239
  const response = await updateRelease({
652
1240
  id: releaseId,
653
- name: values.name
1241
+ name: values.name,
1242
+ scheduledAt: values.scheduledAt,
1243
+ timezone: values.timezone
654
1244
  });
655
1245
  if ("data" in response) {
656
1246
  toggleNotification({
@@ -678,7 +1268,7 @@ const ReleaseDetailsPage = () => {
678
1268
  id: releaseId
679
1269
  });
680
1270
  if ("data" in response) {
681
- push("/plugins/content-releases");
1271
+ replace("/plugins/content-releases");
682
1272
  } else if (index.isAxiosError(response.error)) {
683
1273
  toggleNotification({
684
1274
  type: "warning",
@@ -704,7 +1294,14 @@ const ReleaseDetailsPage = () => {
704
1294
  handleClose: toggleEditReleaseModal,
705
1295
  handleSubmit: handleEditRelease,
706
1296
  isLoading: isLoadingDetails || isSubmittingForm,
707
- initialValues: { name: title || "" }
1297
+ initialValues: {
1298
+ name: title || "",
1299
+ scheduledAt,
1300
+ date,
1301
+ time,
1302
+ isScheduled: Boolean(scheduledAt),
1303
+ timezone
1304
+ }
708
1305
  }
709
1306
  ),
710
1307
  /* @__PURE__ */ jsxRuntime.jsx(
@@ -724,239 +1321,6 @@ const ReleaseDetailsPage = () => {
724
1321
  }
725
1322
  );
726
1323
  };
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
1324
  const App = () => {
961
1325
  return /* @__PURE__ */ jsxRuntime.jsx(helperPlugin.CheckPagePermissions, { permissions: index.PERMISSIONS.main, children: /* @__PURE__ */ jsxRuntime.jsxs(reactRouterDom.Switch, { children: [
962
1326
  /* @__PURE__ */ jsxRuntime.jsx(reactRouterDom.Route, { exact: true, path: `/plugins/${index.pluginId}`, component: ReleasesPage }),
@@ -964,4 +1328,4 @@ const App = () => {
964
1328
  ] }) });
965
1329
  };
966
1330
  exports.App = App;
967
- //# sourceMappingURL=App-o5_WfqR-.js.map
1331
+ //# sourceMappingURL=App-WZHc_d3m.js.map