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

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 (142) 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-Cne--1Z8.mjs +1374 -0
  5. package/dist/_chunks/App-Cne--1Z8.mjs.map +1 -0
  6. package/dist/_chunks/{PurchaseContentReleases-YhAPgpG9.js → PurchaseContentReleases-Be3acS2L.js} +8 -7
  7. package/dist/_chunks/PurchaseContentReleases-Be3acS2L.js.map +1 -0
  8. package/dist/_chunks/{PurchaseContentReleases-Clm0iACO.mjs → PurchaseContentReleases-_MxP6-Dt.mjs} +9 -8
  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-faJDuv3q.js → en-CmYoEnA7.js} +19 -3
  15. package/dist/_chunks/en-CmYoEnA7.js.map +1 -0
  16. package/dist/_chunks/{en-RdapH-9X.mjs → en-D0yVZFqf.mjs} +19 -3
  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 +882 -617
  56. package/dist/server/index.js.map +1 -1
  57. package/dist/server/index.mjs +883 -617
  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-R-kksTW7.mjs +0 -1308
  131. package/dist/_chunks/App-R-kksTW7.mjs.map +0 -1
  132. package/dist/_chunks/App-WZHc_d3m.js +0 -1331
  133. package/dist/_chunks/App-WZHc_d3m.js.map +0 -1
  134. package/dist/_chunks/PurchaseContentReleases-Clm0iACO.mjs.map +0 -1
  135. package/dist/_chunks/PurchaseContentReleases-YhAPgpG9.js.map +0 -1
  136. package/dist/_chunks/en-RdapH-9X.mjs.map +0 -1
  137. package/dist/_chunks/en-faJDuv3q.js.map +0 -1
  138. package/dist/_chunks/index-k6fw6RYi.js +0 -1033
  139. package/dist/_chunks/index-k6fw6RYi.js.map +0 -1
  140. package/dist/_chunks/index-vpSczx8v.mjs +0 -1012
  141. package/dist/_chunks/index-vpSczx8v.mjs.map +0 -1
  142. package/strapi-server.js +0 -3
