@strapi/content-releases 4.20.3 → 4.20.4

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.
@@ -3,7 +3,7 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
3
3
  const jsxRuntime = require("react/jsx-runtime");
4
4
  const helperPlugin = require("@strapi/helper-plugin");
5
5
  const reactRouterDom = require("react-router-dom");
6
- const index = require("./index-SDpSekBU.js");
6
+ const index = require("./index-2xzbhaQP.js");
7
7
  const React = require("react");
8
8
  const strapiAdmin = require("@strapi/admin/strapi-admin");
9
9
  const designSystem = require("@strapi/design-system");
@@ -273,6 +273,9 @@ const TimezoneComponent = ({ timezoneOptions }) => {
273
273
  onChange: (timezone) => {
274
274
  setFieldValue("timezone", timezone);
275
275
  },
276
+ onTextValueChange: (timezone) => {
277
+ setFieldValue("timezone", timezone);
278
+ },
276
279
  onClear: () => {
277
280
  setFieldValue("timezone", "");
278
281
  },
@@ -282,122 +285,187 @@ const TimezoneComponent = ({ timezoneOptions }) => {
282
285
  }
283
286
  );
284
287
  };
285
- const ReleaseInfoWrapper = styled__default.default(designSystem.Flex)`
286
- align-self: stretch;
287
- border-bottom-right-radius: ${({ theme }) => theme.borderRadius};
288
- border-bottom-left-radius: ${({ theme }) => theme.borderRadius};
289
- border-top: 1px solid ${({ theme }) => theme.colors.neutral150};
290
- `;
291
- const StyledMenuItem = styled__default.default(v2.Menu.Item)`
292
- svg path {
293
- fill: ${({ theme, disabled }) => disabled && theme.colors.neutral500};
294
- }
295
- span {
296
- color: ${({ theme, disabled }) => disabled && theme.colors.neutral500};
297
- }
288
+ const LinkCard = styled__default.default(v2.Link)`
289
+ display: block;
298
290
  `;
299
- const PencilIcon = styled__default.default(icons.Pencil)`
300
- width: ${({ theme }) => theme.spaces[3]};
301
- height: ${({ theme }) => theme.spaces[3]};
302
- path {
303
- fill: ${({ theme }) => theme.colors.neutral600};
304
- }
291
+ const CapitalizeRelativeTime = styled__default.default(helperPlugin.RelativeTime)`
292
+ text-transform: capitalize;
305
293
  `;
306
- const TrashIcon = styled__default.default(icons.Trash)`
307
- width: ${({ theme }) => theme.spaces[3]};
308
- height: ${({ theme }) => theme.spaces[3]};
309
- path {
310
- fill: ${({ theme }) => theme.colors.danger600};
294
+ const getBadgeProps = (status) => {
295
+ let color;
296
+ switch (status) {
297
+ case "ready":
298
+ color = "success";
299
+ break;
300
+ case "blocked":
301
+ color = "warning";
302
+ break;
303
+ case "failed":
304
+ color = "danger";
305
+ break;
306
+ case "done":
307
+ color = "primary";
308
+ break;
309
+ case "empty":
310
+ default:
311
+ color = "neutral";
311
312
  }
312
- `;
313
- const TypographyMaxWidth = styled__default.default(designSystem.Typography)`
314
- max-width: 300px;
315
- `;
316
- const EntryValidationText = ({ action, schema, components, entry }) => {
313
+ return {
314
+ textColor: `${color}600`,
315
+ backgroundColor: `${color}100`,
316
+ borderColor: `${color}200`
317
+ };
318
+ };
319
+ const ReleasesGrid = ({ sectionTitle, releases = [], isError = false }) => {
317
320
  const { formatMessage } = reactIntl.useIntl();
318
- const { validate } = strapiAdmin.unstable_useDocument();
319
- const { errors } = validate(entry, {
320
- contentType: schema,
321
- components,
322
- isCreatingEntry: false
323
- });
324
- if (Object.keys(errors).length > 0) {
325
- const validationErrorsMessages = Object.entries(errors).map(
326
- ([key, value]) => formatMessage(
327
- { id: `${value.id}.withField`, defaultMessage: value.defaultMessage },
328
- { field: key }
329
- )
330
- ).join(" ");
331
- return /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { gap: 2, children: [
332
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Icon, { color: "danger600", as: icons.CrossCircle }),
333
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Tooltip, { description: validationErrorsMessages, children: /* @__PURE__ */ jsxRuntime.jsx(TypographyMaxWidth, { textColor: "danger600", variant: "omega", fontWeight: "semiBold", ellipsis: true, children: validationErrorsMessages }) })
334
- ] });
321
+ const IsSchedulingEnabled = window.strapi.future.isEnabled("contentReleasesScheduling");
322
+ if (isError) {
323
+ return /* @__PURE__ */ jsxRuntime.jsx(helperPlugin.AnErrorOccurred, {});
335
324
  }
336
- if (action == "publish") {
337
- return /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { gap: 2, children: [
338
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Icon, { color: "success600", as: icons.CheckCircle }),
339
- entry.publishedAt ? /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { textColor: "success600", fontWeight: "bold", children: formatMessage({
340
- id: "content-releases.pages.ReleaseDetails.entry-validation.already-published",
341
- defaultMessage: "Already published"
342
- }) }) : /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { children: formatMessage({
343
- id: "content-releases.pages.ReleaseDetails.entry-validation.ready-to-publish",
344
- defaultMessage: "Ready to publish"
345
- }) })
346
- ] });
325
+ if (releases?.length === 0) {
326
+ return /* @__PURE__ */ jsxRuntime.jsx(
327
+ designSystem.EmptyStateLayout,
328
+ {
329
+ content: formatMessage(
330
+ {
331
+ id: "content-releases.page.Releases.tab.emptyEntries",
332
+ defaultMessage: "No releases"
333
+ },
334
+ {
335
+ target: sectionTitle
336
+ }
337
+ ),
338
+ icon: /* @__PURE__ */ jsxRuntime.jsx(icons.EmptyDocuments, { width: "10rem" })
339
+ }
340
+ );
347
341
  }
