diff --git a/packages/web/src/components/ChooseAppAndEventSubstep/index.jsx b/packages/web/src/components/ChooseAppAndEventSubstep/index.jsx index 17712178..40936244 100644 --- a/packages/web/src/components/ChooseAppAndEventSubstep/index.jsx +++ b/packages/web/src/components/ChooseAppAndEventSubstep/index.jsx @@ -91,15 +91,15 @@ function ChooseAppAndEventSubstep(props) { const onEventChange = React.useCallback( (event, selectedOption) => { if (typeof selectedOption === 'object') { - // TODO: try to simplify type casting below. - const typedSelectedOption = selectedOption; - const option = typedSelectedOption; - const eventKey = option?.value; + const eventKey = selectedOption?.value; + const eventLabel = selectedOption?.label; + if (step.key !== eventKey) { onChange({ step: { ...step, key: eventKey, + keyLabel: eventLabel, }, }); } @@ -111,10 +111,8 @@ function ChooseAppAndEventSubstep(props) { const onAppChange = React.useCallback( (event, selectedOption) => { if (typeof selectedOption === 'object') { - // TODO: try to simplify type casting below. - const typedSelectedOption = selectedOption; - const option = typedSelectedOption; - const appKey = option?.value; + const appKey = selectedOption?.value; + if (step.appKey !== appKey) { onChange({ step: { diff --git a/packages/web/src/components/EditableTypography/index.jsx b/packages/web/src/components/EditableTypography/index.jsx index bb234326..255ebbd3 100644 --- a/packages/web/src/components/EditableTypography/index.jsx +++ b/packages/web/src/components/EditableTypography/index.jsx @@ -7,37 +7,68 @@ import { Box, TextField } from './style'; const noop = () => null; function EditableTypography(props) { - const { children, onConfirm = noop, sx, ...typographyProps } = props; + const { + children, + onConfirm = noop, + iconPosition = 'start', + iconSize = 'large', + sx, + disabledEditing = false, + prefixValue = '', + ...typographyProps + } = props; + const [editing, setEditing] = React.useState(false); + const handleClick = React.useCallback(() => { + if (disabledEditing) return; + setEditing((editing) => !editing); - }, []); + }, [disabledEditing]); + const handleTextFieldClick = React.useCallback((event) => { event.stopPropagation(); }, []); + const handleTextFieldKeyDown = React.useCallback( async (event) => { const target = event.target; + if (event.key === 'Enter') { if (target.value !== children) { await onConfirm(target.value); } + + setEditing(false); + } + + if (event.key === 'Escape') { setEditing(false); } }, [children], ); + const handleTextFieldBlur = React.useCallback( async (event) => { const value = event.target.value; + if (value !== children) { await onConfirm(value); } + setEditing(false); }, [onConfirm, children], ); - let component = {children}; + + let component = ( + + {prefixValue} + {children} + + ); + if (editing) { component = ( ); } + return ( - - + + {iconPosition === 'start' && editing === false && ( + + )} {component} + + {iconPosition === 'end' && editing === false && ( + + )} ); } EditableTypography.propTypes = { children: PropTypes.string.isRequired, + disabledEditing: PropTypes.bool, + iconPosition: PropTypes.oneOf(['start', 'end']), + iconSize: PropTypes.oneOf(['small', 'large']), onConfirm: PropTypes.func, + prefixValue: PropTypes.string, sx: PropTypes.object, }; diff --git a/packages/web/src/components/EditableTypography/style.js b/packages/web/src/components/EditableTypography/style.js index 8e11fd83..e99cb6ea 100644 --- a/packages/web/src/components/EditableTypography/style.js +++ b/packages/web/src/components/EditableTypography/style.js @@ -2,17 +2,23 @@ import { styled } from '@mui/material/styles'; import MuiBox from '@mui/material/Box'; import MuiTextField from '@mui/material/TextField'; import { inputClasses } from '@mui/material/Input'; -const boxShouldForwardProp = (prop) => !['editing'].includes(prop); + +const boxShouldForwardProp = (prop) => + !['editing', 'disabledEditing'].includes(prop); + export const Box = styled(MuiBox, { shouldForwardProp: boxShouldForwardProp, })` display: flex; flex: 1; - width: 300px; + min-width: 300px; + max-width: 90%; height: 33px; align-items: center; + ${({ disabledEditing }) => !disabledEditing && 'cursor: pointer;'} ${({ editing }) => editing && 'border-bottom: 1px dashed #000;'} `; + export const TextField = styled(MuiTextField)({ width: '100%', [`.${inputClasses.root}:before, .${inputClasses.root}:after, .${inputClasses.root}:hover`]: diff --git a/packages/web/src/components/Editor/index.jsx b/packages/web/src/components/Editor/index.jsx index 96ca3258..5de95d4e 100644 --- a/packages/web/src/components/Editor/index.jsx +++ b/packages/web/src/components/Editor/index.jsx @@ -27,6 +27,10 @@ function Editor(props) { connectionId: step.connection?.id, }; + if (step.name) { + payload.name = step.name; + } + if (step.appKey) { payload.appKey = step.appKey; } diff --git a/packages/web/src/components/EditorNew/EditorNew.jsx b/packages/web/src/components/EditorNew/EditorNew.jsx index fc7a5589..7d52e3cc 100644 --- a/packages/web/src/components/EditorNew/EditorNew.jsx +++ b/packages/web/src/components/EditorNew/EditorNew.jsx @@ -90,6 +90,10 @@ const EditorNew = ({ flow }) => { connectionId: step.connection?.id, }; + if (step.name) { + payload.name = step.name || step.keyLabel; + } + if (step.appKey) { payload.appKey = step.appKey; } diff --git a/packages/web/src/components/FlowStep/index.jsx b/packages/web/src/components/FlowStep/index.jsx index e9a4596c..df7e8ec6 100644 --- a/packages/web/src/components/FlowStep/index.jsx +++ b/packages/web/src/components/FlowStep/index.jsx @@ -3,6 +3,7 @@ import * as React from 'react'; import Stack from '@mui/material/Stack'; import Typography from '@mui/material/Typography'; import Box from '@mui/material/Box'; +import Chip from '@mui/material/Chip'; import Button from '@mui/material/Button'; import Collapse from '@mui/material/Collapse'; import List from '@mui/material/List'; @@ -18,6 +19,7 @@ import { isEqual } from 'lodash'; import { EditorContext } from 'contexts/Editor'; import { StepExecutionsProvider } from 'contexts/StepExecutions'; import TestSubstep from 'components/TestSubstep'; +import EditableTypography from 'components/EditableTypography'; import FlowSubstep from 'components/FlowSubstep'; import ChooseAppAndEventSubstep from 'components/ChooseAppAndEventSubstep'; import ChooseConnectionSubstep from 'components/ChooseConnectionSubstep'; @@ -106,10 +108,9 @@ function generateValidationSchema(substeps) { } function FlowStep(props) { - const { collapsed, onChange, onContinue, flowId } = props; + const { collapsed, onChange, onContinue, flowId, step } = props; const editorContext = React.useContext(EditorContext); const contextButtonRef = React.useRef(null); - const step = props.step; const [anchorEl, setAnchorEl] = React.useState(null); const isTrigger = step.type === 'trigger'; const isAction = step.type === 'action'; @@ -117,6 +118,10 @@ function FlowStep(props) { const [currentSubstep, setCurrentSubstep] = React.useState(0); const useAppsOptions = {}; + const stepTypeName = isTrigger + ? formatMessage('flowStep.triggerType') + : formatMessage('flowStep.actionType'); + if (isTrigger) { useAppsOptions.onlyWithTriggers = true; } @@ -183,6 +188,13 @@ function FlowStep(props) { } }; + const handleStepNameChange = async (name) => { + await onChange({ + ...step, + name, + }); + }; + const stepValidationSchema = React.useMemo( () => generateValidationSchema(substeps), [substeps], @@ -226,7 +238,7 @@ function FlowStep(props) { data-test="flow-step" >
- + -
- - {isTrigger - ? formatMessage('flowStep.triggerType') - : formatMessage('flowStep.actionType')} + + + + + {app?.name} - - {step.position}. {app?.name} - -
+ + {step.name} + +
{/* as there are no other actions besides "delete step", we hide the context menu. */} diff --git a/packages/web/src/components/FlowSubstepTitle/style.jsx b/packages/web/src/components/FlowSubstepTitle/style.jsx index c8c0c090..b885f6be 100644 --- a/packages/web/src/components/FlowSubstepTitle/style.jsx +++ b/packages/web/src/components/FlowSubstepTitle/style.jsx @@ -1,9 +1,11 @@ import { styled } from '@mui/material/styles'; import MuiListItemButton from '@mui/material/ListItemButton'; import MuiTypography from '@mui/material/Typography'; + export const ListItemButton = styled(MuiListItemButton)` justify-content: space-between; `; + export const Typography = styled(MuiTypography)` display: flex; align-items: center; diff --git a/packages/web/src/hooks/useUpdateStep.js b/packages/web/src/hooks/useUpdateStep.js index 65e92170..03548b56 100644 --- a/packages/web/src/hooks/useUpdateStep.js +++ b/packages/web/src/hooks/useUpdateStep.js @@ -6,19 +6,20 @@ export default function useUpdateStep() { const queryClient = useQueryClient(); const query = useMutation({ - mutationFn: async ({ id, appKey, key, connectionId, parameters }) => { + mutationFn: async ({ id, appKey, key, connectionId, name, parameters }) => { const { data } = await api.patch(`/v1/steps/${id}`, { appKey, key, connectionId, + name, parameters, }); return data; }, - onSuccess: () => { - queryClient.invalidateQueries({ + onSuccess: async () => { + await queryClient.invalidateQueries({ queryKey: ['flows'], }); }, diff --git a/packages/web/src/styles/theme.js b/packages/web/src/styles/theme.js index 7c2257bc..1e05d062 100644 --- a/packages/web/src/styles/theme.js +++ b/packages/web/src/styles/theme.js @@ -158,6 +158,10 @@ export const defaultTheme = createTheme({ fontSize: referenceTheme.typography.pxToRem(16), }, }, + stepApp: { + fontSize: referenceTheme.typography.pxToRem(12), + color: '#5C5C5C', + }, }, components: { MuiAppBar: { @@ -211,6 +215,23 @@ export const defaultTheme = createTheme({ }), }, }, + MuiChip: { + variants: [ + { + props: { variant: 'stepType' }, + style: ({ theme }) => ({ + color: '#001F52', + fontSize: theme.typography.pxToRem(12), + border: '1px solid', + borderColor: alpha(theme.palette.primary.main, 0.3), + bgcolor: alpha( + theme.palette.primary.main, + theme.palette.action.selectedOpacity, + ), + }), + }, + ], + }, MuiContainer: { defaultProps: { maxWidth: 'xl', @@ -294,6 +315,7 @@ export const defaultTheme = createTheme({ }, }, }); + export const mationTheme = createTheme( deepmerge(defaultTheme, { palette: { @@ -315,4 +337,5 @@ export const mationTheme = createTheme( }, }), ); + export default defaultTheme;