@strapi/content-releases 0.0.0-experimental.check-license → 0.0.0-experimental.ee4d311a5e6a131fad03cf07e4696f49fdd9c2e6

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.
@@ -0,0 +1,1015 @@
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";
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, g as ReleaseActionMenu, i as isAxiosError, r as releaseApi, h as useGetReleasesQuery, j as useCreateReleaseMutation } from "./index-EIe8S-cw.mjs";
5
+ import * as React from "react";
6
+ import { unstable_useDocument } from "@strapi/admin/strapi-admin";
7
+ import { ModalLayout, ModalHeader, Typography, ModalBody, TextInput, ModalFooter, Button, Flex, ContentLayout, Main, HeaderLayout, Link, IconButton, Popover, SingleSelect, SingleSelectOption, Badge, Tr, Td, Icon, Tooltip, TabGroup, Box, Tabs, Tab, Divider, TabPanels, TabPanel, EmptyStateLayout, Grid, GridItem } from "@strapi/design-system";
8
+ import { LinkButton, Link as Link$2 } from "@strapi/design-system/v2";
9
+ import { Pencil, Trash, ArrowLeft, More, CrossCircle, CheckCircle, Plus, EmptyDocuments } from "@strapi/icons";
10
+ import { useIntl } from "react-intl";
11
+ import styled from "styled-components";
12
+ import { Formik, Form } from "formik";
13
+ import * as yup from "yup";
14
+ import "@reduxjs/toolkit/query";
15
+ import "axios";
16
+ import "@reduxjs/toolkit/query/react";
17
+ import "react-redux";
18
+ const RELEASE_SCHEMA = yup.object().shape({
19
+ name: yup.string().trim().required()
20
+ }).required().noUnknown();
21
+ const ReleaseModal = ({
22
+ handleClose,
23
+ handleSubmit,
24
+ initialValues,
25
+ isLoading = false
26
+ }) => {
27
+ const { formatMessage } = useIntl();
28
+ const { pathname } = useLocation();
29
+ const isCreatingRelease = pathname === `/plugins/${pluginId}`;
30
+ return /* @__PURE__ */ jsxs(ModalLayout, { onClose: handleClose, labelledBy: "title", children: [
31
+ /* @__PURE__ */ jsx(ModalHeader, { children: /* @__PURE__ */ jsx(Typography, { id: "title", fontWeight: "bold", textColor: "neutral800", children: formatMessage(
32
+ {
33
+ id: "content-releases.modal.title",
34
+ defaultMessage: "{isCreatingRelease, select, true {New release} other {Edit release}}"
35
+ },
36
+ { isCreatingRelease }
37
+ ) }) }),
38
+ /* @__PURE__ */ jsx(
39
+ Formik,
40
+ {
41
+ validateOnChange: false,
42
+ onSubmit: handleSubmit,
43
+ initialValues,
44
+ validationSchema: RELEASE_SCHEMA,
45
+ children: ({ values, errors, handleChange }) => /* @__PURE__ */ jsxs(Form, { children: [
46
+ /* @__PURE__ */ jsx(ModalBody, { children: /* @__PURE__ */ jsx(
47
+ TextInput,
48
+ {
49
+ label: formatMessage({
50
+ id: "content-releases.modal.form.input.label.release-name",
51
+ defaultMessage: "Name"
52
+ }),
53
+ name: "name",
54
+ value: values.name,
55
+ error: errors.name,
56
+ onChange: handleChange,
57
+ required: true
58
+ }
59
+ ) }),
60
+ /* @__PURE__ */ jsx(
61
+ ModalFooter,
62
+ {
63
+ startActions: /* @__PURE__ */ jsx(Button, { onClick: handleClose, variant: "tertiary", name: "cancel", children: formatMessage({ id: "cancel", defaultMessage: "Cancel" }) }),
64
+ endActions: /* @__PURE__ */ jsx(
65
+ Button,
66
+ {
67
+ name: "submit",
68
+ loading: isLoading,
69
+ disabled: !values.name || values.name === initialValues.name,
70
+ type: "submit",
71
+ children: formatMessage(
72
+ {
73
+ id: "content-releases.modal.form.button.submit",
74
+ defaultMessage: "{isCreatingRelease, select, true {Continue} other {Save}}"
75
+ },
76
+ { isCreatingRelease }
77
+ )
78
+ }
79
+ )
80
+ }
81
+ )
82
+ ] })
83
+ }
84
+ )
85
+ ] });
86
+ };
87
+ const ReleaseInfoWrapper = styled(Flex)`
88
+ align-self: stretch;
89
+ border-bottom-right-radius: ${({ theme }) => theme.borderRadius};
90
+ border-bottom-left-radius: ${({ theme }) => theme.borderRadius};
91
+ border-top: 1px solid ${({ theme }) => theme.colors.neutral150};
92
+ `;
93
+ const StyledFlex = styled(Flex)`
94
+ align-self: stretch;
95
+ cursor: ${({ disabled }) => disabled ? "not-allowed" : "pointer"};
96
+
97
+ svg path {
98
+ fill: ${({ theme, disabled }) => disabled && theme.colors.neutral500};
99
+ }
100
+ span {
101
+ color: ${({ theme, disabled }) => disabled && theme.colors.neutral500};
102
+ }
103
+ `;
104
+ const PencilIcon = styled(Pencil)`
105
+ width: ${({ theme }) => theme.spaces[4]};
106
+ height: ${({ theme }) => theme.spaces[4]};
107
+ path {
108
+ fill: ${({ theme }) => theme.colors.neutral600};
109
+ }
110
+ `;
111
+ const TrashIcon = styled(Trash)`
112
+ width: ${({ theme }) => theme.spaces[4]};
113
+ height: ${({ theme }) => theme.spaces[4]};
114
+ path {
115
+ fill: ${({ theme }) => theme.colors.danger600};
116
+ }
117
+ `;
118
+ const TypographyMaxWidth = styled(Typography)`
119
+ max-width: 300px;
120
+ `;
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
+ const EntryValidationText = ({ action, schema, components, entry }) => {
140
+ const { formatMessage } = useIntl();
141
+ const { validate } = unstable_useDocument();
142
+ const { errors } = validate(entry, {
143
+ contentType: schema,
144
+ components,
145
+ isCreatingEntry: false
146
+ });
147
+ if (Object.keys(errors).length > 0) {
148
+ const validationErrorsMessages = Object.entries(errors).map(
149
+ ([key, value]) => formatMessage(
150
+ { id: `${value.id}.withField`, defaultMessage: value.defaultMessage },
151
+ { field: key }
152
+ )
153
+ ).join(" ");
154
+ return /* @__PURE__ */ jsxs(Flex, { gap: 2, children: [
155
+ /* @__PURE__ */ jsx(Icon, { color: "danger600", as: CrossCircle }),
156
+ /* @__PURE__ */ jsx(Tooltip, { description: validationErrorsMessages, children: /* @__PURE__ */ jsx(TypographyMaxWidth, { textColor: "danger600", variant: "omega", fontWeight: "semiBold", ellipsis: true, children: validationErrorsMessages }) })
157
+ ] });
158
+ }
159
+ if (action == "publish") {
160
+ return /* @__PURE__ */ jsxs(Flex, { gap: 2, children: [
161
+ /* @__PURE__ */ jsx(Icon, { color: "success600", as: CheckCircle }),
162
+ entry.publishedAt ? /* @__PURE__ */ jsx(Typography, { textColor: "success600", fontWeight: "bold", children: formatMessage({
163
+ id: "content-releases.pages.ReleaseDetails.entry-validation.already-published",
164
+ defaultMessage: "Already published"
165
+ }) }) : /* @__PURE__ */ jsx(Typography, { children: formatMessage({
166
+ id: "content-releases.pages.ReleaseDetails.entry-validation.ready-to-publish",
167
+ defaultMessage: "Ready to publish"
168
+ }) })
169
+ ] });
170
+ }
171
+ return /* @__PURE__ */ jsxs(Flex, { gap: 2, children: [
172
+ /* @__PURE__ */ jsx(Icon, { color: "success600", as: CheckCircle }),
173
+ !entry.publishedAt ? /* @__PURE__ */ jsx(Typography, { textColor: "success600", fontWeight: "bold", children: formatMessage({
174
+ id: "content-releases.pages.ReleaseDetails.entry-validation.already-unpublished",
175
+ defaultMessage: "Already unpublished"
176
+ }) }) : /* @__PURE__ */ jsx(Typography, { children: formatMessage({
177
+ id: "content-releases.pages.ReleaseDetails.entry-validation.ready-to-unpublish",
178
+ defaultMessage: "Ready to unpublish"
179
+ }) })
180
+ ] });
181
+ };
182
+ const ReleaseDetailsLayout = ({
183
+ toggleEditReleaseModal,
184
+ toggleWarningSubmit,
185
+ children
186
+ }) => {
187
+ const { formatMessage } = useIntl();
188
+ const { releaseId } = useParams();
189
+ const [isPopoverVisible, setIsPopoverVisible] = React.useState(false);
190
+ const moreButtonRef = React.useRef(null);
191
+ const {
192
+ data,
193
+ isLoading: isLoadingDetails,
194
+ isError,
195
+ error
196
+ } = useGetReleaseQuery({ id: releaseId });
197
+ const [publishRelease, { isLoading: isPublishing }] = usePublishReleaseMutation();
198
+ const toggleNotification = useNotification();
199
+ const { formatAPIError } = useAPIErrorHandler();
200
+ const {
201
+ allowedActions: { canUpdate, canDelete }
202
+ } = useRBAC(PERMISSIONS);
203
+ const dispatch = useTypedDispatch();
204
+ const release = data?.data;
205
+ const handleTogglePopover = () => {
206
+ setIsPopoverVisible((prev) => !prev);
207
+ };
208
+ const openReleaseModal = () => {
209
+ toggleEditReleaseModal();
210
+ handleTogglePopover();
211
+ };
212
+ const handlePublishRelease = async () => {
213
+ const response = await publishRelease({ id: releaseId });
214
+ if ("data" in response) {
215
+ toggleNotification({
216
+ type: "success",
217
+ message: formatMessage({
218
+ id: "content-releases.pages.ReleaseDetails.publish-notification-success",
219
+ defaultMessage: "Release was published successfully."
220
+ })
221
+ });
222
+ } else if (isAxiosError(response.error)) {
223
+ toggleNotification({
224
+ type: "warning",
225
+ message: formatAPIError(response.error)
226
+ });
227
+ } else {
228
+ toggleNotification({
229
+ type: "warning",
230
+ message: formatMessage({ id: "notification.error", defaultMessage: "An error occurred" })
231
+ });
232
+ }
233
+ };
234
+ const openWarningConfirmDialog = () => {
235
+ toggleWarningSubmit();
236
+ handleTogglePopover();
237
+ };
238
+ const handleRefresh = () => {
239
+ dispatch(releaseApi.util.invalidateTags([{ type: "ReleaseAction", id: "LIST" }]));
240
+ };
241
+ if (isLoadingDetails) {
242
+ return /* @__PURE__ */ jsx(Main, { "aria-busy": isLoadingDetails, children: /* @__PURE__ */ jsx(LoadingIndicatorPage, {}) });
243
+ }
244
+ if (isError || !release) {
245
+ return /* @__PURE__ */ jsx(
246
+ Redirect,
247
+ {
248
+ to: {
249
+ pathname: "/plugins/content-releases",
250
+ state: {
251
+ errors: [
252
+ {
253
+ code: error?.code
254
+ }
255
+ ]
256
+ }
257
+ }
258
+ }
259
+ );
260
+ }
261
+ const totalEntries = release.actions.meta.count || 0;
262
+ const createdBy = release.createdBy.lastname ? `${release.createdBy.firstname} ${release.createdBy.lastname}` : `${release.createdBy.firstname}`;
263
+ return /* @__PURE__ */ jsxs(Main, { "aria-busy": isLoadingDetails, children: [
264
+ /* @__PURE__ */ jsx(
265
+ HeaderLayout,
266
+ {
267
+ title: release.name,
268
+ subtitle: formatMessage(
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
+ ),
275
+ navigationAction: /* @__PURE__ */ jsx(Link, { startIcon: /* @__PURE__ */ jsx(ArrowLeft, {}), to: "/plugins/content-releases", children: formatMessage({
276
+ id: "global.back",
277
+ defaultMessage: "Back"
278
+ }) }),
279
+ primaryAction: !release.releasedAt && /* @__PURE__ */ jsxs(Flex, { gap: 2, children: [
280
+ /* @__PURE__ */ jsx(
281
+ IconButton,
282
+ {
283
+ label: formatMessage({
284
+ id: "content-releases.header.actions.open-release-actions",
285
+ defaultMessage: "Release actions"
286
+ }),
287
+ ref: moreButtonRef,
288
+ onClick: handleTogglePopover,
289
+ children: /* @__PURE__ */ jsx(More, {})
290
+ }
291
+ ),
292
+ isPopoverVisible && /* @__PURE__ */ jsxs(
293
+ Popover,
294
+ {
295
+ source: moreButtonRef,
296
+ placement: "bottom-end",
297
+ onDismiss: handleTogglePopover,
298
+ spacing: 4,
299
+ minWidth: "242px",
300
+ children: [
301
+ /* @__PURE__ */ jsxs(Flex, { alignItems: "center", justifyContent: "center", direction: "column", padding: 1, children: [
302
+ /* @__PURE__ */ jsxs(PopoverButton, { disabled: !canUpdate, onClick: openReleaseModal, children: [
303
+ /* @__PURE__ */ jsx(PencilIcon, {}),
304
+ /* @__PURE__ */ jsx(Typography, { ellipsis: true, children: formatMessage({
305
+ id: "content-releases.header.actions.edit",
306
+ defaultMessage: "Edit"
307
+ }) })
308
+ ] }),
309
+ /* @__PURE__ */ jsxs(PopoverButton, { disabled: !canDelete, onClick: openWarningConfirmDialog, children: [
310
+ /* @__PURE__ */ jsx(TrashIcon, {}),
311
+ /* @__PURE__ */ jsx(Typography, { ellipsis: true, textColor: "danger600", children: formatMessage({
312
+ id: "content-releases.header.actions.delete",
313
+ defaultMessage: "Delete"
314
+ }) })
315
+ ] })
316
+ ] }),
317
+ /* @__PURE__ */ jsxs(
318
+ ReleaseInfoWrapper,
319
+ {
320
+ direction: "column",
321
+ justifyContent: "center",
322
+ alignItems: "flex-start",
323
+ gap: 1,
324
+ padding: 5,
325
+ children: [
326
+ /* @__PURE__ */ jsx(Typography, { variant: "pi", fontWeight: "bold", children: formatMessage({
327
+ id: "content-releases.header.actions.created",
328
+ defaultMessage: "Created"
329
+ }) }),
330
+ /* @__PURE__ */ jsxs(Typography, { variant: "pi", color: "neutral300", children: [
331
+ /* @__PURE__ */ jsx(RelativeTime, { timestamp: new Date(release.createdAt) }),
332
+ formatMessage(
333
+ {
334
+ id: "content-releases.header.actions.created.description",
335
+ defaultMessage: " by {createdBy}"
336
+ },
337
+ { createdBy }
338
+ )
339
+ ] })
340
+ ]
341
+ }
342
+ )
343
+ ]
344
+ }
345
+ ),
346
+ /* @__PURE__ */ jsx(Button, { size: "S", variant: "tertiary", onClick: handleRefresh, children: formatMessage({
347
+ id: "content-releases.header.actions.refresh",
348
+ defaultMessage: "Refresh"
349
+ }) }),
350
+ /* @__PURE__ */ jsx(CheckPermissions, { permissions: PERMISSIONS.publish, children: /* @__PURE__ */ jsx(
351
+ Button,
352
+ {
353
+ size: "S",
354
+ variant: "default",
355
+ onClick: handlePublishRelease,
356
+ loading: isPublishing,
357
+ disabled: release.actions.meta.count === 0,
358
+ children: formatMessage({
359
+ id: "content-releases.header.actions.publish",
360
+ defaultMessage: "Publish"
361
+ })
362
+ }
363
+ ) })
364
+ ] })
365
+ }
366
+ ),
367
+ children
368
+ ] });
369
+ };
370
+ const GROUP_BY_OPTIONS = ["contentType", "locale", "action"];
371
+ const getGroupByOptionLabel = (value) => {
372
+ if (value === "locale") {
373
+ return {
374
+ id: "content-releases.pages.ReleaseDetails.groupBy.option.locales",
375
+ defaultMessage: "Locales"
376
+ };
377
+ }
378
+ if (value === "action") {
379
+ return {
380
+ id: "content-releases.pages.ReleaseDetails.groupBy.option.actions",
381
+ defaultMessage: "Actions"
382
+ };
383
+ }
384
+ return {
385
+ id: "content-releases.pages.ReleaseDetails.groupBy.option.content-type",
386
+ defaultMessage: "Content-Types"
387
+ };
388
+ };
389
+ const ReleaseDetailsBody = () => {
390
+ const { formatMessage } = useIntl();
391
+ const { releaseId } = useParams();
392
+ const [{ query }, setQuery] = useQueryParams();
393
+ const toggleNotification = useNotification();
394
+ const { formatAPIError } = useAPIErrorHandler();
395
+ const {
396
+ data: releaseData,
397
+ isLoading: isReleaseLoading,
398
+ isError: isReleaseError,
399
+ error: releaseError
400
+ } = useGetReleaseQuery({ id: releaseId });
401
+ const release = releaseData?.data;
402
+ const selectedGroupBy = query?.groupBy || "contentType";
403
+ const {
404
+ isLoading,
405
+ isFetching,
406
+ isError,
407
+ data,
408
+ error: releaseActionsError
409
+ } = useGetReleaseActionsQuery({
410
+ ...query,
411
+ releaseId
412
+ });
413
+ const [updateReleaseAction] = useUpdateReleaseActionMutation();
414
+ const handleChangeType = async (e, actionId) => {
415
+ const response = await updateReleaseAction({
416
+ params: {
417
+ releaseId,
418
+ actionId
419
+ },
420
+ body: {
421
+ type: e.target.value
422
+ }
423
+ });
424
+ if ("error" in response) {
425
+ if (isAxiosError(response.error)) {
426
+ toggleNotification({
427
+ type: "warning",
428
+ message: formatAPIError(response.error)
429
+ });
430
+ } else {
431
+ toggleNotification({
432
+ type: "warning",
433
+ message: formatMessage({ id: "notification.error", defaultMessage: "An error occurred" })
434
+ });
435
+ }
436
+ }
437
+ };
438
+ if (isLoading || isReleaseLoading) {
439
+ return /* @__PURE__ */ jsx(ContentLayout, { children: /* @__PURE__ */ jsx(LoadingIndicatorPage, {}) });
440
+ }
441
+ const releaseActions = data?.data;
442
+ const releaseMeta = data?.meta;
443
+ const contentTypes = releaseMeta?.contentTypes || {};
444
+ const components = releaseMeta?.components || {};
445
+ if (isReleaseError || !release) {
446
+ const errorsArray = [];
447
+ if (releaseError) {
448
+ errorsArray.push({
449
+ code: releaseError.code
450
+ });
451
+ }
452
+ if (releaseActionsError) {
453
+ errorsArray.push({
454
+ code: releaseActionsError.code
455
+ });
456
+ }
457
+ return /* @__PURE__ */ jsx(
458
+ Redirect,
459
+ {
460
+ to: {
461
+ pathname: "/plugins/content-releases",
462
+ state: {
463
+ errors: errorsArray
464
+ }
465
+ }
466
+ }
467
+ );
468
+ }
469
+ if (isError || !releaseActions) {
470
+ return /* @__PURE__ */ jsx(ContentLayout, { children: /* @__PURE__ */ jsx(AnErrorOccurred, {}) });
471
+ }
472
+ if (Object.keys(releaseActions).length === 0) {
473
+ return /* @__PURE__ */ jsx(ContentLayout, { children: /* @__PURE__ */ jsx(
474
+ NoContent,
475
+ {
476
+ content: {
477
+ id: "content-releases.pages.Details.tab.emptyEntries",
478
+ defaultMessage: "This release is empty. Open the Content Manager, select an entry and add it to the release."
479
+ },
480
+ action: /* @__PURE__ */ jsx(
481
+ LinkButton,
482
+ {
483
+ as: Link$1,
484
+ to: {
485
+ pathname: "/content-manager"
486
+ },
487
+ style: { textDecoration: "none" },
488
+ variant: "secondary",
489
+ children: formatMessage({
490
+ id: "content-releases.page.Details.button.openContentManager",
491
+ defaultMessage: "Open the Content Manager"
492
+ })
493
+ }
494
+ )
495
+ }
496
+ ) });
497
+ }
498
+ return /* @__PURE__ */ jsx(ContentLayout, { children: /* @__PURE__ */ jsxs(Flex, { gap: 8, direction: "column", alignItems: "stretch", children: [
499
+ /* @__PURE__ */ jsx(Flex, { children: /* @__PURE__ */ jsx(
500
+ SingleSelect,
501
+ {
502
+ "aria-label": formatMessage({
503
+ id: "content-releases.pages.ReleaseDetails.groupBy.label",
504
+ defaultMessage: "Group by"
505
+ }),
506
+ customizeContent: (value) => formatMessage(
507
+ {
508
+ id: `content-releases.pages.ReleaseDetails.groupBy.label`,
509
+ defaultMessage: `Group by {groupBy}`
510
+ },
511
+ {
512
+ groupBy: value
513
+ }
514
+ ),
515
+ value: formatMessage(getGroupByOptionLabel(selectedGroupBy)),
516
+ onChange: (value) => setQuery({ groupBy: value }),
517
+ children: GROUP_BY_OPTIONS.map((option) => /* @__PURE__ */ jsx(SingleSelectOption, { value: option, children: formatMessage(getGroupByOptionLabel(option)) }, option))
518
+ }
519
+ ) }),
520
+ 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 }) }),
522
+ /* @__PURE__ */ jsx(
523
+ Table.Root,
524
+ {
525
+ rows: releaseActions[key].map((item) => ({
526
+ ...item,
527
+ id: Number(item.entry.id)
528
+ })),
529
+ colCount: releaseActions[key].length,
530
+ isLoading,
531
+ isFetching,
532
+ children: /* @__PURE__ */ jsxs(Table.Content, { children: [
533
+ /* @__PURE__ */ jsxs(Table.Head, { children: [
534
+ /* @__PURE__ */ jsx(
535
+ Table.HeaderCell,
536
+ {
537
+ fieldSchemaType: "string",
538
+ label: formatMessage({
539
+ id: "content-releases.page.ReleaseDetails.table.header.label.name",
540
+ defaultMessage: "name"
541
+ }),
542
+ name: "name"
543
+ }
544
+ ),
545
+ /* @__PURE__ */ jsx(
546
+ Table.HeaderCell,
547
+ {
548
+ fieldSchemaType: "string",
549
+ label: formatMessage({
550
+ id: "content-releases.page.ReleaseDetails.table.header.label.locale",
551
+ defaultMessage: "locale"
552
+ }),
553
+ name: "locale"
554
+ }
555
+ ),
556
+ /* @__PURE__ */ jsx(
557
+ Table.HeaderCell,
558
+ {
559
+ fieldSchemaType: "string",
560
+ label: formatMessage({
561
+ id: "content-releases.page.ReleaseDetails.table.header.label.content-type",
562
+ defaultMessage: "content-type"
563
+ }),
564
+ name: "content-type"
565
+ }
566
+ ),
567
+ /* @__PURE__ */ jsx(
568
+ Table.HeaderCell,
569
+ {
570
+ fieldSchemaType: "string",
571
+ label: formatMessage({
572
+ id: "content-releases.page.ReleaseDetails.table.header.label.action",
573
+ defaultMessage: "action"
574
+ }),
575
+ name: "action"
576
+ }
577
+ ),
578
+ !release.releasedAt && /* @__PURE__ */ jsx(
579
+ Table.HeaderCell,
580
+ {
581
+ fieldSchemaType: "string",
582
+ label: formatMessage({
583
+ id: "content-releases.page.ReleaseDetails.table.header.label.status",
584
+ defaultMessage: "status"
585
+ }),
586
+ name: "status"
587
+ }
588
+ )
589
+ ] }),
590
+ /* @__PURE__ */ jsx(Table.LoadingBody, {}),
591
+ /* @__PURE__ */ jsx(Table.Body, { children: releaseActions[key].map(({ id, contentType, locale, type, entry }) => /* @__PURE__ */ jsxs(Tr, { children: [
592
+ /* @__PURE__ */ jsx(Td, { width: "25%", maxWidth: "200px", children: /* @__PURE__ */ jsx(Typography, { ellipsis: true, children: `${contentType.mainFieldValue || entry.id}` }) }),
593
+ /* @__PURE__ */ jsx(Td, { width: "10%", children: /* @__PURE__ */ jsx(Typography, { children: `${locale?.name ? locale.name : "-"}` }) }),
594
+ /* @__PURE__ */ jsx(Td, { width: "10%", children: /* @__PURE__ */ jsx(Typography, { children: contentType.displayName || "" }) }),
595
+ /* @__PURE__ */ jsx(Td, { width: "20%", children: release.releasedAt ? /* @__PURE__ */ jsx(Typography, { children: formatMessage(
596
+ {
597
+ id: "content-releases.page.ReleaseDetails.table.action-published",
598
+ defaultMessage: "This entry was <b>{isPublish, select, true {published} other {unpublished}}</b>."
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,
615
+ {
616
+ action: type,
617
+ schema: contentTypes?.[contentType.uid],
618
+ components,
619
+ entry
620
+ }
621
+ ) }),
622
+ /* @__PURE__ */ jsx(Td, { children: /* @__PURE__ */ jsx(Flex, { justifyContent: "flex-end", children: /* @__PURE__ */ jsxs(ReleaseActionMenu.Root, { children: [
623
+ /* @__PURE__ */ jsx(
624
+ ReleaseActionMenu.ReleaseActionEntryLinkItem,
625
+ {
626
+ contentTypeUid: contentType.uid,
627
+ entryId: entry.id,
628
+ locale: locale?.code
629
+ }
630
+ ),
631
+ /* @__PURE__ */ jsx(
632
+ ReleaseActionMenu.DeleteReleaseActionItem,
633
+ {
634
+ releaseId: release.id,
635
+ actionId: id
636
+ }
637
+ )
638
+ ] }) }) })
639
+ ] })
640
+ ] }, id)) })
641
+ ] })
642
+ }
643
+ )
644
+ ] }, `releases-group-${key}`)),
645
+ /* @__PURE__ */ jsxs(Flex, { paddingTop: 4, alignItems: "flex-end", justifyContent: "space-between", children: [
646
+ /* @__PURE__ */ jsx(PageSizeURLQuery, { defaultValue: releaseMeta?.pagination?.pageSize.toString() }),
647
+ /* @__PURE__ */ jsx(
648
+ PaginationURLQuery,
649
+ {
650
+ pagination: {
651
+ pageCount: releaseMeta?.pagination?.pageCount || 0
652
+ }
653
+ }
654
+ )
655
+ ] })
656
+ ] }) });
657
+ };
658
+ const ReleaseDetailsPage = () => {
659
+ const { formatMessage } = useIntl();
660
+ const { releaseId } = useParams();
661
+ const toggleNotification = useNotification();
662
+ const { formatAPIError } = useAPIErrorHandler();
663
+ const { push } = useHistory();
664
+ const [releaseModalShown, setReleaseModalShown] = React.useState(false);
665
+ const [showWarningSubmit, setWarningSubmit] = React.useState(false);
666
+ const {
667
+ isLoading: isLoadingDetails,
668
+ data,
669
+ isSuccess: isSuccessDetails
670
+ } = useGetReleaseQuery({ id: releaseId });
671
+ const [updateRelease, { isLoading: isSubmittingForm }] = useUpdateReleaseMutation();
672
+ const [deleteRelease, { isLoading: isDeletingRelease }] = useDeleteReleaseMutation();
673
+ const toggleEditReleaseModal = () => {
674
+ setReleaseModalShown((prev) => !prev);
675
+ };
676
+ const toggleWarningSubmit = () => setWarningSubmit((prevState) => !prevState);
677
+ if (isLoadingDetails) {
678
+ return /* @__PURE__ */ jsx(
679
+ ReleaseDetailsLayout,
680
+ {
681
+ toggleEditReleaseModal,
682
+ toggleWarningSubmit,
683
+ children: /* @__PURE__ */ jsx(ContentLayout, { children: /* @__PURE__ */ jsx(LoadingIndicatorPage, {}) })
684
+ }
685
+ );
686
+ }
687
+ const title = isSuccessDetails && data?.data?.name || "";
688
+ const handleEditRelease = async (values) => {
689
+ const response = await updateRelease({
690
+ id: releaseId,
691
+ name: values.name
692
+ });
693
+ if ("data" in response) {
694
+ toggleNotification({
695
+ type: "success",
696
+ message: formatMessage({
697
+ id: "content-releases.modal.release-updated-notification-success",
698
+ defaultMessage: "Release updated."
699
+ })
700
+ });
701
+ } else if (isAxiosError(response.error)) {
702
+ toggleNotification({
703
+ type: "warning",
704
+ message: formatAPIError(response.error)
705
+ });
706
+ } else {
707
+ toggleNotification({
708
+ type: "warning",
709
+ message: formatMessage({ id: "notification.error", defaultMessage: "An error occurred" })
710
+ });
711
+ }
712
+ toggleEditReleaseModal();
713
+ };
714
+ const handleDeleteRelease = async () => {
715
+ const response = await deleteRelease({
716
+ id: releaseId
717
+ });
718
+ if ("data" in response) {
719
+ push("/plugins/content-releases");
720
+ } else if (isAxiosError(response.error)) {
721
+ toggleNotification({
722
+ type: "warning",
723
+ message: formatAPIError(response.error)
724
+ });
725
+ } else {
726
+ toggleNotification({
727
+ type: "warning",
728
+ message: formatMessage({ id: "notification.error", defaultMessage: "An error occurred" })
729
+ });
730
+ }
731
+ };
732
+ return /* @__PURE__ */ jsxs(
733
+ ReleaseDetailsLayout,
734
+ {
735
+ toggleEditReleaseModal,
736
+ toggleWarningSubmit,
737
+ children: [
738
+ /* @__PURE__ */ jsx(ReleaseDetailsBody, {}),
739
+ releaseModalShown && /* @__PURE__ */ jsx(
740
+ ReleaseModal,
741
+ {
742
+ handleClose: toggleEditReleaseModal,
743
+ handleSubmit: handleEditRelease,
744
+ isLoading: isLoadingDetails || isSubmittingForm,
745
+ initialValues: { name: title || "" }
746
+ }
747
+ ),
748
+ /* @__PURE__ */ jsx(
749
+ ConfirmDialog,
750
+ {
751
+ bodyText: {
752
+ id: "content-releases.dialog.confirmation-message",
753
+ defaultMessage: "Are you sure you want to delete this release?"
754
+ },
755
+ isOpen: showWarningSubmit,
756
+ isConfirmButtonLoading: isDeletingRelease,
757
+ onToggleDialog: toggleWarningSubmit,
758
+ onConfirm: handleDeleteRelease
759
+ }
760
+ )
761
+ ]
762
+ }
763
+ );
764
+ };
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
+ const LinkCard = styled(Link$2)`
797
+ display: block;
798
+ `;
799
+ const ReleasesGrid = ({ sectionTitle, releases = [], isError = false }) => {
800
+ const { formatMessage } = useIntl();
801
+ if (isError) {
802
+ return /* @__PURE__ */ jsx(AnErrorOccurred, {});
803
+ }
804
+ if (releases?.length === 0) {
805
+ return /* @__PURE__ */ jsx(
806
+ EmptyStateLayout,
807
+ {
808
+ content: formatMessage(
809
+ {
810
+ id: "content-releases.page.Releases.tab.emptyEntries",
811
+ defaultMessage: "No releases"
812
+ },
813
+ {
814
+ target: sectionTitle
815
+ }
816
+ ),
817
+ icon: /* @__PURE__ */ jsx(EmptyDocuments, { width: "10rem" })
818
+ }
819
+ );
820
+ }
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(
822
+ Flex,
823
+ {
824
+ direction: "column",
825
+ justifyContent: "space-between",
826
+ padding: 4,
827
+ hasRadius: true,
828
+ background: "neutral0",
829
+ shadow: "tableShadow",
830
+ height: "100%",
831
+ width: "100%",
832
+ alignItems: "start",
833
+ gap: 2,
834
+ children: [
835
+ /* @__PURE__ */ jsx(Typography, { as: "h3", variant: "delta", fontWeight: "bold", children: name }),
836
+ /* @__PURE__ */ jsx(Typography, { variant: "pi", children: formatMessage(
837
+ {
838
+ id: "content-releases.page.Releases.release-item.entries",
839
+ defaultMessage: "{number, plural, =0 {No entries} one {# entry} other {# entries}}"
840
+ },
841
+ { number: actions.meta.count }
842
+ ) })
843
+ ]
844
+ }
845
+ ) }) }, id)) });
846
+ };
847
+ const INITIAL_FORM_VALUES = {
848
+ name: ""
849
+ };
850
+ const ReleasesPage = () => {
851
+ const tabRef = React.useRef(null);
852
+ const location = useLocation();
853
+ const [releaseModalShown, setReleaseModalShown] = React.useState(false);
854
+ const toggleNotification = useNotification();
855
+ const { formatMessage } = useIntl();
856
+ const { push, replace } = useHistory();
857
+ const { formatAPIError } = useAPIErrorHandler();
858
+ const [{ query }, setQuery] = useQueryParams();
859
+ const response = useGetReleasesQuery(query);
860
+ const [createRelease, { isLoading: isSubmittingForm }] = useCreateReleaseMutation();
861
+ const { isLoading, isSuccess, isError } = response;
862
+ const activeTab = response?.currentData?.meta?.activeTab || "pending";
863
+ const activeTabIndex = ["pending", "done"].indexOf(activeTab);
864
+ React.useEffect(() => {
865
+ if (location?.state?.errors) {
866
+ toggleNotification({
867
+ type: "warning",
868
+ title: formatMessage({
869
+ id: "content-releases.pages.Releases.notification.error.title",
870
+ defaultMessage: "Your request could not be processed."
871
+ }),
872
+ message: formatMessage({
873
+ id: "content-releases.pages.Releases.notification.error.message",
874
+ defaultMessage: "Please try again or open another release."
875
+ })
876
+ });
877
+ replace({ state: null });
878
+ }
879
+ }, [formatMessage, location?.state?.errors, replace, toggleNotification]);
880
+ React.useEffect(() => {
881
+ if (tabRef.current) {
882
+ tabRef.current._handlers.setSelectedTabIndex(activeTabIndex);
883
+ }
884
+ }, [activeTabIndex]);
885
+ const toggleAddReleaseModal = () => {
886
+ setReleaseModalShown((prev) => !prev);
887
+ };
888
+ if (isLoading) {
889
+ return /* @__PURE__ */ jsx(ReleasesLayout, { onClickAddRelease: toggleAddReleaseModal, isLoading: true, children: /* @__PURE__ */ jsx(ContentLayout, { children: /* @__PURE__ */ jsx(LoadingIndicatorPage, {}) }) });
890
+ }
891
+ const totalReleases = isSuccess && response.currentData?.meta?.pagination?.total || 0;
892
+ const handleTabChange = (index) => {
893
+ setQuery({
894
+ ...query,
895
+ page: 1,
896
+ pageSize: response?.currentData?.meta?.pagination?.pageSize || 16,
897
+ filters: {
898
+ releasedAt: {
899
+ $notNull: index === 0 ? false : true
900
+ }
901
+ }
902
+ });
903
+ };
904
+ const handleAddRelease = async (values) => {
905
+ const response2 = await createRelease({
906
+ name: values.name
907
+ });
908
+ if ("data" in response2) {
909
+ toggleNotification({
910
+ type: "success",
911
+ message: formatMessage({
912
+ id: "content-releases.modal.release-created-notification-success",
913
+ defaultMessage: "Release created."
914
+ })
915
+ });
916
+ push(`/plugins/content-releases/${response2.data.data.id}`);
917
+ } else if (isAxiosError(response2.error)) {
918
+ toggleNotification({
919
+ type: "warning",
920
+ message: formatAPIError(response2.error)
921
+ });
922
+ } else {
923
+ toggleNotification({
924
+ type: "warning",
925
+ message: formatMessage({ id: "notification.error", defaultMessage: "An error occurred" })
926
+ });
927
+ }
928
+ };
929
+ return /* @__PURE__ */ jsxs(ReleasesLayout, { onClickAddRelease: toggleAddReleaseModal, totalReleases, children: [
930
+ /* @__PURE__ */ jsx(ContentLayout, { children: /* @__PURE__ */ jsxs(Fragment, { children: [
931
+ /* @__PURE__ */ jsxs(
932
+ TabGroup,
933
+ {
934
+ label: formatMessage({
935
+ id: "content-releases.pages.Releases.tab-group.label",
936
+ defaultMessage: "Releases list"
937
+ }),
938
+ variant: "simple",
939
+ initialSelectedTabIndex: activeTabIndex,
940
+ onTabChange: handleTabChange,
941
+ ref: tabRef,
942
+ children: [
943
+ /* @__PURE__ */ jsxs(Box, { paddingBottom: 8, children: [
944
+ /* @__PURE__ */ jsxs(Tabs, { children: [
945
+ /* @__PURE__ */ jsx(Tab, { children: formatMessage({
946
+ id: "content-releases.pages.Releases.tab.pending",
947
+ defaultMessage: "Pending"
948
+ }) }),
949
+ /* @__PURE__ */ jsx(Tab, { children: formatMessage({
950
+ id: "content-releases.pages.Releases.tab.done",
951
+ defaultMessage: "Done"
952
+ }) })
953
+ ] }),
954
+ /* @__PURE__ */ jsx(Divider, {})
955
+ ] }),
956
+ /* @__PURE__ */ jsxs(TabPanels, { children: [
957
+ /* @__PURE__ */ jsx(TabPanel, { children: /* @__PURE__ */ jsx(
958
+ ReleasesGrid,
959
+ {
960
+ sectionTitle: "pending",
961
+ releases: response?.currentData?.data,
962
+ isError
963
+ }
964
+ ) }),
965
+ /* @__PURE__ */ jsx(TabPanel, { children: /* @__PURE__ */ jsx(
966
+ ReleasesGrid,
967
+ {
968
+ sectionTitle: "done",
969
+ releases: response?.currentData?.data,
970
+ isError
971
+ }
972
+ ) })
973
+ ] })
974
+ ]
975
+ }
976
+ ),
977
+ totalReleases > 0 && /* @__PURE__ */ jsxs(Flex, { paddingTop: 4, alignItems: "flex-end", justifyContent: "space-between", children: [
978
+ /* @__PURE__ */ jsx(
979
+ PageSizeURLQuery,
980
+ {
981
+ options: ["8", "16", "32", "64"],
982
+ defaultValue: response?.currentData?.meta?.pagination?.pageSize.toString()
983
+ }
984
+ ),
985
+ /* @__PURE__ */ jsx(
986
+ PaginationURLQuery,
987
+ {
988
+ pagination: {
989
+ pageCount: response?.currentData?.meta?.pagination?.pageCount || 0
990
+ }
991
+ }
992
+ )
993
+ ] })
994
+ ] }) }),
995
+ releaseModalShown && /* @__PURE__ */ jsx(
996
+ ReleaseModal,
997
+ {
998
+ handleClose: toggleAddReleaseModal,
999
+ handleSubmit: handleAddRelease,
1000
+ isLoading: isSubmittingForm,
1001
+ initialValues: INITIAL_FORM_VALUES
1002
+ }
1003
+ )
1004
+ ] });
1005
+ };
1006
+ const App = () => {
1007
+ return /* @__PURE__ */ jsx(CheckPagePermissions, { permissions: PERMISSIONS.main, children: /* @__PURE__ */ jsxs(Switch, { children: [
1008
+ /* @__PURE__ */ jsx(Route, { exact: true, path: `/plugins/${pluginId}`, component: ReleasesPage }),
1009
+ /* @__PURE__ */ jsx(Route, { exact: true, path: `/plugins/${pluginId}/:releaseId`, component: ReleaseDetailsPage })
1010
+ ] }) });
1011
+ };
1012
+ export {
1013
+ App
1014
+ };
1015
+ //# sourceMappingURL=App-BWaM2ihP.mjs.map