348
- return /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { gap: 2, children: [
349
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Icon, { color: "success600", as: icons.CheckCircle }),
350
- !entry.publishedAt ? /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { textColor: "success600", fontWeight: "bold", children: formatMessage({
351
- id: "content-releases.pages.ReleaseDetails.entry-validation.already-unpublished",
352
- defaultMessage: "Already unpublished"
353
- }) }) : /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { children: formatMessage({
354
- id: "content-releases.pages.ReleaseDetails.entry-validation.ready-to-unpublish",
355
- defaultMessage: "Ready to unpublish"
356
- }) })
357
- ] });
342
+ return /* @__PURE__ */ jsxRuntime.jsx(designSystem.Grid, { gap: 4, children: releases.map(({ id, name, actions, scheduledAt, status }) => /* @__PURE__ */ jsxRuntime.jsx(designSystem.GridItem, { col: 3, s: 6, xs: 12, children: /* @__PURE__ */ jsxRuntime.jsx(LinkCard, { href: `content-releases/${id}`, isExternal: false, children: /* @__PURE__ */ jsxRuntime.jsxs(
343
+ designSystem.Flex,
344
+ {
345
+ direction: "column",
346
+ justifyContent: "space-between",
347
+ padding: 4,
348
+ hasRadius: true,
349
+ background: "neutral0",
350
+ shadow: "tableShadow",
351
+ height: "100%",
352
+ width: "100%",
353
+ alignItems: "start",
354
+ gap: 4,
355
+ children: [
356
+ /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { direction: "column", alignItems: "start", gap: 1, children: [
357
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { as: "h3", variant: "delta", fontWeight: "bold", children: name }),
358
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "pi", textColor: "neutral600", children: IsSchedulingEnabled ? scheduledAt ? /* @__PURE__ */ jsxRuntime.jsx(CapitalizeRelativeTime, { timestamp: new Date(scheduledAt) }) : formatMessage({
359
+ id: "content-releases.pages.Releases.not-scheduled",
360
+ defaultMessage: "Not scheduled"
361
+ }) : formatMessage(
362
+ {
363
+ id: "content-releases.page.Releases.release-item.entries",
364
+ defaultMessage: "{number, plural, =0 {No entries} one {# entry} other {# entries}}"
365
+ },
366
+ { number: actions.meta.count }
367
+ ) })
368
+ ] }),
369
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Badge, { ...getBadgeProps(status), children: status })
370
+ ]
371
+ }
372
+ ) }) }, id)) });
358
373
  };
