-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(website): Dedicated lineage search field (#3467)
* make 'lineageSearch' a flag that can be enabled for metadata fields * Add some todos * WIP * Forward lineageSearch property * progress * progress * progress * use autocomplete field * swap layout * don't write '*' query * Update lineage file * update link * Add prefixes to combobox? * improve * format * remove pango-lineage-specific expansion * Add Test
- Loading branch information
Showing
8 changed files
with
227 additions
and
21 deletions.
There are no files selected for viewing
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
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
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 |
---|---|---|
@@ -1,10 +1,16 @@ | ||
A.1: | ||
A: | ||
aliases: [] | ||
parents: [] | ||
A.1.1: | ||
A.1: | ||
aliases: [] | ||
parents: | ||
- A | ||
A.1.1: | ||
aliases: | ||
- B | ||
parents: | ||
- A.1 | ||
A.2: | ||
aliases: [] | ||
parents: [] | ||
parents: | ||
- A |
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
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
124 changes: 124 additions & 0 deletions
124
website/src/components/SearchPage/fields/LineageField.spec.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,124 @@ | ||
import { render, screen, fireEvent } from '@testing-library/react'; | ||
import userEvent from '@testing-library/user-event'; | ||
import { describe, it, expect, beforeEach, vi } from 'vitest'; | ||
|
||
import { LineageField } from './LineageField'; | ||
import { lapisClientHooks } from '../../../services/serviceHooks.ts'; | ||
import type { MetadataFilter } from '../../../types/config'; | ||
|
||
vi.mock('../../../services/serviceHooks.ts'); | ||
vi.mock('../../../clientLogger.ts', () => ({ | ||
getClientLogger: () => ({ | ||
error: vi.fn(), | ||
}), | ||
})); | ||
|
||
const mockUseAggregated = vi.fn(); | ||
// @ts-expect-error because mockReturnValue is not defined in the type definition | ||
// eslint-disable-next-line @typescript-eslint/no-unsafe-call | ||
lapisClientHooks.mockReturnValue({ | ||
zodiosHooks: { | ||
useAggregated: mockUseAggregated, | ||
}, | ||
}); | ||
|
||
describe('LineageField', () => { | ||
const field: MetadataFilter = { name: 'lineage', label: 'My Lineage', type: 'string' }; | ||
const setSomeFieldValues = vi.fn(); | ||
const lapisUrl = 'https://example.com/api'; | ||
const lapisSearchParameters = { lineage: 'A.1' }; | ||
|
||
beforeEach(() => { | ||
setSomeFieldValues.mockClear(); | ||
|
||
mockUseAggregated.mockReturnValue({ | ||
data: { | ||
data: [ | ||
{ lineage: 'A.1', count: 10 }, | ||
{ lineage: 'A.1.1', count: 20 }, | ||
], | ||
}, | ||
isLoading: false, | ||
error: null, | ||
mutate: vi.fn(), | ||
}); | ||
}); | ||
|
||
it('renders correctly with initial state', () => { | ||
render( | ||
<LineageField | ||
field={field} | ||
fieldValue='initialValue' | ||
setSomeFieldValues={setSomeFieldValues} | ||
lapisUrl={lapisUrl} | ||
lapisSearchParameters={lapisSearchParameters} | ||
/>, | ||
); | ||
|
||
expect(screen.getByText('My Lineage')).toBeInTheDocument(); | ||
const checkbox = screen.getByRole('checkbox'); | ||
expect(checkbox).not.toBeChecked(); | ||
}); | ||
|
||
it('updates query when sublineages checkbox is toggled', () => { | ||
render( | ||
<LineageField | ||
field={field} | ||
fieldValue='A.1' | ||
setSomeFieldValues={setSomeFieldValues} | ||
lapisUrl={lapisUrl} | ||
lapisSearchParameters={lapisSearchParameters} | ||
/>, | ||
); | ||
|
||
const checkbox = screen.getByRole('checkbox'); | ||
fireEvent.click(checkbox); | ||
|
||
expect(checkbox).toBeChecked(); | ||
expect(setSomeFieldValues).toHaveBeenCalledWith(['lineage', 'A.1*']); | ||
}); | ||
|
||
it('handles input changes and calls setSomeFieldValues', async () => { | ||
render( | ||
<LineageField | ||
field={field} | ||
fieldValue='A.1' | ||
setSomeFieldValues={setSomeFieldValues} | ||
lapisUrl={lapisUrl} | ||
lapisSearchParameters={lapisSearchParameters} | ||
/>, | ||
); | ||
|
||
await userEvent.click(screen.getByLabelText('My Lineage')); | ||
|
||
const options = await screen.findAllByRole('option'); | ||
await userEvent.click(options[1]); | ||
|
||
expect(setSomeFieldValues).toHaveBeenCalledWith(['lineage', 'A.1.1']); | ||
|
||
const checkbox = screen.getByRole('checkbox'); | ||
fireEvent.click(checkbox); | ||
expect(checkbox).toBeChecked(); | ||
|
||
expect(setSomeFieldValues).toHaveBeenCalledWith(['lineage', 'A.1.1*']); | ||
}); | ||
|
||
it('clears wildcard when sublineages is unchecked', () => { | ||
render( | ||
<LineageField | ||
field={field} | ||
fieldValue='value*' | ||
setSomeFieldValues={setSomeFieldValues} | ||
lapisUrl={lapisUrl} | ||
lapisSearchParameters={lapisSearchParameters} | ||
/>, | ||
); | ||
|
||
const checkbox = screen.getByRole('checkbox'); | ||
expect(checkbox).toBeChecked(); | ||
|
||
fireEvent.click(checkbox); | ||
|
||
expect(setSomeFieldValues).toHaveBeenCalledWith(['lineage', 'value']); | ||
}); | ||
}); |
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,55 @@ | ||
import { useEffect, useState, type FC } from 'react'; | ||
|
||
import { AutoCompleteField } from './AutoCompleteField'; | ||
import type { MetadataFilter, SetSomeFieldValues } from '../../../types/config'; | ||
|
||
interface LineageFieldProps { | ||
lapisUrl: string; | ||
lapisSearchParameters: Record<string, any>; // eslint-disable-line @typescript-eslint/no-explicit-any -- TODO(#3451) use a proper type | ||
field: MetadataFilter; | ||
fieldValue: string; | ||
setSomeFieldValues: SetSomeFieldValues; | ||
} | ||
|
||
export const LineageField: FC<LineageFieldProps> = ({ | ||
field, | ||
fieldValue, | ||
setSomeFieldValues, | ||
lapisUrl, | ||
lapisSearchParameters, | ||
}) => { | ||
const [includeSublineages, setIncludeSubLineages] = useState(fieldValue.endsWith('*')); | ||
const [inputText, setInputText] = useState(fieldValue.endsWith('*') ? fieldValue.slice(0, -1) : fieldValue); | ||
|
||
useEffect(() => { | ||
let queryText = includeSublineages ? `${inputText}*` : inputText; | ||
if (queryText === '*') queryText = ''; | ||
if (queryText === fieldValue) return; | ||
setSomeFieldValues([field.name, queryText]); | ||
}, [includeSublineages, inputText, fieldValue]); | ||
|
||
return ( | ||
<div key={field.name} className='flex flex-col border p-3 mb-3 rounded-md border-gray-300'> | ||
<AutoCompleteField | ||
field={field} | ||
lapisUrl={lapisUrl} | ||
setSomeFieldValues={([_, value]) => { | ||
setInputText(value as string); | ||
}} | ||
fieldValue={inputText} | ||
lapisSearchParameters={lapisSearchParameters} | ||
/> | ||
<div className='flex flex-row justify-end'> | ||
<label> | ||
<span className='text-gray-400 text-sm mr-2'>include sublineages</span> | ||
<input | ||
type='checkbox' | ||
className='checkbox checkbox-sm text-3xl [--chkbg:white] [--chkfg:theme(colors.gray.700)] checked:border-gray-300' | ||
checked={includeSublineages} | ||
onChange={(event) => setIncludeSubLineages(event.target.checked)} | ||
/> | ||
</label> | ||
</div> | ||
</div> | ||
); | ||
}; |
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