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

17
server/node_modules/@strapi/review-workflows/LICENSE generated vendored Normal file
View File

@@ -0,0 +1,17 @@
Copyright (c) 2015-present Strapi Solutions SAS
* All software that resides within this directory and its subdirectories, is licensed under the license defined below.
Enterprise License
If you or the company you represent has entered into a written agreement referencing the Enterprise Edition of the Strapi source code available at
https://github.com/strapi/strapi, then such agreement applies to your use of the Enterprise Edition of the Strapi Software. If you or the company you
represent is using the Enterprise Edition of the Strapi Software in connection with a subscription to our cloud offering, then the agreement you have
agreed to with respect to our cloud offering and the licenses included in such agreement apply to your use of the Enterprise Edition of the Strapi Software.
Otherwise, the Strapi Enterprise Software License Agreement (found here https://strapi.io/enterprise-terms) applies to your use of the Enterprise Edition of the Strapi Software.
BY ACCESSING OR USING THE ENTERPRISE EDITION OF THE STRAPI SOFTWARE, YOU ARE AGREEING TO BE BOUND BY THE RELEVANT REFERENCED AGREEMENT.
IF YOU ARE NOT AUTHORIZED TO ACCEPT THESE TERMS ON BEHALF OF THE COMPANY YOU REPRESENT OR IF YOU DO NOT AGREE TO ALL OF THE RELEVANT TERMS AND CONDITIONS REFERENCED AND YOU
HAVE NOT OTHERWISE EXECUTED A WRITTEN AGREEMENT WITH STRAPI, YOU ARE NOT AUTHORIZED TO ACCESS OR USE OR ALLOW ANY USER TO ACCESS OR USE ANY PART OF
THE ENTERPRISE EDITION OF THE STRAPI SOFTWARE. YOUR ACCESS RIGHTS ARE CONDITIONAL ON YOUR CONSENT TO THE RELEVANT REFERENCED TERMS TO THE EXCLUSION OF ALL OTHER TERMS;
IF THE RELEVANT REFERENCED TERMS ARE CONSIDERED AN OFFER BY YOU, ACCEPTANCE IS EXPRESSLY LIMITED TO THE RELEVANT REFERENCED TERMS.

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,122 @@
'use strict';
var jsxRuntime = require('react/jsx-runtime');
require('react');
var designSystem = require('@strapi/design-system');
var icons = require('@strapi/icons');
var reactIntl = require('react-intl');
var styledComponents = require('styled-components');
var balloon = require('../assets/balloon.png.js');
const CTA_LEARN_MORE_HREF = 'https://strapi.io/pricing-cloud';
const CTA_SALES_HREF = 'https://strapi.io/contact-sales';
const Title = ({ children })=>{
return /*#__PURE__*/ jsxRuntime.jsx(designSystem.Modal.Title, {
variant: "alpha",
children: children
});
};
const Body = ({ children })=>{
return /*#__PURE__*/ jsxRuntime.jsx(designSystem.Typography, {
variant: "omega",
children: children
});
};
const CallToActions = ()=>{
const { formatMessage } = reactIntl.useIntl();
return /*#__PURE__*/ jsxRuntime.jsxs(designSystem.Flex, {
gap: 2,
paddingTop: 4,
children: [
/*#__PURE__*/ jsxRuntime.jsx(designSystem.LinkButton, {
variant: "default",
isExternal: true,
href: CTA_LEARN_MORE_HREF,
children: formatMessage({
id: 'Settings.review-workflows.limit.cta.learn',
defaultMessage: 'Learn more'
})
}),
/*#__PURE__*/ jsxRuntime.jsx(designSystem.LinkButton, {
variant: "tertiary",
isExternal: true,
href: CTA_SALES_HREF,
children: formatMessage({
id: 'Settings.review-workflows.limit.cta.sales',
defaultMessage: 'Contact Sales'
})
})
]
});
};
const BalloonImage = styledComponents.styled.img`
// Margin top|right reverse the padding of ModalBody
margin-right: ${({ theme })=>`-${theme.spaces[7]}`};
margin-top: ${({ theme })=>`-${theme.spaces[7]}`};
width: 360px;
`;
const Root = ({ children, open = false, onOpenChange })=>{
const { formatMessage } = reactIntl.useIntl();
return /*#__PURE__*/ jsxRuntime.jsx(designSystem.Modal.Root, {
open: open,
onOpenChange: onOpenChange,
children: /*#__PURE__*/ jsxRuntime.jsx(designSystem.Modal.Content, {
children: /*#__PURE__*/ jsxRuntime.jsx(designSystem.Modal.Body, {
children: /*#__PURE__*/ jsxRuntime.jsxs(designSystem.Flex, {
gap: 2,
paddingLeft: 7,
position: "relative",
children: [
/*#__PURE__*/ jsxRuntime.jsxs(designSystem.Flex, {
alignItems: "start",
direction: "column",
gap: 2,
width: "60%",
children: [
children,
/*#__PURE__*/ jsxRuntime.jsx(CallToActions, {})
]
}),
/*#__PURE__*/ jsxRuntime.jsxs(designSystem.Flex, {
justifyContent: "end",
height: "100%",
width: "40%",
children: [
/*#__PURE__*/ jsxRuntime.jsx(BalloonImage, {
src: balloon,
"aria-hidden": true,
alt: "",
loading: "lazy"
}),
/*#__PURE__*/ jsxRuntime.jsx(designSystem.Box, {
display: "flex",
position: "absolute",
right: 0,
top: 0,
children: /*#__PURE__*/ jsxRuntime.jsx(designSystem.Modal.Close, {
children: /*#__PURE__*/ jsxRuntime.jsx(designSystem.IconButton, {
withTooltip: false,
label: formatMessage({
id: 'global.close',
defaultMessage: 'Close'
}),
children: /*#__PURE__*/ jsxRuntime.jsx(icons.Cross, {})
})
})
})
]
})
]
})
})
})
});
};
const LimitsModal = {
Title,
Body,
Root
};
exports.LimitsModal = LimitsModal;
//# sourceMappingURL=LimitsModal.js.map

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,120 @@
import { jsx, jsxs } from 'react/jsx-runtime';
import 'react';
import { Modal, Typography, Flex, Box, IconButton, LinkButton } from '@strapi/design-system';
import { Cross } from '@strapi/icons';
import { useIntl } from 'react-intl';
import { styled } from 'styled-components';
import img from '../assets/balloon.png.mjs';
const CTA_LEARN_MORE_HREF = 'https://strapi.io/pricing-cloud';
const CTA_SALES_HREF = 'https://strapi.io/contact-sales';
const Title = ({ children })=>{
return /*#__PURE__*/ jsx(Modal.Title, {
variant: "alpha",
children: children
});
};
const Body = ({ children })=>{
return /*#__PURE__*/ jsx(Typography, {
variant: "omega",
children: children
});
};
const CallToActions = ()=>{
const { formatMessage } = useIntl();
return /*#__PURE__*/ jsxs(Flex, {
gap: 2,
paddingTop: 4,
children: [
/*#__PURE__*/ jsx(LinkButton, {
variant: "default",
isExternal: true,
href: CTA_LEARN_MORE_HREF,
children: formatMessage({
id: 'Settings.review-workflows.limit.cta.learn',
defaultMessage: 'Learn more'
})
}),
/*#__PURE__*/ jsx(LinkButton, {
variant: "tertiary",
isExternal: true,
href: CTA_SALES_HREF,
children: formatMessage({
id: 'Settings.review-workflows.limit.cta.sales',
defaultMessage: 'Contact Sales'
})
})
]
});
};
const BalloonImage = styled.img`
// Margin top|right reverse the padding of ModalBody
margin-right: ${({ theme })=>`-${theme.spaces[7]}`};
margin-top: ${({ theme })=>`-${theme.spaces[7]}`};
width: 360px;
`;
const Root = ({ children, open = false, onOpenChange })=>{
const { formatMessage } = useIntl();
return /*#__PURE__*/ jsx(Modal.Root, {
open: open,
onOpenChange: onOpenChange,
children: /*#__PURE__*/ jsx(Modal.Content, {
children: /*#__PURE__*/ jsx(Modal.Body, {
children: /*#__PURE__*/ jsxs(Flex, {
gap: 2,
paddingLeft: 7,
position: "relative",
children: [
/*#__PURE__*/ jsxs(Flex, {
alignItems: "start",
direction: "column",
gap: 2,
width: "60%",
children: [
children,
/*#__PURE__*/ jsx(CallToActions, {})
]
}),
/*#__PURE__*/ jsxs(Flex, {
justifyContent: "end",
height: "100%",
width: "40%",
children: [
/*#__PURE__*/ jsx(BalloonImage, {
src: img,
"aria-hidden": true,
alt: "",
loading: "lazy"
}),
/*#__PURE__*/ jsx(Box, {
display: "flex",
position: "absolute",
right: 0,
top: 0,
children: /*#__PURE__*/ jsx(Modal.Close, {
children: /*#__PURE__*/ jsx(IconButton, {
withTooltip: false,
label: formatMessage({
id: 'global.close',
defaultMessage: 'Close'
}),
children: /*#__PURE__*/ jsx(Cross, {})
})
})
})
]
})
]
})
})
})
});
};
const LimitsModal = {
Title,
Body,
Root
};
export { LimitsModal };
//# sourceMappingURL=LimitsModal.mjs.map

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,18 @@
'use strict';
var designSystem = require('@strapi/design-system');
const PLUGIN_ID = 'review-workflows';
/**
* The name of the feature in the license.
*/ const FEATURE_ID = 'review-workflows';
const CHARGEBEE_WORKFLOW_ENTITLEMENT_NAME = 'numberOfWorkflows';
const CHARGEBEE_STAGES_PER_WORKFLOW_ENTITLEMENT_NAME = 'stagesPerWorkflow';
const STAGE_COLOR_DEFAULT = designSystem.lightTheme.colors.primary600;
exports.CHARGEBEE_STAGES_PER_WORKFLOW_ENTITLEMENT_NAME = CHARGEBEE_STAGES_PER_WORKFLOW_ENTITLEMENT_NAME;
exports.CHARGEBEE_WORKFLOW_ENTITLEMENT_NAME = CHARGEBEE_WORKFLOW_ENTITLEMENT_NAME;
exports.FEATURE_ID = FEATURE_ID;
exports.PLUGIN_ID = PLUGIN_ID;
exports.STAGE_COLOR_DEFAULT = STAGE_COLOR_DEFAULT;
//# sourceMappingURL=constants.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"constants.js","sources":["../../admin/src/constants.ts"],"sourcesContent":["import { lightTheme } from '@strapi/design-system';\n\nconst PLUGIN_ID = 'review-workflows';\n/**\n * The name of the feature in the license.\n */\nconst FEATURE_ID = 'review-workflows';\n\nexport const CHARGEBEE_WORKFLOW_ENTITLEMENT_NAME = 'numberOfWorkflows';\nexport const CHARGEBEE_STAGES_PER_WORKFLOW_ENTITLEMENT_NAME = 'stagesPerWorkflow';\n\nexport const STAGE_COLOR_DEFAULT = lightTheme.colors.primary600;\n\nexport { FEATURE_ID, PLUGIN_ID };\n"],"names":["PLUGIN_ID","FEATURE_ID","CHARGEBEE_WORKFLOW_ENTITLEMENT_NAME","CHARGEBEE_STAGES_PER_WORKFLOW_ENTITLEMENT_NAME","STAGE_COLOR_DEFAULT","lightTheme","colors","primary600"],"mappings":";;;;AAEA,MAAMA,SAAY,GAAA;AAClB;;AAEC,UACKC,UAAa,GAAA;AAEZ,MAAMC,sCAAsC;AAC5C,MAAMC,iDAAiD;MAEjDC,mBAAsBC,GAAAA,uBAAAA,CAAWC,MAAM,CAACC;;;;;;;;"}

View File

@@ -0,0 +1,12 @@
import { lightTheme } from '@strapi/design-system';
const PLUGIN_ID = 'review-workflows';
/**
* The name of the feature in the license.
*/ const FEATURE_ID = 'review-workflows';
const CHARGEBEE_WORKFLOW_ENTITLEMENT_NAME = 'numberOfWorkflows';
const CHARGEBEE_STAGES_PER_WORKFLOW_ENTITLEMENT_NAME = 'stagesPerWorkflow';
const STAGE_COLOR_DEFAULT = lightTheme.colors.primary600;
export { CHARGEBEE_STAGES_PER_WORKFLOW_ENTITLEMENT_NAME, CHARGEBEE_WORKFLOW_ENTITLEMENT_NAME, FEATURE_ID, PLUGIN_ID, STAGE_COLOR_DEFAULT };
//# sourceMappingURL=constants.mjs.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"constants.mjs","sources":["../../admin/src/constants.ts"],"sourcesContent":["import { lightTheme } from '@strapi/design-system';\n\nconst PLUGIN_ID = 'review-workflows';\n/**\n * The name of the feature in the license.\n */\nconst FEATURE_ID = 'review-workflows';\n\nexport const CHARGEBEE_WORKFLOW_ENTITLEMENT_NAME = 'numberOfWorkflows';\nexport const CHARGEBEE_STAGES_PER_WORKFLOW_ENTITLEMENT_NAME = 'stagesPerWorkflow';\n\nexport const STAGE_COLOR_DEFAULT = lightTheme.colors.primary600;\n\nexport { FEATURE_ID, PLUGIN_ID };\n"],"names":["PLUGIN_ID","FEATURE_ID","CHARGEBEE_WORKFLOW_ENTITLEMENT_NAME","CHARGEBEE_STAGES_PER_WORKFLOW_ENTITLEMENT_NAME","STAGE_COLOR_DEFAULT","lightTheme","colors","primary600"],"mappings":";;AAEA,MAAMA,SAAY,GAAA;AAClB;;AAEC,UACKC,UAAa,GAAA;AAEZ,MAAMC,sCAAsC;AAC5C,MAAMC,iDAAiD;MAEjDC,mBAAsBC,GAAAA,UAAAA,CAAWC,MAAM,CAACC;;;;"}

View File

@@ -0,0 +1,93 @@
'use strict';
var constants = require('./constants.js');
var Header = require('./routes/content-manager/model/id/components/Header.js');
var Panel = require('./routes/content-manager/model/id/components/Panel.js');
var cmHooks = require('./utils/cm-hooks.js');
var translations = require('./utils/translations.js');
function _interopNamespaceDefaultOnly (e) { return Object.freeze({ __proto__: null, default: e }); }
function __variableDynamicImportRuntime2__(path) {
switch (path) {
case './translations/en.json': return Promise.resolve().then(function () { return /*#__PURE__*/_interopNamespaceDefaultOnly(require('./translations/en.json.js')); });
case './translations/uk.json': return Promise.resolve().then(function () { return /*#__PURE__*/_interopNamespaceDefaultOnly(require('./translations/uk.json.js')); });
default: return new Promise(function(resolve, reject) {
(typeof queueMicrotask === 'function' ? queueMicrotask : setTimeout)(
reject.bind(null, new Error("Unknown variable dynamic import: " + path))
);
})
}
}
const admin = {
register (app) {
if (window.strapi.features.isEnabled(constants.FEATURE_ID)) {
app.registerHook('Admin/CM/pages/ListView/inject-column-in-table', cmHooks.addColumnToTableHook);
const contentManagerPluginApis = app.getPlugin('content-manager').apis;
if ('addEditViewSidePanel' in contentManagerPluginApis && typeof contentManagerPluginApis.addEditViewSidePanel === 'function') {
contentManagerPluginApis.addEditViewSidePanel([
Panel.Panel
]);
}
app.addSettingsLink('global', {
id: constants.PLUGIN_ID,
to: `review-workflows`,
intlLabel: {
id: `${constants.PLUGIN_ID}.plugin.name`,
defaultMessage: 'Review Workflows'
},
permissions: [],
async Component () {
const { Router } = await Promise.resolve().then(function () { return require('./router.js'); });
return {
default: Router
};
}
});
} else if (!window.strapi.features.isEnabled(constants.FEATURE_ID) && window.strapi?.flags?.promoteEE) {
app.addSettingsLink('global', {
id: constants.PLUGIN_ID,
to: `purchase-review-workflows`,
intlLabel: {
id: `${constants.PLUGIN_ID}.plugin.name`,
defaultMessage: 'Review Workflows'
},
licenseOnly: true,
permissions: [],
async Component () {
const { PurchaseReviewWorkflows } = await Promise.resolve().then(function () { return require('./routes/purchase-review-workflows.js'); });
return {
default: PurchaseReviewWorkflows
};
}
});
}
},
bootstrap (app) {
if (window.strapi.features.isEnabled(constants.FEATURE_ID)) {
app.getPlugin('content-manager').injectComponent('preview', 'actions', {
name: 'review-workflows-assignee',
Component: Header.Header
});
}
},
async registerTrads ({ locales }) {
const importedTrads = await Promise.all(locales.map((locale)=>{
return __variableDynamicImportRuntime2__(`./translations/${locale}.json`).then(({ default: data })=>{
return {
data: translations.prefixPluginTranslations(data, constants.PLUGIN_ID),
locale
};
}).catch(()=>{
return {
data: {},
locale
};
});
}));
return Promise.resolve(importedTrads);
}
};
module.exports = admin;
//# sourceMappingURL=index.js.map

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,89 @@
import { FEATURE_ID, PLUGIN_ID } from './constants.mjs';
import { Header } from './routes/content-manager/model/id/components/Header.mjs';
import { Panel } from './routes/content-manager/model/id/components/Panel.mjs';
import { addColumnToTableHook } from './utils/cm-hooks.mjs';
import { prefixPluginTranslations } from './utils/translations.mjs';
function __variableDynamicImportRuntime2__(path) {
switch (path) {
case './translations/en.json': return import('./translations/en.json.mjs');
case './translations/uk.json': return import('./translations/uk.json.mjs');
default: return new Promise(function(resolve, reject) {
(typeof queueMicrotask === 'function' ? queueMicrotask : setTimeout)(
reject.bind(null, new Error("Unknown variable dynamic import: " + path))
);
})
}
}
const admin = {
register (app) {
if (window.strapi.features.isEnabled(FEATURE_ID)) {
app.registerHook('Admin/CM/pages/ListView/inject-column-in-table', addColumnToTableHook);
const contentManagerPluginApis = app.getPlugin('content-manager').apis;
if ('addEditViewSidePanel' in contentManagerPluginApis && typeof contentManagerPluginApis.addEditViewSidePanel === 'function') {
contentManagerPluginApis.addEditViewSidePanel([
Panel
]);
}
app.addSettingsLink('global', {
id: PLUGIN_ID,
to: `review-workflows`,
intlLabel: {
id: `${PLUGIN_ID}.plugin.name`,
defaultMessage: 'Review Workflows'
},
permissions: [],
async Component () {
const { Router } = await import('./router.mjs');
return {
default: Router
};
}
});
} else if (!window.strapi.features.isEnabled(FEATURE_ID) && window.strapi?.flags?.promoteEE) {
app.addSettingsLink('global', {
id: PLUGIN_ID,
to: `purchase-review-workflows`,
intlLabel: {
id: `${PLUGIN_ID}.plugin.name`,
defaultMessage: 'Review Workflows'
},
licenseOnly: true,
permissions: [],
async Component () {
const { PurchaseReviewWorkflows } = await import('./routes/purchase-review-workflows.mjs');
return {
default: PurchaseReviewWorkflows
};
}
});
}
},
bootstrap (app) {
if (window.strapi.features.isEnabled(FEATURE_ID)) {
app.getPlugin('content-manager').injectComponent('preview', 'actions', {
name: 'review-workflows-assignee',
Component: Header
});
}
},
async registerTrads ({ locales }) {
const importedTrads = await Promise.all(locales.map((locale)=>{
return __variableDynamicImportRuntime2__(`./translations/${locale}.json`).then(({ default: data })=>{
return {
data: prefixPluginTranslations(data, PLUGIN_ID),
locale
};
}).catch(()=>{
return {
data: {},
locale
};
});
}));
return Promise.resolve(importedTrads);
}
};
export { admin as default };
//# sourceMappingURL=index.mjs.map

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,8 @@
'use strict';
var reactRedux = require('react-redux');
const useTypedSelector = reactRedux.useSelector;
exports.useTypedSelector = useTypedSelector;
//# sourceMappingURL=hooks.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"hooks.js","sources":["../../../admin/src/modules/hooks.ts"],"sourcesContent":["import { Dispatch } from '@reduxjs/toolkit';\nimport { TypedUseSelectorHook, useDispatch, useSelector } from 'react-redux';\n\nimport type { Store } from '@strapi/admin/strapi-admin';\n\ntype RootState = ReturnType<Store['getState']>;\n\nconst useTypedDispatch: () => Dispatch = useDispatch;\nconst useTypedSelector: TypedUseSelectorHook<RootState> = useSelector;\n\nexport { useTypedSelector, useTypedDispatch };\n"],"names":["useTypedSelector","useSelector"],"mappings":";;;;AAQA,MAAMA,gBAAoDC,GAAAA;;;;"}

View File

@@ -0,0 +1,6 @@
import { useSelector } from 'react-redux';
const useTypedSelector = useSelector;
export { useTypedSelector };
//# sourceMappingURL=hooks.mjs.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"hooks.mjs","sources":["../../../admin/src/modules/hooks.ts"],"sourcesContent":["import { Dispatch } from '@reduxjs/toolkit';\nimport { TypedUseSelectorHook, useDispatch, useSelector } from 'react-redux';\n\nimport type { Store } from '@strapi/admin/strapi-admin';\n\ntype RootState = ReturnType<Store['getState']>;\n\nconst useTypedDispatch: () => Dispatch = useDispatch;\nconst useTypedSelector: TypedUseSelectorHook<RootState> = useSelector;\n\nexport { useTypedSelector, useTypedDispatch };\n"],"names":["useTypedSelector","useSelector"],"mappings":";;AAQA,MAAMA,gBAAoDC,GAAAA;;;;"}

View File

@@ -0,0 +1,30 @@
'use strict';
var jsxRuntime = require('react/jsx-runtime');
var React = require('react');
var reactRouterDom = require('react-router-dom');
const ProtectedListPage = /*#__PURE__*/ React.lazy(()=>Promise.resolve().then(function () { return require('./routes/settings/index.js'); }).then((mod)=>({
default: mod.ProtectedListPage
})));
const ProtectedEditPage = /*#__PURE__*/ React.lazy(()=>Promise.resolve().then(function () { return require('./routes/settings/id.js'); }).then((mod)=>({
default: mod.ProtectedEditPage
})));
const routes = [
{
path: '/',
Component: ProtectedListPage
},
{
path: ':id',
Component: ProtectedEditPage
}
];
const Router = ()=>/*#__PURE__*/ jsxRuntime.jsx(reactRouterDom.Routes, {
children: routes.map((route)=>/*#__PURE__*/ jsxRuntime.jsx(reactRouterDom.Route, {
...route
}, route.path))
});
exports.Router = Router;
//# sourceMappingURL=router.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"router.js","sources":["../../admin/src/router.tsx"],"sourcesContent":["/* eslint-disable check-file/filename-naming-convention */\nimport { lazy } from 'react';\n\nimport { Routes, Route, PathRouteProps } from 'react-router-dom';\n\nconst ProtectedListPage = lazy(() =>\n import('./routes/settings').then((mod) => ({ default: mod.ProtectedListPage }))\n);\nconst ProtectedEditPage = lazy(() =>\n import('./routes/settings/id').then((mod) => ({ default: mod.ProtectedEditPage }))\n);\n\nconst routes: PathRouteProps[] = [\n {\n path: '/',\n Component: ProtectedListPage,\n },\n {\n path: ':id',\n Component: ProtectedEditPage,\n },\n];\n\nconst Router = () => (\n <Routes>\n {routes.map((route) => (\n <Route key={route.path} {...route} />\n ))}\n </Routes>\n);\n\nexport { Router };\n"],"names":["ProtectedListPage","lazy","then","mod","default","ProtectedEditPage","routes","path","Component","Router","_jsx","Routes","map","route","Route"],"mappings":";;;;;;AAKA,MAAMA,iBAAAA,iBAAoBC,UAAK,CAAA,IAC7B,oDAAO,kCAAqBC,IAAI,CAAC,CAACC,GAAAA,IAAS;AAAEC,YAAAA,OAAAA,EAASD,IAAIH;SAAkB,CAAA,CAAA,CAAA;AAE9E,MAAMK,iBAAAA,iBAAoBJ,UAAK,CAAA,IAC7B,oDAAO,+BAAwBC,IAAI,CAAC,CAACC,GAAAA,IAAS;AAAEC,YAAAA,OAAAA,EAASD,IAAIE;SAAkB,CAAA,CAAA,CAAA;AAGjF,MAAMC,MAA2B,GAAA;AAC/B,IAAA;QACEC,IAAM,EAAA,GAAA;QACNC,SAAWR,EAAAA;AACb,KAAA;AACA,IAAA;QACEO,IAAM,EAAA,KAAA;QACNC,SAAWH,EAAAA;AACb;AACD,CAAA;AAEKI,MAAAA,MAAAA,GAAS,kBACbC,cAACC,CAAAA,qBAAAA,EAAAA;AACEL,QAAAA,QAAAA,EAAAA,MAAAA,CAAOM,GAAG,CAAC,CAACC,KAAAA,iBACXH,cAACI,CAAAA,oBAAAA,EAAAA;AAAwB,gBAAA,GAAGD;AAAhBA,aAAAA,EAAAA,KAAAA,CAAMN,IAAI,CAAA;;;;;"}

View File

@@ -0,0 +1,28 @@
import { jsx } from 'react/jsx-runtime';
import { lazy } from 'react';
import { Routes, Route } from 'react-router-dom';
const ProtectedListPage = /*#__PURE__*/ lazy(()=>import('./routes/settings/index.mjs').then((mod)=>({
default: mod.ProtectedListPage
})));
const ProtectedEditPage = /*#__PURE__*/ lazy(()=>import('./routes/settings/id.mjs').then((mod)=>({
default: mod.ProtectedEditPage
})));
const routes = [
{
path: '/',
Component: ProtectedListPage
},
{
path: ':id',
Component: ProtectedEditPage
}
];
const Router = ()=>/*#__PURE__*/ jsx(Routes, {
children: routes.map((route)=>/*#__PURE__*/ jsx(Route, {
...route
}, route.path))
});
export { Router };
//# sourceMappingURL=router.mjs.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"router.mjs","sources":["../../admin/src/router.tsx"],"sourcesContent":["/* eslint-disable check-file/filename-naming-convention */\nimport { lazy } from 'react';\n\nimport { Routes, Route, PathRouteProps } from 'react-router-dom';\n\nconst ProtectedListPage = lazy(() =>\n import('./routes/settings').then((mod) => ({ default: mod.ProtectedListPage }))\n);\nconst ProtectedEditPage = lazy(() =>\n import('./routes/settings/id').then((mod) => ({ default: mod.ProtectedEditPage }))\n);\n\nconst routes: PathRouteProps[] = [\n {\n path: '/',\n Component: ProtectedListPage,\n },\n {\n path: ':id',\n Component: ProtectedEditPage,\n },\n];\n\nconst Router = () => (\n <Routes>\n {routes.map((route) => (\n <Route key={route.path} {...route} />\n ))}\n </Routes>\n);\n\nexport { Router };\n"],"names":["ProtectedListPage","lazy","then","mod","default","ProtectedEditPage","routes","path","Component","Router","_jsx","Routes","map","route","Route"],"mappings":";;;;AAKA,MAAMA,iBAAAA,iBAAoBC,IAAK,CAAA,IAC7B,OAAO,+BAAqBC,IAAI,CAAC,CAACC,GAAAA,IAAS;AAAEC,YAAAA,OAAAA,EAASD,IAAIH;SAAkB,CAAA,CAAA,CAAA;AAE9E,MAAMK,iBAAAA,iBAAoBJ,IAAK,CAAA,IAC7B,OAAO,4BAAwBC,IAAI,CAAC,CAACC,GAAAA,IAAS;AAAEC,YAAAA,OAAAA,EAASD,IAAIE;SAAkB,CAAA,CAAA,CAAA;AAGjF,MAAMC,MAA2B,GAAA;AAC/B,IAAA;QACEC,IAAM,EAAA,GAAA;QACNC,SAAWR,EAAAA;AACb,KAAA;AACA,IAAA;QACEO,IAAM,EAAA,KAAA;QACNC,SAAWH,EAAAA;AACb;AACD,CAAA;AAEKI,MAAAA,MAAAA,GAAS,kBACbC,GAACC,CAAAA,MAAAA,EAAAA;AACEL,QAAAA,QAAAA,EAAAA,MAAAA,CAAOM,GAAG,CAAC,CAACC,KAAAA,iBACXH,GAACI,CAAAA,KAAAA,EAAAA;AAAwB,gBAAA,GAAGD;AAAhBA,aAAAA,EAAAA,KAAAA,CAAMN,IAAI,CAAA;;;;;"}

View File

@@ -0,0 +1,44 @@
'use strict';
var jsxRuntime = require('react/jsx-runtime');
var designSystem = require('@strapi/design-system');
var constants = require('../../../../constants.js');
var colors = require('../../../../utils/colors.js');
var users = require('../../../../utils/users.js');
const StageColumn = (props)=>{
const { color = constants.STAGE_COLOR_DEFAULT, name } = props.strapi_stage ?? {};
const { themeColorName } = colors.getStageColorByHex(color) ?? {};
return /*#__PURE__*/ jsxRuntime.jsxs(designSystem.Flex, {
alignItems: "center",
gap: 2,
maxWidth: "30rem",
children: [
/*#__PURE__*/ jsxRuntime.jsx(designSystem.Box, {
height: 2,
background: color,
borderColor: themeColorName === 'neutral0' ? 'neutral150' : undefined,
hasRadius: true,
shrink: 0,
width: 2
}),
/*#__PURE__*/ jsxRuntime.jsx(designSystem.Typography, {
fontWeight: "regular",
textColor: "neutral700",
ellipsis: true,
children: name
})
]
});
};
const AssigneeColumn = (props)=>{
const { strapi_assignee: user } = props;
return /*#__PURE__*/ jsxRuntime.jsx(designSystem.Typography, {
textColor: "neutral800",
children: user ? users.getDisplayName(user) : '-'
});
};
exports.AssigneeColumn = AssigneeColumn;
exports.StageColumn = StageColumn;
//# sourceMappingURL=TableColumns.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"TableColumns.js","sources":["../../../../../../admin/src/routes/content-manager/model/components/TableColumns.tsx"],"sourcesContent":["import { SanitizedAdminUser } from '@strapi/admin/strapi-admin';\nimport { Box, Flex, Typography } from '@strapi/design-system';\n\nimport { STAGE_COLOR_DEFAULT } from '../../../../constants';\nimport { getStageColorByHex } from '../../../../utils/colors';\nimport { getDisplayName } from '../../../../utils/users';\n\ninterface StageColumnProps {\n documentId?: string;\n id?: number;\n strapi_stage?: {\n color?: string;\n name: string;\n };\n}\n\nconst StageColumn = (props: StageColumnProps) => {\n const { color = STAGE_COLOR_DEFAULT, name } = props.strapi_stage ?? {};\n const { themeColorName } = getStageColorByHex(color) ?? {};\n\n return (\n <Flex alignItems=\"center\" gap={2} maxWidth=\"30rem\">\n <Box\n height={2}\n background={color}\n borderColor={themeColorName === 'neutral0' ? 'neutral150' : undefined}\n hasRadius\n shrink={0}\n width={2}\n />\n\n <Typography fontWeight=\"regular\" textColor=\"neutral700\" ellipsis>\n {name}\n </Typography>\n </Flex>\n );\n};\n\ninterface AssigneeColumnProps {\n documentId?: string;\n id?: number;\n strapi_assignee?: Pick<\n SanitizedAdminUser,\n 'firstname' | 'lastname' | 'username' | 'email'\n > | null;\n}\n\nconst AssigneeColumn = (props: AssigneeColumnProps) => {\n const { strapi_assignee: user } = props;\n return <Typography textColor=\"neutral800\">{user ? getDisplayName(user) : '-'}</Typography>;\n};\n\nexport { StageColumn, AssigneeColumn };\nexport type { StageColumnProps, AssigneeColumnProps };\n"],"names":["StageColumn","props","color","STAGE_COLOR_DEFAULT","name","strapi_stage","themeColorName","getStageColorByHex","_jsxs","Flex","alignItems","gap","maxWidth","_jsx","Box","height","background","borderColor","undefined","hasRadius","shrink","width","Typography","fontWeight","textColor","ellipsis","AssigneeColumn","strapi_assignee","user","getDisplayName"],"mappings":";;;;;;;;AAgBA,MAAMA,cAAc,CAACC,KAAAA,GAAAA;IACnB,MAAM,EAAEC,KAAQC,GAAAA,6BAAmB,EAAEC,IAAI,EAAE,GAAGH,KAAAA,CAAMI,YAAY,IAAI,EAAC;AACrE,IAAA,MAAM,EAAEC,cAAc,EAAE,GAAGC,yBAAAA,CAAmBL,UAAU,EAAC;AAEzD,IAAA,qBACEM,eAACC,CAAAA,iBAAAA,EAAAA;QAAKC,UAAW,EAAA,QAAA;QAASC,GAAK,EAAA,CAAA;QAAGC,QAAS,EAAA,OAAA;;0BACzCC,cAACC,CAAAA,gBAAAA,EAAAA;gBACCC,MAAQ,EAAA,CAAA;gBACRC,UAAYd,EAAAA,KAAAA;gBACZe,WAAaX,EAAAA,cAAAA,KAAmB,aAAa,YAAeY,GAAAA,SAAAA;gBAC5DC,SAAS,EAAA,IAAA;gBACTC,MAAQ,EAAA,CAAA;gBACRC,KAAO,EAAA;;0BAGTR,cAACS,CAAAA,uBAAAA,EAAAA;gBAAWC,UAAW,EAAA,SAAA;gBAAUC,SAAU,EAAA,YAAA;gBAAaC,QAAQ,EAAA,IAAA;AAC7DrB,gBAAAA,QAAAA,EAAAA;;;;AAIT;AAWA,MAAMsB,iBAAiB,CAACzB,KAAAA,GAAAA;AACtB,IAAA,MAAM,EAAE0B,eAAAA,EAAiBC,IAAI,EAAE,GAAG3B,KAAAA;AAClC,IAAA,qBAAOY,cAACS,CAAAA,uBAAAA,EAAAA;QAAWE,SAAU,EAAA,YAAA;AAAcI,QAAAA,QAAAA,EAAAA,IAAAA,GAAOC,qBAAeD,IAAQ,CAAA,GAAA;;AAC3E;;;;;"}

View File

@@ -0,0 +1,41 @@
import { jsxs, jsx } from 'react/jsx-runtime';
import { Flex, Box, Typography } from '@strapi/design-system';
import { STAGE_COLOR_DEFAULT } from '../../../../constants.mjs';
import { getStageColorByHex } from '../../../../utils/colors.mjs';
import { getDisplayName } from '../../../../utils/users.mjs';
const StageColumn = (props)=>{
const { color = STAGE_COLOR_DEFAULT, name } = props.strapi_stage ?? {};
const { themeColorName } = getStageColorByHex(color) ?? {};
return /*#__PURE__*/ jsxs(Flex, {
alignItems: "center",
gap: 2,
maxWidth: "30rem",
children: [
/*#__PURE__*/ jsx(Box, {
height: 2,
background: color,
borderColor: themeColorName === 'neutral0' ? 'neutral150' : undefined,
hasRadius: true,
shrink: 0,
width: 2
}),
/*#__PURE__*/ jsx(Typography, {
fontWeight: "regular",
textColor: "neutral700",
ellipsis: true,
children: name
})
]
});
};
const AssigneeColumn = (props)=>{
const { strapi_assignee: user } = props;
return /*#__PURE__*/ jsx(Typography, {
textColor: "neutral800",
children: user ? getDisplayName(user) : '-'
});
};
export { AssigneeColumn, StageColumn };
//# sourceMappingURL=TableColumns.mjs.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"TableColumns.mjs","sources":["../../../../../../admin/src/routes/content-manager/model/components/TableColumns.tsx"],"sourcesContent":["import { SanitizedAdminUser } from '@strapi/admin/strapi-admin';\nimport { Box, Flex, Typography } from '@strapi/design-system';\n\nimport { STAGE_COLOR_DEFAULT } from '../../../../constants';\nimport { getStageColorByHex } from '../../../../utils/colors';\nimport { getDisplayName } from '../../../../utils/users';\n\ninterface StageColumnProps {\n documentId?: string;\n id?: number;\n strapi_stage?: {\n color?: string;\n name: string;\n };\n}\n\nconst StageColumn = (props: StageColumnProps) => {\n const { color = STAGE_COLOR_DEFAULT, name } = props.strapi_stage ?? {};\n const { themeColorName } = getStageColorByHex(color) ?? {};\n\n return (\n <Flex alignItems=\"center\" gap={2} maxWidth=\"30rem\">\n <Box\n height={2}\n background={color}\n borderColor={themeColorName === 'neutral0' ? 'neutral150' : undefined}\n hasRadius\n shrink={0}\n width={2}\n />\n\n <Typography fontWeight=\"regular\" textColor=\"neutral700\" ellipsis>\n {name}\n </Typography>\n </Flex>\n );\n};\n\ninterface AssigneeColumnProps {\n documentId?: string;\n id?: number;\n strapi_assignee?: Pick<\n SanitizedAdminUser,\n 'firstname' | 'lastname' | 'username' | 'email'\n > | null;\n}\n\nconst AssigneeColumn = (props: AssigneeColumnProps) => {\n const { strapi_assignee: user } = props;\n return <Typography textColor=\"neutral800\">{user ? getDisplayName(user) : '-'}</Typography>;\n};\n\nexport { StageColumn, AssigneeColumn };\nexport type { StageColumnProps, AssigneeColumnProps };\n"],"names":["StageColumn","props","color","STAGE_COLOR_DEFAULT","name","strapi_stage","themeColorName","getStageColorByHex","_jsxs","Flex","alignItems","gap","maxWidth","_jsx","Box","height","background","borderColor","undefined","hasRadius","shrink","width","Typography","fontWeight","textColor","ellipsis","AssigneeColumn","strapi_assignee","user","getDisplayName"],"mappings":";;;;;;AAgBA,MAAMA,cAAc,CAACC,KAAAA,GAAAA;IACnB,MAAM,EAAEC,KAAQC,GAAAA,mBAAmB,EAAEC,IAAI,EAAE,GAAGH,KAAAA,CAAMI,YAAY,IAAI,EAAC;AACrE,IAAA,MAAM,EAAEC,cAAc,EAAE,GAAGC,kBAAAA,CAAmBL,UAAU,EAAC;AAEzD,IAAA,qBACEM,IAACC,CAAAA,IAAAA,EAAAA;QAAKC,UAAW,EAAA,QAAA;QAASC,GAAK,EAAA,CAAA;QAAGC,QAAS,EAAA,OAAA;;0BACzCC,GAACC,CAAAA,GAAAA,EAAAA;gBACCC,MAAQ,EAAA,CAAA;gBACRC,UAAYd,EAAAA,KAAAA;gBACZe,WAAaX,EAAAA,cAAAA,KAAmB,aAAa,YAAeY,GAAAA,SAAAA;gBAC5DC,SAAS,EAAA,IAAA;gBACTC,MAAQ,EAAA,CAAA;gBACRC,KAAO,EAAA;;0BAGTR,GAACS,CAAAA,UAAAA,EAAAA;gBAAWC,UAAW,EAAA,SAAA;gBAAUC,SAAU,EAAA,YAAA;gBAAaC,QAAQ,EAAA,IAAA;AAC7DrB,gBAAAA,QAAAA,EAAAA;;;;AAIT;AAWA,MAAMsB,iBAAiB,CAACzB,KAAAA,GAAAA;AACtB,IAAA,MAAM,EAAE0B,eAAAA,EAAiBC,IAAI,EAAE,GAAG3B,KAAAA;AAClC,IAAA,qBAAOY,GAACS,CAAAA,UAAAA,EAAAA;QAAWE,SAAU,EAAA,YAAA;AAAcI,QAAAA,QAAAA,EAAAA,IAAAA,GAAOC,eAAeD,IAAQ,CAAA,GAAA;;AAC3E;;;;"}

View File

@@ -0,0 +1,60 @@
'use strict';
var jsxRuntime = require('react/jsx-runtime');
require('react');
require('@strapi/admin/strapi-admin');
require('@strapi/design-system');
require('react-intl');
require('react-router-dom');
require('../../../utils/colors.js');
require('../../../services/settings.js');
var TableColumns = require('./components/TableColumns.js');
var constants = require('./id/components/constants.js');
const REVIEW_WORKFLOW_COLUMNS = [
{
name: constants.STAGE_ATTRIBUTE_NAME,
attribute: {
type: 'relation',
relation: 'oneToMany',
target: 'admin::review-workflow-stage'
},
label: {
id: 'review-workflows.containers.list.table-headers.reviewWorkflows.stage',
defaultMessage: 'Review stage'
},
searchable: false,
sortable: true,
mainField: {
name: 'name',
type: 'string'
},
cellFormatter: (props)=>/*#__PURE__*/ jsxRuntime.jsx(TableColumns.StageColumn, {
...props
})
},
{
name: constants.ASSIGNEE_ATTRIBUTE_NAME,
attribute: {
type: 'relation',
target: 'admin::user',
relation: 'oneToMany'
},
label: {
id: 'review-workflows.containers.list.table-headers.reviewWorkflows.assignee',
defaultMessage: 'Assignee'
},
searchable: false,
sortable: true,
mainField: {
name: 'firstname',
type: 'string'
},
cellFormatter: (props)=>/*#__PURE__*/ jsxRuntime.jsx(TableColumns.AssigneeColumn, {
...props
})
}
];
exports.REVIEW_WORKFLOW_COLUMNS = REVIEW_WORKFLOW_COLUMNS;
//# sourceMappingURL=constants.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"constants.js","sources":["../../../../../admin/src/routes/content-manager/model/constants.tsx"],"sourcesContent":["import { AssigneeFilter } from './components/AssigneeFilter';\nimport { StageFilter } from './components/StageFilter';\nimport { AssigneeColumn, StageColumn } from './components/TableColumns';\nimport { ASSIGNEE_ATTRIBUTE_NAME, STAGE_ATTRIBUTE_NAME } from './id/components/constants';\n\nimport type { Filters } from '@strapi/admin/strapi-admin';\nimport type { ListFieldLayout } from '@strapi/content-manager/strapi-admin';\nimport type { MessageDescriptor } from 'react-intl';\n\nexport const REVIEW_WORKFLOW_COLUMNS = [\n {\n name: STAGE_ATTRIBUTE_NAME,\n attribute: {\n type: 'relation',\n relation: 'oneToMany',\n target: 'admin::review-workflow-stage',\n },\n label: {\n id: 'review-workflows.containers.list.table-headers.reviewWorkflows.stage',\n defaultMessage: 'Review stage',\n },\n searchable: false,\n sortable: true,\n mainField: {\n name: 'name',\n type: 'string',\n },\n cellFormatter: (props) => <StageColumn {...props} />,\n },\n {\n name: ASSIGNEE_ATTRIBUTE_NAME,\n attribute: {\n type: 'relation',\n target: 'admin::user',\n relation: 'oneToMany',\n },\n label: {\n id: 'review-workflows.containers.list.table-headers.reviewWorkflows.assignee',\n defaultMessage: 'Assignee',\n },\n searchable: false,\n sortable: true,\n mainField: {\n name: 'firstname',\n type: 'string',\n },\n cellFormatter: (props) => <AssigneeColumn {...props} />,\n },\n] satisfies Array<Omit<ListFieldLayout, 'label'> & { label: MessageDescriptor }>;\n\nexport const REVIEW_WORKFLOW_FILTERS = [\n {\n mainField: {\n name: 'name',\n type: 'string',\n },\n input: StageFilter,\n label: {\n id: 'review-workflows.containers.list.table-headers.reviewWorkflows.stage',\n defaultMessage: 'Review stage',\n },\n name: 'strapi_stage',\n type: 'relation',\n },\n\n {\n type: 'relation',\n mainField: {\n name: 'id',\n type: 'integer',\n },\n input: AssigneeFilter,\n operators: [\n {\n label: {\n id: 'components.FilterOptions.FILTER_TYPES.$eq',\n defaultMessage: 'is',\n },\n value: '$eq',\n },\n {\n label: {\n id: 'components.FilterOptions.FILTER_TYPES.$ne',\n defaultMessage: 'is not',\n },\n value: '$ne',\n },\n ],\n label: {\n id: 'review-workflows.containers.list.table-headers.reviewWorkflows.assignee.label',\n defaultMessage: 'Assignee',\n },\n name: 'strapi_assignee',\n },\n] satisfies Array<\n Omit<Filters.Filter, 'label' | 'operators'> & {\n label: MessageDescriptor;\n operators?: Array<{ value: string; label: MessageDescriptor }>;\n }\n>;\n"],"names":["REVIEW_WORKFLOW_COLUMNS","name","STAGE_ATTRIBUTE_NAME","attribute","type","relation","target","label","id","defaultMessage","searchable","sortable","mainField","cellFormatter","props","_jsx","StageColumn","ASSIGNEE_ATTRIBUTE_NAME","AssigneeColumn"],"mappings":";;;;;;;;;;;;;MASaA,uBAA0B,GAAA;AACrC,IAAA;QACEC,IAAMC,EAAAA,8BAAAA;QACNC,SAAW,EAAA;YACTC,IAAM,EAAA,UAAA;YACNC,QAAU,EAAA,WAAA;YACVC,MAAQ,EAAA;AACV,SAAA;QACAC,KAAO,EAAA;YACLC,EAAI,EAAA,sEAAA;YACJC,cAAgB,EAAA;AAClB,SAAA;QACAC,UAAY,EAAA,KAAA;QACZC,QAAU,EAAA,IAAA;QACVC,SAAW,EAAA;YACTX,IAAM,EAAA,MAAA;YACNG,IAAM,EAAA;AACR,SAAA;QACAS,aAAe,EAAA,CAACC,sBAAUC,cAACC,CAAAA,wBAAAA,EAAAA;AAAa,gBAAA,GAAGF;;AAC7C,KAAA;AACA,IAAA;QACEb,IAAMgB,EAAAA,iCAAAA;QACNd,SAAW,EAAA;YACTC,IAAM,EAAA,UAAA;YACNE,MAAQ,EAAA,aAAA;YACRD,QAAU,EAAA;AACZ,SAAA;QACAE,KAAO,EAAA;YACLC,EAAI,EAAA,yEAAA;YACJC,cAAgB,EAAA;AAClB,SAAA;QACAC,UAAY,EAAA,KAAA;QACZC,QAAU,EAAA,IAAA;QACVC,SAAW,EAAA;YACTX,IAAM,EAAA,WAAA;YACNG,IAAM,EAAA;AACR,SAAA;QACAS,aAAe,EAAA,CAACC,sBAAUC,cAACG,CAAAA,2BAAAA,EAAAA;AAAgB,gBAAA,GAAGJ;;AAChD;;;;;"}

View File

@@ -0,0 +1,58 @@
import { jsx } from 'react/jsx-runtime';
import 'react';
import '@strapi/admin/strapi-admin';
import '@strapi/design-system';
import 'react-intl';
import 'react-router-dom';
import '../../../utils/colors.mjs';
import '../../../services/settings.mjs';
import { StageColumn, AssigneeColumn } from './components/TableColumns.mjs';
import { STAGE_ATTRIBUTE_NAME, ASSIGNEE_ATTRIBUTE_NAME } from './id/components/constants.mjs';
const REVIEW_WORKFLOW_COLUMNS = [
{
name: STAGE_ATTRIBUTE_NAME,
attribute: {
type: 'relation',
relation: 'oneToMany',
target: 'admin::review-workflow-stage'
},
label: {
id: 'review-workflows.containers.list.table-headers.reviewWorkflows.stage',
defaultMessage: 'Review stage'
},
searchable: false,
sortable: true,
mainField: {
name: 'name',
type: 'string'
},
cellFormatter: (props)=>/*#__PURE__*/ jsx(StageColumn, {
...props
})
},
{
name: ASSIGNEE_ATTRIBUTE_NAME,
attribute: {
type: 'relation',
target: 'admin::user',
relation: 'oneToMany'
},
label: {
id: 'review-workflows.containers.list.table-headers.reviewWorkflows.assignee',
defaultMessage: 'Assignee'
},
searchable: false,
sortable: true,
mainField: {
name: 'firstname',
type: 'string'
},
cellFormatter: (props)=>/*#__PURE__*/ jsx(AssigneeColumn, {
...props
})
}
];
export { REVIEW_WORKFLOW_COLUMNS };
//# sourceMappingURL=constants.mjs.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"constants.mjs","sources":["../../../../../admin/src/routes/content-manager/model/constants.tsx"],"sourcesContent":["import { AssigneeFilter } from './components/AssigneeFilter';\nimport { StageFilter } from './components/StageFilter';\nimport { AssigneeColumn, StageColumn } from './components/TableColumns';\nimport { ASSIGNEE_ATTRIBUTE_NAME, STAGE_ATTRIBUTE_NAME } from './id/components/constants';\n\nimport type { Filters } from '@strapi/admin/strapi-admin';\nimport type { ListFieldLayout } from '@strapi/content-manager/strapi-admin';\nimport type { MessageDescriptor } from 'react-intl';\n\nexport const REVIEW_WORKFLOW_COLUMNS = [\n {\n name: STAGE_ATTRIBUTE_NAME,\n attribute: {\n type: 'relation',\n relation: 'oneToMany',\n target: 'admin::review-workflow-stage',\n },\n label: {\n id: 'review-workflows.containers.list.table-headers.reviewWorkflows.stage',\n defaultMessage: 'Review stage',\n },\n searchable: false,\n sortable: true,\n mainField: {\n name: 'name',\n type: 'string',\n },\n cellFormatter: (props) => <StageColumn {...props} />,\n },\n {\n name: ASSIGNEE_ATTRIBUTE_NAME,\n attribute: {\n type: 'relation',\n target: 'admin::user',\n relation: 'oneToMany',\n },\n label: {\n id: 'review-workflows.containers.list.table-headers.reviewWorkflows.assignee',\n defaultMessage: 'Assignee',\n },\n searchable: false,\n sortable: true,\n mainField: {\n name: 'firstname',\n type: 'string',\n },\n cellFormatter: (props) => <AssigneeColumn {...props} />,\n },\n] satisfies Array<Omit<ListFieldLayout, 'label'> & { label: MessageDescriptor }>;\n\nexport const REVIEW_WORKFLOW_FILTERS = [\n {\n mainField: {\n name: 'name',\n type: 'string',\n },\n input: StageFilter,\n label: {\n id: 'review-workflows.containers.list.table-headers.reviewWorkflows.stage',\n defaultMessage: 'Review stage',\n },\n name: 'strapi_stage',\n type: 'relation',\n },\n\n {\n type: 'relation',\n mainField: {\n name: 'id',\n type: 'integer',\n },\n input: AssigneeFilter,\n operators: [\n {\n label: {\n id: 'components.FilterOptions.FILTER_TYPES.$eq',\n defaultMessage: 'is',\n },\n value: '$eq',\n },\n {\n label: {\n id: 'components.FilterOptions.FILTER_TYPES.$ne',\n defaultMessage: 'is not',\n },\n value: '$ne',\n },\n ],\n label: {\n id: 'review-workflows.containers.list.table-headers.reviewWorkflows.assignee.label',\n defaultMessage: 'Assignee',\n },\n name: 'strapi_assignee',\n },\n] satisfies Array<\n Omit<Filters.Filter, 'label' | 'operators'> & {\n label: MessageDescriptor;\n operators?: Array<{ value: string; label: MessageDescriptor }>;\n }\n>;\n"],"names":["REVIEW_WORKFLOW_COLUMNS","name","STAGE_ATTRIBUTE_NAME","attribute","type","relation","target","label","id","defaultMessage","searchable","sortable","mainField","cellFormatter","props","_jsx","StageColumn","ASSIGNEE_ATTRIBUTE_NAME","AssigneeColumn"],"mappings":";;;;;;;;;;;MASaA,uBAA0B,GAAA;AACrC,IAAA;QACEC,IAAMC,EAAAA,oBAAAA;QACNC,SAAW,EAAA;YACTC,IAAM,EAAA,UAAA;YACNC,QAAU,EAAA,WAAA;YACVC,MAAQ,EAAA;AACV,SAAA;QACAC,KAAO,EAAA;YACLC,EAAI,EAAA,sEAAA;YACJC,cAAgB,EAAA;AAClB,SAAA;QACAC,UAAY,EAAA,KAAA;QACZC,QAAU,EAAA,IAAA;QACVC,SAAW,EAAA;YACTX,IAAM,EAAA,MAAA;YACNG,IAAM,EAAA;AACR,SAAA;QACAS,aAAe,EAAA,CAACC,sBAAUC,GAACC,CAAAA,WAAAA,EAAAA;AAAa,gBAAA,GAAGF;;AAC7C,KAAA;AACA,IAAA;QACEb,IAAMgB,EAAAA,uBAAAA;QACNd,SAAW,EAAA;YACTC,IAAM,EAAA,UAAA;YACNE,MAAQ,EAAA,aAAA;YACRD,QAAU,EAAA;AACZ,SAAA;QACAE,KAAO,EAAA;YACLC,EAAI,EAAA,yEAAA;YACJC,cAAgB,EAAA;AAClB,SAAA;QACAC,UAAY,EAAA,KAAA;QACZC,QAAU,EAAA,IAAA;QACVC,SAAW,EAAA;YACTX,IAAM,EAAA,WAAA;YACNG,IAAM,EAAA;AACR,SAAA;QACAS,aAAe,EAAA,CAACC,sBAAUC,GAACG,CAAAA,cAAAA,EAAAA;AAAgB,gBAAA,GAAGJ;;AAChD;;;;;"}

View File

@@ -0,0 +1,169 @@
'use strict';
var jsxRuntime = require('react/jsx-runtime');
var React = require('react');
var strapiAdmin = require('@strapi/admin/strapi-admin');
var strapiAdmin$1 = require('@strapi/content-manager/strapi-admin');
var designSystem = require('@strapi/design-system');
var reactIntl = require('react-intl');
var reactRouterDom = require('react-router-dom');
var hooks = require('../../../../../modules/hooks.js');
var contentManager = require('../../../../../services/content-manager.js');
var api = require('../../../../../utils/api.js');
var users = require('../../../../../utils/users.js');
var constants = require('./constants.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 AssigneeSelect = ({ isCompact })=>{
const { collectionType = '', id, slug: model = '' } = reactRouterDom.useParams();
const permissions = hooks.useTypedSelector((state)=>state.admin_app.permissions);
const { formatMessage } = reactIntl.useIntl();
const { _unstableFormatAPIError: formatAPIError } = strapiAdmin.useAPIErrorHandler();
const { toggleNotification } = strapiAdmin.useNotification();
const { allowedActions: { canRead }, isLoading: isLoadingPermissions } = strapiAdmin.useRBAC(permissions.settings?.users);
const [{ query }] = strapiAdmin.useQueryParams();
const params = React__namespace.useMemo(()=>api.buildValidParams(query), [
query
]);
const { data, isLoading: isLoadingUsers, isError } = strapiAdmin.useAdminUsers(undefined, {
skip: isLoadingPermissions || !canRead
});
const { document } = strapiAdmin$1.unstable_useDocument({
collectionType,
model,
documentId: id
}, {
skip: !id && collectionType !== 'single-types'
});
const users$1 = data?.users || [];
const currentAssignee = document ? document[constants.ASSIGNEE_ATTRIBUTE_NAME] : null;
const [updateAssignee, { error, isLoading: isMutating }] = contentManager.useUpdateAssigneeMutation();
if (!collectionType || !model || !document?.documentId) {
return null;
}
const handleChange = async (assigneeId)=>{
// a simple way to avoid erroneous updates
if (currentAssignee?.id === assigneeId) {
return;
}
const res = await updateAssignee({
slug: collectionType,
model,
id: document.documentId,
params,
data: {
id: assigneeId ? parseInt(assigneeId, 10) : null
}
});
if ('data' in res) {
toggleNotification({
type: 'success',
message: formatMessage({
id: 'content-manager.reviewWorkflows.assignee.notification.saved',
defaultMessage: 'Assignee updated'
})
});
}
if (isCompact && 'error' in res) {
toggleNotification({
type: 'danger',
message: formatAPIError(res.error)
});
}
};
const isDisabled = !isLoadingPermissions && !isLoadingUsers && users$1.length === 0 || !document.documentId;
const isLoading = isLoadingUsers || isLoadingPermissions || isMutating;
const assigneeLabel = formatMessage({
id: 'content-manager.reviewWorkflows.assignee.label',
defaultMessage: 'Assignee'
});
const assigneeClearLabel = formatMessage({
id: 'content-manager.reviewWorkflows.assignee.clear',
defaultMessage: 'Clear assignee'
});
const assigneePlaceholder = formatMessage({
id: 'content-manager.reviewWorkflows.assignee.placeholder',
defaultMessage: 'Select…'
});
if (isCompact) {
return /*#__PURE__*/ jsxRuntime.jsxs(designSystem.Field.Root, {
name: constants.ASSIGNEE_ATTRIBUTE_NAME,
id: constants.ASSIGNEE_ATTRIBUTE_NAME,
children: [
/*#__PURE__*/ jsxRuntime.jsx(designSystem.VisuallyHidden, {
children: /*#__PURE__*/ jsxRuntime.jsx(designSystem.Field.Label, {
children: assigneeLabel
})
}),
/*#__PURE__*/ jsxRuntime.jsx(designSystem.Combobox, {
clearLabel: assigneeClearLabel,
disabled: isDisabled,
value: currentAssignee ? currentAssignee.id.toString() : null,
onChange: handleChange,
onClear: ()=>handleChange(null),
placeholder: assigneePlaceholder,
loading: isLoading || isLoadingPermissions || isMutating,
size: "S",
children: users$1.map((user)=>{
return /*#__PURE__*/ jsxRuntime.jsx(designSystem.ComboboxOption, {
value: user.id.toString(),
textValue: users.getDisplayName(user),
children: users.getDisplayName(user)
}, user.id);
})
})
]
});
}
return /*#__PURE__*/ jsxRuntime.jsxs(designSystem.Field.Root, {
name: constants.ASSIGNEE_ATTRIBUTE_NAME,
id: constants.ASSIGNEE_ATTRIBUTE_NAME,
error: (isError && canRead && formatMessage({
id: 'content-manager.reviewWorkflows.assignee.error',
defaultMessage: 'An error occurred while fetching users'
}) || error && formatAPIError(error)) ?? undefined,
children: [
/*#__PURE__*/ jsxRuntime.jsx(designSystem.Field.Label, {
children: assigneeLabel
}),
/*#__PURE__*/ jsxRuntime.jsx(designSystem.Combobox, {
clearLabel: assigneeClearLabel,
disabled: !isLoadingPermissions && !isLoading && users$1.length === 0 || !document.documentId,
value: currentAssignee ? currentAssignee.id.toString() : null,
onChange: handleChange,
onClear: ()=>handleChange(null),
placeholder: assigneePlaceholder,
loading: isLoading || isLoadingPermissions || isMutating,
children: users$1.map((user)=>{
return /*#__PURE__*/ jsxRuntime.jsx(designSystem.ComboboxOption, {
value: user.id.toString(),
textValue: users.getDisplayName(user),
children: users.getDisplayName(user)
}, user.id);
})
}),
/*#__PURE__*/ jsxRuntime.jsx(designSystem.Field.Error, {})
]
});
};
exports.AssigneeSelect = AssigneeSelect;
//# sourceMappingURL=AssigneeSelect.js.map

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,148 @@
import { jsxs, jsx } from 'react/jsx-runtime';
import * as React from 'react';
import { useAPIErrorHandler, useNotification, useRBAC, useQueryParams, useAdminUsers } from '@strapi/admin/strapi-admin';
import { unstable_useDocument } from '@strapi/content-manager/strapi-admin';
import { Field, VisuallyHidden, Combobox, ComboboxOption } from '@strapi/design-system';
import { useIntl } from 'react-intl';
import { useParams } from 'react-router-dom';
import { useTypedSelector } from '../../../../../modules/hooks.mjs';
import { useUpdateAssigneeMutation } from '../../../../../services/content-manager.mjs';
import { buildValidParams } from '../../../../../utils/api.mjs';
import { getDisplayName } from '../../../../../utils/users.mjs';
import { ASSIGNEE_ATTRIBUTE_NAME } from './constants.mjs';
const AssigneeSelect = ({ isCompact })=>{
const { collectionType = '', id, slug: model = '' } = useParams();
const permissions = useTypedSelector((state)=>state.admin_app.permissions);
const { formatMessage } = useIntl();
const { _unstableFormatAPIError: formatAPIError } = useAPIErrorHandler();
const { toggleNotification } = useNotification();
const { allowedActions: { canRead }, isLoading: isLoadingPermissions } = useRBAC(permissions.settings?.users);
const [{ query }] = useQueryParams();
const params = React.useMemo(()=>buildValidParams(query), [
query
]);
const { data, isLoading: isLoadingUsers, isError } = useAdminUsers(undefined, {
skip: isLoadingPermissions || !canRead
});
const { document } = unstable_useDocument({
collectionType,
model,
documentId: id
}, {
skip: !id && collectionType !== 'single-types'
});
const users = data?.users || [];
const currentAssignee = document ? document[ASSIGNEE_ATTRIBUTE_NAME] : null;
const [updateAssignee, { error, isLoading: isMutating }] = useUpdateAssigneeMutation();
if (!collectionType || !model || !document?.documentId) {
return null;
}
const handleChange = async (assigneeId)=>{
// a simple way to avoid erroneous updates
if (currentAssignee?.id === assigneeId) {
return;
}
const res = await updateAssignee({
slug: collectionType,
model,
id: document.documentId,
params,
data: {
id: assigneeId ? parseInt(assigneeId, 10) : null
}
});
if ('data' in res) {
toggleNotification({
type: 'success',
message: formatMessage({
id: 'content-manager.reviewWorkflows.assignee.notification.saved',
defaultMessage: 'Assignee updated'
})
});
}
if (isCompact && 'error' in res) {
toggleNotification({
type: 'danger',
message: formatAPIError(res.error)
});
}
};
const isDisabled = !isLoadingPermissions && !isLoadingUsers && users.length === 0 || !document.documentId;
const isLoading = isLoadingUsers || isLoadingPermissions || isMutating;
const assigneeLabel = formatMessage({
id: 'content-manager.reviewWorkflows.assignee.label',
defaultMessage: 'Assignee'
});
const assigneeClearLabel = formatMessage({
id: 'content-manager.reviewWorkflows.assignee.clear',
defaultMessage: 'Clear assignee'
});
const assigneePlaceholder = formatMessage({
id: 'content-manager.reviewWorkflows.assignee.placeholder',
defaultMessage: 'Select…'
});
if (isCompact) {
return /*#__PURE__*/ jsxs(Field.Root, {
name: ASSIGNEE_ATTRIBUTE_NAME,
id: ASSIGNEE_ATTRIBUTE_NAME,
children: [
/*#__PURE__*/ jsx(VisuallyHidden, {
children: /*#__PURE__*/ jsx(Field.Label, {
children: assigneeLabel
})
}),
/*#__PURE__*/ jsx(Combobox, {
clearLabel: assigneeClearLabel,
disabled: isDisabled,
value: currentAssignee ? currentAssignee.id.toString() : null,
onChange: handleChange,
onClear: ()=>handleChange(null),
placeholder: assigneePlaceholder,
loading: isLoading || isLoadingPermissions || isMutating,
size: "S",
children: users.map((user)=>{
return /*#__PURE__*/ jsx(ComboboxOption, {
value: user.id.toString(),
textValue: getDisplayName(user),
children: getDisplayName(user)
}, user.id);
})
})
]
});
}
return /*#__PURE__*/ jsxs(Field.Root, {
name: ASSIGNEE_ATTRIBUTE_NAME,
id: ASSIGNEE_ATTRIBUTE_NAME,
error: (isError && canRead && formatMessage({
id: 'content-manager.reviewWorkflows.assignee.error',
defaultMessage: 'An error occurred while fetching users'
}) || error && formatAPIError(error)) ?? undefined,
children: [
/*#__PURE__*/ jsx(Field.Label, {
children: assigneeLabel
}),
/*#__PURE__*/ jsx(Combobox, {
clearLabel: assigneeClearLabel,
disabled: !isLoadingPermissions && !isLoading && users.length === 0 || !document.documentId,
value: currentAssignee ? currentAssignee.id.toString() : null,
onChange: handleChange,
onClear: ()=>handleChange(null),
placeholder: assigneePlaceholder,
loading: isLoading || isLoadingPermissions || isMutating,
children: users.map((user)=>{
return /*#__PURE__*/ jsx(ComboboxOption, {
value: user.id.toString(),
textValue: getDisplayName(user),
children: getDisplayName(user)
}, user.id);
})
}),
/*#__PURE__*/ jsx(Field.Error, {})
]
});
};
export { AssigneeSelect };
//# sourceMappingURL=AssigneeSelect.mjs.map

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,31 @@
'use strict';
var jsxRuntime = require('react/jsx-runtime');
var strapiAdmin = require('@strapi/content-manager/strapi-admin');
var designSystem = require('@strapi/design-system');
var reactRouterDom = require('react-router-dom');
var AssigneeSelect = require('./AssigneeSelect.js');
var StageSelect = require('./StageSelect.js');
const Header = ()=>{
const { slug = '', id, collectionType } = reactRouterDom.useParams();
const { edit: { options } } = strapiAdmin.unstable_useDocumentLayout(slug);
if (!window.strapi.isEE || !options?.reviewWorkflows || collectionType !== 'single-types' && !id || id === 'create') {
return null;
}
return /*#__PURE__*/ jsxRuntime.jsxs(designSystem.Flex, {
gap: 2,
children: [
/*#__PURE__*/ jsxRuntime.jsx(AssigneeSelect.AssigneeSelect, {
isCompact: true
}),
/*#__PURE__*/ jsxRuntime.jsx(StageSelect.StageSelect, {
isCompact: true
})
]
});
};
Header.type = 'preview';
exports.Header = Header;
//# sourceMappingURL=Header.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"Header.js","sources":["../../../../../../../admin/src/routes/content-manager/model/id/components/Header.tsx"],"sourcesContent":["import { unstable_useDocumentLayout as useDocumentLayout } from '@strapi/content-manager/strapi-admin';\nimport { Flex } from '@strapi/design-system';\nimport { useParams } from 'react-router-dom';\n\nimport { AssigneeSelect } from './AssigneeSelect';\nimport { StageSelect } from './StageSelect';\n\nconst Header = () => {\n const {\n slug = '',\n id,\n collectionType,\n } = useParams<{\n collectionType: string;\n slug: string;\n id: string;\n }>();\n\n const {\n edit: { options },\n } = useDocumentLayout(slug);\n\n if (\n !window.strapi.isEE ||\n !options?.reviewWorkflows ||\n (collectionType !== 'single-types' && !id) ||\n id === 'create'\n ) {\n return null;\n }\n\n return (\n <Flex gap={2}>\n <AssigneeSelect isCompact />\n <StageSelect isCompact />\n </Flex>\n );\n};\n\nHeader.type = 'preview';\n\nexport { Header };\n"],"names":["Header","slug","id","collectionType","useParams","edit","options","useDocumentLayout","window","strapi","isEE","reviewWorkflows","_jsxs","Flex","gap","_jsx","AssigneeSelect","isCompact","StageSelect","type"],"mappings":";;;;;;;;;AAOA,MAAMA,MAAS,GAAA,IAAA;IACb,MAAM,EACJC,OAAO,EAAE,EACTC,EAAE,EACFC,cAAc,EACf,GAAGC,wBAAAA,EAAAA;AAMJ,IAAA,MAAM,EACJC,IAAM,EAAA,EAAEC,OAAO,EAAE,EAClB,GAAGC,sCAAkBN,CAAAA,IAAAA,CAAAA;AAEtB,IAAA,IACE,CAACO,MAAAA,CAAOC,MAAM,CAACC,IAAI,IACnB,CAACJ,OAASK,EAAAA,eAAAA,IACTR,cAAmB,KAAA,cAAA,IAAkB,CAACD,EAAAA,IACvCA,OAAO,QACP,EAAA;QACA,OAAO,IAAA;AACT;AAEA,IAAA,qBACEU,eAACC,CAAAA,iBAAAA,EAAAA;QAAKC,GAAK,EAAA,CAAA;;0BACTC,cAACC,CAAAA,6BAAAA,EAAAA;gBAAeC,SAAS,EAAA;;0BACzBF,cAACG,CAAAA,uBAAAA,EAAAA;gBAAYD,SAAS,EAAA;;;;AAG5B;AAEAjB,MAAAA,CAAOmB,IAAI,GAAG,SAAA;;;;"}

View File

@@ -0,0 +1,29 @@
import { jsxs, jsx } from 'react/jsx-runtime';
import { unstable_useDocumentLayout } from '@strapi/content-manager/strapi-admin';
import { Flex } from '@strapi/design-system';
import { useParams } from 'react-router-dom';
import { AssigneeSelect } from './AssigneeSelect.mjs';
import { StageSelect } from './StageSelect.mjs';
const Header = ()=>{
const { slug = '', id, collectionType } = useParams();
const { edit: { options } } = unstable_useDocumentLayout(slug);
if (!window.strapi.isEE || !options?.reviewWorkflows || collectionType !== 'single-types' && !id || id === 'create') {
return null;
}
return /*#__PURE__*/ jsxs(Flex, {
gap: 2,
children: [
/*#__PURE__*/ jsx(AssigneeSelect, {
isCompact: true
}),
/*#__PURE__*/ jsx(StageSelect, {
isCompact: true
})
]
});
};
Header.type = 'preview';
export { Header };
//# sourceMappingURL=Header.mjs.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"Header.mjs","sources":["../../../../../../../admin/src/routes/content-manager/model/id/components/Header.tsx"],"sourcesContent":["import { unstable_useDocumentLayout as useDocumentLayout } from '@strapi/content-manager/strapi-admin';\nimport { Flex } from '@strapi/design-system';\nimport { useParams } from 'react-router-dom';\n\nimport { AssigneeSelect } from './AssigneeSelect';\nimport { StageSelect } from './StageSelect';\n\nconst Header = () => {\n const {\n slug = '',\n id,\n collectionType,\n } = useParams<{\n collectionType: string;\n slug: string;\n id: string;\n }>();\n\n const {\n edit: { options },\n } = useDocumentLayout(slug);\n\n if (\n !window.strapi.isEE ||\n !options?.reviewWorkflows ||\n (collectionType !== 'single-types' && !id) ||\n id === 'create'\n ) {\n return null;\n }\n\n return (\n <Flex gap={2}>\n <AssigneeSelect isCompact />\n <StageSelect isCompact />\n </Flex>\n );\n};\n\nHeader.type = 'preview';\n\nexport { Header };\n"],"names":["Header","slug","id","collectionType","useParams","edit","options","useDocumentLayout","window","strapi","isEE","reviewWorkflows","_jsxs","Flex","gap","_jsx","AssigneeSelect","isCompact","StageSelect","type"],"mappings":";;;;;;;AAOA,MAAMA,MAAS,GAAA,IAAA;IACb,MAAM,EACJC,OAAO,EAAE,EACTC,EAAE,EACFC,cAAc,EACf,GAAGC,SAAAA,EAAAA;AAMJ,IAAA,MAAM,EACJC,IAAM,EAAA,EAAEC,OAAO,EAAE,EAClB,GAAGC,0BAAkBN,CAAAA,IAAAA,CAAAA;AAEtB,IAAA,IACE,CAACO,MAAAA,CAAOC,MAAM,CAACC,IAAI,IACnB,CAACJ,OAASK,EAAAA,eAAAA,IACTR,cAAmB,KAAA,cAAA,IAAkB,CAACD,EAAAA,IACvCA,OAAO,QACP,EAAA;QACA,OAAO,IAAA;AACT;AAEA,IAAA,qBACEU,IAACC,CAAAA,IAAAA,EAAAA;QAAKC,GAAK,EAAA,CAAA;;0BACTC,GAACC,CAAAA,cAAAA,EAAAA;gBAAeC,SAAS,EAAA;;0BACzBF,GAACG,CAAAA,WAAAA,EAAAA;gBAAYD,SAAS,EAAA;;;;AAG5B;AAEAjB,MAAAA,CAAOmB,IAAI,GAAG,SAAA;;;;"}

View File

@@ -0,0 +1,39 @@
'use strict';
var jsxRuntime = require('react/jsx-runtime');
var strapiAdmin = require('@strapi/content-manager/strapi-admin');
var designSystem = require('@strapi/design-system');
var reactIntl = require('react-intl');
var reactRouterDom = require('react-router-dom');
var AssigneeSelect = require('./AssigneeSelect.js');
var StageSelect = require('./StageSelect.js');
const Panel = ()=>{
const { slug = '', id, collectionType } = reactRouterDom.useParams();
const { edit: { options } } = strapiAdmin.unstable_useDocumentLayout(slug);
const { formatMessage } = reactIntl.useIntl();
if (!window.strapi.isEE || !options?.reviewWorkflows || collectionType !== 'single-types' && !id || id === 'create') {
return null;
}
return {
title: formatMessage({
id: 'content-manager.containers.edit.panels.review-workflows.title',
defaultMessage: 'Review Workflows'
}),
content: /*#__PURE__*/ jsxRuntime.jsxs(designSystem.Flex, {
direction: "column",
gap: 2,
alignItems: "stretch",
width: "100%",
children: [
/*#__PURE__*/ jsxRuntime.jsx(AssigneeSelect.AssigneeSelect, {}),
/*#__PURE__*/ jsxRuntime.jsx(StageSelect.StageSelect, {})
]
})
};
};
// @ts-expect-error this is fine, we like to label the core panels / actions.
Panel.type = 'review-workflows';
exports.Panel = Panel;
//# sourceMappingURL=Panel.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"Panel.js","sources":["../../../../../../../admin/src/routes/content-manager/model/id/components/Panel.tsx"],"sourcesContent":["import { unstable_useDocumentLayout as useDocumentLayout } from '@strapi/content-manager/strapi-admin';\nimport { Flex } from '@strapi/design-system';\nimport { useIntl } from 'react-intl';\nimport { useParams } from 'react-router-dom';\n\nimport { AssigneeSelect } from './AssigneeSelect';\nimport { StageSelect } from './StageSelect';\n\nimport type { PanelComponent } from '@strapi/content-manager/strapi-admin';\n\nconst Panel: PanelComponent = () => {\n const {\n slug = '',\n id,\n collectionType,\n } = useParams<{\n collectionType: string;\n slug: string;\n id: string;\n }>();\n\n const {\n edit: { options },\n } = useDocumentLayout(slug);\n const { formatMessage } = useIntl();\n\n if (\n !window.strapi.isEE ||\n !options?.reviewWorkflows ||\n (collectionType !== 'single-types' && !id) ||\n id === 'create'\n ) {\n return null;\n }\n\n return {\n title: formatMessage({\n id: 'content-manager.containers.edit.panels.review-workflows.title',\n defaultMessage: 'Review Workflows',\n }),\n content: (\n <Flex direction=\"column\" gap={2} alignItems=\"stretch\" width=\"100%\">\n <AssigneeSelect />\n <StageSelect />\n </Flex>\n ),\n };\n};\n\n// @ts-expect-error this is fine, we like to label the core panels / actions.\nPanel.type = 'review-workflows';\n\nexport { Panel };\n"],"names":["Panel","slug","id","collectionType","useParams","edit","options","useDocumentLayout","formatMessage","useIntl","window","strapi","isEE","reviewWorkflows","title","defaultMessage","content","_jsxs","Flex","direction","gap","alignItems","width","_jsx","AssigneeSelect","StageSelect","type"],"mappings":";;;;;;;;;;AAUA,MAAMA,KAAwB,GAAA,IAAA;IAC5B,MAAM,EACJC,OAAO,EAAE,EACTC,EAAE,EACFC,cAAc,EACf,GAAGC,wBAAAA,EAAAA;AAMJ,IAAA,MAAM,EACJC,IAAM,EAAA,EAAEC,OAAO,EAAE,EAClB,GAAGC,sCAAkBN,CAAAA,IAAAA,CAAAA;IACtB,MAAM,EAAEO,aAAa,EAAE,GAAGC,iBAAAA,EAAAA;AAE1B,IAAA,IACE,CAACC,MAAAA,CAAOC,MAAM,CAACC,IAAI,IACnB,CAACN,OAASO,EAAAA,eAAAA,IACTV,cAAmB,KAAA,cAAA,IAAkB,CAACD,EAAAA,IACvCA,OAAO,QACP,EAAA;QACA,OAAO,IAAA;AACT;IAEA,OAAO;AACLY,QAAAA,KAAAA,EAAON,aAAc,CAAA;YACnBN,EAAI,EAAA,+DAAA;YACJa,cAAgB,EAAA;AAClB,SAAA,CAAA;AACAC,QAAAA,OAAAA,gBACEC,eAACC,CAAAA,iBAAAA,EAAAA;YAAKC,SAAU,EAAA,QAAA;YAASC,GAAK,EAAA,CAAA;YAAGC,UAAW,EAAA,SAAA;YAAUC,KAAM,EAAA,MAAA;;8BAC1DC,cAACC,CAAAA,6BAAAA,EAAAA,EAAAA,CAAAA;8BACDD,cAACE,CAAAA,uBAAAA,EAAAA,EAAAA;;;AAGP,KAAA;AACF;AAEA;AACAzB,KAAAA,CAAM0B,IAAI,GAAG,kBAAA;;;;"}

View File

@@ -0,0 +1,37 @@
import { jsxs, jsx } from 'react/jsx-runtime';
import { unstable_useDocumentLayout } from '@strapi/content-manager/strapi-admin';
import { Flex } from '@strapi/design-system';
import { useIntl } from 'react-intl';
import { useParams } from 'react-router-dom';
import { AssigneeSelect } from './AssigneeSelect.mjs';
import { StageSelect } from './StageSelect.mjs';
const Panel = ()=>{
const { slug = '', id, collectionType } = useParams();
const { edit: { options } } = unstable_useDocumentLayout(slug);
const { formatMessage } = useIntl();
if (!window.strapi.isEE || !options?.reviewWorkflows || collectionType !== 'single-types' && !id || id === 'create') {
return null;
}
return {
title: formatMessage({
id: 'content-manager.containers.edit.panels.review-workflows.title',
defaultMessage: 'Review Workflows'
}),
content: /*#__PURE__*/ jsxs(Flex, {
direction: "column",
gap: 2,
alignItems: "stretch",
width: "100%",
children: [
/*#__PURE__*/ jsx(AssigneeSelect, {}),
/*#__PURE__*/ jsx(StageSelect, {})
]
})
};
};
// @ts-expect-error this is fine, we like to label the core panels / actions.
Panel.type = 'review-workflows';
export { Panel };
//# sourceMappingURL=Panel.mjs.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"Panel.mjs","sources":["../../../../../../../admin/src/routes/content-manager/model/id/components/Panel.tsx"],"sourcesContent":["import { unstable_useDocumentLayout as useDocumentLayout } from '@strapi/content-manager/strapi-admin';\nimport { Flex } from '@strapi/design-system';\nimport { useIntl } from 'react-intl';\nimport { useParams } from 'react-router-dom';\n\nimport { AssigneeSelect } from './AssigneeSelect';\nimport { StageSelect } from './StageSelect';\n\nimport type { PanelComponent } from '@strapi/content-manager/strapi-admin';\n\nconst Panel: PanelComponent = () => {\n const {\n slug = '',\n id,\n collectionType,\n } = useParams<{\n collectionType: string;\n slug: string;\n id: string;\n }>();\n\n const {\n edit: { options },\n } = useDocumentLayout(slug);\n const { formatMessage } = useIntl();\n\n if (\n !window.strapi.isEE ||\n !options?.reviewWorkflows ||\n (collectionType !== 'single-types' && !id) ||\n id === 'create'\n ) {\n return null;\n }\n\n return {\n title: formatMessage({\n id: 'content-manager.containers.edit.panels.review-workflows.title',\n defaultMessage: 'Review Workflows',\n }),\n content: (\n <Flex direction=\"column\" gap={2} alignItems=\"stretch\" width=\"100%\">\n <AssigneeSelect />\n <StageSelect />\n </Flex>\n ),\n };\n};\n\n// @ts-expect-error this is fine, we like to label the core panels / actions.\nPanel.type = 'review-workflows';\n\nexport { Panel };\n"],"names":["Panel","slug","id","collectionType","useParams","edit","options","useDocumentLayout","formatMessage","useIntl","window","strapi","isEE","reviewWorkflows","title","defaultMessage","content","_jsxs","Flex","direction","gap","alignItems","width","_jsx","AssigneeSelect","StageSelect","type"],"mappings":";;;;;;;;AAUA,MAAMA,KAAwB,GAAA,IAAA;IAC5B,MAAM,EACJC,OAAO,EAAE,EACTC,EAAE,EACFC,cAAc,EACf,GAAGC,SAAAA,EAAAA;AAMJ,IAAA,MAAM,EACJC,IAAM,EAAA,EAAEC,OAAO,EAAE,EAClB,GAAGC,0BAAkBN,CAAAA,IAAAA,CAAAA;IACtB,MAAM,EAAEO,aAAa,EAAE,GAAGC,OAAAA,EAAAA;AAE1B,IAAA,IACE,CAACC,MAAAA,CAAOC,MAAM,CAACC,IAAI,IACnB,CAACN,OAASO,EAAAA,eAAAA,IACTV,cAAmB,KAAA,cAAA,IAAkB,CAACD,EAAAA,IACvCA,OAAO,QACP,EAAA;QACA,OAAO,IAAA;AACT;IAEA,OAAO;AACLY,QAAAA,KAAAA,EAAON,aAAc,CAAA;YACnBN,EAAI,EAAA,+DAAA;YACJa,cAAgB,EAAA;AAClB,SAAA,CAAA;AACAC,QAAAA,OAAAA,gBACEC,IAACC,CAAAA,IAAAA,EAAAA;YAAKC,SAAU,EAAA,QAAA;YAASC,GAAK,EAAA,CAAA;YAAGC,UAAW,EAAA,SAAA;YAAUC,KAAM,EAAA,MAAA;;8BAC1DC,GAACC,CAAAA,cAAAA,EAAAA,EAAAA,CAAAA;8BACDD,GAACE,CAAAA,WAAAA,EAAAA,EAAAA;;;AAGP,KAAA;AACF;AAEA;AACAzB,KAAAA,CAAM0B,IAAI,GAAG,kBAAA;;;;"}

View File

@@ -0,0 +1,329 @@
'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 strapiAdmin$1 = require('@strapi/content-manager/strapi-admin');
var designSystem = require('@strapi/design-system');
var reactIntl = require('react-intl');
var reactRouterDom = require('react-router-dom');
var LimitsModal = require('../../../../../components/LimitsModal.js');
var constants$1 = require('../../../../../constants.js');
var contentManager = require('../../../../../services/content-manager.js');
var api = require('../../../../../utils/api.js');
var colors = require('../../../../../utils/colors.js');
var constants = require('./constants.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);
/* -------------------------------------------------------------------------------------------------
* LimitModals
* -----------------------------------------------------------------------------------------------*/ const WorkflowLimitModal = ({ open, onOpenChange })=>{
const { formatMessage } = reactIntl.useIntl();
return /*#__PURE__*/ jsxRuntime.jsxs(LimitsModal.LimitsModal.Root, {
open: open,
onOpenChange: onOpenChange,
children: [
/*#__PURE__*/ jsxRuntime.jsx(LimitsModal.LimitsModal.Title, {
children: formatMessage({
id: 'content-manager.reviewWorkflows.workflows.limit.title',
defaultMessage: 'Youve reached the limit of workflows in your plan'
})
}),
/*#__PURE__*/ jsxRuntime.jsx(LimitsModal.LimitsModal.Body, {
children: formatMessage({
id: 'content-manager.reviewWorkflows.workflows.limit.body',
defaultMessage: 'Delete a workflow or contact Sales to enable more workflows.'
})
})
]
});
};
const StageLimitModal = ({ open, onOpenChange })=>{
const { formatMessage } = reactIntl.useIntl();
return /*#__PURE__*/ jsxRuntime.jsxs(LimitsModal.LimitsModal.Root, {
open: open,
onOpenChange: onOpenChange,
children: [
/*#__PURE__*/ jsxRuntime.jsx(LimitsModal.LimitsModal.Title, {
children: formatMessage({
id: 'content-manager.reviewWorkflows.stages.limit.title',
defaultMessage: 'You have reached the limit of stages for this workflow in your plan'
})
}),
/*#__PURE__*/ jsxRuntime.jsx(LimitsModal.LimitsModal.Body, {
children: formatMessage({
id: 'content-manager.reviewWorkflows.stages.limit.body',
defaultMessage: 'Try deleting some stages or contact Sales to enable more stages.'
})
})
]
});
};
/* -------------------------------------------------------------------------------------------------
* StageSelect
* -----------------------------------------------------------------------------------------------*/ const Select = ({ stages, activeWorkflowStage, isLoading, ...props })=>{
const { formatMessage } = reactIntl.useIntl();
const { themeColorName } = colors.getStageColorByHex(activeWorkflowStage?.color) ?? {};
return /*#__PURE__*/ jsxRuntime.jsx(designSystem.SingleSelect, {
disabled: stages.length === 0,
placeholder: formatMessage({
id: 'content-manager.reviewWorkflows.assignee.placeholder',
defaultMessage: 'Select…'
}),
startIcon: activeWorkflowStage && /*#__PURE__*/ jsxRuntime.jsx(designSystem.Flex, {
tag: "span",
height: 2,
background: activeWorkflowStage?.color,
borderColor: themeColorName === 'neutral0' ? 'neutral150' : undefined,
hasRadius: true,
shrink: 0,
width: 2,
marginRight: "-3px"
}),
// @ts-expect-error `customizeContent` is not correctly typed in the DS.
customizeContent: ()=>{
return /*#__PURE__*/ jsxRuntime.jsxs(designSystem.Flex, {
tag: "span",
justifyContent: "space-between",
alignItems: "center",
width: "100%",
children: [
/*#__PURE__*/ jsxRuntime.jsx(designSystem.Typography, {
textColor: "neutral800",
ellipsis: true,
lineHeight: "inherit",
children: activeWorkflowStage?.name ?? ''
}),
isLoading ? /*#__PURE__*/ jsxRuntime.jsx(designSystem.Loader, {
small: true,
style: {
display: 'flex'
},
"data-testid": "loader"
}) : null
]
});
},
...props,
children: stages.map(({ id, color, name })=>{
const { themeColorName } = colors.getStageColorByHex(color) ?? {};
return /*#__PURE__*/ jsxRuntime.jsx(designSystem.SingleSelectOption, {
startIcon: /*#__PURE__*/ jsxRuntime.jsx(designSystem.Flex, {
height: 2,
background: color,
borderColor: themeColorName === 'neutral0' ? 'neutral150' : undefined,
hasRadius: true,
shrink: 0,
width: 2
}),
value: id,
textValue: name,
children: name
}, id);
})
});
};
const StageSelect = ({ isCompact })=>{
const { collectionType = '', slug: model = '', id = '' } = reactRouterDom.useParams();
const { formatMessage } = reactIntl.useIntl();
const { _unstableFormatAPIError: formatAPIError } = strapiAdmin.useAPIErrorHandler();
const { toggleNotification } = strapiAdmin.useNotification();
const [{ query }] = strapiAdmin.useQueryParams();
const params = React__namespace.useMemo(()=>api.buildValidParams(query), [
query
]);
const { document, isLoading: isLoadingDocument } = strapiAdmin$1.unstable_useDocument({
collectionType,
model,
documentId: id
}, {
skip: !id && collectionType !== 'single-types'
});
const { data, isLoading: isLoadingStages } = contentManager.useGetStagesQuery({
slug: collectionType,
model: model,
// @ts-expect-error `id` is not correctly typed in the DS.
id: document?.documentId,
params
}, {
skip: !document?.documentId
});
const { meta, stages = [] } = data ?? {};
const { getFeature } = ee.useLicenseLimits();
const [showLimitModal, setShowLimitModal] = React__namespace.useState(null);
const limits = getFeature('review-workflows') ?? {};
const activeWorkflowStage = document ? document[constants.STAGE_ATTRIBUTE_NAME] : null;
const [updateStage, { error }] = contentManager.useUpdateStageMutation();
const handleChange = async (stageId)=>{
try {
/**
* If the current license has a limit:
* check if the total count of workflows exceeds that limit and display
* the limits modal.
*
* If the current license does not have a limit (e.g. offline license):
* do nothing (for now).
*
*/ if (limits?.[constants$1.CHARGEBEE_WORKFLOW_ENTITLEMENT_NAME] && parseInt(limits[constants$1.CHARGEBEE_WORKFLOW_ENTITLEMENT_NAME], 10) < (meta?.workflowCount ?? 0)) {
setShowLimitModal('workflow');
/**
* If the current license has a limit:
* check if the total count of stages exceeds that limit and display
* the limits modal.
*
* If the current license does not have a limit (e.g. offline license):
* do nothing (for now).
*
*/ } else if (limits?.[constants$1.CHARGEBEE_STAGES_PER_WORKFLOW_ENTITLEMENT_NAME] && parseInt(limits[constants$1.CHARGEBEE_STAGES_PER_WORKFLOW_ENTITLEMENT_NAME], 10) < stages.length) {
setShowLimitModal('stage');
} else {
if (document?.documentId) {
const res = await updateStage({
model,
id: document.documentId,
slug: collectionType,
params,
data: {
id: stageId
}
});
if ('data' in res) {
toggleNotification({
type: 'success',
message: formatMessage({
id: 'content-manager.reviewWorkflows.stage.notification.saved',
defaultMessage: 'Review stage updated'
})
});
}
if (isCompact && 'error' in res) {
toggleNotification({
type: 'danger',
message: formatAPIError(res.error)
});
}
}
}
} catch (error) {
toggleNotification({
type: 'danger',
message: formatMessage({
id: 'content-manager.reviewWorkflows.stage.notification.error',
defaultMessage: 'An error occurred while updating the review stage'
})
});
}
};
const isLoading = isLoadingStages || isLoadingDocument;
const reviewStageLabel = formatMessage({
id: 'content-manager.reviewWorkflows.stage.label',
defaultMessage: 'Review stage'
});
const reviewStageHint = !isLoading && stages.length === 0 && // TODO: Handle errors and hints
formatMessage({
id: 'content-manager.reviewWorkflows.stages.no-transition',
defaultMessage: 'You dont have the permission to update this stage.'
});
if (isCompact) {
return /*#__PURE__*/ jsxRuntime.jsxs(jsxRuntime.Fragment, {
children: [
/*#__PURE__*/ jsxRuntime.jsx(designSystem.Tooltip, {
label: reviewStageHint,
children: /*#__PURE__*/ jsxRuntime.jsx(designSystem.Field.Root, {
name: constants.STAGE_ATTRIBUTE_NAME,
id: constants.STAGE_ATTRIBUTE_NAME,
children: /*#__PURE__*/ jsxRuntime.jsxs(jsxRuntime.Fragment, {
children: [
/*#__PURE__*/ jsxRuntime.jsx(designSystem.VisuallyHidden, {
children: /*#__PURE__*/ jsxRuntime.jsx(designSystem.Field.Label, {
children: reviewStageLabel
})
}),
/*#__PURE__*/ jsxRuntime.jsx(Select, {
stages: stages,
activeWorkflowStage: activeWorkflowStage,
isLoading: isLoading,
size: "S",
disabled: stages.length === 0,
value: activeWorkflowStage?.id,
onChange: handleChange,
placeholder: formatMessage({
id: 'content-manager.reviewWorkflows.assignee.placeholder',
defaultMessage: 'Select…'
})
})
]
})
})
}),
/*#__PURE__*/ jsxRuntime.jsx(WorkflowLimitModal, {
open: showLimitModal === 'workflow',
onOpenChange: ()=>setShowLimitModal(null)
}),
/*#__PURE__*/ jsxRuntime.jsx(StageLimitModal, {
open: showLimitModal === 'stage',
onOpenChange: ()=>setShowLimitModal(null)
})
]
});
}
return /*#__PURE__*/ jsxRuntime.jsxs(jsxRuntime.Fragment, {
children: [
/*#__PURE__*/ jsxRuntime.jsxs(designSystem.Field.Root, {
hint: reviewStageHint,
error: error && formatAPIError(error) || undefined,
name: constants.STAGE_ATTRIBUTE_NAME,
id: constants.STAGE_ATTRIBUTE_NAME,
children: [
/*#__PURE__*/ jsxRuntime.jsx(designSystem.Field.Label, {
children: reviewStageLabel
}),
/*#__PURE__*/ jsxRuntime.jsx(Select, {
stages: stages,
activeWorkflowStage: activeWorkflowStage,
isLoading: isLoading,
disabled: stages.length === 0,
value: activeWorkflowStage?.id,
onChange: handleChange,
placeholder: formatMessage({
id: 'content-manager.reviewWorkflows.assignee.placeholder',
defaultMessage: 'Select…'
})
}),
/*#__PURE__*/ jsxRuntime.jsx(designSystem.Field.Hint, {}),
/*#__PURE__*/ jsxRuntime.jsx(designSystem.Field.Error, {})
]
}),
/*#__PURE__*/ jsxRuntime.jsx(WorkflowLimitModal, {
open: showLimitModal === 'workflow',
onOpenChange: ()=>setShowLimitModal(null)
}),
/*#__PURE__*/ jsxRuntime.jsx(StageLimitModal, {
open: showLimitModal === 'stage',
onOpenChange: ()=>setShowLimitModal(null)
})
]
});
};
exports.StageSelect = StageSelect;
//# sourceMappingURL=StageSelect.js.map

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,308 @@
import { jsxs, Fragment, jsx } from 'react/jsx-runtime';
import * as React from 'react';
import { useAPIErrorHandler, useNotification, useQueryParams } from '@strapi/admin/strapi-admin';
import { useLicenseLimits } from '@strapi/admin/strapi-admin/ee';
import { unstable_useDocument } from '@strapi/content-manager/strapi-admin';
import { Tooltip, Field, VisuallyHidden, SingleSelect, Flex, Typography, Loader, SingleSelectOption } from '@strapi/design-system';
import { useIntl } from 'react-intl';
import { useParams } from 'react-router-dom';
import { LimitsModal } from '../../../../../components/LimitsModal.mjs';
import { CHARGEBEE_WORKFLOW_ENTITLEMENT_NAME, CHARGEBEE_STAGES_PER_WORKFLOW_ENTITLEMENT_NAME } from '../../../../../constants.mjs';
import { useGetStagesQuery, useUpdateStageMutation } from '../../../../../services/content-manager.mjs';
import { buildValidParams } from '../../../../../utils/api.mjs';
import { getStageColorByHex } from '../../../../../utils/colors.mjs';
import { STAGE_ATTRIBUTE_NAME } from './constants.mjs';
/* -------------------------------------------------------------------------------------------------
* LimitModals
* -----------------------------------------------------------------------------------------------*/ const WorkflowLimitModal = ({ open, onOpenChange })=>{
const { formatMessage } = useIntl();
return /*#__PURE__*/ jsxs(LimitsModal.Root, {
open: open,
onOpenChange: onOpenChange,
children: [
/*#__PURE__*/ jsx(LimitsModal.Title, {
children: formatMessage({
id: 'content-manager.reviewWorkflows.workflows.limit.title',
defaultMessage: 'Youve reached the limit of workflows in your plan'
})
}),
/*#__PURE__*/ jsx(LimitsModal.Body, {
children: formatMessage({
id: 'content-manager.reviewWorkflows.workflows.limit.body',
defaultMessage: 'Delete a workflow or contact Sales to enable more workflows.'
})
})
]
});
};
const StageLimitModal = ({ open, onOpenChange })=>{
const { formatMessage } = useIntl();
return /*#__PURE__*/ jsxs(LimitsModal.Root, {
open: open,
onOpenChange: onOpenChange,
children: [
/*#__PURE__*/ jsx(LimitsModal.Title, {
children: formatMessage({
id: 'content-manager.reviewWorkflows.stages.limit.title',
defaultMessage: 'You have reached the limit of stages for this workflow in your plan'
})
}),
/*#__PURE__*/ jsx(LimitsModal.Body, {
children: formatMessage({
id: 'content-manager.reviewWorkflows.stages.limit.body',
defaultMessage: 'Try deleting some stages or contact Sales to enable more stages.'
})
})
]
});
};
/* -------------------------------------------------------------------------------------------------
* StageSelect
* -----------------------------------------------------------------------------------------------*/ const Select = ({ stages, activeWorkflowStage, isLoading, ...props })=>{
const { formatMessage } = useIntl();
const { themeColorName } = getStageColorByHex(activeWorkflowStage?.color) ?? {};
return /*#__PURE__*/ jsx(SingleSelect, {
disabled: stages.length === 0,
placeholder: formatMessage({
id: 'content-manager.reviewWorkflows.assignee.placeholder',
defaultMessage: 'Select…'
}),
startIcon: activeWorkflowStage && /*#__PURE__*/ jsx(Flex, {
tag: "span",
height: 2,
background: activeWorkflowStage?.color,
borderColor: themeColorName === 'neutral0' ? 'neutral150' : undefined,
hasRadius: true,
shrink: 0,
width: 2,
marginRight: "-3px"
}),
// @ts-expect-error `customizeContent` is not correctly typed in the DS.
customizeContent: ()=>{
return /*#__PURE__*/ jsxs(Flex, {
tag: "span",
justifyContent: "space-between",
alignItems: "center",
width: "100%",
children: [
/*#__PURE__*/ jsx(Typography, {
textColor: "neutral800",
ellipsis: true,
lineHeight: "inherit",
children: activeWorkflowStage?.name ?? ''
}),
isLoading ? /*#__PURE__*/ jsx(Loader, {
small: true,
style: {
display: 'flex'
},
"data-testid": "loader"
}) : null
]
});
},
...props,
children: stages.map(({ id, color, name })=>{
const { themeColorName } = getStageColorByHex(color) ?? {};
return /*#__PURE__*/ jsx(SingleSelectOption, {
startIcon: /*#__PURE__*/ jsx(Flex, {
height: 2,
background: color,
borderColor: themeColorName === 'neutral0' ? 'neutral150' : undefined,
hasRadius: true,
shrink: 0,
width: 2
}),
value: id,
textValue: name,
children: name
}, id);
})
});
};
const StageSelect = ({ isCompact })=>{
const { collectionType = '', slug: model = '', id = '' } = useParams();
const { formatMessage } = useIntl();
const { _unstableFormatAPIError: formatAPIError } = useAPIErrorHandler();
const { toggleNotification } = useNotification();
const [{ query }] = useQueryParams();
const params = React.useMemo(()=>buildValidParams(query), [
query
]);
const { document, isLoading: isLoadingDocument } = unstable_useDocument({
collectionType,
model,
documentId: id
}, {
skip: !id && collectionType !== 'single-types'
});
const { data, isLoading: isLoadingStages } = useGetStagesQuery({
slug: collectionType,
model: model,
// @ts-expect-error `id` is not correctly typed in the DS.
id: document?.documentId,
params
}, {
skip: !document?.documentId
});
const { meta, stages = [] } = data ?? {};
const { getFeature } = useLicenseLimits();
const [showLimitModal, setShowLimitModal] = React.useState(null);
const limits = getFeature('review-workflows') ?? {};
const activeWorkflowStage = document ? document[STAGE_ATTRIBUTE_NAME] : null;
const [updateStage, { error }] = useUpdateStageMutation();
const handleChange = async (stageId)=>{
try {
/**
* If the current license has a limit:
* check if the total count of workflows exceeds that limit and display
* the limits modal.
*
* If the current license does not have a limit (e.g. offline license):
* do nothing (for now).
*
*/ if (limits?.[CHARGEBEE_WORKFLOW_ENTITLEMENT_NAME] && parseInt(limits[CHARGEBEE_WORKFLOW_ENTITLEMENT_NAME], 10) < (meta?.workflowCount ?? 0)) {
setShowLimitModal('workflow');
/**
* If the current license has a limit:
* check if the total count of stages exceeds that limit and display
* the limits modal.
*
* If the current license does not have a limit (e.g. offline license):
* do nothing (for now).
*
*/ } else if (limits?.[CHARGEBEE_STAGES_PER_WORKFLOW_ENTITLEMENT_NAME] && parseInt(limits[CHARGEBEE_STAGES_PER_WORKFLOW_ENTITLEMENT_NAME], 10) < stages.length) {
setShowLimitModal('stage');
} else {
if (document?.documentId) {
const res = await updateStage({
model,
id: document.documentId,
slug: collectionType,
params,
data: {
id: stageId
}
});
if ('data' in res) {
toggleNotification({
type: 'success',
message: formatMessage({
id: 'content-manager.reviewWorkflows.stage.notification.saved',
defaultMessage: 'Review stage updated'
})
});
}
if (isCompact && 'error' in res) {
toggleNotification({
type: 'danger',
message: formatAPIError(res.error)
});
}
}
}
} catch (error) {
toggleNotification({
type: 'danger',
message: formatMessage({
id: 'content-manager.reviewWorkflows.stage.notification.error',
defaultMessage: 'An error occurred while updating the review stage'
})
});
}
};
const isLoading = isLoadingStages || isLoadingDocument;
const reviewStageLabel = formatMessage({
id: 'content-manager.reviewWorkflows.stage.label',
defaultMessage: 'Review stage'
});
const reviewStageHint = !isLoading && stages.length === 0 && // TODO: Handle errors and hints
formatMessage({
id: 'content-manager.reviewWorkflows.stages.no-transition',
defaultMessage: 'You dont have the permission to update this stage.'
});
if (isCompact) {
return /*#__PURE__*/ jsxs(Fragment, {
children: [
/*#__PURE__*/ jsx(Tooltip, {
label: reviewStageHint,
children: /*#__PURE__*/ jsx(Field.Root, {
name: STAGE_ATTRIBUTE_NAME,
id: STAGE_ATTRIBUTE_NAME,
children: /*#__PURE__*/ jsxs(Fragment, {
children: [
/*#__PURE__*/ jsx(VisuallyHidden, {
children: /*#__PURE__*/ jsx(Field.Label, {
children: reviewStageLabel
})
}),
/*#__PURE__*/ jsx(Select, {
stages: stages,
activeWorkflowStage: activeWorkflowStage,
isLoading: isLoading,
size: "S",
disabled: stages.length === 0,
value: activeWorkflowStage?.id,
onChange: handleChange,
placeholder: formatMessage({
id: 'content-manager.reviewWorkflows.assignee.placeholder',
defaultMessage: 'Select…'
})
})
]
})
})
}),
/*#__PURE__*/ jsx(WorkflowLimitModal, {
open: showLimitModal === 'workflow',
onOpenChange: ()=>setShowLimitModal(null)
}),
/*#__PURE__*/ jsx(StageLimitModal, {
open: showLimitModal === 'stage',
onOpenChange: ()=>setShowLimitModal(null)
})
]
});
}
return /*#__PURE__*/ jsxs(Fragment, {
children: [
/*#__PURE__*/ jsxs(Field.Root, {
hint: reviewStageHint,
error: error && formatAPIError(error) || undefined,
name: STAGE_ATTRIBUTE_NAME,
id: STAGE_ATTRIBUTE_NAME,
children: [
/*#__PURE__*/ jsx(Field.Label, {
children: reviewStageLabel
}),
/*#__PURE__*/ jsx(Select, {
stages: stages,
activeWorkflowStage: activeWorkflowStage,
isLoading: isLoading,
disabled: stages.length === 0,
value: activeWorkflowStage?.id,
onChange: handleChange,
placeholder: formatMessage({
id: 'content-manager.reviewWorkflows.assignee.placeholder',
defaultMessage: 'Select…'
})
}),
/*#__PURE__*/ jsx(Field.Hint, {}),
/*#__PURE__*/ jsx(Field.Error, {})
]
}),
/*#__PURE__*/ jsx(WorkflowLimitModal, {
open: showLimitModal === 'workflow',
onOpenChange: ()=>setShowLimitModal(null)
}),
/*#__PURE__*/ jsx(StageLimitModal, {
open: showLimitModal === 'stage',
onOpenChange: ()=>setShowLimitModal(null)
})
]
});
};
export { StageSelect };
//# sourceMappingURL=StageSelect.mjs.map

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,8 @@
'use strict';
const STAGE_ATTRIBUTE_NAME = 'strapi_stage';
const ASSIGNEE_ATTRIBUTE_NAME = 'strapi_assignee';
exports.ASSIGNEE_ATTRIBUTE_NAME = ASSIGNEE_ATTRIBUTE_NAME;
exports.STAGE_ATTRIBUTE_NAME = STAGE_ATTRIBUTE_NAME;
//# sourceMappingURL=constants.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"constants.js","sources":["../../../../../../../admin/src/routes/content-manager/model/id/components/constants.ts"],"sourcesContent":["export const STAGE_ATTRIBUTE_NAME = 'strapi_stage';\nexport const ASSIGNEE_ATTRIBUTE_NAME = 'strapi_assignee';\n"],"names":["STAGE_ATTRIBUTE_NAME","ASSIGNEE_ATTRIBUTE_NAME"],"mappings":";;AAAO,MAAMA,uBAAuB;AAC7B,MAAMC,0BAA0B;;;;;"}

View File

@@ -0,0 +1,5 @@
const STAGE_ATTRIBUTE_NAME = 'strapi_stage';
const ASSIGNEE_ATTRIBUTE_NAME = 'strapi_assignee';
export { ASSIGNEE_ATTRIBUTE_NAME, STAGE_ATTRIBUTE_NAME };
//# sourceMappingURL=constants.mjs.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"constants.mjs","sources":["../../../../../../../admin/src/routes/content-manager/model/id/components/constants.ts"],"sourcesContent":["export const STAGE_ATTRIBUTE_NAME = 'strapi_stage';\nexport const ASSIGNEE_ATTRIBUTE_NAME = 'strapi_assignee';\n"],"names":["STAGE_ATTRIBUTE_NAME","ASSIGNEE_ATTRIBUTE_NAME"],"mappings":"AAAO,MAAMA,uBAAuB;AAC7B,MAAMC,0BAA0B;;;;"}

View File

@@ -0,0 +1,194 @@
'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 PurchaseReviewWorkflows = ()=>{
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: 'Settings.review-workflows.list.page.title',
defaultMessage: 'Review Workflows'
})
}),
/*#__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.SealCheck, {
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: 'settings.page.purchase.description',
defaultMessage: 'Manage your content review process'
})
})
}),
/*#__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: 'settings.page.purchase.perks1',
defaultMessage: 'Customizable review stages'
})
})
]
}),
/*#__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: 'settings.page.purchase.perks2',
defaultMessage: 'Manage user permissions'
})
})
]
}),
/*#__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: 'settings.page.purchase.perks3',
defaultMessage: 'Support for webhooks'
})
})
]
})
]
}),
/*#__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=Review%20Workflows",
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/review-workflow?utm_campaign=In-Product-CTA&utm_source=Review%20Workflows",
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-review-workflows-illustration",
width: "100%",
height: "100%",
style: {
position: 'absolute',
top: 0,
left: 0,
width: '100%',
height: '100%',
objectFit: 'cover',
objectPosition: 'bottom left'
}
})
})
})
]
})
})
]
})
});
};
exports.PurchaseReviewWorkflows = PurchaseReviewWorkflows;
//# sourceMappingURL=purchase-review-workflows.js.map

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,192 @@
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 { SealCheck, 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 PurchaseReviewWorkflows = ()=>{
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: 'Settings.review-workflows.list.page.title',
defaultMessage: 'Review Workflows'
})
}),
/*#__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(SealCheck, {
fill: "primary600",
width: `24px`,
height: `24px`
})
}),
/*#__PURE__*/ jsx(Flex, {
paddingTop: 3,
paddingBottom: 4,
children: /*#__PURE__*/ jsx(Typography, {
variant: "beta",
fontWeight: "bold",
children: formatMessage({
id: 'settings.page.purchase.description',
defaultMessage: 'Manage your content review process'
})
})
}),
/*#__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: 'settings.page.purchase.perks1',
defaultMessage: 'Customizable review stages'
})
})
]
}),
/*#__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: 'settings.page.purchase.perks2',
defaultMessage: 'Manage user permissions'
})
})
]
}),
/*#__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: 'settings.page.purchase.perks3',
defaultMessage: 'Support for webhooks'
})
})
]
})
]
}),
/*#__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=Review%20Workflows",
children: formatMessage({
id: 'Settings.page.purchase.upgrade.cta',
defaultMessage: 'Upgrade'
})
}),
/*#__PURE__*/ jsx(LinkButton, {
variant: "tertiary",
endIcon: /*#__PURE__*/ jsx(ExternalLink, {}),
href: "https://strapi.io/features/review-workflow?utm_campaign=In-Product-CTA&utm_source=Review%20Workflows",
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-review-workflows-illustration",
width: "100%",
height: "100%",
style: {
position: 'absolute',
top: 0,
left: 0,
width: '100%',
height: '100%',
objectFit: 'cover',
objectPosition: 'bottom left'
}
})
})
})
]
})
})
]
})
});
};
export { PurchaseReviewWorkflows };
//# sourceMappingURL=purchase-review-workflows.mjs.map

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,51 @@
'use strict';
var jsxRuntime = require('react/jsx-runtime');
var designSystem = require('@strapi/design-system');
var icons = require('@strapi/icons');
var styledComponents = require('styled-components');
const AddStage = ({ children, ...props })=>{
return /*#__PURE__*/ jsxRuntime.jsx(StyledButton, {
tag: "button",
background: "neutral0",
borderColor: "neutral150",
paddingBottom: 3,
paddingLeft: 4,
paddingRight: 4,
paddingTop: 3,
shadow: "filterShadow",
...props,
children: /*#__PURE__*/ jsxRuntime.jsx(designSystem.Typography, {
variant: "pi",
fontWeight: "bold",
children: /*#__PURE__*/ jsxRuntime.jsxs(designSystem.Flex, {
tag: "span",
gap: 2,
children: [
/*#__PURE__*/ jsxRuntime.jsx(icons.PlusCircle, {
width: "2.4rem",
height: "2.4rem",
"aria-hidden": true
}),
children
]
})
})
});
};
const StyledButton = styledComponents.styled(designSystem.Box)`
border-radius: 26px;
color: ${({ theme })=>theme.colors.neutral500};
&:hover {
color: ${({ theme })=>theme.colors.primary600};
}
&:active {
color: ${({ theme })=>theme.colors.primary600};
}
`;
exports.AddStage = AddStage;
//# sourceMappingURL=AddStage.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"AddStage.js","sources":["../../../../../admin/src/routes/settings/components/AddStage.tsx"],"sourcesContent":["import { Box, BoxComponent, ButtonProps, Flex, Typography } from '@strapi/design-system';\nimport { PlusCircle } from '@strapi/icons';\nimport { styled } from 'styled-components';\n\nexport const AddStage = ({ children, ...props }: ButtonProps) => {\n return (\n <StyledButton\n tag=\"button\"\n background=\"neutral0\"\n borderColor=\"neutral150\"\n paddingBottom={3}\n paddingLeft={4}\n paddingRight={4}\n paddingTop={3}\n shadow=\"filterShadow\"\n {...props}\n >\n <Typography variant=\"pi\" fontWeight=\"bold\">\n <Flex tag=\"span\" gap={2}>\n <PlusCircle width=\"2.4rem\" height=\"2.4rem\" aria-hidden />\n {children}\n </Flex>\n </Typography>\n </StyledButton>\n );\n};\n\nconst StyledButton = styled<BoxComponent<'button'>>(Box)`\n border-radius: 26px;\n color: ${({ theme }) => theme.colors.neutral500};\n\n &:hover {\n color: ${({ theme }) => theme.colors.primary600};\n }\n\n &:active {\n color: ${({ theme }) => theme.colors.primary600};\n }\n`;\n"],"names":["AddStage","children","props","_jsx","StyledButton","tag","background","borderColor","paddingBottom","paddingLeft","paddingRight","paddingTop","shadow","Typography","variant","fontWeight","_jsxs","Flex","gap","PlusCircle","width","height","aria-hidden","styled","Box","theme","colors","neutral500","primary600"],"mappings":";;;;;;;MAIaA,QAAW,GAAA,CAAC,EAAEC,QAAQ,EAAE,GAAGC,KAAoB,EAAA,GAAA;AAC1D,IAAA,qBACEC,cAACC,CAAAA,YAAAA,EAAAA;QACCC,GAAI,EAAA,QAAA;QACJC,UAAW,EAAA,UAAA;QACXC,WAAY,EAAA,YAAA;QACZC,aAAe,EAAA,CAAA;QACfC,WAAa,EAAA,CAAA;QACbC,YAAc,EAAA,CAAA;QACdC,UAAY,EAAA,CAAA;QACZC,MAAO,EAAA,cAAA;AACN,QAAA,GAAGV,KAAK;AAET,QAAA,QAAA,gBAAAC,cAACU,CAAAA,uBAAAA,EAAAA;YAAWC,OAAQ,EAAA,IAAA;YAAKC,UAAW,EAAA,MAAA;AAClC,YAAA,QAAA,gBAAAC,eAACC,CAAAA,iBAAAA,EAAAA;gBAAKZ,GAAI,EAAA,MAAA;gBAAOa,GAAK,EAAA,CAAA;;kCACpBf,cAACgB,CAAAA,gBAAAA,EAAAA;wBAAWC,KAAM,EAAA,QAAA;wBAASC,MAAO,EAAA,QAAA;wBAASC,aAAW,EAAA;;AACrDrB,oBAAAA;;;;;AAKX;AAEA,MAAMG,YAAAA,GAAemB,uBAA+BC,CAAAA,gBAAAA,CAAI;;SAE/C,EAAE,CAAC,EAAEC,KAAK,EAAE,GAAKA,KAAMC,CAAAA,MAAM,CAACC,UAAU,CAAC;;;WAGvC,EAAE,CAAC,EAAEF,KAAK,EAAE,GAAKA,KAAMC,CAAAA,MAAM,CAACE,UAAU,CAAC;;;;WAIzC,EAAE,CAAC,EAAEH,KAAK,EAAE,GAAKA,KAAMC,CAAAA,MAAM,CAACE,UAAU,CAAC;;AAEpD,CAAC;;;;"}

