diff --git a/packages/backend/src/graphql/queries/get-flows.ts b/packages/backend/src/graphql/queries/get-flows.ts index b6fb95a1..1b72af81 100644 --- a/packages/backend/src/graphql/queries/get-flows.ts +++ b/packages/backend/src/graphql/queries/get-flows.ts @@ -15,7 +15,7 @@ const getFlows = async (_parent: unknown, params: Params, context: Context) => { .withGraphFetched('steps.[connection]') .where((builder) => { if (params.name) { - builder.where('flows.name', 'like', `%${params.name}%`); + builder.where('flows.name', 'ilike', `%${params.name}%`); } if (params.appKey) { diff --git a/packages/web/src/graphql/queries/get-flows.ts b/packages/web/src/graphql/queries/get-flows.ts index 56e18dc2..71cd5d86 100644 --- a/packages/web/src/graphql/queries/get-flows.ts +++ b/packages/web/src/graphql/queries/get-flows.ts @@ -1,8 +1,8 @@ import { gql } from '@apollo/client'; export const GET_FLOWS = gql` - query GetFlows($limit: Int!, $offset: Int!, $appKey: String) { - getFlows(limit: $limit, offset: $offset, appKey: $appKey) { + query GetFlows($limit: Int!, $offset: Int!, $appKey: String, $name: String) { + getFlows(limit: $limit, offset: $offset, appKey: $appKey, name: $name) { pageInfo { currentPage totalPages diff --git a/packages/web/src/pages/Flows/index.tsx b/packages/web/src/pages/Flows/index.tsx index 5b9faddd..c1ed6660 100644 --- a/packages/web/src/pages/Flows/index.tsx +++ b/packages/web/src/pages/Flows/index.tsx @@ -1,10 +1,12 @@ import * as React from 'react'; import { Link, useSearchParams } from 'react-router-dom'; import type { LinkProps } from 'react-router-dom'; -import { useQuery } from '@apollo/client'; +import { useLazyQuery } from '@apollo/client'; +import debounce from 'lodash/debounce'; import Box from '@mui/material/Box'; import Grid from '@mui/material/Grid'; import AddIcon from '@mui/icons-material/Add'; +import CircularProgress from '@mui/material/CircularProgress'; import Pagination from '@mui/material/Pagination'; import PaginationItem from '@mui/material/PaginationItem'; import type { IFlow } from '@automatisch/types'; @@ -30,17 +32,44 @@ export default function Flows(): React.ReactElement { const [searchParams, setSearchParams] = useSearchParams(); const page = parseInt(searchParams.get('page') || '', 10) || 1; const [flowName, setFlowName] = React.useState(''); - const { data } = useQuery(GET_FLOWS, { - variables: getLimitAndOffset(page), - fetchPolicy: 'cache-and-network', + const [loading, setLoading] = React.useState(false); + const [getFlows, { data }] = useLazyQuery(GET_FLOWS, { + onCompleted: () => { setLoading(false); }, }); - const getFlows = data?.getFlows || {}; - const { pageInfo, edges } = getFlows; + const fetchData = React.useMemo( + () => debounce((name) => getFlows( + { + variables: { + ...getLimitAndOffset(page), + name + } + }), + 300 + ), + [page, getFlows] + ); - const flows: IFlow[] = edges - ?.map(({ node }: { node: IFlow }) => node) - .filter((flow: IFlow) => flow.name?.toLowerCase().includes(flowName.toLowerCase())); + React.useEffect(function fetchFlowsOnSearch() { + setLoading(true); + + fetchData(flowName); + }, [fetchData, flowName]); + + React.useEffect(function resetPageOnSearch() { + // reset search params which only consists of `page` + setSearchParams({}) + }, [flowName]); + + React.useEffect(function cancelDebounceOnUnmount() { + return () => { + fetchData.cancel(); + } + }, []); + + const { pageInfo, edges } = data?.getFlows || {}; + + const flows: IFlow[] = edges?.map(({ node }: { node: IFlow }) => node); const onSearchChange = React.useCallback((event) => { setFlowName(event.target.value); @@ -84,9 +113,11 @@ export default function Flows(): React.ReactElement { - {flows?.map((flow) => ())} + {loading && } - {pageInfo && pageInfo.totalPages > 1 && ())} + + {!loading && pageInfo && pageInfo.totalPages > 1 &&