@strapi/content-releases 0.0.0-next.6d59515520a3850456f256fb0e4c54b75054ddf4 → 0.0.0-next.73143c28059b343ba62d98c29672ab114562fbbc
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.
- package/dist/_chunks/{App-L1jSxCiL.mjs → App-g3vtS2Wa.mjs} +524 -252
- package/dist/_chunks/App-g3vtS2Wa.mjs.map +1 -0
- package/dist/_chunks/{App-_20W9dYa.js → App-lnXbSPgp.js} +520 -247
- package/dist/_chunks/App-lnXbSPgp.js.map +1 -0
- package/dist/_chunks/PurchaseContentReleases-Clm0iACO.mjs +51 -0
- package/dist/_chunks/PurchaseContentReleases-Clm0iACO.mjs.map +1 -0
- package/dist/_chunks/PurchaseContentReleases-YhAPgpG9.js +51 -0
- package/dist/_chunks/PurchaseContentReleases-YhAPgpG9.js.map +1 -0
- package/dist/_chunks/{en-MyLPoISH.mjs → en-WuuhP6Bn.mjs} +21 -6
- package/dist/_chunks/en-WuuhP6Bn.mjs.map +1 -0
- package/dist/_chunks/{en-gYDqKYFd.js → en-gcJJ5htG.js} +21 -6
- package/dist/_chunks/en-gcJJ5htG.js.map +1 -0
- package/dist/_chunks/{index-KJa1Rb5F.js → index-ItlgrLcr.js} +158 -32
- package/dist/_chunks/index-ItlgrLcr.js.map +1 -0
- package/dist/_chunks/{index-c4zRX_sg.mjs → index-uGex_IIQ.mjs} +163 -37
- package/dist/_chunks/index-uGex_IIQ.mjs.map +1 -0
- package/dist/admin/index.js +1 -1
- package/dist/admin/index.mjs +2 -2
- package/dist/server/index.js +887 -398
- package/dist/server/index.js.map +1 -1
- package/dist/server/index.mjs +886 -398
- package/dist/server/index.mjs.map +1 -1
- package/package.json +14 -11
- package/dist/_chunks/App-L1jSxCiL.mjs.map +0 -1
- package/dist/_chunks/App-_20W9dYa.js.map +0 -1
- package/dist/_chunks/en-MyLPoISH.mjs.map +0 -1
- package/dist/_chunks/en-gYDqKYFd.js.map +0 -1
- package/dist/_chunks/index-KJa1Rb5F.js.map +0 -1
- package/dist/_chunks/index-c4zRX_sg.mjs.map +0 -1
|
@@ -1,22 +1,42 @@
|
|
|
1
1
|
import { jsxs, jsx, Fragment } from "react/jsx-runtime";
|
|
2
|
-
import { useNotification, useAPIErrorHandler, LoadingIndicatorPage, ConfirmDialog, useRBAC, RelativeTime, CheckPermissions, useQueryParams, AnErrorOccurred, NoContent, Table, PageSizeURLQuery, PaginationURLQuery, CheckPagePermissions } from "@strapi/helper-plugin";
|
|
2
|
+
import { useNotification, useAPIErrorHandler, LoadingIndicatorPage, ConfirmDialog, useRBAC, useTracking, RelativeTime, CheckPermissions, useQueryParams, AnErrorOccurred, NoContent, Table, PageSizeURLQuery, PaginationURLQuery, CheckPagePermissions } from "@strapi/helper-plugin";
|
|
3
3
|
import { useLocation, useParams, useHistory, Redirect, Link as Link$1, Switch, Route } from "react-router-dom";
|
|
4
|
-
import { p as pluginId, u as useGetReleaseQuery, a as useUpdateReleaseMutation, b as useDeleteReleaseMutation, c as usePublishReleaseMutation, P as PERMISSIONS, d as useTypedDispatch, e as useGetReleaseActionsQuery, f as useUpdateReleaseActionMutation, R as ReleaseActionOptions,
|
|
4
|
+
import { g as getTimezoneOffset, p as pluginId, u as useGetReleaseQuery, a as useUpdateReleaseMutation, b as useDeleteReleaseMutation, c as usePublishReleaseMutation, P as PERMISSIONS, d as useTypedDispatch, e as useGetReleaseActionsQuery, f as useUpdateReleaseActionMutation, R as ReleaseActionOptions, h as ReleaseActionMenu, i as isAxiosError, r as releaseApi, j as useGetReleasesQuery, k as useCreateReleaseMutation } from "./index-uGex_IIQ.mjs";
|
|
5
5
|
import * as React from "react";
|
|
6
|
-
import { unstable_useDocument } from "@strapi/admin/strapi-admin";
|
|
7
|
-
import { ModalLayout, ModalHeader, Typography, ModalBody, TextInput, ModalFooter, Button,
|
|
8
|
-
import { LinkButton, Link as Link$2 } from "@strapi/design-system/v2";
|
|
6
|
+
import { unstable_useDocument, useLicenseLimits } from "@strapi/admin/strapi-admin";
|
|
7
|
+
import { ModalLayout, ModalHeader, Typography, ModalBody, Flex, TextInput, Box, Checkbox, DatePicker, TimePicker, ModalFooter, Button, Combobox, ComboboxOption, ContentLayout, Main, HeaderLayout, Link, IconButton, SingleSelect, SingleSelectOption, Badge, Tr, Td, Icon, Tooltip, Alert, TabGroup, Tabs, Tab, Divider, TabPanels, TabPanel, EmptyStateLayout, Grid, GridItem } from "@strapi/design-system";
|
|
8
|
+
import { Menu, LinkButton, Link as Link$2 } from "@strapi/design-system/v2";
|
|
9
9
|
import { Pencil, Trash, ArrowLeft, More, CrossCircle, CheckCircle, Plus, EmptyDocuments } from "@strapi/icons";
|
|
10
|
+
import format from "date-fns/format";
|
|
11
|
+
import { zonedTimeToUtc, utcToZonedTime } from "date-fns-tz";
|
|
10
12
|
import { useIntl } from "react-intl";
|
|
11
13
|
import styled from "styled-components";
|
|
12
|
-
import {
|
|
14
|
+
import { formatISO, parse } from "date-fns";
|
|
15
|
+
import { Formik, Form, useFormikContext } from "formik";
|
|
13
16
|
import * as yup from "yup";
|
|
14
17
|
import "@reduxjs/toolkit/query";
|
|
15
18
|
import "axios";
|
|
16
19
|
import "@reduxjs/toolkit/query/react";
|
|
17
20
|
import "react-redux";
|
|
18
21
|
const RELEASE_SCHEMA = yup.object().shape({
|
|
19
|
-
name: yup.string().trim().required()
|
|
22
|
+
name: yup.string().trim().required(),
|
|
23
|
+
scheduledAt: yup.string().nullable(),
|
|
24
|
+
isScheduled: yup.boolean().optional(),
|
|
25
|
+
time: yup.string().when("isScheduled", {
|
|
26
|
+
is: true,
|
|
27
|
+
then: yup.string().trim().required(),
|
|
28
|
+
otherwise: yup.string().nullable()
|
|
29
|
+
}),
|
|
30
|
+
timezone: yup.string().when("isScheduled", {
|
|
31
|
+
is: true,
|
|
32
|
+
then: yup.string().required().nullable(),
|
|
33
|
+
otherwise: yup.string().nullable()
|
|
34
|
+
}),
|
|
35
|
+
date: yup.string().when("isScheduled", {
|
|
36
|
+
is: true,
|
|
37
|
+
then: yup.string().required().nullable(),
|
|
38
|
+
otherwise: yup.string().nullable()
|
|
39
|
+
})
|
|
20
40
|
}).required().noUnknown();
|
|
21
41
|
const ReleaseModal = ({
|
|
22
42
|
handleClose,
|
|
@@ -27,6 +47,24 @@ const ReleaseModal = ({
|
|
|
27
47
|
const { formatMessage } = useIntl();
|
|
28
48
|
const { pathname } = useLocation();
|
|
29
49
|
const isCreatingRelease = pathname === `/plugins/${pluginId}`;
|
|
50
|
+
const IsSchedulingEnabled = window.strapi.future.isEnabled("contentReleasesScheduling");
|
|
51
|
+
const { timezoneList, systemTimezone = { value: "UTC+00:00-Africa/Abidjan " } } = getTimezones(
|
|
52
|
+
initialValues.scheduledAt ? new Date(initialValues.scheduledAt) : /* @__PURE__ */ new Date()
|
|
53
|
+
);
|
|
54
|
+
const getScheduledTimestamp = (values) => {
|
|
55
|
+
const { date, time, timezone } = values;
|
|
56
|
+
if (!date || !time || !timezone)
|
|
57
|
+
return null;
|
|
58
|
+
const formattedDate = parse(time, "HH:mm", new Date(date));
|
|
59
|
+
const timezoneWithoutOffset = timezone.split("_")[1];
|
|
60
|
+
return zonedTimeToUtc(formattedDate, timezoneWithoutOffset);
|
|
61
|
+
};
|
|
62
|
+
const getTimezoneWithOffset = () => {
|
|
63
|
+
const currentTimezone = timezoneList.find(
|
|
64
|
+
(timezone) => timezone.value.split("_")[1] === initialValues.timezone
|
|
65
|
+
);
|
|
66
|
+
return currentTimezone?.value || systemTimezone.value;
|
|
67
|
+
};
|
|
30
68
|
return /* @__PURE__ */ jsxs(ModalLayout, { onClose: handleClose, labelledBy: "title", children: [
|
|
31
69
|
/* @__PURE__ */ jsx(ModalHeader, { children: /* @__PURE__ */ jsx(Typography, { id: "title", fontWeight: "bold", textColor: "neutral800", children: formatMessage(
|
|
32
70
|
{
|
|
@@ -38,45 +76,134 @@ const ReleaseModal = ({
|
|
|
38
76
|
/* @__PURE__ */ jsx(
|
|
39
77
|
Formik,
|
|
40
78
|
{
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
79
|
+
onSubmit: (values) => {
|
|
80
|
+
handleSubmit({
|
|
81
|
+
...values,
|
|
82
|
+
timezone: values.timezone ? values.timezone.split("_")[1] : null,
|
|
83
|
+
scheduledAt: values.isScheduled ? getScheduledTimestamp(values) : null
|
|
84
|
+
});
|
|
85
|
+
},
|
|
86
|
+
initialValues: {
|
|
87
|
+
...initialValues,
|
|
88
|
+
timezone: initialValues.timezone ? getTimezoneWithOffset() : systemTimezone.value
|
|
89
|
+
},
|
|
44
90
|
validationSchema: RELEASE_SCHEMA,
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
91
|
+
validateOnChange: false,
|
|
92
|
+
children: ({ values, errors, handleChange, setFieldValue }) => /* @__PURE__ */ jsxs(Form, { children: [
|
|
93
|
+
/* @__PURE__ */ jsx(ModalBody, { children: /* @__PURE__ */ jsxs(Flex, { direction: "column", alignItems: "stretch", gap: 6, children: [
|
|
94
|
+
/* @__PURE__ */ jsx(
|
|
95
|
+
TextInput,
|
|
96
|
+
{
|
|
97
|
+
label: formatMessage({
|
|
98
|
+
id: "content-releases.modal.form.input.label.release-name",
|
|
99
|
+
defaultMessage: "Name"
|
|
100
|
+
}),
|
|
101
|
+
name: "name",
|
|
102
|
+
value: values.name,
|
|
103
|
+
error: errors.name,
|
|
104
|
+
onChange: handleChange,
|
|
105
|
+
required: true
|
|
106
|
+
}
|
|
107
|
+
),
|
|
108
|
+
IsSchedulingEnabled && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
109
|
+
/* @__PURE__ */ jsx(Box, { width: "max-content", children: /* @__PURE__ */ jsx(
|
|
110
|
+
Checkbox,
|
|
111
|
+
{
|
|
112
|
+
name: "isScheduled",
|
|
113
|
+
value: values.isScheduled,
|
|
114
|
+
onChange: (event) => {
|
|
115
|
+
setFieldValue("isScheduled", event.target.checked);
|
|
116
|
+
if (!event.target.checked) {
|
|
117
|
+
setFieldValue("date", null);
|
|
118
|
+
setFieldValue("time", "");
|
|
119
|
+
setFieldValue("timezone", null);
|
|
120
|
+
} else {
|
|
121
|
+
setFieldValue("date", initialValues.date);
|
|
122
|
+
setFieldValue("time", initialValues.time);
|
|
123
|
+
setFieldValue(
|
|
124
|
+
"timezone",
|
|
125
|
+
initialValues.timezone ?? systemTimezone?.value
|
|
126
|
+
);
|
|
127
|
+
}
|
|
128
|
+
},
|
|
129
|
+
children: /* @__PURE__ */ jsx(
|
|
130
|
+
Typography,
|
|
131
|
+
{
|
|
132
|
+
textColor: values.isScheduled ? "primary600" : "neutral800",
|
|
133
|
+
fontWeight: values.isScheduled ? "semiBold" : "regular",
|
|
134
|
+
children: formatMessage({
|
|
135
|
+
id: "modal.form.input.label.schedule-release",
|
|
136
|
+
defaultMessage: "Schedule release"
|
|
137
|
+
})
|
|
138
|
+
}
|
|
139
|
+
)
|
|
140
|
+
}
|
|
141
|
+
) }),
|
|
142
|
+
values.isScheduled && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
143
|
+
/* @__PURE__ */ jsxs(Flex, { gap: 4, alignItems: "start", children: [
|
|
144
|
+
/* @__PURE__ */ jsx(Box, { width: "100%", children: /* @__PURE__ */ jsx(
|
|
145
|
+
DatePicker,
|
|
146
|
+
{
|
|
147
|
+
label: formatMessage({
|
|
148
|
+
id: "content-releases.modal.form.input.label.date",
|
|
149
|
+
defaultMessage: "Date"
|
|
150
|
+
}),
|
|
151
|
+
name: "date",
|
|
152
|
+
error: errors.date,
|
|
153
|
+
onChange: (date) => {
|
|
154
|
+
const isoFormatDate = date ? formatISO(date, { representation: "date" }) : null;
|
|
155
|
+
setFieldValue("date", isoFormatDate);
|
|
156
|
+
},
|
|
157
|
+
clearLabel: formatMessage({
|
|
158
|
+
id: "content-releases.modal.form.input.clearLabel",
|
|
159
|
+
defaultMessage: "Clear"
|
|
160
|
+
}),
|
|
161
|
+
onClear: () => {
|
|
162
|
+
setFieldValue("date", null);
|
|
163
|
+
},
|
|
164
|
+
selectedDate: values.date || void 0,
|
|
165
|
+
required: true
|
|
166
|
+
}
|
|
167
|
+
) }),
|
|
168
|
+
/* @__PURE__ */ jsx(Box, { width: "100%", children: /* @__PURE__ */ jsx(
|
|
169
|
+
TimePicker,
|
|
170
|
+
{
|
|
171
|
+
label: formatMessage({
|
|
172
|
+
id: "content-releases.modal.form.input.label.time",
|
|
173
|
+
defaultMessage: "Time"
|
|
174
|
+
}),
|
|
175
|
+
name: "time",
|
|
176
|
+
error: errors.time,
|
|
177
|
+
onChange: (time) => {
|
|
178
|
+
setFieldValue("time", time);
|
|
179
|
+
},
|
|
180
|
+
clearLabel: formatMessage({
|
|
181
|
+
id: "content-releases.modal.form.input.clearLabel",
|
|
182
|
+
defaultMessage: "Clear"
|
|
183
|
+
}),
|
|
184
|
+
onClear: () => {
|
|
185
|
+
setFieldValue("time", "");
|
|
186
|
+
},
|
|
187
|
+
value: values.time || void 0,
|
|
188
|
+
required: true
|
|
189
|
+
}
|
|
190
|
+
) })
|
|
191
|
+
] }),
|
|
192
|
+
/* @__PURE__ */ jsx(TimezoneComponent, { timezoneOptions: timezoneList })
|
|
193
|
+
] })
|
|
194
|
+
] })
|
|
195
|
+
] }) }),
|
|
60
196
|
/* @__PURE__ */ jsx(
|
|
61
197
|
ModalFooter,
|
|
62
198
|
{
|
|
63
199
|
startActions: /* @__PURE__ */ jsx(Button, { onClick: handleClose, variant: "tertiary", name: "cancel", children: formatMessage({ id: "cancel", defaultMessage: "Cancel" }) }),
|
|
64
|
-
endActions: /* @__PURE__ */ jsx(
|
|
65
|
-
Button,
|
|
200
|
+
endActions: /* @__PURE__ */ jsx(Button, { name: "submit", loading: isLoading, type: "submit", children: formatMessage(
|
|
66
201
|
{
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
{
|
|
73
|
-
id: "content-releases.modal.form.button.submit",
|
|
74
|
-
defaultMessage: "{isCreatingRelease, select, true {Continue} other {Save}}"
|
|
75
|
-
},
|
|
76
|
-
{ isCreatingRelease }
|
|
77
|
-
)
|
|
78
|
-
}
|
|
79
|
-
)
|
|
202
|
+
id: "content-releases.modal.form.button.submit",
|
|
203
|
+
defaultMessage: "{isCreatingRelease, select, true {Continue} other {Save}}"
|
|
204
|
+
},
|
|
205
|
+
{ isCreatingRelease }
|
|
206
|
+
) })
|
|
80
207
|
}
|
|
81
208
|
)
|
|
82
209
|
] })
|
|
@@ -84,33 +211,83 @@ const ReleaseModal = ({
|
|
|
84
211
|
)
|
|
85
212
|
] });
|
|
86
213
|
};
|
|
214
|
+
const getTimezones = (selectedDate) => {
|
|
215
|
+
const timezoneList = Intl.supportedValuesOf("timeZone").map((timezone) => {
|
|
216
|
+
const utcOffset = getTimezoneOffset(timezone, selectedDate);
|
|
217
|
+
return { offset: utcOffset, value: `${utcOffset}_${timezone}` };
|
|
218
|
+
});
|
|
219
|
+
const systemTimezone = timezoneList.find(
|
|
220
|
+
(timezone) => timezone.value.split("_")[1] === Intl.DateTimeFormat().resolvedOptions().timeZone
|
|
221
|
+
);
|
|
222
|
+
return { timezoneList, systemTimezone };
|
|
223
|
+
};
|
|
224
|
+
const TimezoneComponent = ({ timezoneOptions }) => {
|
|
225
|
+
const { values, errors, setFieldValue } = useFormikContext();
|
|
226
|
+
const { formatMessage } = useIntl();
|
|
227
|
+
const [timezoneList, setTimezoneList] = React.useState(timezoneOptions);
|
|
228
|
+
React.useEffect(() => {
|
|
229
|
+
if (values.date) {
|
|
230
|
+
const { timezoneList: timezoneList2 } = getTimezones(new Date(values.date));
|
|
231
|
+
setTimezoneList(timezoneList2);
|
|
232
|
+
const updatedTimezone = values.timezone && timezoneList2.find((tz) => tz.value.split("_")[1] === values.timezone.split("_")[1]);
|
|
233
|
+
if (updatedTimezone) {
|
|
234
|
+
setFieldValue("timezone", updatedTimezone.value);
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
}, [setFieldValue, values.date, values.timezone]);
|
|
238
|
+
return /* @__PURE__ */ jsx(
|
|
239
|
+
Combobox,
|
|
240
|
+
{
|
|
241
|
+
label: formatMessage({
|
|
242
|
+
id: "content-releases.modal.form.input.label.timezone",
|
|
243
|
+
defaultMessage: "Timezone"
|
|
244
|
+
}),
|
|
245
|
+
name: "timezone",
|
|
246
|
+
value: values.timezone || void 0,
|
|
247
|
+
textValue: values.timezone ? values.timezone.replace("_", " ") : void 0,
|
|
248
|
+
onChange: (timezone) => {
|
|
249
|
+
setFieldValue("timezone", timezone);
|
|
250
|
+
},
|
|
251
|
+
onTextValueChange: (timezone) => {
|
|
252
|
+
setFieldValue("timezone", timezone);
|
|
253
|
+
},
|
|
254
|
+
onClear: () => {
|
|
255
|
+
setFieldValue("timezone", "");
|
|
256
|
+
},
|
|
257
|
+
error: errors.timezone,
|
|
258
|
+
required: true,
|
|
259
|
+
children: timezoneList.map((timezone) => /* @__PURE__ */ jsx(ComboboxOption, { value: timezone.value, children: timezone.value.replace("_", " ") }, timezone.value))
|
|
260
|
+
}
|
|
261
|
+
);
|
|
262
|
+
};
|
|
87
263
|
const ReleaseInfoWrapper = styled(Flex)`
|
|
88
264
|
align-self: stretch;
|
|
89
265
|
border-bottom-right-radius: ${({ theme }) => theme.borderRadius};
|
|
90
266
|
border-bottom-left-radius: ${({ theme }) => theme.borderRadius};
|
|
91
267
|
border-top: 1px solid ${({ theme }) => theme.colors.neutral150};
|
|
92
268
|
`;
|
|
93
|
-
const
|
|
94
|
-
align-self: stretch;
|
|
95
|
-
cursor: ${({ disabled }) => disabled ? "not-allowed" : "pointer"};
|
|
96
|
-
|
|
269
|
+
const StyledMenuItem = styled(Menu.Item)`
|
|
97
270
|
svg path {
|
|
98
271
|
fill: ${({ theme, disabled }) => disabled && theme.colors.neutral500};
|
|
99
272
|
}
|
|
100
273
|
span {
|
|
101
274
|
color: ${({ theme, disabled }) => disabled && theme.colors.neutral500};
|
|
102
275
|
}
|
|
276
|
+
|
|
277
|
+
&:hover {
|
|
278
|
+
background: ${({ theme, variant = "neutral" }) => theme.colors[`${variant}100`]};
|
|
279
|
+
}
|
|
103
280
|
`;
|
|
104
281
|
const PencilIcon = styled(Pencil)`
|
|
105
|
-
width: ${({ theme }) => theme.spaces[
|
|
106
|
-
height: ${({ theme }) => theme.spaces[
|
|
282
|
+
width: ${({ theme }) => theme.spaces[3]};
|
|
283
|
+
height: ${({ theme }) => theme.spaces[3]};
|
|
107
284
|
path {
|
|
108
285
|
fill: ${({ theme }) => theme.colors.neutral600};
|
|
109
286
|
}
|
|
110
287
|
`;
|
|
111
288
|
const TrashIcon = styled(Trash)`
|
|
112
|
-
width: ${({ theme }) => theme.spaces[
|
|
113
|
-
height: ${({ theme }) => theme.spaces[
|
|
289
|
+
width: ${({ theme }) => theme.spaces[3]};
|
|
290
|
+
height: ${({ theme }) => theme.spaces[3]};
|
|
114
291
|
path {
|
|
115
292
|
fill: ${({ theme }) => theme.colors.danger600};
|
|
116
293
|
}
|
|
@@ -118,24 +295,6 @@ const TrashIcon = styled(Trash)`
|
|
|
118
295
|
const TypographyMaxWidth = styled(Typography)`
|
|
119
296
|
max-width: 300px;
|
|
120
297
|
`;
|
|
121
|
-
const PopoverButton = ({ onClick, disabled, children }) => {
|
|
122
|
-
return /* @__PURE__ */ jsx(
|
|
123
|
-
StyledFlex,
|
|
124
|
-
{
|
|
125
|
-
paddingTop: 2,
|
|
126
|
-
paddingBottom: 2,
|
|
127
|
-
paddingLeft: 4,
|
|
128
|
-
paddingRight: 4,
|
|
129
|
-
alignItems: "center",
|
|
130
|
-
gap: 2,
|
|
131
|
-
as: "button",
|
|
132
|
-
hasRadius: true,
|
|
133
|
-
onClick,
|
|
134
|
-
disabled,
|
|
135
|
-
children
|
|
136
|
-
}
|
|
137
|
-
);
|
|
138
|
-
};
|
|
139
298
|
const EntryValidationText = ({ action, schema, components, entry }) => {
|
|
140
299
|
const { formatMessage } = useIntl();
|
|
141
300
|
const { validate } = unstable_useDocument();
|
|
@@ -184,10 +343,8 @@ const ReleaseDetailsLayout = ({
|
|
|
184
343
|
toggleWarningSubmit,
|
|
185
344
|
children
|
|
186
345
|
}) => {
|
|
187
|
-
const { formatMessage } = useIntl();
|
|
346
|
+
const { formatMessage, formatDate, formatTime } = useIntl();
|
|
188
347
|
const { releaseId } = useParams();
|
|
189
|
-
const [isPopoverVisible, setIsPopoverVisible] = React.useState(false);
|
|
190
|
-
const moreButtonRef = React.useRef(null);
|
|
191
348
|
const {
|
|
192
349
|
data,
|
|
193
350
|
isLoading: isLoadingDetails,
|
|
@@ -201,14 +358,8 @@ const ReleaseDetailsLayout = ({
|
|
|
201
358
|
allowedActions: { canUpdate, canDelete }
|
|
202
359
|
} = useRBAC(PERMISSIONS);
|
|
203
360
|
const dispatch = useTypedDispatch();
|
|
361
|
+
const { trackUsage } = useTracking();
|
|
204
362
|
const release = data?.data;
|
|
205
|
-
const handleTogglePopover = () => {
|
|
206
|
-
setIsPopoverVisible((prev) => !prev);
|
|
207
|
-
};
|
|
208
|
-
const openReleaseModal = () => {
|
|
209
|
-
toggleEditReleaseModal();
|
|
210
|
-
handleTogglePopover();
|
|
211
|
-
};
|
|
212
363
|
const handlePublishRelease = async () => {
|
|
213
364
|
const response = await publishRelease({ id: releaseId });
|
|
214
365
|
if ("data" in response) {
|
|
@@ -219,6 +370,12 @@ const ReleaseDetailsLayout = ({
|
|
|
219
370
|
defaultMessage: "Release was published successfully."
|
|
220
371
|
})
|
|
221
372
|
});
|
|
373
|
+
const { totalEntries: totalEntries2, totalPublishedEntries, totalUnpublishedEntries } = response.data.meta;
|
|
374
|
+
trackUsage("didPublishRelease", {
|
|
375
|
+
totalEntries: totalEntries2,
|
|
376
|
+
totalPublishedEntries,
|
|
377
|
+
totalUnpublishedEntries
|
|
378
|
+
});
|
|
222
379
|
} else if (isAxiosError(response.error)) {
|
|
223
380
|
toggleNotification({
|
|
224
381
|
type: "warning",
|
|
@@ -231,13 +388,21 @@ const ReleaseDetailsLayout = ({
|
|
|
231
388
|
});
|
|
232
389
|
}
|
|
233
390
|
};
|
|
234
|
-
const openWarningConfirmDialog = () => {
|
|
235
|
-
toggleWarningSubmit();
|
|
236
|
-
handleTogglePopover();
|
|
237
|
-
};
|
|
238
391
|
const handleRefresh = () => {
|
|
239
392
|
dispatch(releaseApi.util.invalidateTags([{ type: "ReleaseAction", id: "LIST" }]));
|
|
240
393
|
};
|
|
394
|
+
const getCreatedByUser = () => {
|
|
395
|
+
if (!release?.createdBy) {
|
|
396
|
+
return null;
|
|
397
|
+
}
|
|
398
|
+
if (release.createdBy.username) {
|
|
399
|
+
return release.createdBy.username;
|
|
400
|
+
}
|
|
401
|
+
if (release.createdBy.firstname) {
|
|
402
|
+
return `${release.createdBy.firstname} ${release.createdBy.lastname || ""}`.trim();
|
|
403
|
+
}
|
|
404
|
+
return release.createdBy.email;
|
|
405
|
+
};
|
|
241
406
|
if (isLoadingDetails) {
|
|
242
407
|
return /* @__PURE__ */ jsx(Main, { "aria-busy": isLoadingDetails, children: /* @__PURE__ */ jsx(LoadingIndicatorPage, {}) });
|
|
243
408
|
}
|
|
@@ -259,90 +424,125 @@ const ReleaseDetailsLayout = ({
|
|
|
259
424
|
);
|
|
260
425
|
}
|
|
261
426
|
const totalEntries = release.actions.meta.count || 0;
|
|
262
|
-
const
|
|
427
|
+
const hasCreatedByUser = Boolean(getCreatedByUser());
|
|
428
|
+
const IsSchedulingEnabled = window.strapi.future.isEnabled("contentReleasesScheduling");
|
|
429
|
+
const isScheduled = release.scheduledAt && release.timezone;
|
|
430
|
+
const numberOfEntriesText = formatMessage(
|
|
431
|
+
{
|
|
432
|
+
id: "content-releases.pages.Details.header-subtitle",
|
|
433
|
+
defaultMessage: "{number, plural, =0 {No entries} one {# entry} other {# entries}}"
|
|
434
|
+
},
|
|
435
|
+
{ number: totalEntries }
|
|
436
|
+
);
|
|
437
|
+
const scheduledText = isScheduled ? formatMessage(
|
|
438
|
+
{
|
|
439
|
+
id: "content-releases.pages.ReleaseDetails.header-subtitle.scheduled",
|
|
440
|
+
defaultMessage: "Scheduled for {date} at {time} ({offset})"
|
|
441
|
+
},
|
|
442
|
+
{
|
|
443
|
+
date: formatDate(new Date(release.scheduledAt), {
|
|
444
|
+
weekday: "long",
|
|
445
|
+
day: "numeric",
|
|
446
|
+
month: "long",
|
|
447
|
+
year: "numeric",
|
|
448
|
+
timeZone: release.timezone
|
|
449
|
+
}),
|
|
450
|
+
time: formatTime(new Date(release.scheduledAt), {
|
|
451
|
+
timeZone: release.timezone,
|
|
452
|
+
hourCycle: "h23"
|
|
453
|
+
}),
|
|
454
|
+
offset: getTimezoneOffset(release.timezone, new Date(release.scheduledAt))
|
|
455
|
+
}
|
|
456
|
+
) : "";
|
|
263
457
|
return /* @__PURE__ */ jsxs(Main, { "aria-busy": isLoadingDetails, children: [
|
|
264
458
|
/* @__PURE__ */ jsx(
|
|
265
459
|
HeaderLayout,
|
|
266
460
|
{
|
|
267
461
|
title: release.name,
|
|
268
|
-
subtitle:
|
|
269
|
-
{
|
|
270
|
-
id: "content-releases.pages.Details.header-subtitle",
|
|
271
|
-
defaultMessage: "{number, plural, =0 {No entries} one {# entry} other {# entries}}"
|
|
272
|
-
},
|
|
273
|
-
{ number: totalEntries }
|
|
274
|
-
),
|
|
462
|
+
subtitle: numberOfEntriesText + (IsSchedulingEnabled && isScheduled ? ` - ${scheduledText}` : ""),
|
|
275
463
|
navigationAction: /* @__PURE__ */ jsx(Link, { startIcon: /* @__PURE__ */ jsx(ArrowLeft, {}), to: "/plugins/content-releases", children: formatMessage({
|
|
276
464
|
id: "global.back",
|
|
277
465
|
defaultMessage: "Back"
|
|
278
466
|
}) }),
|
|
279
467
|
primaryAction: !release.releasedAt && /* @__PURE__ */ jsxs(Flex, { gap: 2, children: [
|
|
280
|
-
/* @__PURE__ */
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
468
|
+
/* @__PURE__ */ jsxs(Menu.Root, { children: [
|
|
469
|
+
/* @__PURE__ */ jsx(
|
|
470
|
+
Menu.Trigger,
|
|
471
|
+
{
|
|
472
|
+
as: IconButton,
|
|
473
|
+
paddingLeft: 2,
|
|
474
|
+
paddingRight: 2,
|
|
475
|
+
"aria-label": formatMessage({
|
|
476
|
+
id: "content-releases.header.actions.open-release-actions",
|
|
477
|
+
defaultMessage: "Release edit and delete menu"
|
|
478
|
+
}),
|
|
479
|
+
icon: /* @__PURE__ */ jsx(More, {}),
|
|
480
|
+
variant: "tertiary"
|
|
481
|
+
}
|
|
482
|
+
),
|
|
483
|
+
/* @__PURE__ */ jsxs(Menu.Content, { top: 1, popoverPlacement: "bottom-end", children: [
|
|
484
|
+
/* @__PURE__ */ jsxs(
|
|
485
|
+
Flex,
|
|
486
|
+
{
|
|
487
|
+
alignItems: "center",
|
|
488
|
+
justifyContent: "center",
|
|
489
|
+
direction: "column",
|
|
490
|
+
padding: 1,
|
|
491
|
+
width: "100%",
|
|
492
|
+
children: [
|
|
493
|
+
/* @__PURE__ */ jsx(StyledMenuItem, { disabled: !canUpdate, onSelect: toggleEditReleaseModal, children: /* @__PURE__ */ jsxs(Flex, { alignItems: "center", gap: 2, hasRadius: true, width: "100%", children: [
|
|
494
|
+
/* @__PURE__ */ jsx(PencilIcon, {}),
|
|
495
|
+
/* @__PURE__ */ jsx(Typography, { ellipsis: true, children: formatMessage({
|
|
496
|
+
id: "content-releases.header.actions.edit",
|
|
497
|
+
defaultMessage: "Edit"
|
|
498
|
+
}) })
|
|
499
|
+
] }) }),
|
|
500
|
+
/* @__PURE__ */ jsx(
|
|
501
|
+
StyledMenuItem,
|
|
502
|
+
{
|
|
503
|
+
disabled: !canDelete,
|
|
504
|
+
onSelect: toggleWarningSubmit,
|
|
505
|
+
variant: "danger",
|
|
506
|
+
children: /* @__PURE__ */ jsxs(Flex, { alignItems: "center", gap: 2, hasRadius: true, width: "100%", children: [
|
|
507
|
+
/* @__PURE__ */ jsx(TrashIcon, {}),
|
|
508
|
+
/* @__PURE__ */ jsx(Typography, { ellipsis: true, textColor: "danger600", children: formatMessage({
|
|
509
|
+
id: "content-releases.header.actions.delete",
|
|
510
|
+
defaultMessage: "Delete"
|
|
511
|
+
}) })
|
|
512
|
+
] })
|
|
513
|
+
}
|
|
514
|
+
)
|
|
515
|
+
]
|
|
516
|
+
}
|
|
517
|
+
),
|
|
518
|
+
/* @__PURE__ */ jsxs(
|
|
519
|
+
ReleaseInfoWrapper,
|
|
520
|
+
{
|
|
521
|
+
direction: "column",
|
|
522
|
+
justifyContent: "center",
|
|
523
|
+
alignItems: "flex-start",
|
|
524
|
+
gap: 1,
|
|
525
|
+
padding: 5,
|
|
526
|
+
children: [
|
|
527
|
+
/* @__PURE__ */ jsx(Typography, { variant: "pi", fontWeight: "bold", children: formatMessage({
|
|
528
|
+
id: "content-releases.header.actions.created",
|
|
529
|
+
defaultMessage: "Created"
|
|
530
|
+
}) }),
|
|
531
|
+
/* @__PURE__ */ jsxs(Typography, { variant: "pi", color: "neutral300", children: [
|
|
532
|
+
/* @__PURE__ */ jsx(RelativeTime, { timestamp: new Date(release.createdAt) }),
|
|
533
|
+
formatMessage(
|
|
534
|
+
{
|
|
535
|
+
id: "content-releases.header.actions.created.description",
|
|
536
|
+
defaultMessage: "{hasCreatedByUser, select, true { by {createdBy}} other { by deleted user}}"
|
|
537
|
+
},
|
|
538
|
+
{ createdBy: getCreatedByUser(), hasCreatedByUser }
|
|
539
|
+
)
|
|
540
|
+
] })
|
|
541
|
+
]
|
|
542
|
+
}
|
|
543
|
+
)
|
|
544
|
+
] })
|
|
545
|
+
] }),
|
|
346
546
|
/* @__PURE__ */ jsx(Button, { size: "S", variant: "tertiary", onClick: handleRefresh, children: formatMessage({
|
|
347
547
|
id: "content-releases.header.actions.refresh",
|
|
348
548
|
defaultMessage: "Refresh"
|
|
@@ -398,6 +598,9 @@ const ReleaseDetailsBody = () => {
|
|
|
398
598
|
isError: isReleaseError,
|
|
399
599
|
error: releaseError
|
|
400
600
|
} = useGetReleaseQuery({ id: releaseId });
|
|
601
|
+
const {
|
|
602
|
+
allowedActions: { canUpdate }
|
|
603
|
+
} = useRBAC(PERMISSIONS);
|
|
401
604
|
const release = releaseData?.data;
|
|
402
605
|
const selectedGroupBy = query?.groupBy || "contentType";
|
|
403
606
|
const {
|
|
@@ -411,7 +614,7 @@ const ReleaseDetailsBody = () => {
|
|
|
411
614
|
releaseId
|
|
412
615
|
});
|
|
413
616
|
const [updateReleaseAction] = useUpdateReleaseActionMutation();
|
|
414
|
-
const handleChangeType = async (e, actionId) => {
|
|
617
|
+
const handleChangeType = async (e, actionId, actionPath) => {
|
|
415
618
|
const response = await updateReleaseAction({
|
|
416
619
|
params: {
|
|
417
620
|
releaseId,
|
|
@@ -419,7 +622,11 @@ const ReleaseDetailsBody = () => {
|
|
|
419
622
|
},
|
|
420
623
|
body: {
|
|
421
624
|
type: e.target.value
|
|
422
|
-
}
|
|
625
|
+
},
|
|
626
|
+
query,
|
|
627
|
+
// We are passing the query params to make optimistic updates
|
|
628
|
+
actionPath
|
|
629
|
+
// We are passing the action path to found the position in the cache of the action for optimistic updates
|
|
423
630
|
});
|
|
424
631
|
if ("error" in response) {
|
|
425
632
|
if (isAxiosError(response.error)) {
|
|
@@ -500,7 +707,7 @@ const ReleaseDetailsBody = () => {
|
|
|
500
707
|
SingleSelect,
|
|
501
708
|
{
|
|
502
709
|
"aria-label": formatMessage({
|
|
503
|
-
id: "content-releases.pages.ReleaseDetails.groupBy.label",
|
|
710
|
+
id: "content-releases.pages.ReleaseDetails.groupBy.aria-label",
|
|
504
711
|
defaultMessage: "Group by"
|
|
505
712
|
}),
|
|
506
713
|
customizeContent: (value) => formatMessage(
|
|
@@ -518,7 +725,7 @@ const ReleaseDetailsBody = () => {
|
|
|
518
725
|
}
|
|
519
726
|
) }),
|
|
520
727
|
Object.keys(releaseActions).map((key) => /* @__PURE__ */ jsxs(Flex, { gap: 4, direction: "column", alignItems: "stretch", children: [
|
|
521
|
-
/* @__PURE__ */ jsx(Flex, { children: /* @__PURE__ */ jsx(Badge, { children: key }) }),
|
|
728
|
+
/* @__PURE__ */ jsx(Flex, { role: "separator", "aria-label": key, children: /* @__PURE__ */ jsx(Badge, { children: key }) }),
|
|
522
729
|
/* @__PURE__ */ jsx(
|
|
523
730
|
Table.Root,
|
|
524
731
|
{
|
|
@@ -588,56 +795,59 @@ const ReleaseDetailsBody = () => {
|
|
|
588
795
|
)
|
|
589
796
|
] }),
|
|
590
797
|
/* @__PURE__ */ jsx(Table.LoadingBody, {}),
|
|
591
|
-
/* @__PURE__ */ jsx(Table.Body, { children: releaseActions[key].map(
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
{
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
selected: type,
|
|
608
|
-
handleChange: (e) => handleChangeType(e, id),
|
|
609
|
-
name: `release-action-${id}-type`
|
|
610
|
-
}
|
|
611
|
-
) }),
|
|
612
|
-
!release.releasedAt && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
613
|
-
/* @__PURE__ */ jsx(Td, { width: "20%", minWidth: "200px", children: /* @__PURE__ */ jsx(
|
|
614
|
-
EntryValidationText,
|
|
798
|
+
/* @__PURE__ */ jsx(Table.Body, { children: releaseActions[key].map(
|
|
799
|
+
({ id, contentType, locale, type, entry }, actionIndex) => /* @__PURE__ */ jsxs(Tr, { children: [
|
|
800
|
+
/* @__PURE__ */ jsx(Td, { width: "25%", maxWidth: "200px", children: /* @__PURE__ */ jsx(Typography, { ellipsis: true, children: `${contentType.mainFieldValue || entry.id}` }) }),
|
|
801
|
+
/* @__PURE__ */ jsx(Td, { width: "10%", children: /* @__PURE__ */ jsx(Typography, { children: `${locale?.name ? locale.name : "-"}` }) }),
|
|
802
|
+
/* @__PURE__ */ jsx(Td, { width: "10%", children: /* @__PURE__ */ jsx(Typography, { children: contentType.displayName || "" }) }),
|
|
803
|
+
/* @__PURE__ */ jsx(Td, { width: "20%", children: release.releasedAt ? /* @__PURE__ */ jsx(Typography, { children: formatMessage(
|
|
804
|
+
{
|
|
805
|
+
id: "content-releases.page.ReleaseDetails.table.action-published",
|
|
806
|
+
defaultMessage: "This entry was <b>{isPublish, select, true {published} other {unpublished}}</b>."
|
|
807
|
+
},
|
|
808
|
+
{
|
|
809
|
+
isPublish: type === "publish",
|
|
810
|
+
b: (children) => /* @__PURE__ */ jsx(Typography, { fontWeight: "bold", children })
|
|
811
|
+
}
|
|
812
|
+
) }) : /* @__PURE__ */ jsx(
|
|
813
|
+
ReleaseActionOptions,
|
|
615
814
|
{
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
815
|
+
selected: type,
|
|
816
|
+
handleChange: (e) => handleChangeType(e, id, [key, actionIndex]),
|
|
817
|
+
name: `release-action-${id}-type`,
|
|
818
|
+
disabled: !canUpdate
|
|
620
819
|
}
|
|
621
820
|
) }),
|
|
622
|
-
|
|
623
|
-
/* @__PURE__ */ jsx(
|
|
624
|
-
|
|
821
|
+
!release.releasedAt && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
822
|
+
/* @__PURE__ */ jsx(Td, { width: "20%", minWidth: "200px", children: /* @__PURE__ */ jsx(
|
|
823
|
+
EntryValidationText,
|
|
625
824
|
{
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
825
|
+
action: type,
|
|
826
|
+
schema: contentTypes?.[contentType.uid],
|
|
827
|
+
components,
|
|
828
|
+
entry
|
|
629
829
|
}
|
|
630
|
-
),
|
|
631
|
-
/* @__PURE__ */ jsx(
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
830
|
+
) }),
|
|
831
|
+
/* @__PURE__ */ jsx(Td, { children: /* @__PURE__ */ jsx(Flex, { justifyContent: "flex-end", children: /* @__PURE__ */ jsxs(ReleaseActionMenu.Root, { children: [
|
|
832
|
+
/* @__PURE__ */ jsx(
|
|
833
|
+
ReleaseActionMenu.ReleaseActionEntryLinkItem,
|
|
834
|
+
{
|
|
835
|
+
contentTypeUid: contentType.uid,
|
|
836
|
+
entryId: entry.id,
|
|
837
|
+
locale: locale?.code
|
|
838
|
+
}
|
|
839
|
+
),
|
|
840
|
+
/* @__PURE__ */ jsx(
|
|
841
|
+
ReleaseActionMenu.DeleteReleaseActionItem,
|
|
842
|
+
{
|
|
843
|
+
releaseId: release.id,
|
|
844
|
+
actionId: id
|
|
845
|
+
}
|
|
846
|
+
)
|
|
847
|
+
] }) }) })
|
|
848
|
+
] })
|
|
849
|
+
] }, id)
|
|
850
|
+
) })
|
|
641
851
|
] })
|
|
642
852
|
}
|
|
643
853
|
)
|
|
@@ -684,11 +894,18 @@ const ReleaseDetailsPage = () => {
|
|
|
684
894
|
}
|
|
685
895
|
);
|
|
686
896
|
}
|
|
687
|
-
const
|
|
897
|
+
const releaseData = isSuccessDetails && data?.data || null;
|
|
898
|
+
const title = releaseData?.name || "";
|
|
899
|
+
const timezone = releaseData?.timezone ?? null;
|
|
900
|
+
const scheduledAt = releaseData?.scheduledAt && timezone ? utcToZonedTime(releaseData.scheduledAt, timezone) : null;
|
|
901
|
+
const date = scheduledAt ? new Date(format(scheduledAt, "yyyy-MM-dd")) : null;
|
|
902
|
+
const time = scheduledAt ? format(scheduledAt, "HH:mm") : "";
|
|
688
903
|
const handleEditRelease = async (values) => {
|
|
689
904
|
const response = await updateRelease({
|
|
690
905
|
id: releaseId,
|
|
691
|
-
name: values.name
|
|
906
|
+
name: values.name,
|
|
907
|
+
scheduledAt: values.scheduledAt,
|
|
908
|
+
timezone: values.timezone
|
|
692
909
|
});
|
|
693
910
|
if ("data" in response) {
|
|
694
911
|
toggleNotification({
|
|
@@ -742,7 +959,14 @@ const ReleaseDetailsPage = () => {
|
|
|
742
959
|
handleClose: toggleEditReleaseModal,
|
|
743
960
|
handleSubmit: handleEditRelease,
|
|
744
961
|
isLoading: isLoadingDetails || isSubmittingForm,
|
|
745
|
-
initialValues: {
|
|
962
|
+
initialValues: {
|
|
963
|
+
name: title || "",
|
|
964
|
+
scheduledAt,
|
|
965
|
+
date,
|
|
966
|
+
time,
|
|
967
|
+
isScheduled: Boolean(scheduledAt),
|
|
968
|
+
timezone
|
|
969
|
+
}
|
|
746
970
|
}
|
|
747
971
|
),
|
|
748
972
|
/* @__PURE__ */ jsx(
|
|
@@ -762,42 +986,12 @@ const ReleaseDetailsPage = () => {
|
|
|
762
986
|
}
|
|
763
987
|
);
|
|
764
988
|
};
|
|
765
|
-
const ReleasesLayout = ({
|
|
766
|
-
isLoading,
|
|
767
|
-
totalReleases,
|
|
768
|
-
onClickAddRelease,
|
|
769
|
-
children
|
|
770
|
-
}) => {
|
|
771
|
-
const { formatMessage } = useIntl();
|
|
772
|
-
return /* @__PURE__ */ jsxs(Main, { "aria-busy": isLoading, children: [
|
|
773
|
-
/* @__PURE__ */ jsx(
|
|
774
|
-
HeaderLayout,
|
|
775
|
-
{
|
|
776
|
-
title: formatMessage({
|
|
777
|
-
id: "content-releases.pages.Releases.title",
|
|
778
|
-
defaultMessage: "Releases"
|
|
779
|
-
}),
|
|
780
|
-
subtitle: !isLoading && formatMessage(
|
|
781
|
-
{
|
|
782
|
-
id: "content-releases.pages.Releases.header-subtitle",
|
|
783
|
-
defaultMessage: "{number, plural, =0 {No releases} one {# release} other {# releases}}"
|
|
784
|
-
},
|
|
785
|
-
{ number: totalReleases }
|
|
786
|
-
),
|
|
787
|
-
primaryAction: /* @__PURE__ */ jsx(CheckPermissions, { permissions: PERMISSIONS.create, children: /* @__PURE__ */ jsx(Button, { startIcon: /* @__PURE__ */ jsx(Plus, {}), onClick: onClickAddRelease, children: formatMessage({
|
|
788
|
-
id: "content-releases.header.actions.add-release",
|
|
789
|
-
defaultMessage: "New release"
|
|
790
|
-
}) }) })
|
|
791
|
-
}
|
|
792
|
-
),
|
|
793
|
-
children
|
|
794
|
-
] });
|
|
795
|
-
};
|
|
796
989
|
const LinkCard = styled(Link$2)`
|
|
797
990
|
display: block;
|
|
798
991
|
`;
|
|
799
992
|
const ReleasesGrid = ({ sectionTitle, releases = [], isError = false }) => {
|
|
800
993
|
const { formatMessage } = useIntl();
|
|
994
|
+
const IsSchedulingEnabled = window.strapi.future.isEnabled("contentReleasesScheduling");
|
|
801
995
|
if (isError) {
|
|
802
996
|
return /* @__PURE__ */ jsx(AnErrorOccurred, {});
|
|
803
997
|
}
|
|
@@ -818,7 +1012,7 @@ const ReleasesGrid = ({ sectionTitle, releases = [], isError = false }) => {
|
|
|
818
1012
|
}
|
|
819
1013
|
);
|
|
820
1014
|
}
|
|
821
|
-
return /* @__PURE__ */ jsx(Grid, { gap: 4, children: releases.map(({ id, name, actions }) => /* @__PURE__ */ jsx(GridItem, { col: 3, s: 6, xs: 12, children: /* @__PURE__ */ jsx(LinkCard, { href: `content-releases/${id}`, isExternal: false, children: /* @__PURE__ */ jsxs(
|
|
1015
|
+
return /* @__PURE__ */ jsx(Grid, { gap: 4, children: releases.map(({ id, name, actions, scheduledAt }) => /* @__PURE__ */ jsx(GridItem, { col: 3, s: 6, xs: 12, children: /* @__PURE__ */ jsx(LinkCard, { href: `content-releases/${id}`, isExternal: false, children: /* @__PURE__ */ jsxs(
|
|
822
1016
|
Flex,
|
|
823
1017
|
{
|
|
824
1018
|
direction: "column",
|
|
@@ -833,7 +1027,10 @@ const ReleasesGrid = ({ sectionTitle, releases = [], isError = false }) => {
|
|
|
833
1027
|
gap: 2,
|
|
834
1028
|
children: [
|
|
835
1029
|
/* @__PURE__ */ jsx(Typography, { as: "h3", variant: "delta", fontWeight: "bold", children: name }),
|
|
836
|
-
/* @__PURE__ */ jsx(Typography, { variant: "pi", children: formatMessage(
|
|
1030
|
+
/* @__PURE__ */ jsx(Typography, { variant: "pi", textColor: "neutral600", children: IsSchedulingEnabled ? scheduledAt ? /* @__PURE__ */ jsx(RelativeTime, { timestamp: new Date(scheduledAt) }) : formatMessage({
|
|
1031
|
+
id: "content-releases.pages.Releases.not-scheduled",
|
|
1032
|
+
defaultMessage: "Not scheduled"
|
|
1033
|
+
}) : formatMessage(
|
|
837
1034
|
{
|
|
838
1035
|
id: "content-releases.page.Releases.release-item.entries",
|
|
839
1036
|
defaultMessage: "{number, plural, =0 {No entries} one {# entry} other {# entries}}"
|
|
@@ -844,8 +1041,22 @@ const ReleasesGrid = ({ sectionTitle, releases = [], isError = false }) => {
|
|
|
844
1041
|
}
|
|
845
1042
|
) }) }, id)) });
|
|
846
1043
|
};
|
|
1044
|
+
const StyledAlert = styled(Alert)`
|
|
1045
|
+
button {
|
|
1046
|
+
display: none;
|
|
1047
|
+
}
|
|
1048
|
+
p + div {
|
|
1049
|
+
margin-left: auto;
|
|
1050
|
+
}
|
|
1051
|
+
`;
|
|
847
1052
|
const INITIAL_FORM_VALUES = {
|
|
848
|
-
name: ""
|
|
1053
|
+
name: "",
|
|
1054
|
+
date: null,
|
|
1055
|
+
time: "",
|
|
1056
|
+
// Remove future flag check after Scheduling Beta release and replace with true as creating new release should include scheduling by default
|
|
1057
|
+
isScheduled: window.strapi.future.isEnabled("contentReleasesScheduling"),
|
|
1058
|
+
scheduledAt: null,
|
|
1059
|
+
timezone: null
|
|
849
1060
|
};
|
|
850
1061
|
const ReleasesPage = () => {
|
|
851
1062
|
const tabRef = React.useRef(null);
|
|
@@ -858,6 +1069,9 @@ const ReleasesPage = () => {
|
|
|
858
1069
|
const [{ query }, setQuery] = useQueryParams();
|
|
859
1070
|
const response = useGetReleasesQuery(query);
|
|
860
1071
|
const [createRelease, { isLoading: isSubmittingForm }] = useCreateReleaseMutation();
|
|
1072
|
+
const { getFeature } = useLicenseLimits();
|
|
1073
|
+
const { maximumReleases = 3 } = getFeature("cms-content-releases");
|
|
1074
|
+
const { trackUsage } = useTracking();
|
|
861
1075
|
const { isLoading, isSuccess, isError } = response;
|
|
862
1076
|
const activeTab = response?.currentData?.meta?.activeTab || "pending";
|
|
863
1077
|
const activeTabIndex = ["pending", "done"].indexOf(activeTab);
|
|
@@ -886,9 +1100,10 @@ const ReleasesPage = () => {
|
|
|
886
1100
|
setReleaseModalShown((prev) => !prev);
|
|
887
1101
|
};
|
|
888
1102
|
if (isLoading) {
|
|
889
|
-
return /* @__PURE__ */ jsx(
|
|
1103
|
+
return /* @__PURE__ */ jsx(Main, { "aria-busy": isLoading, children: /* @__PURE__ */ jsx(LoadingIndicatorPage, {}) });
|
|
890
1104
|
}
|
|
891
|
-
const
|
|
1105
|
+
const totalPendingReleases = isSuccess && response.currentData?.meta?.pendingReleasesCount || 0;
|
|
1106
|
+
const hasReachedMaximumPendingReleases = totalPendingReleases >= maximumReleases;
|
|
892
1107
|
const handleTabChange = (index) => {
|
|
893
1108
|
setQuery({
|
|
894
1109
|
...query,
|
|
@@ -901,9 +1116,11 @@ const ReleasesPage = () => {
|
|
|
901
1116
|
}
|
|
902
1117
|
});
|
|
903
1118
|
};
|
|
904
|
-
const handleAddRelease = async (
|
|
1119
|
+
const handleAddRelease = async ({ name, scheduledAt, timezone }) => {
|
|
905
1120
|
const response2 = await createRelease({
|
|
906
|
-
name
|
|
1121
|
+
name,
|
|
1122
|
+
scheduledAt,
|
|
1123
|
+
timezone
|
|
907
1124
|
});
|
|
908
1125
|
if ("data" in response2) {
|
|
909
1126
|
toggleNotification({
|
|
@@ -913,6 +1130,7 @@ const ReleasesPage = () => {
|
|
|
913
1130
|
defaultMessage: "Release created."
|
|
914
1131
|
})
|
|
915
1132
|
});
|
|
1133
|
+
trackUsage("didCreateRelease");
|
|
916
1134
|
push(`/plugins/content-releases/${response2.data.data.id}`);
|
|
917
1135
|
} else if (isAxiosError(response2.error)) {
|
|
918
1136
|
toggleNotification({
|
|
@@ -926,8 +1144,57 @@ const ReleasesPage = () => {
|
|
|
926
1144
|
});
|
|
927
1145
|
}
|
|
928
1146
|
};
|
|
929
|
-
return /* @__PURE__ */ jsxs(
|
|
1147
|
+
return /* @__PURE__ */ jsxs(Main, { "aria-busy": isLoading, children: [
|
|
1148
|
+
/* @__PURE__ */ jsx(
|
|
1149
|
+
HeaderLayout,
|
|
1150
|
+
{
|
|
1151
|
+
title: formatMessage({
|
|
1152
|
+
id: "content-releases.pages.Releases.title",
|
|
1153
|
+
defaultMessage: "Releases"
|
|
1154
|
+
}),
|
|
1155
|
+
subtitle: formatMessage({
|
|
1156
|
+
id: "content-releases.pages.Releases.header-subtitle",
|
|
1157
|
+
defaultMessage: "Create and manage content updates"
|
|
1158
|
+
}),
|
|
1159
|
+
primaryAction: /* @__PURE__ */ jsx(CheckPermissions, { permissions: PERMISSIONS.create, children: /* @__PURE__ */ jsx(
|
|
1160
|
+
Button,
|
|
1161
|
+
{
|
|
1162
|
+
startIcon: /* @__PURE__ */ jsx(Plus, {}),
|
|
1163
|
+
onClick: toggleAddReleaseModal,
|
|
1164
|
+
disabled: hasReachedMaximumPendingReleases,
|
|
1165
|
+
children: formatMessage({
|
|
1166
|
+
id: "content-releases.header.actions.add-release",
|
|
1167
|
+
defaultMessage: "New release"
|
|
1168
|
+
})
|
|
1169
|
+
}
|
|
1170
|
+
) })
|
|
1171
|
+
}
|
|
1172
|
+
),
|
|
930
1173
|
/* @__PURE__ */ jsx(ContentLayout, { children: /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
1174
|
+
hasReachedMaximumPendingReleases && /* @__PURE__ */ jsx(
|
|
1175
|
+
StyledAlert,
|
|
1176
|
+
{
|
|
1177
|
+
marginBottom: 6,
|
|
1178
|
+
action: /* @__PURE__ */ jsx(Link$2, { href: "https://strapi.io/pricing-cloud", isExternal: true, children: formatMessage({
|
|
1179
|
+
id: "content-releases.pages.Releases.max-limit-reached.action",
|
|
1180
|
+
defaultMessage: "Explore plans"
|
|
1181
|
+
}) }),
|
|
1182
|
+
title: formatMessage(
|
|
1183
|
+
{
|
|
1184
|
+
id: "content-releases.pages.Releases.max-limit-reached.title",
|
|
1185
|
+
defaultMessage: "You have reached the {number} pending {number, plural, one {release} other {releases}} limit."
|
|
1186
|
+
},
|
|
1187
|
+
{ number: maximumReleases }
|
|
1188
|
+
),
|
|
1189
|
+
onClose: () => {
|
|
1190
|
+
},
|
|
1191
|
+
closeLabel: "",
|
|
1192
|
+
children: formatMessage({
|
|
1193
|
+
id: "content-releases.pages.Releases.max-limit-reached.message",
|
|
1194
|
+
defaultMessage: "Upgrade to manage an unlimited number of releases."
|
|
1195
|
+
})
|
|
1196
|
+
}
|
|
1197
|
+
),
|
|
931
1198
|
/* @__PURE__ */ jsxs(
|
|
932
1199
|
TabGroup,
|
|
933
1200
|
{
|
|
@@ -942,10 +1209,15 @@ const ReleasesPage = () => {
|
|
|
942
1209
|
children: [
|
|
943
1210
|
/* @__PURE__ */ jsxs(Box, { paddingBottom: 8, children: [
|
|
944
1211
|
/* @__PURE__ */ jsxs(Tabs, { children: [
|
|
945
|
-
/* @__PURE__ */ jsx(Tab, { children: formatMessage(
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
1212
|
+
/* @__PURE__ */ jsx(Tab, { children: formatMessage(
|
|
1213
|
+
{
|
|
1214
|
+
id: "content-releases.pages.Releases.tab.pending",
|
|
1215
|
+
defaultMessage: "Pending ({count})"
|
|
1216
|
+
},
|
|
1217
|
+
{
|
|
1218
|
+
count: totalPendingReleases
|
|
1219
|
+
}
|
|
1220
|
+
) }),
|
|
949
1221
|
/* @__PURE__ */ jsx(Tab, { children: formatMessage({
|
|
950
1222
|
id: "content-releases.pages.Releases.tab.done",
|
|
951
1223
|
defaultMessage: "Done"
|
|
@@ -974,7 +1246,7 @@ const ReleasesPage = () => {
|
|
|
974
1246
|
]
|
|
975
1247
|
}
|
|
976
1248
|
),
|
|
977
|
-
|
|
1249
|
+
response.currentData?.meta?.pagination?.total ? /* @__PURE__ */ jsxs(Flex, { paddingTop: 4, alignItems: "flex-end", justifyContent: "space-between", children: [
|
|
978
1250
|
/* @__PURE__ */ jsx(
|
|
979
1251
|
PageSizeURLQuery,
|
|
980
1252
|
{
|
|
@@ -990,7 +1262,7 @@ const ReleasesPage = () => {
|
|
|
990
1262
|
}
|
|
991
1263
|
}
|
|
992
1264
|
)
|
|
993
|
-
] })
|
|
1265
|
+
] }) : null
|
|
994
1266
|
] }) }),
|
|
995
1267
|
releaseModalShown && /* @__PURE__ */ jsx(
|
|
996
1268
|
ReleaseModal,
|
|
@@ -1012,4 +1284,4 @@ const App = () => {
|
|
|
1012
1284
|
export {
|
|
1013
1285
|
App
|
|
1014
1286
|
};
|
|
1015
|
-
//# sourceMappingURL=App-
|
|
1287
|
+
//# sourceMappingURL=App-g3vtS2Wa.mjs.map
|