View File

@@ -0,0 +1,49 @@
import { jsx, jsxs } from 'react/jsx-runtime';
import { Box, Typography, Flex } from '@strapi/design-system';
import { PlusCircle } from '@strapi/icons';
import { styled } from 'styled-components';
const AddStage = ({ children, ...props })=>{
return /*#__PURE__*/ jsx(StyledButton, {
tag: "button",
background: "neutral0",
borderColor: "neutral150",
paddingBottom: 3,
paddingLeft: 4,
paddingRight: 4,
paddingTop: 3,
shadow: "filterShadow",
...props,
children: /*#__PURE__*/ jsx(Typography, {
variant: "pi",
fontWeight: "bold",
children: /*#__PURE__*/ jsxs(Flex, {
tag: "span",
gap: 2,
children: [
/*#__PURE__*/ jsx(PlusCircle, {
width: "2.4rem",
height: "2.4rem",
"aria-hidden": true
}),
children
]
})
})
});
};
const StyledButton = styled(Box)`
border-radius: 26px;
color: ${({ theme })=>theme.colors.neutral500};
&:hover {
color: ${({ theme })=>theme.colors.primary600};
}
&:active {
color: ${({ theme })=>theme.colors.primary600};
}
`;
export { AddStage };
//# sourceMappingURL=AddStage.mjs.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"AddStage.mjs","sources":["../../../../../admin/src/routes/settings/components/AddStage.tsx"],"sourcesContent":["import { Box, BoxComponent, ButtonProps, Flex, Typography } from '@strapi/design-system';\nimport { PlusCircle } from '@strapi/icons';\nimport { styled } from 'styled-components';\n\nexport const AddStage = ({ children, ...props }: ButtonProps) => {\n return (\n <StyledButton\n tag=\"button\"\n background=\"neutral0\"\n borderColor=\"neutral150\"\n paddingBottom={3}\n paddingLeft={4}\n paddingRight={4}\n paddingTop={3}\n shadow=\"filterShadow\"\n {...props}\n >\n <Typography variant=\"pi\" fontWeight=\"bold\">\n <Flex tag=\"span\" gap={2}>\n <PlusCircle width=\"2.4rem\" height=\"2.4rem\" aria-hidden />\n {children}\n </Flex>\n </Typography>\n </StyledButton>\n );\n};\n\nconst StyledButton = styled<BoxComponent<'button'>>(Box)`\n border-radius: 26px;\n color: ${({ theme }) => theme.colors.neutral500};\n\n &:hover {\n color: ${({ theme }) => theme.colors.primary600};\n }\n\n &:active {\n color: ${({ theme }) => theme.colors.primary600};\n }\n`;\n"],"names":["AddStage","children","props","_jsx","StyledButton","tag","background","borderColor","paddingBottom","paddingLeft","paddingRight","paddingTop","shadow","Typography","variant","fontWeight","_jsxs","Flex","gap","PlusCircle","width","height","aria-hidden","styled","Box","theme","colors","neutral500","primary600"],"mappings":";;;;;MAIaA,QAAW,GAAA,CAAC,EAAEC,QAAQ,EAAE,GAAGC,KAAoB,EAAA,GAAA;AAC1D,IAAA,qBACEC,GAACC,CAAAA,YAAAA,EAAAA;QACCC,GAAI,EAAA,QAAA;QACJC,UAAW,EAAA,UAAA;QACXC,WAAY,EAAA,YAAA;QACZC,aAAe,EAAA,CAAA;QACfC,WAAa,EAAA,CAAA;QACbC,YAAc,EAAA,CAAA;QACdC,UAAY,EAAA,CAAA;QACZC,MAAO,EAAA,cAAA;AACN,QAAA,GAAGV,KAAK;AAET,QAAA,QAAA,gBAAAC,GAACU,CAAAA,UAAAA,EAAAA;YAAWC,OAAQ,EAAA,IAAA;YAAKC,UAAW,EAAA,MAAA;AAClC,YAAA,QAAA,gBAAAC,IAACC,CAAAA,IAAAA,EAAAA;gBAAKZ,GAAI,EAAA,MAAA;gBAAOa,GAAK,EAAA,CAAA;;kCACpBf,GAACgB,CAAAA,UAAAA,EAAAA;wBAAWC,KAAM,EAAA,QAAA;wBAASC,MAAO,EAAA,QAAA;wBAASC,aAAW,EAAA;;AACrDrB,oBAAAA;;;;;AAKX;AAEA,MAAMG,YAAAA,GAAemB,MAA+BC,CAAAA,GAAAA,CAAI;;SAE/C,EAAE,CAAC,EAAEC,KAAK,EAAE,GAAKA,KAAMC,CAAAA,MAAM,CAACC,UAAU,CAAC;;;WAGvC,EAAE,CAAC,EAAEF,KAAK,EAAE,GAAKA,KAAMC,CAAAA,MAAM,CAACE,UAAU,CAAC;;;;WAIzC,EAAE,CAAC,EAAEH,KAAK,EAAE,GAAKA,KAAMC,CAAAA,MAAM,CAACE,UAAU,CAAC;;AAEpD,CAAC;;;;"}

