node_modules ignore

This commit is contained in:
2025-05-08 23:43:47 +02:00
parent e19d52f172
commit 4574544c9f
65041 changed files with 10593536 additions and 0 deletions

View File

@@ -0,0 +1,29 @@
'use strict';
var jsxRuntime = require('react/jsx-runtime');
var strapiAdmin = require('@strapi/admin/strapi-admin');
var reactRouterDom = require('react-router-dom');
var constants = require('../constants.js');
var ReleaseDetailsPage = require('./ReleaseDetailsPage.js');
var ReleasesPage = require('./ReleasesPage.js');
const App = ()=>{
return /*#__PURE__*/ jsxRuntime.jsx(strapiAdmin.Page.Protect, {
permissions: constants.PERMISSIONS.main,
children: /*#__PURE__*/ jsxRuntime.jsxs(reactRouterDom.Routes, {
children: [
/*#__PURE__*/ jsxRuntime.jsx(reactRouterDom.Route, {
index: true,
element: /*#__PURE__*/ jsxRuntime.jsx(ReleasesPage.ReleasesPage, {})
}),
/*#__PURE__*/ jsxRuntime.jsx(reactRouterDom.Route, {
path: ':releaseId',
element: /*#__PURE__*/ jsxRuntime.jsx(ReleaseDetailsPage.ReleaseDetailsPage, {})
})
]
})
});
};
exports.App = App;
//# sourceMappingURL=App.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"App.js","sources":["../../../admin/src/pages/App.tsx"],"sourcesContent":["import { Page } from '@strapi/admin/strapi-admin';\nimport { Route, Routes } from 'react-router-dom';\n\nimport { PERMISSIONS } from '../constants';\n\nimport { ReleaseDetailsPage } from './ReleaseDetailsPage';\nimport { ReleasesPage } from './ReleasesPage';\n\nexport const App = () => {\n return (\n <Page.Protect permissions={PERMISSIONS.main}>\n <Routes>\n <Route index element={<ReleasesPage />} />\n <Route path={':releaseId'} element={<ReleaseDetailsPage />} />\n </Routes>\n </Page.Protect>\n );\n};\n"],"names":["App","_jsx","Page","Protect","permissions","PERMISSIONS","main","_jsxs","Routes","Route","index","element","ReleasesPage","path","ReleaseDetailsPage"],"mappings":";;;;;;;;;MAQaA,GAAM,GAAA,IAAA;IACjB,qBACEC,cAAA,CAACC,iBAAKC,OAAO,EAAA;AAACC,QAAAA,WAAAA,EAAaC,sBAAYC,IAAI;AACzC,QAAA,QAAA,gBAAAC,eAACC,CAAAA,qBAAAA,EAAAA;;8BACCP,cAACQ,CAAAA,oBAAAA,EAAAA;oBAAMC,KAAK,EAAA,IAAA;AAACC,oBAAAA,OAAAA,gBAASV,cAACW,CAAAA,yBAAAA,EAAAA,EAAAA;;8BACvBX,cAACQ,CAAAA,oBAAAA,EAAAA;oBAAMI,IAAM,EAAA,YAAA;AAAcF,oBAAAA,OAAAA,gBAASV,cAACa,CAAAA,qCAAAA,EAAAA,EAAAA;;;;;AAI7C;;;;"}

View File

@@ -0,0 +1,27 @@
import { jsx, jsxs } from 'react/jsx-runtime';
import { Page } from '@strapi/admin/strapi-admin';
import { Routes, Route } from 'react-router-dom';
import { PERMISSIONS } from '../constants.mjs';
import { ReleaseDetailsPage } from './ReleaseDetailsPage.mjs';
import { ReleasesPage } from './ReleasesPage.mjs';
const App = ()=>{
return /*#__PURE__*/ jsx(Page.Protect, {
permissions: PERMISSIONS.main,
children: /*#__PURE__*/ jsxs(Routes, {
children: [
/*#__PURE__*/ jsx(Route, {
index: true,
element: /*#__PURE__*/ jsx(ReleasesPage, {})
}),
/*#__PURE__*/ jsx(Route, {
path: ':releaseId',
element: /*#__PURE__*/ jsx(ReleaseDetailsPage, {})
})
]
})
});
};
export { App };
//# sourceMappingURL=App.mjs.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"App.mjs","sources":["../../../admin/src/pages/App.tsx"],"sourcesContent":["import { Page } from '@strapi/admin/strapi-admin';\nimport { Route, Routes } from 'react-router-dom';\n\nimport { PERMISSIONS } from '../constants';\n\nimport { ReleaseDetailsPage } from './ReleaseDetailsPage';\nimport { ReleasesPage } from './ReleasesPage';\n\nexport const App = () => {\n return (\n <Page.Protect permissions={PERMISSIONS.main}>\n <Routes>\n <Route index element={<ReleasesPage />} />\n <Route path={':releaseId'} element={<ReleaseDetailsPage />} />\n </Routes>\n </Page.Protect>\n );\n};\n"],"names":["App","_jsx","Page","Protect","permissions","PERMISSIONS","main","_jsxs","Routes","Route","index","element","ReleasesPage","path","ReleaseDetailsPage"],"mappings":";;;;;;;MAQaA,GAAM,GAAA,IAAA;IACjB,qBACEC,GAAA,CAACC,KAAKC,OAAO,EAAA;AAACC,QAAAA,WAAAA,EAAaC,YAAYC,IAAI;AACzC,QAAA,QAAA,gBAAAC,IAACC,CAAAA,MAAAA,EAAAA;;8BACCP,GAACQ,CAAAA,KAAAA,EAAAA;oBAAMC,KAAK,EAAA,IAAA;AAACC,oBAAAA,OAAAA,gBAASV,GAACW,CAAAA,YAAAA,EAAAA,EAAAA;;8BACvBX,GAACQ,CAAAA,KAAAA,EAAAA;oBAAMI,IAAM,EAAA,YAAA;AAAcF,oBAAAA,OAAAA,gBAASV,GAACa,CAAAA,kBAAAA,EAAAA,EAAAA;;;;;AAI7C;;;;"}

View File

