diff --git a/website/src/components/SearchPage/DisplaySearchDocs.tsx b/website/src/components/SearchPage/DisplaySearchDocs.tsx new file mode 100644 index 000000000..f5e130c8c --- /dev/null +++ b/website/src/components/SearchPage/DisplaySearchDocs.tsx @@ -0,0 +1,143 @@ +import { Dialog, Transition, DialogPanel, DialogTitle } from '@headlessui/react'; +import React, { Fragment } from 'react'; + +import X from '~icons/material-symbols/close'; +import MaterialSymbolsHelpOutline from '~icons/material-symbols/help-outline'; + +const DisplaySearchDocs: React.FC = () => { + const [isOpen, setIsOpen] = React.useState(false); + + const openDialog = () => setIsOpen(true); + const closeDialog = () => setIsOpen(false); + + return ( + <> + + + + +
+ + +
+
+ + + + Mutation Search + + +
+

+ Nucleotide Mutations and Insertions +

+

+ For a single-segmented organism, nucleotide mutations have the format{' '} + <position><base> or{' '} + <base_ref><position><base>. A <base>{' '} + can be one of the four nucleotides A, T, C, and{' '} + G. It can also be - for deletion and N for unknown. For + example if the reference sequence is A at position 23 both:{' '} + 23T and A23T will yield the same results. +

+

+ If your organism is multi-segmented you must append the name of the segment + to the start of the mutation, e.g. S:23T and S:A23T for a + mutation in segment S. +

+

+ Insertions can be searched for in the same manner, they just need to have{' '} + ins_ appended to the start of the mutation. Example{' '} + ins_10462:A or if the organism is multi-segmented{' '} + ins_S:10462:A. +

+
+ +
+

+ Amino Acid Mutations and Insertions +

+

+ An amino acid mutation has the format{' '} + <gene>:<position><base> or{' '} + <gene>:<base_ref><position><base>. A{' '} + <base> can be one of the 20 amino acid codes. It can also be{' '} + - for deletion and X for unknown. Example: E:57Q. +

+

+ Insertions can be searched for in the same manner, they just need to have{' '} + ins_ + appended to the start of the mutation. Example ins_NS4B:31:N. +

+
+ +
+

Insertion Wildcards

+

+ Loculus supports insertion queries that contain wildcards ?. For + example ins_S:214:?EP? will match all cases where segment S{' '} + has an insertion of EP between the positions 214 and 215 but also an + insertion of other AAs which include the EP, e.g. the insertion{' '} + EPE will be matched. +

+

+ You can also use wildcards to match any insertion at a given position. For + example ins_S:214:?: will match any (but at least one) insertion + between the positions 214 and 215. +

+
+ +
+

Multiple Mutations

+

+ Multiple mutation filters can be provided by adding one mutation after the + other. +

+
+ +
+

Any Mutation

+

+ To filter for any mutation at a given position you can omit the{' '} + <base>. +

+
+
+

No Mutation

+

+ You can write a . for the <base> to filter for sequences + for which it is confirmed that no mutation occurred, i.e. has the same base + as the reference genome at the specified position. +

+
+
+
+
+
+
+
+ + ); +}; + +export default DisplaySearchDocs; diff --git a/website/src/components/SearchPage/SearchForm.tsx b/website/src/components/SearchPage/SearchForm.tsx index 2ffdcb1a4..4e1f18b85 100644 --- a/website/src/components/SearchPage/SearchForm.tsx +++ b/website/src/components/SearchPage/SearchForm.tsx @@ -13,6 +13,10 @@ import type { GroupedMetadataFilter, MetadataFilter, FieldValues, SetAFieldValue import { type ReferenceGenomesSequenceNames } from '../../types/referencesGenomes.ts'; import type { ClientConfig } from '../../types/runtimeConfig.ts'; import { OffCanvasOverlay } from '../OffCanvasOverlay.tsx'; +import MaterialSymbolsHelpOutline from '~icons/material-symbols/help-outline'; +import MaterialSymbolsResetFocus from '~icons/material-symbols/reset-focus'; +import StreamlineWrench from '~icons/streamline/wrench'; + const queryClient = new QueryClient(); interface SearchFormProps { @@ -61,19 +65,22 @@ export const SearchForm = ({

Search query

-
-
- + + Help +
{' '}
diff --git a/website/src/components/SearchPage/SearchFullUI.spec.tsx b/website/src/components/SearchPage/SearchFullUI.spec.tsx index f7bdbf2b2..5a8fe4fb2 100644 --- a/website/src/components/SearchPage/SearchFullUI.spec.tsx +++ b/website/src/components/SearchPage/SearchFullUI.spec.tsx @@ -218,7 +218,7 @@ describe('SearchFullUI', () => { it('toggle field visibility', async () => { renderSearchFullUI({}); expect(await screen.findByLabelText('Field 1')).toBeVisible(); - const customizeButton = await screen.findByRole('button', { name: 'Customize fields' }); + const customizeButton = await screen.findByRole('button', { name: 'Select fields' }); await userEvent.click(customizeButton); const field1Checkbox = await screen.findByRole('checkbox', { name: 'Field 1' }); expect(field1Checkbox).toBeChecked(); diff --git a/website/src/components/SearchPage/fields/MutationField.tsx b/website/src/components/SearchPage/fields/MutationField.tsx index bccffc3a3..11318d990 100644 --- a/website/src/components/SearchPage/fields/MutationField.tsx +++ b/website/src/components/SearchPage/fields/MutationField.tsx @@ -4,6 +4,7 @@ import * as React from 'react'; import type { ReferenceGenomesSequenceNames } from '../../../types/referencesGenomes.ts'; import type { BaseType } from '../../../utils/sequenceTypeHelpers.ts'; +import DisplaySearchDocs from '../DisplaySearchDocs'; interface MutationFieldProps { referenceGenomesSequenceNames: ReferenceGenomesSequenceNames; @@ -188,9 +189,9 @@ export const MutationField: FC = ({ referenceGenomesSequence }; return ( -
+
-
+
= ({ referenceGenomesSequence > Mutations - setHasFocus(true)} - onBlur={() => setHasFocus(false)} - placeholder={hasFocus ? '' : selectedOptions.length === 0 ? 'Mutations' : 'Enter mutation'} - onChange={handleInputChange} - displayValue={(option: MutationQuery) => option.text} - value={inputValue} - id='mutField' - className={` +
+ setHasFocus(true)} + onBlur={() => setHasFocus(false)} + placeholder={ + hasFocus ? '' : selectedOptions.length === 0 ? 'Mutations' : 'Enter mutation' + } + onChange={handleInputChange} + displayValue={(option: MutationQuery) => option.text} + value={inputValue} + id='mutField' + className={` block w-full text-sm text-gray-900 bg-transparent focus:outline-none focus:ring-0 ${selectedOptions.length === 0 ? 'border-0 focus:border-0 py-3' : 'border border-gray-300 border-solid m-2 text-sm ml-0'} `} - /> + /> +
+ +
+