Merge pull request #434 from automatisch/issue-433

feat: show not found UI in app/connection flows
This commit is contained in:
Ömer Faruk Aydın
2022-08-11 22:10:07 +03:00
committed by GitHub
6 changed files with 62 additions and 11 deletions

View File

@@ -4,6 +4,7 @@ import Context from '../../types/express/context';
type Params = { type Params = {
input: { input: {
triggerAppKey: string; triggerAppKey: string;
connectionId: string;
}; };
}; };
@@ -12,23 +13,32 @@ const createFlow = async (
params: Params, params: Params,
context: Context context: Context
) => { ) => {
const connectionId = params?.input?.connectionId;
const appKey = params?.input?.triggerAppKey; const appKey = params?.input?.triggerAppKey;
const flow = await context.currentUser.$relatedQuery('flows').insert({ const flow = await context.currentUser.$relatedQuery('flows').insert({
name: 'Name your flow', name: 'Name your flow',
}); });
if (connectionId) {
await context.currentUser
.$relatedQuery('connections')
.findById(connectionId)
.throwIfNotFound();
}
await Step.query().insert({ await Step.query().insert({
flowId: flow.id, flowId: flow.id,
type: 'trigger', type: 'trigger',
position: 1, position: 1,
appKey, appKey,
connectionId
}); });
await Step.query().insert({ await Step.query().insert({
flowId: flow.id, flowId: flow.id,
type: 'action', type: 'action',
position: 2, position: 2
}); });
return flow; return flow;

View File

@@ -251,6 +251,7 @@ input DeleteConnectionInput {
input CreateFlowInput { input CreateFlowInput {
triggerAppKey: String triggerAppKey: String
connectionId: String
} }
input UpdateFlowInput { input UpdateFlowInput {

View File

@@ -4,7 +4,10 @@ import { GET_FLOWS } from 'graphql/queries/get-flows';
import Pagination from '@mui/material/Pagination'; import Pagination from '@mui/material/Pagination';
import PaginationItem from '@mui/material/PaginationItem'; import PaginationItem from '@mui/material/PaginationItem';
import * as URLS from 'config/urls';
import AppFlowRow from 'components/FlowRow'; import AppFlowRow from 'components/FlowRow';
import NoResultFound from 'components/NoResultFound';
import useFormatMessage from 'hooks/useFormatMessage';
import type { IFlow } from '@automatisch/types'; import type { IFlow } from '@automatisch/types';
type AppFlowsProps = { type AppFlowsProps = {
@@ -20,8 +23,9 @@ const getLimitAndOffset = (page: number) => ({
export default function AppFlows(props: AppFlowsProps): React.ReactElement { export default function AppFlows(props: AppFlowsProps): React.ReactElement {
const { appKey } = props; const { appKey } = props;
const formatMessage = useFormatMessage();
const [searchParams, setSearchParams] = useSearchParams(); const [searchParams, setSearchParams] = useSearchParams();
const connectionId = searchParams.get('connectionId') || null; const connectionId = searchParams.get('connectionId') || undefined;
const page = parseInt(searchParams.get('page') || '', 10) || 1; const page = parseInt(searchParams.get('page') || '', 10) || 1;
const { data } = useQuery(GET_FLOWS, { variables: { const { data } = useQuery(GET_FLOWS, { variables: {
appKey, appKey,
@@ -31,11 +35,21 @@ export default function AppFlows(props: AppFlowsProps): React.ReactElement {
const getFlows = data?.getFlows || {}; const getFlows = data?.getFlows || {};
const { pageInfo, edges } = getFlows; const { pageInfo, edges } = getFlows;
const appFlows: IFlow[] = edges?.map(({ node }: { node: IFlow }) => node); const flows: IFlow[] = edges?.map(({ node }: { node: IFlow }) => node);
const hasFlows = flows?.length;
if (!hasFlows) {
return (
<NoResultFound
to={URLS.CREATE_FLOW_WITH_APP_AND_CONNECTION(appKey, connectionId)}
text={formatMessage('app.noFlows')}
/>
);
}
return ( return (
<> <>
{appFlows?.map((appFlow: IFlow) => ( {flows?.map((appFlow: IFlow) => (
<AppFlowRow key={appFlow.id} flow={appFlow} /> <AppFlowRow key={appFlow.id} flow={appFlow} />
))} ))}

View File

@@ -22,6 +22,21 @@ export const APP_FLOWS_PATTERN = '/app/:appKey/flows';
export const EDITOR = '/editor'; export const EDITOR = '/editor';
export const CREATE_FLOW ='/editor/create'; export const CREATE_FLOW ='/editor/create';
export const CREATE_FLOW_WITH_APP = (appKey: string) => `/editor/create?appKey=${appKey}`; export const CREATE_FLOW_WITH_APP = (appKey: string) => `/editor/create?appKey=${appKey}`;
export const CREATE_FLOW_WITH_APP_AND_CONNECTION = (appKey?: string, connectionId?: string) => {
const params: { appKey?: string, connectionId?: string } = {};
if (appKey) {
params.appKey = appKey;
}
if (connectionId) {
params.connectionId = connectionId;
}
const searchParams = (new URLSearchParams(params)).toString();
return `/editor/create?${searchParams}`;
}
export const FLOW_EDITOR = (flowId: string): string => `/editor/${flowId}`; export const FLOW_EDITOR = (flowId: string): string => `/editor/${flowId}`;
export const FLOWS = '/flows'; export const FLOWS = '/flows';

View File

@@ -1,6 +1,6 @@
import * as React from 'react'; import * as React from 'react';
import { useQuery } from '@apollo/client'; import { useQuery } from '@apollo/client';
import { Link, Route, Navigate, Routes, useParams, useMatch, useNavigate } from 'react-router-dom'; import { Link, Route, Navigate, Routes, useParams, useSearchParams, useMatch, useNavigate } from 'react-router-dom';
import type { LinkProps } from 'react-router-dom'; import type { LinkProps } from 'react-router-dom';
import { useTheme } from '@mui/material/styles'; import { useTheme } from '@mui/material/styles';
import useMediaQuery from '@mui/material/useMediaQuery'; import useMediaQuery from '@mui/material/useMediaQuery';
@@ -46,10 +46,12 @@ export default function Application(): React.ReactElement | null {
const formatMessage = useFormatMessage(); const formatMessage = useFormatMessage();
const connectionsPathMatch = useMatch({ path: URLS.APP_CONNECTIONS_PATTERN, end: false }); const connectionsPathMatch = useMatch({ path: URLS.APP_CONNECTIONS_PATTERN, end: false });
const flowsPathMatch = useMatch({ path: URLS.APP_FLOWS_PATTERN, end: false }); const flowsPathMatch = useMatch({ path: URLS.APP_FLOWS_PATTERN, end: false });
const [searchParams] = useSearchParams();
const { appKey } = useParams() as ApplicationParams; const { appKey } = useParams() as ApplicationParams;
const navigate = useNavigate(); const navigate = useNavigate();
const { data, loading } = useQuery(GET_APP, { variables: { key: appKey } }); const { data, loading } = useQuery(GET_APP, { variables: { key: appKey } });
const connectionId = searchParams.get('connectionId') || undefined;
const goToApplicationPage = () => navigate('connections'); const goToApplicationPage = () => navigate('connections');
const app = data?.getApp || {}; const app = data?.getApp || {};
@@ -70,9 +72,9 @@ export default function Application(): React.ReactElement | null {
linkProps, linkProps,
ref, ref,
) { ) {
return <Link ref={ref} to={URLS.CREATE_FLOW_WITH_APP(appKey)} {...linkProps} />; return <Link ref={ref} to={URLS.CREATE_FLOW_WITH_APP_AND_CONNECTION(appKey, connectionId)} {...linkProps} />;
}), }),
[appKey], [appKey, connectionId],
); );
if (loading) return null; if (loading) return null;

View File

@@ -17,14 +17,23 @@ export default function CreateFlow(): React.ReactElement {
const [createFlow] = useMutation(CREATE_FLOW); const [createFlow] = useMutation(CREATE_FLOW);
const appKey = searchParams.get('appKey'); const appKey = searchParams.get('appKey');
const connectionId = searchParams.get('connectionId');
React.useEffect(() => { React.useEffect(() => {
async function initiate() { async function initiate() {
const variables: { [key: string]: string } = {};
if (appKey) {
variables.triggerAppKey = appKey;
}
if (connectionId) {
variables.connectionId = connectionId;
}
const response = await createFlow({ const response = await createFlow({
variables: { variables: {
input: { input: variables
triggerAppKey: appKey,
}
} }
}); });
const flowId = response.data?.createFlow?.id; const flowId = response.data?.createFlow?.id;
@@ -33,7 +42,7 @@ export default function CreateFlow(): React.ReactElement {
} }
initiate(); initiate();
}, [createFlow, navigate, appKey]); }, [createFlow, navigate, appKey, connectionId]);
return ( return (
<Box sx={{ display: 'flex', flex: 1, height: '100vh', justifyContent: 'center', alignItems: 'center', gap: 2 }}> <Box sx={{ display: 'flex', flex: 1, height: '100vh', justifyContent: 'center', alignItems: 'center', gap: 2 }}>