359
- const ReleaseDetailsLayout = ({
360
- toggleEditReleaseModal,
361
- toggleWarningSubmit,
362
- children
363
- }) => {
364
- const { formatMessage, formatDate, formatTime } = reactIntl.useIntl();
365
- const { releaseId } = reactRouterDom.useParams();
366
- const {
367
- data,
368
- isLoading: isLoadingDetails,
369
- isError,
370
- error
371
- } = index.useGetReleaseQuery({ id: releaseId });
372
- const [publishRelease, { isLoading: isPublishing }] = index.usePublishReleaseMutation();
374
+ const StyledAlert = styled__default.default(designSystem.Alert)`
375
+ button {
376
+ display: none;
377
+ }
378
+ p + div {
379
+ margin-left: auto;
380
+ }
381
+ `;
382
+ const INITIAL_FORM_VALUES = {
383
+ name: "",
384
+ date: null,
385
+ time: "",
386
+ // Remove future flag check after Scheduling Beta release and replace with true as creating new release should include scheduling by default
387
+ isScheduled: window.strapi.future.isEnabled("contentReleasesScheduling"),
388
+ scheduledAt: null,
389
+ timezone: null
390
+ };
391
+ const ReleasesPage = () => {
392
+ const tabRef = React__namespace.useRef(null);
393
+ const location = reactRouterDom.useLocation();
394
+ const [releaseModalShown, setReleaseModalShown] = React__namespace.useState(false);
373
395
  const toggleNotification = helperPlugin.useNotification();
396
+ const { formatMessage } = reactIntl.useIntl();
397
+ const { push, replace } = reactRouterDom.useHistory();
374
398
  const { formatAPIError } = helperPlugin.useAPIErrorHandler();
375
- const {
376
- allowedActions: { canUpdate, canDelete }
377
- } = helperPlugin.useRBAC(index.PERMISSIONS);
378
- const dispatch = index.useTypedDispatch();
399
+ const [{ query }, setQuery] = helperPlugin.useQueryParams();
400
+ const response = index.useGetReleasesQuery(query);
401
+ const [createRelease, { isLoading: isSubmittingForm }] = index.useCreateReleaseMutation();
402
+ const { getFeature } = strapiAdmin.useLicenseLimits();
403
+ const { maximumReleases = 3 } = getFeature("cms-content-releases");
379
404
  const { trackUsage } = helperPlugin.useTracking();
380
- const release = data?.data;
381
- const handlePublishRelease = async () => {
382
- const response = await publishRelease({ id: releaseId });
383
- if ("data" in response) {
405
+ const { isLoading, isSuccess, isError } = response;
406
+ const activeTab = response?.currentData?.meta?.activeTab || "pending";
407
+ const activeTabIndex = ["pending", "done"].indexOf(activeTab);
408
+ React__namespace.useEffect(() => {
409
+ if (location?.state?.errors) {
384
410
  toggleNotification({
385
- type: "success",
411
+ type: "warning",
412
+ title: formatMessage({
413
+ id: "content-releases.pages.Releases.notification.error.title",
414
+ defaultMessage: "Your request could not be processed."
415
+ }),
386
416
  message: formatMessage({
387
- id: "content-releases.pages.ReleaseDetails.publish-notification-success",
388
- defaultMessage: "Release was published successfully."
417
+ id: "content-releases.pages.Releases.notification.error.message",
418
+ defaultMessage: "Please try again or open another release."
389
419
  })
390
420
  });
391
- const { totalEntries: totalEntries2, totalPublishedEntries, totalUnpublishedEntries } = response.data.meta;
392
- trackUsage("didPublishRelease", {
393
- totalEntries: totalEntries2,
394
- totalPublishedEntries,
395
- totalUnpublishedEntries
421
+ replace({ state: null });
422
+ }
423
+ }, [formatMessage, location?.state?.errors, replace, toggleNotification]);
424
+ React__namespace.useEffect(() => {
425
+ if (tabRef.current) {
426
+ tabRef.current._handlers.setSelectedTabIndex(activeTabIndex);
427
+ }
428
+ }, [activeTabIndex]);
429
+ const toggleAddReleaseModal = () => {
430
+ setReleaseModalShown((prev) => !prev);
431
+ };
432
+ if (isLoading) {
433
+ return /* @__PURE__ */ jsxRuntime.jsx(designSystem.Main, { "aria-busy": isLoading, children: /* @__PURE__ */ jsxRuntime.jsx(helperPlugin.LoadingIndicatorPage, {}) });
434
+ }
435
+ const totalPendingReleases = isSuccess && response.currentData?.meta?.pendingReleasesCount || 0;
436
+ const hasReachedMaximumPendingReleases = totalPendingReleases >= maximumReleases;
437
+ const handleTabChange = (index2) => {
438
+ setQuery({
439
+ ...query,
440
+ page: 1,
441
+ pageSize: response?.currentData?.meta?.pagination?.pageSize || 16,
442
+ filters: {
443
+ releasedAt: {
444
+ $notNull: index2 === 0 ? false : true
445
+ }
446
+ }
447
+ });
448
+ };
449
+ const handleAddRelease = async ({ name, scheduledAt, timezone }) => {
450
+ const response2 = await createRelease({
451
+ name,
452
+ scheduledAt,
453
+ timezone
454
+ });
455
+ if ("data" in response2) {
456
+ toggleNotification({
457
+ type: "success",
458
+ message: formatMessage({
459
+ id: "content-releases.modal.release-created-notification-success",
460
+ defaultMessage: "Release created."
461
+ })
396
462
  });
397
- } else if (index.isAxiosError(response.error)) {
463
+ trackUsage("didCreateRelease");
464
+ push(`/plugins/content-releases/${response2.data.data.id}`);
465
+ } else if (index.isAxiosError(response2.error)) {
398
466
  toggleNotification({
399
467
  type: "warning",
400
- message: formatAPIError(response.error)
468
+ message: formatAPIError(response2.error)
401
469
  });
402
470
  } else {
403
471
  toggleNotification({
@@ -406,33 +474,292 @@ const ReleaseDetailsLayout = ({
406
474
  });
407
475
  }
408
476
  };
409
- const handleRefresh = () => {
410
- dispatch(index.releaseApi.util.invalidateTags([{ type: "ReleaseAction", id: "LIST" }]));
411
- };
412
- const getCreatedByUser = () => {
413
- if (!release?.createdBy) {
414
- return null;
415
- }
416
- if (release.createdBy.username) {
417
- return release.createdBy.username;
418
- }
419
- if (release.createdBy.firstname) {
420
- return `${release.createdBy.firstname} ${release.createdBy.lastname || ""}`.trim();
421
- }
422
- return release.createdBy.email;
423
- };
424
- if (isLoadingDetails) {
425
- return /* @__PURE__ */ jsxRuntime.jsx(designSystem.Main, { "aria-busy": isLoadingDetails, children: /* @__PURE__ */ jsxRuntime.jsx(helperPlugin.LoadingIndicatorPage, {}) });
426
- }
427
- if (isError || !release) {
428
- return /* @__PURE__ */ jsxRuntime.jsx(
429
- reactRouterDom.Redirect,
477
+ return /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Main, { "aria-busy": isLoading, children: [
478
+ /* @__PURE__ */ jsxRuntime.jsx(
479
+ designSystem.HeaderLayout,
430
480
  {
431
- to: {
432
- pathname: "/plugins/content-releases",
433
- state: {
434
- errors: [
435
- {
481
+ title: formatMessage({
482
+ id: "content-releases.pages.Releases.title",
483
+ defaultMessage: "Releases"
484
+ }),
485
+ subtitle: formatMessage({
486
+ id: "content-releases.pages.Releases.header-subtitle",
487
+ defaultMessage: "Create and manage content updates"
488
+ }),
489
+ primaryAction: /* @__PURE__ */ jsxRuntime.jsx(helperPlugin.CheckPermissions, { permissions: index.PERMISSIONS.create, children: /* @__PURE__ */ jsxRuntime.jsx(
490
+ designSystem.Button,
491
+ {
492
+ startIcon: /* @__PURE__ */ jsxRuntime.jsx(icons.Plus, {}),
493
+ onClick: toggleAddReleaseModal,
494
+ disabled: hasReachedMaximumPendingReleases,
495
+ children: formatMessage({
496
+ id: "content-releases.header.actions.add-release",
497
+ defaultMessage: "New release"
498
+ })
499
+ }
500
+ ) })
501
+ }
502
+ ),
503
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.ContentLayout, { children: /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
504
+ hasReachedMaximumPendingReleases && /* @__PURE__ */ jsxRuntime.jsx(
505
+ StyledAlert,
506
+ {
507
+ marginBottom: 6,
508
+ action: /* @__PURE__ */ jsxRuntime.jsx(v2.Link, { href: "https://strapi.io/pricing-cloud", isExternal: true, children: formatMessage({
509
+ id: "content-releases.pages.Releases.max-limit-reached.action",
510
+ defaultMessage: "Explore plans"
511
+ }) }),
512
+ title: formatMessage(
513
+ {
514
+ id: "content-releases.pages.Releases.max-limit-reached.title",
515
+ defaultMessage: "You have reached the {number} pending {number, plural, one {release} other {releases}} limit."
516
+ },
517
+ { number: maximumReleases }
518
+ ),
519
+ onClose: () => {
520
+ },
521
+ closeLabel: "",
522
+ children: formatMessage({
523
+ id: "content-releases.pages.Releases.max-limit-reached.message",
524
+ defaultMessage: "Upgrade to manage an unlimited number of releases."
525
+ })
526
+ }
527
+ ),
528
+ /* @__PURE__ */ jsxRuntime.jsxs(
529
+ designSystem.TabGroup,
530
+ {
531
+ label: formatMessage({
532
+ id: "content-releases.pages.Releases.tab-group.label",
533
+ defaultMessage: "Releases list"
534
+ }),
535
+ variant: "simple",
536
+ initialSelectedTabIndex: activeTabIndex,
537
+ onTabChange: handleTabChange,
538
+ ref: tabRef,
539
+ children: [
540
+ /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Box, { paddingBottom: 8, children: [
541
+ /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Tabs, { children: [
542
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Tab, { children: formatMessage(
543
+ {
544
+ id: "content-releases.pages.Releases.tab.pending",
545
+ defaultMessage: "Pending ({count})"
546
+ },
547
+ {
548
+ count: totalPendingReleases
549
+ }
550
+ ) }),
551
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Tab, { children: formatMessage({
552
+ id: "content-releases.pages.Releases.tab.done",
553
+ defaultMessage: "Done"
554
+ }) })
555
+ ] }),
556
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Divider, {})
557
+ ] }),
558
+ /* @__PURE__ */ jsxRuntime.jsxs(designSystem.TabPanels, { children: [
559
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.TabPanel, { children: /* @__PURE__ */ jsxRuntime.jsx(
560
+ ReleasesGrid,
561
+ {
562
+ sectionTitle: "pending",
563
+ releases: response?.currentData?.data,
564
+ isError
565
+ }
566
+ ) }),
567
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.TabPanel, { children: /* @__PURE__ */ jsxRuntime.jsx(
568
+ ReleasesGrid,
569
+ {
570
+ sectionTitle: "done",
571
+ releases: response?.currentData?.data,
572
+ isError
573
+ }
574
+ ) })
575
+ ] })
576
+ ]
577
+ }
578
+ ),
579
+ response.currentData?.meta?.pagination?.total ? /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { paddingTop: 4, alignItems: "flex-end", justifyContent: "space-between", children: [
580
+ /* @__PURE__ */ jsxRuntime.jsx(
581
+ helperPlugin.PageSizeURLQuery,
582
+ {
583
+ options: ["8", "16", "32", "64"],
584
+ defaultValue: response?.currentData?.meta?.pagination?.pageSize.toString()
585
+ }
586
+ ),
587
+ /* @__PURE__ */ jsxRuntime.jsx(
588
+ helperPlugin.PaginationURLQuery,
589
+ {
590
+ pagination: {
591
+ pageCount: response?.currentData?.meta?.pagination?.pageCount || 0
592
+ }
593
+ }
594
+ )
595
+ ] }) : null
596
+ ] }) }),
597
+ releaseModalShown && /* @__PURE__ */ jsxRuntime.jsx(
598
+ ReleaseModal,
599
+ {
600
+ handleClose: toggleAddReleaseModal,
601
+ handleSubmit: handleAddRelease,
602
+ isLoading: isSubmittingForm,
603
+ initialValues: INITIAL_FORM_VALUES
604
+ }
605
+ )
606
+ ] });
607
+ };
608
+ const ReleaseInfoWrapper = styled__default.default(designSystem.Flex)`
609
+ align-self: stretch;
610
+ border-bottom-right-radius: ${({ theme }) => theme.borderRadius};
611
+ border-bottom-left-radius: ${({ theme }) => theme.borderRadius};
612
+ border-top: 1px solid ${({ theme }) => theme.colors.neutral150};
613
+ `;
614
+ const StyledMenuItem = styled__default.default(v2.Menu.Item)`
615
+ svg path {
616
+ fill: ${({ theme, disabled }) => disabled && theme.colors.neutral500};
617
+ }
618
+ span {
619
+ color: ${({ theme, disabled }) => disabled && theme.colors.neutral500};
620
+ }
621
+
622
+ &:hover {
623
+ background: ${({ theme, variant = "neutral" }) => theme.colors[`${variant}100`]};
624
+ }
625
+ `;
626
+ const PencilIcon = styled__default.default(icons.Pencil)`
627
+ width: ${({ theme }) => theme.spaces[3]};
628
+ height: ${({ theme }) => theme.spaces[3]};
629
+ path {
630
+ fill: ${({ theme }) => theme.colors.neutral600};
631
+ }
632
+ `;
633
+ const TrashIcon = styled__default.default(icons.Trash)`
634
+ width: ${({ theme }) => theme.spaces[3]};
635
+ height: ${({ theme }) => theme.spaces[3]};
636
+ path {
637
+ fill: ${({ theme }) => theme.colors.danger600};
638
+ }
639
+ `;
640
+ const TypographyMaxWidth = styled__default.default(designSystem.Typography)`
641
+ max-width: 300px;
642
+ `;
643
+ const EntryValidationText = ({ action, schema, components, entry }) => {
644
+ const { formatMessage } = reactIntl.useIntl();
645
+ const { validate } = strapiAdmin.unstable_useDocument();
646
+ const { errors } = validate(entry, {
647
+ contentType: schema,
648
+ components,
649
+ isCreatingEntry: false
650
+ });
651
+ if (Object.keys(errors).length > 0) {
652
+ const validationErrorsMessages = Object.entries(errors).map(
653
+ ([key, value]) => formatMessage(
654
+ { id: `${value.id}.withField`, defaultMessage: value.defaultMessage },
655
+ { field: key }
656
+ )
657
+ ).join(" ");
658
+ return /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { gap: 2, children: [
659
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Icon, { color: "danger600", as: icons.CrossCircle }),
660
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Tooltip, { description: validationErrorsMessages, children: /* @__PURE__ */ jsxRuntime.jsx(TypographyMaxWidth, { textColor: "danger600", variant: "omega", fontWeight: "semiBold", ellipsis: true, children: validationErrorsMessages }) })
661
+ ] });
662
+ }
663
+ if (action == "publish") {
664
+ return /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { gap: 2, children: [
665
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Icon, { color: "success600", as: icons.CheckCircle }),
666
+ entry.publishedAt ? /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { textColor: "success600", fontWeight: "bold", children: formatMessage({
667
+ id: "content-releases.pages.ReleaseDetails.entry-validation.already-published",
668
+ defaultMessage: "Already published"
669
+ }) }) : /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { children: formatMessage({
670
+ id: "content-releases.pages.ReleaseDetails.entry-validation.ready-to-publish",
671
+ defaultMessage: "Ready to publish"
672
+ }) })
673
+ ] });
674
+ }
675
+ return /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { gap: 2, children: [
676
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Icon, { color: "success600", as: icons.CheckCircle }),
677
+ !entry.publishedAt ? /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { textColor: "success600", fontWeight: "bold", children: formatMessage({
678
+ id: "content-releases.pages.ReleaseDetails.entry-validation.already-unpublished",
679
+ defaultMessage: "Already unpublished"
680
+ }) }) : /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { children: formatMessage({
681
+ id: "content-releases.pages.ReleaseDetails.entry-validation.ready-to-unpublish",
682
+ defaultMessage: "Ready to unpublish"
683
+ }) })
684
+ ] });
685
+ };
686
+ const ReleaseDetailsLayout = ({
687
+ toggleEditReleaseModal,
688
+ toggleWarningSubmit,
689
+ children
690
+ }) => {
691
+ const { formatMessage, formatDate, formatTime } = reactIntl.useIntl();
692
+ const { releaseId } = reactRouterDom.useParams();
693
+ const {
694
+ data,
695
+ isLoading: isLoadingDetails,
696
+ isError,
697
+ error
698
+ } = index.useGetReleaseQuery({ id: releaseId });
699
+ const [publishRelease, { isLoading: isPublishing }] = index.usePublishReleaseMutation();
700
+ const toggleNotification = helperPlugin.useNotification();
701
+ const { formatAPIError } = helperPlugin.useAPIErrorHandler();
702
+ const {
703
+ allowedActions: { canUpdate, canDelete }
704
+ } = helperPlugin.useRBAC(index.PERMISSIONS);
705
+ const dispatch = index.useTypedDispatch();
706
+ const { trackUsage } = helperPlugin.useTracking();
707
+ const release = data?.data;
708
+ const handlePublishRelease = async () => {
709
+ const response = await publishRelease({ id: releaseId });
710
+ if ("data" in response) {
711
+ toggleNotification({
712
+ type: "success",
713
+ message: formatMessage({
714
+ id: "content-releases.pages.ReleaseDetails.publish-notification-success",
715
+ defaultMessage: "Release was published successfully."
716
+ })
717
+ });
718
+ const { totalEntries: totalEntries2, totalPublishedEntries, totalUnpublishedEntries } = response.data.meta;
719
+ trackUsage("didPublishRelease", {
720
+ totalEntries: totalEntries2,
721
+ totalPublishedEntries,
722
+ totalUnpublishedEntries
723
+ });
724
+ } else if (index.isAxiosError(response.error)) {
725
+ toggleNotification({
726
+ type: "warning",
727
+ message: formatAPIError(response.error)
728
+ });
729
+ } else {
730
+ toggleNotification({
731
+ type: "warning",
732
+ message: formatMessage({ id: "notification.error", defaultMessage: "An error occurred" })
733
+ });
734
+ }
735
+ };
736
+ const handleRefresh = () => {
737
+ dispatch(index.releaseApi.util.invalidateTags([{ type: "ReleaseAction", id: "LIST" }]));
738
+ };
739
+ const getCreatedByUser = () => {
740
+ if (!release?.createdBy) {
741
+ return null;
742
+ }
743
+ if (release.createdBy.username) {
744
+ return release.createdBy.username;
745
+ }
746
+ if (release.createdBy.firstname) {
747
+ return `${release.createdBy.firstname} ${release.createdBy.lastname || ""}`.trim();
748
+ }
749
+ return release.createdBy.email;
750
+ };
751
+ if (isLoadingDetails) {
752
+ return /* @__PURE__ */ jsxRuntime.jsx(designSystem.Main, { "aria-busy": isLoadingDetails, children: /* @__PURE__ */ jsxRuntime.jsx(helperPlugin.LoadingIndicatorPage, {}) });
753
+ }
754
+ if (isError || !release) {
755
+ return /* @__PURE__ */ jsxRuntime.jsx(
756
+ reactRouterDom.Redirect,
757
+ {
758
+ to: {
759
+ pathname: "/plugins/content-releases",
760
+ state: {
761
+ errors: [
762
+ {
436
763
  code: error?.code
437
764
  }
438
765
  ]
@@ -477,7 +804,10 @@ const ReleaseDetailsLayout = ({
477
804
  designSystem.HeaderLayout,
478
805
  {
479
806
  title: release.name,
480
- subtitle: numberOfEntriesText + (IsSchedulingEnabled && isScheduled ? ` - ${scheduledText}` : ""),
807
+ subtitle: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { gap: 2, lineHeight: 6, children: [
808
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { textColor: "neutral600", variant: "epsilon", children: numberOfEntriesText + (IsSchedulingEnabled && isScheduled ? ` - ${scheduledText}` : "") }),
809
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Badge, { ...getBadgeProps(release.status), children: release.status })
810
+ ] }),
481
811
  navigationAction: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Link, { startIcon: /* @__PURE__ */ jsxRuntime.jsx(icons.ArrowLeft, {}), to: "/plugins/content-releases", children: formatMessage({
482
812
  id: "global.back",
483
813
  defaultMessage: "Back"
@@ -508,42 +838,28 @@ const ReleaseDetailsLayout = ({
508
838
  padding: 1,
509
839
  width: "100%",
510
840
  children: [
511
- /* @__PURE__ */ jsxRuntime.jsx(StyledMenuItem, { disabled: !canUpdate, onSelect: toggleEditReleaseModal, children: /* @__PURE__ */ jsxRuntime.jsxs(
512
- designSystem.Flex,
513
- {
514
- paddingTop: 2,
515
- paddingBottom: 2,
516
- alignItems: "center",
517
- gap: 2,
518
- hasRadius: true,
519
- width: "100%",
520
- children: [
521
- /* @__PURE__ */ jsxRuntime.jsx(PencilIcon, {}),
522
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { ellipsis: true, children: formatMessage({
523
- id: "content-releases.header.actions.edit",
524
- defaultMessage: "Edit"
525
- }) })
526
- ]
527
- }
528
- ) }),
529
- /* @__PURE__ */ jsxRuntime.jsx(StyledMenuItem, { disabled: !canDelete, onSelect: toggleWarningSubmit, children: /* @__PURE__ */ jsxRuntime.jsxs(
530
- designSystem.Flex,
841
+ /* @__PURE__ */ jsxRuntime.jsx(StyledMenuItem, { disabled: !canUpdate, onSelect: toggleEditReleaseModal, children: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { alignItems: "center", gap: 2, hasRadius: true, width: "100%", children: [
842
+ /* @__PURE__ */ jsxRuntime.jsx(PencilIcon, {}),
843
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { ellipsis: true, children: formatMessage({
844
+ id: "content-releases.header.actions.edit",
845
+ defaultMessage: "Edit"
846
+ }) })
847
+ ] }) }),
848
+ /* @__PURE__ */ jsxRuntime.jsx(
849
+ StyledMenuItem,
531
850
  {
532
- paddingTop: 2,
533
- paddingBottom: 2,
534
- alignItems: "center",
535
- gap: 2,
536
- hasRadius: true,
537
- width: "100%",
538
- children: [
851
+ disabled: !canDelete,
852
+ onSelect: toggleWarningSubmit,
853
+ variant: "danger",
854
+ children: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { alignItems: "center", gap: 2, hasRadius: true, width: "100%", children: [
539
855
  /* @__PURE__ */ jsxRuntime.jsx(TrashIcon, {}),
540
856
  /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { ellipsis: true, textColor: "danger600", children: formatMessage({
541
857
  id: "content-releases.header.actions.delete",
542
858
  defaultMessage: "Delete"
543
859
  }) })
544
- ]
860
+ ] })
545
861
  }
546
- ) })
862
+ )
547
863
  ]
548
864
  }
549
865
  ),
@@ -872,302 +1188,85 @@ const ReleaseDetailsBody = () => {
872
1188
  /* @__PURE__ */ jsxRuntime.jsx(
873
1189
  index.ReleaseActionMenu.DeleteReleaseActionItem,
874
1190
  {
875
- releaseId: release.id,
876
- actionId: id
877
- }
878
- )
879
- ] }) }) })
880
- ] })
881
- ] }, id)
882
- ) })
883
- ] })
884
- }
885
- )
886
- ] }, `releases-group-${key}`)),
887
- /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { paddingTop: 4, alignItems: "flex-end", justifyContent: "space-between", children: [
888
- /* @__PURE__ */ jsxRuntime.jsx(helperPlugin.PageSizeURLQuery, { defaultValue: releaseMeta?.pagination?.pageSize.toString() }),
889
- /* @__PURE__ */ jsxRuntime.jsx(
890
- helperPlugin.PaginationURLQuery,
891
- {
892
- pagination: {
893
- pageCount: releaseMeta?.pagination?.pageCount || 0
894
- }
895
- }
896
- )
897
- ] })
898
- ] }) });
899
- };
900
- const ReleaseDetailsPage = () => {
901
- const { formatMessage } = reactIntl.useIntl();
902
- const { releaseId } = reactRouterDom.useParams();
903
- const toggleNotification = helperPlugin.useNotification();
904
- const { formatAPIError } = helperPlugin.useAPIErrorHandler();
905
- const { push } = reactRouterDom.useHistory();
906
- const [releaseModalShown, setReleaseModalShown] = React__namespace.useState(false);
907
- const [showWarningSubmit, setWarningSubmit] = React__namespace.useState(false);
908
- const {
909
- isLoading: isLoadingDetails,
910
- data,
911
- isSuccess: isSuccessDetails
912
- } = index.useGetReleaseQuery({ id: releaseId });
913
- const [updateRelease, { isLoading: isSubmittingForm }] = index.useUpdateReleaseMutation();
914
- const [deleteRelease, { isLoading: isDeletingRelease }] = index.useDeleteReleaseMutation();
915
- const toggleEditReleaseModal = () => {
916
- setReleaseModalShown((prev) => !prev);
917
- };
918
- const toggleWarningSubmit = () => setWarningSubmit((prevState) => !prevState);
919
- if (isLoadingDetails) {
920
- return /* @__PURE__ */ jsxRuntime.jsx(
921
- ReleaseDetailsLayout,
922
- {
923
- toggleEditReleaseModal,
924
- toggleWarningSubmit,
925
- children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.ContentLayout, { children: /* @__PURE__ */ jsxRuntime.jsx(helperPlugin.LoadingIndicatorPage, {}) })
926
- }
927
- );
928
- }
929
- const releaseData = isSuccessDetails && data?.data || null;
930
- const title = releaseData?.name || "";
931
- const timezone = releaseData?.timezone ?? null;
932
- const scheduledAt = releaseData?.scheduledAt && timezone ? dateFnsTz.utcToZonedTime(releaseData.scheduledAt, timezone) : null;
933
- const date = scheduledAt ? new Date(format__default.default(scheduledAt, "yyyy-MM-dd")) : null;
934
- const time = scheduledAt ? format__default.default(scheduledAt, "HH:mm") : "";
935
- const handleEditRelease = async (values) => {
936
- const response = await updateRelease({
937
- id: releaseId,
938
- name: values.name,
939
- scheduledAt: values.scheduledAt,
940
- timezone: values.timezone
941
- });
942
- if ("data" in response) {
943
- toggleNotification({
944
- type: "success",
945
- message: formatMessage({
946
- id: "content-releases.modal.release-updated-notification-success",
947
- defaultMessage: "Release updated."
948
- })
949
- });
950
- } else if (index.isAxiosError(response.error)) {
951
- toggleNotification({
952
- type: "warning",
953
- message: formatAPIError(response.error)
954
- });
955
- } else {
956
- toggleNotification({
957
- type: "warning",
958
- message: formatMessage({ id: "notification.error", defaultMessage: "An error occurred" })
959
- });
960
- }
961
- toggleEditReleaseModal();
962
- };
963
- const handleDeleteRelease = async () => {
964
- const response = await deleteRelease({
965
- id: releaseId
966
- });
967
- if ("data" in response) {
968
- push("/plugins/content-releases");
969
- } else if (index.isAxiosError(response.error)) {
970
- toggleNotification({
971
- type: "warning",
972
- message: formatAPIError(response.error)
973
- });
974
- } else {
975
- toggleNotification({
976
- type: "warning",
977
- message: formatMessage({ id: "notification.error", defaultMessage: "An error occurred" })
978
- });
979
- }
980
- };
981
- return /* @__PURE__ */ jsxRuntime.jsxs(
982
- ReleaseDetailsLayout,
983
- {
984
- toggleEditReleaseModal,
985
- toggleWarningSubmit,
986
- children: [
987
- /* @__PURE__ */ jsxRuntime.jsx(ReleaseDetailsBody, {}),
988
- releaseModalShown && /* @__PURE__ */ jsxRuntime.jsx(
989
- ReleaseModal,
990
- {
991
- handleClose: toggleEditReleaseModal,
992
- handleSubmit: handleEditRelease,
993
- isLoading: isLoadingDetails || isSubmittingForm,
994
- initialValues: {
995
- name: title || "",
996
- scheduledAt,
997
- date,
998
- time,
999
- isScheduled: Boolean(scheduledAt),
1000
- timezone
1001
- }
1002
- }
1003
- ),
1004
- /* @__PURE__ */ jsxRuntime.jsx(
1005
- helperPlugin.ConfirmDialog,
1006
- {
1007
- bodyText: {
1008
- id: "content-releases.dialog.confirmation-message",
1009
- defaultMessage: "Are you sure you want to delete this release?"
1010
- },
1011
- isOpen: showWarningSubmit,
1012
- isConfirmButtonLoading: isDeletingRelease,
1013
- onToggleDialog: toggleWarningSubmit,
1014
- onConfirm: handleDeleteRelease
1015
- }
1016
- )
1017
- ]
1018
- }
1019
- );
1020
- };
1021
- const LinkCard = styled__default.default(v2.Link)`
1022
- display: block;
1023
- `;
1024
- const ReleasesGrid = ({ sectionTitle, releases = [], isError = false }) => {
1025
- const { formatMessage } = reactIntl.useIntl();
1026
- const IsSchedulingEnabled = window.strapi.future.isEnabled("contentReleasesScheduling");
1027
- if (isError) {
1028
- return /* @__PURE__ */ jsxRuntime.jsx(helperPlugin.AnErrorOccurred, {});
1029
- }
1030
- if (releases?.length === 0) {
1031
- return /* @__PURE__ */ jsxRuntime.jsx(
1032
- designSystem.EmptyStateLayout,
1033
- {
1034
- content: formatMessage(
1035
- {
1036
- id: "content-releases.page.Releases.tab.emptyEntries",
1037
- defaultMessage: "No releases"
1038
- },
1039
- {
1040
- target: sectionTitle
1041
- }
1042
- ),
1043
- icon: /* @__PURE__ */ jsxRuntime.jsx(icons.EmptyDocuments, { width: "10rem" })
1044
- }
1045
- );
1046
- }
1047
- return /* @__PURE__ */ jsxRuntime.jsx(designSystem.Grid, { gap: 4, children: releases.map(({ id, name, actions, scheduledAt }) => /* @__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(
1048
- designSystem.Flex,
1049
- {
1050
- direction: "column",
1051
- justifyContent: "space-between",
1052
- padding: 4,
1053
- hasRadius: true,
1054
- background: "neutral0",
1055
- shadow: "tableShadow",
1056
- height: "100%",
1057
- width: "100%",
1058
- alignItems: "start",
1059
- gap: 2,
1060
- children: [
1061
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { as: "h3", variant: "delta", fontWeight: "bold", children: name }),
1062
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "pi", textColor: "neutral600", children: IsSchedulingEnabled ? scheduledAt ? /* @__PURE__ */ jsxRuntime.jsx(helperPlugin.RelativeTime, { timestamp: new Date(scheduledAt) }) : formatMessage({
1063
- id: "content-releases.pages.Releases.not-scheduled",
1064
- defaultMessage: "Not scheduled"
1065
- }) : formatMessage(
1066
- {
1067
- id: "content-releases.page.Releases.release-item.entries",
1068
- defaultMessage: "{number, plural, =0 {No entries} one {# entry} other {# entries}}"
1069
- },
1070
- { number: actions.meta.count }
1071
- ) })
1072
- ]
1073
- }
1074
- ) }) }, id)) });
1075
- };
1076
- const StyledAlert = styled__default.default(designSystem.Alert)`
1077
- button {
1078
- display: none;
1079
- }
1080
- p + div {
1081
- margin-left: auto;
1082
- }
1083
- `;
1084
- const INITIAL_FORM_VALUES = {
1085
- name: "",
1086
- date: null,
1087
- time: "",
1088
- // Remove future flag check after Scheduling Beta release and replace with true as creating new release should include scheduling by default
1089
- isScheduled: window.strapi.future.isEnabled("contentReleasesScheduling"),
1090
- scheduledAt: null,
1091
- timezone: null
1092
- };
1093
- const ReleasesPage = () => {
1094
- const tabRef = React__namespace.useRef(null);
1095
- const location = reactRouterDom.useLocation();
1096
- const [releaseModalShown, setReleaseModalShown] = React__namespace.useState(false);
1097
- const toggleNotification = helperPlugin.useNotification();
1098
- const { formatMessage } = reactIntl.useIntl();
1099
- const { push, replace } = reactRouterDom.useHistory();
1100
- const { formatAPIError } = helperPlugin.useAPIErrorHandler();
1101
- const [{ query }, setQuery] = helperPlugin.useQueryParams();
1102
- const response = index.useGetReleasesQuery(query);
1103
- const [createRelease, { isLoading: isSubmittingForm }] = index.useCreateReleaseMutation();
1104
- const { getFeature } = strapiAdmin.useLicenseLimits();
1105
- const { maximumReleases = 3 } = getFeature("cms-content-releases");
1106
- const { trackUsage } = helperPlugin.useTracking();
1107
- const { isLoading, isSuccess, isError } = response;
1108
- const activeTab = response?.currentData?.meta?.activeTab || "pending";
1109
- const activeTabIndex = ["pending", "done"].indexOf(activeTab);
1110
- React__namespace.useEffect(() => {
1111
- if (location?.state?.errors) {
1112
- toggleNotification({
1113
- type: "warning",
1114
- title: formatMessage({
1115
- id: "content-releases.pages.Releases.notification.error.title",
1116
- defaultMessage: "Your request could not be processed."
1117
- }),
1118
- message: formatMessage({
1119
- id: "content-releases.pages.Releases.notification.error.message",
1120
- defaultMessage: "Please try again or open another release."
1121
- })
1122
- });
1123
- replace({ state: null });
1124
- }
1125
- }, [formatMessage, location?.state?.errors, replace, toggleNotification]);
1126
- React__namespace.useEffect(() => {
1127
- if (tabRef.current) {
1128
- tabRef.current._handlers.setSelectedTabIndex(activeTabIndex);
1129
- }
1130
- }, [activeTabIndex]);
1131
- const toggleAddReleaseModal = () => {
1191
+ releaseId: release.id,
1192
+ actionId: id
1193
+ }
1194
+ )
1195
+ ] }) }) })
1196
+ ] })
1197
+ ] }, id)
1198
+ ) })
1199
+ ] })
1200
+ }
1201
+ )
1202
+ ] }, `releases-group-${key}`)),
1203
+ /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { paddingTop: 4, alignItems: "flex-end", justifyContent: "space-between", children: [
1204
+ /* @__PURE__ */ jsxRuntime.jsx(helperPlugin.PageSizeURLQuery, { defaultValue: releaseMeta?.pagination?.pageSize.toString() }),
1205
+ /* @__PURE__ */ jsxRuntime.jsx(
1206
+ helperPlugin.PaginationURLQuery,
1207
+ {
1208
+ pagination: {
1209
+ pageCount: releaseMeta?.pagination?.pageCount || 0
1210
+ }
1211
+ }
1212
+ )
1213
+ ] })
1214
+ ] }) });
1215
+ };
1216
+ const ReleaseDetailsPage = () => {
1217
+ const { formatMessage } = reactIntl.useIntl();
1218
+ const { releaseId } = reactRouterDom.useParams();
1219
+ const toggleNotification = helperPlugin.useNotification();
1220
+ const { formatAPIError } = helperPlugin.useAPIErrorHandler();
1221
+ const { push } = reactRouterDom.useHistory();
1222
+ const [releaseModalShown, setReleaseModalShown] = React__namespace.useState(false);
1223
+ const [showWarningSubmit, setWarningSubmit] = React__namespace.useState(false);
1224
+ const {
1225
+ isLoading: isLoadingDetails,
1226
+ data,
1227
+ isSuccess: isSuccessDetails
1228
+ } = index.useGetReleaseQuery({ id: releaseId });
1229
+ const [updateRelease, { isLoading: isSubmittingForm }] = index.useUpdateReleaseMutation();
1230
+ const [deleteRelease, { isLoading: isDeletingRelease }] = index.useDeleteReleaseMutation();
1231
+ const toggleEditReleaseModal = () => {
1132
1232
  setReleaseModalShown((prev) => !prev);
1133
1233
  };
1134
- if (isLoading) {
1135
- return /* @__PURE__ */ jsxRuntime.jsx(designSystem.Main, { "aria-busy": isLoading, children: /* @__PURE__ */ jsxRuntime.jsx(helperPlugin.LoadingIndicatorPage, {}) });
1136
- }
1137
- const totalReleases = isSuccess && response.currentData?.meta?.pagination?.total || 0;
1138
- const hasReachedMaximumPendingReleases = totalReleases >= maximumReleases;
1139
- const handleTabChange = (index2) => {
1140
- setQuery({
1141
- ...query,
1142
- page: 1,
1143
- pageSize: response?.currentData?.meta?.pagination?.pageSize || 16,
1144
- filters: {
1145
- releasedAt: {
1146
- $notNull: index2 === 0 ? false : true
1147
- }
1234
+ const toggleWarningSubmit = () => setWarningSubmit((prevState) => !prevState);
1235
+ if (isLoadingDetails) {
1236
+ return /* @__PURE__ */ jsxRuntime.jsx(
1237
+ ReleaseDetailsLayout,
1238
+ {
1239
+ toggleEditReleaseModal,
1240
+ toggleWarningSubmit,
1241
+ children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.ContentLayout, { children: /* @__PURE__ */ jsxRuntime.jsx(helperPlugin.LoadingIndicatorPage, {}) })
1148
1242
  }
1243
+ );
1244
+ }
1245
+ const releaseData = isSuccessDetails && data?.data || null;
1246
+ const title = releaseData?.name || "";
1247
+ const timezone = releaseData?.timezone ?? null;
1248
+ const scheduledAt = releaseData?.scheduledAt && timezone ? dateFnsTz.utcToZonedTime(releaseData.scheduledAt, timezone) : null;
1249
+ const date = scheduledAt ? new Date(format__default.default(scheduledAt, "yyyy-MM-dd")) : null;
1250
+ const time = scheduledAt ? format__default.default(scheduledAt, "HH:mm") : "";
1251
+ const handleEditRelease = async (values) => {
1252
+ const response = await updateRelease({
1253
+ id: releaseId,
1254
+ name: values.name,
1255
+ scheduledAt: values.scheduledAt,
1256
+ timezone: values.timezone
1149
1257
  });
1150
- };
1151
- const handleAddRelease = async ({ name, scheduledAt, timezone }) => {
1152
- const response2 = await createRelease({
1153
- name,
1154
- scheduledAt,
1155
- timezone
1156
- });
1157
- if ("data" in response2) {
1258
+ if ("data" in response) {
1158
1259
  toggleNotification({
1159
1260
  type: "success",
1160
1261
  message: formatMessage({
1161
- id: "content-releases.modal.release-created-notification-success",
1162
- defaultMessage: "Release created."
1262
+ id: "content-releases.modal.release-updated-notification-success",
1263
+ defaultMessage: "Release updated."
1163
1264
  })
1164
1265
  });
1165
- trackUsage("didCreateRelease");
1166
- push(`/plugins/content-releases/${response2.data.data.id}`);
1167
- } else if (index.isAxiosError(response2.error)) {
1266
+ } else if (index.isAxiosError(response.error)) {
1168
1267
  toggleNotification({
1169
1268
  type: "warning",
1170
- message: formatAPIError(response2.error)
1269
+ message: formatAPIError(response.error)
1171
1270
  });
1172
1271
  } else {
1173
1272
  toggleNotification({
@@ -1175,135 +1274,65 @@ const ReleasesPage = () => {
1175
1274
  message: formatMessage({ id: "notification.error", defaultMessage: "An error occurred" })
1176
1275
  });
1177
1276
  }
1277
+ toggleEditReleaseModal();
1178
1278
  };
1179
- return /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Main, { "aria-busy": isLoading, children: [
1180
- /* @__PURE__ */ jsxRuntime.jsx(
1181
- designSystem.HeaderLayout,
1182
- {
1183
- title: formatMessage({
1184
- id: "content-releases.pages.Releases.title",
1185
- defaultMessage: "Releases"
1186
- }),
1187
- subtitle: formatMessage(
1188
- {
1189
- id: "content-releases.pages.Releases.header-subtitle",
1190
- defaultMessage: "{number, plural, =0 {No releases} one {# release} other {# releases}}"
1191
- },
1192
- { number: totalReleases }
1193
- ),
1194
- primaryAction: /* @__PURE__ */ jsxRuntime.jsx(helperPlugin.CheckPermissions, { permissions: index.PERMISSIONS.create, children: /* @__PURE__ */ jsxRuntime.jsx(
1195
- designSystem.Button,
1196
- {
1197
- startIcon: /* @__PURE__ */ jsxRuntime.jsx(icons.Plus, {}),
1198
- onClick: toggleAddReleaseModal,
1199
- disabled: hasReachedMaximumPendingReleases,
1200
- children: formatMessage({
1201
- id: "content-releases.header.actions.add-release",
1202
- defaultMessage: "New release"
1203
- })
1204
- }
1205
- ) })
1206
- }
1207
- ),
1208
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.ContentLayout, { children: /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
1209
- activeTab === "pending" && hasReachedMaximumPendingReleases && /* @__PURE__ */ jsxRuntime.jsx(
1210
- StyledAlert,
1211
- {
1212
- marginBottom: 6,
1213
- action: /* @__PURE__ */ jsxRuntime.jsx(v2.Link, { href: "https://strapi.io/pricing-cloud", isExternal: true, children: formatMessage({
1214
- id: "content-releases.pages.Releases.max-limit-reached.action",
1215
- defaultMessage: "Explore plans"
1216
- }) }),
1217
- title: formatMessage(
1218
- {
1219
- id: "content-releases.pages.Releases.max-limit-reached.title",
1220
- defaultMessage: "You have reached the {number} pending {number, plural, one {release} other {releases}} limit."
1221
- },
1222
- { number: maximumReleases }
1223
- ),
1224
- onClose: () => {
1225
- },
1226
- closeLabel: "",
1227
- children: formatMessage({
1228
- id: "content-releases.pages.Releases.max-limit-reached.message",
1229
- defaultMessage: "Upgrade to manage an unlimited number of releases."
1230
- })
1231
- }
1232
- ),
1233
- /* @__PURE__ */ jsxRuntime.jsxs(
1234
- designSystem.TabGroup,
1235
- {
1236
- label: formatMessage({
1237
- id: "content-releases.pages.Releases.tab-group.label",
1238
- defaultMessage: "Releases list"
1239
- }),
1240
- variant: "simple",
1241
- initialSelectedTabIndex: activeTabIndex,
1242
- onTabChange: handleTabChange,
1243
- ref: tabRef,
1244
- children: [
1245
- /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Box, { paddingBottom: 8, children: [
1246
- /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Tabs, { children: [
1247
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Tab, { children: formatMessage({
1248
- id: "content-releases.pages.Releases.tab.pending",
1249
- defaultMessage: "Pending"
1250
- }) }),
1251
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Tab, { children: formatMessage({
1252
- id: "content-releases.pages.Releases.tab.done",
1253
- defaultMessage: "Done"
1254
- }) })
1255
- ] }),
1256
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Divider, {})
1257
- ] }),
1258
- /* @__PURE__ */ jsxRuntime.jsxs(designSystem.TabPanels, { children: [
1259
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.TabPanel, { children: /* @__PURE__ */ jsxRuntime.jsx(
1260
- ReleasesGrid,
1261
- {
1262
- sectionTitle: "pending",
1263
- releases: response?.currentData?.data,
1264
- isError
1265
- }
1266
- ) }),
1267
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.TabPanel, { children: /* @__PURE__ */ jsxRuntime.jsx(
1268
- ReleasesGrid,
1269
- {
1270
- sectionTitle: "done",
1271
- releases: response?.currentData?.data,
1272
- isError
1273
- }
1274
- ) })
1275
- ] })
1276
- ]
1277
- }
1278
- ),
1279
- totalReleases > 0 && /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { paddingTop: 4, alignItems: "flex-end", justifyContent: "space-between", children: [
1280
- /* @__PURE__ */ jsxRuntime.jsx(
1281
- helperPlugin.PageSizeURLQuery,
1279
+ const handleDeleteRelease = async () => {
1280
+ const response = await deleteRelease({
1281
+ id: releaseId
1282
+ });
1283
+ if ("data" in response) {
1284
+ push("/plugins/content-releases");
1285
+ } else if (index.isAxiosError(response.error)) {
1286
+ toggleNotification({
1287
+ type: "warning",
1288
+ message: formatAPIError(response.error)
1289
+ });
1290
+ } else {
1291
+ toggleNotification({
1292
+ type: "warning",
1293
+ message: formatMessage({ id: "notification.error", defaultMessage: "An error occurred" })
1294
+ });
1295
+ }
1296
+ };
1297
+ return /* @__PURE__ */ jsxRuntime.jsxs(
1298
+ ReleaseDetailsLayout,
1299
+ {
1300
+ toggleEditReleaseModal,
1301
+ toggleWarningSubmit,
1302
+ children: [
1303
+ /* @__PURE__ */ jsxRuntime.jsx(ReleaseDetailsBody, {}),
1304
+ releaseModalShown && /* @__PURE__ */ jsxRuntime.jsx(
1305
+ ReleaseModal,
1282
1306
  {
1283
- options: ["8", "16", "32", "64"],
1284
- defaultValue: response?.currentData?.meta?.pagination?.pageSize.toString()
1307
+ handleClose: toggleEditReleaseModal,
1308
+ handleSubmit: handleEditRelease,
1309
+ isLoading: isLoadingDetails || isSubmittingForm,
1310
+ initialValues: {
1311
+ name: title || "",
1312
+ scheduledAt,
1313
+ date,
1314
+ time,
1315
+ isScheduled: Boolean(scheduledAt),
1316
+ timezone
1317
+ }
1285
1318
  }
1286
1319
  ),
1287
1320
  /* @__PURE__ */ jsxRuntime.jsx(
1288
- helperPlugin.PaginationURLQuery,
1321
+ helperPlugin.ConfirmDialog,
1289
1322
  {
1290
- pagination: {
1291
- pageCount: response?.currentData?.meta?.pagination?.pageCount || 0
1292
- }
1323
+ bodyText: {
1324
+ id: "content-releases.dialog.confirmation-message",
1325
+ defaultMessage: "Are you sure you want to delete this release?"
1326
+ },
1327
+ isOpen: showWarningSubmit,
1328
+ isConfirmButtonLoading: isDeletingRelease,
1329
+ onToggleDialog: toggleWarningSubmit,
1330
+ onConfirm: handleDeleteRelease
1293
1331
  }
1294
1332
  )
1295
- ] })
1296
- ] }) }),
1297
- releaseModalShown && /* @__PURE__ */ jsxRuntime.jsx(
1298
- ReleaseModal,
1299
- {
1300
- handleClose: toggleAddReleaseModal,
1301
- handleSubmit: handleAddRelease,
1302
- isLoading: isSubmittingForm,
1303
- initialValues: INITIAL_FORM_VALUES
1304
- }
1305
- )
1306
- ] });
1333
+ ]
1334
+ }
1335
+ );
1307
1336
  };
1308
1337
  const App = () => {
1309
1338
  return /* @__PURE__ */ jsxRuntime.jsx(helperPlugin.CheckPagePermissions, { permissions: index.PERMISSIONS.main, children: /* @__PURE__ */ jsxRuntime.jsxs(reactRouterDom.Switch, { children: [
@@ -1312,4 +1341,4 @@ const App = () => {
1312
1341
  ] }) });
1313
1342
  };
1314
1343
  exports.App = App;
1315
- //# sourceMappingURL=App-C_iroyIu.js.map
1344
+ //# sourceMappingURL=App-P1kyM3gT.js.map