View File

@@ -0,0 +1,86 @@
'use strict';
var jsxRuntime = require('react/jsx-runtime');
require('react');
var strapiAdmin = require('@strapi/admin/strapi-admin');
var designSystem = require('@strapi/design-system');
var reactDnd = require('react-dnd');
var reactIntl = require('react-intl');
var constants = require('../constants.js');
var StageDragPreview = require('./StageDragPreview.js');
function getStyle(initialOffset, currentOffset, mouseOffset) {
if (!initialOffset || !currentOffset || !mouseOffset) {
return {
display: 'none'
};
}
const { x, y } = mouseOffset;
return {
transform: `translate(${x}px, ${y}px)`
};
}
const DragLayerRendered = ()=>{
const { itemType, isDragging, item, initialOffset, currentOffset, mouseOffset } = reactDnd.useDragLayer((monitor)=>({
item: monitor.getItem(),
itemType: monitor.getItemType(),
initialOffset: monitor.getInitialSourceClientOffset(),
currentOffset: monitor.getSourceClientOffset(),
isDragging: monitor.isDragging(),
mouseOffset: monitor.getClientOffset()
}));
if (!isDragging || itemType !== constants.DRAG_DROP_TYPES.STAGE) {
return null;
}
return /*#__PURE__*/ jsxRuntime.jsx(designSystem.Box, {
height: "100%",
left: 0,
position: "fixed",
pointerEvents: "none",
top: 0,
zIndex: 100,
width: "100%",
children: /*#__PURE__*/ jsxRuntime.jsxs(designSystem.Box, {
style: getStyle(initialOffset, currentOffset, mouseOffset),
children: [
/*#__PURE__*/ jsxRuntime.jsx(StageDragPreview.StageDragPreview, {
name: typeof item.item === 'string' ? item.item : null
}),
";"
]
})
});
};
const Root = ({ children })=>{
return /*#__PURE__*/ jsxRuntime.jsx(strapiAdmin.Page.Main, {
children: /*#__PURE__*/ jsxRuntime.jsx(strapiAdmin.Layouts.Content, {
children: children
})
});
};
const Header = ({ title, subtitle, navigationAction, primaryAction })=>{
const { formatMessage } = reactIntl.useIntl();
return /*#__PURE__*/ jsxRuntime.jsxs(jsxRuntime.Fragment, {
children: [
/*#__PURE__*/ jsxRuntime.jsx(strapiAdmin.Page.Title, {
children: formatMessage({
id: 'Settings.PageTitle',
defaultMessage: 'Settings - {name}'
}, {
name: title
})
}),
/*#__PURE__*/ jsxRuntime.jsx(strapiAdmin.Layouts.BaseHeader, {
navigationAction: navigationAction,
primaryAction: primaryAction,
title: title,
subtitle: subtitle
})
]
});
};
exports.DragLayerRendered = DragLayerRendered;
exports.Header = Header;
exports.Root = Root;
//# sourceMappingURL=Layout.js.map

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,82 @@
import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
import 'react';
import { Page, Layouts } from '@strapi/admin/strapi-admin';
import { Box } from '@strapi/design-system';
import { useDragLayer } from 'react-dnd';
import { useIntl } from 'react-intl';
import { DRAG_DROP_TYPES } from '../constants.mjs';
import { StageDragPreview } from './StageDragPreview.mjs';
function getStyle(initialOffset, currentOffset, mouseOffset) {
if (!initialOffset || !currentOffset || !mouseOffset) {
return {
display: 'none'
};
}
const { x, y } = mouseOffset;
return {
transform: `translate(${x}px, ${y}px)`
};
}
const DragLayerRendered = ()=>{
const { itemType, isDragging, item, initialOffset, currentOffset, mouseOffset } = useDragLayer((monitor)=>({
item: monitor.getItem(),
itemType: monitor.getItemType(),
initialOffset: monitor.getInitialSourceClientOffset(),
currentOffset: monitor.getSourceClientOffset(),
isDragging: monitor.isDragging(),
mouseOffset: monitor.getClientOffset()
}));
if (!isDragging || itemType !== DRAG_DROP_TYPES.STAGE) {
return null;
}
return /*#__PURE__*/ jsx(Box, {
height: "100%",
left: 0,
position: "fixed",
pointerEvents: "none",
top: 0,
zIndex: 100,
width: "100%",
children: /*#__PURE__*/ jsxs(Box, {
style: getStyle(initialOffset, currentOffset, mouseOffset),
children: [
/*#__PURE__*/ jsx(StageDragPreview, {
name: typeof item.item === 'string' ? item.item : null
}),
";"
]
})
});
};
const Root = ({ children })=>{
return /*#__PURE__*/ jsx(Page.Main, {
children: /*#__PURE__*/ jsx(Layouts.Content, {
children: children
})
});
};
const Header = ({ title, subtitle, navigationAction, primaryAction })=>{
const { formatMessage } = useIntl();
return /*#__PURE__*/ jsxs(Fragment, {
children: [
/*#__PURE__*/ jsx(Page.Title, {
children: formatMessage({
id: 'Settings.PageTitle',
defaultMessage: 'Settings - {name}'
}, {
name: title
})
}),
/*#__PURE__*/ jsx(Layouts.BaseHeader, {
navigationAction: navigationAction,
primaryAction: primaryAction,
title: title,
subtitle: subtitle
})
]
});
};
export { DragLayerRendered, Header, Root };
//# sourceMappingURL=Layout.mjs.map

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,40 @@
'use strict';
var jsxRuntime = require('react/jsx-runtime');
var designSystem = require('@strapi/design-system');
var icons = require('@strapi/icons');
const StageDragPreview = ({ name })=>{
return /*#__PURE__*/ jsxRuntime.jsxs(designSystem.Flex, {
background: "primary100",
borderStyle: "dashed",
borderColor: "primary600",
borderWidth: "1px",
gap: 3,
hasRadius: true,
padding: 3,
shadow: "tableShadow",
width: "30rem",
children: [
/*#__PURE__*/ jsxRuntime.jsx(designSystem.Flex, {
alignItems: "center",
background: "neutral200",
borderRadius: "50%",
height: 6,
justifyContent: "center",
width: 6,
children: /*#__PURE__*/ jsxRuntime.jsx(icons.CaretDown, {
width: "0.8rem",
fill: "neutral600"
})
}),
/*#__PURE__*/ jsxRuntime.jsx(designSystem.Typography, {
fontWeight: "bold",
children: name
})
]
});
};
exports.StageDragPreview = StageDragPreview;
//# sourceMappingURL=StageDragPreview.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"StageDragPreview.js","sources":["../../../../../admin/src/routes/settings/components/StageDragPreview.tsx"],"sourcesContent":["import { Flex, Typography } from '@strapi/design-system';\nimport { CaretDown } from '@strapi/icons';\n\ninterface StageDragPreviewType {\n name: string | null;\n}\n\nconst StageDragPreview = ({ name }: StageDragPreviewType) => {\n return (\n <Flex\n background=\"primary100\"\n borderStyle=\"dashed\"\n borderColor=\"primary600\"\n borderWidth=\"1px\"\n gap={3}\n hasRadius\n padding={3}\n shadow=\"tableShadow\"\n width=\"30rem\"\n >\n <Flex\n alignItems=\"center\"\n background=\"neutral200\"\n borderRadius=\"50%\"\n height={6}\n justifyContent=\"center\"\n width={6}\n >\n <CaretDown width=\"0.8rem\" fill=\"neutral600\" />\n </Flex>\n\n <Typography fontWeight=\"bold\">{name}</Typography>\n </Flex>\n );\n};\n\nexport { StageDragPreview };\nexport type { StageDragPreviewType };\n"],"names":["StageDragPreview","name","_jsxs","Flex","background","borderStyle","borderColor","borderWidth","gap","hasRadius","padding","shadow","width","_jsx","alignItems","borderRadius","height","justifyContent","CaretDown","fill","Typography","fontWeight"],"mappings":";;;;;;AAOA,MAAMA,gBAAmB,GAAA,CAAC,EAAEC,IAAI,EAAwB,GAAA;AACtD,IAAA,qBACEC,eAACC,CAAAA,iBAAAA,EAAAA;QACCC,UAAW,EAAA,YAAA;QACXC,WAAY,EAAA,QAAA;QACZC,WAAY,EAAA,YAAA;QACZC,WAAY,EAAA,KAAA;QACZC,GAAK,EAAA,CAAA;QACLC,SAAS,EAAA,IAAA;QACTC,OAAS,EAAA,CAAA;QACTC,MAAO,EAAA,aAAA;QACPC,KAAM,EAAA,OAAA;;0BAENC,cAACV,CAAAA,iBAAAA,EAAAA;gBACCW,UAAW,EAAA,QAAA;gBACXV,UAAW,EAAA,YAAA;gBACXW,YAAa,EAAA,KAAA;gBACbC,MAAQ,EAAA,CAAA;gBACRC,cAAe,EAAA,QAAA;gBACfL,KAAO,EAAA,CAAA;AAEP,gBAAA,QAAA,gBAAAC,cAACK,CAAAA,eAAAA,EAAAA;oBAAUN,KAAM,EAAA,QAAA;oBAASO,IAAK,EAAA;;;0BAGjCN,cAACO,CAAAA,uBAAAA,EAAAA;gBAAWC,UAAW,EAAA,MAAA;AAAQpB,gBAAAA,QAAAA,EAAAA;;;;AAGrC;;;;"}

