@genspectrum/dashboard-components 1.8.2 → 1.9.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/custom-elements.json +2 -2
- package/dist/components.d.ts +25 -25
- package/dist/components.js +165 -44
- package/dist/components.js.map +1 -1
- package/dist/util.d.ts +25 -25
- package/package.json +1 -1
- package/src/preact/components/downshift-combobox.tsx +2 -1
- package/src/preact/components/portal-tooltip.tsx +129 -0
- package/src/preact/components/tooltip.tsx +32 -16
- package/src/preact/lineageFilter/fetchLineageAutocompleteList.spec.ts +72 -0
- package/src/preact/lineageFilter/fetchLineageAutocompleteList.ts +81 -19
- package/src/preact/lineageFilter/lineage-filter.stories.tsx +57 -1
- package/src/preact/lineageFilter/lineage-filter.tsx +1 -1
- package/src/preact/locationFilter/location-filter.tsx +3 -1
- package/src/preact/mutationsOverTime/mutations-over-time-grid-tooltip.tsx +1 -1
- package/src/preact/mutationsOverTime/mutations-over-time-grid.tsx +13 -7
- package/src/preact/mutationsOverTime/mutations-over-time.tsx +13 -4
- package/src/preact/textFilter/text-filter.tsx +3 -1
- package/src/preact/wastewater/mutationsOverTime/wastewater-mutations-over-time.tsx +8 -4
- package/src/web-components/input/gs-lineage-filter.stories.ts +1 -1
- package/src/web-components/input/gs-text-filter.stories.ts +1 -1
- package/standalone-bundle/dashboard-components.js +4452 -4361
- package/standalone-bundle/dashboard-components.js.map +1 -1
|
@@ -9,7 +9,8 @@ import { type Deletion, type Substitution } from '../../utils/mutations';
|
|
|
9
9
|
import { type Temporal } from '../../utils/temporalClass';
|
|
10
10
|
import { AnnotatedMutation } from '../components/annotated-mutation';
|
|
11
11
|
import { type ColorScale, getColorWithinScale, getTextColorForScale } from '../components/color-scale-selector';
|
|
12
|
-
import
|
|
12
|
+
import PortalTooltip from '../components/portal-tooltip';
|
|
13
|
+
import { type TooltipPosition } from '../components/tooltip';
|
|
13
14
|
import { formatProportion } from '../shared/table/formatProportion';
|
|
14
15
|
import { type PageSizes, Pagination } from '../shared/tanstackTable/pagination';
|
|
15
16
|
import { usePageSizeContext } from '../shared/tanstackTable/pagination-context';
|
|
@@ -28,6 +29,7 @@ export interface MutationsOverTimeGridProps {
|
|
|
28
29
|
colorScale: ColorScale;
|
|
29
30
|
sequenceType: SequenceType;
|
|
30
31
|
pageSizes: PageSizes;
|
|
32
|
+
tooltipPortalTarget: HTMLElement | null;
|
|
31
33
|
}
|
|
32
34
|
|
|
33
35
|
type RowType = { mutation: Substitution | Deletion; values: (MutationOverTimeMutationValue | undefined)[] };
|
|
@@ -37,6 +39,7 @@ const MutationsOverTimeGrid: FunctionComponent<MutationsOverTimeGridProps> = ({
|
|
|
37
39
|
colorScale,
|
|
38
40
|
sequenceType,
|
|
39
41
|
pageSizes,
|
|
42
|
+
tooltipPortalTarget,
|
|
40
43
|
}) => {
|
|
41
44
|
const tableData = useMemo(() => {
|
|
42
45
|
const allMutations = data.getFirstAxisKeys();
|
|
@@ -91,6 +94,7 @@ const MutationsOverTimeGrid: FunctionComponent<MutationsOverTimeGridProps> = ({
|
|
|
91
94
|
numberOfColumns,
|
|
92
95
|
)}
|
|
93
96
|
colorScale={colorScale}
|
|
97
|
+
tooltipPortalTarget={tooltipPortalTarget}
|
|
94
98
|
/>
|
|
95
99
|
</div>
|
|
96
100
|
);
|
|
@@ -99,7 +103,7 @@ const MutationsOverTimeGrid: FunctionComponent<MutationsOverTimeGridProps> = ({
|
|
|
99
103
|
});
|
|
100
104
|
|
|
101
105
|
return [mutationHeader, ...dateHeaders];
|
|
102
|
-
}, [colorScale, data, sequenceType]);
|
|
106
|
+
}, [colorScale, data, sequenceType, tooltipPortalTarget]);
|
|
103
107
|
|
|
104
108
|
const { pageSize } = usePageSizeContext();
|
|
105
109
|
const table = usePreactTable({
|
|
@@ -165,10 +169,10 @@ function styleGridHeader(columnIndex: number, numDateColumns: number) {
|
|
|
165
169
|
return { className: 'invisible @[6rem]:visible' };
|
|
166
170
|
}
|
|
167
171
|
|
|
168
|
-
function getTooltipPosition(rowIndex: number, rows: number, columnIndex: number, columns: number) {
|
|
172
|
+
function getTooltipPosition(rowIndex: number, rows: number, columnIndex: number, columns: number): TooltipPosition {
|
|
169
173
|
const tooltipX = rowIndex < rows / 2 || rowIndex < 6 ? 'bottom' : 'top';
|
|
170
174
|
const tooltipY = columnIndex < columns / 2 ? 'start' : 'end';
|
|
171
|
-
return `${tooltipX}-${tooltipY}
|
|
175
|
+
return `${tooltipX}-${tooltipY}`;
|
|
172
176
|
}
|
|
173
177
|
|
|
174
178
|
const ProportionCell: FunctionComponent<{
|
|
@@ -177,14 +181,16 @@ const ProportionCell: FunctionComponent<{
|
|
|
177
181
|
mutation: Substitution | Deletion;
|
|
178
182
|
tooltipPosition: TooltipPosition;
|
|
179
183
|
colorScale: ColorScale;
|
|
180
|
-
|
|
184
|
+
tooltipPortalTarget: HTMLElement | null;
|
|
185
|
+
}> = ({ value, mutation, date, tooltipPosition, colorScale, tooltipPortalTarget }) => {
|
|
181
186
|
const proportion = value?.type === 'belowThreshold' ? undefined : value?.proportion;
|
|
182
187
|
|
|
183
188
|
return (
|
|
184
189
|
<div className={'py-1 w-full h-full'}>
|
|
185
|
-
<
|
|
190
|
+
<PortalTooltip
|
|
186
191
|
content={<MutationsOverTimeGridTooltip mutation={mutation} date={date} value={value} />}
|
|
187
192
|
position={tooltipPosition}
|
|
193
|
+
portalTarget={tooltipPortalTarget}
|
|
188
194
|
>
|
|
189
195
|
<div
|
|
190
196
|
style={{
|
|
@@ -201,7 +207,7 @@ const ProportionCell: FunctionComponent<{
|
|
|
201
207
|
</span>
|
|
202
208
|
)}
|
|
203
209
|
</div>
|
|
204
|
-
</
|
|
210
|
+
</PortalTooltip>
|
|
205
211
|
</div>
|
|
206
212
|
);
|
|
207
213
|
};
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { type FunctionComponent } from 'preact';
|
|
2
|
-
import { type Dispatch, type StateUpdater, useMemo, useState, useEffect } from 'preact/hooks';
|
|
2
|
+
import { type Dispatch, type StateUpdater, useMemo, useState, useEffect, useLayoutEffect, useRef } from 'preact/hooks';
|
|
3
3
|
import z from 'zod';
|
|
4
4
|
|
|
5
5
|
// @ts-expect-error -- uses subpath imports and vite worker import
|
|
@@ -142,6 +142,12 @@ const MutationsOverTimeTabs: FunctionComponent<MutationOverTimeTabsProps> = ({
|
|
|
142
142
|
overallMutationData,
|
|
143
143
|
}) => {
|
|
144
144
|
const tabsRef = useDispatchFinishedLoadingEvent();
|
|
145
|
+
const tooltipPortalTargetRef = useRef<HTMLDivElement>(null);
|
|
146
|
+
const [tooltipPortalTarget, setTooltipPortalTarget] = useState<HTMLDivElement | null>(null);
|
|
147
|
+
|
|
148
|
+
useLayoutEffect(() => {
|
|
149
|
+
setTooltipPortalTarget(tooltipPortalTargetRef.current);
|
|
150
|
+
}, []);
|
|
145
151
|
|
|
146
152
|
const [mutationFilterValue, setMutationFilterValue] = useState<MutationFilter>({
|
|
147
153
|
textFilter: '',
|
|
@@ -198,6 +204,7 @@ const MutationsOverTimeTabs: FunctionComponent<MutationOverTimeTabsProps> = ({
|
|
|
198
204
|
colorScale={colorScale}
|
|
199
205
|
sequenceType={originalComponentProps.sequenceType}
|
|
200
206
|
pageSizes={originalComponentProps.pageSizes}
|
|
207
|
+
tooltipPortalTarget={tooltipPortalTarget}
|
|
201
208
|
/>
|
|
202
209
|
),
|
|
203
210
|
};
|
|
@@ -227,9 +234,11 @@ const MutationsOverTimeTabs: FunctionComponent<MutationOverTimeTabsProps> = ({
|
|
|
227
234
|
);
|
|
228
235
|
|
|
229
236
|
return (
|
|
230
|
-
<
|
|
231
|
-
<
|
|
232
|
-
|
|
237
|
+
<div ref={tooltipPortalTargetRef}>
|
|
238
|
+
<PageSizeContextProvider pageSizes={originalComponentProps.pageSizes}>
|
|
239
|
+
<Tabs ref={tabsRef} tabs={tabs} toolbar={toolbar} />
|
|
240
|
+
</PageSizeContextProvider>
|
|
241
|
+
</div>
|
|
233
242
|
);
|
|
234
243
|
};
|
|
235
244
|
|
|
@@ -100,7 +100,9 @@ const TextSelector = ({
|
|
|
100
100
|
return (
|
|
101
101
|
<p>
|
|
102
102
|
<span>{item.value}</span>
|
|
103
|
-
{!hideCounts &&
|
|
103
|
+
{!hideCounts && (
|
|
104
|
+
<span className='ml-2 text-gray-500'>({item.count.toLocaleString('en-US')})</span>
|
|
105
|
+
)}
|
|
104
106
|
</p>
|
|
105
107
|
);
|
|
106
108
|
}}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { type FunctionComponent } from 'preact';
|
|
2
|
-
import { type Dispatch, type StateUpdater, useMemo, useState } from 'preact/hooks';
|
|
2
|
+
import { type Dispatch, type StateUpdater, useMemo, useState, useRef } from 'preact/hooks';
|
|
3
3
|
import z from 'zod';
|
|
4
4
|
|
|
5
5
|
import { computeWastewaterMutationsOverTimeDataPerLocation } from './computeWastewaterMutationsOverTimeDataPerLocation';
|
|
@@ -150,6 +150,7 @@ const MutationsOverTimeTabs: FunctionComponent<MutationOverTimeTabsProps> = ({
|
|
|
150
150
|
originalComponentProps,
|
|
151
151
|
}) => {
|
|
152
152
|
const tabsRef = useDispatchFinishedLoadingEvent();
|
|
153
|
+
const tooltipPortalTargetRef = useRef<HTMLDivElement>(null);
|
|
153
154
|
|
|
154
155
|
const [mutationFilterValue, setMutationFilterValue] = useState<MutationFilter>({
|
|
155
156
|
textFilter: '',
|
|
@@ -176,6 +177,7 @@ const MutationsOverTimeTabs: FunctionComponent<MutationOverTimeTabsProps> = ({
|
|
|
176
177
|
colorScale={colorScale}
|
|
177
178
|
pageSizes={originalComponentProps.pageSizes}
|
|
178
179
|
sequenceType={originalComponentProps.sequenceType}
|
|
180
|
+
tooltipPortalTarget={tooltipPortalTargetRef.current}
|
|
179
181
|
/>
|
|
180
182
|
),
|
|
181
183
|
})),
|
|
@@ -204,9 +206,11 @@ const MutationsOverTimeTabs: FunctionComponent<MutationOverTimeTabsProps> = ({
|
|
|
204
206
|
);
|
|
205
207
|
|
|
206
208
|
return (
|
|
207
|
-
<
|
|
208
|
-
<
|
|
209
|
-
|
|
209
|
+
<div ref={tooltipPortalTargetRef}>
|
|
210
|
+
<PageSizeContextProvider pageSizes={originalComponentProps.pageSizes}>
|
|
211
|
+
<Tabs ref={tabsRef} tabs={tabs} toolbar={toolbar} />
|
|
212
|
+
</PageSizeContextProvider>
|
|
213
|
+
</div>
|
|
210
214
|
);
|
|
211
215
|
};
|
|
212
216
|
|
|
@@ -229,7 +229,7 @@ export const FiresEvent: StoryObj<Required<LineageFilterProps>> = {
|
|
|
229
229
|
|
|
230
230
|
await step('Enter a valid lineage value', async () => {
|
|
231
231
|
await userEvent.type(inputField(), 'B.1.1.7*');
|
|
232
|
-
await userEvent.click(canvas.getByRole('option', { name: 'B.1.1.7*(
|
|
232
|
+
await userEvent.click(canvas.getByRole('option', { name: 'B.1.1.7*(677,146)' }));
|
|
233
233
|
|
|
234
234
|
await waitFor(() => {
|
|
235
235
|
return expect(listenerMock.mock.calls.at(-1)![0].detail).toStrictEqual({
|
|
@@ -162,7 +162,7 @@ export const FiresEvents: StoryObj<Required<TextFilterProps>> = {
|
|
|
162
162
|
await step('Remove initial value', async () => {
|
|
163
163
|
await userEvent.click(canvas.getByRole('button', { name: 'clear selection' }));
|
|
164
164
|
|
|
165
|
-
await expect(listenerMock).
|
|
165
|
+
await expect(listenerMock).toHaveBeenCalledWith(
|
|
166
166
|
expect.objectContaining({
|
|
167
167
|
detail: {
|
|
168
168
|
host: undefined,
|