@genspectrum/dashboard-components 0.4.3 → 0.4.5
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 +145 -12
- package/dist/dashboard-components.js +232 -149
- package/dist/dashboard-components.js.map +1 -1
- package/dist/genspectrum-components.d.ts +33 -0
- package/package.json +1 -1
- package/src/preact/aggregatedData/aggregate-table.tsx +3 -2
- package/src/preact/aggregatedData/aggregate.stories.tsx +6 -0
- package/src/preact/aggregatedData/aggregate.tsx +28 -6
- package/src/preact/components/table.stories.tsx +51 -1
- package/src/preact/components/table.tsx +4 -3
- package/src/preact/locationFilter/location-filter.stories.tsx +12 -1
- package/src/preact/locationFilter/location-filter.tsx +10 -3
- package/src/preact/mutationComparison/mutation-comparison-table.tsx +7 -2
- package/src/preact/mutationComparison/mutation-comparison.stories.tsx +3 -0
- package/src/preact/mutationComparison/mutation-comparison.tsx +25 -3
- package/src/preact/mutations/mutations-grid.tsx +8 -2
- package/src/preact/mutations/mutations-insertions-table.tsx +3 -2
- package/src/preact/mutations/mutations-table.tsx +3 -2
- package/src/preact/mutations/mutations.stories.tsx +3 -0
- package/src/preact/mutations/mutations.tsx +16 -6
- package/src/preact/prevalenceOverTime/prevalence-over-time-table.tsx +3 -2
- package/src/preact/prevalenceOverTime/prevalence-over-time.stories.tsx +4 -0
- package/src/preact/prevalenceOverTime/prevalence-over-time.tsx +8 -1
- package/src/query/queryAggregateData.spec.ts +117 -3
- package/src/query/queryAggregateData.ts +31 -2
- package/src/web-components/input/gs-location-filter.stories.ts +11 -0
- package/src/web-components/input/gs-location-filter.tsx +14 -1
- package/src/web-components/visualization/gs-aggregate.stories.ts +15 -0
- package/src/web-components/visualization/gs-aggregate.tsx +23 -0
- package/src/web-components/visualization/gs-mutation-comparison.stories.ts +4 -0
- package/src/web-components/visualization/gs-mutation-comparison.tsx +8 -0
- package/src/web-components/visualization/gs-mutations.stories.ts +4 -0
- package/src/web-components/visualization/gs-mutations.tsx +8 -0
- package/src/web-components/visualization/gs-prevalence-over-time.stories.ts +5 -0
- package/src/web-components/visualization/gs-prevalence-over-time.tsx +12 -4
|
@@ -57,6 +57,20 @@ export declare class AggregateComponent extends PreactLitAdapterWithGridJsStyles
|
|
|
57
57
|
* The headline of the component. Set to an empty string to hide the headline.
|
|
58
58
|
*/
|
|
59
59
|
headline: string;
|
|
60
|
+
/**
|
|
61
|
+
* The field by which the table is initially sorted.
|
|
62
|
+
* Must be one of the fields specified in the fields property, 'count', or 'proportion'.
|
|
63
|
+
*/
|
|
64
|
+
initialSortField: string;
|
|
65
|
+
/**
|
|
66
|
+
* The initial sort direction of the table.
|
|
67
|
+
*/
|
|
68
|
+
initialSortDirection: 'ascending' | 'descending';
|
|
69
|
+
/**
|
|
70
|
+
* The maximum number of rows to display in the table view.
|
|
71
|
+
* Set to `false` to disable pagination. Set to `true` to enable pagination with a default limit (10).
|
|
72
|
+
*/
|
|
73
|
+
pageSize: boolean | number;
|
|
60
74
|
render(): JSX_2.Element;
|
|
61
75
|
}
|
|
62
76
|
|
|
@@ -219,6 +233,10 @@ export declare class LocationFilterComponent extends PreactLitAdapter {
|
|
|
219
233
|
* Visit https://genspectrum.github.io/dashboards/?path=/docs/components-size-of-components--docs for more information.
|
|
220
234
|
*/
|
|
221
235
|
width: string;
|
|
236
|
+
/**
|
|
237
|
+
* The placeholder text to display in the input field, if it is empty.
|
|
238
|
+
*/
|
|
239
|
+
placeholderText: string;
|
|
222
240
|
render(): JSX_2.Element;
|
|
223
241
|
}
|
|
224
242
|
|
|
@@ -287,6 +305,11 @@ export declare class MutationComparisonComponent extends PreactLitAdapterWithGri
|
|
|
287
305
|
* The headline of the component. Set to an empty string to hide the headline.
|
|
288
306
|
*/
|
|
289
307
|
headline: string;
|
|
308
|
+
/**
|
|
309
|
+
* The maximum number of rows to display in the table view.
|
|
310
|
+
* Set to `false` to disable pagination. Set to `true` to enable pagination with a default limit (10).
|
|
311
|
+
*/
|
|
312
|
+
pageSize: boolean | number;
|
|
290
313
|
render(): JSX_2.Element;
|
|
291
314
|
}
|
|
292
315
|
|
|
@@ -424,6 +447,11 @@ export declare class MutationsComponent extends PreactLitAdapterWithGridJsStyles
|
|
|
424
447
|
* The headline of the component. Set to an empty string to hide the headline.
|
|
425
448
|
*/
|
|
426
449
|
headline: string;
|
|
450
|
+
/**
|
|
451
|
+
* The maximum number of rows to display in the table view.
|
|
452
|
+
* Set to `false` to disable pagination. Set to `true` to enable pagination with a default limit (10).
|
|
453
|
+
*/
|
|
454
|
+
pageSize: boolean | number;
|
|
427
455
|
render(): JSX_2.Element;
|
|
428
456
|
}
|
|
429
457
|
|
|
@@ -546,6 +574,11 @@ export declare class PrevalenceOverTimeComponent extends PreactLitAdapterWithGri
|
|
|
546
574
|
* Must be a field of type `date` in LAPIS.
|
|
547
575
|
*/
|
|
548
576
|
lapisDateField: string;
|
|
577
|
+
/**
|
|
578
|
+
* The maximum number of rows to display in the table view.
|
|
579
|
+
* Set to `false` to disable pagination. Set to `true` to enable pagination with a default limit (10).
|
|
580
|
+
*/
|
|
581
|
+
pageSize: boolean | number;
|
|
549
582
|
render(): JSX_2.Element;
|
|
550
583
|
}
|
|
551
584
|
|
package/package.json
CHANGED
|
@@ -7,9 +7,10 @@ import { formatProportion } from '../shared/table/formatProportion';
|
|
|
7
7
|
type AggregateTableProps = {
|
|
8
8
|
fields: string[];
|
|
9
9
|
data: AggregateData;
|
|
10
|
+
pageSize: boolean | number;
|
|
10
11
|
};
|
|
11
12
|
|
|
12
|
-
export const AggregateTable: FunctionComponent<AggregateTableProps> = ({ data, fields }) => {
|
|
13
|
+
export const AggregateTable: FunctionComponent<AggregateTableProps> = ({ data, fields, pageSize }) => {
|
|
13
14
|
const headers = [
|
|
14
15
|
...fields.map((field) => {
|
|
15
16
|
return {
|
|
@@ -28,5 +29,5 @@ export const AggregateTable: FunctionComponent<AggregateTableProps> = ({ data, f
|
|
|
28
29
|
},
|
|
29
30
|
];
|
|
30
31
|
|
|
31
|
-
return <Table data={data} columns={headers}
|
|
32
|
+
return <Table data={data} columns={headers} pageSize={pageSize} />;
|
|
32
33
|
};
|
|
@@ -13,6 +13,9 @@ const meta: Meta<AggregateProps> = {
|
|
|
13
13
|
width: { control: 'text' },
|
|
14
14
|
height: { control: 'text' },
|
|
15
15
|
headline: { control: 'text' },
|
|
16
|
+
initialSortField: { control: 'text' },
|
|
17
|
+
initialSortDirection: { control: 'radio', options: ['ascending', 'descending'] },
|
|
18
|
+
pageSize: { control: 'object' },
|
|
16
19
|
},
|
|
17
20
|
parameters: {
|
|
18
21
|
fetchMock: {
|
|
@@ -53,5 +56,8 @@ export const Default: StoryObj<AggregateProps> = {
|
|
|
53
56
|
width: '100%',
|
|
54
57
|
height: '700px',
|
|
55
58
|
headline: 'Aggregate',
|
|
59
|
+
initialSortField: 'count',
|
|
60
|
+
initialSortDirection: 'descending',
|
|
61
|
+
pageSize: 10,
|
|
56
62
|
},
|
|
57
63
|
};
|
|
@@ -17,6 +17,7 @@ import Tabs from '../components/tabs';
|
|
|
17
17
|
import { useQuery } from '../useQuery';
|
|
18
18
|
|
|
19
19
|
export type View = 'table';
|
|
20
|
+
export type InitialSort = { field: string; direction: 'ascending' | 'descending' };
|
|
20
21
|
|
|
21
22
|
export type AggregateProps = {
|
|
22
23
|
width: string;
|
|
@@ -28,6 +29,9 @@ export interface AggregateInnerProps {
|
|
|
28
29
|
filter: LapisFilter;
|
|
29
30
|
fields: string[];
|
|
30
31
|
views: View[];
|
|
32
|
+
initialSortField: string;
|
|
33
|
+
initialSortDirection: 'ascending' | 'descending';
|
|
34
|
+
pageSize: boolean | number;
|
|
31
35
|
}
|
|
32
36
|
|
|
33
37
|
export const Aggregate: FunctionComponent<AggregateProps> = ({
|
|
@@ -37,6 +41,9 @@ export const Aggregate: FunctionComponent<AggregateProps> = ({
|
|
|
37
41
|
headline = 'Mutations',
|
|
38
42
|
filter,
|
|
39
43
|
fields,
|
|
44
|
+
pageSize,
|
|
45
|
+
initialSortField,
|
|
46
|
+
initialSortDirection,
|
|
40
47
|
}) => {
|
|
41
48
|
const size = { height, width };
|
|
42
49
|
|
|
@@ -44,18 +51,32 @@ export const Aggregate: FunctionComponent<AggregateProps> = ({
|
|
|
44
51
|
<ErrorBoundary size={size} headline={headline}>
|
|
45
52
|
<ResizeContainer size={size}>
|
|
46
53
|
<Headline heading={headline}>
|
|
47
|
-
<AggregateInner
|
|
54
|
+
<AggregateInner
|
|
55
|
+
fields={fields}
|
|
56
|
+
filter={filter}
|
|
57
|
+
views={views}
|
|
58
|
+
initialSortField={initialSortField}
|
|
59
|
+
initialSortDirection={initialSortDirection}
|
|
60
|
+
pageSize={pageSize}
|
|
61
|
+
/>
|
|
48
62
|
</Headline>
|
|
49
63
|
</ResizeContainer>
|
|
50
64
|
</ErrorBoundary>
|
|
51
65
|
);
|
|
52
66
|
};
|
|
53
67
|
|
|
54
|
-
export const AggregateInner: FunctionComponent<AggregateInnerProps> = ({
|
|
68
|
+
export const AggregateInner: FunctionComponent<AggregateInnerProps> = ({
|
|
69
|
+
fields,
|
|
70
|
+
views,
|
|
71
|
+
filter,
|
|
72
|
+
initialSortField,
|
|
73
|
+
initialSortDirection,
|
|
74
|
+
pageSize,
|
|
75
|
+
}) => {
|
|
55
76
|
const lapis = useContext(LapisUrlContext);
|
|
56
77
|
|
|
57
78
|
const { data, error, isLoading } = useQuery(async () => {
|
|
58
|
-
return queryAggregateData(filter, fields, lapis);
|
|
79
|
+
return queryAggregateData(filter, fields, lapis, { field: initialSortField, direction: initialSortDirection });
|
|
59
80
|
}, [filter, fields, lapis]);
|
|
60
81
|
|
|
61
82
|
if (isLoading) {
|
|
@@ -70,22 +91,23 @@ export const AggregateInner: FunctionComponent<AggregateInnerProps> = ({ fields,
|
|
|
70
91
|
return <NoDataDisplay />;
|
|
71
92
|
}
|
|
72
93
|
|
|
73
|
-
return <AggregatedDataTabs data={data} views={views} fields={fields} />;
|
|
94
|
+
return <AggregatedDataTabs data={data} views={views} fields={fields} pageSize={pageSize} />;
|
|
74
95
|
};
|
|
75
96
|
|
|
76
97
|
type AggregatedDataTabsProps = {
|
|
77
98
|
data: AggregateData;
|
|
78
99
|
fields: string[];
|
|
79
100
|
views: View[];
|
|
101
|
+
pageSize: boolean | number;
|
|
80
102
|
};
|
|
81
103
|
|
|
82
|
-
const AggregatedDataTabs: FunctionComponent<AggregatedDataTabsProps> = ({ data, views, fields }) => {
|
|
104
|
+
const AggregatedDataTabs: FunctionComponent<AggregatedDataTabsProps> = ({ data, views, fields, pageSize }) => {
|
|
83
105
|
const getTab = (view: View) => {
|
|
84
106
|
switch (view) {
|
|
85
107
|
case 'table':
|
|
86
108
|
return {
|
|
87
109
|
title: 'Table',
|
|
88
|
-
content: <AggregateTable data={data} fields={fields} />,
|
|
110
|
+
content: <AggregateTable data={data} fields={fields} pageSize={pageSize} />,
|
|
89
111
|
};
|
|
90
112
|
}
|
|
91
113
|
};
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { type Meta, type StoryObj } from '@storybook/preact';
|
|
2
|
+
import { expect, userEvent, waitFor, within } from '@storybook/test';
|
|
2
3
|
|
|
3
4
|
import { Table } from './table';
|
|
4
5
|
|
|
@@ -6,13 +7,51 @@ const meta: Meta = {
|
|
|
6
7
|
title: 'Component/Table',
|
|
7
8
|
component: Table,
|
|
8
9
|
parameters: { fetchMock: {} },
|
|
10
|
+
argTypes: {
|
|
11
|
+
data: { control: 'object' },
|
|
12
|
+
columns: { control: 'object' },
|
|
13
|
+
pageSize: { control: 'object' },
|
|
14
|
+
},
|
|
9
15
|
};
|
|
10
16
|
|
|
11
17
|
export default meta;
|
|
12
18
|
|
|
13
19
|
export const TableStory: StoryObj = {
|
|
14
20
|
render: (args) => {
|
|
15
|
-
return <Table data={args.data} columns={args.columns}
|
|
21
|
+
return <Table data={args.data} columns={args.columns} pageSize={args.pageSize} />;
|
|
22
|
+
},
|
|
23
|
+
args: {
|
|
24
|
+
data: [
|
|
25
|
+
['John Do', 'john@example.com', '123-456-7890'],
|
|
26
|
+
['Jane Doe', 'jane@example.com', '098-765-4321'],
|
|
27
|
+
],
|
|
28
|
+
columns: [{ name: 'Name' }, { name: 'Email', sort: true }, { name: 'Phone Number' }],
|
|
29
|
+
pageSize: 1,
|
|
30
|
+
},
|
|
31
|
+
play: async ({ canvasElement, step }) => {
|
|
32
|
+
const canvas = within(canvasElement);
|
|
33
|
+
|
|
34
|
+
const firstRow = () => canvas.queryByText('John Do', { exact: true });
|
|
35
|
+
const secondRow = () => canvas.queryByText('Jane Doe', { exact: true });
|
|
36
|
+
|
|
37
|
+
await step('Expect first row to be visible and not second row', async () => {
|
|
38
|
+
await waitFor(() => expect(firstRow()).toBeVisible());
|
|
39
|
+
await expect(secondRow()).toBeNull();
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
await step('Expect second row to be visible and not first row after clicking next', async () => {
|
|
43
|
+
const nextButton = canvas.getByRole('button', { name: 'Next' });
|
|
44
|
+
await userEvent.click(nextButton);
|
|
45
|
+
|
|
46
|
+
await waitFor(() => expect(secondRow()).toBeVisible());
|
|
47
|
+
await expect(firstRow()).toBeNull();
|
|
48
|
+
});
|
|
49
|
+
},
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
export const TableStoryNoPagination: StoryObj = {
|
|
53
|
+
render: (args) => {
|
|
54
|
+
return <Table data={args.data} columns={args.columns} pageSize={args.pageSize} />;
|
|
16
55
|
},
|
|
17
56
|
args: {
|
|
18
57
|
data: [
|
|
@@ -20,5 +59,16 @@ export const TableStory: StoryObj = {
|
|
|
20
59
|
['Jane Doe', 'jane@example.com', '098-765-4321'],
|
|
21
60
|
],
|
|
22
61
|
columns: [{ name: 'Name' }, { name: 'Email', sort: true }, { name: 'Phone Number' }],
|
|
62
|
+
pageSize: false,
|
|
63
|
+
},
|
|
64
|
+
play: async ({ canvasElement }) => {
|
|
65
|
+
const canvas = within(canvasElement);
|
|
66
|
+
|
|
67
|
+
const firstRow = () => canvas.queryByText('John Do', { exact: true });
|
|
68
|
+
const secondRow = () => canvas.queryByText('Jane Doe', { exact: true });
|
|
69
|
+
|
|
70
|
+
await waitFor(() => expect(firstRow()).toBeVisible());
|
|
71
|
+
await expect(secondRow()).toBeVisible();
|
|
72
|
+
await waitFor(() => expect(canvas.queryByText('Next')).toBeNull());
|
|
23
73
|
},
|
|
24
74
|
};
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { Grid } from 'gridjs';
|
|
2
2
|
import { type OneDArray, type TColumn, type TData } from 'gridjs/dist/src/types';
|
|
3
|
-
import { type PaginationConfig } from 'gridjs/dist/src/view/plugin/pagination';
|
|
4
3
|
import { type ComponentChild } from 'preact';
|
|
5
4
|
import { useEffect, useRef } from 'preact/hooks';
|
|
6
5
|
|
|
@@ -26,10 +25,12 @@ export const tableStyle = {
|
|
|
26
25
|
interface TableProps {
|
|
27
26
|
data: TData;
|
|
28
27
|
columns: OneDArray<TColumn | string | ComponentChild>;
|
|
29
|
-
|
|
28
|
+
pageSize: number | boolean;
|
|
30
29
|
}
|
|
31
30
|
|
|
32
|
-
export const Table = ({ data, columns,
|
|
31
|
+
export const Table = ({ data, columns, pageSize }: TableProps) => {
|
|
32
|
+
const pagination = typeof pageSize === 'number' ? { limit: pageSize } : pageSize;
|
|
33
|
+
|
|
33
34
|
const wrapper = useRef(null);
|
|
34
35
|
|
|
35
36
|
useEffect(() => {
|
|
@@ -35,6 +35,7 @@ const meta: Meta<LocationFilterProps> = {
|
|
|
35
35
|
width: '100%',
|
|
36
36
|
fields: ['region', 'country', 'division', 'location'],
|
|
37
37
|
initialValue: 'Europe',
|
|
38
|
+
placeholderText: 'Enter a location',
|
|
38
39
|
},
|
|
39
40
|
argTypes: {
|
|
40
41
|
fields: {
|
|
@@ -52,6 +53,11 @@ const meta: Meta<LocationFilterProps> = {
|
|
|
52
53
|
type: 'text',
|
|
53
54
|
},
|
|
54
55
|
},
|
|
56
|
+
placeholderText: {
|
|
57
|
+
control: {
|
|
58
|
+
type: 'text',
|
|
59
|
+
},
|
|
60
|
+
},
|
|
55
61
|
},
|
|
56
62
|
decorators: [withActions],
|
|
57
63
|
};
|
|
@@ -61,7 +67,12 @@ export default meta;
|
|
|
61
67
|
export const Primary: StoryObj<LocationFilterProps> = {
|
|
62
68
|
render: (args) => (
|
|
63
69
|
<LapisUrlContext.Provider value={LAPIS_URL}>
|
|
64
|
-
<LocationFilter
|
|
70
|
+
<LocationFilter
|
|
71
|
+
fields={args.fields}
|
|
72
|
+
initialValue={args.initialValue}
|
|
73
|
+
width={args.width}
|
|
74
|
+
placeholderText={args.placeholderText}
|
|
75
|
+
/>
|
|
65
76
|
</LapisUrlContext.Provider>
|
|
66
77
|
),
|
|
67
78
|
};
|
|
@@ -12,6 +12,7 @@ import { useQuery } from '../useQuery';
|
|
|
12
12
|
|
|
13
13
|
export interface LocationFilterInnerProps {
|
|
14
14
|
initialValue?: string;
|
|
15
|
+
placeholderText?: string;
|
|
15
16
|
fields: string[];
|
|
16
17
|
}
|
|
17
18
|
|
|
@@ -19,19 +20,24 @@ export interface LocationFilterProps extends LocationFilterInnerProps {
|
|
|
19
20
|
width: string;
|
|
20
21
|
}
|
|
21
22
|
|
|
22
|
-
export const LocationFilter: FunctionComponent<LocationFilterProps> = ({
|
|
23
|
+
export const LocationFilter: FunctionComponent<LocationFilterProps> = ({
|
|
24
|
+
width,
|
|
25
|
+
initialValue,
|
|
26
|
+
fields,
|
|
27
|
+
placeholderText,
|
|
28
|
+
}) => {
|
|
23
29
|
const size = { width, height: '3rem' };
|
|
24
30
|
|
|
25
31
|
return (
|
|
26
32
|
<ErrorBoundary size={size}>
|
|
27
33
|
<ResizeContainer size={size}>
|
|
28
|
-
<LocationFilterInner initialValue={initialValue} fields={fields} />
|
|
34
|
+
<LocationFilterInner initialValue={initialValue} fields={fields} placeholderText={placeholderText} />
|
|
29
35
|
</ResizeContainer>
|
|
30
36
|
</ErrorBoundary>
|
|
31
37
|
);
|
|
32
38
|
};
|
|
33
39
|
|
|
34
|
-
export const LocationFilterInner = ({ initialValue, fields }: LocationFilterInnerProps) => {
|
|
40
|
+
export const LocationFilterInner = ({ initialValue, fields, placeholderText }: LocationFilterInnerProps) => {
|
|
35
41
|
const lapis = useContext(LapisUrlContext);
|
|
36
42
|
|
|
37
43
|
const [value, setValue] = useState(initialValue ?? '');
|
|
@@ -77,6 +83,7 @@ export const LocationFilterInner = ({ initialValue, fields }: LocationFilterInne
|
|
|
77
83
|
value={value}
|
|
78
84
|
onInput={onInput}
|
|
79
85
|
list='countries'
|
|
86
|
+
placeholder={placeholderText}
|
|
80
87
|
/>
|
|
81
88
|
<datalist id='countries'>
|
|
82
89
|
{data?.map((v) => {
|
|
@@ -12,9 +12,14 @@ import { formatProportion } from '../shared/table/formatProportion';
|
|
|
12
12
|
export interface MutationsTableProps {
|
|
13
13
|
data: Dataset<MutationData>;
|
|
14
14
|
proportionInterval: ProportionInterval;
|
|
15
|
+
pageSize: boolean | number;
|
|
15
16
|
}
|
|
16
17
|
|
|
17
|
-
export const MutationComparisonTable: FunctionComponent<MutationsTableProps> = ({
|
|
18
|
+
export const MutationComparisonTable: FunctionComponent<MutationsTableProps> = ({
|
|
19
|
+
data,
|
|
20
|
+
proportionInterval,
|
|
21
|
+
pageSize,
|
|
22
|
+
}) => {
|
|
18
23
|
const headers = [
|
|
19
24
|
{
|
|
20
25
|
name: 'Mutation',
|
|
@@ -37,5 +42,5 @@ export const MutationComparisonTable: FunctionComponent<MutationsTableProps> = (
|
|
|
37
42
|
|
|
38
43
|
const tableData = getMutationComparisonTableData(data, proportionInterval).map((row) => Object.values(row));
|
|
39
44
|
|
|
40
|
-
return <Table data={tableData} columns={headers}
|
|
45
|
+
return <Table data={tableData} columns={headers} pageSize={pageSize} />;
|
|
41
46
|
};
|
|
@@ -30,6 +30,7 @@ const meta: Meta<MutationComparisonProps> = {
|
|
|
30
30
|
width: { control: 'text' },
|
|
31
31
|
height: { control: 'text' },
|
|
32
32
|
headline: { control: 'text' },
|
|
33
|
+
pageSize: { control: 'object' },
|
|
33
34
|
},
|
|
34
35
|
parameters: {
|
|
35
36
|
fetchMock: {
|
|
@@ -85,6 +86,7 @@ const Template: StoryObj<MutationComparisonProps> = {
|
|
|
85
86
|
width={args.width}
|
|
86
87
|
height={args.height}
|
|
87
88
|
headline={args.headline}
|
|
89
|
+
pageSize={args.pageSize}
|
|
88
90
|
/>
|
|
89
91
|
</ReferenceGenomeContext.Provider>
|
|
90
92
|
</LapisUrlContext.Provider>
|
|
@@ -114,6 +116,7 @@ export const TwoVariants: StoryObj<MutationComparisonProps> = {
|
|
|
114
116
|
width: '100%',
|
|
115
117
|
height: '700px',
|
|
116
118
|
headline: 'Mutation comparison',
|
|
119
|
+
pageSize: 10,
|
|
117
120
|
},
|
|
118
121
|
};
|
|
119
122
|
|
|
@@ -34,6 +34,7 @@ export interface MutationComparisonInnerProps {
|
|
|
34
34
|
variants: NamedLapisFilter[];
|
|
35
35
|
sequenceType: SequenceType;
|
|
36
36
|
views: View[];
|
|
37
|
+
pageSize: boolean | number;
|
|
37
38
|
}
|
|
38
39
|
|
|
39
40
|
export const MutationComparison: FunctionComponent<MutationComparisonProps> = ({
|
|
@@ -43,6 +44,7 @@ export const MutationComparison: FunctionComponent<MutationComparisonProps> = ({
|
|
|
43
44
|
width,
|
|
44
45
|
height,
|
|
45
46
|
headline = 'Mutation comparison',
|
|
47
|
+
pageSize,
|
|
46
48
|
}) => {
|
|
47
49
|
const size = { height, width };
|
|
48
50
|
|
|
@@ -50,7 +52,12 @@ export const MutationComparison: FunctionComponent<MutationComparisonProps> = ({
|
|
|
50
52
|
<ErrorBoundary size={size} headline={headline}>
|
|
51
53
|
<ResizeContainer size={size}>
|
|
52
54
|
<Headline heading={headline}>
|
|
53
|
-
<MutationComparisonInner
|
|
55
|
+
<MutationComparisonInner
|
|
56
|
+
variants={variants}
|
|
57
|
+
sequenceType={sequenceType}
|
|
58
|
+
views={views}
|
|
59
|
+
pageSize={pageSize}
|
|
60
|
+
/>
|
|
54
61
|
</Headline>
|
|
55
62
|
</ResizeContainer>
|
|
56
63
|
</ErrorBoundary>
|
|
@@ -61,6 +68,7 @@ export const MutationComparisonInner: FunctionComponent<MutationComparisonInnerP
|
|
|
61
68
|
variants,
|
|
62
69
|
sequenceType,
|
|
63
70
|
views,
|
|
71
|
+
pageSize,
|
|
64
72
|
}) => {
|
|
65
73
|
const lapis = useContext(LapisUrlContext);
|
|
66
74
|
|
|
@@ -80,16 +88,29 @@ export const MutationComparisonInner: FunctionComponent<MutationComparisonInnerP
|
|
|
80
88
|
return <NoDataDisplay />;
|
|
81
89
|
}
|
|
82
90
|
|
|
83
|
-
return
|
|
91
|
+
return (
|
|
92
|
+
<MutationComparisonTabs
|
|
93
|
+
data={data.mutationData}
|
|
94
|
+
sequenceType={sequenceType}
|
|
95
|
+
views={views}
|
|
96
|
+
pageSize={pageSize}
|
|
97
|
+
/>
|
|
98
|
+
);
|
|
84
99
|
};
|
|
85
100
|
|
|
86
101
|
type MutationComparisonTabsProps = {
|
|
87
102
|
data: MutationData[];
|
|
88
103
|
views: View[];
|
|
89
104
|
sequenceType: SequenceType;
|
|
105
|
+
pageSize: boolean | number;
|
|
90
106
|
};
|
|
91
107
|
|
|
92
|
-
const MutationComparisonTabs: FunctionComponent<MutationComparisonTabsProps> = ({
|
|
108
|
+
const MutationComparisonTabs: FunctionComponent<MutationComparisonTabsProps> = ({
|
|
109
|
+
data,
|
|
110
|
+
views,
|
|
111
|
+
sequenceType,
|
|
112
|
+
pageSize,
|
|
113
|
+
}) => {
|
|
93
114
|
const [proportionInterval, setProportionInterval] = useState({ min: 0.5, max: 1 });
|
|
94
115
|
const [displayedMutationTypes, setDisplayedMutationTypes] = useState<DisplayedMutationType[]>([
|
|
95
116
|
{ label: 'Substitutions', checked: true, type: 'substitution' },
|
|
@@ -111,6 +132,7 @@ const MutationComparisonTabs: FunctionComponent<MutationComparisonTabsProps> = (
|
|
|
111
132
|
<MutationComparisonTable
|
|
112
133
|
data={{ content: filteredData }}
|
|
113
134
|
proportionInterval={proportionInterval}
|
|
135
|
+
pageSize={pageSize}
|
|
114
136
|
/>
|
|
115
137
|
),
|
|
116
138
|
};
|
|
@@ -13,6 +13,7 @@ interface MutationsGridProps {
|
|
|
13
13
|
data: SubstitutionOrDeletionEntry[];
|
|
14
14
|
sequenceType: SequenceType;
|
|
15
15
|
proportionInterval: ProportionInterval;
|
|
16
|
+
pageSize: boolean | number;
|
|
16
17
|
}
|
|
17
18
|
|
|
18
19
|
export type BaseCell = {
|
|
@@ -20,7 +21,12 @@ export type BaseCell = {
|
|
|
20
21
|
isReference: boolean;
|
|
21
22
|
};
|
|
22
23
|
|
|
23
|
-
export const MutationsGrid: FunctionComponent<MutationsGridProps> = ({
|
|
24
|
+
export const MutationsGrid: FunctionComponent<MutationsGridProps> = ({
|
|
25
|
+
data,
|
|
26
|
+
sequenceType,
|
|
27
|
+
proportionInterval,
|
|
28
|
+
pageSize,
|
|
29
|
+
}) => {
|
|
24
30
|
const getHeaders = () => {
|
|
25
31
|
return [
|
|
26
32
|
{
|
|
@@ -80,5 +86,5 @@ export const MutationsGrid: FunctionComponent<MutationsGridProps> = ({ data, seq
|
|
|
80
86
|
|
|
81
87
|
const tableData = getMutationsGridData(data, sequenceType, proportionInterval).map((row) => Object.values(row));
|
|
82
88
|
|
|
83
|
-
return <Table data={tableData} columns={getHeaders()}
|
|
89
|
+
return <Table data={tableData} columns={getHeaders()} pageSize={pageSize} />;
|
|
84
90
|
};
|
|
@@ -8,9 +8,10 @@ import { sortInsertions } from '../shared/sort/sortInsertions';
|
|
|
8
8
|
|
|
9
9
|
export interface InsertionsTableProps {
|
|
10
10
|
data: InsertionEntry[];
|
|
11
|
+
pageSize: boolean | number;
|
|
11
12
|
}
|
|
12
13
|
|
|
13
|
-
export const InsertionsTable: FunctionComponent<InsertionsTableProps> = ({ data }) => {
|
|
14
|
+
export const InsertionsTable: FunctionComponent<InsertionsTableProps> = ({ data, pageSize }) => {
|
|
14
15
|
const getHeaders = () => {
|
|
15
16
|
return [
|
|
16
17
|
{
|
|
@@ -31,5 +32,5 @@ export const InsertionsTable: FunctionComponent<InsertionsTableProps> = ({ data
|
|
|
31
32
|
|
|
32
33
|
const tableData = getInsertionsTableData(data).map((row) => Object.values(row));
|
|
33
34
|
|
|
34
|
-
return <Table data={tableData} columns={getHeaders()}
|
|
35
|
+
return <Table data={tableData} columns={getHeaders()} pageSize={pageSize} />;
|
|
35
36
|
};
|
|
@@ -11,9 +11,10 @@ import { formatProportion } from '../shared/table/formatProportion';
|
|
|
11
11
|
export interface MutationsTableProps {
|
|
12
12
|
data: SubstitutionOrDeletionEntry[];
|
|
13
13
|
proportionInterval: ProportionInterval;
|
|
14
|
+
pageSize: boolean | number;
|
|
14
15
|
}
|
|
15
16
|
|
|
16
|
-
const MutationsTable: FunctionComponent<MutationsTableProps> = ({ data, proportionInterval }) => {
|
|
17
|
+
const MutationsTable: FunctionComponent<MutationsTableProps> = ({ data, proportionInterval, pageSize }) => {
|
|
17
18
|
const getHeaders = () => {
|
|
18
19
|
return [
|
|
19
20
|
{
|
|
@@ -43,7 +44,7 @@ const MutationsTable: FunctionComponent<MutationsTableProps> = ({ data, proporti
|
|
|
43
44
|
|
|
44
45
|
const tableData = getMutationsTableData(data, proportionInterval).map((row) => Object.values(row));
|
|
45
46
|
|
|
46
|
-
return <Table data={tableData} columns={getHeaders()}
|
|
47
|
+
return <Table data={tableData} columns={getHeaders()} pageSize={pageSize} />;
|
|
47
48
|
};
|
|
48
49
|
|
|
49
50
|
export default MutationsTable;
|
|
@@ -25,6 +25,7 @@ const meta: Meta<MutationsProps> = {
|
|
|
25
25
|
width: { control: 'text' },
|
|
26
26
|
height: { control: 'text' },
|
|
27
27
|
headline: { control: 'text' },
|
|
28
|
+
pageSize: { control: 'object' },
|
|
28
29
|
},
|
|
29
30
|
};
|
|
30
31
|
|
|
@@ -41,6 +42,7 @@ const Template = {
|
|
|
41
42
|
width={args.width}
|
|
42
43
|
height={args.height}
|
|
43
44
|
headline={args.headline}
|
|
45
|
+
pageSize={args.pageSize}
|
|
44
46
|
/>
|
|
45
47
|
</ReferenceGenomeContext.Provider>
|
|
46
48
|
</LapisUrlContext.Provider>
|
|
@@ -56,6 +58,7 @@ export const Default: StoryObj<MutationsProps> = {
|
|
|
56
58
|
width: '100%',
|
|
57
59
|
height: '700px',
|
|
58
60
|
headline: 'Mutations',
|
|
61
|
+
pageSize: 10,
|
|
59
62
|
},
|
|
60
63
|
parameters: {
|
|
61
64
|
fetchMock: {
|