feat(FlowEditor): allow adding new connection in step
This commit is contained in:
@@ -19,7 +19,7 @@ const generateDocsLink = (link: string) => (str: string) => (
|
|||||||
);
|
);
|
||||||
|
|
||||||
type AddAppConnectionProps = {
|
type AddAppConnectionProps = {
|
||||||
onClose: () => void;
|
onClose: (response: Record<string, unknown>) => void;
|
||||||
application: IApp;
|
application: IApp;
|
||||||
connectionId?: string;
|
connectionId?: string;
|
||||||
};
|
};
|
||||||
@@ -76,7 +76,7 @@ export default function AddAppConnection(props: AddAppConnectionProps): React.Re
|
|||||||
stepIndex++;
|
stepIndex++;
|
||||||
|
|
||||||
if (stepIndex === steps.length) {
|
if (stepIndex === steps.length) {
|
||||||
onClose();
|
onClose(response);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -6,13 +6,16 @@ import Collapse from '@mui/material/Collapse';
|
|||||||
import ListItem from '@mui/material/ListItem';
|
import ListItem from '@mui/material/ListItem';
|
||||||
import Autocomplete from '@mui/material/Autocomplete';
|
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 { EditorContext } from 'contexts/Editor';
|
||||||
import FlowSubstepTitle from 'components/FlowSubstepTitle';
|
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 { GET_APP_CONNECTIONS } from 'graphql/queries/get-app-connections';
|
||||||
import { TEST_CONNECTION } from 'graphql/queries/test-connection';
|
import { TEST_CONNECTION } from 'graphql/queries/test-connection';
|
||||||
|
|
||||||
type ChooseConnectionSubstepProps = {
|
type ChooseConnectionSubstepProps = {
|
||||||
|
application: IApp;
|
||||||
substep: ISubstep,
|
substep: ISubstep,
|
||||||
expanded?: boolean;
|
expanded?: boolean;
|
||||||
onExpand: () => void;
|
onExpand: () => void;
|
||||||
@@ -22,6 +25,8 @@ type ChooseConnectionSubstepProps = {
|
|||||||
step: IStep;
|
step: IStep;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const ADD_CONNECTION_VALUE = 'ADD_CONNECTION';
|
||||||
|
|
||||||
const optionGenerator = (connection: IConnection): { label: string; value: string; } => ({
|
const optionGenerator = (connection: IConnection): { label: string; value: string; } => ({
|
||||||
label: connection?.formattedData?.screenName as string ?? 'Unnamed',
|
label: connection?.formattedData?.screenName as string ?? 'Unnamed',
|
||||||
value: connection?.id as string,
|
value: connection?.id as string,
|
||||||
@@ -38,13 +43,16 @@ function ChooseConnectionSubstep(props: ChooseConnectionSubstepProps): React.Rea
|
|||||||
step,
|
step,
|
||||||
onSubmit,
|
onSubmit,
|
||||||
onChange,
|
onChange,
|
||||||
|
application,
|
||||||
} = props;
|
} = props;
|
||||||
const {
|
const {
|
||||||
connection,
|
connection,
|
||||||
appKey,
|
appKey,
|
||||||
} = step;
|
} = step;
|
||||||
|
const formatMessage = useFormatMessage();
|
||||||
const editorContext = React.useContext(EditorContext);
|
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
|
// TODO: show detailed error when connection test/verification fails
|
||||||
const [
|
const [
|
||||||
testConnection,
|
testConnection,
|
||||||
@@ -72,10 +80,41 @@ function ChooseConnectionSubstep(props: ChooseConnectionSubstepProps): React.Rea
|
|||||||
// intentionally no dependencies for initial test
|
// 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 { 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) => {
|
const handleChange = React.useCallback((event: React.SyntheticEvent, selectedOption: unknown) => {
|
||||||
if (typeof selectedOption === 'object') {
|
if (typeof selectedOption === 'object') {
|
||||||
// TODO: try to simplify type casting below.
|
// TODO: try to simplify type casting below.
|
||||||
@@ -83,6 +122,11 @@ function ChooseConnectionSubstep(props: ChooseConnectionSubstepProps): React.Rea
|
|||||||
const option: { value: string } = typedSelectedOption;
|
const option: { value: string } = typedSelectedOption;
|
||||||
const connectionId = option?.value as string;
|
const connectionId = option?.value as string;
|
||||||
|
|
||||||
|
if (connectionId === ADD_CONNECTION_VALUE) {
|
||||||
|
setShowAddConnectionDialog(true);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (connectionId !== step.connection?.id) {
|
if (connectionId !== step.connection?.id) {
|
||||||
onChange({
|
onChange({
|
||||||
step: {
|
step: {
|
||||||
@@ -122,7 +166,12 @@ function ChooseConnectionSubstep(props: ChooseConnectionSubstepProps): React.Rea
|
|||||||
disableClearable
|
disableClearable
|
||||||
disabled={editorContext.readOnly}
|
disabled={editorContext.readOnly}
|
||||||
options={connectionOptions}
|
options={connectionOptions}
|
||||||
renderInput={(params) => <TextField {...params} label="Choose connection" />}
|
renderInput={(params) => (
|
||||||
|
<TextField
|
||||||
|
{...params}
|
||||||
|
label={formatMessage('chooseConnectionSubstep.chooseConnection')}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
value={getOption(connectionOptions, connection?.id)}
|
value={getOption(connectionOptions, connection?.id)}
|
||||||
onChange={handleChange}
|
onChange={handleChange}
|
||||||
loading={loading}
|
loading={loading}
|
||||||
@@ -136,10 +185,15 @@ function ChooseConnectionSubstep(props: ChooseConnectionSubstepProps): React.Rea
|
|||||||
sx={{ mt: 2 }}
|
sx={{ mt: 2 }}
|
||||||
disabled={testResultLoading || !connection?.verified || editorContext.readOnly}data-test="flow-substep-continue-button"
|
disabled={testResultLoading || !connection?.verified || editorContext.readOnly}data-test="flow-substep-continue-button"
|
||||||
>
|
>
|
||||||
Continue
|
{formatMessage('chooseConnectionSubstep.continue')}
|
||||||
</Button>
|
</Button>
|
||||||
</ListItem>
|
</ListItem>
|
||||||
</Collapse>
|
</Collapse>
|
||||||
|
|
||||||
|
{application && showAddConnectionDialog && <AddAppConnection
|
||||||
|
onClose={handleAddConnectionClose}
|
||||||
|
application={application}
|
||||||
|
/>}
|
||||||
</React.Fragment>
|
</React.Fragment>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@@ -251,7 +251,7 @@ export default function FlowStep(
|
|||||||
index: number
|
index: number
|
||||||
) => (
|
) => (
|
||||||
<React.Fragment key={`${substep?.name}-${index}`}>
|
<React.Fragment key={`${substep?.name}-${index}`}>
|
||||||
{substep.key === 'chooseConnection' && (
|
{substep.key === 'chooseConnection' && app && (
|
||||||
<ChooseConnectionSubstep
|
<ChooseConnectionSubstep
|
||||||
expanded={currentSubstep === index + 1}
|
expanded={currentSubstep === index + 1}
|
||||||
substep={substep}
|
substep={substep}
|
||||||
@@ -259,6 +259,7 @@ export default function FlowStep(
|
|||||||
onCollapse={() => toggleSubstep(index + 1)}
|
onCollapse={() => toggleSubstep(index + 1)}
|
||||||
onSubmit={expandNextStep}
|
onSubmit={expandNextStep}
|
||||||
onChange={handleChange}
|
onChange={handleChange}
|
||||||
|
application={app}
|
||||||
step={step}
|
step={step}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
@@ -57,6 +57,9 @@
|
|||||||
"flowEditor.pollIntervalValue": "Every {minutes} minutes",
|
"flowEditor.pollIntervalValue": "Every {minutes} minutes",
|
||||||
"flowEditor.triggerEvent": "Trigger event",
|
"flowEditor.triggerEvent": "Trigger event",
|
||||||
"flowEditor.actionEvent": "Action event",
|
"flowEditor.actionEvent": "Action event",
|
||||||
|
"chooseConnectionSubstep.continue": "Continue",
|
||||||
|
"chooseConnectionSubstep.addNewConnection": "Add new connection",
|
||||||
|
"chooseConnectionSubstep.chooseConnection": "Choose connection",
|
||||||
"flow.createdAt": "created {datetime}",
|
"flow.createdAt": "created {datetime}",
|
||||||
"flow.updatedAt": "updated {datetime}",
|
"flow.updatedAt": "updated {datetime}",
|
||||||
"flow.view": "View",
|
"flow.view": "View",
|
||||||
|
Reference in New Issue
Block a user