@@ -0,0 +1,192 @@
'use strict';
var jsxRuntime = require('react/jsx-runtime');
var strapiAdmin = require('@strapi/admin/strapi-admin');
var designSystem = require('@strapi/design-system');
var icons = require('@strapi/icons');
var reactIntl = require('react-intl');
var purchasePageIllustrationDark = require('../assets/purchase-page-illustration-dark.svg.js');
var purchasePageIllustrationLight = require('../assets/purchase-page-illustration-light.svg.js');
var hooks = require('../modules/hooks.js');
const PurchaseContentReleases = ()=>{
const { formatMessage } = reactIntl.useIntl();
const currentTheme = hooks.useTypedSelector((state)=>state.admin_app.theme.currentTheme);
const illustration = currentTheme === 'light' ? purchasePageIllustrationLight : purchasePageIllustrationDark;
return /*#__PURE__*/ jsxRuntime.jsx(strapiAdmin.Layouts.Root, {
children: /*#__PURE__*/ jsxRuntime.jsxs(designSystem.Main, {
children: [
/*#__PURE__*/ jsxRuntime.jsx(strapiAdmin.Layouts.Header, {
title: formatMessage({
id: 'content-releases.pages.Releases.title',
defaultMessage: 'Releases'
})
}),
/*#__PURE__*/ jsxRuntime.jsx(designSystem.Box, {
marginLeft: 10,
marginRight: 10,
shadow: "filterShadow",
hasRadius: true,
background: "neutral0",
borderColor: 'neutral150',
overflow: 'hidden',
children: /*#__PURE__*/ jsxRuntime.jsxs(designSystem.Grid.Root, {
children: [
/*#__PURE__*/ jsxRuntime.jsx(designSystem.Grid.Item, {
col: 6,
s: 12,
alignItems: 'flex-start',
children: /*#__PURE__*/ jsxRuntime.jsxs(designSystem.Flex, {
direction: "column",
alignItems: "flex-start",
padding: 7,
width: '100%',
children: [
/*#__PURE__*/ jsxRuntime.jsx(designSystem.Flex, {
children: /*#__PURE__*/ jsxRuntime.jsx(icons.PaperPlane, {
fill: "primary600",
width: `24px`,
height: `24px`
})
}),
/*#__PURE__*/ jsxRuntime.jsx(designSystem.Flex, {
paddingTop: 3,
paddingBottom: 4,
children: /*#__PURE__*/ jsxRuntime.jsx(designSystem.Typography, {
variant: "beta",
fontWeight: "bold",
children: formatMessage({
id: 'pages.PurchaseRelease.description',
defaultMessage: 'Group content and publish updates together'
})
})
}),
/*#__PURE__*/ jsxRuntime.jsxs(designSystem.Flex, {
direction: "column",
alignItems: 'flex-start',
gap: 2,
children: [
/*#__PURE__*/ jsxRuntime.jsxs(designSystem.Flex, {
gap: 2,
children: [
/*#__PURE__*/ jsxRuntime.jsx(icons.Check, {
fill: "success500",
width: `16px`,
height: `16px`,
style: {
flexShrink: 0
}
}),
/*#__PURE__*/ jsxRuntime.jsx(designSystem.Typography, {
textColor: "neutral700",
children: formatMessage({
id: 'pages.PurchaseRelease.perks1',
defaultMessage: 'Add many entries to releases'
})
})
]
}),
/*#__PURE__*/ jsxRuntime.jsxs(designSystem.Flex, {
gap: 2,
children: [
/*#__PURE__*/ jsxRuntime.jsx(icons.Check, {
fill: "success500",
width: `16px`,
height: `16px`,
style: {
flexShrink: 0
}
}),
/*#__PURE__*/ jsxRuntime.jsx(designSystem.Typography, {
textColor: "neutral700",
children: formatMessage({
id: 'pages.PurchaseRelease.perks2',
defaultMessage: 'Quickly identify entries containing errors'
})
})
]
}),
/*#__PURE__*/ jsxRuntime.jsxs(designSystem.Flex, {
gap: 2,
children: [
/*#__PURE__*/ jsxRuntime.jsx(icons.Check, {
fill: "success500",
width: `16px`,
height: `16px`,
style: {
flexShrink: 0
}
}),
/*#__PURE__*/ jsxRuntime.jsx(designSystem.Typography, {
textColor: "neutral700",
children: formatMessage({
id: 'pages.PurchaseRelease.perks3',
defaultMessage: 'Schedule their publication, or publish them manually'
})
})
]
})
]
}),
/*#__PURE__*/ jsxRuntime.jsxs(designSystem.Flex, {
gap: 2,
marginTop: 7,
children: [
/*#__PURE__*/ jsxRuntime.jsx(designSystem.LinkButton, {
variant: "default",
href: "https://strapi.io/pricing-self-hosted?utm_campaign=In-Product-CTA&utm_source=Releases",
children: formatMessage({
id: 'Settings.page.purchase.upgrade.cta',
defaultMessage: 'Upgrade'
})
}),
/*#__PURE__*/ jsxRuntime.jsx(designSystem.LinkButton, {
variant: "tertiary",
endIcon: /*#__PURE__*/ jsxRuntime.jsx(icons.ExternalLink, {}),
href: "https://strapi.io/features/releases?utm_campaign=In-Product-CTA&utm_source=Releases",
children: formatMessage({
id: 'Settings.page.purchase.learn-more.cta',
defaultMessage: 'Learn more'
})
})
]
})
]
})
}),
/*#__PURE__*/ jsxRuntime.jsx(designSystem.Grid.Item, {
col: 6,
s: 12,
background: "primary100",
minHeight: '280px',
children: /*#__PURE__*/ jsxRuntime.jsx("div", {
style: {
position: 'relative',
width: '100%',
height: '100%'
},
children: /*#__PURE__*/ jsxRuntime.jsx("img", {
src: illustration,
alt: "purchase-page-content-releases-illustration",
style: {
position: 'absolute',
top: 0,
left: 0,
width: '100%',
height: '100%',
objectFit: 'cover',
objectPosition: 'top left'
}
})
})
})
]
})
})
]
})
});
};
exports.PurchaseContentReleases = PurchaseContentReleases;
//# sourceMappingURL=PurchaseContentReleases.js.map

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,190 @@
import { jsx, jsxs } from 'react/jsx-runtime';
import { Layouts } from '@strapi/admin/strapi-admin';
import { Main, Box, Grid, Flex, Typography, LinkButton } from '@strapi/design-system';
import { PaperPlane, Check, ExternalLink } from '@strapi/icons';
import { useIntl } from 'react-intl';
import img$1 from '../assets/purchase-page-illustration-dark.svg.mjs';
import img from '../assets/purchase-page-illustration-light.svg.mjs';
import { useTypedSelector } from '../modules/hooks.mjs';
const PurchaseContentReleases = ()=>{
const { formatMessage } = useIntl();
const currentTheme = useTypedSelector((state)=>state.admin_app.theme.currentTheme);
const illustration = currentTheme === 'light' ? img : img$1;
return /*#__PURE__*/ jsx(Layouts.Root, {
children: /*#__PURE__*/ jsxs(Main, {
children: [
/*#__PURE__*/ jsx(Layouts.Header, {
title: formatMessage({
id: 'content-releases.pages.Releases.title',
defaultMessage: 'Releases'
})
}),
/*#__PURE__*/ jsx(Box, {
marginLeft: 10,
marginRight: 10,
shadow: "filterShadow",
hasRadius: true,
background: "neutral0",
borderColor: 'neutral150',
overflow: 'hidden',
children: /*#__PURE__*/ jsxs(Grid.Root, {
children: [
/*#__PURE__*/ jsx(Grid.Item, {
col: 6,
s: 12,
alignItems: 'flex-start',
children: /*#__PURE__*/ jsxs(Flex, {
direction: "column",
alignItems: "flex-start",
padding: 7,
width: '100%',
children: [
/*#__PURE__*/ jsx(Flex, {
children: /*#__PURE__*/ jsx(PaperPlane, {
fill: "primary600",
width: `24px`,
height: `24px`
})
}),
/*#__PURE__*/ jsx(Flex, {
paddingTop: 3,
paddingBottom: 4,
children: /*#__PURE__*/ jsx(Typography, {
variant: "beta",
fontWeight: "bold",
children: formatMessage({
id: 'pages.PurchaseRelease.description',
defaultMessage: 'Group content and publish updates together'
})
})
}),
/*#__PURE__*/ jsxs(Flex, {
direction: "column",
alignItems: 'flex-start',
gap: 2,
children: [
/*#__PURE__*/ jsxs(Flex, {
gap: 2,
children: [
/*#__PURE__*/ jsx(Check, {
fill: "success500",
width: `16px`,
height: `16px`,
style: {
flexShrink: 0
}
}),
/*#__PURE__*/ jsx(Typography, {
textColor: "neutral700",
children: formatMessage({
id: 'pages.PurchaseRelease.perks1',
defaultMessage: 'Add many entries to releases'
})
})
]
}),
/*#__PURE__*/ jsxs(Flex, {
gap: 2,
children: [
/*#__PURE__*/ jsx(Check, {
fill: "success500",
width: `16px`,
height: `16px`,
style: {
flexShrink: 0
}
}),
/*#__PURE__*/ jsx(Typography, {
textColor: "neutral700",
children: formatMessage({
id: 'pages.PurchaseRelease.perks2',
defaultMessage: 'Quickly identify entries containing errors'
})
})
]
}),
/*#__PURE__*/ jsxs(Flex, {
gap: 2,
children: [
/*#__PURE__*/ jsx(Check, {
fill: "success500",
width: `16px`,
height: `16px`,
style: {
flexShrink: 0
}
}),
/*#__PURE__*/ jsx(Typography, {
textColor: "neutral700",
children: formatMessage({
id: 'pages.PurchaseRelease.perks3',
defaultMessage: 'Schedule their publication, or publish them manually'
})
})
]
})
]
}),
/*#__PURE__*/ jsxs(Flex, {
gap: 2,
marginTop: 7,
children: [
/*#__PURE__*/ jsx(LinkButton, {
variant: "default",
href: "https://strapi.io/pricing-self-hosted?utm_campaign=In-Product-CTA&utm_source=Releases",
children: formatMessage({
id: 'Settings.page.purchase.upgrade.cta',
defaultMessage: 'Upgrade'
})
}),
/*#__PURE__*/ jsx(LinkButton, {
variant: "tertiary",
endIcon: /*#__PURE__*/ jsx(ExternalLink, {}),
href: "https://strapi.io/features/releases?utm_campaign=In-Product-CTA&utm_source=Releases",
children: formatMessage({
id: 'Settings.page.purchase.learn-more.cta',
defaultMessage: 'Learn more'
})
})
]
})
]
})
}),
/*#__PURE__*/ jsx(Grid.Item, {
col: 6,
s: 12,
background: "primary100",
minHeight: '280px',
children: /*#__PURE__*/ jsx("div", {
style: {
position: 'relative',
width: '100%',
height: '100%'
},
children: /*#__PURE__*/ jsx("img", {
src: illustration,
alt: "purchase-page-content-releases-illustration",
style: {
position: 'absolute',
top: 0,
left: 0,
width: '100%',
height: '100%',
objectFit: 'cover',
objectPosition: 'top left'
}
})
})
})
]
})
})
]
})
});
};
export { PurchaseContentReleases };
//# sourceMappingURL=PurchaseContentReleases.mjs.map

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,821 @@
'use strict';
var jsxRuntime = require('react/jsx-runtime');
var React = require('react');
var strapiAdmin = require('@strapi/admin/strapi-admin');
var designSystem = require('@strapi/design-system');
var icons = require('@strapi/icons');
var symbols = require('@strapi/icons/symbols');
var format = require('date-fns/format');
var dateFnsTz = require('date-fns-tz');
var reactIntl = require('react-intl');
var reactRouterDom = require('react-router-dom');
var styledComponents = require('styled-components');
var EntryValidationPopover = require('../components/EntryValidationPopover.js');
var RelativeTime = require('../components/RelativeTime.js');
var ReleaseActionMenu = require('../components/ReleaseActionMenu.js');
var ReleaseActionOptions = require('../components/ReleaseActionOptions.js');
var ReleaseModal = require('../components/ReleaseModal.js');
var constants = require('../constants.js');
var release = require('../services/release.js');
var hooks = require('../store/hooks.js');
var api = require('../utils/api.js');
var time = require('../utils/time.js');
var ReleasesPage = require('./ReleasesPage.js');
function _interopNamespaceDefault(e) {
var n = Object.create(null);
if (e) {
Object.keys(e).forEach(function (k) {
if (k !== 'default') {
var d = Object.getOwnPropertyDescriptor(e, k);
Object.defineProperty(n, k, d.get ? d : {
enumerable: true,
get: function () { return e[k]; }
});
}
});
}
n.default = e;
return Object.freeze(n);
}
var React__namespace = /*#__PURE__*/_interopNamespaceDefault(React);
/* -------------------------------------------------------------------------------------------------
* ReleaseDetailsLayout
* -----------------------------------------------------------------------------------------------*/ const ReleaseInfoWrapper = styledComponents.styled(designSystem.Flex)`
align-self: stretch;
border-bottom-right-radius: ${({ theme })=>theme.borderRadius};
border-bottom-left-radius: ${({ theme })=>theme.borderRadius};
border-top: 1px solid ${({ theme })=>theme.colors.neutral150};
`;
const StyledMenuItem = styledComponents.styled(designSystem.MenuItem)`
svg path {
fill: ${({ theme, disabled })=>disabled && theme.colors.neutral500};
}
span {
color: ${({ theme, disabled })=>disabled && theme.colors.neutral500};
}
&:hover {
background: ${({ theme, $variant = 'neutral' })=>theme.colors[`${$variant}100`]};
}
`;
const PencilIcon = styledComponents.styled(icons.Pencil)`
width: ${({ theme })=>theme.spaces[4]};
height: ${({ theme })=>theme.spaces[4]};
path {
fill: ${({ theme })=>theme.colors.neutral600};
}
`;
const TrashIcon = styledComponents.styled(icons.Trash)`
width: ${({ theme })=>theme.spaces[4]};
height: ${({ theme })=>theme.spaces[4]};
path {
fill: ${({ theme })=>theme.colors.danger600};
}
`;
const ReleaseDetailsLayout = ({ toggleEditReleaseModal, toggleWarningSubmit, children })=>{
const { formatMessage, formatDate, formatTime } = reactIntl.useIntl();
const { releaseId } = reactRouterDom.useParams();
const { data, isLoading: isLoadingDetails, error } = release.useGetReleaseQuery({
id: releaseId
}, {
skip: !releaseId
});
const [publishRelease, { isLoading: isPublishing }] = release.usePublishReleaseMutation();
const { toggleNotification } = strapiAdmin.useNotification();
const { formatAPIError } = strapiAdmin.useAPIErrorHandler();
const { allowedActions } = strapiAdmin.useRBAC(constants.PERMISSIONS);
const { canUpdate, canDelete, canPublish } = allowedActions;
const dispatch = hooks.useTypedDispatch();
const { trackUsage } = strapiAdmin.useTracking();
const release$1 = data?.data;
const handlePublishRelease = (id)=>async ()=>{
const response = await publishRelease({
id
});
if ('data' in response) {
// When the response returns an object with 'data', handle success
toggleNotification({
type: 'success',
message: formatMessage({
id: 'content-releases.pages.ReleaseDetails.publish-notification-success',
defaultMessage: 'Release was published successfully.'
})
});
const { totalEntries, totalPublishedEntries, totalUnpublishedEntries } = response.data.meta;
trackUsage('didPublishRelease', {
totalEntries,
totalPublishedEntries,
totalUnpublishedEntries
});
} else if (strapiAdmin.isFetchError(response.error)) {
// When the response returns an object with 'error', handle fetch error
toggleNotification({
type: 'danger',
message: formatAPIError(response.error)
});
} else {
// Otherwise, the response returns an object with 'error', handle a generic error
toggleNotification({
type: 'danger',
message: formatMessage({
id: 'notification.error',
defaultMessage: 'An error occurred'
})
});
}
};
const handleRefresh = ()=>{
dispatch(release.releaseApi.util.invalidateTags([
{
type: 'ReleaseAction',
id: 'LIST'
},
{
type: 'Release',
id: releaseId
}
]));
};
const getCreatedByUser = ()=>{
if (!release$1?.createdBy) {
return null;
}
// Favor the username
if (release$1.createdBy.username) {
return release$1.createdBy.username;
}
// Firstname may not exist if created with SSO
if (release$1.createdBy.firstname) {
return `${release$1.createdBy.firstname} ${release$1.createdBy.lastname || ''}`.trim();
}
// All users must have at least an email
return release$1.createdBy.email;
};
if (isLoadingDetails) {
return /*#__PURE__*/ jsxRuntime.jsx(strapiAdmin.Page.Loading, {});
}
if (api.isBaseQueryError(error) && 'code' in error || !release$1) {
return /*#__PURE__*/ jsxRuntime.jsx(reactRouterDom.Navigate, {
to: "..",
state: {
errors: [
{
// @ts-expect-error TODO: fix this weird error flow
code: error?.code
}
]
}
});
}
const totalEntries = release$1.actions.meta.count || 0;
const hasCreatedByUser = Boolean(getCreatedByUser());
const isScheduled = release$1.scheduledAt && release$1.timezone;
const numberOfEntriesText = formatMessage({
id: 'content-releases.pages.Details.header-subtitle',
defaultMessage: '{number, plural, =0 {No entries} one {# entry} other {# entries}}'
}, {
number: totalEntries
});
const scheduledText = isScheduled ? formatMessage({
id: 'content-releases.pages.ReleaseDetails.header-subtitle.scheduled',
defaultMessage: 'Scheduled for {date} at {time} ({offset})'
}, {
date: formatDate(new Date(release$1.scheduledAt), {
weekday: 'long',
day: 'numeric',
month: 'long',
year: 'numeric',
timeZone: release$1.timezone
}),
time: formatTime(new Date(release$1.scheduledAt), {
timeZone: release$1.timezone,
hourCycle: 'h23'
}),
offset: time.getTimezoneOffset(release$1.timezone, new Date(release$1.scheduledAt))
}) : '';
return /*#__PURE__*/ jsxRuntime.jsxs(designSystem.Main, {
"aria-busy": isLoadingDetails,
children: [
/*#__PURE__*/ jsxRuntime.jsx(strapiAdmin.Layouts.Header, {
title: release$1.name,
subtitle: /*#__PURE__*/ jsxRuntime.jsxs(designSystem.Flex, {
gap: 2,
lineHeight: 6,
children: [
/*#__PURE__*/ jsxRuntime.jsx(designSystem.Typography, {
textColor: "neutral600",
variant: "epsilon",
children: numberOfEntriesText + (isScheduled ? ` - ${scheduledText}` : '')
}),
/*#__PURE__*/ jsxRuntime.jsx(designSystem.Badge, {
...ReleasesPage.getBadgeProps(release$1.status),
children: release$1.status
})
]
}),
navigationAction: /*#__PURE__*/ jsxRuntime.jsx(strapiAdmin.BackButton, {
fallback: ".."
}),
primaryAction: !release$1.releasedAt && /*#__PURE__*/ jsxRuntime.jsxs(designSystem.Flex, {
gap: 2,
children: [
/*#__PURE__*/ jsxRuntime.jsxs(SimpleMenuButton, {
label: /*#__PURE__*/ jsxRuntime.jsx(icons.More, {}),
variant: "tertiary",
endIcon: null,
paddingLeft: "7px",
paddingRight: "7px",
"aria-label": formatMessage({
id: 'content-releases.header.actions.open-release-actions',
defaultMessage: 'Release edit and delete menu'
}),
popoverPlacement: "bottom-end",
children: [
/*#__PURE__*/ jsxRuntime.jsx(StyledMenuItem, {
disabled: !canUpdate,
onSelect: toggleEditReleaseModal,
children: /*#__PURE__*/ jsxRuntime.jsxs(designSystem.Flex, {
alignItems: "center",
gap: 2,
hasRadius: true,
width: "100%",
children: [
/*#__PURE__*/ jsxRuntime.jsx(PencilIcon, {}),
/*#__PURE__*/ jsxRuntime.jsx(designSystem.Typography, {
ellipsis: true,
children: formatMessage({
id: 'content-releases.header.actions.edit',
defaultMessage: 'Edit'
})
})
]
})
}),
/*#__PURE__*/ jsxRuntime.jsx(StyledMenuItem, {
disabled: !canDelete,
onSelect: toggleWarningSubmit,
$variant: "danger",
children: /*#__PURE__*/ jsxRuntime.jsxs(designSystem.Flex, {
alignItems: "center",
gap: 2,
hasRadius: true,
width: "100%",
children: [
/*#__PURE__*/ jsxRuntime.jsx(TrashIcon, {}),
/*#__PURE__*/ jsxRuntime.jsx(designSystem.Typography, {
ellipsis: true,
textColor: "danger600",
children: formatMessage({
id: 'content-releases.header.actions.delete',
defaultMessage: 'Delete'
})
})
]
})
}),
/*#__PURE__*/ jsxRuntime.jsxs(ReleaseInfoWrapper, {
direction: "column",
justifyContent: "center",
alignItems: "flex-start",
gap: 1,
padding: 4,
children: [
/*#__PURE__*/ jsxRuntime.jsx(designSystem.Typography, {
variant: "pi",
fontWeight: "bold",
children: formatMessage({
id: 'content-releases.header.actions.created',
defaultMessage: 'Created'
})
}),
/*#__PURE__*/ jsxRuntime.jsxs(designSystem.Typography, {
variant: "pi",
color: "neutral300",
children: [
/*#__PURE__*/ jsxRuntime.jsx(RelativeTime.RelativeTime, {
timestamp: new Date(release$1.createdAt)
}),
formatMessage({
id: 'content-releases.header.actions.created.description',
defaultMessage: '{hasCreatedByUser, select, true { by {createdBy}} other { by deleted user}}'
}, {
createdBy: getCreatedByUser(),
hasCreatedByUser
})
]
})
]
})
]
}),
/*#__PURE__*/ jsxRuntime.jsx(designSystem.Button, {
size: "S",
variant: "tertiary",
onClick: handleRefresh,
children: formatMessage({
id: 'content-releases.header.actions.refresh',
defaultMessage: 'Refresh'
})
}),
canPublish ? /*#__PURE__*/ jsxRuntime.jsx(designSystem.Button, {
size: "S",
variant: "default",
onClick: handlePublishRelease(release$1.id.toString()),
loading: isPublishing,
disabled: release$1.actions.meta.count === 0,
children: formatMessage({
id: 'content-releases.header.actions.publish',
defaultMessage: 'Publish'
})
}) : null
]
})
}),
children
]
});
};
const SimpleMenuButton = styledComponents.styled(designSystem.SimpleMenu)`
& > span {
display: flex;
}
`;
/* -------------------------------------------------------------------------------------------------
* ReleaseDetailsBody
* -----------------------------------------------------------------------------------------------*/ const GROUP_BY_OPTIONS = [
'contentType',
'locale',
'action'
];
const GROUP_BY_OPTIONS_NO_LOCALE = [
'contentType',
'action'
];
const getGroupByOptionLabel = (value)=>{
if (value === 'locale') {
return {
id: 'content-releases.pages.ReleaseDetails.groupBy.option.locales',
defaultMessage: 'Locales'
};
}
if (value === 'action') {
return {
id: 'content-releases.pages.ReleaseDetails.groupBy.option.actions',
defaultMessage: 'Actions'
};
}
return {
id: 'content-releases.pages.ReleaseDetails.groupBy.option.content-type',
defaultMessage: 'Content-Types'
};
};
const ReleaseDetailsBody = ({ releaseId })=>{
const { formatMessage } = reactIntl.useIntl();
const [{ query }, setQuery] = strapiAdmin.useQueryParams();
const { toggleNotification } = strapiAdmin.useNotification();
const { formatAPIError } = strapiAdmin.useAPIErrorHandler();
const { data: releaseData, isLoading: isReleaseLoading, error: releaseError } = release.useGetReleaseQuery({
id: releaseId
});
const { allowedActions: { canUpdate } } = strapiAdmin.useRBAC(constants.PERMISSIONS);
const runHookWaterfall = strapiAdmin.useStrapiApp('ReleaseDetailsPage', (state)=>state.runHookWaterfall);
// TODO: Migrated displayedHeader to v5
const { displayedHeaders, hasI18nEnabled } = runHookWaterfall('ContentReleases/pages/ReleaseDetails/add-locale-in-releases', {
displayedHeaders: [
{
label: {
id: 'content-releases.page.ReleaseDetails.table.header.label.name',
defaultMessage: 'name'
},
name: 'name'
}
],
hasI18nEnabled: false
});
const release$1 = releaseData?.data;
const selectedGroupBy = query?.groupBy || 'contentType';
const { isLoading, isFetching, isError, data, error: releaseActionsError } = release.useGetReleaseActionsQuery({
...query,
releaseId
});
const [updateReleaseAction] = release.useUpdateReleaseActionMutation();
const handleChangeType = async (e, actionId, actionPath)=>{
const response = await updateReleaseAction({
params: {
releaseId,
actionId
},
body: {
type: e.target.value
},
query,
actionPath
});
if ('error' in response) {
if (strapiAdmin.isFetchError(response.error)) {
// When the response returns an object with 'error', handle fetch error
toggleNotification({
type: 'danger',
message: formatAPIError(response.error)
});
} else {
// Otherwise, the response returns an object with 'error', handle a generic error
toggleNotification({
type: 'danger',
message: formatMessage({
id: 'notification.error',
defaultMessage: 'An error occurred'
})
});
}
}
};
if (isLoading || isReleaseLoading) {
return /*#__PURE__*/ jsxRuntime.jsx(strapiAdmin.Page.Loading, {});
}
const releaseActions = data?.data;
const releaseMeta = data?.meta;
const contentTypes = releaseMeta?.contentTypes || {};
releaseMeta?.components || {};
if (api.isBaseQueryError(releaseError) || !release$1) {
const errorsArray = [];
if (releaseError && 'code' in releaseError) {
errorsArray.push({
code: releaseError.code
});
}
if (releaseActionsError && 'code' in releaseActionsError) {
errorsArray.push({
code: releaseActionsError.code
});
}
return /*#__PURE__*/ jsxRuntime.jsx(reactRouterDom.Navigate, {
to: "..",
state: {
errors: errorsArray
}
});
}
if (isError || !releaseActions) {
return /*#__PURE__*/ jsxRuntime.jsx(strapiAdmin.Page.Error, {});
}
if (Object.keys(releaseActions).length === 0) {
return /*#__PURE__*/ jsxRuntime.jsx(strapiAdmin.Layouts.Content, {
children: /*#__PURE__*/ jsxRuntime.jsx(designSystem.EmptyStateLayout, {
action: /*#__PURE__*/ jsxRuntime.jsx(designSystem.LinkButton, {
tag: reactRouterDom.Link,
to: {
pathname: '/content-manager'
},
style: {
textDecoration: 'none'
},
variant: "secondary",
children: formatMessage({
id: 'content-releases.page.Details.button.openContentManager',
defaultMessage: 'Open the Content Manager'
})
}),
icon: /*#__PURE__*/ jsxRuntime.jsx(symbols.EmptyDocuments, {
width: "16rem"
}),
content: formatMessage({
id: 'content-releases.pages.Details.tab.emptyEntries',
defaultMessage: 'This release is empty. Open the Content Manager, select an entry and add it to the release.'
})
})
});
}
const groupByLabel = formatMessage({
id: 'content-releases.pages.ReleaseDetails.groupBy.aria-label',
defaultMessage: 'Group by'
});
const headers = [
...displayedHeaders,
{
label: {
id: 'content-releases.page.ReleaseDetails.table.header.label.content-type',
defaultMessage: 'content-type'
},
name: 'content-type'
},
{
label: {
id: 'content-releases.page.ReleaseDetails.table.header.label.action',
defaultMessage: 'action'
},
name: 'action'
},
...!release$1.releasedAt ? [
{
label: {
id: 'content-releases.page.ReleaseDetails.table.header.label.status',
defaultMessage: 'status'
},
name: 'status'
}
] : []
];
const options = hasI18nEnabled ? GROUP_BY_OPTIONS : GROUP_BY_OPTIONS_NO_LOCALE;
return /*#__PURE__*/ jsxRuntime.jsx(strapiAdmin.Layouts.Content, {
children: /*#__PURE__*/ jsxRuntime.jsxs(designSystem.Flex, {
gap: 8,
direction: "column",
alignItems: "stretch",
children: [
/*#__PURE__*/ jsxRuntime.jsx(designSystem.Flex, {
children: /*#__PURE__*/ jsxRuntime.jsx(designSystem.SingleSelect, {
placeholder: groupByLabel,
"aria-label": groupByLabel,
customizeContent: (value)=>formatMessage({
id: `content-releases.pages.ReleaseDetails.groupBy.label`,
defaultMessage: `Group by {groupBy}`
}, {
groupBy: value
}),
value: formatMessage(getGroupByOptionLabel(selectedGroupBy)),
onChange: (value)=>setQuery({
groupBy: value
}),
children: options.map((option)=>/*#__PURE__*/ jsxRuntime.jsx(designSystem.SingleSelectOption, {
value: option,
children: formatMessage(getGroupByOptionLabel(option))
}, option))
})
}),
Object.keys(releaseActions).map((key)=>/*#__PURE__*/ jsxRuntime.jsxs(designSystem.Flex, {
gap: 4,
direction: "column",
alignItems: "stretch",
children: [
/*#__PURE__*/ jsxRuntime.jsx(designSystem.Flex, {
role: "separator",
"aria-label": key,
children: /*#__PURE__*/ jsxRuntime.jsx(designSystem.Badge, {
children: key
})
}),
/*#__PURE__*/ jsxRuntime.jsx(strapiAdmin.Table.Root, {
rows: releaseActions[key].map((item)=>({
...item,
id: Number(item.entry.id)
})),
headers: headers,
isLoading: isLoading || isFetching,
children: /*#__PURE__*/ jsxRuntime.jsxs(strapiAdmin.Table.Content, {
children: [
/*#__PURE__*/ jsxRuntime.jsx(strapiAdmin.Table.Head, {
children: headers.map(({ label, name })=>/*#__PURE__*/ jsxRuntime.jsx(strapiAdmin.Table.HeaderCell, {
label: formatMessage(label),
name: name
}, name))
}),
/*#__PURE__*/ jsxRuntime.jsx(strapiAdmin.Table.Loading, {}),
/*#__PURE__*/ jsxRuntime.jsx(strapiAdmin.Table.Body, {
children: releaseActions[key].map(({ id, contentType, locale, type, entry, status }, actionIndex)=>/*#__PURE__*/ jsxRuntime.jsxs(designSystem.Tr, {
children: [
/*#__PURE__*/ jsxRuntime.jsx(designSystem.Td, {
width: "25%",
maxWidth: "200px",
children: /*#__PURE__*/ jsxRuntime.jsx(designSystem.Typography, {
ellipsis: true,
children: `${contentType.mainFieldValue || entry.id}`
})
}),
hasI18nEnabled && /*#__PURE__*/ jsxRuntime.jsx(designSystem.Td, {
width: "10%",
children: /*#__PURE__*/ jsxRuntime.jsx(designSystem.Typography, {
children: `${locale?.name ? locale.name : '-'}`
})
}),
/*#__PURE__*/ jsxRuntime.jsx(designSystem.Td, {
width: "10%",
children: /*#__PURE__*/ jsxRuntime.jsx(designSystem.Typography, {
children: contentType.displayName || ''
})
}),
/*#__PURE__*/ jsxRuntime.jsx(designSystem.Td, {
width: "20%",
children: release$1.releasedAt ? /*#__PURE__*/ jsxRuntime.jsx(designSystem.Typography, {
children: formatMessage({
id: 'content-releases.page.ReleaseDetails.table.action-published',
defaultMessage: 'This entry was <b>{isPublish, select, true {published} other {unpublished}}</b>.'
}, {
isPublish: type === 'publish',
b: (children)=>/*#__PURE__*/ jsxRuntime.jsx(designSystem.Typography, {
fontWeight: "bold",
children: children
})
})
}) : /*#__PURE__*/ jsxRuntime.jsx(ReleaseActionOptions.ReleaseActionOptions, {
selected: type,
handleChange: (e)=>handleChangeType(e, id, [
key,
actionIndex
]),
name: `release-action-${id}-type`,
disabled: !canUpdate
})
}),
!release$1.releasedAt && /*#__PURE__*/ jsxRuntime.jsxs(jsxRuntime.Fragment, {
children: [
/*#__PURE__*/ jsxRuntime.jsx(designSystem.Td, {
width: "20%",
minWidth: "200px",
children: /*#__PURE__*/ jsxRuntime.jsx(EntryValidationPopover.EntryValidationPopover, {
action: type,
schema: contentTypes?.[contentType.uid],
entry: entry,
status: status
})
}),
/*#__PURE__*/ jsxRuntime.jsx(designSystem.Td, {
children: /*#__PURE__*/ jsxRuntime.jsx(designSystem.Flex, {
justifyContent: "flex-end",
children: /*#__PURE__*/ jsxRuntime.jsxs(ReleaseActionMenu.ReleaseActionMenu.Root, {
children: [
/*#__PURE__*/ jsxRuntime.jsx(ReleaseActionMenu.ReleaseActionMenu.ReleaseActionEntryLinkItem, {
contentTypeUid: contentType.uid,
documentId: entry.documentId,
locale: locale?.code
}),
/*#__PURE__*/ jsxRuntime.jsx(ReleaseActionMenu.ReleaseActionMenu.DeleteReleaseActionItem, {
releaseId: release$1.id,
actionId: id
})
]
})
})
})
]
})
]
}, id))
})
]
})
})
]
}, `releases-group-${key}`)),
/*#__PURE__*/ jsxRuntime.jsxs(strapiAdmin.Pagination.Root, {
...releaseMeta?.pagination,
defaultPageSize: releaseMeta?.pagination?.pageSize,
children: [
/*#__PURE__*/ jsxRuntime.jsx(strapiAdmin.Pagination.PageSize, {}),
/*#__PURE__*/ jsxRuntime.jsx(strapiAdmin.Pagination.Links, {})
]
})
]
})
});
};
/* -------------------------------------------------------------------------------------------------
* ReleaseDetailsPage
* -----------------------------------------------------------------------------------------------*/ const ReleaseDetailsPage = ()=>{
const { formatMessage } = reactIntl.useIntl();
const { releaseId } = reactRouterDom.useParams();
const { toggleNotification } = strapiAdmin.useNotification();
const { formatAPIError } = strapiAdmin.useAPIErrorHandler();
const navigate = reactRouterDom.useNavigate();
const [releaseModalShown, setReleaseModalShown] = React__namespace.useState(false);
const [showWarningSubmit, setWarningSubmit] = React__namespace.useState(false);
const { isLoading: isLoadingDetails, data, isSuccess: isSuccessDetails } = release.useGetReleaseQuery({
id: releaseId
}, {
skip: !releaseId
});
const { data: dataTimezone, isLoading: isLoadingTimezone } = release.useGetReleaseSettingsQuery();
const [updateRelease, { isLoading: isSubmittingForm }] = release.useUpdateReleaseMutation();
const [deleteRelease] = release.useDeleteReleaseMutation();
const toggleEditReleaseModal = ()=>{
setReleaseModalShown((prev)=>!prev);
};
const getTimezoneValue = ()=>{
if (releaseData?.timezone) {
return releaseData.timezone;
} else {
if (dataTimezone?.data.defaultTimezone) {
return dataTimezone.data.defaultTimezone;
}
return null;
}
};
const toggleWarningSubmit = ()=>setWarningSubmit((prevState)=>!prevState);
if (isLoadingDetails || isLoadingTimezone) {
return /*#__PURE__*/ jsxRuntime.jsx(ReleaseDetailsLayout, {
toggleEditReleaseModal: toggleEditReleaseModal,
toggleWarningSubmit: toggleWarningSubmit,
children: /*#__PURE__*/ jsxRuntime.jsx(strapiAdmin.Page.Loading, {})
});
}
if (!releaseId) {
return /*#__PURE__*/ jsxRuntime.jsx(reactRouterDom.Navigate, {
to: ".."
});
}
const releaseData = isSuccessDetails && data?.data || null;
const title = releaseData?.name || '';
const timezone = getTimezoneValue();
const scheduledAt = releaseData?.scheduledAt && timezone ? dateFnsTz.utcToZonedTime(releaseData.scheduledAt, timezone) : null;
// Just get the date and time to display without considering updated timezone time
const date = scheduledAt ? format(scheduledAt, 'yyyy-MM-dd') : undefined;
const time = scheduledAt ? format(scheduledAt, 'HH:mm') : '';
const handleEditRelease = async (values)=>{
const response = await updateRelease({
id: releaseId,
name: values.name,
scheduledAt: values.scheduledAt,
timezone: values.timezone
});
if ('data' in response) {
// When the response returns an object with 'data', handle success
toggleNotification({
type: 'success',
message: formatMessage({
id: 'content-releases.modal.release-updated-notification-success',
defaultMessage: 'Release updated.'
})
});
toggleEditReleaseModal();
} else if (strapiAdmin.isFetchError(response.error)) {
// When the response returns an object with 'error', handle fetch error
toggleNotification({
type: 'danger',
message: formatAPIError(response.error)
});
} else {
// Otherwise, the response returns an object with 'error', handle a generic error
toggleNotification({
type: 'danger',
message: formatMessage({
id: 'notification.error',
defaultMessage: 'An error occurred'
})
});
}
};
const handleDeleteRelease = async ()=>{
const response = await deleteRelease({
id: releaseId
});
if ('data' in response) {
navigate('..');
} else if (strapiAdmin.isFetchError(response.error)) {
// When the response returns an object with 'error', handle fetch error
toggleNotification({
type: 'danger',
message: formatAPIError(response.error)
});
} else {
// Otherwise, the response returns an object with 'error', handle a generic error
toggleNotification({
type: 'danger',
message: formatMessage({
id: 'notification.error',
defaultMessage: 'An error occurred'
})
});
}
};
return /*#__PURE__*/ jsxRuntime.jsxs(ReleaseDetailsLayout, {
toggleEditReleaseModal: toggleEditReleaseModal,
toggleWarningSubmit: toggleWarningSubmit,
children: [
/*#__PURE__*/ jsxRuntime.jsx(ReleaseDetailsBody, {
releaseId: releaseId
}),
/*#__PURE__*/ jsxRuntime.jsx(ReleaseModal.ReleaseModal, {
open: releaseModalShown,
handleClose: toggleEditReleaseModal,
handleSubmit: handleEditRelease,
isLoading: isLoadingDetails || isSubmittingForm,
initialValues: {
name: title || '',
scheduledAt,
date,
time,
isScheduled: Boolean(scheduledAt),
timezone
}
}),
/*#__PURE__*/ jsxRuntime.jsx(designSystem.Dialog.Root, {
open: showWarningSubmit,
onOpenChange: toggleWarningSubmit,
children: /*#__PURE__*/ jsxRuntime.jsx(strapiAdmin.ConfirmDialog, {
onConfirm: handleDeleteRelease,
children: formatMessage({
id: 'content-releases.dialog.confirmation-message',
defaultMessage: 'Are you sure you want to delete this release?'
})
})
})
]
});
};
exports.ReleaseDetailsPage = ReleaseDetailsPage;
//# sourceMappingURL=ReleaseDetailsPage.js.map

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,800 @@
import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
import * as React from 'react';
import { useNotification, useAPIErrorHandler, Page, ConfirmDialog, useRBAC, useTracking, Layouts, BackButton, useQueryParams, useStrapiApp, Table, Pagination, isFetchError } from '@strapi/admin/strapi-admin';
import { Flex, MenuItem, SimpleMenu, Dialog, Main, Typography, Badge, Button, EmptyStateLayout, LinkButton, SingleSelect, SingleSelectOption, Tr, Td } from '@strapi/design-system';
import { Pencil, Trash, More } from '@strapi/icons';
import { EmptyDocuments } from '@strapi/icons/symbols';
import format from 'date-fns/format';
import { utcToZonedTime } from 'date-fns-tz';
import { useIntl } from 'react-intl';
import { useParams, useNavigate, Navigate, Link } from 'react-router-dom';
import { styled } from 'styled-components';
import { EntryValidationPopover } from '../components/EntryValidationPopover.mjs';
import { RelativeTime } from '../components/RelativeTime.mjs';
import { ReleaseActionMenu } from '../components/ReleaseActionMenu.mjs';
import { ReleaseActionOptions } from '../components/ReleaseActionOptions.mjs';
import { ReleaseModal } from '../components/ReleaseModal.mjs';
import { PERMISSIONS } from '../constants.mjs';
import { useGetReleaseQuery, useGetReleaseSettingsQuery, useUpdateReleaseMutation, useDeleteReleaseMutation, usePublishReleaseMutation, useGetReleaseActionsQuery, useUpdateReleaseActionMutation, releaseApi } from '../services/release.mjs';
import { useTypedDispatch } from '../store/hooks.mjs';
import { isBaseQueryError } from '../utils/api.mjs';
import { getTimezoneOffset } from '../utils/time.mjs';
import { getBadgeProps } from './ReleasesPage.mjs';
/* -------------------------------------------------------------------------------------------------
* ReleaseDetailsLayout
* -----------------------------------------------------------------------------------------------*/ const ReleaseInfoWrapper = styled(Flex)`
align-self: stretch;
border-bottom-right-radius: ${({ theme })=>theme.borderRadius};
border-bottom-left-radius: ${({ theme })=>theme.borderRadius};
border-top: 1px solid ${({ theme })=>theme.colors.neutral150};
`;
const StyledMenuItem = styled(MenuItem)`
svg path {
fill: ${({ theme, disabled })=>disabled && theme.colors.neutral500};
}
span {
color: ${({ theme, disabled })=>disabled && theme.colors.neutral500};
}
&:hover {
background: ${({ theme, $variant = 'neutral' })=>theme.colors[`${$variant}100`]};
}
`;
const PencilIcon = styled(Pencil)`
width: ${({ theme })=>theme.spaces[4]};
height: ${({ theme })=>theme.spaces[4]};
path {
fill: ${({ theme })=>theme.colors.neutral600};
}
`;
const TrashIcon = styled(Trash)`
width: ${({ theme })=>theme.spaces[4]};
height: ${({ theme })=>theme.spaces[4]};
path {
fill: ${({ theme })=>theme.colors.danger600};
}
`;
const ReleaseDetailsLayout = ({ toggleEditReleaseModal, toggleWarningSubmit, children })=>{
const { formatMessage, formatDate, formatTime } = useIntl();
const { releaseId } = useParams();
const { data, isLoading: isLoadingDetails, error } = useGetReleaseQuery({
id: releaseId
}, {
skip: !releaseId
});
const [publishRelease, { isLoading: isPublishing }] = usePublishReleaseMutation();
const { toggleNotification } = useNotification();
const { formatAPIError } = useAPIErrorHandler();
const { allowedActions } = useRBAC(PERMISSIONS);
const { canUpdate, canDelete, canPublish } = allowedActions;
const dispatch = useTypedDispatch();
const { trackUsage } = useTracking();
const release = data?.data;
const handlePublishRelease = (id)=>async ()=>{
const response = await publishRelease({
id
});
if ('data' in response) {
// When the response returns an object with 'data', handle success
toggleNotification({
type: 'success',
message: formatMessage({
id: 'content-releases.pages.ReleaseDetails.publish-notification-success',
defaultMessage: 'Release was published successfully.'
})
});
const { totalEntries, totalPublishedEntries, totalUnpublishedEntries } = response.data.meta;
trackUsage('didPublishRelease', {
totalEntries,
totalPublishedEntries,
totalUnpublishedEntries
});
} else if (isFetchError(response.error)) {
// When the response returns an object with 'error', handle fetch error
toggleNotification({
type: 'danger',
message: formatAPIError(response.error)
});
} else {
// Otherwise, the response returns an object with 'error', handle a generic error
toggleNotification({
type: 'danger',
message: formatMessage({
id: 'notification.error',
defaultMessage: 'An error occurred'
})
});
}
};
const handleRefresh = ()=>{
dispatch(releaseApi.util.invalidateTags([
{
type: 'ReleaseAction',
id: 'LIST'
},
{
type: 'Release',
id: releaseId
}
]));
};
const getCreatedByUser = ()=>{
if (!release?.createdBy) {
return null;
}
// Favor the username
if (release.createdBy.username) {
return release.createdBy.username;
}
// Firstname may not exist if created with SSO
if (release.createdBy.firstname) {
return `${release.createdBy.firstname} ${release.createdBy.lastname || ''}`.trim();
}
// All users must have at least an email
return release.createdBy.email;
};
if (isLoadingDetails) {
return /*#__PURE__*/ jsx(Page.Loading, {});
}
if (isBaseQueryError(error) && 'code' in error || !release) {
return /*#__PURE__*/ jsx(Navigate, {
to: "..",
state: {
errors: [
{
// @ts-expect-error TODO: fix this weird error flow
code: error?.code
}
]
}
});
}
const totalEntries = release.actions.meta.count || 0;
const hasCreatedByUser = Boolean(getCreatedByUser());
const isScheduled = release.scheduledAt && release.timezone;
const numberOfEntriesText = formatMessage({
id: 'content-releases.pages.Details.header-subtitle',
defaultMessage: '{number, plural, =0 {No entries} one {# entry} other {# entries}}'
}, {
number: totalEntries
});
const scheduledText = isScheduled ? formatMessage({
id: 'content-releases.pages.ReleaseDetails.header-subtitle.scheduled',
defaultMessage: 'Scheduled for {date} at {time} ({offset})'
}, {
date: formatDate(new Date(release.scheduledAt), {
weekday: 'long',
day: 'numeric',
month: 'long',
year: 'numeric',
timeZone: release.timezone
}),
time: formatTime(new Date(release.scheduledAt), {
timeZone: release.timezone,
hourCycle: 'h23'
}),
offset: getTimezoneOffset(release.timezone, new Date(release.scheduledAt))
}) : '';
return /*#__PURE__*/ jsxs(Main, {
"aria-busy": isLoadingDetails,
children: [
/*#__PURE__*/ jsx(Layouts.Header, {
title: release.name,
subtitle: /*#__PURE__*/ jsxs(Flex, {
gap: 2,
lineHeight: 6,
children: [
/*#__PURE__*/ jsx(Typography, {
textColor: "neutral600",
variant: "epsilon",
children: numberOfEntriesText + (isScheduled ? ` - ${scheduledText}` : '')
}),
/*#__PURE__*/ jsx(Badge, {
...getBadgeProps(release.status),
children: release.status
})
]
}),
navigationAction: /*#__PURE__*/ jsx(BackButton, {
fallback: ".."
}),
primaryAction: !release.releasedAt && /*#__PURE__*/ jsxs(Flex, {
gap: 2,
children: [
/*#__PURE__*/ jsxs(SimpleMenuButton, {
label: /*#__PURE__*/ jsx(More, {}),
variant: "tertiary",
endIcon: null,
paddingLeft: "7px",
paddingRight: "7px",
"aria-label": formatMessage({
id: 'content-releases.header.actions.open-release-actions',
defaultMessage: 'Release edit and delete menu'
}),
popoverPlacement: "bottom-end",
children: [
/*#__PURE__*/ jsx(StyledMenuItem, {
disabled: !canUpdate,
onSelect: toggleEditReleaseModal,
children: /*#__PURE__*/ jsxs(Flex, {
alignItems: "center",
gap: 2,
hasRadius: true,
width: "100%",
children: [
/*#__PURE__*/ jsx(PencilIcon, {}),
/*#__PURE__*/ jsx(Typography, {
ellipsis: true,
children: formatMessage({
id: 'content-releases.header.actions.edit',
defaultMessage: 'Edit'
})
})
]
})
}),
/*#__PURE__*/ jsx(StyledMenuItem, {
disabled: !canDelete,
onSelect: toggleWarningSubmit,
$variant: "danger",
children: /*#__PURE__*/ jsxs(Flex, {
alignItems: "center",
gap: 2,
hasRadius: true,
width: "100%",
children: [
/*#__PURE__*/ jsx(TrashIcon, {}),
/*#__PURE__*/ jsx(Typography, {
ellipsis: true,
textColor: "danger600",
children: formatMessage({
id: 'content-releases.header.actions.delete',
defaultMessage: 'Delete'
})
})
]
})
}),
/*#__PURE__*/ jsxs(ReleaseInfoWrapper, {
direction: "column",
justifyContent: "center",
alignItems: "flex-start",
gap: 1,
padding: 4,
children: [
/*#__PURE__*/ jsx(Typography, {
variant: "pi",
fontWeight: "bold",
children: formatMessage({
id: 'content-releases.header.actions.created',
defaultMessage: 'Created'
})
}),
/*#__PURE__*/ jsxs(Typography, {
variant: "pi",
color: "neutral300",
children: [
/*#__PURE__*/ jsx(RelativeTime, {
timestamp: new Date(release.createdAt)
}),
formatMessage({
id: 'content-releases.header.actions.created.description',
defaultMessage: '{hasCreatedByUser, select, true { by {createdBy}} other { by deleted user}}'
}, {
createdBy: getCreatedByUser(),
hasCreatedByUser
})
]
})
]
})
]
}),
/*#__PURE__*/ jsx(Button, {
size: "S",
variant: "tertiary",
onClick: handleRefresh,
children: formatMessage({
id: 'content-releases.header.actions.refresh',
defaultMessage: 'Refresh'
})
}),
canPublish ? /*#__PURE__*/ jsx(Button, {
size: "S",
variant: "default",
onClick: handlePublishRelease(release.id.toString()),
loading: isPublishing,
disabled: release.actions.meta.count === 0,
children: formatMessage({
id: 'content-releases.header.actions.publish',
defaultMessage: 'Publish'
})
}) : null
]
})
}),
children
]
});
};
const SimpleMenuButton = styled(SimpleMenu)`
& > span {
display: flex;
}
`;
/* -------------------------------------------------------------------------------------------------
* ReleaseDetailsBody
* -----------------------------------------------------------------------------------------------*/ const GROUP_BY_OPTIONS = [
'contentType',
'locale',
'action'
];
const GROUP_BY_OPTIONS_NO_LOCALE = [
'contentType',
'action'
];
const getGroupByOptionLabel = (value)=>{
if (value === 'locale') {
return {
id: 'content-releases.pages.ReleaseDetails.groupBy.option.locales',
defaultMessage: 'Locales'
};
}
if (value === 'action') {
return {
id: 'content-releases.pages.ReleaseDetails.groupBy.option.actions',
defaultMessage: 'Actions'
};
}
return {
id: 'content-releases.pages.ReleaseDetails.groupBy.option.content-type',
defaultMessage: 'Content-Types'
};
};
const ReleaseDetailsBody = ({ releaseId })=>{
const { formatMessage } = useIntl();
const [{ query }, setQuery] = useQueryParams();
const { toggleNotification } = useNotification();
const { formatAPIError } = useAPIErrorHandler();
const { data: releaseData, isLoading: isReleaseLoading, error: releaseError } = useGetReleaseQuery({
id: releaseId
});
const { allowedActions: { canUpdate } } = useRBAC(PERMISSIONS);
const runHookWaterfall = useStrapiApp('ReleaseDetailsPage', (state)=>state.runHookWaterfall);
// TODO: Migrated displayedHeader to v5
const { displayedHeaders, hasI18nEnabled } = runHookWaterfall('ContentReleases/pages/ReleaseDetails/add-locale-in-releases', {
displayedHeaders: [
{
label: {
id: 'content-releases.page.ReleaseDetails.table.header.label.name',
defaultMessage: 'name'
},
name: 'name'
}
],
hasI18nEnabled: false
});
const release = releaseData?.data;
const selectedGroupBy = query?.groupBy || 'contentType';
const { isLoading, isFetching, isError, data, error: releaseActionsError } = useGetReleaseActionsQuery({
...query,
releaseId
});
const [updateReleaseAction] = useUpdateReleaseActionMutation();
const handleChangeType = async (e, actionId, actionPath)=>{
const response = await updateReleaseAction({
params: {
releaseId,
actionId
},
body: {
type: e.target.value
},
query,
actionPath
});
if ('error' in response) {
if (isFetchError(response.error)) {
// When the response returns an object with 'error', handle fetch error
toggleNotification({
type: 'danger',
message: formatAPIError(response.error)
});
} else {
// Otherwise, the response returns an object with 'error', handle a generic error
toggleNotification({
type: 'danger',
message: formatMessage({
id: 'notification.error',
defaultMessage: 'An error occurred'
})
});
}
}
};
if (isLoading || isReleaseLoading) {
return /*#__PURE__*/ jsx(Page.Loading, {});
}
const releaseActions = data?.data;
const releaseMeta = data?.meta;
const contentTypes = releaseMeta?.contentTypes || {};
releaseMeta?.components || {};
if (isBaseQueryError(releaseError) || !release) {
const errorsArray = [];
if (releaseError && 'code' in releaseError) {
errorsArray.push({
code: releaseError.code
});
}
if (releaseActionsError && 'code' in releaseActionsError) {
errorsArray.push({
code: releaseActionsError.code
});
}
return /*#__PURE__*/ jsx(Navigate, {
to: "..",
state: {
errors: errorsArray
}
});
}
if (isError || !releaseActions) {
return /*#__PURE__*/ jsx(Page.Error, {});
}
if (Object.keys(releaseActions).length === 0) {
return /*#__PURE__*/ jsx(Layouts.Content, {
children: /*#__PURE__*/ jsx(EmptyStateLayout, {
action: /*#__PURE__*/ jsx(LinkButton, {
tag: Link,
to: {
pathname: '/content-manager'
},
style: {
textDecoration: 'none'
},
variant: "secondary",
children: formatMessage({
id: 'content-releases.page.Details.button.openContentManager',
defaultMessage: 'Open the Content Manager'
})
}),
icon: /*#__PURE__*/ jsx(EmptyDocuments, {
width: "16rem"
}),
content: formatMessage({
id: 'content-releases.pages.Details.tab.emptyEntries',
defaultMessage: 'This release is empty. Open the Content Manager, select an entry and add it to the release.'
})
})
});
}
const groupByLabel = formatMessage({
id: 'content-releases.pages.ReleaseDetails.groupBy.aria-label',
defaultMessage: 'Group by'
});
const headers = [
...displayedHeaders,
{
label: {
id: 'content-releases.page.ReleaseDetails.table.header.label.content-type',
defaultMessage: 'content-type'
},
name: 'content-type'
},
{
label: {
id: 'content-releases.page.ReleaseDetails.table.header.label.action',
defaultMessage: 'action'
},
name: 'action'
},
...!release.releasedAt ? [
{
label: {
id: 'content-releases.page.ReleaseDetails.table.header.label.status',
defaultMessage: 'status'
},
name: 'status'
}
] : []
];
const options = hasI18nEnabled ? GROUP_BY_OPTIONS : GROUP_BY_OPTIONS_NO_LOCALE;
return /*#__PURE__*/ jsx(Layouts.Content, {
children: /*#__PURE__*/ jsxs(Flex, {
gap: 8,
direction: "column",
alignItems: "stretch",
children: [
/*#__PURE__*/ jsx(Flex, {
children: /*#__PURE__*/ jsx(SingleSelect, {
placeholder: groupByLabel,
"aria-label": groupByLabel,
customizeContent: (value)=>formatMessage({
id: `content-releases.pages.ReleaseDetails.groupBy.label`,
defaultMessage: `Group by {groupBy}`
}, {
groupBy: value
}),
value: formatMessage(getGroupByOptionLabel(selectedGroupBy)),
onChange: (value)=>setQuery({
groupBy: value
}),
children: options.map((option)=>/*#__PURE__*/ jsx(SingleSelectOption, {
value: option,
children: formatMessage(getGroupByOptionLabel(option))
}, option))
})
}),
Object.keys(releaseActions).map((key)=>/*#__PURE__*/ jsxs(Flex, {
gap: 4,
direction: "column",
alignItems: "stretch",
children: [
/*#__PURE__*/ jsx(Flex, {
role: "separator",
"aria-label": key,
children: /*#__PURE__*/ jsx(Badge, {
children: key
})
}),
/*#__PURE__*/ jsx(Table.Root, {
rows: releaseActions[key].map((item)=>({
...item,
id: Number(item.entry.id)
})),
headers: headers,
isLoading: isLoading || isFetching,
children: /*#__PURE__*/ jsxs(Table.Content, {
children: [
/*#__PURE__*/ jsx(Table.Head, {
children: headers.map(({ label, name })=>/*#__PURE__*/ jsx(Table.HeaderCell, {
label: formatMessage(label),
name: name
}, name))
}),
/*#__PURE__*/ jsx(Table.Loading, {}),
/*#__PURE__*/ jsx(Table.Body, {
children: releaseActions[key].map(({ id, contentType, locale, type, entry, status }, actionIndex)=>/*#__PURE__*/ jsxs(Tr, {
children: [
/*#__PURE__*/ jsx(Td, {
width: "25%",
maxWidth: "200px",
children: /*#__PURE__*/ jsx(Typography, {
ellipsis: true,
children: `${contentType.mainFieldValue || entry.id}`
})
}),
hasI18nEnabled && /*#__PURE__*/ jsx(Td, {
width: "10%",
children: /*#__PURE__*/ jsx(Typography, {
children: `${locale?.name ? locale.name : '-'}`
})
}),
/*#__PURE__*/ jsx(Td, {
width: "10%",
children: /*#__PURE__*/ jsx(Typography, {
children: contentType.displayName || ''
})
}),
/*#__PURE__*/ jsx(Td, {
width: "20%",
children: release.releasedAt ? /*#__PURE__*/ jsx(Typography, {
children: formatMessage({
id: 'content-releases.page.ReleaseDetails.table.action-published',
defaultMessage: 'This entry was <b>{isPublish, select, true {published} other {unpublished}}</b>.'
}, {
isPublish: type === 'publish',
b: (children)=>/*#__PURE__*/ jsx(Typography, {
fontWeight: "bold",
children: children
})
})
}) : /*#__PURE__*/ jsx(ReleaseActionOptions, {
selected: type,
handleChange: (e)=>handleChangeType(e, id, [
key,
actionIndex
]),
name: `release-action-${id}-type`,
disabled: !canUpdate
})
}),
!release.releasedAt && /*#__PURE__*/ jsxs(Fragment, {
children: [
/*#__PURE__*/ jsx(Td, {
width: "20%",
minWidth: "200px",
children: /*#__PURE__*/ jsx(EntryValidationPopover, {
action: type,
schema: contentTypes?.[contentType.uid],
entry: entry,
status: status
})
}),
/*#__PURE__*/ jsx(Td, {
children: /*#__PURE__*/ jsx(Flex, {
justifyContent: "flex-end",
children: /*#__PURE__*/ jsxs(ReleaseActionMenu.Root, {
children: [
/*#__PURE__*/ jsx(ReleaseActionMenu.ReleaseActionEntryLinkItem, {
contentTypeUid: contentType.uid,
documentId: entry.documentId,
locale: locale?.code
}),
/*#__PURE__*/ jsx(ReleaseActionMenu.DeleteReleaseActionItem, {
releaseId: release.id,
actionId: id
})
]
})
})
})
]
})
]
}, id))
})
]
})
})
]
}, `releases-group-${key}`)),
/*#__PURE__*/ jsxs(Pagination.Root, {
...releaseMeta?.pagination,
defaultPageSize: releaseMeta?.pagination?.pageSize,
children: [
/*#__PURE__*/ jsx(Pagination.PageSize, {}),
/*#__PURE__*/ jsx(Pagination.Links, {})
]
})
]
})
});
};
/* -------------------------------------------------------------------------------------------------
* ReleaseDetailsPage
* -----------------------------------------------------------------------------------------------*/ const ReleaseDetailsPage = ()=>{
const { formatMessage } = useIntl();
const { releaseId } = useParams();
const { toggleNotification } = useNotification();
const { formatAPIError } = useAPIErrorHandler();
const navigate = useNavigate();
const [releaseModalShown, setReleaseModalShown] = React.useState(false);
const [showWarningSubmit, setWarningSubmit] = React.useState(false);
const { isLoading: isLoadingDetails, data, isSuccess: isSuccessDetails } = useGetReleaseQuery({
id: releaseId
}, {
skip: !releaseId
});
const { data: dataTimezone, isLoading: isLoadingTimezone } = useGetReleaseSettingsQuery();
const [updateRelease, { isLoading: isSubmittingForm }] = useUpdateReleaseMutation();
const [deleteRelease] = useDeleteReleaseMutation();
const toggleEditReleaseModal = ()=>{
setReleaseModalShown((prev)=>!prev);
};
const getTimezoneValue = ()=>{
if (releaseData?.timezone) {
return releaseData.timezone;
} else {
if (dataTimezone?.data.defaultTimezone) {
return dataTimezone.data.defaultTimezone;
}
return null;
}
};
const toggleWarningSubmit = ()=>setWarningSubmit((prevState)=>!prevState);
if (isLoadingDetails || isLoadingTimezone) {
return /*#__PURE__*/ jsx(ReleaseDetailsLayout, {
toggleEditReleaseModal: toggleEditReleaseModal,
toggleWarningSubmit: toggleWarningSubmit,
children: /*#__PURE__*/ jsx(Page.Loading, {})
});
}
if (!releaseId) {
return /*#__PURE__*/ jsx(Navigate, {
to: ".."
});
}
const releaseData = isSuccessDetails && data?.data || null;
const title = releaseData?.name || '';
const timezone = getTimezoneValue();
const scheduledAt = releaseData?.scheduledAt && timezone ? utcToZonedTime(releaseData.scheduledAt, timezone) : null;
// Just get the date and time to display without considering updated timezone time
const date = scheduledAt ? format(scheduledAt, 'yyyy-MM-dd') : undefined;
const time = scheduledAt ? format(scheduledAt, 'HH:mm') : '';
const handleEditRelease = async (values)=>{
const response = await updateRelease({
id: releaseId,
name: values.name,
scheduledAt: values.scheduledAt,
timezone: values.timezone
});
if ('data' in response) {
// When the response returns an object with 'data', handle success
toggleNotification({
type: 'success',
message: formatMessage({
id: 'content-releases.modal.release-updated-notification-success',
defaultMessage: 'Release updated.'
})
});
toggleEditReleaseModal();
} else if (isFetchError(response.error)) {
// When the response returns an object with 'error', handle fetch error
toggleNotification({
type: 'danger',
message: formatAPIError(response.error)
});
} else {
// Otherwise, the response returns an object with 'error', handle a generic error
toggleNotification({
type: 'danger',
message: formatMessage({
id: 'notification.error',
defaultMessage: 'An error occurred'
})
});
}
};
const handleDeleteRelease = async ()=>{
const response = await deleteRelease({
id: releaseId
});
if ('data' in response) {
navigate('..');
} else if (isFetchError(response.error)) {
// When the response returns an object with 'error', handle fetch error
toggleNotification({
type: 'danger',
message: formatAPIError(response.error)
});
} else {
// Otherwise, the response returns an object with 'error', handle a generic error
toggleNotification({
type: 'danger',
message: formatMessage({
id: 'notification.error',
defaultMessage: 'An error occurred'
})
});
}
};
return /*#__PURE__*/ jsxs(ReleaseDetailsLayout, {
toggleEditReleaseModal: toggleEditReleaseModal,
toggleWarningSubmit: toggleWarningSubmit,
children: [
/*#__PURE__*/ jsx(ReleaseDetailsBody, {
releaseId: releaseId
}),
/*#__PURE__*/ jsx(ReleaseModal, {
open: releaseModalShown,
handleClose: toggleEditReleaseModal,
handleSubmit: handleEditRelease,
isLoading: isLoadingDetails || isSubmittingForm,
initialValues: {
name: title || '',
scheduledAt,
date,
time,
isScheduled: Boolean(scheduledAt),
timezone
}
}),
/*#__PURE__*/ jsx(Dialog.Root, {
open: showWarningSubmit,
onOpenChange: toggleWarningSubmit,
children: /*#__PURE__*/ jsx(ConfirmDialog, {
onConfirm: handleDeleteRelease,
children: formatMessage({
id: 'content-releases.dialog.confirmation-message',
defaultMessage: 'Are you sure you want to delete this release?'
})
})
})
]
});
};
export { ReleaseDetailsPage };
//# sourceMappingURL=ReleaseDetailsPage.mjs.map

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,397 @@
'use strict';
var jsxRuntime = require('react/jsx-runtime');
var React = require('react');
var strapiAdmin = require('@strapi/admin/strapi-admin');
var ee = require('@strapi/admin/strapi-admin/ee');
var designSystem = require('@strapi/design-system');
var icons = require('@strapi/icons');
var symbols = require('@strapi/icons/symbols');
var dateFns = require('date-fns');
var reactIntl = require('react-intl');
var reactRouterDom = require('react-router-dom');
var styledComponents = require('styled-components');
var RelativeTime$1 = require('../components/RelativeTime.js');
var ReleaseModal = require('../components/ReleaseModal.js');
var constants = require('../constants.js');
var release = require('../services/release.js');
function _interopNamespaceDefault(e) {
var n = Object.create(null);
if (e) {
Object.keys(e).forEach(function (k) {
if (k !== 'default') {
var d = Object.getOwnPropertyDescriptor(e, k);
Object.defineProperty(n, k, d.get ? d : {
enumerable: true,
get: function () { return e[k]; }
});
}
});
}
n.default = e;
return Object.freeze(n);
}
var React__namespace = /*#__PURE__*/_interopNamespaceDefault(React);
const LinkCard = styledComponents.styled(designSystem.Link)`
display: block;
`;
const RelativeTime = styledComponents.styled(RelativeTime$1.RelativeTime)`
display: inline-block;
&::first-letter {
text-transform: uppercase;
}
`;
const getBadgeProps = (status)=>{
let color;
switch(status){
case 'ready':
color = 'success';
break;
case 'blocked':
color = 'warning';
break;
case 'failed':
color = 'danger';
break;
case 'done':
color = 'primary';
break;
case 'empty':
default:
color = 'neutral';
}
return {
textColor: `${color}600`,
backgroundColor: `${color}100`,
borderColor: `${color}200`
};
};
const ReleasesGrid = ({ sectionTitle, releases = [], isError = false })=>{
const { formatMessage } = reactIntl.useIntl();
if (isError) {
return /*#__PURE__*/ jsxRuntime.jsx(strapiAdmin.Page.Error, {});
}
if (releases?.length === 0) {
return /*#__PURE__*/ jsxRuntime.jsx(designSystem.EmptyStateLayout, {
content: formatMessage({
id: 'content-releases.page.Releases.tab.emptyEntries',
defaultMessage: 'No releases'
}, {
target: sectionTitle
}),
icon: /*#__PURE__*/ jsxRuntime.jsx(symbols.EmptyDocuments, {
width: "16rem"
})
});
}
return /*#__PURE__*/ jsxRuntime.jsx(designSystem.Grid.Root, {
gap: 4,
children: releases.map(({ id, name, scheduledAt, status })=>/*#__PURE__*/ jsxRuntime.jsx(designSystem.Grid.Item, {
col: 3,
s: 6,
xs: 12,
direction: "column",
alignItems: "stretch",
children: /*#__PURE__*/ jsxRuntime.jsx(LinkCard, {
tag: reactRouterDom.NavLink,
to: `${id}`,
isExternal: false,
children: /*#__PURE__*/ jsxRuntime.jsxs(designSystem.Flex, {
direction: "column",
justifyContent: "space-between",
padding: 4,
hasRadius: true,
background: "neutral0",
shadow: "tableShadow",
height: "100%",
width: "100%",
alignItems: "start",
gap: 4,
children: [
/*#__PURE__*/ jsxRuntime.jsxs(designSystem.Flex, {
direction: "column",
alignItems: "start",
gap: 1,
children: [
/*#__PURE__*/ jsxRuntime.jsx(designSystem.Typography, {
textColor: "neutral800",
tag: "h3",
variant: "delta",
fontWeight: "bold",
children: name
}),
/*#__PURE__*/ jsxRuntime.jsx(designSystem.Typography, {
variant: "pi",
textColor: "neutral600",
children: scheduledAt ? /*#__PURE__*/ jsxRuntime.jsx(RelativeTime, {
timestamp: new Date(scheduledAt)
}) : formatMessage({
id: 'content-releases.pages.Releases.not-scheduled',
defaultMessage: 'Not scheduled'
})
})
]
}),
/*#__PURE__*/ jsxRuntime.jsx(designSystem.Badge, {
...getBadgeProps(status),
children: status
})
]
})
})
}, id))
});
};
/* -------------------------------------------------------------------------------------------------
* ReleasesPage
* -----------------------------------------------------------------------------------------------*/ const StyledAlert = styledComponents.styled(designSystem.Alert)`
button {
display: none;
}
p + div {
margin-left: auto;
}
`;
const INITIAL_FORM_VALUES = {
name: '',
date: dateFns.format(new Date(), 'yyyy-MM-dd'),
time: '',
isScheduled: true,
scheduledAt: null,
timezone: null
};
const ReleasesPage = ()=>{
const location = reactRouterDom.useLocation();
const [releaseModalShown, setReleaseModalShown] = React__namespace.useState(false);
const { toggleNotification } = strapiAdmin.useNotification();
const { formatMessage } = reactIntl.useIntl();
const navigate = reactRouterDom.useNavigate();
const { formatAPIError } = strapiAdmin.useAPIErrorHandler();
const [{ query }, setQuery] = strapiAdmin.useQueryParams();
const response = release.useGetReleasesQuery(query);
const { data, isLoading: isLoadingSettings } = release.useGetReleaseSettingsQuery();
const [createRelease, { isLoading: isSubmittingForm }] = release.useCreateReleaseMutation();
const { getFeature } = ee.useLicenseLimits();
const { maximumReleases = 3 } = getFeature('cms-content-releases');
const { trackUsage } = strapiAdmin.useTracking();
const { allowedActions: { canCreate } } = strapiAdmin.useRBAC(constants.PERMISSIONS);
const { isLoading: isLoadingReleases, isSuccess, isError } = response;
const activeTab = response?.currentData?.meta?.activeTab || 'pending';
// Check if we have some errors and show a notification to the user to explain the error
React__namespace.useEffect(()=>{
if (location?.state?.errors) {
toggleNotification({
type: 'danger',
title: formatMessage({
id: 'content-releases.pages.Releases.notification.error.title',
defaultMessage: 'Your request could not be processed.'
}),
message: formatMessage({
id: 'content-releases.pages.Releases.notification.error.message',
defaultMessage: 'Please try again or open another release.'
})
});
navigate('', {
replace: true,
state: null
});
}
}, [
formatMessage,
location?.state?.errors,
navigate,
toggleNotification
]);
const toggleAddReleaseModal = ()=>{
setReleaseModalShown((prev)=>!prev);
};
if (isLoadingReleases || isLoadingSettings) {
return /*#__PURE__*/ jsxRuntime.jsx(strapiAdmin.Page.Loading, {});
}
const totalPendingReleases = isSuccess && response.currentData?.meta?.pendingReleasesCount || 0;
const hasReachedMaximumPendingReleases = totalPendingReleases >= maximumReleases;
const handleTabChange = (tabValue)=>{
setQuery({
...query,
page: 1,
pageSize: response?.currentData?.meta?.pagination?.pageSize || 16,
filters: {
releasedAt: {
$notNull: tabValue !== 'pending'
}
}
});
};
const handleAddRelease = async ({ name, scheduledAt, timezone })=>{
const response = await createRelease({
name,
scheduledAt,
timezone
});
if ('data' in response) {
// When the response returns an object with 'data', handle success
toggleNotification({
type: 'success',
message: formatMessage({
id: 'content-releases.modal.release-created-notification-success',
defaultMessage: 'Release created.'
})
});
trackUsage('didCreateRelease');
navigate(response.data.data.id.toString());
} else if (strapiAdmin.isFetchError(response.error)) {
// When the response returns an object with 'error', handle fetch error
toggleNotification({
type: 'danger',
message: formatAPIError(response.error)
});
} else {
// Otherwise, the response returns an object with 'error', handle a generic error
toggleNotification({
type: 'danger',
message: formatMessage({
id: 'notification.error',
defaultMessage: 'An error occurred'
})
});
}
};
return /*#__PURE__*/ jsxRuntime.jsxs(designSystem.Main, {
"aria-busy": isLoadingReleases || isLoadingSettings,
children: [
/*#__PURE__*/ jsxRuntime.jsx(strapiAdmin.Layouts.Header, {
title: formatMessage({
id: 'content-releases.pages.Releases.title',
defaultMessage: 'Releases'
}),
subtitle: formatMessage({
id: 'content-releases.pages.Releases.header-subtitle',
defaultMessage: 'Create and manage content updates'
}),
primaryAction: canCreate ? /*#__PURE__*/ jsxRuntime.jsx(designSystem.Button, {
startIcon: /*#__PURE__*/ jsxRuntime.jsx(icons.Plus, {}),
onClick: toggleAddReleaseModal,
disabled: hasReachedMaximumPendingReleases,
children: formatMessage({
id: 'content-releases.header.actions.add-release',
defaultMessage: 'New release'
})
}) : null
}),
/*#__PURE__*/ jsxRuntime.jsx(strapiAdmin.Layouts.Content, {
children: /*#__PURE__*/ jsxRuntime.jsxs(jsxRuntime.Fragment, {
children: [
hasReachedMaximumPendingReleases && /*#__PURE__*/ jsxRuntime.jsx(StyledAlert, {
marginBottom: 6,
action: /*#__PURE__*/ jsxRuntime.jsx(designSystem.Link, {
href: "https://strapi.io/pricing-cloud",
isExternal: true,
children: formatMessage({
id: 'content-releases.pages.Releases.max-limit-reached.action',
defaultMessage: 'Explore plans'
})
}),
title: formatMessage({
id: 'content-releases.pages.Releases.max-limit-reached.title',
defaultMessage: 'You have reached the {number} pending {number, plural, one {release} other {releases}} limit.'
}, {
number: maximumReleases
}),
onClose: ()=>{},
closeLabel: "",
children: formatMessage({
id: 'content-releases.pages.Releases.max-limit-reached.message',
defaultMessage: 'Upgrade to manage an unlimited number of releases.'
})
}),
/*#__PURE__*/ jsxRuntime.jsxs(designSystem.Tabs.Root, {
variant: "simple",
onValueChange: handleTabChange,
value: activeTab,
children: [
/*#__PURE__*/ jsxRuntime.jsxs(designSystem.Box, {
paddingBottom: 8,
children: [
/*#__PURE__*/ jsxRuntime.jsxs(designSystem.Tabs.List, {
"aria-label": formatMessage({
id: 'content-releases.pages.Releases.tab-group.label',
defaultMessage: 'Releases list'
}),
children: [
/*#__PURE__*/ jsxRuntime.jsx(designSystem.Tabs.Trigger, {
value: "pending",
children: formatMessage({
id: 'content-releases.pages.Releases.tab.pending',
defaultMessage: 'Pending ({count})'
}, {
count: totalPendingReleases
})
}),
/*#__PURE__*/ jsxRuntime.jsx(designSystem.Tabs.Trigger, {
value: "done",
children: formatMessage({
id: 'content-releases.pages.Releases.tab.done',
defaultMessage: 'Done'
})
})
]
}),
/*#__PURE__*/ jsxRuntime.jsx(designSystem.Divider, {})
]
}),
/*#__PURE__*/ jsxRuntime.jsx(designSystem.Tabs.Content, {
value: "pending",
children: /*#__PURE__*/ jsxRuntime.jsx(ReleasesGrid, {
sectionTitle: "pending",
releases: response?.currentData?.data,
isError: isError
})
}),
/*#__PURE__*/ jsxRuntime.jsx(designSystem.Tabs.Content, {
value: "done",
children: /*#__PURE__*/ jsxRuntime.jsx(ReleasesGrid, {
sectionTitle: "done",
releases: response?.currentData?.data,
isError: isError
})
})
]
}),
/*#__PURE__*/ jsxRuntime.jsxs(strapiAdmin.Pagination.Root, {
...response?.currentData?.meta?.pagination,
defaultPageSize: response?.currentData?.meta?.pagination?.pageSize,
children: [
/*#__PURE__*/ jsxRuntime.jsx(strapiAdmin.Pagination.PageSize, {
options: [
'8',
'16',
'32',
'64'
]
}),
/*#__PURE__*/ jsxRuntime.jsx(strapiAdmin.Pagination.Links, {})
]
})
]
})
}),
/*#__PURE__*/ jsxRuntime.jsx(ReleaseModal.ReleaseModal, {
open: releaseModalShown,
handleClose: toggleAddReleaseModal,
handleSubmit: handleAddRelease,
isLoading: isSubmittingForm,
initialValues: {
...INITIAL_FORM_VALUES,
timezone: data?.data.defaultTimezone ? data.data.defaultTimezone.split('&')[1] : null
}
})
]
});
};
exports.ReleasesPage = ReleasesPage;
exports.getBadgeProps = getBadgeProps;
//# sourceMappingURL=ReleasesPage.js.map

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,375 @@
import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
import * as React from 'react';
import { useNotification, useAPIErrorHandler, useQueryParams, useTracking, useRBAC, Page, Layouts, Pagination, isFetchError } from '@strapi/admin/strapi-admin';
import { useLicenseLimits } from '@strapi/admin/strapi-admin/ee';
import { Link, Alert, Main, Button, Tabs, Box, Divider, EmptyStateLayout, Grid, Flex, Typography, Badge } from '@strapi/design-system';
import { Plus } from '@strapi/icons';
import { EmptyDocuments } from '@strapi/icons/symbols';
import { format } from 'date-fns';
import { useIntl } from 'react-intl';
import { useLocation, useNavigate, NavLink } from 'react-router-dom';
import { styled } from 'styled-components';
import { RelativeTime as RelativeTime$1 } from '../components/RelativeTime.mjs';
import { ReleaseModal } from '../components/ReleaseModal.mjs';
import { PERMISSIONS } from '../constants.mjs';
import { useGetReleasesQuery, useGetReleaseSettingsQuery, useCreateReleaseMutation } from '../services/release.mjs';
const LinkCard = styled(Link)`
display: block;
`;
const RelativeTime = styled(RelativeTime$1)`
display: inline-block;
&::first-letter {
text-transform: uppercase;
}
`;
const getBadgeProps = (status)=>{
let color;
switch(status){
case 'ready':
color = 'success';
break;
case 'blocked':
color = 'warning';
break;
case 'failed':
color = 'danger';
break;
case 'done':
color = 'primary';
break;
case 'empty':
default:
color = 'neutral';
}
return {
textColor: `${color}600`,
backgroundColor: `${color}100`,
borderColor: `${color}200`
};
};
const ReleasesGrid = ({ sectionTitle, releases = [], isError = false })=>{
const { formatMessage } = useIntl();
if (isError) {
return /*#__PURE__*/ jsx(Page.Error, {});
}
if (releases?.length === 0) {
return /*#__PURE__*/ jsx(EmptyStateLayout, {
content: formatMessage({
id: 'content-releases.page.Releases.tab.emptyEntries',
defaultMessage: 'No releases'
}, {
target: sectionTitle
}),
icon: /*#__PURE__*/ jsx(EmptyDocuments, {
width: "16rem"
})
});
}
return /*#__PURE__*/ jsx(Grid.Root, {
gap: 4,
children: releases.map(({ id, name, scheduledAt, status })=>/*#__PURE__*/ jsx(Grid.Item, {
col: 3,
s: 6,
xs: 12,
direction: "column",
alignItems: "stretch",
children: /*#__PURE__*/ jsx(LinkCard, {
tag: NavLink,
to: `${id}`,
isExternal: false,
children: /*#__PURE__*/ jsxs(Flex, {
direction: "column",
justifyContent: "space-between",
padding: 4,
hasRadius: true,
background: "neutral0",
shadow: "tableShadow",
height: "100%",
width: "100%",
alignItems: "start",
gap: 4,
children: [
/*#__PURE__*/ jsxs(Flex, {
direction: "column",
alignItems: "start",
gap: 1,
children: [
/*#__PURE__*/ jsx(Typography, {
textColor: "neutral800",
tag: "h3",
variant: "delta",
fontWeight: "bold",
children: name
}),
/*#__PURE__*/ jsx(Typography, {
variant: "pi",
textColor: "neutral600",
children: scheduledAt ? /*#__PURE__*/ jsx(RelativeTime, {
timestamp: new Date(scheduledAt)
}) : formatMessage({
id: 'content-releases.pages.Releases.not-scheduled',
defaultMessage: 'Not scheduled'
})
})
]
}),
/*#__PURE__*/ jsx(Badge, {
...getBadgeProps(status),
children: status
})
]
})
})
}, id))
});
};
/* -------------------------------------------------------------------------------------------------
* ReleasesPage
* -----------------------------------------------------------------------------------------------*/ const StyledAlert = styled(Alert)`
button {
display: none;
}
p + div {
margin-left: auto;
}
`;
const INITIAL_FORM_VALUES = {
name: '',
date: format(new Date(), 'yyyy-MM-dd'),
time: '',
isScheduled: true,
scheduledAt: null,
timezone: null
};
const ReleasesPage = ()=>{
const location = useLocation();
const [releaseModalShown, setReleaseModalShown] = React.useState(false);
const { toggleNotification } = useNotification();
const { formatMessage } = useIntl();
const navigate = useNavigate();
const { formatAPIError } = useAPIErrorHandler();
const [{ query }, setQuery] = useQueryParams();
const response = useGetReleasesQuery(query);
const { data, isLoading: isLoadingSettings } = useGetReleaseSettingsQuery();
const [createRelease, { isLoading: isSubmittingForm }] = useCreateReleaseMutation();
const { getFeature } = useLicenseLimits();
const { maximumReleases = 3 } = getFeature('cms-content-releases');
const { trackUsage } = useTracking();
const { allowedActions: { canCreate } } = useRBAC(PERMISSIONS);
const { isLoading: isLoadingReleases, isSuccess, isError } = response;
const activeTab = response?.currentData?.meta?.activeTab || 'pending';
// Check if we have some errors and show a notification to the user to explain the error
React.useEffect(()=>{
if (location?.state?.errors) {
toggleNotification({
type: 'danger',
title: formatMessage({
id: 'content-releases.pages.Releases.notification.error.title',
defaultMessage: 'Your request could not be processed.'
}),
message: formatMessage({
id: 'content-releases.pages.Releases.notification.error.message',
defaultMessage: 'Please try again or open another release.'
})
});
navigate('', {
replace: true,
state: null
});
}
}, [
formatMessage,
location?.state?.errors,
navigate,
toggleNotification
]);
const toggleAddReleaseModal = ()=>{
setReleaseModalShown((prev)=>!prev);
};
if (isLoadingReleases || isLoadingSettings) {
return /*#__PURE__*/ jsx(Page.Loading, {});
}
const totalPendingReleases = isSuccess && response.currentData?.meta?.pendingReleasesCount || 0;
const hasReachedMaximumPendingReleases = totalPendingReleases >= maximumReleases;
const handleTabChange = (tabValue)=>{
setQuery({
...query,
page: 1,
pageSize: response?.currentData?.meta?.pagination?.pageSize || 16,
filters: {
releasedAt: {
$notNull: tabValue !== 'pending'
}
}
});
};
const handleAddRelease = async ({ name, scheduledAt, timezone })=>{
const response = await createRelease({
name,
scheduledAt,
timezone
});
if ('data' in response) {
// When the response returns an object with 'data', handle success
toggleNotification({
type: 'success',
message: formatMessage({
id: 'content-releases.modal.release-created-notification-success',
defaultMessage: 'Release created.'
})
});
trackUsage('didCreateRelease');
navigate(response.data.data.id.toString());
} else if (isFetchError(response.error)) {
// When the response returns an object with 'error', handle fetch error
toggleNotification({
type: 'danger',
message: formatAPIError(response.error)
});
} else {
// Otherwise, the response returns an object with 'error', handle a generic error
toggleNotification({
type: 'danger',
message: formatMessage({
id: 'notification.error',
defaultMessage: 'An error occurred'
})
});
}
};
return /*#__PURE__*/ jsxs(Main, {
"aria-busy": isLoadingReleases || isLoadingSettings,
children: [
/*#__PURE__*/ jsx(Layouts.Header, {
title: formatMessage({
id: 'content-releases.pages.Releases.title',
defaultMessage: 'Releases'
}),
subtitle: formatMessage({
id: 'content-releases.pages.Releases.header-subtitle',
defaultMessage: 'Create and manage content updates'
}),
primaryAction: canCreate ? /*#__PURE__*/ jsx(Button, {
startIcon: /*#__PURE__*/ jsx(Plus, {}),
onClick: toggleAddReleaseModal,
disabled: hasReachedMaximumPendingReleases,
children: formatMessage({
id: 'content-releases.header.actions.add-release',
defaultMessage: 'New release'
})
}) : null
}),
/*#__PURE__*/ jsx(Layouts.Content, {
children: /*#__PURE__*/ jsxs(Fragment, {
children: [
hasReachedMaximumPendingReleases && /*#__PURE__*/ jsx(StyledAlert, {
marginBottom: 6,
action: /*#__PURE__*/ jsx(Link, {
href: "https://strapi.io/pricing-cloud",
isExternal: true,
children: formatMessage({
id: 'content-releases.pages.Releases.max-limit-reached.action',
defaultMessage: 'Explore plans'
})
}),
title: formatMessage({
id: 'content-releases.pages.Releases.max-limit-reached.title',
defaultMessage: 'You have reached the {number} pending {number, plural, one {release} other {releases}} limit.'
}, {
number: maximumReleases
}),
onClose: ()=>{},
closeLabel: "",
children: formatMessage({
id: 'content-releases.pages.Releases.max-limit-reached.message',
defaultMessage: 'Upgrade to manage an unlimited number of releases.'
})
}),
/*#__PURE__*/ jsxs(Tabs.Root, {
variant: "simple",
onValueChange: handleTabChange,
value: activeTab,
children: [
/*#__PURE__*/ jsxs(Box, {
paddingBottom: 8,
children: [
/*#__PURE__*/ jsxs(Tabs.List, {
"aria-label": formatMessage({
id: 'content-releases.pages.Releases.tab-group.label',
defaultMessage: 'Releases list'
}),
children: [
/*#__PURE__*/ jsx(Tabs.Trigger, {
value: "pending",
children: formatMessage({
id: 'content-releases.pages.Releases.tab.pending',
defaultMessage: 'Pending ({count})'
}, {
count: totalPendingReleases
})
}),
/*#__PURE__*/ jsx(Tabs.Trigger, {
value: "done",
children: formatMessage({
id: 'content-releases.pages.Releases.tab.done',
defaultMessage: 'Done'
})
})
]
}),
/*#__PURE__*/ jsx(Divider, {})
]
}),
/*#__PURE__*/ jsx(Tabs.Content, {
value: "pending",
children: /*#__PURE__*/ jsx(ReleasesGrid, {
sectionTitle: "pending",
releases: response?.currentData?.data,
isError: isError
})
}),
/*#__PURE__*/ jsx(Tabs.Content, {
value: "done",
children: /*#__PURE__*/ jsx(ReleasesGrid, {
sectionTitle: "done",
releases: response?.currentData?.data,
isError: isError
})
})
]
}),
/*#__PURE__*/ jsxs(Pagination.Root, {
...response?.currentData?.meta?.pagination,
defaultPageSize: response?.currentData?.meta?.pagination?.pageSize,
children: [
/*#__PURE__*/ jsx(Pagination.PageSize, {
options: [
'8',
'16',
'32',
'64'
]
}),
/*#__PURE__*/ jsx(Pagination.Links, {})
]
})
]
})
}),
/*#__PURE__*/ jsx(ReleaseModal, {
open: releaseModalShown,
handleClose: toggleAddReleaseModal,
handleSubmit: handleAddRelease,
isLoading: isSubmittingForm,
initialValues: {
...INITIAL_FORM_VALUES,
timezone: data?.data.defaultTimezone ? data.data.defaultTimezone.split('&')[1] : null
}
})
]
});
};
export { ReleasesPage, getBadgeProps };
//# sourceMappingURL=ReleasesPage.mjs.map

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,199 @@
'use strict';
var jsxRuntime = require('react/jsx-runtime');
var strapiAdmin = require('@strapi/admin/strapi-admin');
var designSystem = require('@strapi/design-system');
var icons = require('@strapi/icons');
var reactIntl = require('react-intl');
var hooks = require('../modules/hooks.js');
var release = require('../services/release.js');
var time = require('../utils/time.js');
var schemas = require('../validation/schemas.js');
const ReleasesSettingsPage = ()=>{
const { formatMessage } = reactIntl.useIntl();
const { formatAPIError } = strapiAdmin.useAPIErrorHandler();
const { toggleNotification } = strapiAdmin.useNotification();
const { data, isLoading: isLoadingSettings } = release.useGetReleaseSettingsQuery();
const [updateReleaseSettings, { isLoading: isSubmittingForm }] = release.useUpdateReleaseSettingsMutation();
const permissions = hooks.useTypedSelector((state)=>state.admin_app.permissions['settings']?.['releases']);
const { allowedActions: { canUpdate } } = strapiAdmin.useRBAC(permissions);
const { timezoneList } = time.getTimezones(new Date());
const handleSubmit = async (body)=>{
const { defaultTimezone } = body;
const isBodyTimezoneValid = timezoneList.some((timezone)=>timezone.value === defaultTimezone);
const newBody = !defaultTimezone || !isBodyTimezoneValid ? {
defaultTimezone: null
} : {
...body
};
try {
const response = await updateReleaseSettings(newBody);
if ('data' in response) {
toggleNotification({
type: 'success',
message: formatMessage({
id: 'content-releases.pages.Settings.releases.setting.default-timezone-notification-success',
defaultMessage: 'Default timezone updated.'
})
});
} else if (strapiAdmin.isFetchError(response.error)) {
toggleNotification({
type: 'danger',
message: formatAPIError(response.error)
});
} else {
toggleNotification({
type: 'danger',
message: formatMessage({
id: 'notification.error',
defaultMessage: 'An error occurred'
})
});
}
} catch (error) {
toggleNotification({
type: 'danger',
message: formatMessage({
id: 'notification.error',
defaultMessage: 'An error occurred'
})
});
}
};
if (isLoadingSettings) {
return /*#__PURE__*/ jsxRuntime.jsx(strapiAdmin.Page.Loading, {});
}
return /*#__PURE__*/ jsxRuntime.jsxs(strapiAdmin.Layouts.Root, {
children: [
/*#__PURE__*/ jsxRuntime.jsx(strapiAdmin.Page.Title, {
children: formatMessage({
id: 'Settings.PageTitle',
defaultMessage: 'Settings - {name}'
}, {
name: 'Releases'
})
}),
/*#__PURE__*/ jsxRuntime.jsx(strapiAdmin.Page.Main, {
"aria-busy": isLoadingSettings,
tabIndex: -1,
children: /*#__PURE__*/ jsxRuntime.jsx(strapiAdmin.Form, {
method: "PUT",
initialValues: {
defaultTimezone: data?.data.defaultTimezone
},
onSubmit: handleSubmit,
validationSchema: schemas.SETTINGS_SCHEMA,
children: ({ modified, isSubmitting })=>{
return /*#__PURE__*/ jsxRuntime.jsxs(jsxRuntime.Fragment, {
children: [
/*#__PURE__*/ jsxRuntime.jsx(strapiAdmin.Layouts.Header, {
primaryAction: canUpdate ? /*#__PURE__*/ jsxRuntime.jsx(designSystem.Button, {
disabled: !modified || isSubmittingForm,
loading: isSubmitting,
startIcon: /*#__PURE__*/ jsxRuntime.jsx(icons.Check, {}),
type: "submit",
children: formatMessage({
id: 'global.save',
defaultMessage: 'Save'
})
}) : null,
title: formatMessage({
id: 'content-releases.pages.Settings.releases.title',
defaultMessage: 'Releases'
}),
subtitle: formatMessage({
id: 'content-releases.pages.Settings.releases.description',
defaultMessage: 'Create and manage content updates'
})
}),
/*#__PURE__*/ jsxRuntime.jsx(strapiAdmin.Layouts.Content, {
children: /*#__PURE__*/ jsxRuntime.jsxs(designSystem.Flex, {
direction: "column",
background: "neutral0",
alignItems: "stretch",
padding: 6,
gap: 6,
shadow: "filterShadow",
hasRadius: true,
children: [
/*#__PURE__*/ jsxRuntime.jsx(designSystem.Typography, {
variant: "delta",
tag: "h2",
children: formatMessage({
id: 'content-releases.pages.Settings.releases.preferences.title',
defaultMessage: 'Preferences'
})
}),
/*#__PURE__*/ jsxRuntime.jsx(designSystem.Grid.Root, {
children: /*#__PURE__*/ jsxRuntime.jsx(designSystem.Grid.Item, {
col: 6,
s: 12,
direction: "column",
alignItems: "stretch",
children: /*#__PURE__*/ jsxRuntime.jsx(TimezoneDropdown, {})
})
})
]
})
})
]
});
}
})
})
]
});
};
const TimezoneDropdown = ()=>{
const permissions = hooks.useTypedSelector((state)=>state.admin_app.permissions['settings']?.['releases']);
const { allowedActions: { canUpdate } } = strapiAdmin.useRBAC(permissions);
const { formatMessage } = reactIntl.useIntl();
const { timezoneList } = time.getTimezones(new Date());
const field = strapiAdmin.useField('defaultTimezone');
return /*#__PURE__*/ jsxRuntime.jsxs(designSystem.Field.Root, {
name: "defaultTimezone",
hint: formatMessage({
id: 'content-releases.pages.Settings.releases.timezone.hint',
defaultMessage: 'The timezone of every release can still be changed individually. '
}),
error: field.error,
children: [
/*#__PURE__*/ jsxRuntime.jsx(designSystem.Field.Label, {
children: formatMessage({
id: 'content-releases.pages.Settings.releases.timezone.label',
defaultMessage: 'Default timezone'
})
}),
/*#__PURE__*/ jsxRuntime.jsx(designSystem.Combobox, {
autocomplete: {
type: 'list',
filter: 'contains'
},
onChange: (value)=>field.onChange('defaultTimezone', value),
onTextValueChange: (value)=>field.onChange('defaultTimezone', value),
onClear: ()=>field.onChange('defaultTimezone', ''),
value: field.value,
disabled: !canUpdate,
children: timezoneList.map((timezone)=>/*#__PURE__*/ jsxRuntime.jsx(designSystem.ComboboxOption, {
value: timezone.value,
children: timezone.value.replace(/&/, ' ')
}, timezone.value))
}),
/*#__PURE__*/ jsxRuntime.jsx(designSystem.Field.Hint, {}),
/*#__PURE__*/ jsxRuntime.jsx(designSystem.Field.Error, {})
]
});
};
/* -------------------------------------------------------------------------------------------------
* ProtectedSettingsPage
* -----------------------------------------------------------------------------------------------*/ const ProtectedReleasesSettingsPage = ()=>{
const permissions = hooks.useTypedSelector((state)=>state.admin_app.permissions['settings']?.['releases']?.read);
return /*#__PURE__*/ jsxRuntime.jsx(strapiAdmin.Page.Protect, {
permissions: permissions,
children: /*#__PURE__*/ jsxRuntime.jsx(ReleasesSettingsPage, {})
});
};
exports.ProtectedReleasesSettingsPage = ProtectedReleasesSettingsPage;
//# sourceMappingURL=ReleasesSettingsPage.js.map

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,197 @@
import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
import { Page, useAPIErrorHandler, useNotification, useRBAC, Layouts, Form, useField, isFetchError } from '@strapi/admin/strapi-admin';
import { Button, Flex, Typography, Grid, Field, Combobox, ComboboxOption } from '@strapi/design-system';
import { Check } from '@strapi/icons';
import { useIntl } from 'react-intl';
import { useTypedSelector } from '../modules/hooks.mjs';
import { useGetReleaseSettingsQuery, useUpdateReleaseSettingsMutation } from '../services/release.mjs';
import { getTimezones } from '../utils/time.mjs';
import { SETTINGS_SCHEMA } from '../validation/schemas.mjs';
const ReleasesSettingsPage = ()=>{
const { formatMessage } = useIntl();
const { formatAPIError } = useAPIErrorHandler();
const { toggleNotification } = useNotification();
const { data, isLoading: isLoadingSettings } = useGetReleaseSettingsQuery();
const [updateReleaseSettings, { isLoading: isSubmittingForm }] = useUpdateReleaseSettingsMutation();
const permissions = useTypedSelector((state)=>state.admin_app.permissions['settings']?.['releases']);
const { allowedActions: { canUpdate } } = useRBAC(permissions);
const { timezoneList } = getTimezones(new Date());
const handleSubmit = async (body)=>{
const { defaultTimezone } = body;
const isBodyTimezoneValid = timezoneList.some((timezone)=>timezone.value === defaultTimezone);
const newBody = !defaultTimezone || !isBodyTimezoneValid ? {
defaultTimezone: null
} : {
...body
};
try {
const response = await updateReleaseSettings(newBody);
if ('data' in response) {
toggleNotification({
type: 'success',
message: formatMessage({
id: 'content-releases.pages.Settings.releases.setting.default-timezone-notification-success',
defaultMessage: 'Default timezone updated.'
})
});
} else if (isFetchError(response.error)) {
toggleNotification({
type: 'danger',
message: formatAPIError(response.error)
});
} else {
toggleNotification({
type: 'danger',
message: formatMessage({
id: 'notification.error',
defaultMessage: 'An error occurred'
})
});
}
} catch (error) {
toggleNotification({
type: 'danger',
message: formatMessage({
id: 'notification.error',
defaultMessage: 'An error occurred'
})
});
}
};
if (isLoadingSettings) {
return /*#__PURE__*/ jsx(Page.Loading, {});
}
return /*#__PURE__*/ jsxs(Layouts.Root, {
children: [
/*#__PURE__*/ jsx(Page.Title, {
children: formatMessage({
id: 'Settings.PageTitle',
defaultMessage: 'Settings - {name}'
}, {
name: 'Releases'
})
}),
/*#__PURE__*/ jsx(Page.Main, {
"aria-busy": isLoadingSettings,
tabIndex: -1,
children: /*#__PURE__*/ jsx(Form, {
method: "PUT",
initialValues: {
defaultTimezone: data?.data.defaultTimezone
},
onSubmit: handleSubmit,
validationSchema: SETTINGS_SCHEMA,
children: ({ modified, isSubmitting })=>{
return /*#__PURE__*/ jsxs(Fragment, {
children: [
/*#__PURE__*/ jsx(Layouts.Header, {
primaryAction: canUpdate ? /*#__PURE__*/ jsx(Button, {
disabled: !modified || isSubmittingForm,
loading: isSubmitting,
startIcon: /*#__PURE__*/ jsx(Check, {}),
type: "submit",
children: formatMessage({
id: 'global.save',
defaultMessage: 'Save'
})
}) : null,
title: formatMessage({
id: 'content-releases.pages.Settings.releases.title',
defaultMessage: 'Releases'
}),
subtitle: formatMessage({
id: 'content-releases.pages.Settings.releases.description',
defaultMessage: 'Create and manage content updates'
})
}),
/*#__PURE__*/ jsx(Layouts.Content, {
children: /*#__PURE__*/ jsxs(Flex, {
direction: "column",
background: "neutral0",
alignItems: "stretch",
padding: 6,
gap: 6,
shadow: "filterShadow",
hasRadius: true,
children: [
/*#__PURE__*/ jsx(Typography, {
variant: "delta",
tag: "h2",
children: formatMessage({
id: 'content-releases.pages.Settings.releases.preferences.title',
defaultMessage: 'Preferences'
})
}),
/*#__PURE__*/ jsx(Grid.Root, {
children: /*#__PURE__*/ jsx(Grid.Item, {
col: 6,
s: 12,
direction: "column",
alignItems: "stretch",
children: /*#__PURE__*/ jsx(TimezoneDropdown, {})
})
})
]
})
})
]
});
}
})
})
]
});
};
const TimezoneDropdown = ()=>{
const permissions = useTypedSelector((state)=>state.admin_app.permissions['settings']?.['releases']);
const { allowedActions: { canUpdate } } = useRBAC(permissions);
const { formatMessage } = useIntl();
const { timezoneList } = getTimezones(new Date());
const field = useField('defaultTimezone');
return /*#__PURE__*/ jsxs(Field.Root, {
name: "defaultTimezone",
hint: formatMessage({
id: 'content-releases.pages.Settings.releases.timezone.hint',
defaultMessage: 'The timezone of every release can still be changed individually. '
}),
error: field.error,
children: [
/*#__PURE__*/ jsx(Field.Label, {
children: formatMessage({
id: 'content-releases.pages.Settings.releases.timezone.label',
defaultMessage: 'Default timezone'
})
}),
/*#__PURE__*/ jsx(Combobox, {
autocomplete: {
type: 'list',
filter: 'contains'
},
onChange: (value)=>field.onChange('defaultTimezone', value),
onTextValueChange: (value)=>field.onChange('defaultTimezone', value),
onClear: ()=>field.onChange('defaultTimezone', ''),
value: field.value,
disabled: !canUpdate,
children: timezoneList.map((timezone)=>/*#__PURE__*/ jsx(ComboboxOption, {
value: timezone.value,
children: timezone.value.replace(/&/, ' ')
}, timezone.value))
}),
/*#__PURE__*/ jsx(Field.Hint, {}),
/*#__PURE__*/ jsx(Field.Error, {})
]
});
};
/* -------------------------------------------------------------------------------------------------
* ProtectedSettingsPage
* -----------------------------------------------------------------------------------------------*/ const ProtectedReleasesSettingsPage = ()=>{
const permissions = useTypedSelector((state)=>state.admin_app.permissions['settings']?.['releases']?.read);
return /*#__PURE__*/ jsx(Page.Protect, {
permissions: permissions,
children: /*#__PURE__*/ jsx(ReleasesSettingsPage, {})
});
};
export { ProtectedReleasesSettingsPage };
//# sourceMappingURL=ReleasesSettingsPage.mjs.map

File diff suppressed because one or more lines are too long