@strapi/content-releases 0.0.0-next.d10040847b91742ccb8083938399b63ffa289c7a → 0.0.0-next.e09d30edcbd16960a838997778a31d50e9c60bc4

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