View File

@@ -0,0 +1,38 @@
import { jsxs, jsx } from 'react/jsx-runtime';
import { Flex, Typography } from '@strapi/design-system';
import { CaretDown } from '@strapi/icons';
const StageDragPreview = ({ name })=>{
return /*#__PURE__*/ jsxs(Flex, {
background: "primary100",
borderStyle: "dashed",
borderColor: "primary600",
borderWidth: "1px",
gap: 3,
hasRadius: true,
padding: 3,
shadow: "tableShadow",
width: "30rem",
children: [
/*#__PURE__*/ jsx(Flex, {
alignItems: "center",
background: "neutral200",
borderRadius: "50%",
height: 6,
justifyContent: "center",
width: 6,
children: /*#__PURE__*/ jsx(CaretDown, {
width: "0.8rem",
fill: "neutral600"
})
}),
/*#__PURE__*/ jsx(Typography, {
fontWeight: "bold",
children: name
})
]
});
};
export { StageDragPreview };
//# sourceMappingURL=StageDragPreview.mjs.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"StageDragPreview.mjs","sources":["../../../../../admin/src/routes/settings/components/StageDragPreview.tsx"],"sourcesContent":["import { Flex, Typography } from '@strapi/design-system';\nimport { CaretDown } from '@strapi/icons';\n\ninterface StageDragPreviewType {\n name: string | null;\n}\n\nconst StageDragPreview = ({ name }: StageDragPreviewType) => {\n return (\n <Flex\n background=\"primary100\"\n borderStyle=\"dashed\"\n borderColor=\"primary600\"\n borderWidth=\"1px\"\n gap={3}\n hasRadius\n padding={3}\n shadow=\"tableShadow\"\n width=\"30rem\"\n >\n <Flex\n alignItems=\"center\"\n background=\"neutral200\"\n borderRadius=\"50%\"\n height={6}\n justifyContent=\"center\"\n width={6}\n >\n <CaretDown width=\"0.8rem\" fill=\"neutral600\" />\n </Flex>\n\n <Typography fontWeight=\"bold\">{name}</Typography>\n </Flex>\n );\n};\n\nexport { StageDragPreview };\nexport type { StageDragPreviewType };\n"],"names":["StageDragPreview","name","_jsxs","Flex","background","borderStyle","borderColor","borderWidth","gap","hasRadius","padding","shadow","width","_jsx","alignItems","borderRadius","height","justifyContent","CaretDown","fill","Typography","fontWeight"],"mappings":";;;;AAOA,MAAMA,gBAAmB,GAAA,CAAC,EAAEC,IAAI,EAAwB,GAAA;AACtD,IAAA,qBACEC,IAACC,CAAAA,IAAAA,EAAAA;QACCC,UAAW,EAAA,YAAA;QACXC,WAAY,EAAA,QAAA;QACZC,WAAY,EAAA,YAAA;QACZC,WAAY,EAAA,KAAA;QACZC,GAAK,EAAA,CAAA;QACLC,SAAS,EAAA,IAAA;QACTC,OAAS,EAAA,CAAA;QACTC,MAAO,EAAA,aAAA;QACPC,KAAM,EAAA,OAAA;;0BAENC,GAACV,CAAAA,IAAAA,EAAAA;gBACCW,UAAW,EAAA,QAAA;gBACXV,UAAW,EAAA,YAAA;gBACXW,YAAa,EAAA,KAAA;gBACbC,MAAQ,EAAA,CAAA;gBACRC,cAAe,EAAA,QAAA;gBACfL,KAAO,EAAA,CAAA;AAEP,gBAAA,QAAA,gBAAAC,GAACK,CAAAA,SAAAA,EAAAA;oBAAUN,KAAM,EAAA,QAAA;oBAASO,IAAK,EAAA;;;0BAGjCN,GAACO,CAAAA,UAAAA,EAAAA;gBAAWC,UAAW,EAAA,MAAA;AAAQpB,gBAAAA,QAAAA,EAAAA;;;;AAGrC;;;;"}

