Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions website/src/components/collections/form/CollectionForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,7 @@ export function CollectionForm({
onRemove={removeVariant}
canRemove={variants.length > 1}
lineageFields={lineageFields}
lapisUrl={lapisUrl}
/>
))}
<button type='button' className='btn btn-sm w-full' onClick={addVariant}>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,13 @@ import { describe, expect, it as itVitest, vi } from 'vitest';
import { render } from 'vitest-browser-react';

import { VariantEditor } from './VariantEditor.tsx';
import { DUMMY_LAPIS_URL } from '../../../../routeMocker.ts';
import { it } from '../../../../test-extend.ts';
import { withQueryProvider } from '../../../backendApi/withQueryProvider.tsx';
import type { VariantUpdate } from '../../../types/Collection.ts';

const VariantEditorWithProvider = withQueryProvider(VariantEditor);

const FILTER_VARIANT: VariantUpdate = { type: 'filterObject', name: 'JN.1*', filterObject: {} };
const QUERY_VARIANT: VariantUpdate = {
type: 'query',
Expand All @@ -17,13 +21,14 @@ describe('VariantEditor', () => {
lapis.mockLapisDown();

const { getByText } = render(
<VariantEditor
<VariantEditorWithProvider
index={0}
variant={FILTER_VARIANT}
onChange={vi.fn()}
onRemove={vi.fn()}
canRemove={false}
lineageFields={[]}
lapisUrl={DUMMY_LAPIS_URL}
/>,
);

Expand All @@ -35,13 +40,14 @@ describe('VariantEditor', () => {
lapis.mockLapisDown();

const { getByRole } = render(
<VariantEditor
<VariantEditorWithProvider
index={0}
variant={FILTER_VARIANT}
onChange={vi.fn()}
onRemove={vi.fn()}
canRemove={false}
lineageFields={[]}
lapisUrl={DUMMY_LAPIS_URL}
/>,
);

Expand All @@ -50,13 +56,14 @@ describe('VariantEditor', () => {

itVitest('"Use advanced query" checkbox is checked for query variant', async () => {
const { getByRole } = render(
<VariantEditor
<VariantEditorWithProvider
index={0}
variant={QUERY_VARIANT}
onChange={vi.fn()}
onRemove={vi.fn()}
canRemove={false}
lineageFields={[]}
lapisUrl={DUMMY_LAPIS_URL}
/>,
);

Expand All @@ -69,13 +76,14 @@ describe('VariantEditor', () => {
const onChange = vi.fn();

const { getByRole } = render(
<VariantEditor
<VariantEditorWithProvider
index={0}
variant={FILTER_VARIANT}
onChange={onChange}
onRemove={vi.fn()}
canRemove={false}
lineageFields={[]}
lapisUrl={DUMMY_LAPIS_URL}
/>,
);

Expand All @@ -88,13 +96,14 @@ describe('VariantEditor', () => {
lapis.mockLapisDown();

const { getByRole } = render(
<VariantEditor
<VariantEditorWithProvider
index={0}
variant={FILTER_VARIANT}
onChange={vi.fn()}
onRemove={vi.fn()}
canRemove={true}
lineageFields={[]}
lapisUrl={DUMMY_LAPIS_URL}
/>,
);

Expand All @@ -107,13 +116,14 @@ describe('VariantEditor', () => {
const onRemove = vi.fn();

const { getByRole } = render(
<VariantEditor
<VariantEditorWithProvider
index={2}
variant={FILTER_VARIANT}
onChange={vi.fn()}
onRemove={onRemove}
canRemove={true}
lineageFields={[]}
lapisUrl={DUMMY_LAPIS_URL}
/>,
);

Expand All @@ -126,13 +136,14 @@ describe('VariantEditor', () => {
const onChange = vi.fn();

const { getByPlaceholder } = render(
<VariantEditor
<VariantEditorWithProvider
index={0}
variant={QUERY_VARIANT}
onChange={onChange}
onRemove={vi.fn()}
canRemove={false}
lineageFields={[]}
lapisUrl={DUMMY_LAPIS_URL}
/>,
);

Expand Down
32 changes: 11 additions & 21 deletions website/src/components/collections/form/VariantEditor.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { memo, useCallback, useRef } from 'react';

import type { FilterObject, VariantUpdate } from '../../../types/Collection.ts';
import { AdvancedQueryFilter } from '../../genspectrum/AdvancedQueryFilter.tsx';
import { GsLineageFilter } from '../../genspectrum/GsLineageFilter.tsx';
import { GsMutationFilter } from '../../genspectrum/GsMutationFilter.tsx';

Expand All @@ -11,6 +12,7 @@ type Props = {
onRemove: (index: number) => void;
canRemove?: boolean;
lineageFields: string[];
lapisUrl: string;
};

// Memoized to prevent re-rendering all variant cards when only one changes in the parent list.
Expand All @@ -21,6 +23,7 @@ export const VariantEditor = memo(function VariantEditor({
onRemove,
canRemove = true,
lineageFields,
lapisUrl,
}: Props) {
const variantRef = useRef(variant);
variantRef.current = variant;
Expand Down Expand Up @@ -75,7 +78,14 @@ export const VariantEditor = memo(function VariantEditor({

<div className='col-span-2 flex flex-col gap-4'>
{variant.type === 'query' ? (
<QueryVariantFields variant={variant} onChange={(v) => onChange(index, v)} />
<AdvancedQueryFilter
enabled
lapisUrl={lapisUrl}
value={variant.countQuery}
allowedFields={lineageFields.length > 0 ? lineageFields : undefined}
onInput={(newValue) => onChange(index, { ...variant, countQuery: newValue ?? '' })}
errorTooltipClass='tooltip-top'
/>
Comment thread
fhennig marked this conversation as resolved.
Comment on lines +81 to +88

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The tooltip overlaps:

Image

Did you plan to still include changing the direction in this PR or do you want to do it later?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

image

Might still be cut off on some screens - but maybe fine for now?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, we can improve later.

) : (
<MutationListVariantFields
filterObject={variant.filterObject}
Expand Down Expand Up @@ -109,26 +119,6 @@ export const VariantEditor = memo(function VariantEditor({
);
});

function QueryVariantFields({
variant,
onChange,
}: {
variant: Extract<VariantUpdate, { type: 'query' }>;
onChange: (v: VariantUpdate) => void;
}) {
return (
<div className='flex flex-col'>
<label className='label'>Query</label>
<textarea
className='textarea textarea-bordered w-full max-w-xl font-mono text-sm'
placeholder='LAPIS filter expression for counting sequences matching this variant.'
value={variant.countQuery}
onChange={(e) => onChange({ ...variant, countQuery: e.currentTarget.value })}
/>
</div>
);
}

// Memoized because GsMutationFilter is expensive to re-render. Relies on handleFilterObjectChange
// being stable (via useCallback) in the parent — otherwise memo would have no effect.
const MutationListVariantFields = memo(function MutationListVariantFields({
Expand Down