feat: add delete step functionality
This commit is contained in:

committed by
Ömer Faruk Aydın

parent
0b6eecd41d
commit
90aac874bf
@@ -1,6 +1,5 @@
|
||||
import * as React from 'react';
|
||||
import { useMutation } from '@apollo/client';
|
||||
import { ApolloCache, FetchResult } from '@apollo/client';
|
||||
import Box from '@mui/material/Box';
|
||||
import IconButton from '@mui/material/IconButton';
|
||||
import AddIcon from '@mui/icons-material/Add';
|
||||
@@ -10,7 +9,6 @@ import { CREATE_STEP } from 'graphql/mutations/create-step';
|
||||
import { UPDATE_STEP } from 'graphql/mutations/update-step';
|
||||
import FlowStep from 'components/FlowStep';
|
||||
import type { Flow } from 'types/flow';
|
||||
import type { Step } from 'types/step';
|
||||
|
||||
type EditorProps = {
|
||||
flow: Flow;
|
||||
@@ -42,7 +40,7 @@ function updateHandlerFactory(flowId: string, previousStepId: string) {
|
||||
|
||||
export default function Editor(props: EditorProps): React.ReactElement {
|
||||
const [updateStep] = useMutation(UPDATE_STEP);
|
||||
const [createStep] = useMutation(CREATE_STEP);
|
||||
const [createStep, { loading: creationInProgress }] = useMutation(CREATE_STEP);
|
||||
const [currentStep, setCurrentStep] = React.useState<number | null>(0);
|
||||
const { flow } = props;
|
||||
|
||||
@@ -96,7 +94,7 @@ export default function Editor(props: EditorProps): React.ReactElement {
|
||||
alignItems="center"
|
||||
alignSelf="center"
|
||||
py={3}
|
||||
gap={2}
|
||||
gap={1}
|
||||
>
|
||||
{flow?.steps?.map((step, index) => (
|
||||
<React.Fragment key={`${step}-${index}`}>
|
||||
@@ -110,7 +108,7 @@ export default function Editor(props: EditorProps): React.ReactElement {
|
||||
onChange={onStepChange}
|
||||
/>
|
||||
|
||||
<IconButton onClick={() => addStep(step.id)} color="primary">
|
||||
<IconButton onClick={() => addStep(step.id)} color="primary" disabled={creationInProgress}>
|
||||
<AddIcon />
|
||||
</IconButton>
|
||||
</React.Fragment>
|
||||
|
@@ -2,6 +2,7 @@ import * as React from 'react';
|
||||
import { useQuery } from '@apollo/client';
|
||||
import Stack from '@mui/material/Stack';
|
||||
import Typography from '@mui/material/Typography';
|
||||
import Box from '@mui/material/Box';
|
||||
import Button from '@mui/material/Button';
|
||||
import Collapse from '@mui/material/Collapse';
|
||||
import List from '@mui/material/List';
|
||||
@@ -9,7 +10,10 @@ import ListItem from '@mui/material/ListItem';
|
||||
import ListItemButton from '@mui/material/ListItemButton';
|
||||
import TextField from '@mui/material/TextField';
|
||||
import Autocomplete from '@mui/material/Autocomplete';
|
||||
import MoreHorizIcon from '@mui/icons-material/MoreHoriz';
|
||||
import IconButton from '@mui/material/IconButton';
|
||||
|
||||
import FlowStepContextMenu from 'components/FlowStepContextMenu';
|
||||
import AppIcon from 'components/AppIcon';
|
||||
import { GET_APPS } from 'graphql/queries/get-apps';
|
||||
import useFormatMessage from 'hooks/useFormatMessage';
|
||||
@@ -49,7 +53,9 @@ const parseStep = (step: any) => {
|
||||
|
||||
export default function FlowStep(props: FlowStepProps): React.ReactElement | null {
|
||||
const { collapsed, index, onChange } = props;
|
||||
const contextButtonRef = React.useRef<HTMLButtonElement | null>(null);
|
||||
const [step, setStep] = React.useState<Step>(() => parseStep(props.step));
|
||||
const [anchorEl, setAnchorEl] = React.useState<HTMLButtonElement | null>(null);
|
||||
const isTrigger = step.type === StepType.Trigger;
|
||||
const isAction = step.type === StepType.Action;
|
||||
const initialRender = React.useRef<boolean>(true);
|
||||
@@ -97,6 +103,14 @@ export default function FlowStep(props: FlowStepProps): React.ReactElement | nul
|
||||
|
||||
if (!apps) return null;
|
||||
|
||||
const onContextMenuClose = (event: React.SyntheticEvent) => {
|
||||
event.stopPropagation();
|
||||
setAnchorEl(null);
|
||||
}
|
||||
const onContextMenuClick = (event: React.SyntheticEvent) => {
|
||||
event.stopPropagation();
|
||||
setAnchorEl(contextButtonRef.current);
|
||||
}
|
||||
const onOpen = () => collapsed && props.onOpen?.();
|
||||
const onClose = () => props.onClose?.();
|
||||
|
||||
@@ -121,6 +135,13 @@ export default function FlowStep(props: FlowStepProps): React.ReactElement | nul
|
||||
{index}. {app?.name}
|
||||
</Typography>
|
||||
</div>
|
||||
|
||||
<Box display="flex" flex={1} justifyContent="end">
|
||||
{/* as there are no other actions besides "delete step", we hide the context menu. */}
|
||||
{!isTrigger && <IconButton color="primary" onClick={onContextMenuClick} ref={contextButtonRef}>
|
||||
<MoreHorizIcon />
|
||||
</IconButton>}
|
||||
</Box>
|
||||
</Stack>
|
||||
</Header>
|
||||
|
||||
@@ -170,6 +191,13 @@ export default function FlowStep(props: FlowStepProps): React.ReactElement | nul
|
||||
</Button>
|
||||
</Collapse>
|
||||
)}
|
||||
|
||||
{anchorEl && <FlowStepContextMenu
|
||||
stepId={step.id}
|
||||
deletable={!isTrigger}
|
||||
onClose={onContextMenuClose}
|
||||
anchorEl={anchorEl}
|
||||
/>}
|
||||
</Wrapper>
|
||||
)
|
||||
};
|
||||
|
41
packages/web/src/components/FlowStepContextMenu/index.tsx
Normal file
41
packages/web/src/components/FlowStepContextMenu/index.tsx
Normal file
@@ -0,0 +1,41 @@
|
||||
import * as React from 'react';
|
||||
import { useMutation } from '@apollo/client';
|
||||
import Menu from '@mui/material/Menu';
|
||||
import MenuItem from '@mui/material/MenuItem';
|
||||
import type { PopoverProps } from '@mui/material/Popover';
|
||||
|
||||
import { DELETE_STEP } from 'graphql/mutations/delete-step';
|
||||
import useFormatMessage from 'hooks/useFormatMessage';
|
||||
|
||||
type FlowStepContextMenuProps = {
|
||||
stepId: string;
|
||||
onClose: PopoverProps['onClose'];
|
||||
anchorEl: HTMLButtonElement;
|
||||
deletable: boolean;
|
||||
};
|
||||
|
||||
function FlowStepContextMenu(props: FlowStepContextMenuProps): React.ReactElement {
|
||||
const { stepId, onClose, anchorEl, deletable } = props;
|
||||
const [deleteStep] = useMutation(DELETE_STEP);
|
||||
const formatMessage = useFormatMessage();
|
||||
|
||||
const deleteActionHandler = React.useCallback(async (event: React.SyntheticEvent) => {
|
||||
event.stopPropagation();
|
||||
await deleteStep({ variables: { id: stepId }});
|
||||
}, [stepId]);
|
||||
|
||||
return (
|
||||
<Menu
|
||||
open={true}
|
||||
onClose={onClose}
|
||||
hideBackdrop={false}
|
||||
anchorEl={anchorEl}
|
||||
>
|
||||
{deletable && <MenuItem onClick={deleteActionHandler}>
|
||||
{formatMessage('connection.delete')}
|
||||
</MenuItem>}
|
||||
</Menu>
|
||||
);
|
||||
};
|
||||
|
||||
export default FlowStepContextMenu;
|
@@ -7,6 +7,7 @@ export const CREATE_STEP = gql`
|
||||
type
|
||||
key
|
||||
appKey
|
||||
parameters
|
||||
connection {
|
||||
id
|
||||
}
|
||||
|
15
packages/web/src/graphql/mutations/delete-step.ts
Normal file
15
packages/web/src/graphql/mutations/delete-step.ts
Normal file
@@ -0,0 +1,15 @@
|
||||
import { gql } from '@apollo/client';
|
||||
|
||||
export const DELETE_STEP = gql`
|
||||
mutation DeleteStep($id: String!) {
|
||||
deleteStep(id: $id) {
|
||||
id
|
||||
flow {
|
||||
id
|
||||
steps {
|
||||
id
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
`;
|
@@ -8,7 +8,6 @@ export const GET_APP = gql`
|
||||
iconUrl
|
||||
docUrl
|
||||
primaryColor
|
||||
connectionCount
|
||||
fields {
|
||||
key
|
||||
label
|
||||
|
Reference in New Issue
Block a user