View File

@@ -0,0 +1,593 @@
'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 reactDndHtml5Backend = require('react-dnd-html5-backend');
var reactIntl = require('react-intl');
var styledComponents = require('styled-components');
var admin = require('../../../services/admin.js');
var colors = require('../../../utils/colors.js');
var constants = require('../constants.js');
var useDragAndDrop = require('../hooks/useDragAndDrop.js');
var AddStage = require('./AddStage.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 Stages = ({ canDelete = true, canUpdate = true, isCreating })=>{
const { formatMessage } = reactIntl.useIntl();
const { trackUsage } = strapiAdmin.useTracking();
const addFieldRow = strapiAdmin.useForm('Stages', (state)=>state.addFieldRow);
const { value: stages = [] } = strapiAdmin.useField('stages');
return /*#__PURE__*/ jsxRuntime.jsxs(designSystem.Flex, {
direction: "column",
gap: 6,
width: "100%",
children: [
/*#__PURE__*/ jsxRuntime.jsxs(designSystem.Box, {
position: "relative",
width: "100%",
children: [
/*#__PURE__*/ jsxRuntime.jsx(Background, {
background: "neutral200",
height: "100%",
left: "50%",
position: "absolute",
top: "0",
width: 2
}),
/*#__PURE__*/ jsxRuntime.jsx(designSystem.Flex, {
direction: "column",
alignItems: "stretch",
gap: 6,
position: "relative",
tag: "ol",
children: stages.map((stage, index)=>{
return /*#__PURE__*/ jsxRuntime.jsx(designSystem.Box, {
tag: "li",
children: /*#__PURE__*/ jsxRuntime.jsx(Stage, {
index: index,
canDelete: stages.length > 1 && canDelete,
canReorder: stages.length > 1,
canUpdate: canUpdate,
stagesCount: stages.length,
defaultOpen: !stage.id,
...stage
})
}, stage.__temp_key__);
})
})
]
}),
canUpdate && /*#__PURE__*/ jsxRuntime.jsx(AddStage.AddStage, {
type: "button",
onClick: ()=>{
addFieldRow('stages', {
name: ''
});
trackUsage('willCreateStage');
},
children: formatMessage({
id: 'Settings.review-workflows.stage.add',
defaultMessage: 'Add new stage'
})
})
]
});
};
const Background = styledComponents.styled(designSystem.Box)`
transform: translateX(-50%);
`;
const Stage = ({ index, canDelete = false, canReorder = false, canUpdate = false, stagesCount, name, permissions, color, defaultOpen })=>{
const [liveText, setLiveText] = React__namespace.useState();
const { formatMessage } = reactIntl.useIntl();
const { trackUsage } = strapiAdmin.useTracking();
const stageErrors = strapiAdmin.useForm('Stages', (state)=>state.errors.stages);
const error = stageErrors?.[index];
const addFieldRow = strapiAdmin.useForm('Stage', (state)=>state.addFieldRow);
const moveFieldRow = strapiAdmin.useForm('Stage', (state)=>state.moveFieldRow);
const removeFieldRow = strapiAdmin.useForm('Stage', (state)=>state.removeFieldRow);
const getItemPos = (index)=>`${index + 1} of ${stagesCount}`;
const handleGrabStage = (index)=>{
setLiveText(formatMessage({
id: 'dnd.grab-item',
defaultMessage: `{item}, grabbed. Current position in list: {position}. Press up and down arrow to change position, Spacebar to drop, Escape to cancel.`
}, {
item: name,
position: getItemPos(index)
}));
};
const handleDropStage = (index)=>{
setLiveText(formatMessage({
id: 'dnd.drop-item',
defaultMessage: `{item}, dropped. Final position in list: {position}.`
}, {
item: name,
position: getItemPos(index)
}));
};
const handleCancelDragStage = ()=>{
setLiveText(formatMessage({
id: 'dnd.cancel-item',
defaultMessage: '{item}, dropped. Re-order cancelled.'
}, {
item: name
}));
};
const handleMoveStage = (newIndex, oldIndex)=>{
setLiveText(formatMessage({
id: 'dnd.reorder',
defaultMessage: '{item}, moved. New position in list: {position}.'
}, {
item: name,
position: getItemPos(newIndex)
}));
moveFieldRow('stages', oldIndex, newIndex);
};
const [{ handlerId, isDragging, handleKeyDown }, stageRef, dropRef, dragRef, dragPreviewRef] = useDragAndDrop.useDragAndDrop(canReorder, {
index,
item: {
index,
name
},
onGrabItem: handleGrabStage,
onDropItem: handleDropStage,
onMoveItem: handleMoveStage,
onCancel: handleCancelDragStage,
type: constants.DRAG_DROP_TYPES.STAGE
});
// @ts-expect-error the stageRef is incorrectly typed.
const composedRef = designSystem.useComposedRefs(stageRef, dropRef);
React__namespace.useEffect(()=>{
dragPreviewRef(reactDndHtml5Backend.getEmptyImage(), {
captureDraggingState: false
});
}, [
dragPreviewRef,
index
]);
const handleCloneClick = ()=>{
addFieldRow('stages', {
name,
color,
permissions
});
};
const id = React__namespace.useId();
return /*#__PURE__*/ jsxRuntime.jsxs(designSystem.Box, {
ref: composedRef,
shadow: "tableShadow",
children: [
liveText && /*#__PURE__*/ jsxRuntime.jsx(designSystem.VisuallyHidden, {
"aria-live": "assertive",
children: liveText
}),
isDragging ? /*#__PURE__*/ jsxRuntime.jsx(designSystem.Box, {
background: "primary100",
borderStyle: "dashed",
borderColor: "primary600",
borderWidth: "1px",
display: "block",
hasRadius: true,
padding: 6
}) : /*#__PURE__*/ jsxRuntime.jsx(AccordionRoot, {
onValueChange: (value)=>{
if (value) {
trackUsage('willEditStage');
}
},
defaultValue: defaultOpen ? id : undefined,
$error: Object.values(error ?? {}).length > 0,
children: /*#__PURE__*/ jsxRuntime.jsxs(designSystem.Accordion.Item, {
value: id,
children: [
/*#__PURE__*/ jsxRuntime.jsxs(designSystem.Accordion.Header, {
children: [
/*#__PURE__*/ jsxRuntime.jsx(designSystem.Accordion.Trigger, {
children: name
}),
/*#__PURE__*/ jsxRuntime.jsx(designSystem.Accordion.Actions, {
children: canDelete || canUpdate ? /*#__PURE__*/ jsxRuntime.jsxs(jsxRuntime.Fragment, {
children: [
/*#__PURE__*/ jsxRuntime.jsxs(designSystem.Menu.Root, {
children: [
/*#__PURE__*/ jsxRuntime.jsxs(ContextMenuTrigger, {
size: "S",
endIcon: null,
paddingLeft: 2,
paddingRight: 2,
children: [
/*#__PURE__*/ jsxRuntime.jsx(icons.More, {
"aria-hidden": true,
focusable: false
}),
/*#__PURE__*/ jsxRuntime.jsx(designSystem.VisuallyHidden, {
tag: "span",
children: formatMessage({
id: '[tbdb].components.DynamicZone.more-actions',
defaultMessage: 'More actions'
})
})
]
}),
/*#__PURE__*/ jsxRuntime.jsx(designSystem.Menu.Content, {
popoverPlacement: "bottom-end",
zIndex: 2,
children: /*#__PURE__*/ jsxRuntime.jsxs(designSystem.Menu.SubRoot, {
children: [
canUpdate && /*#__PURE__*/ jsxRuntime.jsx(designSystem.MenuItem, {
onClick: handleCloneClick,
children: formatMessage({
id: 'Settings.review-workflows.stage.delete',
defaultMessage: 'Duplicate stage'
})
}),
canDelete && /*#__PURE__*/ jsxRuntime.jsx(DeleteMenuItem, {
onClick: ()=>removeFieldRow('stages', index),
children: formatMessage({
id: 'Settings.review-workflows.stage.delete',
defaultMessage: 'Delete'
})
})
]
})
})
]
}),
canUpdate && /*#__PURE__*/ jsxRuntime.jsx(designSystem.IconButton, {
background: "transparent",
hasRadius: true,
variant: "ghost",
"data-handler-id": handlerId,
ref: dragRef,
label: formatMessage({
id: 'Settings.review-workflows.stage.drag',
defaultMessage: 'Drag'
}),
onClick: (e)=>e.stopPropagation(),
onKeyDown: handleKeyDown,
children: /*#__PURE__*/ jsxRuntime.jsx(icons.Drag, {})
})
]
}) : null
})
]
}),
/*#__PURE__*/ jsxRuntime.jsx(designSystem.Accordion.Content, {
children: /*#__PURE__*/ jsxRuntime.jsx(designSystem.Grid.Root, {
gap: 4,
padding: 6,
children: [
{
disabled: !canUpdate,
label: formatMessage({
id: 'Settings.review-workflows.stage.name.label',
defaultMessage: 'Stage name'
}),
name: `stages.${index}.name`,
required: true,
size: 6,
type: 'string'
},
{
disabled: !canUpdate,
label: formatMessage({
id: 'content-manager.reviewWorkflows.stage.color',
defaultMessage: 'Color'
}),
name: `stages.${index}.color`,
required: true,
size: 6,
type: 'color'
},
{
disabled: !canUpdate,
label: formatMessage({
id: 'Settings.review-workflows.stage.permissions.label',
defaultMessage: 'Roles that can change this stage'
}),
name: `stages.${index}.permissions`,
placeholder: formatMessage({
id: 'Settings.review-workflows.stage.permissions.placeholder',
defaultMessage: 'Select a role'
}),
required: true,
size: 6,
type: 'permissions'
}
].map(({ size, ...field })=>/*#__PURE__*/ jsxRuntime.jsx(designSystem.Grid.Item, {
col: size,
direction: "column",
alignItems: "stretch",
children: /*#__PURE__*/ jsxRuntime.jsx(InputRenderer, {
...field
})
}, field.name))
})
})
]
})
})
]
});
};
const AccordionRoot = styledComponents.styled(designSystem.Accordion.Root)`
border: 1px solid
${({ theme, $error })=>$error ? theme.colors.danger600 : theme.colors.neutral200};
`;
const DeleteMenuItem = styledComponents.styled(designSystem.MenuItem)`
color: ${({ theme })=>theme.colors.danger600};
`;
// Removing the font-size from the child-span aligns the
// more icon vertically
const ContextMenuTrigger = styledComponents.styled(designSystem.Menu.Trigger)`
:hover,
:focus {
background-color: ${({ theme })=>theme.colors.neutral100};
}
> span {
font-size: 0;
}
`;
const InputRenderer = (props)=>{
switch(props.type){
case 'color':
return /*#__PURE__*/ jsxRuntime.jsx(ColorSelector, {
...props
});
case 'permissions':
return /*#__PURE__*/ jsxRuntime.jsx(PermissionsField, {
...props
});
default:
return /*#__PURE__*/ jsxRuntime.jsx(strapiAdmin.InputRenderer, {
...props
});
}
};
const ColorSelector = ({ disabled, label, name, required })=>{
const { formatMessage } = reactIntl.useIntl();
const { value, error, onChange } = strapiAdmin.useField(name);
const colorOptions = colors.AVAILABLE_COLORS.map(({ hex, name })=>({
value: hex,
label: formatMessage({
id: 'Settings.review-workflows.stage.color.name',
defaultMessage: '{name}'
}, {
name
}),
color: hex
}));
const { themeColorName } = colors.getStageColorByHex(value) ?? {};
return /*#__PURE__*/ jsxRuntime.jsxs(designSystem.Field.Root, {
error: error,
name: name,
required: required,
children: [
/*#__PURE__*/ jsxRuntime.jsx(designSystem.Field.Label, {
children: label
}),
/*#__PURE__*/ jsxRuntime.jsx(designSystem.SingleSelect, {
disabled: disabled,
onChange: (v)=>{
onChange(name, v.toString());
},
value: value?.toUpperCase(),
startIcon: /*#__PURE__*/ jsxRuntime.jsx(designSystem.Flex, {
tag: "span",
height: 2,
background: value,
borderColor: themeColorName === 'neutral0' ? 'neutral150' : 'transparent',
hasRadius: true,
shrink: 0,
width: 2
}),
children: colorOptions.map(({ value, label, color })=>{
const { themeColorName } = colors.getStageColorByHex(color) || {};
return /*#__PURE__*/ jsxRuntime.jsx(designSystem.SingleSelectOption, {
value: value,
startIcon: /*#__PURE__*/ jsxRuntime.jsx(designSystem.Flex, {
tag: "span",
height: 2,
background: color,
borderColor: themeColorName === 'neutral0' ? 'neutral150' : 'transparent',
hasRadius: true,
shrink: 0,
width: 2
}),
children: label
}, value);
})
}),
/*#__PURE__*/ jsxRuntime.jsx(designSystem.Field.Error, {})
]
});
};
const PermissionsField = ({ disabled, name, placeholder, required })=>{
const { formatMessage } = reactIntl.useIntl();
const { toggleNotification } = strapiAdmin.useNotification();
const [isApplyAllConfirmationOpen, setIsApplyAllConfirmationOpen] = React__namespace.useState(false);
const { value = [], error, onChange } = strapiAdmin.useField(name);
const allStages = strapiAdmin.useForm('PermissionsField', (state)=>state.values.stages);
const onFormValueChange = strapiAdmin.useForm('PermissionsField', (state)=>state.onChange);
const rolesErrorCount = React__namespace.useRef(0);
const { data: roles = [], isLoading, error: getRolesError } = admin.useGetAdminRolesQuery();
// Super admins always have permissions to do everything and therefore
// there is no point for this role to show up in the role combobox
const filteredRoles = roles?.filter((role)=>role.code !== 'strapi-super-admin') ?? [];
React__namespace.useEffect(()=>{
if (!isLoading && getRolesError && 'status' in getRolesError && getRolesError.status == 403 && rolesErrorCount.current === 0) {
rolesErrorCount.current = 1;
toggleNotification({
blockTransition: true,
type: 'danger',
message: formatMessage({
id: 'review-workflows.stage.permissions.noPermissions.description',
defaultMessage: 'You dont have the permission to see roles. Contact your administrator.'
})
});
}
}, [
formatMessage,
isLoading,
roles,
toggleNotification,
getRolesError
]);
if (!isLoading && filteredRoles.length === 0) {
return /*#__PURE__*/ jsxRuntime.jsxs(designSystem.Field.Root, {
name: name,
hint: formatMessage({
id: 'Settings.review-workflows.stage.permissions.noPermissions.description',
defaultMessage: 'You dont have the permission to see roles'
}),
required: required,
children: [
/*#__PURE__*/ jsxRuntime.jsx(designSystem.Field.Label, {
children: formatMessage({
id: 'Settings.review-workflows.stage.permissions.label',
defaultMessage: 'Roles that can change this stage'
})
}),
/*#__PURE__*/ jsxRuntime.jsx(designSystem.TextInput, {
disabled: true,
placeholder: formatMessage({
id: 'components.NotAllowedInput.text',
defaultMessage: 'No permissions to see this field'
}),
startAction: /*#__PURE__*/ jsxRuntime.jsx(icons.EyeStriked, {
fill: "neutral600"
}),
type: "text",
value: ""
}),
/*#__PURE__*/ jsxRuntime.jsx(designSystem.Field.Hint, {})
]
});
}
return /*#__PURE__*/ jsxRuntime.jsx(jsxRuntime.Fragment, {
children: /*#__PURE__*/ jsxRuntime.jsxs(designSystem.Flex, {
alignItems: "flex-end",
gap: 3,
children: [
/*#__PURE__*/ jsxRuntime.jsx(PermissionWrapper, {
grow: 1,
children: /*#__PURE__*/ jsxRuntime.jsxs(designSystem.Field.Root, {
error: error,
name: name,
required: true,
children: [
/*#__PURE__*/ jsxRuntime.jsx(designSystem.Field.Label, {
children: formatMessage({
id: 'Settings.review-workflows.stage.permissions.label',
defaultMessage: 'Roles that can change this stage'
})
}),
/*#__PURE__*/ jsxRuntime.jsx(designSystem.MultiSelect, {
disabled: disabled,
onChange: (values)=>{
// Because the select components expects strings for values, but
// the yup schema validates we are sending full permission objects to the API,
// we must coerce the string value back to an object
const permissions = values.map((value)=>({
role: parseInt(value, 10),
action: 'admin::review-workflows.stage.transition'
}));
onChange(name, permissions);
},
placeholder: placeholder,
// The Select component expects strings for values
value: value.map((permission)=>`${permission.role}`),
withTags: true,
children: /*#__PURE__*/ jsxRuntime.jsx(designSystem.MultiSelectGroup, {
label: formatMessage({
id: 'Settings.review-workflows.stage.permissions.allRoles.label',
defaultMessage: 'All roles'
}),
values: filteredRoles.map((r)=>`${r.id}`),
children: filteredRoles.map((role)=>{
return /*#__PURE__*/ jsxRuntime.jsx(NestedOption, {
value: `${role.id}`,
children: role.name
}, role.id);
})
})
}),
/*#__PURE__*/ jsxRuntime.jsx(designSystem.Field.Error, {})
]
})
}),
/*#__PURE__*/ jsxRuntime.jsxs(designSystem.Dialog.Root, {
open: isApplyAllConfirmationOpen,
onOpenChange: setIsApplyAllConfirmationOpen,
children: [
/*#__PURE__*/ jsxRuntime.jsx(designSystem.Dialog.Trigger, {
children: /*#__PURE__*/ jsxRuntime.jsx(designSystem.IconButton, {
disabled: disabled,
label: formatMessage({
id: 'Settings.review-workflows.stage.permissions.apply.label',
defaultMessage: 'Apply to all stages'
}),
size: "L",
children: /*#__PURE__*/ jsxRuntime.jsx(icons.Duplicate, {})
})
}),
/*#__PURE__*/ jsxRuntime.jsx(strapiAdmin.ConfirmDialog, {
onConfirm: ()=>{
onFormValueChange('stages', allStages.map((stage)=>({
...stage,
permissions: value
})));
setIsApplyAllConfirmationOpen(false);
toggleNotification({
type: 'success',
message: formatMessage({
id: 'Settings.review-workflows.page.edit.confirm.stages.permissions.copy.success',
defaultMessage: 'Applied roles to all other stages of the workflow'
})
});
},
variant: "default",
children: formatMessage({
id: 'Settings.review-workflows.page.edit.confirm.stages.permissions.copy',
defaultMessage: 'Roles that can change that stage will be applied to all the other stages.'
})
})
]
})
]
})
});
};
const NestedOption = styledComponents.styled(designSystem.MultiSelectOption)`
padding-left: ${({ theme })=>theme.spaces[7]};
`;
// Grow the size of the permission Select
const PermissionWrapper = styledComponents.styled(designSystem.Flex)`
> * {
flex-grow: 1;
}
`;
exports.Stages = Stages;
//# sourceMappingURL=Stages.js.map

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,572 @@
import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
import * as React from 'react';
import { useTracking, useForm, useField, InputRenderer as InputRenderer$1, useNotification, ConfirmDialog } from '@strapi/admin/strapi-admin';
import { Box, Accordion, MenuItem, Menu, MultiSelectOption, Flex, useComposedRefs, VisuallyHidden, IconButton, Grid, Field, SingleSelect, SingleSelectOption, TextInput, MultiSelect, MultiSelectGroup, Dialog } from '@strapi/design-system';
import { More, Drag, EyeStriked, Duplicate } from '@strapi/icons';
import { getEmptyImage } from 'react-dnd-html5-backend';
import { useIntl } from 'react-intl';
import { styled } from 'styled-components';
import { useGetAdminRolesQuery } from '../../../services/admin.mjs';
import { AVAILABLE_COLORS, getStageColorByHex } from '../../../utils/colors.mjs';
import { DRAG_DROP_TYPES } from '../constants.mjs';
import { useDragAndDrop } from '../hooks/useDragAndDrop.mjs';
import { AddStage } from './AddStage.mjs';
const Stages = ({ canDelete = true, canUpdate = true, isCreating })=>{
const { formatMessage } = useIntl();
const { trackUsage } = useTracking();
const addFieldRow = useForm('Stages', (state)=>state.addFieldRow);
const { value: stages = [] } = useField('stages');
return /*#__PURE__*/ jsxs(Flex, {
direction: "column",
gap: 6,
width: "100%",
children: [
/*#__PURE__*/ jsxs(Box, {
position: "relative",
width: "100%",
children: [
/*#__PURE__*/ jsx(Background, {
background: "neutral200",
height: "100%",
left: "50%",
position: "absolute",
top: "0",
width: 2
}),
/*#__PURE__*/ jsx(Flex, {
direction: "column",
alignItems: "stretch",
gap: 6,
position: "relative",
tag: "ol",
children: stages.map((stage, index)=>{
return /*#__PURE__*/ jsx(Box, {
tag: "li",
children: /*#__PURE__*/ jsx(Stage, {
index: index,
canDelete: stages.length > 1 && canDelete,
canReorder: stages.length > 1,
canUpdate: canUpdate,
stagesCount: stages.length,
defaultOpen: !stage.id,
...stage
})
}, stage.__temp_key__);
})
})
]
}),
canUpdate && /*#__PURE__*/ jsx(AddStage, {
type: "button",
onClick: ()=>{
addFieldRow('stages', {
name: ''
});
trackUsage('willCreateStage');
},
children: formatMessage({
id: 'Settings.review-workflows.stage.add',
defaultMessage: 'Add new stage'
})
})
]
});
};
const Background = styled(Box)`
transform: translateX(-50%);
`;
const Stage = ({ index, canDelete = false, canReorder = false, canUpdate = false, stagesCount, name, permissions, color, defaultOpen })=>{
const [liveText, setLiveText] = React.useState();
const { formatMessage } = useIntl();
const { trackUsage } = useTracking();
const stageErrors = useForm('Stages', (state)=>state.errors.stages);
const error = stageErrors?.[index];
const addFieldRow = useForm('Stage', (state)=>state.addFieldRow);
const moveFieldRow = useForm('Stage', (state)=>state.moveFieldRow);
const removeFieldRow = useForm('Stage', (state)=>state.removeFieldRow);
const getItemPos = (index)=>`${index + 1} of ${stagesCount}`;
const handleGrabStage = (index)=>{
setLiveText(formatMessage({
id: 'dnd.grab-item',
defaultMessage: `{item}, grabbed. Current position in list: {position}. Press up and down arrow to change position, Spacebar to drop, Escape to cancel.`
}, {
item: name,
position: getItemPos(index)
}));
};
const handleDropStage = (index)=>{
setLiveText(formatMessage({
id: 'dnd.drop-item',
defaultMessage: `{item}, dropped. Final position in list: {position}.`
}, {
item: name,
position: getItemPos(index)
}));
};
const handleCancelDragStage = ()=>{
setLiveText(formatMessage({
id: 'dnd.cancel-item',
defaultMessage: '{item}, dropped. Re-order cancelled.'
}, {
item: name
}));
};
const handleMoveStage = (newIndex, oldIndex)=>{
setLiveText(formatMessage({
id: 'dnd.reorder',
defaultMessage: '{item}, moved. New position in list: {position}.'
}, {
item: name,
position: getItemPos(newIndex)
}));
moveFieldRow('stages', oldIndex, newIndex);
};
const [{ handlerId, isDragging, handleKeyDown }, stageRef, dropRef, dragRef, dragPreviewRef] = useDragAndDrop(canReorder, {
index,
item: {
index,
name
},
onGrabItem: handleGrabStage,
onDropItem: handleDropStage,
onMoveItem: handleMoveStage,
onCancel: handleCancelDragStage,
type: DRAG_DROP_TYPES.STAGE
});
// @ts-expect-error the stageRef is incorrectly typed.
const composedRef = useComposedRefs(stageRef, dropRef);
React.useEffect(()=>{
dragPreviewRef(getEmptyImage(), {
captureDraggingState: false
});
}, [
dragPreviewRef,
index
]);
const handleCloneClick = ()=>{
addFieldRow('stages', {
name,
color,
permissions
});
};
const id = React.useId();
return /*#__PURE__*/ jsxs(Box, {
ref: composedRef,
shadow: "tableShadow",
children: [
liveText && /*#__PURE__*/ jsx(VisuallyHidden, {
"aria-live": "assertive",
children: liveText
}),
isDragging ? /*#__PURE__*/ jsx(Box, {
background: "primary100",
borderStyle: "dashed",
borderColor: "primary600",
borderWidth: "1px",
display: "block",
hasRadius: true,
padding: 6
}) : /*#__PURE__*/ jsx(AccordionRoot, {
onValueChange: (value)=>{
if (value) {
trackUsage('willEditStage');
}
},
defaultValue: defaultOpen ? id : undefined,
$error: Object.values(error ?? {}).length > 0,
children: /*#__PURE__*/ jsxs(Accordion.Item, {
value: id,
children: [
/*#__PURE__*/ jsxs(Accordion.Header, {
children: [
/*#__PURE__*/ jsx(Accordion.Trigger, {
children: name
}),
/*#__PURE__*/ jsx(Accordion.Actions, {
children: canDelete || canUpdate ? /*#__PURE__*/ jsxs(Fragment, {
children: [
/*#__PURE__*/ jsxs(Menu.Root, {
children: [
/*#__PURE__*/ jsxs(ContextMenuTrigger, {
size: "S",
endIcon: null,
paddingLeft: 2,
paddingRight: 2,
children: [
/*#__PURE__*/ jsx(More, {
"aria-hidden": true,
focusable: false
}),
/*#__PURE__*/ jsx(VisuallyHidden, {
tag: "span",
children: formatMessage({
id: '[tbdb].components.DynamicZone.more-actions',
defaultMessage: 'More actions'
})
})
]
}),
/*#__PURE__*/ jsx(Menu.Content, {
popoverPlacement: "bottom-end",
zIndex: 2,
children: /*#__PURE__*/ jsxs(Menu.SubRoot, {
children: [
canUpdate && /*#__PURE__*/ jsx(MenuItem, {
onClick: handleCloneClick,
children: formatMessage({
id: 'Settings.review-workflows.stage.delete',
defaultMessage: 'Duplicate stage'
})
}),
canDelete && /*#__PURE__*/ jsx(DeleteMenuItem, {
onClick: ()=>removeFieldRow('stages', index),
children: formatMessage({
id: 'Settings.review-workflows.stage.delete',
defaultMessage: 'Delete'
})
})
]
})
})
]
}),
canUpdate && /*#__PURE__*/ jsx(IconButton, {
background: "transparent",
hasRadius: true,
variant: "ghost",
"data-handler-id": handlerId,
ref: dragRef,
label: formatMessage({
id: 'Settings.review-workflows.stage.drag',
defaultMessage: 'Drag'
}),
onClick: (e)=>e.stopPropagation(),
onKeyDown: handleKeyDown,
children: /*#__PURE__*/ jsx(Drag, {})
})
]
}) : null
})
]
}),
/*#__PURE__*/ jsx(Accordion.Content, {
children: /*#__PURE__*/ jsx(Grid.Root, {
gap: 4,
padding: 6,
children: [
{
disabled: !canUpdate,
label: formatMessage({
id: 'Settings.review-workflows.stage.name.label',
defaultMessage: 'Stage name'
}),
name: `stages.${index}.name`,
required: true,
size: 6,
type: 'string'
},
{
disabled: !canUpdate,
label: formatMessage({
id: 'content-manager.reviewWorkflows.stage.color',
defaultMessage: 'Color'
}),
name: `stages.${index}.color`,
required: true,
size: 6,
type: 'color'
},
{
disabled: !canUpdate,
label: formatMessage({
id: 'Settings.review-workflows.stage.permissions.label',
defaultMessage: 'Roles that can change this stage'
}),
name: `stages.${index}.permissions`,
placeholder: formatMessage({
id: 'Settings.review-workflows.stage.permissions.placeholder',
defaultMessage: 'Select a role'
}),
required: true,
size: 6,
type: 'permissions'
}
].map(({ size, ...field })=>/*#__PURE__*/ jsx(Grid.Item, {
col: size,
direction: "column",
alignItems: "stretch",
children: /*#__PURE__*/ jsx(InputRenderer, {
...field
})
}, field.name))
})
})
]
})
})
]
});
};
const AccordionRoot = styled(Accordion.Root)`
border: 1px solid
${({ theme, $error })=>$error ? theme.colors.danger600 : theme.colors.neutral200};
`;
const DeleteMenuItem = styled(MenuItem)`
color: ${({ theme })=>theme.colors.danger600};
`;
// Removing the font-size from the child-span aligns the
// more icon vertically
const ContextMenuTrigger = styled(Menu.Trigger)`
:hover,
:focus {
background-color: ${({ theme })=>theme.colors.neutral100};
}
> span {
font-size: 0;
}
`;
const InputRenderer = (props)=>{
switch(props.type){
case 'color':
return /*#__PURE__*/ jsx(ColorSelector, {
...props
});
case 'permissions':
return /*#__PURE__*/ jsx(PermissionsField, {
...props
});
default:
return /*#__PURE__*/ jsx(InputRenderer$1, {
...props
});
}
};
const ColorSelector = ({ disabled, label, name, required })=>{
const { formatMessage } = useIntl();
const { value, error, onChange } = useField(name);
const colorOptions = AVAILABLE_COLORS.map(({ hex, name })=>({
value: hex,
label: formatMessage({
id: 'Settings.review-workflows.stage.color.name',
defaultMessage: '{name}'
}, {
name
}),
color: hex
}));
const { themeColorName } = getStageColorByHex(value) ?? {};
return /*#__PURE__*/ jsxs(Field.Root, {
error: error,
name: name,
required: required,
children: [
/*#__PURE__*/ jsx(Field.Label, {
children: label
}),
/*#__PURE__*/ jsx(SingleSelect, {
disabled: disabled,
onChange: (v)=>{
onChange(name, v.toString());
},
value: value?.toUpperCase(),
startIcon: /*#__PURE__*/ jsx(Flex, {
tag: "span",
height: 2,
background: value,
borderColor: themeColorName === 'neutral0' ? 'neutral150' : 'transparent',
hasRadius: true,
shrink: 0,
width: 2
}),
children: colorOptions.map(({ value, label, color })=>{
const { themeColorName } = getStageColorByHex(color) || {};
return /*#__PURE__*/ jsx(SingleSelectOption, {
value: value,
startIcon: /*#__PURE__*/ jsx(Flex, {
tag: "span",
height: 2,
background: color,
borderColor: themeColorName === 'neutral0' ? 'neutral150' : 'transparent',
hasRadius: true,
shrink: 0,
width: 2
}),
children: label
}, value);
})
}),
/*#__PURE__*/ jsx(Field.Error, {})
]
});
};
const PermissionsField = ({ disabled, name, placeholder, required })=>{
const { formatMessage } = useIntl();
const { toggleNotification } = useNotification();
const [isApplyAllConfirmationOpen, setIsApplyAllConfirmationOpen] = React.useState(false);
const { value = [], error, onChange } = useField(name);
const allStages = useForm('PermissionsField', (state)=>state.values.stages);
const onFormValueChange = useForm('PermissionsField', (state)=>state.onChange);
const rolesErrorCount = React.useRef(0);
const { data: roles = [], isLoading, error: getRolesError } = useGetAdminRolesQuery();
// Super admins always have permissions to do everything and therefore
// there is no point for this role to show up in the role combobox
const filteredRoles = roles?.filter((role)=>role.code !== 'strapi-super-admin') ?? [];
React.useEffect(()=>{
if (!isLoading && getRolesError && 'status' in getRolesError && getRolesError.status == 403 && rolesErrorCount.current === 0) {
rolesErrorCount.current = 1;
toggleNotification({
blockTransition: true,
type: 'danger',
message: formatMessage({
id: 'review-workflows.stage.permissions.noPermissions.description',
defaultMessage: 'You dont have the permission to see roles. Contact your administrator.'
})
});
}
}, [
formatMessage,
isLoading,
roles,
toggleNotification,
getRolesError
]);
if (!isLoading && filteredRoles.length === 0) {
return /*#__PURE__*/ jsxs(Field.Root, {
name: name,
hint: formatMessage({
id: 'Settings.review-workflows.stage.permissions.noPermissions.description',
defaultMessage: 'You dont have the permission to see roles'
}),
required: required,
children: [
/*#__PURE__*/ jsx(Field.Label, {
children: formatMessage({
id: 'Settings.review-workflows.stage.permissions.label',
defaultMessage: 'Roles that can change this stage'
})
}),
/*#__PURE__*/ jsx(TextInput, {
disabled: true,
placeholder: formatMessage({
id: 'components.NotAllowedInput.text',
defaultMessage: 'No permissions to see this field'
}),
startAction: /*#__PURE__*/ jsx(EyeStriked, {
fill: "neutral600"
}),
type: "text",
value: ""
}),
/*#__PURE__*/ jsx(Field.Hint, {})
]
});
}
return /*#__PURE__*/ jsx(Fragment, {
children: /*#__PURE__*/ jsxs(Flex, {
alignItems: "flex-end",
gap: 3,
children: [
/*#__PURE__*/ jsx(PermissionWrapper, {
grow: 1,
children: /*#__PURE__*/ jsxs(Field.Root, {
error: error,
name: name,
required: true,
children: [
/*#__PURE__*/ jsx(Field.Label, {
children: formatMessage({
id: 'Settings.review-workflows.stage.permissions.label',
defaultMessage: 'Roles that can change this stage'
})
}),
/*#__PURE__*/ jsx(MultiSelect, {
disabled: disabled,
onChange: (values)=>{
// Because the select components expects strings for values, but
// the yup schema validates we are sending full permission objects to the API,
// we must coerce the string value back to an object
const permissions = values.map((value)=>({
role: parseInt(value, 10),
action: 'admin::review-workflows.stage.transition'
}));
onChange(name, permissions);
},
placeholder: placeholder,
// The Select component expects strings for values
value: value.map((permission)=>`${permission.role}`),
withTags: true,
children: /*#__PURE__*/ jsx(MultiSelectGroup, {
label: formatMessage({
id: 'Settings.review-workflows.stage.permissions.allRoles.label',
defaultMessage: 'All roles'
}),
values: filteredRoles.map((r)=>`${r.id}`),
children: filteredRoles.map((role)=>{
return /*#__PURE__*/ jsx(NestedOption, {
value: `${role.id}`,
children: role.name
}, role.id);
})
})
}),
/*#__PURE__*/ jsx(Field.Error, {})
]
})
}),
/*#__PURE__*/ jsxs(Dialog.Root, {
open: isApplyAllConfirmationOpen,
onOpenChange: setIsApplyAllConfirmationOpen,
children: [
/*#__PURE__*/ jsx(Dialog.Trigger, {
children: /*#__PURE__*/ jsx(IconButton, {
disabled: disabled,
label: formatMessage({
id: 'Settings.review-workflows.stage.permissions.apply.label',
defaultMessage: 'Apply to all stages'
}),
size: "L",
children: /*#__PURE__*/ jsx(Duplicate, {})
})
}),
/*#__PURE__*/ jsx(ConfirmDialog, {
onConfirm: ()=>{
onFormValueChange('stages', allStages.map((stage)=>({
...stage,
permissions: value
})));
setIsApplyAllConfirmationOpen(false);
toggleNotification({
type: 'success',
message: formatMessage({
id: 'Settings.review-workflows.page.edit.confirm.stages.permissions.copy.success',
defaultMessage: 'Applied roles to all other stages of the workflow'
})
});
},
variant: "default",
children: formatMessage({
id: 'Settings.review-workflows.page.edit.confirm.stages.permissions.copy',
defaultMessage: 'Roles that can change that stage will be applied to all the other stages.'
})
})
]
})
]
})
});
};
const NestedOption = styled(MultiSelectOption)`
padding-left: ${({ theme })=>theme.spaces[7]};
`;
// Grow the size of the permission Select
const PermissionWrapper = styled(Flex)`
> * {
flex-grow: 1;
}
`;
export { Stages };
//# sourceMappingURL=Stages.mjs.map

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,203 @@
'use strict';
var jsxRuntime = require('react/jsx-runtime');
var strapiAdmin = require('@strapi/admin/strapi-admin');
var designSystem = require('@strapi/design-system');
var reactIntl = require('react-intl');
var styledComponents = require('styled-components');
var contentManager = require('../../../services/content-manager.js');
var useReviewWorkflows = require('../hooks/useReviewWorkflows.js');
const WorkflowAttributes = ({ canUpdate = true })=>{
const { formatMessage } = reactIntl.useIntl();
return /*#__PURE__*/ jsxRuntime.jsxs(designSystem.Grid.Root, {
background: "neutral0",
hasRadius: true,
gap: 4,
padding: 6,
shadow: "tableShadow",
children: [
/*#__PURE__*/ jsxRuntime.jsx(designSystem.Grid.Item, {
col: 6,
direction: "column",
alignItems: "stretch",
children: /*#__PURE__*/ jsxRuntime.jsx(strapiAdmin.InputRenderer, {
disabled: !canUpdate,
label: formatMessage({
id: 'Settings.review-workflows.workflow.name.label',
defaultMessage: 'Workflow Name'
}),
name: "name",
required: true,
type: "string"
})
}),
/*#__PURE__*/ jsxRuntime.jsx(designSystem.Grid.Item, {
col: 6,
direction: "column",
alignItems: "stretch",
children: /*#__PURE__*/ jsxRuntime.jsx(ContentTypesSelector, {
disabled: !canUpdate
})
}),
/*#__PURE__*/ jsxRuntime.jsx(designSystem.Grid.Item, {
col: 6,
direction: "column",
alignItems: "stretch",
children: /*#__PURE__*/ jsxRuntime.jsx(StageSelector, {
disabled: !canUpdate
})
})
]
});
};
const ContentTypesSelector = ({ disabled })=>{
const { formatMessage, locale } = reactIntl.useIntl();
const { data: contentTypes, isLoading } = contentManager.useGetContentTypesQuery();
const { workflows } = useReviewWorkflows.useReviewWorkflows();
const currentWorkflow = strapiAdmin.useForm('ContentTypesSelector', (state)=>state.values);
const { error, value, onChange } = strapiAdmin.useField('contentTypes');
const formatter = designSystem.useCollator(locale, {
sensitivity: 'base'
});
const isDisabled = disabled || isLoading || !contentTypes || contentTypes.collectionType.length === 0 && contentTypes.singleType.length === 0;
const collectionTypes = (contentTypes?.collectionType ?? []).toSorted((a, b)=>formatter.compare(a.info.displayName, b.info.displayName)).map((contentType)=>({
label: contentType.info.displayName,
value: contentType.uid
}));
const singleTypes = (contentTypes?.singleType ?? []).map((contentType)=>({
label: contentType.info.displayName,
value: contentType.uid
}));
return /*#__PURE__*/ jsxRuntime.jsxs(designSystem.Field.Root, {
error: error,
name: 'contentTypes',
children: [
/*#__PURE__*/ jsxRuntime.jsx(designSystem.Field.Label, {
children: formatMessage({
id: 'Settings.review-workflows.workflow.contentTypes.label',
defaultMessage: 'Associated to'
})
}),
/*#__PURE__*/ jsxRuntime.jsx(designSystem.MultiSelect, {
customizeContent: (value)=>formatMessage({
id: 'Settings.review-workflows.workflow.contentTypes.displayValue',
defaultMessage: '{count} {count, plural, one {content type} other {content types}} selected'
}, {
count: value?.length
}),
disabled: isDisabled,
onChange: (values)=>{
onChange('contentTypes', values);
},
value: value,
placeholder: formatMessage({
id: 'Settings.review-workflows.workflow.contentTypes.placeholder',
defaultMessage: 'Select'
}),
children: [
...collectionTypes.length > 0 ? [
{
label: formatMessage({
id: 'Settings.review-workflows.workflow.contentTypes.collectionTypes.label',
defaultMessage: 'Collection Types'
}),
children: collectionTypes
}
] : [],
...singleTypes.length > 0 ? [
{
label: formatMessage({
id: 'Settings.review-workflows.workflow.contentTypes.singleTypes.label',
defaultMessage: 'Single Types'
}),
children: singleTypes
}
] : []
].map((opt)=>{
return /*#__PURE__*/ jsxRuntime.jsx(designSystem.MultiSelectGroup, {
label: opt.label,
values: opt.children.map((child)=>child.value.toString()),
children: opt.children.map((child)=>{
const { name: assignedWorkflowName } = workflows?.find((workflow)=>(currentWorkflow && workflow.id !== currentWorkflow.id || !currentWorkflow) && workflow.contentTypes.includes(child.value)) ?? {};
return /*#__PURE__*/ jsxRuntime.jsx(NestedOption, {
value: child.value,
children: /*#__PURE__*/ jsxRuntime.jsx(designSystem.Typography, {
children: // @ts-expect-error - formatMessage options doesn't expect to be a React component but that's what we need actually for the <i> and <em> components
formatMessage({
id: 'Settings.review-workflows.workflow.contentTypes.assigned.notice',
defaultMessage: '{label} {name, select, undefined {} other {<i>(assigned to <em>{name}</em> workflow)</i>}}'
}, {
label: child.label,
name: assignedWorkflowName,
em: (...children)=>/*#__PURE__*/ jsxRuntime.jsx(designSystem.Typography, {
tag: "em",
fontWeight: "bold",
children: children
}),
i: (...children)=>/*#__PURE__*/ jsxRuntime.jsx(ContentTypeTakeNotice, {
children: children
})
})
})
}, child.value);
})
}, opt.label);
})
})
]
});
};
const NestedOption = styledComponents.styled(designSystem.MultiSelectOption)`
padding-left: ${({ theme })=>theme.spaces[7]};
`;
const ContentTypeTakeNotice = styledComponents.styled(designSystem.Typography)`
font-style: italic;
`;
const StageSelector = ({ disabled })=>{
const { value: stages = [] } = strapiAdmin.useField('stages');
const { formatMessage } = reactIntl.useIntl();
const { error, value, onChange } = strapiAdmin.useField('stageRequiredToPublish');
// stages with empty names are not valid, so we avoid them from being used to avoid errors
const validStages = stages.filter((stage)=>stage.name);
return /*#__PURE__*/ jsxRuntime.jsxs(designSystem.Field.Root, {
error: error,
name: "stageRequiredToPublish",
hint: formatMessage({
id: 'settings.review-workflows.workflow.stageRequiredToPublish.hint',
defaultMessage: 'Prevents entries from being published if they are not at the required stage.'
}),
children: [
/*#__PURE__*/ jsxRuntime.jsx(designSystem.Field.Label, {
children: formatMessage({
id: 'settings.review-workflows.workflow.stageRequiredToPublish.label',
defaultMessage: 'Required stage for publishing'
})
}),
/*#__PURE__*/ jsxRuntime.jsxs(designSystem.SingleSelect, {
disabled: disabled,
onChange: (value)=>{
onChange('stageRequiredToPublish', value);
},
value: value,
children: [
/*#__PURE__*/ jsxRuntime.jsx(designSystem.SingleSelectOption, {
value: '',
children: formatMessage({
id: 'settings.review-workflows.workflow.stageRequiredToPublish.any',
defaultMessage: 'Any stage'
})
}),
validStages.map((stage, i)=>/*#__PURE__*/ jsxRuntime.jsx(designSystem.SingleSelectOption, {
value: stage.id?.toString() || stage.__temp_key__,
children: stage.name
}, `requiredToPublishStage-${stage.id || stage.__temp_key__}`))
]
}),
/*#__PURE__*/ jsxRuntime.jsx(designSystem.Field.Hint, {})
]
});
};
exports.WorkflowAttributes = WorkflowAttributes;
//# sourceMappingURL=WorkflowAttributes.js.map

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,201 @@
import { jsxs, jsx } from 'react/jsx-runtime';
import { InputRenderer, useForm, useField } from '@strapi/admin/strapi-admin';
import { MultiSelectOption, Typography, Grid, useCollator, Field, MultiSelect, MultiSelectGroup, SingleSelect, SingleSelectOption } from '@strapi/design-system';
import { useIntl } from 'react-intl';
import { styled } from 'styled-components';
import { useGetContentTypesQuery } from '../../../services/content-manager.mjs';
import { useReviewWorkflows } from '../hooks/useReviewWorkflows.mjs';
const WorkflowAttributes = ({ canUpdate = true })=>{
const { formatMessage } = useIntl();
return /*#__PURE__*/ jsxs(Grid.Root, {
background: "neutral0",
hasRadius: true,
gap: 4,
padding: 6,
shadow: "tableShadow",
children: [
/*#__PURE__*/ jsx(Grid.Item, {
col: 6,
direction: "column",
alignItems: "stretch",
children: /*#__PURE__*/ jsx(InputRenderer, {
disabled: !canUpdate,
label: formatMessage({
id: 'Settings.review-workflows.workflow.name.label',
defaultMessage: 'Workflow Name'
}),
name: "name",
required: true,
type: "string"
})
}),
/*#__PURE__*/ jsx(Grid.Item, {
col: 6,
direction: "column",
alignItems: "stretch",
children: /*#__PURE__*/ jsx(ContentTypesSelector, {
disabled: !canUpdate
})
}),
/*#__PURE__*/ jsx(Grid.Item, {
col: 6,
direction: "column",
alignItems: "stretch",
children: /*#__PURE__*/ jsx(StageSelector, {
disabled: !canUpdate
})
})
]
});
};
const ContentTypesSelector = ({ disabled })=>{
const { formatMessage, locale } = useIntl();
const { data: contentTypes, isLoading } = useGetContentTypesQuery();
const { workflows } = useReviewWorkflows();
const currentWorkflow = useForm('ContentTypesSelector', (state)=>state.values);
const { error, value, onChange } = useField('contentTypes');
const formatter = useCollator(locale, {
sensitivity: 'base'
});
const isDisabled = disabled || isLoading || !contentTypes || contentTypes.collectionType.length === 0 && contentTypes.singleType.length === 0;
const collectionTypes = (contentTypes?.collectionType ?? []).toSorted((a, b)=>formatter.compare(a.info.displayName, b.info.displayName)).map((contentType)=>({
label: contentType.info.displayName,
value: contentType.uid
}));
const singleTypes = (contentTypes?.singleType ?? []).map((contentType)=>({
label: contentType.info.displayName,
value: contentType.uid
}));
return /*#__PURE__*/ jsxs(Field.Root, {
error: error,
name: 'contentTypes',
children: [
/*#__PURE__*/ jsx(Field.Label, {
children: formatMessage({
id: 'Settings.review-workflows.workflow.contentTypes.label',
defaultMessage: 'Associated to'
})
}),
/*#__PURE__*/ jsx(MultiSelect, {
customizeContent: (value)=>formatMessage({
id: 'Settings.review-workflows.workflow.contentTypes.displayValue',
defaultMessage: '{count} {count, plural, one {content type} other {content types}} selected'
}, {
count: value?.length
}),
disabled: isDisabled,
onChange: (values)=>{
onChange('contentTypes', values);
},
value: value,
placeholder: formatMessage({
id: 'Settings.review-workflows.workflow.contentTypes.placeholder',
defaultMessage: 'Select'
}),
children: [
...collectionTypes.length > 0 ? [
{
label: formatMessage({
id: 'Settings.review-workflows.workflow.contentTypes.collectionTypes.label',
defaultMessage: 'Collection Types'
}),
children: collectionTypes
}
] : [],
...singleTypes.length > 0 ? [
{
label: formatMessage({
id: 'Settings.review-workflows.workflow.contentTypes.singleTypes.label',
defaultMessage: 'Single Types'
}),
children: singleTypes
}
] : []
].map((opt)=>{
return /*#__PURE__*/ jsx(MultiSelectGroup, {
label: opt.label,
values: opt.children.map((child)=>child.value.toString()),
children: opt.children.map((child)=>{
const { name: assignedWorkflowName } = workflows?.find((workflow)=>(currentWorkflow && workflow.id !== currentWorkflow.id || !currentWorkflow) && workflow.contentTypes.includes(child.value)) ?? {};
return /*#__PURE__*/ jsx(NestedOption, {
value: child.value,
children: /*#__PURE__*/ jsx(Typography, {
children: // @ts-expect-error - formatMessage options doesn't expect to be a React component but that's what we need actually for the <i> and <em> components
formatMessage({
id: 'Settings.review-workflows.workflow.contentTypes.assigned.notice',
defaultMessage: '{label} {name, select, undefined {} other {<i>(assigned to <em>{name}</em> workflow)</i>}}'
}, {
label: child.label,
name: assignedWorkflowName,
em: (...children)=>/*#__PURE__*/ jsx(Typography, {
tag: "em",
fontWeight: "bold",
children: children
}),
i: (...children)=>/*#__PURE__*/ jsx(ContentTypeTakeNotice, {
children: children
})
})
})
}, child.value);
})
}, opt.label);
})
})
]
});
};
const NestedOption = styled(MultiSelectOption)`
padding-left: ${({ theme })=>theme.spaces[7]};
`;
const ContentTypeTakeNotice = styled(Typography)`
font-style: italic;
`;
const StageSelector = ({ disabled })=>{
const { value: stages = [] } = useField('stages');
const { formatMessage } = useIntl();
const { error, value, onChange } = useField('stageRequiredToPublish');
// stages with empty names are not valid, so we avoid them from being used to avoid errors
const validStages = stages.filter((stage)=>stage.name);
return /*#__PURE__*/ jsxs(Field.Root, {
error: error,
name: "stageRequiredToPublish",
hint: formatMessage({
id: 'settings.review-workflows.workflow.stageRequiredToPublish.hint',
defaultMessage: 'Prevents entries from being published if they are not at the required stage.'
}),
children: [
/*#__PURE__*/ jsx(Field.Label, {
children: formatMessage({
id: 'settings.review-workflows.workflow.stageRequiredToPublish.label',
defaultMessage: 'Required stage for publishing'
})
}),
/*#__PURE__*/ jsxs(SingleSelect, {
disabled: disabled,
onChange: (value)=>{
onChange('stageRequiredToPublish', value);
},
value: value,
children: [
/*#__PURE__*/ jsx(SingleSelectOption, {
value: '',
children: formatMessage({
id: 'settings.review-workflows.workflow.stageRequiredToPublish.any',
defaultMessage: 'Any stage'
})
}),
validStages.map((stage, i)=>/*#__PURE__*/ jsx(SingleSelectOption, {
value: stage.id?.toString() || stage.__temp_key__,
children: stage.name
}, `requiredToPublishStage-${stage.id || stage.__temp_key__}`))
]
}),
/*#__PURE__*/ jsx(Field.Hint, {})
]
});
};
export { WorkflowAttributes };
//# sourceMappingURL=WorkflowAttributes.mjs.map

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,8 @@
'use strict';
const DRAG_DROP_TYPES = {
STAGE: 'stage'
};
exports.DRAG_DROP_TYPES = DRAG_DROP_TYPES;
//# sourceMappingURL=constants.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"constants.js","sources":["../../../../admin/src/routes/settings/constants.ts"],"sourcesContent":["export type DragDropTypes = 'stage';\n\nexport const DRAG_DROP_TYPES: Record<Uppercase<DragDropTypes>, DragDropTypes> = {\n STAGE: 'stage',\n};\n"],"names":["DRAG_DROP_TYPES","STAGE"],"mappings":";;MAEaA,eAAmE,GAAA;IAC9EC,KAAO,EAAA;AACT;;;;"}

