From 5aae9a60f405fb53a79989b289f95a7e887bc246 Mon Sep 17 00:00:00 2001 From: Ali BARIN Date: Sat, 5 Feb 2022 23:59:56 +0100 Subject: [PATCH] feat: introduce FlowSubstepTitle in FlowStep --- .../components/ChooseAccountSubstep/index.tsx | 1 + .../web/src/components/FlowStep/index.tsx | 90 ++++++++++++------- .../src/components/FlowSubstepTitle/index.tsx | 42 +++++++++ .../src/components/FlowSubstepTitle/style.tsx | 13 +++ 4 files changed, 115 insertions(+), 31 deletions(-) create mode 100644 packages/web/src/components/FlowSubstepTitle/index.tsx create mode 100644 packages/web/src/components/FlowSubstepTitle/style.tsx diff --git a/packages/web/src/components/ChooseAccountSubstep/index.tsx b/packages/web/src/components/ChooseAccountSubstep/index.tsx index 270922db..92486600 100644 --- a/packages/web/src/components/ChooseAccountSubstep/index.tsx +++ b/packages/web/src/components/ChooseAccountSubstep/index.tsx @@ -38,6 +38,7 @@ function ChooseAccountSubstep(props: ChooseAccountSubstepProps): React.ReactElem } value={getOption(connectionOptions, connectionId)} diff --git a/packages/web/src/components/FlowStep/index.tsx b/packages/web/src/components/FlowStep/index.tsx index 5883d8d6..d9ea2d73 100644 --- a/packages/web/src/components/FlowStep/index.tsx +++ b/packages/web/src/components/FlowStep/index.tsx @@ -15,6 +15,7 @@ import ExpandLessIcon from '@mui/icons-material/ExpandLess'; import ExpandMoreIcon from '@mui/icons-material/ExpandMore'; import IconButton from '@mui/material/IconButton'; +import FlowSubstepTitle from 'components/FlowSubstepTitle'; import ChooseAccountSubstep from 'components/ChooseAccountSubstep'; import Form from 'components/Form'; import InputCreator from 'components/InputCreator'; @@ -56,6 +57,28 @@ const parseStep = (step: any) => { } }; +const validateSubstep = (substep: any, step: Step, substepIndex: number, substepCount: number) => { + if (!substep) return true; + + if (substepCount < substepIndex + 1) { + return null; + } + + if (substep.name === 'Choose account') { + return Boolean(step.connection?.id); + } + + const args: AppFields[] = substep.arguments || []; + + return args.every(arg => { + if (arg.required === false) { return true; } + + const argValue = step.parameters[arg.key]; + + return argValue !== null && argValue !== undefined; + }); +}; + export default function FlowStep(props: FlowStepProps): React.ReactElement | null { const { collapsed, index, onChange } = props; const contextButtonRef = React.useRef(null); @@ -82,7 +105,8 @@ export default function FlowStep(props: FlowStepProps): React.ReactElement | nul const appOptions = React.useMemo(() => apps?.map((app) => optionGenerator(app)), [apps]); const actionsOrTriggers = isTrigger ? app?.triggers : app?.actions; const actionOptions = React.useMemo(() => actionsOrTriggers?.map((trigger) => optionGenerator(trigger)) ?? [], [app?.key]); - const substeps = React.useMemo(() => actionsOrTriggers?.find(({ key }) => key === step.key)?.subSteps, [actionsOrTriggers, step?.key]); + const substeps = React.useMemo(() => actionsOrTriggers?.find(({ key }) => key === step.key)?.subSteps || [], [actionsOrTriggers, step?.key]); + const substepCount = substeps.length + 1; const expandNextStep = React.useCallback(() => { setCurrentSubstep((currentSubstep) => (currentSubstep ?? 0) + 1); }, []); @@ -180,12 +204,12 @@ export default function FlowStep(props: FlowStepProps): React.ReactElement | nul - toggleSubstep(0)} selected={currentSubstep === 0} divider> - - {currentSubstep === 0 ? : } - Choose app & event - - + toggleSubstep(0)} + title="Choose app & event" + valid={substepCount === 1 ? null : !!step.appKey && !!step.key} + /> {substeps?.length > 0 && substeps.map((substep: { name: string, arguments: AppFields[] }, index: number) => ( - toggleSubstep(index + 1)} selected={currentSubstep === (index + 1)} divider> - - {currentSubstep === (index + 1) ? : } - {substep.name as string} - - - - - {substep.name === 'Choose account' && ( - - )} + {validateSubstep(substeps[index - 1], step, index, substepCount) && ( + + toggleSubstep(index + 1)} + title={substep.name} + valid={validateSubstep(substep, step, index + 1, substepCount)} + /> + + + {substep.name === 'Choose account' && ( + + )} - {substep.name !== 'Choose account' && ( - - {substep?.arguments?.map((argument: AppFields) => ( - - ))} - - )} - - + {substep.name !== 'Choose account' && ( + + {substep?.arguments?.map((argument: AppFields) => ( + + ))} + + )} + + + + )} ))} diff --git a/packages/web/src/components/FlowSubstepTitle/index.tsx b/packages/web/src/components/FlowSubstepTitle/index.tsx new file mode 100644 index 00000000..f085fe4d --- /dev/null +++ b/packages/web/src/components/FlowSubstepTitle/index.tsx @@ -0,0 +1,42 @@ +import * as React from 'react'; +import ExpandLessIcon from '@mui/icons-material/ExpandLess'; +import ExpandMoreIcon from '@mui/icons-material/ExpandMore'; +import ErrorIcon from '@mui/icons-material/Error'; +import CheckCircleIcon from '@mui/icons-material/CheckCircle'; + +import { ListItemButton, Typography} from './style'; + +type FlowSubstepTitleProps = { + expanded?: boolean; + onClick: () => void; + title: string; + valid?: boolean | null; +}; + +function FlowSubstepTitle(props: FlowSubstepTitleProps): React.ReactElement { + const { + expanded = false, + onClick = () => null, + valid = null, + title, + } = props; + + const hasValidation = valid !== null; + + const validIcon = ; + const errorIcon = ; + const validationStatusIcon = valid ? validIcon : errorIcon; + + return ( + + + {expanded ? : } + {title} + + + {hasValidation && validationStatusIcon} + + ); +} + +export default FlowSubstepTitle; diff --git a/packages/web/src/components/FlowSubstepTitle/style.tsx b/packages/web/src/components/FlowSubstepTitle/style.tsx new file mode 100644 index 00000000..b885f6be --- /dev/null +++ b/packages/web/src/components/FlowSubstepTitle/style.tsx @@ -0,0 +1,13 @@ +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; + gap: ${({ theme }) => theme.spacing(1)}; +`;