-
Notifications
You must be signed in to change notification settings - Fork 107
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Rename Domain Workflows Filters to Header Add SegmentedControl to switch between Search and Query Add Query Input and Run button for Query view Add Query Label component with configurable Tooltip Add Tooltip config
- Loading branch information
1 parent
ccca673
commit 396707b
Showing
10 changed files
with
362 additions
and
30 deletions.
There are no files selected for viewing
8 changes: 0 additions & 8 deletions
8
src/views/domain-workflows/domain-workflows-filters/domain-workflows-filters.styles.ts
This file was deleted.
Oops, something went wrong.
20 changes: 0 additions & 20 deletions
20
src/views/domain-workflows/domain-workflows-filters/domain-workflows-filters.tsx
This file was deleted.
Oops, something went wrong.
97 changes: 97 additions & 0 deletions
97
...views/domain-workflows/domain-workflows-header/__tests__/domain-workflows-header.test.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,97 @@ | ||
import { render, screen, userEvent } from '@/test-utils/rtl'; | ||
|
||
import * as usePageFiltersModule from '@/components/page-filters/hooks/use-page-filters'; | ||
import { type Props as PageFiltersToggleProps } from '@/components/page-filters/page-filters-toggle/page-filters-toggle.types'; | ||
|
||
import { mockDomainWorkflowsQueryParamsValues } from '../../__fixtures__/domain-workflows-query-params'; | ||
import DomainWorkflowsHeader from '../domain-workflows-header'; | ||
|
||
jest.mock( | ||
'@/components/page-filters/page-filters-search/page-filters-search', | ||
() => jest.fn(() => <div>Filter search</div>) | ||
); | ||
|
||
jest.mock( | ||
'@/components/page-filters/page-filters-fields/page-filters-fields', | ||
() => jest.fn(() => <div>Filter fields</div>) | ||
); | ||
|
||
jest.mock( | ||
'@/components/page-filters/page-filters-toggle/page-filters-toggle', | ||
() => | ||
jest.fn((props: PageFiltersToggleProps) => ( | ||
<button onClick={props.onClick}>Filter toggle</button> | ||
)) | ||
); | ||
|
||
jest.mock( | ||
'../../domain-workflows-query-input/domain-workflows-query-input', | ||
() => jest.fn(() => <div>Query input</div>) | ||
); | ||
|
||
const mockSetQueryParams = jest.fn(); | ||
const mockResetAllFilters = jest.fn(); | ||
const mockActiveFiltersCount = 2; | ||
jest.mock('@/components/page-filters/hooks/use-page-filters', () => | ||
jest.fn(() => ({ | ||
resetAllFilters: mockResetAllFilters, | ||
activeFiltersCount: mockActiveFiltersCount, | ||
queryParams: mockDomainWorkflowsQueryParamsValues, | ||
setQueryParams: mockSetQueryParams, | ||
})) | ||
); | ||
|
||
describe(DomainWorkflowsHeader.name, () => { | ||
it('renders segmented control', async () => { | ||
render(<DomainWorkflowsHeader />); | ||
|
||
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(<DomainWorkflowsHeader />); | ||
|
||
expect(await screen.findByText('Filter search')).toBeInTheDocument(); | ||
expect(await screen.findByText('Filter toggle')).toBeInTheDocument(); | ||
}); | ||
|
||
it('renders page filters when filter toggle is clicked', async () => { | ||
const user = userEvent.setup(); | ||
render(<DomainWorkflowsHeader />); | ||
|
||
const filterToggle = await screen.findByText('Filter toggle'); | ||
await user.click(filterToggle); | ||
|
||
expect(await screen.findByText('Filter fields')).toBeInTheDocument(); | ||
}); | ||
|
||
it('renders query input when input type is query', async () => { | ||
jest.spyOn(usePageFiltersModule, 'default').mockReturnValueOnce({ | ||
resetAllFilters: mockResetAllFilters, | ||
activeFiltersCount: mockActiveFiltersCount, | ||
queryParams: { | ||
...mockDomainWorkflowsQueryParamsValues, | ||
inputType: 'query', | ||
}, | ||
setQueryParams: mockSetQueryParams, | ||
}); | ||
|
||
render(<DomainWorkflowsHeader />); | ||
|
||
expect(await screen.findByText('Query')).toBeInTheDocument(); | ||
}); | ||
|
||
it('toggles input type when segmented control is used', async () => { | ||
const user = userEvent.setup(); | ||
render(<DomainWorkflowsHeader />); | ||
|
||
const queryButton = await screen.findByText('Search'); | ||
await user.click(queryButton); | ||
|
||
expect(mockSetQueryParams).toHaveBeenCalledWith( | ||
{ inputType: 'search' }, | ||
{ pageRerender: true, replace: false } | ||
); | ||
}); | ||
}); |
60 changes: 60 additions & 0 deletions
60
src/views/domain-workflows/domain-workflows-header/domain-workflows-header.styles.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,60 @@ | ||
import { styled as createStyled, type Theme } from 'baseui'; | ||
import { | ||
type SegmentOverrides, | ||
type SegmentedControlOverrides, | ||
} from 'baseui/segmented-control'; | ||
import { type StyleObject } from 'styletron-react'; | ||
|
||
export const styled = { | ||
HeaderContainer: createStyled('div', ({ $theme }: { $theme: Theme }) => ({ | ||
marginTop: $theme.sizing.scale950, | ||
marginBottom: $theme.sizing.scale900, | ||
})), | ||
InputContainer: createStyled('div', ({ $theme }: { $theme: Theme }) => ({ | ||
display: 'flex', | ||
flexDirection: 'column', | ||
gap: $theme.sizing.scale500, | ||
marginBottom: $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, | ||
[$theme.mediaQuery.medium]: { | ||
width: 'auto', | ||
}, | ||
}), | ||
}, | ||
SegmentList: { | ||
style: ({ $theme }: { $theme: Theme }): StyleObject => ({ | ||
height: $theme.sizing.scale950, | ||
...$theme.typography.ParagraphSmall, | ||
}), | ||
}, | ||
Active: { | ||
style: ({ $theme }: { $theme: Theme }): StyleObject => ({ | ||
height: $theme.sizing.scale900, | ||
top: 0, | ||
}), | ||
}, | ||
} satisfies SegmentedControlOverrides, | ||
inputToggleSegment: { | ||
Segment: { | ||
style: ({ $theme }: { $theme: Theme }): StyleObject => ({ | ||
height: $theme.sizing.scale900, | ||
whiteSpace: 'nowrap', | ||
}), | ||
}, | ||
} satisfies SegmentOverrides, | ||
}; |
85 changes: 85 additions & 0 deletions
85
src/views/domain-workflows/domain-workflows-header/domain-workflows-header.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,85 @@ | ||
'use client'; | ||
import { useState } from 'react'; | ||
|
||
import { Segment, SegmentedControl } from 'baseui/segmented-control'; | ||
|
||
import usePageFilters from '@/components/page-filters/hooks/use-page-filters'; | ||
import PageFiltersFields from '@/components/page-filters/page-filters-fields/page-filters-fields'; | ||
import PageFiltersSearch from '@/components/page-filters/page-filters-search/page-filters-search'; | ||
import PageFiltersToggle from '@/components/page-filters/page-filters-toggle/page-filters-toggle'; | ||
import domainPageQueryParamsConfig from '@/views/domain-page/config/domain-page-query-params.config'; | ||
|
||
import domainWorkflowsFiltersConfig from '../config/domain-workflows-filters.config'; | ||
import DomainWorkflowsQueryInput from '../domain-workflows-query-input/domain-workflows-query-input'; | ||
|
||
import { overrides, styled } from './domain-workflows-header.styles'; | ||
|
||
export default function DomainWorkflowsHeader() { | ||
const [areFiltersShown, setAreFiltersShown] = useState(false); | ||
|
||
const { resetAllFilters, activeFiltersCount, queryParams, setQueryParams } = | ||
usePageFilters({ | ||
pageFiltersConfig: domainWorkflowsFiltersConfig, | ||
pageQueryParamsConfig: domainPageQueryParamsConfig, | ||
}); | ||
|
||
return ( | ||
<styled.HeaderContainer> | ||
<styled.InputContainer> | ||
<SegmentedControl | ||
activeKey={queryParams.inputType} | ||
onChange={({ activeKey }) => { | ||
setQueryParams( | ||
{ | ||
inputType: activeKey === 'query' ? 'query' : 'search', | ||
}, | ||
{ replace: false, pageRerender: true } | ||
); | ||
}} | ||
overrides={overrides.inputToggle} | ||
> | ||
<Segment | ||
overrides={overrides.inputToggleSegment} | ||
key="search" | ||
label="Search" | ||
/> | ||
<Segment | ||
overrides={overrides.inputToggleSegment} | ||
key="query" | ||
// TODO @adhitya.mamallan - replace this with the label tooltip component | ||
label="Query" | ||
/> | ||
</SegmentedControl> | ||
{queryParams.inputType === 'query' ? ( | ||
<DomainWorkflowsQueryInput | ||
value={queryParams.query} | ||
setValue={(v) => setQueryParams({ query: v })} | ||
/> | ||
) : ( | ||
<> | ||
<PageFiltersSearch | ||
pageQueryParamsConfig={domainPageQueryParamsConfig} | ||
searchQueryParamKey="search" | ||
searchPlaceholder="Search for Workflow ID, Run ID, or Workflow Type" | ||
/> | ||
<PageFiltersToggle | ||
isActive={areFiltersShown} | ||
onClick={() => { | ||
setAreFiltersShown((value) => !value); | ||
}} | ||
activeFiltersCount={activeFiltersCount} | ||
/> | ||
</> | ||
)} | ||
</styled.InputContainer> | ||
{queryParams.inputType === 'search' && areFiltersShown && ( | ||
<PageFiltersFields | ||
pageFiltersConfig={domainWorkflowsFiltersConfig} | ||
resetAllFilters={resetAllFilters} | ||
queryParams={queryParams} | ||
setQueryParams={setQueryParams} | ||
/> | ||
)} | ||
</styled.HeaderContainer> | ||
); | ||
} |
45 changes: 45 additions & 0 deletions
45
...in-workflows/domain-workflows-query-input/__tests__/domain-workflows-query-input.test.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,45 @@ | ||
import React from 'react'; | ||
|
||
import { render, screen, userEvent, waitFor } from '@/test-utils/rtl'; | ||
|
||
import DomainWorkflowsQueryInput from '../domain-workflows-query-input'; | ||
|
||
describe(DomainWorkflowsQueryInput.name, () => { | ||
it('renders as expected', async () => { | ||
setup({}); | ||
|
||
expect(await screen.findByRole('textbox')).toBeInTheDocument(); | ||
expect(await screen.findByText('Run Query')).toBeInTheDocument(); | ||
}); | ||
|
||
it('renders as expected when loaded with a start value', async () => { | ||
setup({ startValue: 'test_query' }); | ||
|
||
const textbox = await screen.findByRole('textbox'); | ||
await waitFor(() => expect(textbox).toHaveValue('test_query')); | ||
expect(await screen.findByText('Rerun Query')).toBeInTheDocument(); | ||
}); | ||
|
||
it('calls setValue and changes text when the Run Query button is clicked', async () => { | ||
const { mockSetValue, user } = setup({}); | ||
|
||
const textbox = await screen.findByRole('textbox'); | ||
await user.type(textbox, 'mock_query'); | ||
await user.click(await screen.findByText('Run Query')); | ||
|
||
expect(mockSetValue).toHaveBeenCalledWith('mock_query'); | ||
}); | ||
}); | ||
|
||
function setup({ startValue }: { startValue?: string }) { | ||
const mockSetValue = jest.fn(); | ||
const user = userEvent.setup(); | ||
render( | ||
<DomainWorkflowsQueryInput | ||
value={startValue ?? ''} | ||
setValue={mockSetValue} | ||
/> | ||
); | ||
|
||
return { mockSetValue, user }; | ||
} |
28 changes: 28 additions & 0 deletions
28
...iews/domain-workflows/domain-workflows-query-input/domain-workflows-query-input.styles.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
import { type Theme } from 'baseui'; | ||
import { type ButtonOverrides } from 'baseui/button'; | ||
import { type InputOverrides } from 'baseui/input'; | ||
import { type StyleObject } from 'styletron-react'; | ||
|
||
export const overrides = { | ||
input: { | ||
Root: { | ||
style: ({ $theme }: { $theme: Theme }): StyleObject => ({ | ||
height: $theme.sizing.scale950, | ||
}), | ||
}, | ||
Input: { | ||
style: ({ $theme }: { $theme: Theme }): StyleObject => ({ | ||
...$theme.typography.MonoParagraphXSmall, | ||
}), | ||
}, | ||
} satisfies InputOverrides, | ||
runButton: { | ||
Root: { | ||
style: ({ $theme }: { $theme: Theme }): StyleObject => ({ | ||
whiteSpace: 'nowrap', | ||
height: $theme.sizing.scale950, | ||
...$theme.typography.LabelSmall, | ||
}), | ||
}, | ||
} satisfies ButtonOverrides, | ||
}; |
41 changes: 41 additions & 0 deletions
41
src/views/domain-workflows/domain-workflows-query-input/domain-workflows-query-input.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
import React, { 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 { type Props } from './domain-workflows-query-input.types'; | ||
|
||
export default function DomainWorkflowsQueryInput({ value, setValue }: Props) { | ||
const [queryText, setQueryText] = useState<string>(''); | ||
|
||
useEffect(() => { | ||
setQueryText(value); | ||
}, [value]); | ||
|
||
const isQueryUnchanged = value && value === queryText; | ||
|
||
return ( | ||
<> | ||
<Input | ||
value={queryText} | ||
onChange={(event) => { | ||
setQueryText(event.target.value); | ||
}} | ||
startEnhancer={() => <MdCode />} | ||
overrides={overrides.input} | ||
placeholder="Filter workflows using a custom query" | ||
clearable | ||
clearOnEscape | ||
/> | ||
<Button | ||
onClick={() => setValue(queryText || undefined)} | ||
overrides={overrides.runButton} | ||
startEnhancer={isQueryUnchanged ? <MdRefresh /> : <MdPlayArrow />} | ||
> | ||
{isQueryUnchanged ? 'Rerun Query' : 'Run Query'} | ||
</Button> | ||
</> | ||
); | ||
} |
4 changes: 4 additions & 0 deletions
4
...views/domain-workflows/domain-workflows-query-input/domain-workflows-query-input.types.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
export type Props = { | ||
value: string; | ||
setValue: (v: string | undefined) => void; | ||
}; |
Oops, something went wrong.