diff --git a/packages/web/src/components/AddAppConnection/index.tsx b/packages/web/src/components/AddAppConnection/index.tsx index 193bcde9..726d555e 100644 --- a/packages/web/src/components/AddAppConnection/index.tsx +++ b/packages/web/src/components/AddAppConnection/index.tsx @@ -19,7 +19,7 @@ const generateDocsLink = (link: string) => (str: string) => ( ); type AddAppConnectionProps = { - onClose: () => void; + onClose: (response: Record) => void; application: IApp; connectionId?: string; }; @@ -76,7 +76,7 @@ export default function AddAppConnection(props: AddAppConnectionProps): React.Re stepIndex++; if (stepIndex === steps.length) { - onClose(); + onClose(response); } } diff --git a/packages/web/src/components/ChooseConnectionSubstep/index.tsx b/packages/web/src/components/ChooseConnectionSubstep/index.tsx index f99e51bc..1c32c932 100644 --- a/packages/web/src/components/ChooseConnectionSubstep/index.tsx +++ b/packages/web/src/components/ChooseConnectionSubstep/index.tsx @@ -6,13 +6,16 @@ import Collapse from '@mui/material/Collapse'; import ListItem from '@mui/material/ListItem'; import Autocomplete from '@mui/material/Autocomplete'; +import type { IApp, IConnection, IStep, ISubstep } from '@automatisch/types'; +import useFormatMessage from 'hooks/useFormatMessage'; import { EditorContext } from 'contexts/Editor'; import FlowSubstepTitle from 'components/FlowSubstepTitle'; -import type { IApp, IConnection, IStep, ISubstep } from '@automatisch/types'; +import AddAppConnection from 'components/AddAppConnection'; import { GET_APP_CONNECTIONS } from 'graphql/queries/get-app-connections'; import { TEST_CONNECTION } from 'graphql/queries/test-connection'; type ChooseConnectionSubstepProps = { + application: IApp; substep: ISubstep, expanded?: boolean; onExpand: () => void; @@ -22,6 +25,8 @@ type ChooseConnectionSubstepProps = { step: IStep; }; +const ADD_CONNECTION_VALUE = 'ADD_CONNECTION'; + const optionGenerator = (connection: IConnection): { label: string; value: string; } => ({ label: connection?.formattedData?.screenName as string ?? 'Unnamed', value: connection?.id as string, @@ -38,13 +43,16 @@ function ChooseConnectionSubstep(props: ChooseConnectionSubstepProps): React.Rea step, onSubmit, onChange, + application, } = props; const { connection, appKey, } = step; + const formatMessage = useFormatMessage(); const editorContext = React.useContext(EditorContext); - const { data, loading } = useQuery(GET_APP_CONNECTIONS, { variables: { key: appKey }}); + const [showAddConnectionDialog, setShowAddConnectionDialog] = React.useState(false); + const { data, loading, refetch } = useQuery(GET_APP_CONNECTIONS, { variables: { key: appKey }}); // TODO: show detailed error when connection test/verification fails const [ testConnection, @@ -72,10 +80,41 @@ function ChooseConnectionSubstep(props: ChooseConnectionSubstepProps): React.Rea // intentionally no dependencies for initial test }, []); - const connectionOptions = React.useMemo(() => (data?.getApp as IApp)?.connections?.map((connection) => optionGenerator(connection)) || [], [data]); + const connectionOptions = React.useMemo(() => { + const appWithConnections = data?.getApp as IApp; + const options = appWithConnections + ?.connections + ?.map((connection) => optionGenerator(connection)) || []; + + options.push({ + label: formatMessage('chooseConnectionSubstep.addNewConnection'), + value: ADD_CONNECTION_VALUE + }) + + return options; + }, [data, formatMessage]); const { name } = substep; + const handleAddConnectionClose = React.useCallback(async (response) => { + setShowAddConnectionDialog(false); + + const connectionId = response?.createConnection.id; + + if (connectionId) { + await refetch(); + + onChange({ + step: { + ...step, + connection: { + id: connectionId, + }, + }, + }); + } + }, [onChange, refetch, step]); + const handleChange = React.useCallback((event: React.SyntheticEvent, selectedOption: unknown) => { if (typeof selectedOption === 'object') { // TODO: try to simplify type casting below. @@ -83,6 +122,11 @@ function ChooseConnectionSubstep(props: ChooseConnectionSubstepProps): React.Rea const option: { value: string } = typedSelectedOption; const connectionId = option?.value as string; + if (connectionId === ADD_CONNECTION_VALUE) { + setShowAddConnectionDialog(true); + return; + } + if (connectionId !== step.connection?.id) { onChange({ step: { @@ -122,7 +166,12 @@ function ChooseConnectionSubstep(props: ChooseConnectionSubstepProps): React.Rea disableClearable disabled={editorContext.readOnly} options={connectionOptions} - renderInput={(params) => } + renderInput={(params) => ( + + )} value={getOption(connectionOptions, connection?.id)} onChange={handleChange} loading={loading} @@ -136,10 +185,15 @@ function ChooseConnectionSubstep(props: ChooseConnectionSubstepProps): React.Rea sx={{ mt: 2 }} disabled={testResultLoading || !connection?.verified || editorContext.readOnly}data-test="flow-substep-continue-button" > - Continue + {formatMessage('chooseConnectionSubstep.continue')} + + {application && showAddConnectionDialog && } ); } diff --git a/packages/web/src/components/FlowStep/index.tsx b/packages/web/src/components/FlowStep/index.tsx index ece980f9..5b77edb5 100644 --- a/packages/web/src/components/FlowStep/index.tsx +++ b/packages/web/src/components/FlowStep/index.tsx @@ -251,7 +251,7 @@ export default function FlowStep( index: number ) => ( - {substep.key === 'chooseConnection' && ( + {substep.key === 'chooseConnection' && app && ( toggleSubstep(index + 1)} onSubmit={expandNextStep} onChange={handleChange} + application={app} step={step} /> )} diff --git a/packages/web/src/locales/en.json b/packages/web/src/locales/en.json index cbe8c1c0..eb3c71c9 100644 --- a/packages/web/src/locales/en.json +++ b/packages/web/src/locales/en.json @@ -57,6 +57,9 @@ "flowEditor.pollIntervalValue": "Every {minutes} minutes", "flowEditor.triggerEvent": "Trigger event", "flowEditor.actionEvent": "Action event", + "chooseConnectionSubstep.continue": "Continue", + "chooseConnectionSubstep.addNewConnection": "Add new connection", + "chooseConnectionSubstep.chooseConnection": "Choose connection", "flow.createdAt": "created {datetime}", "flow.updatedAt": "updated {datetime}", "flow.view": "View",