@strapi/content-releases 0.0.0-next.fc231041206e6f3999b094160cfa05db2892ad54 → 0.0.0-next.fc9d26d995624dc886b29f563e1de655d47e6609

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 (146) hide show
  1. package/LICENSE +17 -1
  2. package/dist/admin/chunks/App-B9yCdSLJ.js +1866 -0
  3. package/dist/admin/chunks/App-B9yCdSLJ.js.map +1 -0
  4. package/dist/admin/chunks/App-CZiJBsId.js +1845 -0
  5. package/dist/admin/chunks/App-CZiJBsId.js.map +1 -0
  6. package/dist/admin/chunks/PurchaseContentReleases-BCME5SQU.js +55 -0
  7. package/dist/admin/chunks/PurchaseContentReleases-BCME5SQU.js.map +1 -0
  8. package/dist/admin/chunks/PurchaseContentReleases-S1ccDSwp.js +53 -0
  9. package/dist/admin/chunks/PurchaseContentReleases-S1ccDSwp.js.map +1 -0
  10. package/dist/admin/chunks/ReleasesSettingsPage-Csq9aGu9.js +206 -0
  11. package/dist/admin/chunks/ReleasesSettingsPage-Csq9aGu9.js.map +1 -0
  12. package/dist/admin/chunks/ReleasesSettingsPage-DFVGppsl.js +208 -0
  13. package/dist/admin/chunks/ReleasesSettingsPage-DFVGppsl.js.map +1 -0
  14. package/dist/admin/chunks/en-B2EeDoOz.js +101 -0
  15. package/dist/admin/chunks/en-B2EeDoOz.js.map +1 -0
  16. package/dist/admin/chunks/en-BzpFfVeO.js +103 -0
  17. package/dist/admin/chunks/en-BzpFfVeO.js.map +1 -0
  18. package/dist/admin/chunks/index-1nn-zHX-.js +1657 -0
  19. package/dist/admin/chunks/index-1nn-zHX-.js.map +1 -0
  20. package/dist/admin/chunks/index-BexsXldu.js +1618 -0
  21. package/dist/admin/chunks/index-BexsXldu.js.map +1 -0
  22. package/dist/admin/chunks/schemas-DMt8h1z-.js +43 -0
  23. package/dist/admin/chunks/schemas-DMt8h1z-.js.map +1 -0
  24. package/dist/admin/chunks/schemas-DS7NeFDN.js +65 -0
  25. package/dist/admin/chunks/schemas-DS7NeFDN.js.map +1 -0
  26. package/dist/admin/index.js +18 -17
  27. package/dist/admin/index.mjs +13 -19
  28. package/dist/admin/index.mjs.map +1 -1
  29. package/dist/admin/src/components/EntryValidationPopover.d.ts +13 -0
  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 +2203 -1573
  56. package/dist/server/index.js.map +1 -1
  57. package/dist/server/index.mjs +2197 -1566
  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 +2111 -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 +1824 -0
  108. package/dist/server/src/services/index.d.ts.map +1 -0
  109. package/dist/server/src/services/release-action.d.ts +34 -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 +136 -0
  122. package/dist/shared/contracts/release-actions.d.ts.map +1 -0
  123. package/dist/shared/contracts/releases.d.ts +183 -0
  124. package/dist/shared/contracts/releases.d.ts.map +1 -0
  125. package/dist/shared/contracts/settings.d.ts +38 -0
  126. package/dist/shared/contracts/settings.d.ts.map +1 -0
  127. package/dist/shared/types.d.ts +23 -0
  128. package/dist/shared/types.d.ts.map +1 -0
  129. package/package.json +40 -42
  130. package/dist/_chunks/App-HVXzE3i3.mjs +0 -1313
  131. package/dist/_chunks/App-HVXzE3i3.mjs.map +0 -1
  132. package/dist/_chunks/App-l62gIUTX.js +0 -1336
  133. package/dist/_chunks/App-l62gIUTX.js.map +0 -1
  134. package/dist/_chunks/PurchaseContentReleases-Clm0iACO.mjs +0 -51
  135. package/dist/_chunks/PurchaseContentReleases-Clm0iACO.mjs.map +0 -1
  136. package/dist/_chunks/PurchaseContentReleases-YhAPgpG9.js +0 -51
  137. package/dist/_chunks/PurchaseContentReleases-YhAPgpG9.js.map +0 -1
  138. package/dist/_chunks/en-RdapH-9X.mjs +0 -77
  139. package/dist/_chunks/en-RdapH-9X.mjs.map +0 -1
  140. package/dist/_chunks/en-faJDuv3q.js +0 -77
  141. package/dist/_chunks/en-faJDuv3q.js.map +0 -1
  142. package/dist/_chunks/index-ML_b3php.js +0 -1034
  143. package/dist/_chunks/index-ML_b3php.js.map +0 -1
  144. package/dist/_chunks/index-Ys87ROOe.mjs +0 -1013
  145. package/dist/_chunks/index-Ys87ROOe.mjs.map +0 -1
  146. package/strapi-server.js +0 -3
