@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.
Files changed (35) hide show
  1. package/custom-elements.json +145 -12
  2. package/dist/dashboard-components.js +232 -149
  3. package/dist/dashboard-components.js.map +1 -1
  4. package/dist/genspectrum-components.d.ts +33 -0
  5. package/package.json +1 -1
  6. package/src/preact/aggregatedData/aggregate-table.tsx +3 -2
  7. package/src/preact/aggregatedData/aggregate.stories.tsx +6 -0
  8. package/src/preact/aggregatedData/aggregate.tsx +28 -6
  9. package/src/preact/components/table.stories.tsx +51 -1
  10. package/src/preact/components/table.tsx +4 -3
  11. package/src/preact/locationFilter/location-filter.stories.tsx +12 -1
  12. package/src/preact/locationFilter/location-filter.tsx +10 -3
  13. package/src/preact/mutationComparison/mutation-comparison-table.tsx +7 -2
  14. package/src/preact/mutationComparison/mutation-comparison.stories.tsx +3 -0
  15. package/src/preact/mutationComparison/mutation-comparison.tsx +25 -3
  16. package/src/preact/mutations/mutations-grid.tsx +8 -2
  17. package/src/preact/mutations/mutations-insertions-table.tsx +3 -2
  18. package/src/preact/mutations/mutations-table.tsx +3 -2
  19. package/src/preact/mutations/mutations.stories.tsx +3 -0
  20. package/src/preact/mutations/mutations.tsx +16 -6
  21. package/src/preact/prevalenceOverTime/prevalence-over-time-table.tsx +3 -2
  22. package/src/preact/prevalenceOverTime/prevalence-over-time.stories.tsx +4 -0
  23. package/src/preact/prevalenceOverTime/prevalence-over-time.tsx +8 -1
  24. package/src/query/queryAggregateData.spec.ts +117 -3
  25. package/src/query/queryAggregateData.ts +31 -2
  26. package/src/web-components/input/gs-location-filter.stories.ts +11 -0
  27. package/src/web-components/input/gs-location-filter.tsx +14 -1
  28. package/src/web-components/visualization/gs-aggregate.stories.ts +15 -0
  29. package/src/web-components/visualization/gs-aggregate.tsx +23 -0
  30. package/src/web-components/visualization/gs-mutation-comparison.stories.ts +4 -0
  31. package/src/web-components/visualization/gs-mutation-comparison.tsx +8 -0
  32. package/src/web-components/visualization/gs-mutations.stories.ts +4 -0
  33. package/src/web-components/visualization/gs-mutations.tsx +8 -0
  34. package/src/web-components/visualization/gs-prevalence-over-time.stories.ts +5 -0
  35. package/src/web-components/visualization/gs-prevalence-over-time.tsx +12 -4
@@ -35,6 +35,7 @@ export interface MutationsInnerProps {
35
35
  variant: LapisFilter;
36
36
  sequenceType: SequenceType;
37
37
  views: View[];
38
+ pageSize: boolean | number;
38
39
  }
39
40
 
