@strapi/content-releases 0.0.0-next.f4ff842a3cb7b83db540bee67554b704e042b042 → 0.0.0-next.f6dca5adf05ef6bed9605a1535999ab0bbbf063e

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 (141) hide show
  1. package/LICENSE +17 -1
  2. package/dist/_chunks/App-BKB1esYS.js +1395 -0
  3. package/dist/_chunks/App-BKB1esYS.js.map +1 -0
  4. package/dist/_chunks/{App-jrh58sXY.mjs → App-Cne--1Z8.mjs} +602 -558
  5. package/dist/_chunks/App-Cne--1Z8.mjs.map +1 -0
  6. package/dist/_chunks/{PurchaseContentReleases-bpIYXOfu.js → PurchaseContentReleases-Be3acS2L.js} +7 -6
  7. package/dist/_chunks/PurchaseContentReleases-Be3acS2L.js.map +1 -0
  8. package/dist/_chunks/{PurchaseContentReleases-3tRbmbY3.mjs → PurchaseContentReleases-_MxP6-Dt.mjs} +8 -7
  9. package/dist/_chunks/PurchaseContentReleases-_MxP6-Dt.mjs.map +1 -0
  10. package/dist/_chunks/ReleasesSettingsPage-C1WwGWIH.mjs +178 -0
  11. package/dist/_chunks/ReleasesSettingsPage-C1WwGWIH.mjs.map +1 -0
  12. package/dist/_chunks/ReleasesSettingsPage-kuXIwpWp.js +178 -0
  13. package/dist/_chunks/ReleasesSettingsPage-kuXIwpWp.js.map +1 -0
  14. package/dist/_chunks/{en-HrREghh3.js → en-CmYoEnA7.js} +9 -2
  15. package/dist/_chunks/en-CmYoEnA7.js.map +1 -0
  16. package/dist/_chunks/{en-ltT1TlKQ.mjs → en-D0yVZFqf.mjs} +9 -2
  17. package/dist/_chunks/en-D0yVZFqf.mjs.map +1 -0
  18. package/dist/_chunks/index-5Odi61vw.js +1381 -0
  19. package/dist/_chunks/index-5Odi61vw.js.map +1 -0
  20. package/dist/_chunks/index-Cy7qwpaU.mjs +1362 -0
  21. package/dist/_chunks/index-Cy7qwpaU.mjs.map +1 -0
  22. package/dist/_chunks/schemas-BE1LxE9J.js +62 -0
  23. package/dist/_chunks/schemas-BE1LxE9J.js.map +1 -0
  24. package/dist/_chunks/schemas-DdA2ic2U.mjs +44 -0
  25. package/dist/_chunks/schemas-DdA2ic2U.mjs.map +1 -0
  26. package/dist/admin/index.js +1 -15
  27. package/dist/admin/index.js.map +1 -1
  28. package/dist/admin/index.mjs +2 -16
  29. package/dist/admin/index.mjs.map +1 -1
  30. package/dist/admin/src/components/RelativeTime.d.ts +28 -0
  31. package/dist/admin/src/components/ReleaseAction.d.ts +3 -0
  32. package/dist/admin/src/components/ReleaseActionMenu.d.ts +26 -0
  33. package/dist/admin/src/components/ReleaseActionModal.d.ts +24 -0
  34. package/dist/admin/src/components/ReleaseActionOptions.d.ts +9 -0
  35. package/dist/admin/src/components/ReleaseListCell.d.ts +28 -0
  36. package/dist/admin/src/components/ReleaseModal.d.ts +17 -0
  37. package/dist/admin/src/components/ReleasesPanel.d.ts +3 -0
  38. package/dist/admin/src/constants.d.ts +76 -0
  39. package/dist/admin/src/index.d.ts +3 -0
  40. package/dist/admin/src/modules/hooks.d.ts +7 -0
  41. package/dist/admin/src/pages/App.d.ts +1 -0
  42. package/dist/admin/src/pages/PurchaseContentReleases.d.ts +2 -0
  43. package/dist/admin/src/pages/ReleaseDetailsPage.d.ts +2 -0
  44. package/dist/admin/src/pages/ReleasesPage.d.ts +8 -0
  45. package/dist/admin/src/pages/ReleasesSettingsPage.d.ts +1 -0
  46. package/dist/admin/src/pages/tests/mockReleaseDetailsPageData.d.ts +181 -0
  47. package/dist/admin/src/pages/tests/mockReleasesPageData.d.ts +39 -0
  48. package/dist/admin/src/pluginId.d.ts +1 -0
  49. package/dist/admin/src/services/release.d.ts +112 -0
  50. package/dist/admin/src/store/hooks.d.ts +7 -0
  51. package/dist/admin/src/utils/api.d.ts +6 -0
  52. package/dist/admin/src/utils/prefixPluginTranslations.d.ts +3 -0
  53. package/dist/admin/src/utils/time.d.ts +10 -0
  54. package/dist/admin/src/validation/schemas.d.ts +6 -0
  55. package/dist/server/index.js +843 -636
  56. package/dist/server/index.js.map +1 -1
  57. package/dist/server/index.mjs +844 -636
  58. package/dist/server/index.mjs.map +1 -1
  59. package/dist/server/src/bootstrap.d.ts +5 -0
  60. package/dist/server/src/bootstrap.d.ts.map +1 -0
  61. package/dist/server/src/constants.d.ts +21 -0
  62. package/dist/server/src/constants.d.ts.map +1 -0
  63. package/dist/server/src/content-types/index.d.ts +97 -0
  64. package/dist/server/src/content-types/index.d.ts.map +1 -0
  65. package/dist/server/src/content-types/release/index.d.ts +48 -0
  66. package/dist/server/src/content-types/release/index.d.ts.map +1 -0
  67. package/dist/server/src/content-types/release/schema.d.ts +47 -0
  68. package/dist/server/src/content-types/release/schema.d.ts.map +1 -0
  69. package/dist/server/src/content-types/release-action/index.d.ts +48 -0
  70. package/dist/server/src/content-types/release-action/index.d.ts.map +1 -0
  71. package/dist/server/src/content-types/release-action/schema.d.ts +47 -0
  72. package/dist/server/src/content-types/release-action/schema.d.ts.map +1 -0
  73. package/dist/server/src/controllers/index.d.ts +25 -0
  74. package/dist/server/src/controllers/index.d.ts.map +1 -0
  75. package/dist/server/src/controllers/release-action.d.ts +10 -0
  76. package/dist/server/src/controllers/release-action.d.ts.map +1 -0
  77. package/dist/server/src/controllers/release.d.ts +18 -0
  78. package/dist/server/src/controllers/release.d.ts.map +1 -0
  79. package/dist/server/src/controllers/settings.d.ts +11 -0
  80. package/dist/server/src/controllers/settings.d.ts.map +1 -0
  81. package/dist/server/src/controllers/validation/release-action.d.ts +14 -0
  82. package/dist/server/src/controllers/validation/release-action.d.ts.map +1 -0
  83. package/dist/server/src/controllers/validation/release.d.ts +4 -0
  84. package/dist/server/src/controllers/validation/release.d.ts.map +1 -0
  85. package/dist/server/src/controllers/validation/settings.d.ts +3 -0
  86. package/dist/server/src/controllers/validation/settings.d.ts.map +1 -0
  87. package/dist/server/src/destroy.d.ts +5 -0
  88. package/dist/server/src/destroy.d.ts.map +1 -0
  89. package/dist/server/src/index.d.ts +2115 -0
  90. package/dist/server/src/index.d.ts.map +1 -0
  91. package/dist/server/src/middlewares/documents.d.ts +6 -0
  92. package/dist/server/src/middlewares/documents.d.ts.map +1 -0
  93. package/dist/server/src/migrations/database/5.0.0-document-id-in-actions.d.ts +9 -0
  94. package/dist/server/src/migrations/database/5.0.0-document-id-in-actions.d.ts.map +1 -0
  95. package/dist/server/src/migrations/index.d.ts +13 -0
  96. package/dist/server/src/migrations/index.d.ts.map +1 -0
  97. package/dist/server/src/register.d.ts +5 -0
  98. package/dist/server/src/register.d.ts.map +1 -0
  99. package/dist/server/src/routes/index.d.ts +51 -0
  100. package/dist/server/src/routes/index.d.ts.map +1 -0
  101. package/dist/server/src/routes/release-action.d.ts +18 -0
  102. package/dist/server/src/routes/release-action.d.ts.map +1 -0
  103. package/dist/server/src/routes/release.d.ts +18 -0
  104. package/dist/server/src/routes/release.d.ts.map +1 -0
  105. package/dist/server/src/routes/settings.d.ts +18 -0
  106. package/dist/server/src/routes/settings.d.ts.map +1 -0
  107. package/dist/server/src/services/index.d.ts +1828 -0
  108. package/dist/server/src/services/index.d.ts.map +1 -0
  109. package/dist/server/src/services/release-action.d.ts +38 -0
  110. package/dist/server/src/services/release-action.d.ts.map +1 -0
  111. package/dist/server/src/services/release.d.ts +31 -0
  112. package/dist/server/src/services/release.d.ts.map +1 -0
  113. package/dist/server/src/services/scheduling.d.ts +18 -0
  114. package/dist/server/src/services/scheduling.d.ts.map +1 -0
  115. package/dist/server/src/services/settings.d.ts +13 -0
  116. package/dist/server/src/services/settings.d.ts.map +1 -0
  117. package/dist/server/src/services/validation.d.ts +18 -0
  118. package/dist/server/src/services/validation.d.ts.map +1 -0
  119. package/dist/server/src/utils/index.d.ts +35 -0
  120. package/dist/server/src/utils/index.d.ts.map +1 -0
  121. package/dist/shared/contracts/release-actions.d.ts +130 -0
  122. package/dist/shared/contracts/release-actions.d.ts.map +1 -0
  123. package/dist/shared/contracts/releases.d.ts +184 -0
  124. package/dist/shared/contracts/releases.d.ts.map +1 -0
  125. package/dist/shared/contracts/settings.d.ts +39 -0
  126. package/dist/shared/contracts/settings.d.ts.map +1 -0
  127. package/dist/shared/types.d.ts +24 -0
  128. package/dist/shared/types.d.ts.map +1 -0
  129. package/package.json +34 -39
  130. package/dist/_chunks/App-dLXY5ei3.js +0 -1353
  131. package/dist/_chunks/App-dLXY5ei3.js.map +0 -1
  132. package/dist/_chunks/App-jrh58sXY.mjs.map +0 -1
  133. package/dist/_chunks/PurchaseContentReleases-3tRbmbY3.mjs.map +0 -1
  134. package/dist/_chunks/PurchaseContentReleases-bpIYXOfu.js.map +0 -1
  135. package/dist/_chunks/en-HrREghh3.js.map +0 -1
  136. package/dist/_chunks/en-ltT1TlKQ.mjs.map +0 -1
  137. package/dist/_chunks/index-CVO0Rqdm.js +0 -1336
  138. package/dist/_chunks/index-CVO0Rqdm.js.map +0 -1
  139. package/dist/_chunks/index-PiOGBETy.mjs +0 -1315
  140. package/dist/_chunks/index-PiOGBETy.mjs.map +0 -1
  141. package/strapi-server.js +0 -3