@@ -1,1336 +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-ML_b3php.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(
726
- index.releaseApi.util.invalidateTags([
727
- { type: "ReleaseAction", id: "LIST" },
728
- { type: "Release", id: releaseId }
729
- ])
730
- );
731
- };
732
- const getCreatedByUser = () => {
733
- if (!release?.createdBy) {
734
- return null;
735
- }
736
- if (release.createdBy.username) {
737
- return release.createdBy.username;
738
- }
739
- if (release.createdBy.firstname) {
740
- return `${release.createdBy.firstname} ${release.createdBy.lastname || ""}`.trim();
741
- }
742
- return release.createdBy.email;
743
- };
744
- if (isLoadingDetails) {
745
- return /* @__PURE__ */ jsxRuntime.jsx(designSystem.Main, { "aria-busy": isLoadingDetails, children: /* @__PURE__ */ jsxRuntime.jsx(helperPlugin.LoadingIndicatorPage, {}) });
746
- }
747
- if (isError || !release) {
748
- return /* @__PURE__ */ jsxRuntime.jsx(
749
- reactRouterDom.Redirect,
750
- {
751
- to: {
752
- pathname: "/plugins/content-releases",
753
- state: {
754
- errors: [
755
- {
756
- code: error?.code
757
- }
758
- ]
759
- }
760
- }
761
- }
762
- );
763
- }
764
- const totalEntries = release.actions.meta.count || 0;
765
- const hasCreatedByUser = Boolean(getCreatedByUser());
766
- const isScheduled = release.scheduledAt && release.timezone;
767
- const numberOfEntriesText = formatMessage(
768
- {
769
- id: "content-releases.pages.Details.header-subtitle",
770
- defaultMessage: "{number, plural, =0 {No entries} one {# entry} other {# entries}}"
771
- },
772
- { number: totalEntries }
773
- );
774
- const scheduledText = isScheduled ? formatMessage(
775
- {
776
- id: "content-releases.pages.ReleaseDetails.header-subtitle.scheduled",
777
- defaultMessage: "Scheduled for {date} at {time} ({offset})"
778
- },
779
- {
780
- date: formatDate(new Date(release.scheduledAt), {
781
- weekday: "long",
782
- day: "numeric",
783
- month: "long",
784
- year: "numeric",
785
- timeZone: release.timezone
786
- }),
787
- time: formatTime(new Date(release.scheduledAt), {
788
- timeZone: release.timezone,
789
- hourCycle: "h23"
790
- }),
791
- offset: index.getTimezoneOffset(release.timezone, new Date(release.scheduledAt))
792
- }
793
- ) : "";
794
- return /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Main, { "aria-busy": isLoadingDetails, children: [
795
- /* @__PURE__ */ jsxRuntime.jsx(
796
- designSystem.HeaderLayout,
797
- {
798
- title: release.name,
799
- subtitle: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { gap: 2, lineHeight: 6, children: [
800
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { textColor: "neutral600", variant: "epsilon", children: numberOfEntriesText + (isScheduled ? ` - ${scheduledText}` : "") }),
801
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Badge, { ...getBadgeProps(release.status), children: release.status })
802
- ] }),
803
- navigationAction: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Link, { startIcon: /* @__PURE__ */ jsxRuntime.jsx(icons.ArrowLeft, {}), to: "/plugins/content-releases", children: formatMessage({
804
- id: "global.back",
805
- defaultMessage: "Back"
806
- }) }),
807
- primaryAction: !release.releasedAt && /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { gap: 2, children: [
808
- /* @__PURE__ */ jsxRuntime.jsxs(v2.Menu.Root, { children: [
809
- /* @__PURE__ */ jsxRuntime.jsx(
810
- v2.Menu.Trigger,
811
- {
812
- as: designSystem.IconButton,
813
- paddingLeft: 2,
814
- paddingRight: 2,
815
- "aria-label": formatMessage({
816
- id: "content-releases.header.actions.open-release-actions",
817
- defaultMessage: "Release edit and delete menu"
818
- }),
819
- icon: /* @__PURE__ */ jsxRuntime.jsx(icons.More, {}),
820
- variant: "tertiary"
821
- }
822
- ),
823
- /* @__PURE__ */ jsxRuntime.jsxs(v2.Menu.Content, { top: 1, popoverPlacement: "bottom-end", children: [
824
- /* @__PURE__ */ jsxRuntime.jsxs(
825
- designSystem.Flex,
826
- {
827
- alignItems: "center",
828
- justifyContent: "center",
829
- direction: "column",
830
- padding: 1,
831
- width: "100%",
832
- children: [
833
- /* @__PURE__ */ jsxRuntime.jsx(StyledMenuItem, { disabled: !canUpdate, onSelect: toggleEditReleaseModal, children: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { alignItems: "center", gap: 2, hasRadius: true, width: "100%", children: [
834
- /* @__PURE__ */ jsxRuntime.jsx(PencilIcon, {}),
835
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { ellipsis: true, children: formatMessage({
836
- id: "content-releases.header.actions.edit",
837
- defaultMessage: "Edit"
838
- }) })
839
- ] }) }),
840
- /* @__PURE__ */ jsxRuntime.jsx(
841
- StyledMenuItem,
842
- {
843
- disabled: !canDelete,
844
- onSelect: toggleWarningSubmit,
845
- variant: "danger",
846
- children: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { alignItems: "center", gap: 2, hasRadius: true, width: "100%", children: [
847
- /* @__PURE__ */ jsxRuntime.jsx(TrashIcon, {}),
848
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { ellipsis: true, textColor: "danger600", children: formatMessage({
849
- id: "content-releases.header.actions.delete",
850
- defaultMessage: "Delete"
851
- }) })
852
- ] })
853
- }
854
- )
855
- ]
856
- }
857
- ),
858
- /* @__PURE__ */ jsxRuntime.jsxs(
859
- ReleaseInfoWrapper,
860
- {
861
- direction: "column",
862
- justifyContent: "center",
863
- alignItems: "flex-start",
864
- gap: 1,
865
- padding: 5,
866
- children: [
867
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "pi", fontWeight: "bold", children: formatMessage({
868
- id: "content-releases.header.actions.created",
869
- defaultMessage: "Created"
870
- }) }),
871
- /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Typography, { variant: "pi", color: "neutral300", children: [
872
- /* @__PURE__ */ jsxRuntime.jsx(helperPlugin.RelativeTime, { timestamp: new Date(release.createdAt) }),
873
- formatMessage(
874
- {
875
- id: "content-releases.header.actions.created.description",
876
- defaultMessage: "{hasCreatedByUser, select, true { by {createdBy}} other { by deleted user}}"
877
- },
878
- { createdBy: getCreatedByUser(), hasCreatedByUser }
879
- )
880
- ] })
881
- ]
882
- }
883
- )
884
- ] })
885
- ] }),
886
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Button, { size: "S", variant: "tertiary", onClick: handleRefresh, children: formatMessage({
887
- id: "content-releases.header.actions.refresh",
888
- defaultMessage: "Refresh"
889
- }) }),
890
- /* @__PURE__ */ jsxRuntime.jsx(helperPlugin.CheckPermissions, { permissions: index.PERMISSIONS.publish, children: /* @__PURE__ */ jsxRuntime.jsx(
891
- designSystem.Button,
892
- {
893
- size: "S",
894
- variant: "default",
895
- onClick: handlePublishRelease,
896
- loading: isPublishing,
897
- disabled: release.actions.meta.count === 0,
898
- children: formatMessage({
899
- id: "content-releases.header.actions.publish",
900
- defaultMessage: "Publish"
901
- })
902
- }
903
- ) })
904
- ] })
905
- }
906
- ),
907
- children
908
- ] });
909
- };
910
- const GROUP_BY_OPTIONS = ["contentType", "locale", "action"];
911
- const getGroupByOptionLabel = (value) => {
912
- if (value === "locale") {
913
- return {
914
- id: "content-releases.pages.ReleaseDetails.groupBy.option.locales",
915
- defaultMessage: "Locales"
916
- };
917
- }
918
- if (value === "action") {
919
- return {
920
- id: "content-releases.pages.ReleaseDetails.groupBy.option.actions",
921
- defaultMessage: "Actions"
922
- };
923
- }
924
- return {
925
- id: "content-releases.pages.ReleaseDetails.groupBy.option.content-type",
926
- defaultMessage: "Content-Types"
927
- };
928
- };
929
- const ReleaseDetailsBody = () => {
930
- const { formatMessage } = reactIntl.useIntl();
931
- const { releaseId } = reactRouterDom.useParams();
932
- const [{ query }, setQuery] = helperPlugin.useQueryParams();
933
- const toggleNotification = helperPlugin.useNotification();
934
- const { formatAPIError } = helperPlugin.useAPIErrorHandler();
935
- const {
936
- data: releaseData,
937
- isLoading: isReleaseLoading,
938
- isError: isReleaseError,
939
- error: releaseError
940
- } = index.useGetReleaseQuery({ id: releaseId });
941
- const {
942
- allowedActions: { canUpdate }
943
- } = helperPlugin.useRBAC(index.PERMISSIONS);
944
- const release = releaseData?.data;
945
- const selectedGroupBy = query?.groupBy || "contentType";
946
- const {
947
- isLoading,
948
- isFetching,
949
- isError,
950
- data,
951
- error: releaseActionsError
952
- } = index.useGetReleaseActionsQuery({
953
- ...query,
954
- releaseId
955
- });
956
- const [updateReleaseAction] = index.useUpdateReleaseActionMutation();
957
- const handleChangeType = async (e, actionId, actionPath) => {
958
- const response = await updateReleaseAction({
959
- params: {
960
- releaseId,
961
- actionId
962
- },
963
- body: {
964
- type: e.target.value
965
- },
966
- query,
967
- // We are passing the query params to make optimistic updates
968
- actionPath
969
- // We are passing the action path to found the position in the cache of the action for optimistic updates
970
- });
971
- if ("error" in response) {
972
- if (index.isAxiosError(response.error)) {
973
- toggleNotification({
974
- type: "warning",
975
- message: formatAPIError(response.error)
976
- });
977
- } else {
978
- toggleNotification({
979
- type: "warning",
980
- message: formatMessage({ id: "notification.error", defaultMessage: "An error occurred" })
981
- });
982
- }
983
- }
984
- };
985
- if (isLoading || isReleaseLoading) {
986
- return /* @__PURE__ */ jsxRuntime.jsx(designSystem.ContentLayout, { children: /* @__PURE__ */ jsxRuntime.jsx(helperPlugin.LoadingIndicatorPage, {}) });
987
- }
988
- const releaseActions = data?.data;
989
- const releaseMeta = data?.meta;
990
- const contentTypes = releaseMeta?.contentTypes || {};
991
- const components = releaseMeta?.components || {};
992
- if (isReleaseError || !release) {
993
- const errorsArray = [];
994
- if (releaseError) {
995
- errorsArray.push({
996
- code: releaseError.code
997
- });
998
- }
999
- if (releaseActionsError) {
1000
- errorsArray.push({
1001
- code: releaseActionsError.code
1002
- });
1003
- }
1004
- return /* @__PURE__ */ jsxRuntime.jsx(
1005
- reactRouterDom.Redirect,
1006
- {
1007
- to: {
1008
- pathname: "/plugins/content-releases",
1009
- state: {
1010
- errors: errorsArray
1011
- }
1012
- }
1013
- }
1014
- );
1015
- }
1016
- if (isError || !releaseActions) {
1017
- return /* @__PURE__ */ jsxRuntime.jsx(designSystem.ContentLayout, { children: /* @__PURE__ */ jsxRuntime.jsx(helperPlugin.AnErrorOccurred, {}) });
1018
- }
1019
- if (Object.keys(releaseActions).length === 0) {
1020
- return /* @__PURE__ */ jsxRuntime.jsx(designSystem.ContentLayout, { children: /* @__PURE__ */ jsxRuntime.jsx(
1021
- helperPlugin.NoContent,
1022
- {
1023
- content: {
1024
- id: "content-releases.pages.Details.tab.emptyEntries",
1025
- defaultMessage: "This release is empty. Open the Content Manager, select an entry and add it to the release."
1026
- },
1027
- action: /* @__PURE__ */ jsxRuntime.jsx(
1028
- v2.LinkButton,
1029
- {
1030
- as: reactRouterDom.Link,
1031
- to: {
1032
- pathname: "/content-manager"
1033
- },
1034
- style: { textDecoration: "none" },
1035
- variant: "secondary",
1036
- children: formatMessage({
1037
- id: "content-releases.page.Details.button.openContentManager",
1038
- defaultMessage: "Open the Content Manager"
1039
- })
1040
- }
1041
- )
1042
- }
1043
- ) });
1044
- }
1045
- return /* @__PURE__ */ jsxRuntime.jsx(designSystem.ContentLayout, { children: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { gap: 8, direction: "column", alignItems: "stretch", children: [
1046
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Flex, { children: /* @__PURE__ */ jsxRuntime.jsx(
1047
- designSystem.SingleSelect,
1048
- {
1049
- "aria-label": formatMessage({
1050
- id: "content-releases.pages.ReleaseDetails.groupBy.aria-label",
1051
- defaultMessage: "Group by"
1052
- }),
1053
- customizeContent: (value) => formatMessage(
1054
- {
1055
- id: `content-releases.pages.ReleaseDetails.groupBy.label`,
1056
- defaultMessage: `Group by {groupBy}`
1057
- },
1058
- {
1059
- groupBy: value
1060
- }
1061
- ),
1062
- value: formatMessage(getGroupByOptionLabel(selectedGroupBy)),
1063
- onChange: (value) => setQuery({ groupBy: value }),
1064
- children: GROUP_BY_OPTIONS.map((option) => /* @__PURE__ */ jsxRuntime.jsx(designSystem.SingleSelectOption, { value: option, children: formatMessage(getGroupByOptionLabel(option)) }, option))
1065
- }
1066
- ) }),
1067
- Object.keys(releaseActions).map((key) => /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { gap: 4, direction: "column", alignItems: "stretch", children: [
1068
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Flex, { role: "separator", "aria-label": key, children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Badge, { children: key }) }),
1069
- /* @__PURE__ */ jsxRuntime.jsx(
1070
- helperPlugin.Table.Root,
1071
- {
1072
- rows: releaseActions[key].map((item) => ({
1073
- ...item,
1074
- id: Number(item.entry.id)
1075
- })),
1076
- colCount: releaseActions[key].length,
1077
- isLoading,
1078
- isFetching,
1079
- children: /* @__PURE__ */ jsxRuntime.jsxs(helperPlugin.Table.Content, { children: [
1080
- /* @__PURE__ */ jsxRuntime.jsxs(helperPlugin.Table.Head, { children: [
1081
- /* @__PURE__ */ jsxRuntime.jsx(
1082
- helperPlugin.Table.HeaderCell,
1083
- {
1084
- fieldSchemaType: "string",
1085
- label: formatMessage({
1086
- id: "content-releases.page.ReleaseDetails.table.header.label.name",
1087
- defaultMessage: "name"
1088
- }),
1089
- name: "name"
1090
- }
1091
- ),
1092
- /* @__PURE__ */ jsxRuntime.jsx(
1093
- helperPlugin.Table.HeaderCell,
1094
- {
1095
- fieldSchemaType: "string",
1096
- label: formatMessage({
1097
- id: "content-releases.page.ReleaseDetails.table.header.label.locale",
1098
- defaultMessage: "locale"
1099
- }),
1100
- name: "locale"
1101
- }
1102
- ),
1103
- /* @__PURE__ */ jsxRuntime.jsx(
1104
- helperPlugin.Table.HeaderCell,
1105
- {
1106
- fieldSchemaType: "string",
1107
- label: formatMessage({
1108
- id: "content-releases.page.ReleaseDetails.table.header.label.content-type",
1109
- defaultMessage: "content-type"
1110
- }),
1111
- name: "content-type"
1112
- }
1113
- ),
1114
- /* @__PURE__ */ jsxRuntime.jsx(
1115
- helperPlugin.Table.HeaderCell,
1116
- {
1117
- fieldSchemaType: "string",
1118
- label: formatMessage({
1119
- id: "content-releases.page.ReleaseDetails.table.header.label.action",
1120
- defaultMessage: "action"
1121
- }),
1122
- name: "action"
1123
- }
1124
- ),
1125
- !release.releasedAt && /* @__PURE__ */ jsxRuntime.jsx(
1126
- helperPlugin.Table.HeaderCell,
1127
- {
1128
- fieldSchemaType: "string",
1129
- label: formatMessage({
1130
- id: "content-releases.page.ReleaseDetails.table.header.label.status",
1131
- defaultMessage: "status"
1132
- }),
1133
- name: "status"
1134
- }
1135
- )
1136
- ] }),
1137
- /* @__PURE__ */ jsxRuntime.jsx(helperPlugin.Table.LoadingBody, {}),
1138
- /* @__PURE__ */ jsxRuntime.jsx(helperPlugin.Table.Body, { children: releaseActions[key].map(
1139
- ({ id, contentType, locale, type, entry }, actionIndex) => /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Tr, { children: [
1140
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Td, { width: "25%", maxWidth: "200px", children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { ellipsis: true, children: `${contentType.mainFieldValue || entry.id}` }) }),
1141
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Td, { width: "10%", children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { children: `${locale?.name ? locale.name : "-"}` }) }),
1142
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Td, { width: "10%", children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { children: contentType.displayName || "" }) }),
1143
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Td, { width: "20%", children: release.releasedAt ? /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { children: formatMessage(
1144
- {
1145
- id: "content-releases.page.ReleaseDetails.table.action-published",
1146
- defaultMessage: "This entry was <b>{isPublish, select, true {published} other {unpublished}}</b>."
1147
- },
1148
- {
1149
- isPublish: type === "publish",
1150
- b: (children) => /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { fontWeight: "bold", children })
1151
- }
1152
- ) }) : /* @__PURE__ */ jsxRuntime.jsx(
1153
- index.ReleaseActionOptions,
1154
- {
1155
- selected: type,
1156
- handleChange: (e) => handleChangeType(e, id, [key, actionIndex]),
1157
- name: `release-action-${id}-type`,
1158
- disabled: !canUpdate
1159
- }
1160
- ) }),
1161
- !release.releasedAt && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
1162
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Td, { width: "20%", minWidth: "200px", children: /* @__PURE__ */ jsxRuntime.jsx(
1163
- EntryValidationText,
1164
- {
1165
- action: type,
1166
- schema: contentTypes?.[contentType.uid],
1167
- components,
1168
- entry
1169
- }
1170
- ) }),
1171
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Td, { children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Flex, { justifyContent: "flex-end", children: /* @__PURE__ */ jsxRuntime.jsxs(index.ReleaseActionMenu.Root, { children: [
1172
- /* @__PURE__ */ jsxRuntime.jsx(
1173
- index.ReleaseActionMenu.ReleaseActionEntryLinkItem,
1174
- {
1175
- contentTypeUid: contentType.uid,
1176
- entryId: entry.id,
1177
- locale: locale?.code
1178
- }
1179
- ),
1180
- /* @__PURE__ */ jsxRuntime.jsx(
1181
- index.ReleaseActionMenu.DeleteReleaseActionItem,
1182
- {
1183
- releaseId: release.id,
1184
- actionId: id
1185
- }
1186
- )
1187
- ] }) }) })
1188
- ] })
1189
- ] }, id)
1190
- ) })
1191
- ] })
1192
- }
1193
- )
1194
- ] }, `releases-group-${key}`)),
1195
- /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { paddingTop: 4, alignItems: "flex-end", justifyContent: "space-between", children: [
1196
- /* @__PURE__ */ jsxRuntime.jsx(helperPlugin.PageSizeURLQuery, { defaultValue: releaseMeta?.pagination?.pageSize.toString() }),
1197
- /* @__PURE__ */ jsxRuntime.jsx(
1198
- helperPlugin.PaginationURLQuery,
1199
- {
1200
- pagination: {
1201
- pageCount: releaseMeta?.pagination?.pageCount || 0
1202
- }
1203
- }
1204
- )
1205
- ] })
1206
- ] }) });
1207
- };
1208
- const ReleaseDetailsPage = () => {
1209
- const { formatMessage } = reactIntl.useIntl();
1210
- const { releaseId } = reactRouterDom.useParams();
1211
- const toggleNotification = helperPlugin.useNotification();
1212
- const { formatAPIError } = helperPlugin.useAPIErrorHandler();
1213
- const { replace } = reactRouterDom.useHistory();
1214
- const [releaseModalShown, setReleaseModalShown] = React__namespace.useState(false);
1215
- const [showWarningSubmit, setWarningSubmit] = React__namespace.useState(false);
1216
- const {
1217
- isLoading: isLoadingDetails,
1218
- data,
1219
- isSuccess: isSuccessDetails
1220
- } = index.useGetReleaseQuery({ id: releaseId });
1221
- const [updateRelease, { isLoading: isSubmittingForm }] = index.useUpdateReleaseMutation();
1222
- const [deleteRelease, { isLoading: isDeletingRelease }] = index.useDeleteReleaseMutation();
1223
- const toggleEditReleaseModal = () => {
1224
- setReleaseModalShown((prev) => !prev);
1225
- };
1226
- const toggleWarningSubmit = () => setWarningSubmit((prevState) => !prevState);
1227
- if (isLoadingDetails) {
1228
- return /* @__PURE__ */ jsxRuntime.jsx(
1229
- ReleaseDetailsLayout,
1230
- {
1231
- toggleEditReleaseModal,
1232
- toggleWarningSubmit,
1233
- children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.ContentLayout, { children: /* @__PURE__ */ jsxRuntime.jsx(helperPlugin.LoadingIndicatorPage, {}) })
1234
- }
1235
- );
1236
- }
1237
- const releaseData = isSuccessDetails && data?.data || null;
1238
- const title = releaseData?.name || "";
1239
- const timezone = releaseData?.timezone ?? null;
1240
- const scheduledAt = releaseData?.scheduledAt && timezone ? dateFnsTz.utcToZonedTime(releaseData.scheduledAt, timezone) : null;
1241
- const date = scheduledAt ? new Date(format__default.default(scheduledAt, "yyyy-MM-dd")) : null;
1242
- const time = scheduledAt ? format__default.default(scheduledAt, "HH:mm") : "";
1243
- const handleEditRelease = async (values) => {
1244
- const response = await updateRelease({
1245
- id: releaseId,
1246
- name: values.name,
1247
- scheduledAt: values.scheduledAt,
1248
- timezone: values.timezone
1249
- });
1250
- if ("data" in response) {
1251
- toggleNotification({
1252
- type: "success",
1253
- message: formatMessage({
1254
- id: "content-releases.modal.release-updated-notification-success",
1255
- defaultMessage: "Release updated."
1256
- })
1257
- });
1258
- } else if (index.isAxiosError(response.error)) {
1259
- toggleNotification({
1260
- type: "warning",
1261
- message: formatAPIError(response.error)
1262
- });
1263
- } else {
1264
- toggleNotification({
1265
- type: "warning",
1266
- message: formatMessage({ id: "notification.error", defaultMessage: "An error occurred" })
1267
- });
1268
- }
1269
- toggleEditReleaseModal();
1270
- };
1271
- const handleDeleteRelease = async () => {
1272
- const response = await deleteRelease({
1273
- id: releaseId
1274
- });
1275
- if ("data" in response) {
1276
- replace("/plugins/content-releases");
1277
- } else if (index.isAxiosError(response.error)) {
1278
- toggleNotification({
1279
- type: "warning",
1280
- message: formatAPIError(response.error)
1281
- });
1282
- } else {
1283
- toggleNotification({
1284
- type: "warning",
1285
- message: formatMessage({ id: "notification.error", defaultMessage: "An error occurred" })
1286
- });
1287
- }
1288
- };
1289
- return /* @__PURE__ */ jsxRuntime.jsxs(
1290
- ReleaseDetailsLayout,
1291
- {
1292
- toggleEditReleaseModal,
1293
- toggleWarningSubmit,
1294
- children: [
1295
- /* @__PURE__ */ jsxRuntime.jsx(ReleaseDetailsBody, {}),
1296
- releaseModalShown && /* @__PURE__ */ jsxRuntime.jsx(
1297
- ReleaseModal,
1298
- {
1299
- handleClose: toggleEditReleaseModal,
1300
- handleSubmit: handleEditRelease,
1301
- isLoading: isLoadingDetails || isSubmittingForm,
1302
- initialValues: {
1303
- name: title || "",
1304
- scheduledAt,
1305
- date,
1306
- time,
1307
- isScheduled: Boolean(scheduledAt),
1308
- timezone
1309
- }
1310
- }
1311
- ),
1312
- /* @__PURE__ */ jsxRuntime.jsx(
1313
- helperPlugin.ConfirmDialog,
1314
- {
1315
- bodyText: {
1316
- id: "content-releases.dialog.confirmation-message",
1317
- defaultMessage: "Are you sure you want to delete this release?"
1318
- },
1319
- isOpen: showWarningSubmit,
1320
- isConfirmButtonLoading: isDeletingRelease,
1321
- onToggleDialog: toggleWarningSubmit,
1322
- onConfirm: handleDeleteRelease
1323
- }
1324
- )
1325
- ]
1326
- }
1327
- );
1328
- };
1329
- const App = () => {
1330
- return /* @__PURE__ */ jsxRuntime.jsx(helperPlugin.CheckPagePermissions, { permissions: index.PERMISSIONS.main, children: /* @__PURE__ */ jsxRuntime.jsxs(reactRouterDom.Switch, { children: [
1331
- /* @__PURE__ */ jsxRuntime.jsx(reactRouterDom.Route, { exact: true, path: `/plugins/${index.pluginId}`, component: ReleasesPage }),
1332
- /* @__PURE__ */ jsxRuntime.jsx(reactRouterDom.Route, { exact: true, path: `/plugins/${index.pluginId}/:releaseId`, component: ReleaseDetailsPage })
1333
- ] }) });
1334
- };
1335
- exports.App = App;
1336
- //# sourceMappingURL=App-l62gIUTX.js.map