From 599b1702f245dc03203d8a6929579a5d77fe6179 Mon Sep 17 00:00:00 2001 From: Adhitya Mamallan Date: Mon, 25 Nov 2024 19:10:51 +0530 Subject: [PATCH] Fetch domain workflows when a query is provided (#742) * Add changes to table * Change impl * Fix tests and type checks * make changes to type * Split search and query table configs * Add type for domain workflows query config --- .../domain-workflows-query-table.config.ts | 59 +++++++++++++++++++ ...> domain-workflows-search-table.config.ts} | 4 +- .../domain-workflows-header.test.tsx | 26 ++++++-- .../domain-workflows-header.tsx | 7 ++- .../domain-workflows-header.types.ts | 5 ++ .../domain-workflows-query-input.test.tsx | 12 +++- .../domain-workflows-query-input.tsx | 10 +++- .../domain-workflows-query-input.types.ts | 1 + .../__tests__/domain-workflows-table.test.tsx | 56 ++++++++++++++++-- .../domain-workflows-table.tsx | 58 +++++++++--------- .../domain-workflows-table.types.ts | 7 +++ .../get-workflows-error-panel-props.test.ts | 19 +++++- .../get-workflows-error-panel-props.ts | 13 +++- .../domain-workflows/domain-workflows.tsx | 2 +- .../domain-workflows.types.ts | 10 ++-- .../hooks/use-list-workflows.ts | 21 ++++++- 16 files changed, 256 insertions(+), 54 deletions(-) create mode 100644 src/views/domain-workflows/config/domain-workflows-query-table.config.ts rename src/views/domain-workflows/config/{domain-workflows-table.config.ts => domain-workflows-search-table.config.ts} (94%) diff --git a/src/views/domain-workflows/config/domain-workflows-query-table.config.ts b/src/views/domain-workflows/config/domain-workflows-query-table.config.ts new file mode 100644 index 000000000..f8be5a532 --- /dev/null +++ b/src/views/domain-workflows/config/domain-workflows-query-table.config.ts @@ -0,0 +1,59 @@ +import { createElement } from 'react'; + +import FormattedDate from '@/components/formatted-date/formatted-date'; +import Link from '@/components/link/link'; +import { type DomainWorkflow } from '@/views/domain-page/domain-page.types'; +import WorkflowStatusTag from '@/views/shared/workflow-status-tag/workflow-status-tag'; + +import { type DomainWorkflowsQueryTableConfig } from '../domain-workflows-table/domain-workflows-table.types'; + +const domainWorkflowsQueryTableConfig = [ + { + name: 'Workflow ID', + id: 'WorkflowID', + renderCell: (row: DomainWorkflow) => row.workflowID, + width: '25.5%', + }, + { + name: 'Status', + id: 'CloseStatus', + renderCell: (row: DomainWorkflow) => + createElement(WorkflowStatusTag, { status: row.status }), + width: '7.5%', + }, + { + name: 'Run ID', + id: 'RunID', + renderCell: (row: DomainWorkflow) => + createElement( + Link, + { + href: `workflows/${encodeURIComponent(row.workflowID)}/${encodeURIComponent(row.runID)}`, + }, + row.runID + ), + width: '22%', + }, + { + name: 'Workflow type', + id: 'WorkflowType', + renderCell: (row: DomainWorkflow) => row.workflowName, + width: '20%', + }, + { + name: 'Started', + id: 'StartTime', + renderCell: (row: DomainWorkflow) => + createElement(FormattedDate, { timestampMs: row.startTime }), + width: '12.5%', + }, + { + name: 'Ended', + id: 'CloseTime', + renderCell: (row: DomainWorkflow) => + createElement(FormattedDate, { timestampMs: row.closeTime }), + width: '12.5%', + }, +] as const satisfies DomainWorkflowsQueryTableConfig; + +export default domainWorkflowsQueryTableConfig; diff --git a/src/views/domain-workflows/config/domain-workflows-table.config.ts b/src/views/domain-workflows/config/domain-workflows-search-table.config.ts similarity index 94% rename from src/views/domain-workflows/config/domain-workflows-table.config.ts rename to src/views/domain-workflows/config/domain-workflows-search-table.config.ts index 09dbd8a69..49f13e5e2 100644 --- a/src/views/domain-workflows/config/domain-workflows-table.config.ts +++ b/src/views/domain-workflows/config/domain-workflows-search-table.config.ts @@ -6,7 +6,7 @@ import { type TableConfig } from '@/components/table/table.types'; import { type DomainWorkflow } from '@/views/domain-page/domain-page.types'; import WorkflowStatusTag from '@/views/shared/workflow-status-tag/workflow-status-tag'; -const domainWorkflowsTableConfig = [ +const domainWorkflowsSearchTableConfig = [ { name: 'Workflow ID', id: 'WorkflowID', @@ -57,4 +57,4 @@ const domainWorkflowsTableConfig = [ }, ] as const satisfies TableConfig; -export default domainWorkflowsTableConfig; +export default domainWorkflowsSearchTableConfig; diff --git a/src/views/domain-workflows/domain-workflows-header/__tests__/domain-workflows-header.test.tsx b/src/views/domain-workflows/domain-workflows-header/__tests__/domain-workflows-header.test.tsx index fc587dcde..807b34adc 100644 --- a/src/views/domain-workflows/domain-workflows-header/__tests__/domain-workflows-header.test.tsx +++ b/src/views/domain-workflows/domain-workflows-header/__tests__/domain-workflows-header.test.tsx @@ -41,16 +41,26 @@ jest.mock('@/components/page-filters/hooks/use-page-filters', () => })) ); +jest.mock('../../hooks/use-list-workflows', () => + jest.fn(() => ({ + refetch: jest.fn(), + })) +); + describe(DomainWorkflowsHeader.name, () => { it('renders segmented control', async () => { - render(); + render( + + ); expect(await screen.findByText('Search')).toBeInTheDocument(); expect(await screen.findByText('Query')).toBeInTheDocument(); }); it('renders page search and filters button when input type is search', async () => { - render(); + render( + + ); expect(await screen.findByText('Filter search')).toBeInTheDocument(); expect(await screen.findByText('Filter toggle')).toBeInTheDocument(); @@ -58,7 +68,9 @@ describe(DomainWorkflowsHeader.name, () => { it('renders page filters when filter toggle is clicked', async () => { const user = userEvent.setup(); - render(); + render( + + ); const filterToggle = await screen.findByText('Filter toggle'); await user.click(filterToggle); @@ -77,14 +89,18 @@ describe(DomainWorkflowsHeader.name, () => { setQueryParams: mockSetQueryParams, }); - render(); + render( + + ); expect(await screen.findByText('Query')).toBeInTheDocument(); }); it('toggles input type when segmented control is used', async () => { const user = userEvent.setup(); - render(); + render( + + ); const queryButton = await screen.findByText('Search'); await user.click(queryButton); diff --git a/src/views/domain-workflows/domain-workflows-header/domain-workflows-header.tsx b/src/views/domain-workflows/domain-workflows-header/domain-workflows-header.tsx index 847fe3b29..da3d9ae5d 100644 --- a/src/views/domain-workflows/domain-workflows-header/domain-workflows-header.tsx +++ b/src/views/domain-workflows/domain-workflows-header/domain-workflows-header.tsx @@ -11,10 +11,12 @@ import domainPageQueryParamsConfig from '@/views/domain-page/config/domain-page- import domainWorkflowsFiltersConfig from '../config/domain-workflows-filters.config'; import DomainWorkflowsQueryInput from '../domain-workflows-query-input/domain-workflows-query-input'; +import useListWorkflows from '../hooks/use-list-workflows'; import { overrides, styled } from './domain-workflows-header.styles'; +import { type Props } from './domain-workflows-header.types'; -export default function DomainWorkflowsHeader() { +export default function DomainWorkflowsHeader({ domain, cluster }: Props) { const [areFiltersShown, setAreFiltersShown] = useState(false); const { resetAllFilters, activeFiltersCount, queryParams, setQueryParams } = @@ -23,6 +25,8 @@ export default function DomainWorkflowsHeader() { pageQueryParamsConfig: domainPageQueryParamsConfig, }); + const { refetch } = useListWorkflows({ domain, cluster }); + return ( @@ -54,6 +58,7 @@ export default function DomainWorkflowsHeader() { setQueryParams({ query: v })} + refetchQuery={refetch} /> ) : ( <> diff --git a/src/views/domain-workflows/domain-workflows-header/domain-workflows-header.types.ts b/src/views/domain-workflows/domain-workflows-header/domain-workflows-header.types.ts index 1caec1506..5ab04ad92 100644 --- a/src/views/domain-workflows/domain-workflows-header/domain-workflows-header.types.ts +++ b/src/views/domain-workflows/domain-workflows-header/domain-workflows-header.types.ts @@ -2,3 +2,8 @@ import { type ListWorkflowsRequestQueryParams } from '@/route-handlers/list-work export type DomainWorkflowsHeaderInputType = ListWorkflowsRequestQueryParams['inputType']; + +export type Props = { + domain: string; + cluster: string; +}; diff --git a/src/views/domain-workflows/domain-workflows-query-input/__tests__/domain-workflows-query-input.test.tsx b/src/views/domain-workflows/domain-workflows-query-input/__tests__/domain-workflows-query-input.test.tsx index 99bb0a7a7..0f614fd96 100644 --- a/src/views/domain-workflows/domain-workflows-query-input/__tests__/domain-workflows-query-input.test.tsx +++ b/src/views/domain-workflows/domain-workflows-query-input/__tests__/domain-workflows-query-input.test.tsx @@ -29,17 +29,27 @@ describe(DomainWorkflowsQueryInput.name, () => { expect(mockSetValue).toHaveBeenCalledWith('mock_query'); }); + + it('calls refetchQuery when the Rerun Query button is clicked', async () => { + const { mockRefetch, user } = setup({ startValue: 'test_query' }); + + await user.click(await screen.findByText('Rerun Query')); + + expect(mockRefetch).toHaveBeenCalled(); + }); }); function setup({ startValue }: { startValue?: string }) { const mockSetValue = jest.fn(); + const mockRefetch = jest.fn(); const user = userEvent.setup(); render( ); - return { mockSetValue, user }; + return { mockSetValue, mockRefetch, user }; } diff --git a/src/views/domain-workflows/domain-workflows-query-input/domain-workflows-query-input.tsx b/src/views/domain-workflows/domain-workflows-query-input/domain-workflows-query-input.tsx index 3066aadd5..0827ce66a 100644 --- a/src/views/domain-workflows/domain-workflows-query-input/domain-workflows-query-input.tsx +++ b/src/views/domain-workflows/domain-workflows-query-input/domain-workflows-query-input.tsx @@ -7,7 +7,11 @@ import { MdPlayArrow, MdCode, MdRefresh } from 'react-icons/md'; import { overrides } from './domain-workflows-query-input.styles'; import { type Props } from './domain-workflows-query-input.types'; -export default function DomainWorkflowsQueryInput({ value, setValue }: Props) { +export default function DomainWorkflowsQueryInput({ + value, + setValue, + refetchQuery, +}: Props) { const [queryText, setQueryText] = useState(''); useEffect(() => { @@ -30,7 +34,9 @@ export default function DomainWorkflowsQueryInput({ value, setValue }: Props) { clearOnEscape />