@strapi/content-releases 0.0.0-next.6d59515520a3850456f256fb0e4c54b75054ddf4 → 0.0.0-next.898f8ae81b2cb3f89bd012e9db20a2d9b78a48d2
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-_20W9dYa.js → App-OK4Xac-O.js} +518 -240
- package/dist/_chunks/App-OK4Xac-O.js.map +1 -0
- package/dist/_chunks/{App-L1jSxCiL.mjs → App-xAkiD42p.mjs} +522 -245
- package/dist/_chunks/App-xAkiD42p.mjs.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-gYDqKYFd.js → en-r0otWaln.js} +18 -4
- package/dist/_chunks/en-r0otWaln.js.map +1 -0
- package/dist/_chunks/{en-MyLPoISH.mjs → en-veqvqeEr.mjs} +18 -4
- package/dist/_chunks/en-veqvqeEr.mjs.map +1 -0
- package/dist/_chunks/{index-KJa1Rb5F.js → index-JvA2_26n.js} +134 -27
- package/dist/_chunks/index-JvA2_26n.js.map +1 -0
- package/dist/_chunks/{index-c4zRX_sg.mjs → index-exoiSU3V.mjs} +139 -32
- package/dist/_chunks/index-exoiSU3V.mjs.map +1 -0
- package/dist/admin/index.js +1 -1
- package/dist/admin/index.mjs +2 -2
- package/dist/server/index.js +597 -382
- package/dist/server/index.js.map +1 -1
- package/dist/server/index.mjs +597 -382
- package/dist/server/index.mjs.map +1 -1
- package/package.json +12 -9
- 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-exoiSU3V.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,16 +211,59 @@ 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
|
+
onClear: () => {
|
|
252
|
+
setFieldValue("timezone", "");
|
|
253
|
+
},
|
|
254
|
+
error: errors.timezone,
|
|
255
|
+
required: true,
|
|
256
|
+
children: timezoneList.map((timezone) => /* @__PURE__ */ jsx(ComboboxOption, { value: timezone.value, children: timezone.value.replace("_", " ") }, timezone.value))
|
|
257
|
+
}
|
|
258
|
+
);
|
|
259
|
+
};
|
|
87
260
|
const ReleaseInfoWrapper = styled(Flex)`
|
|
88
261
|
align-self: stretch;
|
|
89
262
|
border-bottom-right-radius: ${({ theme }) => theme.borderRadius};
|
|
90
263
|
border-bottom-left-radius: ${({ theme }) => theme.borderRadius};
|
|
91
264
|
border-top: 1px solid ${({ theme }) => theme.colors.neutral150};
|
|
92
265
|
`;
|
|
93
|
-
const
|
|
94
|
-
align-self: stretch;
|
|
95
|
-
cursor: ${({ disabled }) => disabled ? "not-allowed" : "pointer"};
|
|
96
|
-
|
|
266
|
+
const StyledMenuItem = styled(Menu.Item)`
|
|
97
267
|
svg path {
|
|
98
268
|
fill: ${({ theme, disabled }) => disabled && theme.colors.neutral500};
|
|
99
269
|
}
|
|
@@ -102,15 +272,15 @@ const StyledFlex = styled(Flex)`
|
|
|
102
272
|
}
|
|
103
273
|
`;
|
|
104
274
|
const PencilIcon = styled(Pencil)`
|
|
105
|
-
width: ${({ theme }) => theme.spaces[
|
|
106
|
-
height: ${({ theme }) => theme.spaces[
|
|
275
|
+
width: ${({ theme }) => theme.spaces[3]};
|
|
276
|
+
height: ${({ theme }) => theme.spaces[3]};
|
|
107
277
|
path {
|
|
108
278
|
fill: ${({ theme }) => theme.colors.neutral600};
|
|
109
279
|
}
|
|
110
280
|
`;
|
|
111
281
|
const TrashIcon = styled(Trash)`
|
|
112
|
-
width: ${({ theme }) => theme.spaces[
|
|
113
|
-
height: ${({ theme }) => theme.spaces[
|
|
282
|
+
width: ${({ theme }) => theme.spaces[3]};
|
|
283
|
+
height: ${({ theme }) => theme.spaces[3]};
|
|
114
284
|
path {
|
|
115
285
|
fill: ${({ theme }) => theme.colors.danger600};
|
|
116
286
|
}
|
|
@@ -118,24 +288,6 @@ const TrashIcon = styled(Trash)`
|
|
|
118
288
|
const TypographyMaxWidth = styled(Typography)`
|
|
119
289
|
max-width: 300px;
|
|
120
290
|
`;
|
|
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
291
|
const EntryValidationText = ({ action, schema, components, entry }) => {
|
|
140
292
|
const { formatMessage } = useIntl();
|
|
141
293
|
const { validate } = unstable_useDocument();
|
|
@@ -184,10 +336,8 @@ const ReleaseDetailsLayout = ({
|
|
|
184
336
|
toggleWarningSubmit,
|
|
185
337
|
children
|
|
186
338
|
}) => {
|
|
187
|
-
const { formatMessage } = useIntl();
|
|
339
|
+
const { formatMessage, formatDate, formatTime } = useIntl();
|
|
188
340
|
const { releaseId } = useParams();
|
|
189
|
-
const [isPopoverVisible, setIsPopoverVisible] = React.useState(false);
|
|
190
|
-
const moreButtonRef = React.useRef(null);
|
|
191
341
|
const {
|
|
192
342
|
data,
|
|
193
343
|
isLoading: isLoadingDetails,
|
|
@@ -201,14 +351,8 @@ const ReleaseDetailsLayout = ({
|
|
|
201
351
|
allowedActions: { canUpdate, canDelete }
|
|
202
352
|
} = useRBAC(PERMISSIONS);
|
|
203
353
|
const dispatch = useTypedDispatch();
|
|
354
|
+
const { trackUsage } = useTracking();
|
|
204
355
|
const release = data?.data;
|
|
205
|
-
const handleTogglePopover = () => {
|
|
206
|
-
setIsPopoverVisible((prev) => !prev);
|
|
207
|
-
};
|
|
208
|
-
const openReleaseModal = () => {
|
|
209
|
-
toggleEditReleaseModal();
|
|
210
|
-
handleTogglePopover();
|
|
211
|
-
};
|
|
212
356
|
const handlePublishRelease = async () => {
|
|
213
357
|
const response = await publishRelease({ id: releaseId });
|
|
214
358
|
if ("data" in response) {
|
|
@@ -219,6 +363,12 @@ const ReleaseDetailsLayout = ({
|
|
|
219
363
|
defaultMessage: "Release was published successfully."
|
|
220
364
|
})
|
|
221
365
|
});
|
|
366
|
+
const { totalEntries: totalEntries2, totalPublishedEntries, totalUnpublishedEntries } = response.data.meta;
|
|
367
|
+
trackUsage("didPublishRelease", {
|
|
368
|
+
totalEntries: totalEntries2,
|
|
369
|
+
totalPublishedEntries,
|
|
370
|
+
totalUnpublishedEntries
|
|
371
|
+
});
|
|
222
372
|
} else if (isAxiosError(response.error)) {
|
|
223
373
|
toggleNotification({
|
|
224
374
|
type: "warning",
|
|
@@ -231,13 +381,21 @@ const ReleaseDetailsLayout = ({
|
|
|
231
381
|
});
|
|
232
382
|
}
|
|
233
383
|
};
|
|
234
|
-
const openWarningConfirmDialog = () => {
|
|
235
|
-
toggleWarningSubmit();
|
|
236
|
-
handleTogglePopover();
|
|
237
|
-
};
|
|
238
384
|
const handleRefresh = () => {
|
|
239
385
|
dispatch(releaseApi.util.invalidateTags([{ type: "ReleaseAction", id: "LIST" }]));
|
|
240
386
|
};
|
|
387
|
+
const getCreatedByUser = () => {
|
|
388
|
+
if (!release?.createdBy) {
|
|
389
|
+
return null;
|
|
390
|
+
}
|
|
391
|
+
if (release.createdBy.username) {
|
|
392
|
+
return release.createdBy.username;
|
|
393
|
+
}
|
|
394
|
+
if (release.createdBy.firstname) {
|
|
395
|
+
return `${release.createdBy.firstname} ${release.createdBy.lastname || ""}`.trim();
|
|
396
|
+
}
|
|
397
|
+
return release.createdBy.email;
|
|
398
|
+
};
|
|
241
399
|
if (isLoadingDetails) {
|
|
242
400
|
return /* @__PURE__ */ jsx(Main, { "aria-busy": isLoadingDetails, children: /* @__PURE__ */ jsx(LoadingIndicatorPage, {}) });
|
|
243
401
|
}
|
|
@@ -259,90 +417,139 @@ const ReleaseDetailsLayout = ({
|
|
|
259
417
|
);
|
|
260
418
|
}
|
|
261
419
|
const totalEntries = release.actions.meta.count || 0;
|
|
262
|
-
const
|
|
420
|
+
const hasCreatedByUser = Boolean(getCreatedByUser());
|
|
421
|
+
const IsSchedulingEnabled = window.strapi.future.isEnabled("contentReleasesScheduling");
|
|
422
|
+
const isScheduled = release.scheduledAt && release.timezone;
|
|
423
|
+
const numberOfEntriesText = formatMessage(
|
|
424
|
+
{
|
|
425
|
+
id: "content-releases.pages.Details.header-subtitle",
|
|
426
|
+
defaultMessage: "{number, plural, =0 {No entries} one {# entry} other {# entries}}"
|
|
427
|
+
},
|
|
428
|
+
{ number: totalEntries }
|
|
429
|
+
);
|
|
430
|
+
const scheduledText = isScheduled ? formatMessage(
|
|
431
|
+
{
|
|
432
|
+
id: "content-releases.pages.ReleaseDetails.header-subtitle.scheduled",
|
|
433
|
+
defaultMessage: "Scheduled for {date} at {time} ({offset})"
|
|
434
|
+
},
|
|
435
|
+
{
|
|
436
|
+
date: formatDate(new Date(release.scheduledAt), {
|
|
437
|
+
weekday: "long",
|
|
438
|
+
day: "numeric",
|
|
439
|
+
month: "long",
|
|
440
|
+
year: "numeric",
|
|
441
|
+
timeZone: release.timezone
|
|
442
|
+
}),
|
|
443
|
+
time: formatTime(new Date(release.scheduledAt), {
|
|
444
|
+
timeZone: release.timezone,
|
|
445
|
+
hourCycle: "h23"
|
|
446
|
+
}),
|
|
447
|
+
offset: getTimezoneOffset(release.timezone, new Date(release.scheduledAt))
|
|
448
|
+
}
|
|
449
|
+
) : "";
|
|
263
450
|
return /* @__PURE__ */ jsxs(Main, { "aria-busy": isLoadingDetails, children: [
|
|
264
451
|
/* @__PURE__ */ jsx(
|
|
265
452
|
HeaderLayout,
|
|
266
453
|
{
|
|
267
454
|
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
|
-
),
|
|
455
|
+
subtitle: numberOfEntriesText + (IsSchedulingEnabled && isScheduled ? ` - ${scheduledText}` : ""),
|
|
275
456
|
navigationAction: /* @__PURE__ */ jsx(Link, { startIcon: /* @__PURE__ */ jsx(ArrowLeft, {}), to: "/plugins/content-releases", children: formatMessage({
|
|
276
457
|
id: "global.back",
|
|
277
458
|
defaultMessage: "Back"
|
|
278
459
|
}) }),
|
|
279
460
|
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
|
-
|
|
461
|
+
/* @__PURE__ */ jsxs(Menu.Root, { children: [
|
|
462
|
+
/* @__PURE__ */ jsx(
|
|
463
|
+
Menu.Trigger,
|
|
464
|
+
{
|
|
465
|
+
as: IconButton,
|
|
466
|
+
paddingLeft: 2,
|
|
467
|
+
paddingRight: 2,
|
|
468
|
+
"aria-label": formatMessage({
|
|
469
|
+
id: "content-releases.header.actions.open-release-actions",
|
|
470
|
+
defaultMessage: "Release edit and delete menu"
|
|
471
|
+
}),
|
|
472
|
+
icon: /* @__PURE__ */ jsx(More, {}),
|
|
473
|
+
variant: "tertiary"
|
|
474
|
+
}
|
|
475
|
+
),
|
|
476
|
+
/* @__PURE__ */ jsxs(Menu.Content, { top: 1, popoverPlacement: "bottom-end", children: [
|
|
477
|
+
/* @__PURE__ */ jsxs(
|
|
478
|
+
Flex,
|
|
479
|
+
{
|
|
480
|
+
alignItems: "center",
|
|
481
|
+
justifyContent: "center",
|
|
482
|
+
direction: "column",
|
|
483
|
+
padding: 1,
|
|
484
|
+
width: "100%",
|
|
485
|
+
children: [
|
|
486
|
+
/* @__PURE__ */ jsx(StyledMenuItem, { disabled: !canUpdate, onSelect: toggleEditReleaseModal, children: /* @__PURE__ */ jsxs(
|
|
487
|
+
Flex,
|
|
488
|
+
{
|
|
489
|
+
paddingTop: 2,
|
|
490
|
+
paddingBottom: 2,
|
|
491
|
+
alignItems: "center",
|
|
492
|
+
gap: 2,
|
|
493
|
+
hasRadius: true,
|
|
494
|
+
width: "100%",
|
|
495
|
+
children: [
|
|
496
|
+
/* @__PURE__ */ jsx(PencilIcon, {}),
|
|
497
|
+
/* @__PURE__ */ jsx(Typography, { ellipsis: true, children: formatMessage({
|
|
498
|
+
id: "content-releases.header.actions.edit",
|
|
499
|
+
defaultMessage: "Edit"
|
|
500
|
+
}) })
|
|
501
|
+
]
|
|
502
|
+
}
|
|
503
|
+
) }),
|
|
504
|
+
/* @__PURE__ */ jsx(StyledMenuItem, { disabled: !canDelete, onSelect: toggleWarningSubmit, children: /* @__PURE__ */ jsxs(
|
|
505
|
+
Flex,
|
|
506
|
+
{
|
|
507
|
+
paddingTop: 2,
|
|
508
|
+
paddingBottom: 2,
|
|
509
|
+
alignItems: "center",
|
|
510
|
+
gap: 2,
|
|
511
|
+
hasRadius: true,
|
|
512
|
+
width: "100%",
|
|
513
|
+
children: [
|
|
514
|
+
/* @__PURE__ */ jsx(TrashIcon, {}),
|
|
515
|
+
/* @__PURE__ */ jsx(Typography, { ellipsis: true, textColor: "danger600", children: formatMessage({
|
|
516
|
+
id: "content-releases.header.actions.delete",
|
|
517
|
+
defaultMessage: "Delete"
|
|
518
|
+
}) })
|
|
519
|
+
]
|
|
520
|
+
}
|
|
521
|
+
) })
|
|
522
|
+
]
|
|
523
|
+
}
|
|
524
|
+
),
|
|
525
|
+
/* @__PURE__ */ jsxs(
|
|
526
|
+
ReleaseInfoWrapper,
|
|
527
|
+
{
|
|
528
|
+
direction: "column",
|
|
529
|
+
justifyContent: "center",
|
|
530
|
+
alignItems: "flex-start",
|
|
531
|
+
gap: 1,
|
|
532
|
+
padding: 5,
|
|
533
|
+
children: [
|
|
534
|
+
/* @__PURE__ */ jsx(Typography, { variant: "pi", fontWeight: "bold", children: formatMessage({
|
|
535
|
+
id: "content-releases.header.actions.created",
|
|
536
|
+
defaultMessage: "Created"
|
|
537
|
+
}) }),
|
|
538
|
+
/* @__PURE__ */ jsxs(Typography, { variant: "pi", color: "neutral300", children: [
|
|
539
|
+
/* @__PURE__ */ jsx(RelativeTime, { timestamp: new Date(release.createdAt) }),
|
|
540
|
+
formatMessage(
|
|
541
|
+
{
|
|
542
|
+
id: "content-releases.header.actions.created.description",
|
|
543
|
+
defaultMessage: "{hasCreatedByUser, select, true { by {createdBy}} other { by deleted user}}"
|
|
544
|
+
},
|
|
545
|
+
{ createdBy: getCreatedByUser(), hasCreatedByUser }
|
|
546
|
+
)
|
|
547
|
+
] })
|
|
548
|
+
]
|
|
549
|
+
}
|
|
550
|
+
)
|
|
551
|
+
] })
|
|
552
|
+
] }),
|
|
346
553
|
/* @__PURE__ */ jsx(Button, { size: "S", variant: "tertiary", onClick: handleRefresh, children: formatMessage({
|
|
347
554
|
id: "content-releases.header.actions.refresh",
|
|
348
555
|
defaultMessage: "Refresh"
|
|
@@ -398,6 +605,9 @@ const ReleaseDetailsBody = () => {
|
|
|
398
605
|
isError: isReleaseError,
|
|
399
606
|
error: releaseError
|
|
400
607
|
} = useGetReleaseQuery({ id: releaseId });
|
|
608
|
+
const {
|
|
609
|
+
allowedActions: { canUpdate }
|
|
610
|
+
} = useRBAC(PERMISSIONS);
|
|
401
611
|
const release = releaseData?.data;
|
|
402
612
|
const selectedGroupBy = query?.groupBy || "contentType";
|
|
403
613
|
const {
|
|
@@ -411,7 +621,7 @@ const ReleaseDetailsBody = () => {
|
|
|
411
621
|
releaseId
|
|
412
622
|
});
|
|
413
623
|
const [updateReleaseAction] = useUpdateReleaseActionMutation();
|
|
414
|
-
const handleChangeType = async (e, actionId) => {
|
|
624
|
+
const handleChangeType = async (e, actionId, actionPath) => {
|
|
415
625
|
const response = await updateReleaseAction({
|
|
416
626
|
params: {
|
|
417
627
|
releaseId,
|
|
@@ -419,7 +629,11 @@ const ReleaseDetailsBody = () => {
|
|
|
419
629
|
},
|
|
420
630
|
body: {
|
|
421
631
|
type: e.target.value
|
|
422
|
-
}
|
|
632
|
+
},
|
|
633
|
+
query,
|
|
634
|
+
// We are passing the query params to make optimistic updates
|
|
635
|
+
actionPath
|
|
636
|
+
// We are passing the action path to found the position in the cache of the action for optimistic updates
|
|
423
637
|
});
|
|
424
638
|
if ("error" in response) {
|
|
425
639
|
if (isAxiosError(response.error)) {
|
|
@@ -500,7 +714,7 @@ const ReleaseDetailsBody = () => {
|
|
|
500
714
|
SingleSelect,
|
|
501
715
|
{
|
|
502
716
|
"aria-label": formatMessage({
|
|
503
|
-
id: "content-releases.pages.ReleaseDetails.groupBy.label",
|
|
717
|
+
id: "content-releases.pages.ReleaseDetails.groupBy.aria-label",
|
|
504
718
|
defaultMessage: "Group by"
|
|
505
719
|
}),
|
|
506
720
|
customizeContent: (value) => formatMessage(
|
|
@@ -518,7 +732,7 @@ const ReleaseDetailsBody = () => {
|
|
|
518
732
|
}
|
|
519
733
|
) }),
|
|
520
734
|
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 }) }),
|
|
735
|
+
/* @__PURE__ */ jsx(Flex, { role: "separator", "aria-label": key, children: /* @__PURE__ */ jsx(Badge, { children: key }) }),
|
|
522
736
|
/* @__PURE__ */ jsx(
|
|
523
737
|
Table.Root,
|
|
524
738
|
{
|
|
@@ -588,56 +802,59 @@ const ReleaseDetailsBody = () => {
|
|
|
588
802
|
)
|
|
589
803
|
] }),
|
|
590
804
|
/* @__PURE__ */ jsx(Table.LoadingBody, {}),
|
|
591
|
-
/* @__PURE__ */ jsx(Table.Body, { children: releaseActions[key].map(
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
{
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
isPublish: type === "publish",
|
|
602
|
-
b: (children) => /* @__PURE__ */ jsx(Typography, { fontWeight: "bold", children })
|
|
603
|
-
}
|
|
604
|
-
) }) : /* @__PURE__ */ jsx(
|
|
605
|
-
ReleaseActionOptions,
|
|
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,
|
|
805
|
+
/* @__PURE__ */ jsx(Table.Body, { children: releaseActions[key].map(
|
|
806
|
+
({ id, contentType, locale, type, entry }, actionIndex) => /* @__PURE__ */ jsxs(Tr, { children: [
|
|
807
|
+
/* @__PURE__ */ jsx(Td, { width: "25%", maxWidth: "200px", children: /* @__PURE__ */ jsx(Typography, { ellipsis: true, children: `${contentType.mainFieldValue || entry.id}` }) }),
|
|
808
|
+
/* @__PURE__ */ jsx(Td, { width: "10%", children: /* @__PURE__ */ jsx(Typography, { children: `${locale?.name ? locale.name : "-"}` }) }),
|
|
809
|
+
/* @__PURE__ */ jsx(Td, { width: "10%", children: /* @__PURE__ */ jsx(Typography, { children: contentType.displayName || "" }) }),
|
|
810
|
+
/* @__PURE__ */ jsx(Td, { width: "20%", children: release.releasedAt ? /* @__PURE__ */ jsx(Typography, { children: formatMessage(
|
|
811
|
+
{
|
|
812
|
+
id: "content-releases.page.ReleaseDetails.table.action-published",
|
|
813
|
+
defaultMessage: "This entry was <b>{isPublish, select, true {published} other {unpublished}}</b>."
|
|
814
|
+
},
|
|
615
815
|
{
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
816
|
+
isPublish: type === "publish",
|
|
817
|
+
b: (children) => /* @__PURE__ */ jsx(Typography, { fontWeight: "bold", children })
|
|
818
|
+
}
|
|
819
|
+
) }) : /* @__PURE__ */ jsx(
|
|
820
|
+
ReleaseActionOptions,
|
|
821
|
+
{
|
|
822
|
+
selected: type,
|
|
823
|
+
handleChange: (e) => handleChangeType(e, id, [key, actionIndex]),
|
|
824
|
+
name: `release-action-${id}-type`,
|
|
825
|
+
disabled: !canUpdate
|
|
620
826
|
}
|
|
621
827
|
) }),
|
|
622
|
-
|
|
623
|
-
/* @__PURE__ */ jsx(
|
|
624
|
-
|
|
625
|
-
{
|
|
626
|
-
contentTypeUid: contentType.uid,
|
|
627
|
-
entryId: entry.id,
|
|
628
|
-
locale: locale?.code
|
|
629
|
-
}
|
|
630
|
-
),
|
|
631
|
-
/* @__PURE__ */ jsx(
|
|
632
|
-
ReleaseActionMenu.DeleteReleaseActionItem,
|
|
828
|
+
!release.releasedAt && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
829
|
+
/* @__PURE__ */ jsx(Td, { width: "20%", minWidth: "200px", children: /* @__PURE__ */ jsx(
|
|
830
|
+
EntryValidationText,
|
|
633
831
|
{
|
|
634
|
-
|
|
635
|
-
|
|
832
|
+
action: type,
|
|
833
|
+
schema: contentTypes?.[contentType.uid],
|
|
834
|
+
components,
|
|
835
|
+
entry
|
|
636
836
|
}
|
|
637
|
-
)
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
837
|
+
) }),
|
|
838
|
+
/* @__PURE__ */ jsx(Td, { children: /* @__PURE__ */ jsx(Flex, { justifyContent: "flex-end", children: /* @__PURE__ */ jsxs(ReleaseActionMenu.Root, { children: [
|
|
839
|
+
/* @__PURE__ */ jsx(
|
|
840
|
+
ReleaseActionMenu.ReleaseActionEntryLinkItem,
|
|
841
|
+
{
|
|
842
|
+
contentTypeUid: contentType.uid,
|
|
843
|
+
entryId: entry.id,
|
|
844
|
+
locale: locale?.code
|
|
845
|
+
}
|
|
846
|
+
),
|
|
847
|
+
/* @__PURE__ */ jsx(
|
|
848
|
+
ReleaseActionMenu.DeleteReleaseActionItem,
|
|
849
|
+
{
|
|
850
|
+
releaseId: release.id,
|
|
851
|
+
actionId: id
|
|
852
|
+
}
|
|
853
|
+
)
|
|
854
|
+
] }) }) })
|
|
855
|
+
] })
|
|
856
|
+
] }, id)
|
|
857
|
+
) })
|
|
641
858
|
] })
|
|
642
859
|
}
|
|
643
860
|
)
|
|
@@ -684,11 +901,18 @@ const ReleaseDetailsPage = () => {
|
|
|
684
901
|
}
|
|
685
902
|
);
|
|
686
903
|
}
|
|
687
|
-
const
|
|
904
|
+
const releaseData = isSuccessDetails && data?.data || null;
|
|
905
|
+
const title = releaseData?.name || "";
|
|
906
|
+
const timezone = releaseData?.timezone ?? null;
|
|
907
|
+
const scheduledAt = releaseData?.scheduledAt && timezone ? utcToZonedTime(releaseData.scheduledAt, timezone) : null;
|
|
908
|
+
const date = scheduledAt ? new Date(format(scheduledAt, "yyyy-MM-dd")) : null;
|
|
909
|
+
const time = scheduledAt ? format(scheduledAt, "HH:mm") : "";
|
|
688
910
|
const handleEditRelease = async (values) => {
|
|
689
911
|
const response = await updateRelease({
|
|
690
912
|
id: releaseId,
|
|
691
|
-
name: values.name
|
|
913
|
+
name: values.name,
|
|
914
|
+
scheduledAt: values.scheduledAt,
|
|
915
|
+
timezone: values.timezone
|
|
692
916
|
});
|
|
693
917
|
if ("data" in response) {
|
|
694
918
|
toggleNotification({
|
|
@@ -742,7 +966,14 @@ const ReleaseDetailsPage = () => {
|
|
|
742
966
|
handleClose: toggleEditReleaseModal,
|
|
743
967
|
handleSubmit: handleEditRelease,
|
|
744
968
|
isLoading: isLoadingDetails || isSubmittingForm,
|
|
745
|
-
initialValues: {
|
|
969
|
+
initialValues: {
|
|
970
|
+
name: title || "",
|
|
971
|
+
scheduledAt,
|
|
972
|
+
date,
|
|
973
|
+
time,
|
|
974
|
+
isScheduled: Boolean(scheduledAt),
|
|
975
|
+
timezone
|
|
976
|
+
}
|
|
746
977
|
}
|
|
747
978
|
),
|
|
748
979
|
/* @__PURE__ */ jsx(
|
|
@@ -762,42 +993,12 @@ const ReleaseDetailsPage = () => {
|
|
|
762
993
|
}
|
|
763
994
|
);
|
|
764
995
|
};
|
|
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
996
|
const LinkCard = styled(Link$2)`
|
|
797
997
|
display: block;
|
|
798
998
|
`;
|
|
799
999
|
const ReleasesGrid = ({ sectionTitle, releases = [], isError = false }) => {
|
|
800
1000
|
const { formatMessage } = useIntl();
|
|
1001
|
+
const IsSchedulingEnabled = window.strapi.future.isEnabled("contentReleasesScheduling");
|
|
801
1002
|
if (isError) {
|
|
802
1003
|
return /* @__PURE__ */ jsx(AnErrorOccurred, {});
|
|
803
1004
|
}
|
|
@@ -818,7 +1019,7 @@ const ReleasesGrid = ({ sectionTitle, releases = [], isError = false }) => {
|
|
|
818
1019
|
}
|
|
819
1020
|
);
|
|
820
1021
|
}
|
|
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(
|
|
1022
|
+
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
1023
|
Flex,
|
|
823
1024
|
{
|
|
824
1025
|
direction: "column",
|
|
@@ -833,7 +1034,10 @@ const ReleasesGrid = ({ sectionTitle, releases = [], isError = false }) => {
|
|
|
833
1034
|
gap: 2,
|
|
834
1035
|
children: [
|
|
835
1036
|
/* @__PURE__ */ jsx(Typography, { as: "h3", variant: "delta", fontWeight: "bold", children: name }),
|
|
836
|
-
/* @__PURE__ */ jsx(Typography, { variant: "pi", children: formatMessage(
|
|
1037
|
+
/* @__PURE__ */ jsx(Typography, { variant: "pi", textColor: "neutral600", children: IsSchedulingEnabled ? scheduledAt ? /* @__PURE__ */ jsx(RelativeTime, { timestamp: new Date(scheduledAt) }) : formatMessage({
|
|
1038
|
+
id: "content-releases.pages.Releases.not-scheduled",
|
|
1039
|
+
defaultMessage: "Not scheduled"
|
|
1040
|
+
}) : formatMessage(
|
|
837
1041
|
{
|
|
838
1042
|
id: "content-releases.page.Releases.release-item.entries",
|
|
839
1043
|
defaultMessage: "{number, plural, =0 {No entries} one {# entry} other {# entries}}"
|
|
@@ -844,8 +1048,22 @@ const ReleasesGrid = ({ sectionTitle, releases = [], isError = false }) => {
|
|
|
844
1048
|
}
|
|
845
1049
|
) }) }, id)) });
|
|
846
1050
|
};
|
|
1051
|
+
const StyledAlert = styled(Alert)`
|
|
1052
|
+
button {
|
|
1053
|
+
display: none;
|
|
1054
|
+
}
|
|
1055
|
+
p + div {
|
|
1056
|
+
margin-left: auto;
|
|
1057
|
+
}
|
|
1058
|
+
`;
|
|
847
1059
|
const INITIAL_FORM_VALUES = {
|
|
848
|
-
name: ""
|
|
1060
|
+
name: "",
|
|
1061
|
+
date: null,
|
|
1062
|
+
time: "",
|
|
1063
|
+
// Remove future flag check after Scheduling Beta release and replace with true as creating new release should include scheduling by default
|
|
1064
|
+
isScheduled: window.strapi.future.isEnabled("contentReleasesScheduling"),
|
|
1065
|
+
scheduledAt: null,
|
|
1066
|
+
timezone: null
|
|
849
1067
|
};
|
|
850
1068
|
const ReleasesPage = () => {
|
|
851
1069
|
const tabRef = React.useRef(null);
|
|
@@ -858,6 +1076,9 @@ const ReleasesPage = () => {
|
|
|
858
1076
|
const [{ query }, setQuery] = useQueryParams();
|
|
859
1077
|
const response = useGetReleasesQuery(query);
|
|
860
1078
|
const [createRelease, { isLoading: isSubmittingForm }] = useCreateReleaseMutation();
|
|
1079
|
+
const { getFeature } = useLicenseLimits();
|
|
1080
|
+
const { maximumReleases = 3 } = getFeature("cms-content-releases");
|
|
1081
|
+
const { trackUsage } = useTracking();
|
|
861
1082
|
const { isLoading, isSuccess, isError } = response;
|
|
862
1083
|
const activeTab = response?.currentData?.meta?.activeTab || "pending";
|
|
863
1084
|
const activeTabIndex = ["pending", "done"].indexOf(activeTab);
|
|
@@ -886,9 +1107,10 @@ const ReleasesPage = () => {
|
|
|
886
1107
|
setReleaseModalShown((prev) => !prev);
|
|
887
1108
|
};
|
|
888
1109
|
if (isLoading) {
|
|
889
|
-
return /* @__PURE__ */ jsx(
|
|
1110
|
+
return /* @__PURE__ */ jsx(Main, { "aria-busy": isLoading, children: /* @__PURE__ */ jsx(LoadingIndicatorPage, {}) });
|
|
890
1111
|
}
|
|
891
1112
|
const totalReleases = isSuccess && response.currentData?.meta?.pagination?.total || 0;
|
|
1113
|
+
const hasReachedMaximumPendingReleases = totalReleases >= maximumReleases;
|
|
892
1114
|
const handleTabChange = (index) => {
|
|
893
1115
|
setQuery({
|
|
894
1116
|
...query,
|
|
@@ -901,9 +1123,11 @@ const ReleasesPage = () => {
|
|
|
901
1123
|
}
|
|
902
1124
|
});
|
|
903
1125
|
};
|
|
904
|
-
const handleAddRelease = async (
|
|
1126
|
+
const handleAddRelease = async ({ name, scheduledAt, timezone }) => {
|
|
905
1127
|
const response2 = await createRelease({
|
|
906
|
-
name
|
|
1128
|
+
name,
|
|
1129
|
+
scheduledAt,
|
|
1130
|
+
timezone
|
|
907
1131
|
});
|
|
908
1132
|
if ("data" in response2) {
|
|
909
1133
|
toggleNotification({
|
|
@@ -913,6 +1137,7 @@ const ReleasesPage = () => {
|
|
|
913
1137
|
defaultMessage: "Release created."
|
|
914
1138
|
})
|
|
915
1139
|
});
|
|
1140
|
+
trackUsage("didCreateRelease");
|
|
916
1141
|
push(`/plugins/content-releases/${response2.data.data.id}`);
|
|
917
1142
|
} else if (isAxiosError(response2.error)) {
|
|
918
1143
|
toggleNotification({
|
|
@@ -926,8 +1151,60 @@ const ReleasesPage = () => {
|
|
|
926
1151
|
});
|
|
927
1152
|
}
|
|
928
1153
|
};
|
|
929
|
-
return /* @__PURE__ */ jsxs(
|
|
1154
|
+
return /* @__PURE__ */ jsxs(Main, { "aria-busy": isLoading, children: [
|
|
1155
|
+
/* @__PURE__ */ jsx(
|
|
1156
|
+
HeaderLayout,
|
|
1157
|
+
{
|
|
1158
|
+
title: formatMessage({
|
|
1159
|
+
id: "content-releases.pages.Releases.title",
|
|
1160
|
+
defaultMessage: "Releases"
|
|
1161
|
+
}),
|
|
1162
|
+
subtitle: formatMessage(
|
|
1163
|
+
{
|
|
1164
|
+
id: "content-releases.pages.Releases.header-subtitle",
|
|
1165
|
+
defaultMessage: "{number, plural, =0 {No releases} one {# release} other {# releases}}"
|
|
1166
|
+
},
|
|
1167
|
+
{ number: totalReleases }
|
|
1168
|
+
),
|
|
1169
|
+
primaryAction: /* @__PURE__ */ jsx(CheckPermissions, { permissions: PERMISSIONS.create, children: /* @__PURE__ */ jsx(
|
|
1170
|
+
Button,
|
|
1171
|
+
{
|
|
1172
|
+
startIcon: /* @__PURE__ */ jsx(Plus, {}),
|
|
1173
|
+
onClick: toggleAddReleaseModal,
|
|
1174
|
+
disabled: hasReachedMaximumPendingReleases,
|
|
1175
|
+
children: formatMessage({
|
|
1176
|
+
id: "content-releases.header.actions.add-release",
|
|
1177
|
+
defaultMessage: "New release"
|
|
1178
|
+
})
|
|
1179
|
+
}
|
|
1180
|
+
) })
|
|
1181
|
+
}
|
|
1182
|
+
),
|
|
930
1183
|
/* @__PURE__ */ jsx(ContentLayout, { children: /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
1184
|
+
activeTab === "pending" && hasReachedMaximumPendingReleases && /* @__PURE__ */ jsx(
|
|
1185
|
+
StyledAlert,
|
|
1186
|
+
{
|
|
1187
|
+
marginBottom: 6,
|
|
1188
|
+
action: /* @__PURE__ */ jsx(Link$2, { href: "https://strapi.io/pricing-cloud", isExternal: true, children: formatMessage({
|
|
1189
|
+
id: "content-releases.pages.Releases.max-limit-reached.action",
|
|
1190
|
+
defaultMessage: "Explore plans"
|
|
1191
|
+
}) }),
|
|
1192
|
+
title: formatMessage(
|
|
1193
|
+
{
|
|
1194
|
+
id: "content-releases.pages.Releases.max-limit-reached.title",
|
|
1195
|
+
defaultMessage: "You have reached the {number} pending {number, plural, one {release} other {releases}} limit."
|
|
1196
|
+
},
|
|
1197
|
+
{ number: maximumReleases }
|
|
1198
|
+
),
|
|
1199
|
+
onClose: () => {
|
|
1200
|
+
},
|
|
1201
|
+
closeLabel: "",
|
|
1202
|
+
children: formatMessage({
|
|
1203
|
+
id: "content-releases.pages.Releases.max-limit-reached.message",
|
|
1204
|
+
defaultMessage: "Upgrade to manage an unlimited number of releases."
|
|
1205
|
+
})
|
|
1206
|
+
}
|
|
1207
|
+
),
|
|
931
1208
|
/* @__PURE__ */ jsxs(
|
|
932
1209
|
TabGroup,
|
|
933
1210
|
{
|
|
@@ -1012,4 +1289,4 @@ const App = () => {
|
|
|
1012
1289
|
export {
|
|
1013
1290
|
App
|
|
1014
1291
|
};
|
|
1015
|
-
//# sourceMappingURL=App-
|
|
1292
|
+
//# sourceMappingURL=App-xAkiD42p.mjs.map
|