@@ -1,1353 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
3
- const jsxRuntime = require("react/jsx-runtime");
4
- const helperPlugin = require("@strapi/helper-plugin");
5
- const reactRouterDom = require("react-router-dom");
6
- const index = require("./index-CVO0Rqdm.js");
7
- const React = require("react");
8
- const strapiAdmin = require("@strapi/admin/strapi-admin");
9
- const designSystem = require("@strapi/design-system");
10
- const v2 = require("@strapi/design-system/v2");
11
- const icons = require("@strapi/icons");
12
- const format = require("date-fns/format");
13
- const dateFnsTz = require("date-fns-tz");
14
- const reactIntl = require("react-intl");
15
- const styled = require("styled-components");
16
- const dateFns = require("date-fns");
17
- const formik = require("formik");
18
- const yup = require("yup");
19
- require("@reduxjs/toolkit/query");
20
- require("axios");
21
- require("@reduxjs/toolkit/query/react");
22
- require("react-redux");
23
- const _interopDefault = (e) => e && e.__esModule ? e : { default: e };
24
- function _interopNamespace(e) {
25
- if (e && e.__esModule)
26
- return e;
27
- const n = Object.create(null, { [Symbol.toStringTag]: { value: "Module" } });
28
- if (e) {
29
- for (const k in e) {
30
- if (k !== "default") {
31
- const d = Object.getOwnPropertyDescriptor(e, k);
32
- Object.defineProperty(n, k, d.get ? d : {
33
- enumerable: true,
34
- get: () => e[k]
35
- });
36
- }
37
- }
38
- }
39
- n.default = e;
40
- return Object.freeze(n);
41
- }
42
- const React__namespace = /* @__PURE__ */ _interopNamespace(React);
43
- const format__default = /* @__PURE__ */ _interopDefault(format);
44
- const styled__default = /* @__PURE__ */ _interopDefault(styled);
45
- const yup__namespace = /* @__PURE__ */ _interopNamespace(yup);
46
- const RELEASE_SCHEMA = yup__namespace.object().shape({
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
- })
65
- }).required().noUnknown();
66
- const ReleaseModal = ({
67
- handleClose,
68
- handleSubmit,
69
- initialValues,
70
- isLoading = false
71
- }) => {
72
- const { formatMessage } = reactIntl.useIntl();
73
- const { pathname } = reactRouterDom.useLocation();
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
- };
91
- return /* @__PURE__ */ jsxRuntime.jsxs(designSystem.ModalLayout, { onClose: handleClose, labelledBy: "title", children: [
92
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.ModalHeader, { children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { id: "title", fontWeight: "bold", textColor: "neutral800", children: formatMessage(
93
- {
94
- id: "content-releases.modal.title",
95
- defaultMessage: "{isCreatingRelease, select, true {New release} other {Edit release}}"
96
- },
97
- { isCreatingRelease }
98
- ) }) }),
99
- /* @__PURE__ */ jsxRuntime.jsx(
100
- formik.Formik,
101
- {
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
- },
113
- validationSchema: RELEASE_SCHEMA,
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
- ] }) }),
215
- /* @__PURE__ */ jsxRuntime.jsx(
216
- designSystem.ModalFooter,
217
- {
218
- startActions: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Button, { onClick: handleClose, variant: "tertiary", name: "cancel", children: formatMessage({ id: "cancel", defaultMessage: "Cancel" }) }),
219
- endActions: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Button, { name: "submit", loading: isLoading, type: "submit", children: formatMessage(
220
- {
221
- id: "content-releases.modal.form.button.submit",
222
- defaultMessage: "{isCreatingRelease, select, true {Continue} other {Save}}"
223
- },
224
- { isCreatingRelease }
225
- ) })
226
- }
227
- )
228
- ] })
229
- }
230
- )
231
- ] });
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 RelativeTime = styled__default.default(helperPlugin.RelativeTime)`
287
- display: inline-block;
288
- &::first-letter {
289
- text-transform: uppercase;
290
- }
291
- `;
292
- const getBadgeProps = (status) => {
293
- let color;
294
- switch (status) {
295
- case "ready":
296
- color = "success";
297
- break;
298
- case "blocked":
299
- color = "warning";
300
- break;
301
- case "failed":
302
- color = "danger";
303
- break;
304
- case "done":
305
- color = "primary";
306
- break;
307
- case "empty":
308
- default:
309
- color = "neutral";
310
- }
311
- return {
312
- textColor: `${color}600`,
313
- backgroundColor: `${color}100`,
314
- borderColor: `${color}200`
315
- };
316
- };
317
- const ReleasesGrid = ({ sectionTitle, releases = [], isError = false }) => {
318
- const { formatMessage } = reactIntl.useIntl();
319
- if (isError) {
320
- return /* @__PURE__ */ jsxRuntime.jsx(helperPlugin.AnErrorOccurred, {});
321
- }
322
- if (releases?.length === 0) {
323
- return /* @__PURE__ */ jsxRuntime.jsx(
324
- designSystem.EmptyStateLayout,
325
- {
326
- content: formatMessage(
327
- {
328
- id: "content-releases.page.Releases.tab.emptyEntries",
329
- defaultMessage: "No releases"
330
- },
331
- {
332
- target: sectionTitle
333
- }
334
- ),
335
- icon: /* @__PURE__ */ jsxRuntime.jsx(icons.EmptyDocuments, { width: "10rem" })
336
- }
337
- );
338
- }
339
- 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(
340
- designSystem.Flex,
341
- {
342
- direction: "column",
343
- justifyContent: "space-between",
344
- padding: 4,
345
- hasRadius: true,
346
- background: "neutral0",
347
- shadow: "tableShadow",
348
- height: "100%",
349
- width: "100%",
350
- alignItems: "start",
351
- gap: 4,
352
- children: [
353
- /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { direction: "column", alignItems: "start", gap: 1, children: [
354
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { as: "h3", variant: "delta", fontWeight: "bold", children: name }),
355
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "pi", textColor: "neutral600", children: scheduledAt ? /* @__PURE__ */ jsxRuntime.jsx(RelativeTime, { timestamp: new Date(scheduledAt) }) : formatMessage({
356
- id: "content-releases.pages.Releases.not-scheduled",
357
- defaultMessage: "Not scheduled"
358
- }) })
359
- ] }),
360
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Badge, { ...getBadgeProps(status), children: status })
361
- ]
362
- }
363
- ) }) }, id)) });
364
- };
365
- const StyledAlert = styled__default.default(designSystem.Alert)`
366
- button {
367
- display: none;
368
- }
369
- p + div {
370
- margin-left: auto;
371
- }
372
- `;
373
- const INITIAL_FORM_VALUES = {
374
- name: "",
375
- date: null,
376
- time: "",
377
- isScheduled: true,
378
- scheduledAt: null,
379
- timezone: null
380
- };
381
- const ReleasesPage = () => {
382
- const tabRef = React__namespace.useRef(null);
383
- const location = reactRouterDom.useLocation();
384
- const [releaseModalShown, setReleaseModalShown] = React__namespace.useState(false);
385
- const toggleNotification = helperPlugin.useNotification();
386
- const { formatMessage } = reactIntl.useIntl();
387
- const { push, replace } = reactRouterDom.useHistory();
388
- const { formatAPIError } = helperPlugin.useAPIErrorHandler();
389
- const [{ query }, setQuery] = helperPlugin.useQueryParams();
390
- const response = index.useGetReleasesQuery(query);
391
- const [createRelease, { isLoading: isSubmittingForm }] = index.useCreateReleaseMutation();
392
- const { getFeature } = strapiAdmin.useLicenseLimits();
393
- const { maximumReleases = 3 } = getFeature("cms-content-releases");
394
- const { trackUsage } = helperPlugin.useTracking();
395
- const { isLoading, isSuccess, isError } = response;
396
- const activeTab = response?.currentData?.meta?.activeTab || "pending";
397
- const activeTabIndex = ["pending", "done"].indexOf(activeTab);
398
- React__namespace.useEffect(() => {
399
- if (location?.state?.errors) {
400
- toggleNotification({
401
- type: "warning",
402
- title: formatMessage({
403
- id: "content-releases.pages.Releases.notification.error.title",
404
- defaultMessage: "Your request could not be processed."
405
- }),
406
- message: formatMessage({
407
- id: "content-releases.pages.Releases.notification.error.message",
408
- defaultMessage: "Please try again or open another release."
409
- })
410
- });
411
- replace({ state: null });
412
- }
413
- }, [formatMessage, location?.state?.errors, replace, toggleNotification]);
414
- React__namespace.useEffect(() => {
415
- if (tabRef.current) {
416
- tabRef.current._handlers.setSelectedTabIndex(activeTabIndex);
417
- }
418
- }, [activeTabIndex]);
419
- const toggleAddReleaseModal = () => {
420
- setReleaseModalShown((prev) => !prev);
421
- };
422
- if (isLoading) {
423
- return /* @__PURE__ */ jsxRuntime.jsx(designSystem.Main, { "aria-busy": isLoading, children: /* @__PURE__ */ jsxRuntime.jsx(helperPlugin.LoadingIndicatorPage, {}) });
424
- }
425
- const totalPendingReleases = isSuccess && response.currentData?.meta?.pendingReleasesCount || 0;
426
- const hasReachedMaximumPendingReleases = totalPendingReleases >= maximumReleases;
427
- const handleTabChange = (index2) => {
428
- setQuery({
429
- ...query,
430
- page: 1,
431
- pageSize: response?.currentData?.meta?.pagination?.pageSize || 16,
432
- filters: {
433
- releasedAt: {
434
- $notNull: index2 === 0 ? false : true
435
- }
436
- }
437
- });
438
- };
439
- const handleAddRelease = async ({ name, scheduledAt, timezone }) => {
440
- const response2 = await createRelease({
441
- name,
442
- scheduledAt,
443
- timezone
444
- });
445
- if ("data" in response2) {
446
- toggleNotification({
447
- type: "success",
448
- message: formatMessage({
449
- id: "content-releases.modal.release-created-notification-success",
450
- defaultMessage: "Release created."
451
- })
452
- });
453
- trackUsage("didCreateRelease");
454
- push(`/plugins/content-releases/${response2.data.data.id}`);
455
- } else if (index.isAxiosError(response2.error)) {
456
- toggleNotification({
457
- type: "warning",
458
- message: formatAPIError(response2.error)
459
- });
460
- } else {
461
- toggleNotification({
462
- type: "warning",
463
- message: formatMessage({ id: "notification.error", defaultMessage: "An error occurred" })
464
- });
465
- }
466
- };
467
- return /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Main, { "aria-busy": isLoading, children: [
468
- /* @__PURE__ */ jsxRuntime.jsx(
469
- designSystem.HeaderLayout,
470
- {
471
- title: formatMessage({
472
- id: "content-releases.pages.Releases.title",
473
- defaultMessage: "Releases"
474
- }),
475
- subtitle: formatMessage({
476
- id: "content-releases.pages.Releases.header-subtitle",
477
- defaultMessage: "Create and manage content updates"
478
- }),
479
- primaryAction: /* @__PURE__ */ jsxRuntime.jsx(helperPlugin.CheckPermissions, { permissions: index.PERMISSIONS.create, children: /* @__PURE__ */ jsxRuntime.jsx(
480
- designSystem.Button,
481
- {
482
- startIcon: /* @__PURE__ */ jsxRuntime.jsx(icons.Plus, {}),
483
- onClick: toggleAddReleaseModal,
484
- disabled: hasReachedMaximumPendingReleases,
485
- children: formatMessage({
486
- id: "content-releases.header.actions.add-release",
487
- defaultMessage: "New release"
488
- })
489
- }
490
- ) })
491
- }
492
- ),
493
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.ContentLayout, { children: /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
494
- hasReachedMaximumPendingReleases && /* @__PURE__ */ jsxRuntime.jsx(
495
- StyledAlert,
496
- {
497
- marginBottom: 6,
498
- action: /* @__PURE__ */ jsxRuntime.jsx(v2.Link, { href: "https://strapi.io/pricing-cloud", isExternal: true, children: formatMessage({
499
- id: "content-releases.pages.Releases.max-limit-reached.action",
500
- defaultMessage: "Explore plans"
501
- }) }),
502
- title: formatMessage(
503
- {
504
- id: "content-releases.pages.Releases.max-limit-reached.title",
505
- defaultMessage: "You have reached the {number} pending {number, plural, one {release} other {releases}} limit."
506
- },
507
- { number: maximumReleases }
508
- ),
509
- onClose: () => {
510
- },
511
- closeLabel: "",
512
- children: formatMessage({
513
- id: "content-releases.pages.Releases.max-limit-reached.message",
514
- defaultMessage: "Upgrade to manage an unlimited number of releases."
515
- })
516
- }
517
- ),
518
- /* @__PURE__ */ jsxRuntime.jsxs(
519
- designSystem.TabGroup,
520
- {
521
- label: formatMessage({
522
- id: "content-releases.pages.Releases.tab-group.label",
523
- defaultMessage: "Releases list"
524
- }),
525
- variant: "simple",
526
- initialSelectedTabIndex: activeTabIndex,
527
- onTabChange: handleTabChange,
528
- ref: tabRef,
529
- children: [
530
- /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Box, { paddingBottom: 8, children: [
531
- /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Tabs, { children: [
532
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Tab, { children: formatMessage(
533
- {
534
- id: "content-releases.pages.Releases.tab.pending",
535
- defaultMessage: "Pending ({count})"
536
- },
537
- {
538
- count: totalPendingReleases
539
- }
540
- ) }),
541
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Tab, { children: formatMessage({
542
- id: "content-releases.pages.Releases.tab.done",
543
- defaultMessage: "Done"
544
- }) })
545
- ] }),
546
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Divider, {})
547
- ] }),
548
- /* @__PURE__ */ jsxRuntime.jsxs(designSystem.TabPanels, { children: [
549
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.TabPanel, { children: /* @__PURE__ */ jsxRuntime.jsx(
550
- ReleasesGrid,
551
- {
552
- sectionTitle: "pending",
553
- releases: response?.currentData?.data,
554
- isError
555
- }
556
- ) }),
557
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.TabPanel, { children: /* @__PURE__ */ jsxRuntime.jsx(
558
- ReleasesGrid,
559
- {
560
- sectionTitle: "done",
561
- releases: response?.currentData?.data,
562
- isError
563
- }
564
- ) })
565
- ] })
566
- ]
567
- }
568
- ),
569
- response.currentData?.meta?.pagination?.total ? /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { paddingTop: 4, alignItems: "flex-end", justifyContent: "space-between", children: [
570
- /* @__PURE__ */ jsxRuntime.jsx(
571
- helperPlugin.PageSizeURLQuery,
572
- {
573
- options: ["8", "16", "32", "64"],
574
- defaultValue: response?.currentData?.meta?.pagination?.pageSize.toString()
575
- }
576
- ),
577
- /* @__PURE__ */ jsxRuntime.jsx(
578
- helperPlugin.PaginationURLQuery,
579
- {
580
- pagination: {
581
- pageCount: response?.currentData?.meta?.pagination?.pageCount || 0
582
- }
583
- }
584
- )
585
- ] }) : null
586
- ] }) }),
587
- releaseModalShown && /* @__PURE__ */ jsxRuntime.jsx(
588
- ReleaseModal,
589
- {
590
- handleClose: toggleAddReleaseModal,
591
- handleSubmit: handleAddRelease,
592
- isLoading: isSubmittingForm,
593
- initialValues: INITIAL_FORM_VALUES
594
- }
595
- )
596
- ] });
597
- };
598
- const ReleaseInfoWrapper = styled__default.default(designSystem.Flex)`
599
- align-self: stretch;
600
- border-bottom-right-radius: ${({ theme }) => theme.borderRadius};
601
- border-bottom-left-radius: ${({ theme }) => theme.borderRadius};
602
- border-top: 1px solid ${({ theme }) => theme.colors.neutral150};
603
- `;
604
- const StyledMenuItem = styled__default.default(v2.Menu.Item)`
605
- svg path {
606
- fill: ${({ theme, disabled }) => disabled && theme.colors.neutral500};
607
- }
608
- span {
609
- color: ${({ theme, disabled }) => disabled && theme.colors.neutral500};
610
- }
611
-
612
- &:hover {
613
- background: ${({ theme, variant = "neutral" }) => theme.colors[`${variant}100`]};
614
- }
615
- `;
616
- const PencilIcon = styled__default.default(icons.Pencil)`
617
- width: ${({ theme }) => theme.spaces[3]};
618
- height: ${({ theme }) => theme.spaces[3]};
619
- path {
620
- fill: ${({ theme }) => theme.colors.neutral600};
621
- }
622
- `;
623
- const TrashIcon = styled__default.default(icons.Trash)`
624
- width: ${({ theme }) => theme.spaces[3]};
625
- height: ${({ theme }) => theme.spaces[3]};
626
- path {
627
- fill: ${({ theme }) => theme.colors.danger600};
628
- }
629
- `;
630
- const TypographyMaxWidth = styled__default.default(designSystem.Typography)`
631
- max-width: 300px;
632
- `;
633
- const EntryValidationText = ({ action, schema, components, entry }) => {
634
- const { formatMessage } = reactIntl.useIntl();
635
- const { validate } = strapiAdmin.unstable_useDocument();
636
- const { errors } = validate(entry, {
637
- contentType: schema,
638
- components,
639
- isCreatingEntry: false
640
- });
641
- if (Object.keys(errors).length > 0) {
642
- const validationErrorsMessages = Object.entries(errors).map(
643
- ([key, value]) => formatMessage(
644
- { id: `${value.id}.withField`, defaultMessage: value.defaultMessage },
645
- { field: key }
646
- )
647
- ).join(" ");
648
- return /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { gap: 2, children: [
649
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Icon, { color: "danger600", as: icons.CrossCircle }),
650
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Tooltip, { description: validationErrorsMessages, children: /* @__PURE__ */ jsxRuntime.jsx(TypographyMaxWidth, { textColor: "danger600", variant: "omega", fontWeight: "semiBold", ellipsis: true, children: validationErrorsMessages }) })
651
- ] });
652
- }
653
- if (action == "publish") {
654
- return /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { gap: 2, children: [
655
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Icon, { color: "success600", as: icons.CheckCircle }),
656
- entry.publishedAt ? /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { textColor: "success600", fontWeight: "bold", children: formatMessage({
657
- id: "content-releases.pages.ReleaseDetails.entry-validation.already-published",
658
- defaultMessage: "Already published"
659
- }) }) : /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { children: formatMessage({
660
- id: "content-releases.pages.ReleaseDetails.entry-validation.ready-to-publish",
661
- defaultMessage: "Ready to publish"
662
- }) })
663
- ] });
664
- }
665
- return /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { gap: 2, children: [
666
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Icon, { color: "success600", as: icons.CheckCircle }),
667
- !entry.publishedAt ? /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { textColor: "success600", fontWeight: "bold", children: formatMessage({
668
- id: "content-releases.pages.ReleaseDetails.entry-validation.already-unpublished",
669
- defaultMessage: "Already unpublished"
670
- }) }) : /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { children: formatMessage({
671
- id: "content-releases.pages.ReleaseDetails.entry-validation.ready-to-unpublish",
672
- defaultMessage: "Ready to unpublish"
673
- }) })
674
- ] });
675
- };
676
- const ReleaseDetailsLayout = ({
677
- toggleEditReleaseModal,
678
- toggleWarningSubmit,
679
- children
680
- }) => {
681
- const { formatMessage, formatDate, formatTime } = reactIntl.useIntl();
682
- const { releaseId } = reactRouterDom.useParams();
683
- const {
684
- data,
685
- isLoading: isLoadingDetails,
686
- isError,
687
- error
688
- } = index.useGetReleaseQuery({ id: releaseId });
689
- const [publishRelease, { isLoading: isPublishing }] = index.usePublishReleaseMutation();
690
- const toggleNotification = helperPlugin.useNotification();
691
- const { formatAPIError } = helperPlugin.useAPIErrorHandler();
692
- const {
693
- allowedActions: { canUpdate, canDelete }
694
- } = helperPlugin.useRBAC(index.PERMISSIONS);
695
- const dispatch = index.useTypedDispatch();
696
- const { trackUsage } = helperPlugin.useTracking();
697
- const release = data?.data;
698
- const handlePublishRelease = async () => {
699
- const response = await publishRelease({ id: releaseId });
700
- if ("data" in response) {
701
- toggleNotification({
702
- type: "success",
703
- message: formatMessage({
704
- id: "content-releases.pages.ReleaseDetails.publish-notification-success",
705
- defaultMessage: "Release was published successfully."
706
- })
707
- });
708
- const { totalEntries: totalEntries2, totalPublishedEntries, totalUnpublishedEntries } = response.data.meta;
709
- trackUsage("didPublishRelease", {
710
- totalEntries: totalEntries2,
711
- totalPublishedEntries,
712
- totalUnpublishedEntries
713
- });
714
- } else if (index.isAxiosError(response.error)) {
715
- toggleNotification({
716
- type: "warning",
717
- message: formatAPIError(response.error)
718
- });
719
- } else {
720
- toggleNotification({
721
- type: "warning",
722
- message: formatMessage({ id: "notification.error", defaultMessage: "An error occurred" })
723
- });
724
- }
725
- };
726
- const handleRefresh = () => {
727
- dispatch(
728
- index.releaseApi.util.invalidateTags([
729
- { type: "ReleaseAction", id: "LIST" },
730
- { type: "Release", id: releaseId }
731
- ])
732
- );
733
- };
734
- const getCreatedByUser = () => {
735
- if (!release?.createdBy) {
736
- return null;
737
- }
738
- if (release.createdBy.username) {
739
- return release.createdBy.username;
740
- }
741
- if (release.createdBy.firstname) {
742
- return `${release.createdBy.firstname} ${release.createdBy.lastname || ""}`.trim();
743
- }
744
- return release.createdBy.email;
745
- };
746
- if (isLoadingDetails) {
747
- return /* @__PURE__ */ jsxRuntime.jsx(designSystem.Main, { "aria-busy": isLoadingDetails, children: /* @__PURE__ */ jsxRuntime.jsx(helperPlugin.LoadingIndicatorPage, {}) });
748
- }
749
- if (isError || !release) {
750
- return /* @__PURE__ */ jsxRuntime.jsx(
751
- reactRouterDom.Redirect,
752
- {
753
- to: {
754
- pathname: "/plugins/content-releases",
755
- state: {
756
- errors: [
757
- {
758
- code: error?.code
759
- }
760
- ]
761
- }
762
- }
763
- }
764
- );
765
- }
766
- const totalEntries = release.actions.meta.count || 0;
767
- const hasCreatedByUser = Boolean(getCreatedByUser());
768
- const isScheduled = release.scheduledAt && release.timezone;
769
- const numberOfEntriesText = formatMessage(
770
- {
771
- id: "content-releases.pages.Details.header-subtitle",
772
- defaultMessage: "{number, plural, =0 {No entries} one {# entry} other {# entries}}"
773
- },
774
- { number: totalEntries }
775
- );
776
- const scheduledText = isScheduled ? formatMessage(
777
- {
778
- id: "content-releases.pages.ReleaseDetails.header-subtitle.scheduled",
779
- defaultMessage: "Scheduled for {date} at {time} ({offset})"
780
- },
781
- {
782
- date: formatDate(new Date(release.scheduledAt), {
783
- weekday: "long",
784
- day: "numeric",
785
- month: "long",
786
- year: "numeric",
787
- timeZone: release.timezone
788
- }),
789
- time: formatTime(new Date(release.scheduledAt), {
790
- timeZone: release.timezone,
791
- hourCycle: "h23"
792
- }),
793
- offset: index.getTimezoneOffset(release.timezone, new Date(release.scheduledAt))
794
- }
795
- ) : "";
796
- return /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Main, { "aria-busy": isLoadingDetails, children: [
797
- /* @__PURE__ */ jsxRuntime.jsx(
798
- designSystem.HeaderLayout,
799
- {
800
- title: release.name,
801
- subtitle: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { gap: 2, lineHeight: 6, children: [
802
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { textColor: "neutral600", variant: "epsilon", children: numberOfEntriesText + (isScheduled ? ` - ${scheduledText}` : "") }),
803
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Badge, { ...getBadgeProps(release.status), children: release.status })
804
- ] }),
805
- navigationAction: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Link, { startIcon: /* @__PURE__ */ jsxRuntime.jsx(icons.ArrowLeft, {}), to: "/plugins/content-releases", children: formatMessage({
806
- id: "global.back",
807
- defaultMessage: "Back"
808
- }) }),
809
- primaryAction: !release.releasedAt && /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { gap: 2, children: [
810
- /* @__PURE__ */ jsxRuntime.jsxs(v2.Menu.Root, { children: [
811
- /* @__PURE__ */ jsxRuntime.jsx(
812
- v2.Menu.Trigger,
813
- {
814
- as: designSystem.IconButton,
815
- paddingLeft: 2,
816
- paddingRight: 2,
817
- "aria-label": formatMessage({
818
- id: "content-releases.header.actions.open-release-actions",
819
- defaultMessage: "Release edit and delete menu"
820
- }),
821
- icon: /* @__PURE__ */ jsxRuntime.jsx(icons.More, {}),
822
- variant: "tertiary"
823
- }
824
- ),
825
- /* @__PURE__ */ jsxRuntime.jsxs(v2.Menu.Content, { top: 1, popoverPlacement: "bottom-end", children: [
826
- /* @__PURE__ */ jsxRuntime.jsxs(
827
- designSystem.Flex,
828
- {
829
- alignItems: "center",
830
- justifyContent: "center",
831
- direction: "column",
832
- padding: 1,
833
- width: "100%",
834
- children: [
835
- /* @__PURE__ */ jsxRuntime.jsx(StyledMenuItem, { disabled: !canUpdate, onSelect: toggleEditReleaseModal, children: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { alignItems: "center", gap: 2, hasRadius: true, width: "100%", children: [
836
- /* @__PURE__ */ jsxRuntime.jsx(PencilIcon, {}),
837
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { ellipsis: true, children: formatMessage({
838
- id: "content-releases.header.actions.edit",
839
- defaultMessage: "Edit"
840
- }) })
841
- ] }) }),
842
- /* @__PURE__ */ jsxRuntime.jsx(
843
- StyledMenuItem,
844
- {
845
- disabled: !canDelete,
846
- onSelect: toggleWarningSubmit,
847
- variant: "danger",
848
- children: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { alignItems: "center", gap: 2, hasRadius: true, width: "100%", children: [
849
- /* @__PURE__ */ jsxRuntime.jsx(TrashIcon, {}),
850
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { ellipsis: true, textColor: "danger600", children: formatMessage({
851
- id: "content-releases.header.actions.delete",
852
- defaultMessage: "Delete"
853
- }) })
854
- ] })
855
- }
856
- )
857
- ]
858
- }
859
- ),
860
- /* @__PURE__ */ jsxRuntime.jsxs(
861
- ReleaseInfoWrapper,
862
- {
863
- direction: "column",
864
- justifyContent: "center",
865
- alignItems: "flex-start",
866
- gap: 1,
867
- padding: 5,
868
- children: [
869
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "pi", fontWeight: "bold", children: formatMessage({
870
- id: "content-releases.header.actions.created",
871
- defaultMessage: "Created"
872
- }) }),
873
- /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Typography, { variant: "pi", color: "neutral300", children: [
874
- /* @__PURE__ */ jsxRuntime.jsx(helperPlugin.RelativeTime, { timestamp: new Date(release.createdAt) }),
875
- formatMessage(
876
- {
877
- id: "content-releases.header.actions.created.description",
878
- defaultMessage: "{hasCreatedByUser, select, true { by {createdBy}} other { by deleted user}}"
879
- },
880
- { createdBy: getCreatedByUser(), hasCreatedByUser }
881
- )
882
- ] })
883
- ]
884
- }
885
- )
886
- ] })
887
- ] }),
888
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Button, { size: "S", variant: "tertiary", onClick: handleRefresh, children: formatMessage({
889
- id: "content-releases.header.actions.refresh",
890
- defaultMessage: "Refresh"
891
- }) }),
892
- /* @__PURE__ */ jsxRuntime.jsx(helperPlugin.CheckPermissions, { permissions: index.PERMISSIONS.publish, children: /* @__PURE__ */ jsxRuntime.jsx(
893
- designSystem.Button,
894
- {
895
- size: "S",
896
- variant: "default",
897
- onClick: handlePublishRelease,
898
- loading: isPublishing,
899
- disabled: release.actions.meta.count === 0,
900
- children: formatMessage({
901
- id: "content-releases.header.actions.publish",
902
- defaultMessage: "Publish"
903
- })
904
- }
905
- ) })
906
- ] })
907
- }
908
- ),
909
- children
910
- ] });
911
- };
912
- const GROUP_BY_OPTIONS = ["contentType", "locale", "action"];
913
- const GROUP_BY_OPTIONS_NO_LOCALE = ["contentType", "action"];
914
- const getGroupByOptionLabel = (value) => {
915
- if (value === "locale") {
916
- return {
917
- id: "content-releases.pages.ReleaseDetails.groupBy.option.locales",
918
- defaultMessage: "Locales"
919
- };
920
- }
921
- if (value === "action") {
922
- return {
923
- id: "content-releases.pages.ReleaseDetails.groupBy.option.actions",
924
- defaultMessage: "Actions"
925
- };
926
- }
927
- return {
928
- id: "content-releases.pages.ReleaseDetails.groupBy.option.content-type",
929
- defaultMessage: "Content-Types"
930
- };
931
- };
932
- const DEFAULT_RELEASE_DETAILS_HEADER = [
933
- {
934
- key: "__name__",
935
- fieldSchema: { type: "string" },
936
- metadatas: {
937
- label: {
938
- id: "content-releases.page.ReleaseDetails.table.header.label.name",
939
- defaultMessage: "name"
940
- },
941
- searchable: false,
942
- sortable: false
943
- },
944
- name: "name"
945
- }
946
- ];
947
- const ReleaseDetailsBody = () => {
948
- const { formatMessage } = reactIntl.useIntl();
949
- const { releaseId } = reactRouterDom.useParams();
950
- const [{ query }, setQuery] = helperPlugin.useQueryParams();
951
- const toggleNotification = helperPlugin.useNotification();
952
- const { formatAPIError } = helperPlugin.useAPIErrorHandler();
953
- const {
954
- data: releaseData,
955
- isLoading: isReleaseLoading,
956
- isError: isReleaseError,
957
- error: releaseError
958
- } = index.useGetReleaseQuery({ id: releaseId });
959
- const {
960
- allowedActions: { canUpdate }
961
- } = helperPlugin.useRBAC(index.PERMISSIONS);
962
- const { runHookWaterfall } = helperPlugin.useStrapiApp();
963
- const {
964
- displayedHeaders,
965
- hasI18nEnabled
966
- } = runHookWaterfall(
967
- "ContentReleases/pages/ReleaseDetails/add-locale-in-releases",
968
- {
969
- displayedHeaders: DEFAULT_RELEASE_DETAILS_HEADER,
970
- hasI18nEnabled: false
971
- }
972
- );
973
- const release = releaseData?.data;
974
- const selectedGroupBy = query?.groupBy || "contentType";
975
- const {
976
- isLoading,
977
- isFetching,
978
- isError,
979
- data,
980
- error: releaseActionsError
981
- } = index.useGetReleaseActionsQuery({
982
- ...query,
983
- releaseId
984
- });
985
- const [updateReleaseAction] = index.useUpdateReleaseActionMutation();
986
- const handleChangeType = async (e, actionId, actionPath) => {
987
- const response = await updateReleaseAction({
988
- params: {
989
- releaseId,
990
- actionId
991
- },
992
- body: {
993
- type: e.target.value
994
- },
995
- query,
996
- // We are passing the query params to make optimistic updates
997
- actionPath
998
- // We are passing the action path to found the position in the cache of the action for optimistic updates
999
- });
1000
- if ("error" in response) {
1001
- if (index.isAxiosError(response.error)) {
1002
- toggleNotification({
1003
- type: "warning",
1004
- message: formatAPIError(response.error)
1005
- });
1006
- } else {
1007
- toggleNotification({
1008
- type: "warning",
1009
- message: formatMessage({ id: "notification.error", defaultMessage: "An error occurred" })
1010
- });
1011
- }
1012
- }
1013
- };
1014
- if (isLoading || isReleaseLoading) {
1015
- return /* @__PURE__ */ jsxRuntime.jsx(designSystem.ContentLayout, { children: /* @__PURE__ */ jsxRuntime.jsx(helperPlugin.LoadingIndicatorPage, {}) });
1016
- }
1017
- const releaseActions = data?.data;
1018
- const releaseMeta = data?.meta;
1019
- const contentTypes = releaseMeta?.contentTypes || {};
1020
- const components = releaseMeta?.components || {};
1021
- if (isReleaseError || !release) {
1022
- const errorsArray = [];
1023
- if (releaseError) {
1024
- errorsArray.push({
1025
- code: releaseError.code
1026
- });
1027
- }
1028
- if (releaseActionsError) {
1029
- errorsArray.push({
1030
- code: releaseActionsError.code
1031
- });
1032
- }
1033
- return /* @__PURE__ */ jsxRuntime.jsx(
1034
- reactRouterDom.Redirect,
1035
- {
1036
- to: {
1037
- pathname: "/plugins/content-releases",
1038
- state: {
1039
- errors: errorsArray
1040
- }
1041
- }
1042
- }
1043
- );
1044
- }
1045
- if (isError || !releaseActions) {
1046
- return /* @__PURE__ */ jsxRuntime.jsx(designSystem.ContentLayout, { children: /* @__PURE__ */ jsxRuntime.jsx(helperPlugin.AnErrorOccurred, {}) });
1047
- }
1048
- if (Object.keys(releaseActions).length === 0) {
1049
- return /* @__PURE__ */ jsxRuntime.jsx(designSystem.ContentLayout, { children: /* @__PURE__ */ jsxRuntime.jsx(
1050
- helperPlugin.NoContent,
1051
- {
1052
- content: {
1053
- id: "content-releases.pages.Details.tab.emptyEntries",
1054
- defaultMessage: "This release is empty. Open the Content Manager, select an entry and add it to the release."
1055
- },
1056
- action: /* @__PURE__ */ jsxRuntime.jsx(
1057
- v2.LinkButton,
1058
- {
1059
- as: reactRouterDom.Link,
1060
- to: {
1061
- pathname: "/content-manager"
1062
- },
1063
- style: { textDecoration: "none" },
1064
- variant: "secondary",
1065
- children: formatMessage({
1066
- id: "content-releases.page.Details.button.openContentManager",
1067
- defaultMessage: "Open the Content Manager"
1068
- })
1069
- }
1070
- )
1071
- }
1072
- ) });
1073
- }
1074
- const options = hasI18nEnabled ? GROUP_BY_OPTIONS : GROUP_BY_OPTIONS_NO_LOCALE;
1075
- return /* @__PURE__ */ jsxRuntime.jsx(designSystem.ContentLayout, { children: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { gap: 8, direction: "column", alignItems: "stretch", children: [
1076
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Flex, { children: /* @__PURE__ */ jsxRuntime.jsx(
1077
- designSystem.SingleSelect,
1078
- {
1079
- "aria-label": formatMessage({
1080
- id: "content-releases.pages.ReleaseDetails.groupBy.aria-label",
1081
- defaultMessage: "Group by"
1082
- }),
1083
- customizeContent: (value) => formatMessage(
1084
- {
1085
- id: `content-releases.pages.ReleaseDetails.groupBy.label`,
1086
- defaultMessage: `Group by {groupBy}`
1087
- },
1088
- {
1089
- groupBy: value
1090
- }
1091
- ),
1092
- value: formatMessage(getGroupByOptionLabel(selectedGroupBy)),
1093
- onChange: (value) => setQuery({ groupBy: value }),
1094
- children: options.map((option) => /* @__PURE__ */ jsxRuntime.jsx(designSystem.SingleSelectOption, { value: option, children: formatMessage(getGroupByOptionLabel(option)) }, option))
1095
- }
1096
- ) }),
1097
- Object.keys(releaseActions).map((key) => /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { gap: 4, direction: "column", alignItems: "stretch", children: [
1098
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Flex, { role: "separator", "aria-label": key, children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Badge, { children: key }) }),
1099
- /* @__PURE__ */ jsxRuntime.jsx(
1100
- helperPlugin.Table.Root,
1101
- {
1102
- rows: releaseActions[key].map((item) => ({
1103
- ...item,
1104
- id: Number(item.entry.id)
1105
- })),
1106
- colCount: releaseActions[key].length,
1107
- isLoading,
1108
- isFetching,
1109
- children: /* @__PURE__ */ jsxRuntime.jsxs(helperPlugin.Table.Content, { children: [
1110
- /* @__PURE__ */ jsxRuntime.jsxs(helperPlugin.Table.Head, { children: [
1111
- displayedHeaders.map(({ key: key2, fieldSchema, metadatas, name }) => /* @__PURE__ */ jsxRuntime.jsx(
1112
- helperPlugin.Table.HeaderCell,
1113
- {
1114
- fieldSchemaType: fieldSchema.type,
1115
- label: formatMessage(metadatas.label),
1116
- name
1117
- },
1118
- key2
1119
- )),
1120
- /* @__PURE__ */ jsxRuntime.jsx(
1121
- helperPlugin.Table.HeaderCell,
1122
- {
1123
- fieldSchemaType: "string",
1124
- label: formatMessage({
1125
- id: "content-releases.page.ReleaseDetails.table.header.label.content-type",
1126
- defaultMessage: "content-type"
1127
- }),
1128
- name: "content-type"
1129
- }
1130
- ),
1131
- /* @__PURE__ */ jsxRuntime.jsx(
1132
- helperPlugin.Table.HeaderCell,
1133
- {
1134
- fieldSchemaType: "string",
1135
- label: formatMessage({
1136
- id: "content-releases.page.ReleaseDetails.table.header.label.action",
1137
- defaultMessage: "action"
1138
- }),
1139
- name: "action"
1140
- }
1141
- ),
1142
- !release.releasedAt && /* @__PURE__ */ jsxRuntime.jsx(
1143
- helperPlugin.Table.HeaderCell,
1144
- {
1145
- fieldSchemaType: "string",
1146
- label: formatMessage({
1147
- id: "content-releases.page.ReleaseDetails.table.header.label.status",
1148
- defaultMessage: "status"
1149
- }),
1150
- name: "status"
1151
- }
1152
- )
1153
- ] }),
1154
- /* @__PURE__ */ jsxRuntime.jsx(helperPlugin.Table.LoadingBody, {}),
1155
- /* @__PURE__ */ jsxRuntime.jsx(helperPlugin.Table.Body, { children: releaseActions[key].map(
1156
- ({ id, contentType, locale, type, entry }, actionIndex) => /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Tr, { children: [
1157
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Td, { width: "25%", maxWidth: "200px", children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { ellipsis: true, children: `${contentType.mainFieldValue || entry.id}` }) }),
1158
- hasI18nEnabled && /* @__PURE__ */ jsxRuntime.jsx(designSystem.Td, { width: "10%", children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { children: `${locale?.name ? locale.name : "-"}` }) }),
1159
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Td, { width: "10%", children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { children: contentType.displayName || "" }) }),
1160
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Td, { width: "20%", children: release.releasedAt ? /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { children: formatMessage(
1161
- {
1162
- id: "content-releases.page.ReleaseDetails.table.action-published",
1163
- defaultMessage: "This entry was <b>{isPublish, select, true {published} other {unpublished}}</b>."
1164
- },
1165
- {
1166
- isPublish: type === "publish",
1167
- b: (children) => /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { fontWeight: "bold", children })
1168
- }
1169
- ) }) : /* @__PURE__ */ jsxRuntime.jsx(
1170
- index.ReleaseActionOptions,
1171
- {
1172
- selected: type,
1173
- handleChange: (e) => handleChangeType(e, id, [key, actionIndex]),
1174
- name: `release-action-${id}-type`,
1175
- disabled: !canUpdate
1176
- }
1177
- ) }),
1178
- !release.releasedAt && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
1179
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Td, { width: "20%", minWidth: "200px", children: /* @__PURE__ */ jsxRuntime.jsx(
1180
- EntryValidationText,
1181
- {
1182
- action: type,
1183
- schema: contentTypes?.[contentType.uid],
1184
- components,
1185
- entry
1186
- }
1187
- ) }),
1188
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Td, { children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Flex, { justifyContent: "flex-end", children: /* @__PURE__ */ jsxRuntime.jsxs(index.ReleaseActionMenu.Root, { children: [
1189
- /* @__PURE__ */ jsxRuntime.jsx(
1190
- index.ReleaseActionMenu.ReleaseActionEntryLinkItem,
1191
- {
1192
- contentTypeUid: contentType.uid,
1193
- entryId: entry.id,
1194
- locale: locale?.code
1195
- }
1196
- ),
1197
- /* @__PURE__ */ jsxRuntime.jsx(
1198
- index.ReleaseActionMenu.DeleteReleaseActionItem,
1199
- {
1200
- releaseId: release.id,
1201
- actionId: id
1202
- }
1203
- )
1204
- ] }) }) })
1205
- ] })
1206
- ] }, id)
1207
- ) })
1208
- ] })
1209
- }
1210
- )
1211
- ] }, `releases-group-${key}`)),
1212
- /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { paddingTop: 4, alignItems: "flex-end", justifyContent: "space-between", children: [
1213
- /* @__PURE__ */ jsxRuntime.jsx(helperPlugin.PageSizeURLQuery, { defaultValue: releaseMeta?.pagination?.pageSize.toString() }),
1214
- /* @__PURE__ */ jsxRuntime.jsx(
1215
- helperPlugin.PaginationURLQuery,
1216
- {
1217
- pagination: {
1218
- pageCount: releaseMeta?.pagination?.pageCount || 0
1219
- }
1220
- }
1221
- )
1222
- ] })
1223
- ] }) });
1224
- };
1225
- const ReleaseDetailsPage = () => {
1226
- const { formatMessage } = reactIntl.useIntl();
1227
- const { releaseId } = reactRouterDom.useParams();
1228
- const toggleNotification = helperPlugin.useNotification();
1229
- const { formatAPIError } = helperPlugin.useAPIErrorHandler();
1230
- const { replace } = reactRouterDom.useHistory();
1231
- const [releaseModalShown, setReleaseModalShown] = React__namespace.useState(false);
1232
- const [showWarningSubmit, setWarningSubmit] = React__namespace.useState(false);
1233
- const {
1234
- isLoading: isLoadingDetails,
1235
- data,
1236
- isSuccess: isSuccessDetails
1237
- } = index.useGetReleaseQuery({ id: releaseId });
1238
- const [updateRelease, { isLoading: isSubmittingForm }] = index.useUpdateReleaseMutation();
1239
- const [deleteRelease, { isLoading: isDeletingRelease }] = index.useDeleteReleaseMutation();
1240
- const toggleEditReleaseModal = () => {
1241
- setReleaseModalShown((prev) => !prev);
1242
- };
1243
- const toggleWarningSubmit = () => setWarningSubmit((prevState) => !prevState);
1244
- if (isLoadingDetails) {
1245
- return /* @__PURE__ */ jsxRuntime.jsx(
1246
- ReleaseDetailsLayout,
1247
- {
1248
- toggleEditReleaseModal,
1249
- toggleWarningSubmit,
1250
- children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.ContentLayout, { children: /* @__PURE__ */ jsxRuntime.jsx(helperPlugin.LoadingIndicatorPage, {}) })
1251
- }
1252
- );
1253
- }
1254
- const releaseData = isSuccessDetails && data?.data || null;
1255
- const title = releaseData?.name || "";
1256
- const timezone = releaseData?.timezone ?? null;
1257
- const scheduledAt = releaseData?.scheduledAt && timezone ? dateFnsTz.utcToZonedTime(releaseData.scheduledAt, timezone) : null;
1258
- const date = scheduledAt ? format__default.default(scheduledAt, "yyyy-MM-dd") : null;
1259
- const time = scheduledAt ? format__default.default(scheduledAt, "HH:mm") : "";
1260
- const handleEditRelease = async (values) => {
1261
- const response = await updateRelease({
1262
- id: releaseId,
1263
- name: values.name,
1264
- scheduledAt: values.scheduledAt,
1265
- timezone: values.timezone
1266
- });
1267
- if ("data" in response) {
1268
- toggleNotification({
1269
- type: "success",
1270
- message: formatMessage({
1271
- id: "content-releases.modal.release-updated-notification-success",
1272
- defaultMessage: "Release updated."
1273
- })
1274
- });
1275
- toggleEditReleaseModal();
1276
- } else if (index.isAxiosError(response.error)) {
1277
- toggleNotification({
1278
- type: "warning",
1279
- message: formatAPIError(response.error)
1280
- });
1281
- } else {
1282
- toggleNotification({
1283
- type: "warning",
1284
- message: formatMessage({ id: "notification.error", defaultMessage: "An error occurred" })
1285
- });
1286
- }
1287
- };
1288
- const handleDeleteRelease = async () => {
1289
- const response = await deleteRelease({
1290
- id: releaseId
1291
- });
1292
- if ("data" in response) {
1293
- replace("/plugins/content-releases");
1294
- } else if (index.isAxiosError(response.error)) {
1295
- toggleNotification({
1296
- type: "warning",
1297
- message: formatAPIError(response.error)
1298
- });
1299
- } else {
1300
- toggleNotification({
1301
- type: "warning",
1302
- message: formatMessage({ id: "notification.error", defaultMessage: "An error occurred" })
1303
- });
1304
- }
1305
- };
1306
- return /* @__PURE__ */ jsxRuntime.jsxs(
1307
- ReleaseDetailsLayout,
1308
- {
1309
- toggleEditReleaseModal,
1310
- toggleWarningSubmit,
1311
- children: [
1312
- /* @__PURE__ */ jsxRuntime.jsx(ReleaseDetailsBody, {}),
1313
- releaseModalShown && /* @__PURE__ */ jsxRuntime.jsx(
1314
- ReleaseModal,
1315
- {
1316
- handleClose: toggleEditReleaseModal,
1317
- handleSubmit: handleEditRelease,
1318
- isLoading: isLoadingDetails || isSubmittingForm,
1319
- initialValues: {
1320
- name: title || "",
1321
- scheduledAt,
1322
- date,
1323
- time,
1324
- isScheduled: Boolean(scheduledAt),
1325
- timezone
1326
- }
1327
- }
1328
- ),
1329
- /* @__PURE__ */ jsxRuntime.jsx(
1330
- helperPlugin.ConfirmDialog,
1331
- {
1332
- bodyText: {
1333
- id: "content-releases.dialog.confirmation-message",
1334
- defaultMessage: "Are you sure you want to delete this release?"
1335
- },
1336
- isOpen: showWarningSubmit,
1337
- isConfirmButtonLoading: isDeletingRelease,
1338
- onToggleDialog: toggleWarningSubmit,
1339
- onConfirm: handleDeleteRelease
1340
- }
1341
- )
1342
- ]
1343
- }
1344
- );
1345
- };
1346
- const App = () => {
1347
- return /* @__PURE__ */ jsxRuntime.jsx(helperPlugin.CheckPagePermissions, { permissions: index.PERMISSIONS.main, children: /* @__PURE__ */ jsxRuntime.jsxs(reactRouterDom.Switch, { children: [
1348
- /* @__PURE__ */ jsxRuntime.jsx(reactRouterDom.Route, { exact: true, path: `/plugins/${index.pluginId}`, component: ReleasesPage }),
1349
- /* @__PURE__ */ jsxRuntime.jsx(reactRouterDom.Route, { exact: true, path: `/plugins/${index.pluginId}/:releaseId`, component: ReleaseDetailsPage })
1350
- ] }) });
1351
- };
1352
- exports.App = App;
1353
- //# sourceMappingURL=App-dLXY5ei3.js.map