diff --git a/src/views/domain-workflows/domain-workflows-header/domain-workflows-header.styles.ts b/src/views/domain-workflows/domain-workflows-header/domain-workflows-header.styles.ts index f651cce16..aeafb0e0d 100644 --- a/src/views/domain-workflows/domain-workflows-header/domain-workflows-header.styles.ts +++ b/src/views/domain-workflows/domain-workflows-header/domain-workflows-header.styles.ts @@ -19,20 +19,29 @@ export const styled = { flexDirection: 'row', }, })), + SearchContainer: createStyled('div', ({ $theme }: { $theme: Theme }) => ({ + flexGrow: 1, + display: 'flex', + flexDirection: 'column', + gap: $theme.sizing.scale500, + [$theme.mediaQuery.medium]: { + flexDirection: 'row', + }, + })), }; export const overrides = { inputToggle: { Root: { style: ({ $theme }: { $theme: Theme }): StyleObject => ({ - flex: '1 0 auto', height: $theme.sizing.scale950, padding: $theme.sizing.scale0, borderRadius: $theme.borders.radius300, - width: '100%', ...$theme.typography.ParagraphSmall, + width: 'auto', + flexGrow: 1, [$theme.mediaQuery.medium]: { - width: 'auto', + flexGrow: 0, }, }), }, 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 b33386e34..50b5cd9f6 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 @@ -26,7 +26,10 @@ export default function DomainWorkflowsHeader({ domain, cluster }: Props) { pageQueryParamsConfig: domainPageQueryParamsConfig, }); - const { refetch } = useListWorkflows({ domain, cluster }); + const { refetch, isFetching } = useListWorkflows({ + domain, + cluster, + }); return ( @@ -59,9 +62,10 @@ export default function DomainWorkflowsHeader({ domain, cluster }: Props) { value={queryParams.query} setValue={(v) => setQueryParams({ query: v })} refetchQuery={refetch} + isQueryRunning={isFetching} /> ) : ( - <> + - + )} {queryParams.inputType === 'search' && areFiltersShown && ( 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 0f614fd96..aafea044c 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 @@ -20,6 +20,14 @@ describe(DomainWorkflowsQueryInput.name, () => { expect(await screen.findByText('Rerun Query')).toBeInTheDocument(); }); + it('renders in loading state when query is running', async () => { + setup({ isQueryRunning: true }); + + expect( + await screen.findByLabelText('loading Run Query') + ).toBeInTheDocument(); + }); + it('calls setValue and changes text when the Run Query button is clicked', async () => { const { mockSetValue, user } = setup({}); @@ -30,6 +38,16 @@ describe(DomainWorkflowsQueryInput.name, () => { expect(mockSetValue).toHaveBeenCalledWith('mock_query'); }); + it('calls setValue and changes text when Enter is pressed', async () => { + const { mockSetValue, user } = setup({}); + + const textbox = await screen.findByRole('textbox'); + await user.type(textbox, 'mock_query'); + await user.keyboard('{Enter}'); + + expect(mockSetValue).toHaveBeenCalledWith('mock_query'); + }); + it('calls refetchQuery when the Rerun Query button is clicked', async () => { const { mockRefetch, user } = setup({ startValue: 'test_query' }); @@ -39,7 +57,13 @@ describe(DomainWorkflowsQueryInput.name, () => { }); }); -function setup({ startValue }: { startValue?: string }) { +function setup({ + startValue, + isQueryRunning, +}: { + startValue?: string; + isQueryRunning?: boolean; +}) { const mockSetValue = jest.fn(); const mockRefetch = jest.fn(); const user = userEvent.setup(); @@ -48,6 +72,7 @@ function setup({ startValue }: { startValue?: string }) { value={startValue ?? ''} setValue={mockSetValue} refetchQuery={mockRefetch} + isQueryRunning={isQueryRunning ?? false} /> ); diff --git a/src/views/domain-workflows/domain-workflows-query-input/domain-workflows-query-input.styles.ts b/src/views/domain-workflows/domain-workflows-query-input/domain-workflows-query-input.styles.ts index 40aebdcef..2c7cddc14 100644 --- a/src/views/domain-workflows/domain-workflows-query-input/domain-workflows-query-input.styles.ts +++ b/src/views/domain-workflows/domain-workflows-query-input/domain-workflows-query-input.styles.ts @@ -1,12 +1,26 @@ import { type Theme } from 'baseui'; +import { styled as createStyled } from 'baseui'; import { type ButtonOverrides } from 'baseui/button'; import { type InputOverrides } from 'baseui/input'; import { type StyleObject } from 'styletron-react'; +export const styled = { + QueryForm: createStyled('form', ({ $theme }) => ({ + flexGrow: 1, + display: 'flex', + flexDirection: 'column', + gap: $theme.sizing.scale500, + [$theme.mediaQuery.medium]: { + flexDirection: 'row', + }, + })), +}; + export const overrides = { input: { Root: { style: ({ $theme }: { $theme: Theme }): StyleObject => ({ + flexGrow: 1, height: $theme.sizing.scale950, }), }, 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 0827ce66a..c818f490a 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 @@ -1,16 +1,17 @@ -import React, { useEffect, useState } from 'react'; +import React, { useCallback, useEffect, useState } from 'react'; import { Button } from 'baseui/button'; import { Input } from 'baseui/input'; import { MdPlayArrow, MdCode, MdRefresh } from 'react-icons/md'; -import { overrides } from './domain-workflows-query-input.styles'; +import { styled, overrides } from './domain-workflows-query-input.styles'; import { type Props } from './domain-workflows-query-input.types'; export default function DomainWorkflowsQueryInput({ value, setValue, refetchQuery, + isQueryRunning, }: Props) { const [queryText, setQueryText] = useState(''); @@ -20,8 +21,21 @@ export default function DomainWorkflowsQueryInput({ const isQueryUnchanged = value && value === queryText; + const onSubmit = useCallback(() => { + if (!isQueryUnchanged) { + setValue(queryText || undefined); + } else { + refetchQuery(); + } + }, [isQueryUnchanged, setValue, queryText, refetchQuery]); + return ( - <> + { + e.preventDefault(); + onSubmit(); + }} + > { @@ -34,14 +48,13 @@ export default function DomainWorkflowsQueryInput({ clearOnEscape /> - + ); } diff --git a/src/views/domain-workflows/domain-workflows-query-input/domain-workflows-query-input.types.ts b/src/views/domain-workflows/domain-workflows-query-input/domain-workflows-query-input.types.ts index 7b0aa1329..7a88aca6f 100644 --- a/src/views/domain-workflows/domain-workflows-query-input/domain-workflows-query-input.types.ts +++ b/src/views/domain-workflows/domain-workflows-query-input/domain-workflows-query-input.types.ts @@ -2,4 +2,5 @@ export type Props = { value: string; setValue: (v: string | undefined) => void; refetchQuery: () => void; + isQueryRunning: boolean; }; diff --git a/src/views/domain-workflows/domain-workflows-query-label/domain-workflows-query-label.styles.ts b/src/views/domain-workflows/domain-workflows-query-label/domain-workflows-query-label.styles.ts index 595507246..af5fbd04b 100644 --- a/src/views/domain-workflows/domain-workflows-query-label/domain-workflows-query-label.styles.ts +++ b/src/views/domain-workflows/domain-workflows-query-label/domain-workflows-query-label.styles.ts @@ -68,6 +68,11 @@ export const styled = { export const overrides = { popover: { + Body: { + style: ({ $theme }) => ({ + margin: $theme.sizing.scale600, + }), + }, Inner: { style: ({ $theme }: { $theme: Theme }): StyleObject => ({ backgroundColor: $theme.colors.backgroundPrimary, diff --git a/src/views/domain-workflows/domain-workflows-table/helpers/__tests__/get-workflows-error-panel-props.test.ts b/src/views/domain-workflows/domain-workflows-table/helpers/__tests__/get-workflows-error-panel-props.test.ts index 8956fd76a..36680a73c 100644 --- a/src/views/domain-workflows/domain-workflows-table/helpers/__tests__/get-workflows-error-panel-props.test.ts +++ b/src/views/domain-workflows/domain-workflows-table/helpers/__tests__/get-workflows-error-panel-props.test.ts @@ -28,7 +28,7 @@ describe(getWorkflowsErrorPanelProps.name, () => { }); }); - it('returns "not found" error panel props when search params are absent', () => { + it('returns "not found" error panel props when search params are absent in search mode', () => { expect( getWorkflowsErrorPanelProps({ inputType: 'search', @@ -48,6 +48,16 @@ describe(getWorkflowsErrorPanelProps.name, () => { }); }); + it('returns undefined when search params are absent in query mode', () => { + expect( + getWorkflowsErrorPanelProps({ + inputType: 'query', + error: null, + areSearchParamsAbsent: true, + }) + ).toEqual(undefined); + }); + it('returns undefined in all other cases', () => { expect( getWorkflowsErrorPanelProps({ diff --git a/src/views/domain-workflows/domain-workflows-table/helpers/get-workflows-error-panel-props.ts b/src/views/domain-workflows/domain-workflows-table/helpers/get-workflows-error-panel-props.ts index 972d9306c..83ad85ec1 100644 --- a/src/views/domain-workflows/domain-workflows-table/helpers/get-workflows-error-panel-props.ts +++ b/src/views/domain-workflows/domain-workflows-table/helpers/get-workflows-error-panel-props.ts @@ -25,7 +25,7 @@ export default function getWorkflowsErrorPanelProps({ }; } - if (areSearchParamsAbsent) { + if (inputType === 'search' && areSearchParamsAbsent) { return { message: 'No workflows found for this domain', actions: [ diff --git a/src/views/domain-workflows/hooks/use-list-workflows.ts b/src/views/domain-workflows/hooks/use-list-workflows.ts index 564929824..3105bd727 100644 --- a/src/views/domain-workflows/hooks/use-list-workflows.ts +++ b/src/views/domain-workflows/hooks/use-list-workflows.ts @@ -62,6 +62,7 @@ export default function useListWorkflows({ }, retry: false, refetchOnWindowFocus: (query) => query.state.status !== 'error', + gcTime: 0, }); const workflows = useMemo(() => {