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