View File

@@ -0,0 +1,6 @@
const DRAG_DROP_TYPES = {
STAGE: 'stage'
};
export { DRAG_DROP_TYPES };
//# sourceMappingURL=constants.mjs.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"constants.mjs","sources":["../../../../admin/src/routes/settings/constants.ts"],"sourcesContent":["export type DragDropTypes = 'stage';\n\nexport const DRAG_DROP_TYPES: Record<Uppercase<DragDropTypes>, DragDropTypes> = {\n STAGE: 'stage',\n};\n"],"names":["DRAG_DROP_TYPES","STAGE"],"mappings":"MAEaA,eAAmE,GAAA;IAC9EC,KAAO,EAAA;AACT;;;;"}

View File

@@ -0,0 +1,193 @@
'use strict';
var React = require('react');
var reactDnd = require('react-dnd');
var useKeyboardDragAndDrop = require('./useKeyboardDragAndDrop.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 DIRECTIONS = {
UPWARD: 'upward',
DOWNWARD: 'downward'
};
const DROP_SENSITIVITY = {
REGULAR: 'regular',
IMMEDIATE: 'immediate'
};
/**
* A utility hook abstracting the general drag and drop hooks from react-dnd.
* Centralising the same behaviours and by default offering keyboard support.
*/ const useDragAndDrop = (active, { type = 'STRAPI_DND', index, item, onStart, onEnd, onGrabItem, onDropItem, onCancel, onMoveItem, dropSensitivity = DROP_SENSITIVITY.REGULAR })=>{
const objectRef = React__namespace.useRef(null);
const [{ handlerId, isOver }, dropRef] = reactDnd.useDrop({
accept: type,
collect (monitor) {
return {
handlerId: monitor.getHandlerId(),
isOver: monitor.isOver({
shallow: true
})
};
},
drop (item) {
const draggedIndex = item.index;
const newIndex = index;
if (isOver && onDropItem) {
onDropItem(draggedIndex, newIndex);
}
},
hover (item, monitor) {
if (!objectRef.current || !onMoveItem) {
return;
}
const dragIndex = item.index;
const newIndex = index;
const hoverBoundingRect = objectRef.current?.getBoundingClientRect();
const hoverMiddleY = (hoverBoundingRect.bottom - hoverBoundingRect.top) / 2;
const clientOffset = monitor.getClientOffset();
if (!clientOffset) return;
const hoverClientY = clientOffset && clientOffset.y - hoverBoundingRect.top;
if (typeof dragIndex === 'number' && typeof newIndex === 'number') {
if (dragIndex === newIndex) {
// Don't replace items with themselves
return;
}
if (dropSensitivity === DROP_SENSITIVITY.REGULAR) {
// Dragging downwards
if (dragIndex < newIndex && hoverClientY < hoverMiddleY) {
return;
}
// Dragging upwards
if (dragIndex > newIndex && hoverClientY > hoverMiddleY) {
return;
}
}
// Time to actually perform the action
onMoveItem(newIndex, dragIndex);
item.index = newIndex;
} else {
// Using numbers as indices doesn't work for nested list items with path like [1, 1, 0]
if (Array.isArray(dragIndex) && Array.isArray(newIndex)) {
// Indices comparison to find item position in nested list
const minLength = Math.min(dragIndex.length, newIndex.length);
let areEqual = true;
let isLessThan = false;
let isGreaterThan = false;
for(let i = 0; i < minLength; i++){
if (dragIndex[i] < newIndex[i]) {
isLessThan = true;
areEqual = false;
break;
} else if (dragIndex[i] > newIndex[i]) {
isGreaterThan = true;
areEqual = false;
break;
}
}
// Don't replace items with themselves
if (areEqual && dragIndex.length === newIndex.length) {
return;
}
if (dropSensitivity === DROP_SENSITIVITY.REGULAR) {
// Dragging downwards
if (isLessThan && !isGreaterThan && hoverClientY < hoverMiddleY) {
return;
}
// Dragging upwards
if (isGreaterThan && !isLessThan && hoverClientY > hoverMiddleY) {
return;
}
}
}
onMoveItem(newIndex, dragIndex);
item.index = newIndex;
}
}
});
const getDragDirection = (monitor)=>{
if (monitor && monitor.isDragging() && !monitor.didDrop() && monitor.getInitialClientOffset() && monitor.getClientOffset()) {
const deltaY = monitor.getInitialClientOffset().y - monitor.getClientOffset().y;
if (deltaY > 0) return DIRECTIONS.UPWARD;
if (deltaY < 0) return DIRECTIONS.DOWNWARD;
return null;
}
return null;
};
const [{ isDragging, direction }, dragRef, dragPreviewRef] = reactDnd.useDrag({
type,
item () {
if (onStart) {
onStart();
}
/**
* This will be attached and it helps define the preview sizes
* when a component is flexy e.g. Relations
*/ const { width } = objectRef.current?.getBoundingClientRect() ?? {};
return {
index,
width,
...item
};
},
end () {
if (onEnd) {
onEnd();
}
},
canDrag: active,
/**
* This is useful when the item is in a virtualized list.
* However, if we don't have an ID then we want the libraries
* defaults to take care of this.
*/ isDragging: item?.id ? (monitor)=>{
return item.id === monitor.getItem().id;
} : undefined,
collect: (monitor)=>({
isDragging: monitor.isDragging(),
initialOffset: monitor.getInitialClientOffset(),
currentOffset: monitor.getClientOffset(),
direction: getDragDirection(monitor)
})
});
const handleKeyDown = useKeyboardDragAndDrop.useKeyboardDragAndDrop(active, index, {
onGrabItem,
onDropItem,
onCancel,
onMoveItem
});
return [
{
handlerId,
isDragging,
handleKeyDown,
isOverDropTarget: isOver,
direction
},
objectRef,
dropRef,
dragRef,
dragPreviewRef
];
};
exports.DIRECTIONS = DIRECTIONS;
exports.DROP_SENSITIVITY = DROP_SENSITIVITY;
exports.useDragAndDrop = useDragAndDrop;
//# sourceMappingURL=useDragAndDrop.js.map

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,170 @@
import * as React from 'react';
import { useDrop, useDrag } from 'react-dnd';
import { useKeyboardDragAndDrop } from './useKeyboardDragAndDrop.mjs';
const DIRECTIONS = {
UPWARD: 'upward',
DOWNWARD: 'downward'
};
const DROP_SENSITIVITY = {
REGULAR: 'regular',
IMMEDIATE: 'immediate'
};
/**
* A utility hook abstracting the general drag and drop hooks from react-dnd.
* Centralising the same behaviours and by default offering keyboard support.
*/ const useDragAndDrop = (active, { type = 'STRAPI_DND', index, item, onStart, onEnd, onGrabItem, onDropItem, onCancel, onMoveItem, dropSensitivity = DROP_SENSITIVITY.REGULAR })=>{
const objectRef = React.useRef(null);
const [{ handlerId, isOver }, dropRef] = useDrop({
accept: type,
collect (monitor) {
return {
handlerId: monitor.getHandlerId(),
isOver: monitor.isOver({
shallow: true
})
};
},
drop (item) {
const draggedIndex = item.index;
const newIndex = index;
if (isOver && onDropItem) {
onDropItem(draggedIndex, newIndex);
}
},
hover (item, monitor) {
if (!objectRef.current || !onMoveItem) {
return;
}
const dragIndex = item.index;
const newIndex = index;
const hoverBoundingRect = objectRef.current?.getBoundingClientRect();
const hoverMiddleY = (hoverBoundingRect.bottom - hoverBoundingRect.top) / 2;
const clientOffset = monitor.getClientOffset();
if (!clientOffset) return;
const hoverClientY = clientOffset && clientOffset.y - hoverBoundingRect.top;
if (typeof dragIndex === 'number' && typeof newIndex === 'number') {
if (dragIndex === newIndex) {
// Don't replace items with themselves
return;
}
if (dropSensitivity === DROP_SENSITIVITY.REGULAR) {
// Dragging downwards
if (dragIndex < newIndex && hoverClientY < hoverMiddleY) {
return;
}
// Dragging upwards
if (dragIndex > newIndex && hoverClientY > hoverMiddleY) {
return;
}
}
// Time to actually perform the action
onMoveItem(newIndex, dragIndex);
item.index = newIndex;
} else {
// Using numbers as indices doesn't work for nested list items with path like [1, 1, 0]
if (Array.isArray(dragIndex) && Array.isArray(newIndex)) {
// Indices comparison to find item position in nested list
const minLength = Math.min(dragIndex.length, newIndex.length);
let areEqual = true;
let isLessThan = false;
let isGreaterThan = false;
for(let i = 0; i < minLength; i++){
if (dragIndex[i] < newIndex[i]) {
isLessThan = true;
areEqual = false;
break;
} else if (dragIndex[i] > newIndex[i]) {
isGreaterThan = true;
areEqual = false;
break;
}
}
// Don't replace items with themselves
if (areEqual && dragIndex.length === newIndex.length) {
return;
}
if (dropSensitivity === DROP_SENSITIVITY.REGULAR) {
// Dragging downwards
if (isLessThan && !isGreaterThan && hoverClientY < hoverMiddleY) {
return;
}
// Dragging upwards
if (isGreaterThan && !isLessThan && hoverClientY > hoverMiddleY) {
return;
}
}
}
onMoveItem(newIndex, dragIndex);
item.index = newIndex;
}
}
});
const getDragDirection = (monitor)=>{
if (monitor && monitor.isDragging() && !monitor.didDrop() && monitor.getInitialClientOffset() && monitor.getClientOffset()) {
const deltaY = monitor.getInitialClientOffset().y - monitor.getClientOffset().y;
if (deltaY > 0) return DIRECTIONS.UPWARD;
if (deltaY < 0) return DIRECTIONS.DOWNWARD;
return null;
}
return null;
};
const [{ isDragging, direction }, dragRef, dragPreviewRef] = useDrag({
type,
item () {
if (onStart) {
onStart();
}
/**
* This will be attached and it helps define the preview sizes
* when a component is flexy e.g. Relations
*/ const { width } = objectRef.current?.getBoundingClientRect() ?? {};
return {
index,
width,
...item
};
},
end () {
if (onEnd) {
onEnd();
}
},
canDrag: active,
/**
* This is useful when the item is in a virtualized list.
* However, if we don't have an ID then we want the libraries
* defaults to take care of this.
*/ isDragging: item?.id ? (monitor)=>{
return item.id === monitor.getItem().id;
} : undefined,
collect: (monitor)=>({
isDragging: monitor.isDragging(),
initialOffset: monitor.getInitialClientOffset(),
currentOffset: monitor.getClientOffset(),
direction: getDragDirection(monitor)
})
});
const handleKeyDown = useKeyboardDragAndDrop(active, index, {
onGrabItem,
onDropItem,
onCancel,
onMoveItem
});
return [
{
handlerId,
isDragging,
handleKeyDown,
isOverDropTarget: isOver,
direction
},
objectRef,
dropRef,
dragRef,
dragPreviewRef
];
};
export { DIRECTIONS, DROP_SENSITIVITY, useDragAndDrop };
//# sourceMappingURL=useDragAndDrop.mjs.map

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,94 @@
'use strict';
var React = require('react');
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);
/**
* Utility hook designed to implement keyboard accessibile drag and drop by
* returning an onKeyDown handler to be passed to the drag icon button.
*
* @internal - You should use `useDragAndDrop` instead.
*/ const useKeyboardDragAndDrop = (active, index, { onCancel, onDropItem, onGrabItem, onMoveItem })=>{
const [isSelected, setIsSelected] = React__namespace.useState(false);
const handleMove = (movement)=>{
if (!isSelected) {
return;
}
if (typeof index === 'number' && onMoveItem) {
if (movement === 'UP') {
onMoveItem(index - 1, index);
} else if (movement === 'DOWN') {
onMoveItem(index + 1, index);
}
}
};
const handleDragClick = ()=>{
if (isSelected) {
if (onDropItem) {
onDropItem(index);
}
setIsSelected(false);
} else {
if (onGrabItem) {
onGrabItem(index);
}
setIsSelected(true);
}
};
const handleCancel = ()=>{
if (isSelected) {
setIsSelected(false);
if (onCancel) {
onCancel(index);
}
}
};
const handleKeyDown = (e)=>{
if (!active) {
return;
}
if (e.key === 'Tab' && !isSelected) {
return;
}
e.preventDefault();
switch(e.key){
case ' ':
case 'Enter':
handleDragClick();
break;
case 'Escape':
handleCancel();
break;
case 'ArrowDown':
case 'ArrowRight':
handleMove('DOWN');
break;
case 'ArrowUp':
case 'ArrowLeft':
handleMove('UP');
break;
}
};
return handleKeyDown;
};
exports.useKeyboardDragAndDrop = useKeyboardDragAndDrop;
//# sourceMappingURL=useKeyboardDragAndDrop.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"useKeyboardDragAndDrop.js","sources":["../../../../../admin/src/routes/settings/hooks/useKeyboardDragAndDrop.ts"],"sourcesContent":["import * as React from 'react';\n\nexport type UseKeyboardDragAndDropCallbacks<TIndex extends number | Array<number> = number> = {\n onCancel?: (index: TIndex) => void;\n onDropItem?: (currentIndex: TIndex, newIndex?: TIndex) => void;\n onGrabItem?: (index: TIndex) => void;\n onMoveItem?: (newIndex: TIndex, currentIndex: TIndex) => void;\n};\n\n/**\n * Utility hook designed to implement keyboard accessibile drag and drop by\n * returning an onKeyDown handler to be passed to the drag icon button.\n *\n * @internal - You should use `useDragAndDrop` instead.\n */\nexport const useKeyboardDragAndDrop = <TIndex extends number | Array<number> = number>(\n active: boolean,\n index: TIndex,\n { onCancel, onDropItem, onGrabItem, onMoveItem }: UseKeyboardDragAndDropCallbacks<TIndex>\n) => {\n const [isSelected, setIsSelected] = React.useState(false);\n\n const handleMove = (movement: 'UP' | 'DOWN') => {\n if (!isSelected) {\n return;\n }\n if (typeof index === 'number' && onMoveItem) {\n if (movement === 'UP') {\n onMoveItem((index - 1) as TIndex, index);\n } else if (movement === 'DOWN') {\n onMoveItem((index + 1) as TIndex, index);\n }\n }\n };\n\n const handleDragClick = () => {\n if (isSelected) {\n if (onDropItem) {\n onDropItem(index);\n }\n setIsSelected(false);\n } else {\n if (onGrabItem) {\n onGrabItem(index);\n }\n setIsSelected(true);\n }\n };\n\n const handleCancel = () => {\n if (isSelected) {\n setIsSelected(false);\n\n if (onCancel) {\n onCancel(index);\n }\n }\n };\n\n const handleKeyDown = <E extends Element>(e: React.KeyboardEvent<E>) => {\n if (!active) {\n return;\n }\n\n if (e.key === 'Tab' && !isSelected) {\n return;\n }\n\n e.preventDefault();\n\n switch (e.key) {\n case ' ':\n case 'Enter':\n handleDragClick();\n break;\n\n case 'Escape':\n handleCancel();\n break;\n\n case 'ArrowDown':\n case 'ArrowRight':\n handleMove('DOWN');\n break;\n\n case 'ArrowUp':\n case 'ArrowLeft':\n handleMove('UP');\n break;\n\n default:\n }\n };\n\n return handleKeyDown;\n};\n"],"names":["useKeyboardDragAndDrop","active","index","onCancel","onDropItem","onGrabItem","onMoveItem","isSelected","setIsSelected","React","useState","handleMove","movement","handleDragClick","handleCancel","handleKeyDown","e","key","preventDefault"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;AASA;;;;;AAKC,IACM,MAAMA,sBAAyB,GAAA,CACpCC,QACAC,KACA,EAAA,EAAEC,QAAQ,EAAEC,UAAU,EAAEC,UAAU,EAAEC,UAAU,EAA2C,GAAA;AAEzF,IAAA,MAAM,CAACC,UAAYC,EAAAA,aAAAA,CAAc,GAAGC,gBAAAA,CAAMC,QAAQ,CAAC,KAAA,CAAA;AAEnD,IAAA,MAAMC,aAAa,CAACC,QAAAA,GAAAA;AAClB,QAAA,IAAI,CAACL,UAAY,EAAA;AACf,YAAA;AACF;QACA,IAAI,OAAOL,KAAU,KAAA,QAAA,IAAYI,UAAY,EAAA;AAC3C,YAAA,IAAIM,aAAa,IAAM,EAAA;AACrBN,gBAAAA,UAAAA,CAAYJ,QAAQ,CAAcA,EAAAA,KAAAA,CAAAA;aAC7B,MAAA,IAAIU,aAAa,MAAQ,EAAA;AAC9BN,gBAAAA,UAAAA,CAAYJ,QAAQ,CAAcA,EAAAA,KAAAA,CAAAA;AACpC;AACF;AACF,KAAA;AAEA,IAAA,MAAMW,eAAkB,GAAA,IAAA;AACtB,QAAA,IAAIN,UAAY,EAAA;AACd,YAAA,IAAIH,UAAY,EAAA;gBACdA,UAAWF,CAAAA,KAAAA,CAAAA;AACb;YACAM,aAAc,CAAA,KAAA,CAAA;SACT,MAAA;AACL,YAAA,IAAIH,UAAY,EAAA;gBACdA,UAAWH,CAAAA,KAAAA,CAAAA;AACb;YACAM,aAAc,CAAA,IAAA,CAAA;AAChB;AACF,KAAA;AAEA,IAAA,MAAMM,YAAe,GAAA,IAAA;AACnB,QAAA,IAAIP,UAAY,EAAA;YACdC,aAAc,CAAA,KAAA,CAAA;AAEd,YAAA,IAAIL,QAAU,EAAA;gBACZA,QAASD,CAAAA,KAAAA,CAAAA;AACX;AACF;AACF,KAAA;AAEA,IAAA,MAAMa,gBAAgB,CAAoBC,CAAAA,GAAAA;AACxC,QAAA,IAAI,CAACf,MAAQ,EAAA;AACX,YAAA;AACF;AAEA,QAAA,IAAIe,CAAEC,CAAAA,GAAG,KAAK,KAAA,IAAS,CAACV,UAAY,EAAA;AAClC,YAAA;AACF;AAEAS,QAAAA,CAAAA,CAAEE,cAAc,EAAA;AAEhB,QAAA,OAAQF,EAAEC,GAAG;YACX,KAAK,GAAA;YACL,KAAK,OAAA;AACHJ,gBAAAA,eAAAA,EAAAA;AACA,gBAAA;YAEF,KAAK,QAAA;AACHC,gBAAAA,YAAAA,EAAAA;AACA,gBAAA;YAEF,KAAK,WAAA;YACL,KAAK,YAAA;gBACHH,UAAW,CAAA,MAAA,CAAA;AACX,gBAAA;YAEF,KAAK,SAAA;YACL,KAAK,WAAA;gBACHA,UAAW,CAAA,IAAA,CAAA;AACX,gBAAA;AAGJ;AACF,KAAA;IAEA,OAAOI,aAAAA;AACT;;;;"}