40
41
  export interface MutationsProps extends MutationsInnerProps {
@@ -50,6 +51,7 @@ export const Mutations: FunctionComponent<MutationsProps> = ({
50
51
  width,
51
52
  height,
52
53
  headline = 'Mutations',
54
+ pageSize,
53
55
  }) => {
54
56
  const size = { height, width };
55
57
 
@@ -57,14 +59,14 @@ export const Mutations: FunctionComponent<MutationsProps> = ({
57
59
  <ErrorBoundary size={size} headline={headline}>
58
60
  <ResizeContainer size={size}>
59
61
  <Headline heading={headline}>
60
- <MutationsInner variant={variant} sequenceType={sequenceType} views={views} />
62
+ <MutationsInner variant={variant} sequenceType={sequenceType} views={views} pageSize={pageSize} />
61
63
  </Headline>
62
64
  </ResizeContainer>
63
65
  </ErrorBoundary>
64
66
  );
65
67
  };
66
68
 
67
- export const MutationsInner: FunctionComponent<MutationsInnerProps> = ({ variant, sequenceType, views }) => {
69
+ export const MutationsInner: FunctionComponent<MutationsInnerProps> = ({ variant, sequenceType, views, pageSize }) => {
68
70
  const lapis = useContext(LapisUrlContext);
69
71
  const { data, error, isLoading } = useQuery(async () => {
70
72
  return queryMutationsData(variant, sequenceType, lapis);
@@ -82,16 +84,17 @@ export const MutationsInner: FunctionComponent<MutationsInnerProps> = ({ variant
82
84
  return <NoDataDisplay />;
83
85
  }
84
86
 
85
- return <MutationsTabs mutationsData={data} sequenceType={sequenceType} views={views} />;
87
+ return <MutationsTabs mutationsData={data} sequenceType={sequenceType} views={views} pageSize={pageSize} />;
86
88
  };
87
89
 
88
90
  type MutationTabsProps = {
89
91
  mutationsData: { insertions: InsertionEntry[]; substitutionsOrDeletions: SubstitutionOrDeletionEntry[] };
90
92
  sequenceType: SequenceType;
91
93
  views: View[];
94
+ pageSize: boolean | number;
92
95
  };
93
96
 
94
- const MutationsTabs: FunctionComponent<MutationTabsProps> = ({ mutationsData, sequenceType, views }) => {
97
+ const MutationsTabs: FunctionComponent<MutationTabsProps> = ({ mutationsData, sequenceType, views, pageSize }) => {
95
98
  const [proportionInterval, setProportionInterval] = useState({ min: 0.05, max: 1 });
96
99
 
97
100
  const [displayedSegments, setDisplayedSegments] = useDisplayedSegments(sequenceType);
@@ -107,7 +110,13 @@ const MutationsTabs: FunctionComponent<MutationTabsProps> = ({ mutationsData, se
107
110
  case 'table':
108
111
  return {
109
112
  title: 'Table',
110
- content: <MutationsTable data={filteredData.tableData} proportionInterval={proportionInterval} />,
113
+ content: (
114
+ <MutationsTable
115
+ data={filteredData.tableData}
116
+ proportionInterval={proportionInterval}
117
+ pageSize={pageSize}
118
+ />
119
+ ),
111
120
  };
112
121
  case 'grid':
113
122
  return {
@@ -117,13 +126,14 @@ const MutationsTabs: FunctionComponent<MutationTabsProps> = ({ mutationsData, se
117
126
  data={filteredData.gridData}
118
127
  sequenceType={sequenceType}
119
128
  proportionInterval={proportionInterval}
129
+ pageSize={pageSize}
120
130
  />
121
131
  ),
122
132
  };
123
133
  case 'insertions':
124
134
  return {
125
135
  title: 'Insertions',
126
- content: <InsertionsTable data={filteredData.insertions} />,
136
+ content: <InsertionsTable data={filteredData.insertions} pageSize={pageSize} />,
127
137
  };
128
138
  }
129
139
  };
@@ -7,9 +7,10 @@ import { formatProportion } from '../shared/table/formatProportion';
7
7
  interface PrevalenceOverTimeTableProps {
8
8
  data: PrevalenceOverTimeData;
9
9
  granularity: TemporalGranularity;
10
+ pageSize: boolean | number;
10
11
  }
11
12
 
12
- const PrevalenceOverTimeTable = ({ data, granularity }: PrevalenceOverTimeTableProps) => {
13
+ const PrevalenceOverTimeTable = ({ data, granularity, pageSize }: PrevalenceOverTimeTableProps) => {
13
14
  const getSplitColumns = (data: PrevalenceOverTimeData) => {
14
15
  return data.map((dataset) => ({
15
16
  name: dataset.displayName,
@@ -40,7 +41,7 @@ const PrevalenceOverTimeTable = ({ data, granularity }: PrevalenceOverTimeTableP
40
41
  return Object.values(dataByHeader).map((row) => Object.values(row));
41
42
  };
42
43
 
43
- return <Table data={getData(data, granularity)} columns={getColumns(data)} pagination={false} />;
44
+ return <Table data={getData(data, granularity)} columns={getColumns(data)} pageSize={pageSize} />;
44
45
  };
45
46
 
46
47
  export default PrevalenceOverTimeTable;
@@ -32,6 +32,7 @@ export default {
32
32
  width: { control: 'text' },
33
33
  height: { control: 'text' },
34
34
  headline: { control: 'text' },
35
+ pageSize: { control: 'object' },
35
36
  },
36
37
  };
37
38
 
@@ -49,6 +50,7 @@ const Template = {
49
50
  height={args.height}
50
51
  headline={args.headline}
51
52
  lapisDateField={args.lapisDateField}
53
+ pageSize={args.pageSize}
52
54
  />
53
55
  </LapisUrlContext.Provider>
54
56
  ),
@@ -70,6 +72,7 @@ export const TwoVariants = {
70
72
  height: '700px',
71
73
  headline: 'Prevalence over time',
72
74
  lapisDateField: 'date',
75
+ pageSize: 10,
73
76
  },
74
77
  parameters: {
75
78
  fetchMock: {
@@ -142,6 +145,7 @@ export const OneVariant = {
142
145
  height: '700px',
143
146
  headline: 'Prevalence over time',
144
147
  lapisDateField: 'date',
148
+ pageSize: 10,
145
149
  },
146
150
  parameters: {
147
151
  fetchMock: {
@@ -40,6 +40,7 @@ export interface PrevalenceOverTimeInnerProps {
40
40
  views: View[];
41
41
  confidenceIntervalMethods: ConfidenceIntervalMethod[];
42
42
  lapisDateField: string;
43
+ pageSize: boolean | number;
43
44
  }
44
45
 
45
46
  export const PrevalenceOverTime: FunctionComponent<PrevalenceOverTimeProps> = ({
@@ -53,6 +54,7 @@ export const PrevalenceOverTime: FunctionComponent<PrevalenceOverTimeProps> = ({
53
54
  height,
54
55
  headline = 'Prevalence over time',
55
56
  lapisDateField,
57
+ pageSize,
56
58
  }) => {
57
59
  const size = { height, width };
58
60
 
@@ -68,6 +70,7 @@ export const PrevalenceOverTime: FunctionComponent<PrevalenceOverTimeProps> = ({
68
70
  views={views}
69
71
  confidenceIntervalMethods={confidenceIntervalMethods}
70
72
  lapisDateField={lapisDateField}
73
+ pageSize={pageSize}
71
74
  />
72
75
  </Headline>
73
76
  </ResizeContainer>
@@ -83,6 +86,7 @@ export const PrevalenceOverTimeInner: FunctionComponent<PrevalenceOverTimeInnerP
83
86
  views,
84
87
  confidenceIntervalMethods,
85
88
  lapisDateField,
89
+ pageSize,
86
90
  }) => {
87
91
  const lapis = useContext(LapisUrlContext);
88
92
 
@@ -109,6 +113,7 @@ export const PrevalenceOverTimeInner: FunctionComponent<PrevalenceOverTimeInnerP
109
113
  data={data}
110
114
  granularity={granularity}
111
115
  confidenceIntervalMethods={confidenceIntervalMethods}
116
+ pageSize={pageSize}
112
117
  />
113
118
  );
114
119
  };
@@ -118,6 +123,7 @@ type PrevalenceOverTimeTabsProps = {
118
123
  data: PrevalenceOverTimeData;
119
124
  granularity: TemporalGranularity;
120
125
  confidenceIntervalMethods: ConfidenceIntervalMethod[];
126
+ pageSize: boolean | number;
121
127
  };
122
128
 
123
129
  const PrevalenceOverTimeTabs: FunctionComponent<PrevalenceOverTimeTabsProps> = ({
@@ -125,6 +131,7 @@ const PrevalenceOverTimeTabs: FunctionComponent<PrevalenceOverTimeTabsProps> = (
125
131
  data,
126
132
  granularity,
127
133
  confidenceIntervalMethods,
134
+ pageSize,
128
135
  }) => {
129
136
  const [yAxisScaleType, setYAxisScaleType] = useState<ScaleType>('linear');
130
137
  const [confidenceIntervalMethod, setConfidenceIntervalMethod] = useState<ConfidenceIntervalMethod>(
@@ -163,7 +170,7 @@ const PrevalenceOverTimeTabs: FunctionComponent<PrevalenceOverTimeTabsProps> = (
163
170
  case 'table':
164
171
  return {
165
172
  title: 'Table',
166
- content: <PrevalenceOverTimeTable data={data} granularity={granularity} />,
173
+ content: <PrevalenceOverTimeTable data={data} granularity={granularity} pageSize={pageSize} />,
167
174
  };
168
175
  }
169
176
  };
@@ -4,7 +4,7 @@ import { queryAggregateData } from './queryAggregateData';
4
4
  import { DUMMY_LAPIS_URL, lapisRequestMocks } from '../../vitest.setup';
5
5
 
6
6
  describe('queryAggregateData', () => {
7
- test('should fetch aggregate data', async () => {
7
+ test('should fetch aggregate data and sort initially by count descending when no initialSort is provided', async () => {
8
8
  const fields = ['division', 'host'];
9
9
  const filter = { country: 'USA' };
10
10
 
@@ -23,10 +23,124 @@ describe('queryAggregateData', () => {
23
23
  const result = await queryAggregateData(filter, fields, DUMMY_LAPIS_URL);
24
24
 
25
25
  expect(result).to.deep.equal([
26
+ { proportion: 0.5, count: 16, region: 'region2', host: 'host2' },
27
+ { proportion: 0.25, count: 8, region: 'region2', host: 'host1' },
26
28
  { proportion: 0.125, count: 4, region: 'region1', host: 'host1' },
27
29
  { proportion: 0.125, count: 4, region: 'region1', host: 'host2' },
28
- { proportion: 0.25, count: 8, region: 'region2', host: 'host1' },
29
- { proportion: 0.5, count: 16, region: 'region2', host: 'host2' },
30
30
  ]);
31
31
  });
32
+
33
+ test('should sort by initialSort field ascending', async () => {
34
+ const fields = ['division', 'host'];
35
+ const filter = { country: 'USA' };
36
+ const initialSortField = 'host';
37
+ const initialSortDirection = 'ascending';
38
+
39
+ lapisRequestMocks.aggregated(
40
+ { fields, ...filter },
41
+ {
42
+ data: [
43
+ { count: 4, region: 'region1', host: 'A_host' },
44
+ { count: 4, region: 'region1', host: 'B_host' },
45
+ { count: 8, region: 'region2', host: 'A_host1' },
46
+ { count: 16, region: 'region2', host: 'C_host' },
47
+ ],
48
+ },
49
+ );
50
+
51
+ const result = await queryAggregateData(filter, fields, DUMMY_LAPIS_URL, {
52
+ field: initialSortField,
53
+ direction: initialSortDirection,
54
+ });
55
+
56
+ expect(result).to.deep.equal([
57
+ { proportion: 0.125, count: 4, region: 'region1', host: 'A_host' },
58
+ { proportion: 0.25, count: 8, region: 'region2', host: 'A_host1' },
59
+ { proportion: 0.125, count: 4, region: 'region1', host: 'B_host' },
60
+ { proportion: 0.5, count: 16, region: 'region2', host: 'C_host' },
61
+ ]);
62
+ });
63
+
64
+ test('should sort by initialSort field descending', async () => {
65
+ const fields = ['division', 'host'];
66
+ const filter = { country: 'USA' };
67
+ const initialSortField = 'host';
68
+ const initialSortDirection = 'descending';
69
+
70
+ lapisRequestMocks.aggregated(
71
+ { fields, ...filter },
72
+ {
73
+ data: [
74
+ { count: 4, region: 'region1', host: 'A_host' },
75
+ { count: 4, region: 'region1', host: 'B_host' },
76
+ { count: 8, region: 'region2', host: 'A_host1' },
77
+ { count: 16, region: 'region2', host: 'C_host' },
78
+ ],
79
+ },
80
+ );
81
+
82
+ const result = await queryAggregateData(filter, fields, DUMMY_LAPIS_URL, {
83
+ field: initialSortField,
84
+ direction: initialSortDirection,
85
+ });
86
+
87
+ expect(result).to.deep.equal([
88
+ { proportion: 0.5, count: 16, region: 'region2', host: 'C_host' },
89
+ { proportion: 0.125, count: 4, region: 'region1', host: 'B_host' },
90
+ { proportion: 0.25, count: 8, region: 'region2', host: 'A_host1' },
91
+ { proportion: 0.125, count: 4, region: 'region1', host: 'A_host' },
92
+ ]);
93
+ });
94
+
95
+ test('should sort by initialSort number field', async () => {
96
+ const fields = ['division', 'host'];
97
+ const filter = { country: 'USA' };
98
+ const initialSortField = 'proportion';
99
+ const initialSortDirection = 'descending';
100
+
101
+ lapisRequestMocks.aggregated(
102
+ { fields, ...filter },
103
+ {
104
+ data: [
105
+ { count: 4, region: 'region1', host: 'A_host' },
106
+ { count: 4, region: 'region1', host: 'B_host' },
107
+ { count: 8, region: 'region2', host: 'A_host1' },
108
+ { count: 16, region: 'region2', host: 'C_host' },
109
+ ],
110
+ },
111
+ );
112
+
113
+ const result = await queryAggregateData(filter, fields, DUMMY_LAPIS_URL, {
114
+ field: initialSortField,
115
+ direction: initialSortDirection,
116
+ });
117
+
118
+ expect(result).to.deep.equal([
119
+ { proportion: 0.125, count: 4, region: 'region1', host: 'A_host' },
120
+ { proportion: 0.125, count: 4, region: 'region1', host: 'B_host' },
121
+ { proportion: 0.25, count: 8, region: 'region2', host: 'A_host1' },
122
+ { proportion: 0.5, count: 16, region: 'region2', host: 'C_host' },
123
+ ]);
124
+ });
125
+
126
+ test('should throw if initialSortField is not in fields', async () => {
127
+ const fields = ['division', 'host'];
128
+ const filter = { country: 'USA' };
129
+ const initialSortField = 'not_in_fields';
130
+ const initialSortDirection = 'descending';
131
+
132
+ lapisRequestMocks.aggregated(
133
+ { fields, ...filter },
134
+ {
135
+ data: [{ count: 4, region: 'region1', host: 'A_host' }],
136
+ },
137
+ );
138
+
139
+ await expect(
140
+ queryAggregateData(filter, fields, DUMMY_LAPIS_URL, {
141
+ field: initialSortField,
142
+ direction: initialSortDirection,
143
+ }),
144
+ ).rejects.toThrowError('InitialSort field not in fields. Valid fields are: count, proportion, division, host');
145
+ });
32
146
  });
@@ -1,4 +1,6 @@
1
1
  import { FetchAggregatedOperator } from '../operator/FetchAggregatedOperator';
2
+ import { SortOperator } from '../operator/SortOperator';
3
+ import { type InitialSort } from '../preact/aggregatedData/aggregate';
2
4
  import { type LapisFilter } from '../types';
3
5
 
4
6
  export type AggregateData = (Record<string, string | null | number | boolean> & {
@@ -6,9 +8,36 @@ export type AggregateData = (Record<string, string | null | number | boolean> &
6
8
  proportion: number;
7
9
  })[];
8
10
 
9
- export async function queryAggregateData(variant: LapisFilter, fields: string[], lapis: string, signal?: AbortSignal) {
11
+ const compareAscending = (a: string | null | number, b: string | null | number) => {
12
+ if (typeof a === 'number' && typeof b === 'number') {
13
+ return a - b;
14
+ }
15
+
16
+ const strA = a != null ? String(a) : '';
17
+ const strB = b != null ? String(b) : '';
18
+
19
+ return strA.localeCompare(strB);
20
+ };
21
+
22
+ export async function queryAggregateData(
23
+ variant: LapisFilter,
24
+ fields: string[],
25
+ lapis: string,
26
+ initialSort: InitialSort = { field: 'count', direction: 'descending' },
27
+ signal?: AbortSignal,
28
+ ) {
29
+ const validSortFields = ['count', 'proportion', ...fields];
30
+ if (!validSortFields.includes(initialSort.field)) {
31
+ throw new Error(`InitialSort field not in fields. Valid fields are: ${validSortFields.join(', ')}`);
32
+ }
33
+
10
34
  const fetchData = new FetchAggregatedOperator<Record<string, string | null | number>>(variant, fields);
11
- const data = (await fetchData.evaluate(lapis, signal)).content;
35
+ const sortData = new SortOperator(fetchData, (a, b) => {
36
+ return initialSort.direction === 'ascending'
37
+ ? compareAscending(a[initialSort.field], b[initialSort.field])
38
+ : compareAscending(b[initialSort.field], a[initialSort.field]);
39
+ });
40
+ const data = (await sortData.evaluate(lapis, signal)).content;
12
41
 
13
42
  const total = data.reduce((acc, row) => acc + row.count, 0);
14
43
 
@@ -17,6 +17,7 @@ const codeExample = String.raw`
17
17
  fields='["region", "country"]'
18
18
  initialValue='Europe / Switzerland'
19
19
  width="100%"
20
+ placeholderText="Enter a location"
20
21
  ></gs-location-filter>`;
21
22
 
22
23
  const meta: Meta = {
@@ -48,6 +49,11 @@ const meta: Meta = {
48
49
  type: 'text',
49
50
  },
50
51
  },
52
+ placeholderText: {
53
+ control: {
54
+ type: 'text',
55
+ },
56
+ },
51
57
  },
52
58
  decorators: [withActions],
53
59
  tags: ['autodocs'],
@@ -63,6 +69,7 @@ const Template: StoryObj<LocationFilterProps> = {
63
69
  .fields=${args.fields}
64
70
  initialValue=${ifDefined(args.initialValue)}
65
71
  .width=${args.width}
72
+ placeholderText=${ifDefined(args.placeholderText)}
66
73
  ></gs-location-filter>
67
74
  </div>
68
75
  </gs-app>`;
@@ -71,6 +78,7 @@ const Template: StoryObj<LocationFilterProps> = {
71
78
  fields: ['region', 'country', 'division', 'location'],
72
79
  initialValue: '',
73
80
  width: '100%',
81
+ placeholderText: 'Enter a location',
74
82
  },
75
83
  };
76
84
 
@@ -102,6 +110,9 @@ export const LocationFilter: StoryObj<LocationFilterProps> = {
102
110
  await waitFor(() => {
103
111
  return expect(canvas.getByRole('combobox')).toBeEnabled();
104
112
  });
113
+ await waitFor(() => {
114
+ return expect(canvas.getByPlaceholderText('Enter a location')).toBeInTheDocument();
115
+ });
105
116
  },
106
117
  };
107
118
 
@@ -59,8 +59,21 @@ export class LocationFilterComponent extends PreactLitAdapter {
59
59
  @property({ type: String })
60
60
  width: string = '100%';
61
61
 
62
+ /**
63
+ * The placeholder text to display in the input field, if it is empty.
64
+ */
65
+ @property()
66
+ placeholderText: string = '';
67
+
62
68
  override render() {
63
- return <LocationFilter initialValue={this.initialValue} fields={this.fields} width={this.width} />;
69
+ return (
70
+ <LocationFilter
71
+ initialValue={this.initialValue}
72
+ fields={this.fields}
73
+ width={this.width}
74
+ placeholderText={this.placeholderText}
75
+ />
76
+ );
64
77
  }
65
78
  }
66
79
 
@@ -17,6 +17,9 @@ const codeExample = `
17
17
  headline="Aggregate"
18
18
  width='100%'
19
19
  height='700px'
20
+ initialSortField="count"
21
+ initialSortDirection="descending"
22
+ pageSize="10"
20
23
  ></gs-aggregate>`;
21
24
 
22
25
  const meta: Meta<Required<AggregateProps>> = {
@@ -31,6 +34,12 @@ const meta: Meta<Required<AggregateProps>> = {
31
34
  width: { control: 'text' },
32
35
  height: { control: 'text' },
33
36
  headline: { control: 'text' },
37
+ pageSize: { control: 'object' },
38
+ initialSortField: { control: 'text' },
39
+ initialSortDirection: {
40
+ options: ['ascending', 'descending'],
41
+ control: { type: 'radio' },
42
+ },
34
43
  },
35
44
  parameters: withComponentDocs({
36
45
  fetchMock: {
@@ -72,6 +81,9 @@ export const Table: StoryObj<Required<AggregateProps>> = {
72
81
  .width=${args.width}
73
82
  .height=${args.height}
74
83
  .headline=${args.headline}
84
+ .initialSortField=${args.initialSortField}
85
+ .initialSortDirection=${args.initialSortDirection}
86
+ .pageSize=${args.pageSize}
75
87
  ></gs-aggregate>
76
88
  </gs-app>
77
89
  `,
@@ -84,5 +96,8 @@ export const Table: StoryObj<Required<AggregateProps>> = {
84
96
  width: '100%',
85
97
  height: '700px',
86
98
  headline: 'Aggregate',
99
+ initialSortField: 'count',
100
+ initialSortDirection: 'descending',
101
+ pageSize: 10,
87
102
  },
88
103
  };
@@ -67,6 +67,26 @@ export class AggregateComponent extends PreactLitAdapterWithGridJsStyles {
67
67
  @property({ type: String })
68
68
  headline: string = 'Aggregate';
69
69
 
70
+ /**
71
+ * The field by which the table is initially sorted.
72
+ * Must be one of the fields specified in the fields property, 'count', or 'proportion'.
73
+ */
74
+ @property({ type: String })
75
+ initialSortField: string = 'count';
76
+
77
+ /**
78
+ * The initial sort direction of the table.
79
+ */
80
+ @property({ type: String })
81
+ initialSortDirection: 'ascending' | 'descending' = 'descending';
82
+
83
+ /**
84
+ * The maximum number of rows to display in the table view.
85
+ * Set to `false` to disable pagination. Set to `true` to enable pagination with a default limit (10).
86
+ */
87
+ @property({ type: Object })
88
+ pageSize: boolean | number = false;
89
+
70
90
  override render() {
71
91
  return (
72
92
  <Aggregate
@@ -76,6 +96,9 @@ export class AggregateComponent extends PreactLitAdapterWithGridJsStyles {
76
96
  width={this.width}
77
97
  height={this.height}
78
98
  headline={this.headline}
99
+ initialSortField={this.initialSortField}
100
+ initialSortDirection={this.initialSortDirection}
101
+ pageSize={this.pageSize}
79
102
  />
80
103
  );
81
104
  }
@@ -19,6 +19,7 @@ const codeExample = String.raw`
19
19
  headline="Mutation comparison"
20
20
  width='100%'
21
21
  height='700px'
22
+ pageSize="10"
22
23
  ></gs-mutation-comparison>`;
23
24
 
24
25
  const meta: Meta<Required<MutationComparisonProps>> = {
@@ -37,6 +38,7 @@ const meta: Meta<Required<MutationComparisonProps>> = {
37
38
  width: { control: 'text' },
38
39
  height: { control: 'text' },
39
40
  headline: { control: 'text' },
41
+ pageSize: { control: 'object' },
40
42
  },
41
43
  parameters: withComponentDocs({
42
44
  componentDocs: {
@@ -60,6 +62,7 @@ const Template: StoryObj<Required<MutationComparisonProps>> = {
60
62
  .width=${args.width}
61
63
  .height=${args.height}
62
64
  .headline=${args.headline}
65
+ .pageSize=${args.pageSize}
63
66
  ></gs-mutation-comparison>
64
67
  </gs-app>
65
68
  `,
@@ -91,6 +94,7 @@ export const Default: StoryObj<Required<MutationComparisonProps>> = {
91
94
  width: '100%',
92
95
  height: '700px',
93
96
  headline: 'Mutation comparison',
97
+ pageSize: 10,
94
98
  },
95
99
  parameters: {
96
100
  fetchMock: {
@@ -82,6 +82,13 @@ export class MutationComparisonComponent extends PreactLitAdapterWithGridJsStyle
82
82
  @property({ type: String })
83
83
  headline: string = 'Mutation comparison';
84
84
 
85
+ /**
86
+ * The maximum number of rows to display in the table view.
87
+ * Set to `false` to disable pagination. Set to `true` to enable pagination with a default limit (10).
88
+ */
89
+ @property({ type: Object })
90
+ pageSize: boolean | number = false;
91
+
85
92
  override render() {
86
93
  return (
87
94
  <MutationComparison
@@ -91,6 +98,7 @@ export class MutationComparisonComponent extends PreactLitAdapterWithGridJsStyle
91
98
  width={this.width}
92
99
  height={this.height}
93
100
  headline={this.headline}
101
+ pageSize={this.pageSize}
94
102
  />
95
103
  );
96
104
  }
@@ -19,6 +19,7 @@ const codeExample = String.raw`
19
19
  headline="Mutations"
20
20
  width='100%'
21
21
  height='700px'
22
+ pageSize="10"
22
23
  ></gs-mutations>`;
23
24
 
24
25
  const meta: Meta<Required<MutationsProps>> = {
@@ -37,6 +38,7 @@ const meta: Meta<Required<MutationsProps>> = {
37
38
  width: { control: 'text' },
38
39
  height: { control: 'text' },
39
40
  headline: { control: 'text' },
41
+ pageSize: { control: 'object' },
40
42
  },
41
43
  args: {
42
44
  variant: { country: 'Switzerland', pangoLineage: 'B.1.1.7', dateTo: '2022-01-01' },
@@ -45,6 +47,7 @@ const meta: Meta<Required<MutationsProps>> = {
45
47
  width: '100%',
46
48
  height: '700px',
47
49
  headline: 'Mutations',
50
+ pageSize: 10,
48
51
  },
49
52
  parameters: withComponentDocs({
50
53
  componentDocs: {
@@ -68,6 +71,7 @@ const Template: StoryObj<Required<MutationsProps>> = {
68
71
  .width=${args.width}
69
72
  .height=${args.height}
70
73
  .headline=${args.headline}
74
+ .pageSize=${args.pageSize}
71
75
  ></gs-mutations>
72
76
  </gs-app>
73
77
  `,
@@ -77,6 +77,13 @@ export class MutationsComponent extends PreactLitAdapterWithGridJsStyles {
77
77
  @property({ type: String })
78
78
  headline: string = 'Mutations';
79
79
 
80
+ /**
81
+ * The maximum number of rows to display in the table view.
82
+ * Set to `false` to disable pagination. Set to `true` to enable pagination with a default limit (10).
83
+ */
84
+ @property({ type: Object })
85
+ pageSize: boolean | number = false;
86
+
80
87
  override render() {
81
88
  return (
82
89
  <Mutations
@@ -86,6 +93,7 @@ export class MutationsComponent extends PreactLitAdapterWithGridJsStyles {
86
93
  width={this.width}
87
94
  height={this.height}
88
95
  headline={this.headline}
96
+ pageSize={this.pageSize}
89
97
  />
90
98
  );
91
99
  }
@@ -26,6 +26,7 @@ const codeExample = String.raw`
26
26
  width="100%"
27
27
  height="700px"
28
28
  lapisDateField="date"
29
+ pageSize="10"
29
30
  ></gs-prevalence-over-time>`;
30
31
 
31
32
  const meta: Meta<Required<PrevalenceOverTimeProps>> = {
@@ -50,6 +51,7 @@ const meta: Meta<Required<PrevalenceOverTimeProps>> = {
50
51
  width: { control: 'text' },
51
52
  height: { control: 'text' },
52
53
  headline: { control: 'text' },
54
+ pageSize: { control: 'object' },
53
55
  },
54
56
  parameters: withComponentDocs({
55
57
  componentDocs: {
@@ -77,6 +79,7 @@ const Template: StoryObj<Required<PrevalenceOverTimeProps>> = {
77
79
  .height=${args.height}
78
80
  .headline=${args.headline}
79
81
  .lapisDateField=${args.lapisDateField}
82
+ .pageSize=${args.pageSize}
80
83
  ></gs-prevalence-over-time>
81
84
  </gs-app>
82
85
  `,
@@ -98,6 +101,7 @@ export const TwoVariants: StoryObj<Required<PrevalenceOverTimeProps>> = {
98
101
  height: '700px',
99
102
  headline: 'Prevalence over time',
100
103
  lapisDateField: 'date',
104
+ pageSize: 10,
101
105
  },
102
106
  parameters: {
103
107
  fetchMock: {
@@ -170,6 +174,7 @@ export const OneVariant: StoryObj<Required<PrevalenceOverTimeProps>> = {
170
174
  height: '700px',
171
175
  headline: 'Prevalence over time',
172
176
  lapisDateField: 'date',
177
+ pageSize: 10,
173
178
  },
174
179
  parameters: {
175
180
  fetchMock: {