Files
automatisch/packages/web/src/components/FlowContextMenu/index.jsx
2025-04-09 14:02:16 +00:00

195 lines
5.3 KiB
JavaScript

import Menu from '@mui/material/Menu';
import MenuItem from '@mui/material/MenuItem';
import { useQueryClient } from '@tanstack/react-query';
import PropTypes from 'prop-types';
import * as React from 'react';
import { Link, useNavigate, useLocation } from 'react-router-dom';
import Can from 'components/Can';
import FlowFolderChangeDialog from 'components/FlowFolderChangeDialog';
import * as URLS from 'config/urls';
import useDeleteFlow from 'hooks/useDeleteFlow';
import useDownloadJsonAsFile from 'hooks/useDownloadJsonAsFile';
import useDuplicateFlow from 'hooks/useDuplicateFlow';
import useEnqueueSnackbar from 'hooks/useEnqueueSnackbar';
import useExportFlow from 'hooks/useExportFlow';
import useFormatMessage from 'hooks/useFormatMessage';
import useIsCurrentUserAdmin from 'hooks/useIsCurrentUserAdmin';
function ContextMenu(props) {
const location = useLocation();
const { flowId, onClose, anchorEl, onDuplicateFlow, appKey } = props;
const [showFlowFolderChangeDialog, setShowFlowFolderChangeDialog] =
React.useState(false);
const navigate = useNavigate();
const enqueueSnackbar = useEnqueueSnackbar();
const formatMessage = useFormatMessage();
const queryClient = useQueryClient();
const isCurrentUserAdmin = useIsCurrentUserAdmin();
const { mutateAsync: duplicateFlow } = useDuplicateFlow(flowId);
const { mutateAsync: deleteFlow } = useDeleteFlow(flowId);
const { mutateAsync: exportFlow } = useExportFlow(flowId);
const downloadJsonAsFile = useDownloadJsonAsFile();
const onFlowDuplicate = React.useCallback(async () => {
await duplicateFlow();
if (appKey) {
await queryClient.invalidateQueries({
queryKey: ['apps', appKey, 'flows'],
});
}
enqueueSnackbar(formatMessage('flow.successfullyDuplicated'), {
variant: 'success',
SnackbarProps: {
'data-test': 'snackbar-duplicate-flow-success',
},
});
onDuplicateFlow?.();
onClose();
}, [
appKey,
enqueueSnackbar,
onClose,
duplicateFlow,
queryClient,
onDuplicateFlow,
formatMessage,
]);
const onCreateTemplate = React.useCallback(async () => {
navigate(URLS.ADMIN_CREATE_TEMPLATE(flowId));
}, [flowId]);
const onFlowDelete = React.useCallback(async () => {
await deleteFlow();
if (appKey) {
await queryClient.invalidateQueries({
queryKey: ['apps', appKey, 'flows'],
});
}
enqueueSnackbar(formatMessage('flow.successfullyDeleted'), {
variant: 'success',
});
onClose();
}, [
deleteFlow,
appKey,
enqueueSnackbar,
formatMessage,
onClose,
queryClient,
]);
const onFlowExport = React.useCallback(async () => {
const flowExport = await exportFlow();
downloadJsonAsFile({
contents: flowExport.data,
name: flowExport.data.name,
});
enqueueSnackbar(formatMessage('flow.successfullyExported'), {
variant: 'success',
});
onClose();
}, [exportFlow, downloadJsonAsFile, enqueueSnackbar, formatMessage, onClose]);
const onFlowFolderUpdate = React.useCallback(() => {
setShowFlowFolderChangeDialog(true);
}, []);
return (
<>
<Menu
open={true}
onClose={onClose}
hideBackdrop={false}
anchorEl={anchorEl}
>
<Can I="read" a="Flow" passThrough>
{(allowed) => (
<MenuItem
disabled={!allowed}
component={Link}
to={URLS.FLOW(flowId)}
state={{
from: `${location.pathname}${location.search}${location.hash}`,
}}
>
{formatMessage('flow.view')}
</MenuItem>
)}
</Can>
<Can I="manage" a="Flow" passThrough>
{(allowed) => (
<MenuItem disabled={!allowed} onClick={onFlowDuplicate}>
{formatMessage('flow.duplicate')}
</MenuItem>
)}
</Can>
{isCurrentUserAdmin && (
<Can I="manage" a="Flow" passThrough>
{(allowed) => (
<MenuItem disabled={!allowed} onClick={onCreateTemplate}>
{formatMessage('flow.createTemplateFromFlow')}
</MenuItem>
)}
</Can>
)}
<Can I="manage" a="Flow" passThrough>
{(allowed) => (
<MenuItem disabled={!allowed} onClick={onFlowFolderUpdate}>
{formatMessage('flow.moveTo')}
</MenuItem>
)}
</Can>
<Can I="read" a="Flow" passThrough>
{(allowed) => (
<MenuItem disabled={!allowed} onClick={onFlowExport}>
{formatMessage('flow.export')}
</MenuItem>
)}
</Can>
<Can I="manage" a="Flow" passThrough>
{(allowed) => (
<MenuItem disabled={!allowed} onClick={onFlowDelete}>
{formatMessage('flow.delete')}
</MenuItem>
)}
</Can>
</Menu>
{showFlowFolderChangeDialog && (
<FlowFolderChangeDialog flowId={flowId} onClose={onClose} />
)}
</>
);
}
ContextMenu.propTypes = {
flowId: PropTypes.string.isRequired,
onClose: PropTypes.func.isRequired,
anchorEl: PropTypes.oneOfType([
PropTypes.func,
PropTypes.shape({ current: PropTypes.instanceOf(Element) }),
]).isRequired,
onDuplicateFlow: PropTypes.func,
appKey: PropTypes.string,
};
export default ContextMenu;