View File

@@ -0,0 +1,73 @@
import * as React from 'react';
/**
* Utility hook designed to implement keyboard accessibile drag and drop by
* returning an onKeyDown handler to be passed to the drag icon button.
*
* @internal - You should use `useDragAndDrop` instead.
*/ const useKeyboardDragAndDrop = (active, index, { onCancel, onDropItem, onGrabItem, onMoveItem })=>{
const [isSelected, setIsSelected] = React.useState(false);
const handleMove = (movement)=>{
if (!isSelected) {
return;
}
if (typeof index === 'number' && onMoveItem) {
if (movement === 'UP') {
onMoveItem(index - 1, index);
} else if (movement === 'DOWN') {
onMoveItem(index + 1, index);
}
}
};
const handleDragClick = ()=>{
if (isSelected) {
if (onDropItem) {
onDropItem(index);
}
setIsSelected(false);
} else {
if (onGrabItem) {
onGrabItem(index);
}
setIsSelected(true);
}
};
const handleCancel = ()=>{
if (isSelected) {
setIsSelected(false);
if (onCancel) {
onCancel(index);
}
}
};
const handleKeyDown = (e)=>{
if (!active) {
return;
}
if (e.key === 'Tab' && !isSelected) {
return;
}
e.preventDefault();
switch(e.key){
case ' ':
case 'Enter':
handleDragClick();
break;
case 'Escape':
handleCancel();
break;
case 'ArrowDown':
case 'ArrowRight':
handleMove('DOWN');
break;
case 'ArrowUp':
case 'ArrowLeft':
handleMove('UP');
break;
}
};
return handleKeyDown;
};
export { useKeyboardDragAndDrop };
//# sourceMappingURL=useKeyboardDragAndDrop.mjs.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"useKeyboardDragAndDrop.mjs","sources":["../../../../../admin/src/routes/settings/hooks/useKeyboardDragAndDrop.ts"],"sourcesContent":["import * as React from 'react';\n\nexport type UseKeyboardDragAndDropCallbacks<TIndex extends number | Array<number> = number> = {\n onCancel?: (index: TIndex) => void;\n onDropItem?: (currentIndex: TIndex, newIndex?: TIndex) => void;\n onGrabItem?: (index: TIndex) => void;\n onMoveItem?: (newIndex: TIndex, currentIndex: TIndex) => void;\n};\n\n/**\n * Utility hook designed to implement keyboard accessibile drag and drop by\n * returning an onKeyDown handler to be passed to the drag icon button.\n *\n * @internal - You should use `useDragAndDrop` instead.\n */\nexport const useKeyboardDragAndDrop = <TIndex extends number | Array<number> = number>(\n active: boolean,\n index: TIndex,\n { onCancel, onDropItem, onGrabItem, onMoveItem }: UseKeyboardDragAndDropCallbacks<TIndex>\n) => {\n const [isSelected, setIsSelected] = React.useState(false);\n\n const handleMove = (movement: 'UP' | 'DOWN') => {\n if (!isSelected) {\n return;\n }\n if (typeof index === 'number' && onMoveItem) {\n if (movement === 'UP') {\n onMoveItem((index - 1) as TIndex, index);\n } else if (movement === 'DOWN') {\n onMoveItem((index + 1) as TIndex, index);\n }\n }\n };\n\n const handleDragClick = () => {\n if (isSelected) {\n if (onDropItem) {\n onDropItem(index);\n }\n setIsSelected(false);\n } else {\n if (onGrabItem) {\n onGrabItem(index);\n }\n setIsSelected(true);\n }\n };\n\n const handleCancel = () => {\n if (isSelected) {\n setIsSelected(false);\n\n if (onCancel) {\n onCancel(index);\n }\n }\n };\n\n const handleKeyDown = <E extends Element>(e: React.KeyboardEvent<E>) => {\n if (!active) {\n return;\n }\n\n if (e.key === 'Tab' && !isSelected) {\n return;\n }\n\n e.preventDefault();\n\n switch (e.key) {\n case ' ':\n case 'Enter':\n handleDragClick();\n break;\n\n case 'Escape':\n handleCancel();\n break;\n\n case 'ArrowDown':\n case 'ArrowRight':\n handleMove('DOWN');\n break;\n\n case 'ArrowUp':\n case 'ArrowLeft':\n handleMove('UP');\n break;\n\n default:\n }\n };\n\n return handleKeyDown;\n};\n"],"names":["useKeyboardDragAndDrop","active","index","onCancel","onDropItem","onGrabItem","onMoveItem","isSelected","setIsSelected","React","useState","handleMove","movement","handleDragClick","handleCancel","handleKeyDown","e","key","preventDefault"],"mappings":";;AASA;;;;;AAKC,IACM,MAAMA,sBAAyB,GAAA,CACpCC,QACAC,KACA,EAAA,EAAEC,QAAQ,EAAEC,UAAU,EAAEC,UAAU,EAAEC,UAAU,EAA2C,GAAA;AAEzF,IAAA,MAAM,CAACC,UAAYC,EAAAA,aAAAA,CAAc,GAAGC,KAAAA,CAAMC,QAAQ,CAAC,KAAA,CAAA;AAEnD,IAAA,MAAMC,aAAa,CAACC,QAAAA,GAAAA;AAClB,QAAA,IAAI,CAACL,UAAY,EAAA;AACf,YAAA;AACF;QACA,IAAI,OAAOL,KAAU,KAAA,QAAA,IAAYI,UAAY,EAAA;AAC3C,YAAA,IAAIM,aAAa,IAAM,EAAA;AACrBN,gBAAAA,UAAAA,CAAYJ,QAAQ,CAAcA,EAAAA,KAAAA,CAAAA;aAC7B,MAAA,IAAIU,aAAa,MAAQ,EAAA;AAC9BN,gBAAAA,UAAAA,CAAYJ,QAAQ,CAAcA,EAAAA,KAAAA,CAAAA;AACpC;AACF;AACF,KAAA;AAEA,IAAA,MAAMW,eAAkB,GAAA,IAAA;AACtB,QAAA,IAAIN,UAAY,EAAA;AACd,YAAA,IAAIH,UAAY,EAAA;gBACdA,UAAWF,CAAAA,KAAAA,CAAAA;AACb;YACAM,aAAc,CAAA,KAAA,CAAA;SACT,MAAA;AACL,YAAA,IAAIH,UAAY,EAAA;gBACdA,UAAWH,CAAAA,KAAAA,CAAAA;AACb;YACAM,aAAc,CAAA,IAAA,CAAA;AAChB;AACF,KAAA;AAEA,IAAA,MAAMM,YAAe,GAAA,IAAA;AACnB,QAAA,IAAIP,UAAY,EAAA;YACdC,aAAc,CAAA,KAAA,CAAA;AAEd,YAAA,IAAIL,QAAU,EAAA;gBACZA,QAASD,CAAAA,KAAAA,CAAAA;AACX;AACF;AACF,KAAA;AAEA,IAAA,MAAMa,gBAAgB,CAAoBC,CAAAA,GAAAA;AACxC,QAAA,IAAI,CAACf,MAAQ,EAAA;AACX,YAAA;AACF;AAEA,QAAA,IAAIe,CAAEC,CAAAA,GAAG,KAAK,KAAA,IAAS,CAACV,UAAY,EAAA;AAClC,YAAA;AACF;AAEAS,QAAAA,CAAAA,CAAEE,cAAc,EAAA;AAEhB,QAAA,OAAQF,EAAEC,GAAG;YACX,KAAK,GAAA;YACL,KAAK,OAAA;AACHJ,gBAAAA,eAAAA,EAAAA;AACA,gBAAA;YAEF,KAAK,QAAA;AACHC,gBAAAA,YAAAA,EAAAA;AACA,gBAAA;YAEF,KAAK,WAAA;YACL,KAAK,YAAA;gBACHH,UAAW,CAAA,MAAA,CAAA;AACX,gBAAA;YAEF,KAAK,SAAA;YACL,KAAK,WAAA;gBACHA,UAAW,CAAA,IAAA,CAAA;AACX,gBAAA;AAGJ;AACF,KAAA;IAEA,OAAOI,aAAAA;AACT;;;;"}

