feat(web): add import flow functionality

This commit is contained in:
Ali BARIN
2025-01-20 12:27:09 +00:00
committed by Faruk AYDIN
parent 48e9541af5
commit 5695609180
9 changed files with 369 additions and 90 deletions

View File

@@ -9,6 +9,7 @@ function ConditionalIconButton(props) {
const { icon, ...buttonProps } = props;
const theme = useTheme();
const matchSmallScreens = useMediaQuery(theme.breakpoints.down('md'));
if (matchSmallScreens) {
return (
<IconButton
@@ -24,7 +25,8 @@ function ConditionalIconButton(props) {
</IconButton>
);
}
return <Button {...buttonProps} />;
return <Button {...buttonProps} startIcon={icon} />;
}
ConditionalIconButton.propTypes = {

View File

@@ -0,0 +1,38 @@
import * as React from 'react';
import PropTypes from 'prop-types';
import { styled } from '@mui/material/styles';
import Button from '@mui/material/Button';
import AttachFileIcon from '@mui/icons-material/AttachFile';
const VisuallyHiddenInput = styled('input')({
clip: 'rect(0 0 0 0)',
clipPath: 'inset(50%)',
height: 1,
overflow: 'hidden',
position: 'absolute',
bottom: 0,
left: 0,
whiteSpace: 'nowrap',
width: 1,
});
export default function FileUploadInput(props) {
return (
<Button
component="label"
role={undefined}
variant="contained"
tabIndex={-1}
startIcon={<AttachFileIcon />}
>
{props.children}
<VisuallyHiddenInput type="file" onChange={props.onChange} />
</Button>
);
}
FileUploadInput.propTypes = {
onChange: PropTypes.func.isRequired,
children: PropTypes.node.isRequired,
};

View File

@@ -0,0 +1,158 @@
import * as React from 'react';
import PropTypes from 'prop-types';
import { useNavigate, Link } from 'react-router-dom';
import Alert from '@mui/material/Alert';
import Button from '@mui/material/Button';
import Stack from '@mui/material/Stack';
import Dialog from '@mui/material/Dialog';
import DialogActions from '@mui/material/DialogActions';
import DialogContent from '@mui/material/DialogContent';
import DialogContentText from '@mui/material/DialogContentText';
import DialogTitle from '@mui/material/DialogTitle';
import Typography from '@mui/material/Typography';
import UploadIcon from '@mui/icons-material/Upload';
import * as URLS from 'config/urls';
import useFormatMessage from 'hooks/useFormatMessage';
import FileUploadInput from 'components/FileUploadInput';
import useImportFlow from 'hooks/useImportFlow';
function ImportFlowDialog(props) {
const {
onClose,
open = true,
'data-test': dataTest = 'import-flow-dialog',
} = props;
const [hasParsingError, setParsingError] = React.useState(false);
const [selectedFile, setSelectedFile] = React.useState(null);
const navigate = useNavigate();
const formatMessage = useFormatMessage();
const {
mutate: importFlow,
data: importedFlow,
error,
isError,
isSuccess,
reset,
} = useImportFlow();
const handleFileSelection = (event) => {
reset();
setParsingError(false);
const file = event.target.files[0];
setSelectedFile(file);
};
const parseFlowFile = (fileContents) => {
try {
const flowData = JSON.parse(fileContents);
return flowData;
} catch {
setParsingError(true);
}
};
const handleImportFlow = (event) => {
if (!selectedFile) return;
const fileReader = new FileReader();
fileReader.onload = async function readFileLoaded(e) {
const flowData = parseFlowFile(e.target.result);
if (flowData) {
importFlow(flowData);
}
};
fileReader.readAsText(selectedFile);
};
return (
<Dialog open={open} onClose={onClose} data-test={dataTest}>
<DialogTitle>{formatMessage('importFlowDialog.title')}</DialogTitle>
<DialogContent>
<DialogContentText>
{formatMessage('importFlowDialog.description')}
<Stack direction="row" alignItems="center" spacing={2} mt={4}>
<FileUploadInput
onChange={handleFileSelection}
data-test="import-flow-dialog-button"
>
{formatMessage('importFlowDialog.selectFile')}
</FileUploadInput>
{selectedFile && (
<Typography>
{formatMessage('importFlowDialog.selectedFileInformation', {
fileName: selectedFile.name,
})}
</Typography>
)}
</Stack>
</DialogContentText>
</DialogContent>
<DialogActions>
<Button
variant="outlined"
onClick={() => navigate('..')}
data-test="import-flow-dialog-close-button"
>
{formatMessage('importFlowDialog.close')}
</Button>
<Button
variant="contained"
onClick={handleImportFlow}
data-test="import-flow-dialog-import-button"
startIcon={<UploadIcon />}
>
{formatMessage('importFlowDialog.import')}
</Button>
</DialogActions>
{hasParsingError && (
<Alert
data-test="import-flow-dialog-parsing-error-alert"
severity="error"
>
{formatMessage('importFlowDialog.parsingError')}
</Alert>
)}
{isError && (
<Alert
data-test="import-flow-dialog-generic-error-alert"
severity="error"
>
{error.data || formatMessage('genericError')}
</Alert>
)}
{isSuccess && (
<Alert data-test="import-flow-dialog-success-alert" severity="success">
{formatMessage('importFlowDialog.successfullyImportedFlow', {
link: (str) => (
<Link to={URLS.FLOW(importedFlow.data.id)}>{str}</Link>
),
})}
</Alert>
)}
</Dialog>
);
}
ImportFlowDialog.propTypes = {
onClose: PropTypes.func.isRequired,
open: PropTypes.bool,
'data-test': PropTypes.string,
};
export default ImportFlowDialog;