@genspectrum/dashboard-components 1.9.1 → 1.9.2
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/dist/components.d.ts +21 -21
- package/dist/components.js +3 -3
- package/dist/components.js.map +1 -1
- package/dist/util.d.ts +21 -21
- package/package.json +1 -1
- package/src/preact/components/mutations-over-time-mutations-filter.stories.tsx +73 -14
- package/src/preact/components/mutations-over-time-mutations-filter.tsx +30 -28
- package/standalone-bundle/dashboard-components.js +3 -3
- package/standalone-bundle/dashboard-components.js.map +1 -1
package/dist/util.d.ts
CHANGED
|
@@ -939,22 +939,6 @@ declare global {
|
|
|
939
939
|
}
|
|
940
940
|
|
|
941
941
|
|
|
942
|
-
declare global {
|
|
943
|
-
interface HTMLElementTagNameMap {
|
|
944
|
-
'gs-wastewater-mutations-over-time': WastewaterMutationsOverTimeComponent;
|
|
945
|
-
}
|
|
946
|
-
}
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
declare global {
|
|
950
|
-
namespace JSX {
|
|
951
|
-
interface IntrinsicElements {
|
|
952
|
-
'gs-wastewater-mutations-over-time': DetailedHTMLProps<HTMLAttributes<HTMLElement>, HTMLElement>;
|
|
953
|
-
}
|
|
954
|
-
}
|
|
955
|
-
}
|
|
956
|
-
|
|
957
|
-
|
|
958
942
|
declare global {
|
|
959
943
|
interface HTMLElementTagNameMap {
|
|
960
944
|
'gs-genome-data-viewer': GenomeDataViewerComponent;
|
|
@@ -1117,10 +1101,7 @@ declare global {
|
|
|
1117
1101
|
|
|
1118
1102
|
declare global {
|
|
1119
1103
|
interface HTMLElementTagNameMap {
|
|
1120
|
-
'gs-
|
|
1121
|
-
}
|
|
1122
|
-
interface HTMLElementEventMap {
|
|
1123
|
-
[gsEventNames.locationChanged]: LocationChangedEvent;
|
|
1104
|
+
'gs-wastewater-mutations-over-time': WastewaterMutationsOverTimeComponent;
|
|
1124
1105
|
}
|
|
1125
1106
|
}
|
|
1126
1107
|
|
|
@@ -1128,7 +1109,7 @@ declare global {
|
|
|
1128
1109
|
declare global {
|
|
1129
1110
|
namespace JSX {
|
|
1130
1111
|
interface IntrinsicElements {
|
|
1131
|
-
'gs-
|
|
1112
|
+
'gs-wastewater-mutations-over-time': DetailedHTMLProps<HTMLAttributes<HTMLElement>, HTMLElement>;
|
|
1132
1113
|
}
|
|
1133
1114
|
}
|
|
1134
1115
|
}
|
|
@@ -1154,6 +1135,25 @@ declare global {
|
|
|
1154
1135
|
}
|
|
1155
1136
|
|
|
1156
1137
|
|
|
1138
|
+
declare global {
|
|
1139
|
+
interface HTMLElementTagNameMap {
|
|
1140
|
+
'gs-location-filter': LocationFilterComponent;
|
|
1141
|
+
}
|
|
1142
|
+
interface HTMLElementEventMap {
|
|
1143
|
+
[gsEventNames.locationChanged]: LocationChangedEvent;
|
|
1144
|
+
}
|
|
1145
|
+
}
|
|
1146
|
+
|
|
1147
|
+
|
|
1148
|
+
declare global {
|
|
1149
|
+
namespace JSX {
|
|
1150
|
+
interface IntrinsicElements {
|
|
1151
|
+
'gs-location-filter': DetailedHTMLProps<HTMLAttributes<HTMLElement>, HTMLElement>;
|
|
1152
|
+
}
|
|
1153
|
+
}
|
|
1154
|
+
}
|
|
1155
|
+
|
|
1156
|
+
|
|
1157
1157
|
declare global {
|
|
1158
1158
|
interface HTMLElementTagNameMap {
|
|
1159
1159
|
'gs-text-filter': TextFilterComponent;
|
package/package.json
CHANGED
|
@@ -7,6 +7,7 @@ import {
|
|
|
7
7
|
MutationsOverTimeMutationsFilter,
|
|
8
8
|
type MutationsOverTimeMutationsFilterProps,
|
|
9
9
|
} from './mutations-over-time-mutations-filter';
|
|
10
|
+
import { type MutationAnnotations } from '../../web-components/mutation-annotations-context';
|
|
10
11
|
import { MutationAnnotationsContextProvider } from '../MutationAnnotationsContext';
|
|
11
12
|
import { type MutationFilter } from '../mutationsOverTime/getFilteredMutationsOverTimeData';
|
|
12
13
|
|
|
@@ -18,30 +19,38 @@ const meta: Meta = {
|
|
|
18
19
|
|
|
19
20
|
export default meta;
|
|
20
21
|
|
|
22
|
+
const manyMutationAnnotations = Array.from({ length: 300 }, (_, i) => ({
|
|
23
|
+
name: `Annotation ${i + 1}`,
|
|
24
|
+
description: `This is test annotation number ${i + 1} for testing many annotations.`,
|
|
25
|
+
symbol: String.fromCharCode(33 + (i % 94)), // Cycle through printable ASCII characters
|
|
26
|
+
nucleotideMutations: ['A23G'],
|
|
27
|
+
aminoAcidMutations: [],
|
|
28
|
+
})) satisfies MutationAnnotations;
|
|
29
|
+
|
|
21
30
|
const WrapperWithState = ({
|
|
22
31
|
setFilterValue,
|
|
23
32
|
value,
|
|
33
|
+
annotations = [
|
|
34
|
+
{
|
|
35
|
+
name: 'Test Annotation 1',
|
|
36
|
+
description: 'Test Annotation 1',
|
|
37
|
+
symbol: '#',
|
|
38
|
+
},
|
|
39
|
+
{
|
|
40
|
+
name: 'Test Annotation 2',
|
|
41
|
+
description: 'Test Annotation 2',
|
|
42
|
+
symbol: '+',
|
|
43
|
+
},
|
|
44
|
+
],
|
|
24
45
|
}: {
|
|
25
46
|
setFilterValue: Dispatch<StateUpdater<MutationFilter>>;
|
|
26
47
|
value: MutationFilter;
|
|
48
|
+
annotations?: MutationAnnotations;
|
|
27
49
|
}) => {
|
|
28
50
|
const [state, setState] = useState(value);
|
|
29
51
|
|
|
30
52
|
return (
|
|
31
|
-
<MutationAnnotationsContextProvider
|
|
32
|
-
value={[
|
|
33
|
-
{
|
|
34
|
-
name: 'Test Annotation 1',
|
|
35
|
-
description: 'Test Annotation 1',
|
|
36
|
-
symbol: '#',
|
|
37
|
-
},
|
|
38
|
-
{
|
|
39
|
-
name: 'Test Annotation 2',
|
|
40
|
-
description: 'Test Annotation 2',
|
|
41
|
-
symbol: '+',
|
|
42
|
-
},
|
|
43
|
-
]}
|
|
44
|
-
>
|
|
53
|
+
<MutationAnnotationsContextProvider value={annotations}>
|
|
45
54
|
<MutationsOverTimeMutationsFilter
|
|
46
55
|
setFilterValue={(value) => {
|
|
47
56
|
setFilterValue(value);
|
|
@@ -107,3 +116,53 @@ export const FilterByAnnotation: StoryObj<MutationsOverTimeMutationsFilterProps>
|
|
|
107
116
|
});
|
|
108
117
|
},
|
|
109
118
|
};
|
|
119
|
+
|
|
120
|
+
export const WithManyMutationAnnotations: StoryObj<MutationsOverTimeMutationsFilterProps> = {
|
|
121
|
+
render: (args) => {
|
|
122
|
+
return (
|
|
123
|
+
<WrapperWithState
|
|
124
|
+
setFilterValue={args.setFilterValue}
|
|
125
|
+
value={args.value}
|
|
126
|
+
annotations={manyMutationAnnotations}
|
|
127
|
+
/>
|
|
128
|
+
);
|
|
129
|
+
},
|
|
130
|
+
args: {
|
|
131
|
+
setFilterValue: fn(),
|
|
132
|
+
value: { textFilter: '', annotationNameFilter: new Set() },
|
|
133
|
+
},
|
|
134
|
+
play: async ({ canvasElement, step }) => {
|
|
135
|
+
const canvas = within(canvasElement);
|
|
136
|
+
|
|
137
|
+
await step('Open filter dropdown', async () => {
|
|
138
|
+
const filterButton = canvas.getByRole('button', { name: 'Filter mutations' });
|
|
139
|
+
await userEvent.click(filterButton);
|
|
140
|
+
});
|
|
141
|
+
|
|
142
|
+
await step('Verify scroll container is scrollable', () => {
|
|
143
|
+
const scrollContainer = canvas
|
|
144
|
+
.getByText('Filter by annotations')
|
|
145
|
+
.parentElement!.querySelector('.overflow-scroll')!;
|
|
146
|
+
void expect(scrollContainer).toBeInTheDocument();
|
|
147
|
+
|
|
148
|
+
// Verify the container has scrollable content
|
|
149
|
+
void expect(scrollContainer.scrollHeight).toBeGreaterThan(scrollContainer.clientHeight);
|
|
150
|
+
});
|
|
151
|
+
|
|
152
|
+
await step('Scroll to bottom and verify we can scroll', async () => {
|
|
153
|
+
const scrollContainer = canvas
|
|
154
|
+
.getByText('Filter by annotations')
|
|
155
|
+
.parentElement!.querySelector('.overflow-scroll')!;
|
|
156
|
+
|
|
157
|
+
const initialScrollTop = scrollContainer.scrollTop;
|
|
158
|
+
|
|
159
|
+
// Scroll to the bottom
|
|
160
|
+
scrollContainer.scrollTop = scrollContainer.scrollHeight;
|
|
161
|
+
|
|
162
|
+
await waitFor(async () => {
|
|
163
|
+
// Verify that scrollTop actually changed
|
|
164
|
+
await expect(scrollContainer.scrollTop).toBeGreaterThan(initialScrollTop);
|
|
165
|
+
});
|
|
166
|
+
});
|
|
167
|
+
},
|
|
168
|
+
};
|
|
@@ -105,34 +105,36 @@ const AnnotationCheckboxes: FunctionComponent<MutationsOverTimeMutationsFilterPr
|
|
|
105
105
|
<div className='divider mt-0.5 mb-0' />
|
|
106
106
|
<div className='text-sm'>
|
|
107
107
|
<div className='font-bold mb-1'>Filter by annotations</div>
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
<
|
|
111
|
-
<
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
108
|
+
<div className='max-h-72 overflow-scroll'>
|
|
109
|
+
{mutationAnnotations.map((annotation, index) => (
|
|
110
|
+
<li className='flex flex-row items-center' key={annotation.name}>
|
|
111
|
+
<label>
|
|
112
|
+
<input
|
|
113
|
+
className={'mr-2'}
|
|
114
|
+
type='checkbox'
|
|
115
|
+
id={`item-${index}`}
|
|
116
|
+
checked={value.annotationNameFilter.has(annotation.name)}
|
|
117
|
+
onChange={() => {
|
|
118
|
+
setFilterValue((previousFilter) => {
|
|
119
|
+
const newAnnotationFilter = previousFilter.annotationNameFilter.has(
|
|
120
|
+
annotation.name,
|
|
121
|
+
)
|
|
122
|
+
? [...previousFilter.annotationNameFilter].filter(
|
|
123
|
+
(name) => name !== annotation.name,
|
|
124
|
+
)
|
|
125
|
+
: [...previousFilter.annotationNameFilter, annotation.name];
|
|
126
|
+
return {
|
|
127
|
+
...previousFilter,
|
|
128
|
+
annotationNameFilter: new Set(newAnnotationFilter),
|
|
129
|
+
};
|
|
130
|
+
});
|
|
131
|
+
}}
|
|
132
|
+
/>
|
|
133
|
+
{annotation.name} (<span className='text-red-600'>{annotation.symbol}</span>)
|
|
134
|
+
</label>
|
|
135
|
+
</li>
|
|
136
|
+
))}
|
|
137
|
+
</div>
|
|
136
138
|
</div>
|
|
137
139
|
</>
|
|
138
140
|
);
|