View File

@@ -0,0 +1,171 @@
'use strict';
var React = require('react');
var strapiAdmin = require('@strapi/admin/strapi-admin');
var reactIntl = require('react-intl');
var settings = require('../../../services/settings.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 DEFAULT_UNEXPECTED_ERROR_MSG = {
id: 'notification.error',
defaultMessage: 'An error occurred, please try again'
};
const useReviewWorkflows = (params = {})=>{
const { toggleNotification } = strapiAdmin.useNotification();
const { formatMessage } = reactIntl.useIntl();
const { _unstableFormatAPIError: formatAPIError } = strapiAdmin.useAPIErrorHandler();
const { skip = false, ...queryParams } = params;
const { data, isLoading, error } = settings.useGetWorkflowsQuery({
...queryParams
}, {
skip
});
React__namespace.useEffect(()=>{
if (error) {
toggleNotification({
type: 'danger',
message: formatAPIError(error)
});
}
}, [
error,
formatAPIError,
toggleNotification
]);
const [createWorkflow] = settings.useCreateWorkflowMutation();
const create = React__namespace.useCallback(async (data)=>{
try {
const res = await createWorkflow({
data
});
if ('error' in res) {
toggleNotification({
type: 'danger',
message: formatAPIError(res.error)
});
return res;
}
toggleNotification({
type: 'success',
message: formatMessage({
id: 'actions.created',
defaultMessage: 'Created workflow'
})
});
return res;
} catch (err) {
toggleNotification({
type: 'danger',
message: formatMessage(DEFAULT_UNEXPECTED_ERROR_MSG)
});
throw err;
}
}, [
createWorkflow,
formatAPIError,
formatMessage,
toggleNotification
]);
const [updateWorkflow] = settings.useUpdateWorkflowMutation();
const update = React__namespace.useCallback(async (id, data)=>{
try {
const res = await updateWorkflow({
id,
data
});
if ('error' in res) {
toggleNotification({
type: 'danger',
message: formatAPIError(res.error)
});
return res;
}
toggleNotification({
type: 'success',
message: formatMessage({
id: 'actions.updated',
defaultMessage: 'Updated workflow'
})
});
return res;
} catch (err) {
toggleNotification({
type: 'danger',
message: formatMessage(DEFAULT_UNEXPECTED_ERROR_MSG)
});
throw err;
}
}, [
formatAPIError,
formatMessage,
toggleNotification,
updateWorkflow
]);
const [deleteWorkflow] = settings.useDeleteWorkflowMutation();
const deleteAction = React__namespace.useCallback(async (id)=>{
try {
const res = await deleteWorkflow({
id
});
if ('error' in res) {
toggleNotification({
type: 'danger',
message: formatAPIError(res.error)
});
return;
}
toggleNotification({
type: 'success',
message: formatMessage({
id: 'actions.deleted',
defaultMessage: 'Deleted workflow'
})
});
return res.data;
} catch (err) {
toggleNotification({
type: 'danger',
message: formatMessage(DEFAULT_UNEXPECTED_ERROR_MSG)
});
throw err;
}
}, [
deleteWorkflow,
formatAPIError,
formatMessage,
toggleNotification
]);
const { workflows = [], meta } = data ?? {};
return {
// meta contains e.g. the total of all workflows. we can not use
// the pagination object here, because the list is not paginated.
meta,
workflows,
isLoading,
error,
create,
delete: deleteAction,
update
};
};
exports.useReviewWorkflows = useReviewWorkflows;
//# sourceMappingURL=useReviewWorkflows.js.map

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,150 @@
import * as React from 'react';
import { useNotification, useAPIErrorHandler } from '@strapi/admin/strapi-admin';
import { useIntl } from 'react-intl';
import { useGetWorkflowsQuery, useCreateWorkflowMutation, useUpdateWorkflowMutation, useDeleteWorkflowMutation } from '../../../services/settings.mjs';
const DEFAULT_UNEXPECTED_ERROR_MSG = {
id: 'notification.error',
defaultMessage: 'An error occurred, please try again'
};
const useReviewWorkflows = (params = {})=>{
const { toggleNotification } = useNotification();
const { formatMessage } = useIntl();
const { _unstableFormatAPIError: formatAPIError } = useAPIErrorHandler();
const { skip = false, ...queryParams } = params;
const { data, isLoading, error } = useGetWorkflowsQuery({
...queryParams
}, {
skip
});
React.useEffect(()=>{
if (error) {
toggleNotification({
type: 'danger',
message: formatAPIError(error)
});
}
}, [
error,
formatAPIError,
toggleNotification
]);
const [createWorkflow] = useCreateWorkflowMutation();
const create = React.useCallback(async (data)=>{
try {
const res = await createWorkflow({
data
});
if ('error' in res) {
toggleNotification({
type: 'danger',
message: formatAPIError(res.error)
});
return res;
}
toggleNotification({
type: 'success',
message: formatMessage({
id: 'actions.created',
defaultMessage: 'Created workflow'
})
});
return res;
} catch (err) {
toggleNotification({
type: 'danger',
message: formatMessage(DEFAULT_UNEXPECTED_ERROR_MSG)
});
throw err;
}
}, [
createWorkflow,
formatAPIError,
formatMessage,
toggleNotification
]);
const [updateWorkflow] = useUpdateWorkflowMutation();
const update = React.useCallback(async (id, data)=>{
try {
const res = await updateWorkflow({
id,
data
});
if ('error' in res) {
toggleNotification({
type: 'danger',
message: formatAPIError(res.error)
});
return res;
}
toggleNotification({
type: 'success',
message: formatMessage({
id: 'actions.updated',
defaultMessage: 'Updated workflow'
})
});
return res;
} catch (err) {
toggleNotification({
type: 'danger',
message: formatMessage(DEFAULT_UNEXPECTED_ERROR_MSG)
});
throw err;
}
}, [
formatAPIError,
formatMessage,
toggleNotification,
updateWorkflow
]);
const [deleteWorkflow] = useDeleteWorkflowMutation();
const deleteAction = React.useCallback(async (id)=>{
try {
const res = await deleteWorkflow({
id
});
if ('error' in res) {
toggleNotification({
type: 'danger',
message: formatAPIError(res.error)
});
return;
}
toggleNotification({
type: 'success',
message: formatMessage({
id: 'actions.deleted',
defaultMessage: 'Deleted workflow'
})
});
return res.data;
} catch (err) {
toggleNotification({
type: 'danger',
message: formatMessage(DEFAULT_UNEXPECTED_ERROR_MSG)
});
throw err;
}
}, [
deleteWorkflow,
formatAPIError,
formatMessage,
toggleNotification
]);
const { workflows = [], meta } = data ?? {};
return {
// meta contains e.g. the total of all workflows. we can not use
// the pagination object here, because the list is not paginated.
meta,
workflows,
isLoading,
error,
create,
delete: deleteAction,
update
};
};
export { useReviewWorkflows };
//# sourceMappingURL=useReviewWorkflows.mjs.map

Some files were not shown because too many files have changed in this diff Show More