@@ -1,1331 +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-k6fw6RYi.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 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
- };
92
- return /* @__PURE__ */ jsxRuntime.jsxs(designSystem.ModalLayout, { onClose: handleClose, labelledBy: "title", children: [
93
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.ModalHeader, { children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { id: "title", fontWeight: "bold", textColor: "neutral800", children: formatMessage(
94
- {
95
- id: "content-releases.modal.title",
96
- defaultMessage: "{isCreatingRelease, select, true {New release} other {Edit release}}"
97
- },
98
- { isCreatingRelease }
99
- ) }) }),
100
- /* @__PURE__ */ jsxRuntime.jsx(
101
- formik.Formik,
102
- {
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
- },
114
- validationSchema: RELEASE_SCHEMA,
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
- ] }) }),
216
- /* @__PURE__ */ jsxRuntime.jsx(
217
- designSystem.ModalFooter,
218
- {
219
- startActions: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Button, { onClick: handleClose, variant: "tertiary", name: "cancel", children: formatMessage({ id: "cancel", defaultMessage: "Cancel" }) }),
220
- endActions: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Button, { name: "submit", loading: isLoading, type: "submit", children: formatMessage(
221
- {
222
- id: "content-releases.modal.form.button.submit",
223
- defaultMessage: "{isCreatingRelease, select, true {Continue} other {Save}}"
224
- },
225
- { isCreatingRelease }
226
- ) })
227
- }
228
- )
229
- ] })
230
- }
231
- )
232
- ] });
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
- };
596
- const ReleaseInfoWrapper = styled__default.default(designSystem.Flex)`
597
- align-self: stretch;
598
- border-bottom-right-radius: ${({ theme }) => theme.borderRadius};
599
- border-bottom-left-radius: ${({ theme }) => theme.borderRadius};
600
- border-top: 1px solid ${({ theme }) => theme.colors.neutral150};
601
- `;
602
- const StyledMenuItem = styled__default.default(v2.Menu.Item)`
603
- svg path {
604
- fill: ${({ theme, disabled }) => disabled && theme.colors.neutral500};
605
- }
606
- span {
607
- color: ${({ theme, disabled }) => disabled && theme.colors.neutral500};
608
- }
609
-
610
- &:hover {
611
- background: ${({ theme, variant = "neutral" }) => theme.colors[`${variant}100`]};
612
- }
613
- `;
614
- const PencilIcon = styled__default.default(icons.Pencil)`
615
- width: ${({ theme }) => theme.spaces[3]};
616
- height: ${({ theme }) => theme.spaces[3]};
617
- path {
618
- fill: ${({ theme }) => theme.colors.neutral600};
619
- }
620
- `;
621
- const TrashIcon = styled__default.default(icons.Trash)`
622
- width: ${({ theme }) => theme.spaces[3]};
623
- height: ${({ theme }) => theme.spaces[3]};
624
- path {
625
- fill: ${({ theme }) => theme.colors.danger600};
626
- }
627
- `;
628
- const TypographyMaxWidth = styled__default.default(designSystem.Typography)`
629
- max-width: 300px;
630
- `;
631
- const EntryValidationText = ({ action, schema, components, entry }) => {
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
- }
651
- if (action == "publish") {
652
- return /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { gap: 2, children: [
653
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Icon, { color: "success600", as: icons.CheckCircle }),
654
- entry.publishedAt ? /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { textColor: "success600", fontWeight: "bold", children: formatMessage({
655
- id: "content-releases.pages.ReleaseDetails.entry-validation.already-published",
656
- defaultMessage: "Already published"
657
- }) }) : /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { children: formatMessage({
658
- id: "content-releases.pages.ReleaseDetails.entry-validation.ready-to-publish",
659
- defaultMessage: "Ready to publish"
660
- }) })
661
- ] });
662
- }
663
- return /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { gap: 2, children: [
664
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Icon, { color: "success600", as: icons.CheckCircle }),
665
- !entry.publishedAt ? /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { textColor: "success600", fontWeight: "bold", children: formatMessage({
666
- id: "content-releases.pages.ReleaseDetails.entry-validation.already-unpublished",
667
- defaultMessage: "Already unpublished"
668
- }) }) : /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { children: formatMessage({
669
- id: "content-releases.pages.ReleaseDetails.entry-validation.ready-to-unpublish",
670
- defaultMessage: "Ready to unpublish"
671
- }) })
672
- ] });
673
- };
674
- const ReleaseDetailsLayout = ({
675
- toggleEditReleaseModal,
676
- toggleWarningSubmit,
677
- children
678
- }) => {
679
- const { formatMessage, formatDate, formatTime } = reactIntl.useIntl();
680
- const { releaseId } = reactRouterDom.useParams();
681
- const {
682
- data,
683
- isLoading: isLoadingDetails,
684
- isError,
685
- error
686
- } = index.useGetReleaseQuery({ id: releaseId });
687
- const [publishRelease, { isLoading: isPublishing }] = index.usePublishReleaseMutation();
688
- const toggleNotification = helperPlugin.useNotification();
689
- const { formatAPIError } = helperPlugin.useAPIErrorHandler();
690
- const {
691
- allowedActions: { canUpdate, canDelete }
692
- } = helperPlugin.useRBAC(index.PERMISSIONS);
693
- const dispatch = index.useTypedDispatch();
694
- const { trackUsage } = helperPlugin.useTracking();
695
- const release = data?.data;
696
- const handlePublishRelease = async () => {
697
- const response = await publishRelease({ id: releaseId });
698
- if ("data" in response) {
699
- toggleNotification({
700
- type: "success",
701
- message: formatMessage({
702
- id: "content-releases.pages.ReleaseDetails.publish-notification-success",
703
- defaultMessage: "Release was published successfully."
704
- })
705
- });
706
- const { totalEntries: totalEntries2, totalPublishedEntries, totalUnpublishedEntries } = response.data.meta;
707
- trackUsage("didPublishRelease", {
708
- totalEntries: totalEntries2,
709
- totalPublishedEntries,
710
- totalUnpublishedEntries
711
- });
712
- } else if (index.isAxiosError(response.error)) {
713
- toggleNotification({
714
- type: "warning",
715
- message: formatAPIError(response.error)
716
- });
717
- } else {
718
- toggleNotification({
719
- type: "warning",
720
- message: formatMessage({ id: "notification.error", defaultMessage: "An error occurred" })
721
- });
722
- }
723
- };
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;
738
- };
739
- if (isLoadingDetails) {
740
- return /* @__PURE__ */ jsxRuntime.jsx(designSystem.Main, { "aria-busy": isLoadingDetails, children: /* @__PURE__ */ jsxRuntime.jsx(helperPlugin.LoadingIndicatorPage, {}) });
741
- }
742
- if (isError || !release) {
743
- return /* @__PURE__ */ jsxRuntime.jsx(
744
- reactRouterDom.Redirect,
745
- {
746
- to: {
747
- pathname: "/plugins/content-releases",
748
- state: {
749
- errors: [
750
- {
751
- code: error?.code
752
- }
753
- ]
754
- }
755
- }
756
- }
757
- );
758
- }
759
- const totalEntries = release.actions.meta.count || 0;
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
- ) : "";
789
- return /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Main, { "aria-busy": isLoadingDetails, children: [
790
- /* @__PURE__ */ jsxRuntime.jsx(
791
- designSystem.HeaderLayout,
792
- {
793
- title: release.name,
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
- ] }),
798
- navigationAction: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Link, { startIcon: /* @__PURE__ */ jsxRuntime.jsx(icons.ArrowLeft, {}), to: "/plugins/content-releases", children: formatMessage({
799
- id: "global.back",
800
- defaultMessage: "Back"
801
- }) }),
802
- primaryAction: !release.releasedAt && /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { gap: 2, children: [
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
- }) }),
885
- /* @__PURE__ */ jsxRuntime.jsx(helperPlugin.CheckPermissions, { permissions: index.PERMISSIONS.publish, children: /* @__PURE__ */ jsxRuntime.jsx(
886
- designSystem.Button,
887
- {
888
- size: "S",
889
- variant: "default",
890
- onClick: handlePublishRelease,
891
- loading: isPublishing,
892
- disabled: release.actions.meta.count === 0,
893
- children: formatMessage({
894
- id: "content-releases.header.actions.publish",
895
- defaultMessage: "Publish"
896
- })
897
- }
898
- ) })
899
- ] })
900
- }
901
- ),
902
- children
903
- ] });
904
- };
905
- const GROUP_BY_OPTIONS = ["contentType", "locale", "action"];
906
- const getGroupByOptionLabel = (value) => {
907
- if (value === "locale") {
908
- return {
909
- id: "content-releases.pages.ReleaseDetails.groupBy.option.locales",
910
- defaultMessage: "Locales"
911
- };
912
- }
913
- if (value === "action") {
914
- return {
915
- id: "content-releases.pages.ReleaseDetails.groupBy.option.actions",
916
- defaultMessage: "Actions"
917
- };
918
- }
919
- return {
920
- id: "content-releases.pages.ReleaseDetails.groupBy.option.content-type",
921
- defaultMessage: "Content-Types"
922
- };
923
- };
924
- const ReleaseDetailsBody = () => {
925
- const { formatMessage } = reactIntl.useIntl();
926
- const { releaseId } = reactRouterDom.useParams();
927
- const [{ query }, setQuery] = helperPlugin.useQueryParams();
928
- const toggleNotification = helperPlugin.useNotification();
929
- const { formatAPIError } = helperPlugin.useAPIErrorHandler();
930
- const {
931
- data: releaseData,
932
- isLoading: isReleaseLoading,
933
- isError: isReleaseError,
934
- error: releaseError
935
- } = index.useGetReleaseQuery({ id: releaseId });
936
- const {
937
- allowedActions: { canUpdate }
938
- } = helperPlugin.useRBAC(index.PERMISSIONS);
939
- const release = releaseData?.data;
940
- const selectedGroupBy = query?.groupBy || "contentType";
941
- const {
942
- isLoading,
943
- isFetching,
944
- isError,
945
- data,
946
- error: releaseActionsError
947
- } = index.useGetReleaseActionsQuery({
948
- ...query,
949
- releaseId
950
- });
951
- const [updateReleaseAction] = index.useUpdateReleaseActionMutation();
952
- const handleChangeType = async (e, actionId, actionPath) => {
953
- const response = await updateReleaseAction({
954
- params: {
955
- releaseId,
956
- actionId
957
- },
958
- body: {
959
- type: e.target.value
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
965
- });
966
- if ("error" in response) {
967
- if (index.isAxiosError(response.error)) {
968
- toggleNotification({
969
- type: "warning",
970
- message: formatAPIError(response.error)
971
- });
972
- } else {
973
- toggleNotification({
974
- type: "warning",
975
- message: formatMessage({ id: "notification.error", defaultMessage: "An error occurred" })
976
- });
977
- }
978
- }
979
- };
980
- if (isLoading || isReleaseLoading) {
981
- return /* @__PURE__ */ jsxRuntime.jsx(designSystem.ContentLayout, { children: /* @__PURE__ */ jsxRuntime.jsx(helperPlugin.LoadingIndicatorPage, {}) });
982
- }
983
- const releaseActions = data?.data;
984
- const releaseMeta = data?.meta;
985
- const contentTypes = releaseMeta?.contentTypes || {};
986
- const components = releaseMeta?.components || {};
987
- if (isReleaseError || !release) {
988
- const errorsArray = [];
989
- if (releaseError) {
990
- errorsArray.push({
991
- code: releaseError.code
992
- });
993
- }
994
- if (releaseActionsError) {
995
- errorsArray.push({
996
- code: releaseActionsError.code
997
- });
998
- }
999
- return /* @__PURE__ */ jsxRuntime.jsx(
1000
- reactRouterDom.Redirect,
1001
- {
1002
- to: {
1003
- pathname: "/plugins/content-releases",
1004
- state: {
1005
- errors: errorsArray
1006
- }
1007
- }
1008
- }
1009
- );
1010
- }
1011
- if (isError || !releaseActions) {
1012
- return /* @__PURE__ */ jsxRuntime.jsx(designSystem.ContentLayout, { children: /* @__PURE__ */ jsxRuntime.jsx(helperPlugin.AnErrorOccurred, {}) });
1013
- }
1014
- if (Object.keys(releaseActions).length === 0) {
1015
- return /* @__PURE__ */ jsxRuntime.jsx(designSystem.ContentLayout, { children: /* @__PURE__ */ jsxRuntime.jsx(
1016
- helperPlugin.NoContent,
1017
- {
1018
- content: {
1019
- id: "content-releases.pages.Details.tab.emptyEntries",
1020
- defaultMessage: "This release is empty. Open the Content Manager, select an entry and add it to the release."
1021
- },
1022
- action: /* @__PURE__ */ jsxRuntime.jsx(
1023
- v2.LinkButton,
1024
- {
1025
- as: reactRouterDom.Link,
1026
- to: {
1027
- pathname: "/content-manager"
1028
- },
1029
- style: { textDecoration: "none" },
1030
- variant: "secondary",
1031
- children: formatMessage({
1032
- id: "content-releases.page.Details.button.openContentManager",
1033
- defaultMessage: "Open the Content Manager"
1034
- })
1035
- }
1036
- )
1037
- }
1038
- ) });
1039
- }
1040
- return /* @__PURE__ */ jsxRuntime.jsx(designSystem.ContentLayout, { children: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { gap: 8, direction: "column", alignItems: "stretch", children: [
1041
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Flex, { children: /* @__PURE__ */ jsxRuntime.jsx(
1042
- designSystem.SingleSelect,
1043
- {
1044
- "aria-label": formatMessage({
1045
- id: "content-releases.pages.ReleaseDetails.groupBy.aria-label",
1046
- defaultMessage: "Group by"
1047
- }),
1048
- customizeContent: (value) => formatMessage(
1049
- {
1050
- id: `content-releases.pages.ReleaseDetails.groupBy.label`,
1051
- defaultMessage: `Group by {groupBy}`
1052
- },
1053
- {
1054
- groupBy: value
1055
- }
1056
- ),
1057
- value: formatMessage(getGroupByOptionLabel(selectedGroupBy)),
1058
- onChange: (value) => setQuery({ groupBy: value }),
1059
- children: GROUP_BY_OPTIONS.map((option) => /* @__PURE__ */ jsxRuntime.jsx(designSystem.SingleSelectOption, { value: option, children: formatMessage(getGroupByOptionLabel(option)) }, option))
1060
- }
1061
- ) }),
1062
- Object.keys(releaseActions).map((key) => /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { gap: 4, direction: "column", alignItems: "stretch", children: [
1063
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Flex, { role: "separator", "aria-label": key, children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Badge, { children: key }) }),
1064
- /* @__PURE__ */ jsxRuntime.jsx(
1065
- helperPlugin.Table.Root,
1066
- {
1067
- rows: releaseActions[key].map((item) => ({
1068
- ...item,
1069
- id: Number(item.entry.id)
1070
- })),
1071
- colCount: releaseActions[key].length,
1072
- isLoading,
1073
- isFetching,
1074
- children: /* @__PURE__ */ jsxRuntime.jsxs(helperPlugin.Table.Content, { children: [
1075
- /* @__PURE__ */ jsxRuntime.jsxs(helperPlugin.Table.Head, { children: [
1076
- /* @__PURE__ */ jsxRuntime.jsx(
1077
- helperPlugin.Table.HeaderCell,
1078
- {
1079
- fieldSchemaType: "string",
1080
- label: formatMessage({
1081
- id: "content-releases.page.ReleaseDetails.table.header.label.name",
1082
- defaultMessage: "name"
1083
- }),
1084
- name: "name"
1085
- }
1086
- ),
1087
- /* @__PURE__ */ jsxRuntime.jsx(
1088
- helperPlugin.Table.HeaderCell,
1089
- {
1090
- fieldSchemaType: "string",
1091
- label: formatMessage({
1092
- id: "content-releases.page.ReleaseDetails.table.header.label.locale",
1093
- defaultMessage: "locale"
1094
- }),
1095
- name: "locale"
1096
- }
1097
- ),
1098
- /* @__PURE__ */ jsxRuntime.jsx(
1099
- helperPlugin.Table.HeaderCell,
1100
- {
1101
- fieldSchemaType: "string",
1102
- label: formatMessage({
1103
- id: "content-releases.page.ReleaseDetails.table.header.label.content-type",
1104
- defaultMessage: "content-type"
1105
- }),
1106
- name: "content-type"
1107
- }
1108
- ),
1109
- /* @__PURE__ */ jsxRuntime.jsx(
1110
- helperPlugin.Table.HeaderCell,
1111
- {
1112
- fieldSchemaType: "string",
1113
- label: formatMessage({
1114
- id: "content-releases.page.ReleaseDetails.table.header.label.action",
1115
- defaultMessage: "action"
1116
- }),
1117
- name: "action"
1118
- }
1119
- ),
1120
- !release.releasedAt && /* @__PURE__ */ jsxRuntime.jsx(
1121
- helperPlugin.Table.HeaderCell,
1122
- {
1123
- fieldSchemaType: "string",
1124
- label: formatMessage({
1125
- id: "content-releases.page.ReleaseDetails.table.header.label.status",
1126
- defaultMessage: "status"
1127
- }),
1128
- name: "status"
1129
- }
1130
- )
1131
- ] }),
1132
- /* @__PURE__ */ jsxRuntime.jsx(helperPlugin.Table.LoadingBody, {}),
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
- ) })
1186
- ] })
1187
- }
1188
- )
1189
- ] }, `releases-group-${key}`)),
1190
- /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { paddingTop: 4, alignItems: "flex-end", justifyContent: "space-between", children: [
1191
- /* @__PURE__ */ jsxRuntime.jsx(helperPlugin.PageSizeURLQuery, { defaultValue: releaseMeta?.pagination?.pageSize.toString() }),
1192
- /* @__PURE__ */ jsxRuntime.jsx(
1193
- helperPlugin.PaginationURLQuery,
1194
- {
1195
- pagination: {
1196
- pageCount: releaseMeta?.pagination?.pageCount || 0
1197
- }
1198
- }
1199
- )
1200
- ] })
1201
- ] }) });
1202
- };
1203
- const ReleaseDetailsPage = () => {
1204
- const { formatMessage } = reactIntl.useIntl();
1205
- const { releaseId } = reactRouterDom.useParams();
1206
- const toggleNotification = helperPlugin.useNotification();
1207
- const { formatAPIError } = helperPlugin.useAPIErrorHandler();
1208
- const { replace } = reactRouterDom.useHistory();
1209
- const [releaseModalShown, setReleaseModalShown] = React__namespace.useState(false);
1210
- const [showWarningSubmit, setWarningSubmit] = React__namespace.useState(false);
1211
- const {
1212
- isLoading: isLoadingDetails,
1213
- data,
1214
- isSuccess: isSuccessDetails
1215
- } = index.useGetReleaseQuery({ id: releaseId });
1216
- const [updateRelease, { isLoading: isSubmittingForm }] = index.useUpdateReleaseMutation();
1217
- const [deleteRelease, { isLoading: isDeletingRelease }] = index.useDeleteReleaseMutation();
1218
- const toggleEditReleaseModal = () => {
1219
- setReleaseModalShown((prev) => !prev);
1220
- };
1221
- const toggleWarningSubmit = () => setWarningSubmit((prevState) => !prevState);
1222
- if (isLoadingDetails) {
1223
- return /* @__PURE__ */ jsxRuntime.jsx(
1224
- ReleaseDetailsLayout,
1225
- {
1226
- toggleEditReleaseModal,
1227
- toggleWarningSubmit,
1228
- children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.ContentLayout, { children: /* @__PURE__ */ jsxRuntime.jsx(helperPlugin.LoadingIndicatorPage, {}) })
1229
- }
1230
- );
1231
- }
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") : "";
1238
- const handleEditRelease = async (values) => {
1239
- const response = await updateRelease({
1240
- id: releaseId,
1241
- name: values.name,
1242
- scheduledAt: values.scheduledAt,
1243
- timezone: values.timezone
1244
- });
1245
- if ("data" in response) {
1246
- toggleNotification({
1247
- type: "success",
1248
- message: formatMessage({
1249
- id: "content-releases.modal.release-updated-notification-success",
1250
- defaultMessage: "Release updated."
1251
- })
1252
- });
1253
- } else if (index.isAxiosError(response.error)) {
1254
- toggleNotification({
1255
- type: "warning",
1256
- message: formatAPIError(response.error)
1257
- });
1258
- } else {
1259
- toggleNotification({
1260
- type: "warning",
1261
- message: formatMessage({ id: "notification.error", defaultMessage: "An error occurred" })
1262
- });
1263
- }
1264
- toggleEditReleaseModal();
1265
- };
1266
- const handleDeleteRelease = async () => {
1267
- const response = await deleteRelease({
1268
- id: releaseId
1269
- });
1270
- if ("data" in response) {
1271
- replace("/plugins/content-releases");
1272
- } else if (index.isAxiosError(response.error)) {
1273
- toggleNotification({
1274
- type: "warning",
1275
- message: formatAPIError(response.error)
1276
- });
1277
- } else {
1278
- toggleNotification({
1279
- type: "warning",
1280
- message: formatMessage({ id: "notification.error", defaultMessage: "An error occurred" })
1281
- });
1282
- }
1283
- };
1284
- return /* @__PURE__ */ jsxRuntime.jsxs(
1285
- ReleaseDetailsLayout,
1286
- {
1287
- toggleEditReleaseModal,
1288
- toggleWarningSubmit,
1289
- children: [
1290
- /* @__PURE__ */ jsxRuntime.jsx(ReleaseDetailsBody, {}),
1291
- releaseModalShown && /* @__PURE__ */ jsxRuntime.jsx(
1292
- ReleaseModal,
1293
- {
1294
- handleClose: toggleEditReleaseModal,
1295
- handleSubmit: handleEditRelease,
1296
- isLoading: isLoadingDetails || isSubmittingForm,
1297
- initialValues: {
1298
- name: title || "",
1299
- scheduledAt,
1300
- date,
1301
- time,
1302
- isScheduled: Boolean(scheduledAt),
1303
- timezone
1304
- }
1305
- }
1306
- ),
1307
- /* @__PURE__ */ jsxRuntime.jsx(
1308
- helperPlugin.ConfirmDialog,
1309
- {
1310
- bodyText: {
1311
- id: "content-releases.dialog.confirmation-message",
1312
- defaultMessage: "Are you sure you want to delete this release?"
1313
- },
1314
- isOpen: showWarningSubmit,
1315
- isConfirmButtonLoading: isDeletingRelease,
1316
- onToggleDialog: toggleWarningSubmit,
1317
- onConfirm: handleDeleteRelease
1318
- }
1319
- )
1320
- ]
1321
- }
1322
- );
1323
- };
1324
- const App = () => {
1325
- return /* @__PURE__ */ jsxRuntime.jsx(helperPlugin.CheckPagePermissions, { permissions: index.PERMISSIONS.main, children: /* @__PURE__ */ jsxRuntime.jsxs(reactRouterDom.Switch, { children: [
1326
- /* @__PURE__ */ jsxRuntime.jsx(reactRouterDom.Route, { exact: true, path: `/plugins/${index.pluginId}`, component: ReleasesPage }),
1327
- /* @__PURE__ */ jsxRuntime.jsx(reactRouterDom.Route, { exact: true, path: `/plugins/${index.pluginId}/:releaseId`, component: ReleaseDetailsPage })
1328
- ] }) });
1329
- };
1330
- exports.App = App;
1331
- //# sourceMappingURL=App-WZHc_d3m.js.map