@genspectrum/dashboard-components 0.11.3 → 0.11.4

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/style.css CHANGED
@@ -482,7 +482,7 @@ input[type="range"] {
482
482
  --tw-contain-paint: ;
483
483
  --tw-contain-style: ;
484
484
  }/*
485
- ! tailwindcss v3.4.16 | MIT License | https://tailwindcss.com
485
+ ! tailwindcss v3.4.17 | MIT License | https://tailwindcss.com
486
486
  *//*
487
487
  1. Prevent padding and border from affecting element width. (https://github.com/mozdevs/cssremedy/issues/4)
488
488
  2. Allow adding a border to an element by just adding a border-width. (https://github.com/tailwindcss/tailwindcss/pull/116)
@@ -1154,6 +1154,7 @@ html {
1154
1154
  display: grid;
1155
1155
  width: 100%;
1156
1156
  overflow: hidden;
1157
+ direction: ltr;
1157
1158
  container-type: inline-size;
1158
1159
  grid-template-columns: auto 1fr;
1159
1160
  }
package/dist/util.d.ts CHANGED
@@ -787,10 +787,7 @@ declare global {
787
787
 
788
788
  declare global {
789
789
  interface HTMLElementTagNameMap {
790
- 'gs-location-filter': LocationFilterComponent;
791
- }
792
- interface HTMLElementEventMap {
793
- 'gs-location-changed': CustomEvent<Record<string, string>>;
790
+ 'gs-mutations-component': MutationsComponent;
794
791
  }
795
792
  }
796
793
 
@@ -798,7 +795,7 @@ declare global {
798
795
  declare global {
799
796
  namespace JSX {
800
797
  interface IntrinsicElements {
801
- 'gs-location-filter': DetailedHTMLProps<HTMLAttributes<HTMLElement>, HTMLElement>;
798
+ 'gs-mutations-component': DetailedHTMLProps<HTMLAttributes<HTMLElement>, HTMLElement>;
802
799
  }
803
800
  }
804
801
  }
@@ -806,11 +803,7 @@ declare global {
806
803
 
807
804
  declare global {
808
805
  interface HTMLElementTagNameMap {
809
- 'gs-date-range-selector': DateRangeSelectorComponent;
810
- }
811
- interface HTMLElementEventMap {
812
- 'gs-date-range-filter-changed': CustomEvent<Record<string, string>>;
813
- 'gs-date-range-option-changed': DateRangeOptionChangedEvent;
806
+ 'gs-prevalence-over-time': PrevalenceOverTimeComponent;
814
807
  }
815
808
  }
816
809
 
@@ -818,7 +811,7 @@ declare global {
818
811
  declare global {
819
812
  namespace JSX {
820
813
  interface IntrinsicElements {
821
- 'gs-date-range-selector': DetailedHTMLProps<HTMLAttributes<HTMLElement>, HTMLElement>;
814
+ 'gs-prevalence-over-time': DetailedHTMLProps<HTMLAttributes<HTMLElement>, HTMLElement>;
822
815
  }
823
816
  }
824
817
  }
@@ -826,10 +819,7 @@ declare global {
826
819
 
827
820
  declare global {
828
821
  interface HTMLElementTagNameMap {
829
- 'gs-text-input': TextInputComponent;
830
- }
831
- interface HTMLElementEventMap {
832
- 'gs-text-input-changed': CustomEvent<Record<string, string>>;
822
+ 'gs-relative-growth-advantage': RelativeGrowthAdvantageComponent;
833
823
  }
834
824
  }
835
825
 
@@ -837,7 +827,7 @@ declare global {
837
827
  declare global {
838
828
  namespace JSX {
839
829
  interface IntrinsicElements {
840
- 'gs-text-input': DetailedHTMLProps<HTMLAttributes<HTMLElement>, HTMLElement>;
830
+ 'gs-relative-growth-advantage': DetailedHTMLProps<HTMLAttributes<HTMLElement>, HTMLElement>;
841
831
  }
842
832
  }
843
833
  }
@@ -845,10 +835,7 @@ declare global {
845
835
 
846
836
  declare global {
847
837
  interface HTMLElementTagNameMap {
848
- 'gs-mutation-filter': MutationFilterComponent;
849
- }
850
- interface HTMLElementEventMap {
851
- 'gs-mutation-filter-changed': CustomEvent<MutationsFilter>;
838
+ 'gs-aggregate': AggregateComponent;
852
839
  }
853
840
  }
854
841
 
@@ -856,7 +843,7 @@ declare global {
856
843
  declare global {
857
844
  namespace JSX {
858
845
  interface IntrinsicElements {
859
- 'gs-mutation-filter': DetailedHTMLProps<HTMLAttributes<HTMLElement>, HTMLElement>;
846
+ 'gs-aggregate': DetailedHTMLProps<HTMLAttributes<HTMLElement>, HTMLElement>;
860
847
  }
861
848
  }
862
849
  }
@@ -864,10 +851,7 @@ declare global {
864
851
 
865
852
  declare global {
866
853
  interface HTMLElementTagNameMap {
867
- 'gs-lineage-filter': LineageFilterComponent;
868
- }
869
- interface HTMLElementEventMap {
870
- 'gs-lineage-filter-changed': CustomEvent<Record<string, string>>;
854
+ 'gs-mutation-comparison-component': MutationComparisonComponent;
871
855
  }
872
856
  }
873
857
 
@@ -875,7 +859,7 @@ declare global {
875
859
  declare global {
876
860
  namespace JSX {
877
861
  interface IntrinsicElements {
878
- 'gs-lineage-filter': DetailedHTMLProps<HTMLAttributes<HTMLElement>, HTMLElement>;
862
+ 'gs-mutation-comparison-component': DetailedHTMLProps<HTMLAttributes<HTMLElement>, HTMLElement>;
879
863
  }
880
864
  }
881
865
  }
@@ -883,7 +867,7 @@ declare global {
883
867
 
884
868
  declare global {
885
869
  interface HTMLElementTagNameMap {
886
- 'gs-mutation-comparison-component': MutationComparisonComponent;
870
+ 'gs-number-sequences-over-time': NumberSequencesOverTimeComponent;
887
871
  }
888
872
  }
889
873
 
@@ -891,7 +875,7 @@ declare global {
891
875
  declare global {
892
876
  namespace JSX {
893
877
  interface IntrinsicElements {
894
- 'gs-mutation-comparison-component': DetailedHTMLProps<HTMLAttributes<HTMLElement>, HTMLElement>;
878
+ 'gs-number-sequences-over-time': DetailedHTMLProps<HTMLAttributes<HTMLElement>, HTMLElement>;
895
879
  }
896
880
  }
897
881
  }
@@ -899,7 +883,7 @@ declare global {
899
883
 
900
884
  declare global {
901
885
  interface HTMLElementTagNameMap {
902
- 'gs-mutations-component': MutationsComponent;
886
+ 'gs-sequences-by-location': SequencesByLocationComponent;
903
887
  }
904
888
  }
905
889
 
@@ -907,7 +891,7 @@ declare global {
907
891
  declare global {
908
892
  namespace JSX {
909
893
  interface IntrinsicElements {
910
- 'gs-mutations-component': DetailedHTMLProps<HTMLAttributes<HTMLElement>, HTMLElement>;
894
+ 'gs-sequences-by-location': DetailedHTMLProps<HTMLAttributes<HTMLElement>, HTMLElement>;
911
895
  }
912
896
  }
913
897
  }
@@ -915,7 +899,7 @@ declare global {
915
899
 
916
900
  declare global {
917
901
  interface HTMLElementTagNameMap {
918
- 'gs-prevalence-over-time': PrevalenceOverTimeComponent;
902
+ 'gs-mutations-over-time': MutationsOverTimeComponent;
919
903
  }
920
904
  }
921
905
 
@@ -923,7 +907,7 @@ declare global {
923
907
  declare global {
924
908
  namespace JSX {
925
909
  interface IntrinsicElements {
926
- 'gs-prevalence-over-time': DetailedHTMLProps<HTMLAttributes<HTMLElement>, HTMLElement>;
910
+ 'gs-mutations-over-time': DetailedHTMLProps<HTMLAttributes<HTMLElement>, HTMLElement>;
927
911
  }
928
912
  }
929
913
  }
@@ -931,7 +915,7 @@ declare global {
931
915
 
932
916
  declare global {
933
917
  interface HTMLElementTagNameMap {
934
- 'gs-relative-growth-advantage': RelativeGrowthAdvantageComponent;
918
+ 'gs-statistics': StatisticsComponent;
935
919
  }
936
920
  }
937
921
 
@@ -939,7 +923,7 @@ declare global {
939
923
  declare global {
940
924
  namespace JSX {
941
925
  interface IntrinsicElements {
942
- 'gs-relative-growth-advantage': DetailedHTMLProps<HTMLAttributes<HTMLElement>, HTMLElement>;
926
+ 'gs-statistics': DetailedHTMLProps<HTMLAttributes<HTMLElement>, HTMLElement>;
943
927
  }
944
928
  }
945
929
  }
@@ -947,7 +931,11 @@ declare global {
947
931
 
948
932
  declare global {
949
933
  interface HTMLElementTagNameMap {
950
- 'gs-aggregate': AggregateComponent;
934
+ 'gs-date-range-selector': DateRangeSelectorComponent;
935
+ }
936
+ interface HTMLElementEventMap {
937
+ 'gs-date-range-filter-changed': CustomEvent<Record<string, string>>;
938
+ 'gs-date-range-option-changed': DateRangeOptionChangedEvent;
951
939
  }
952
940
  }
953
941
 
@@ -955,7 +943,7 @@ declare global {
955
943
  declare global {
956
944
  namespace JSX {
957
945
  interface IntrinsicElements {
958
- 'gs-aggregate': DetailedHTMLProps<HTMLAttributes<HTMLElement>, HTMLElement>;
946
+ 'gs-date-range-selector': DetailedHTMLProps<HTMLAttributes<HTMLElement>, HTMLElement>;
959
947
  }
960
948
  }
961
949
  }
@@ -963,7 +951,10 @@ declare global {
963
951
 
964
952
  declare global {
965
953
  interface HTMLElementTagNameMap {
966
- 'gs-number-sequences-over-time': NumberSequencesOverTimeComponent;
954
+ 'gs-location-filter': LocationFilterComponent;
955
+ }
956
+ interface HTMLElementEventMap {
957
+ 'gs-location-changed': CustomEvent<Record<string, string>>;
967
958
  }
968
959
  }
969
960
 
@@ -971,7 +962,7 @@ declare global {
971
962
  declare global {
972
963
  namespace JSX {
973
964
  interface IntrinsicElements {
974
- 'gs-number-sequences-over-time': DetailedHTMLProps<HTMLAttributes<HTMLElement>, HTMLElement>;
965
+ 'gs-location-filter': DetailedHTMLProps<HTMLAttributes<HTMLElement>, HTMLElement>;
975
966
  }
976
967
  }
977
968
  }
@@ -979,7 +970,10 @@ declare global {
979
970
 
980
971
  declare global {
981
972
  interface HTMLElementTagNameMap {
982
- 'gs-mutations-over-time': MutationsOverTimeComponent;
973
+ 'gs-text-input': TextInputComponent;
974
+ }
975
+ interface HTMLElementEventMap {
976
+ 'gs-text-input-changed': CustomEvent<Record<string, string>>;
983
977
  }
984
978
  }
985
979
 
@@ -987,7 +981,7 @@ declare global {
987
981
  declare global {
988
982
  namespace JSX {
989
983
  interface IntrinsicElements {
990
- 'gs-mutations-over-time': DetailedHTMLProps<HTMLAttributes<HTMLElement>, HTMLElement>;
984
+ 'gs-text-input': DetailedHTMLProps<HTMLAttributes<HTMLElement>, HTMLElement>;
991
985
  }
992
986
  }
993
987
  }
@@ -995,7 +989,10 @@ declare global {
995
989
 
996
990
  declare global {
997
991
  interface HTMLElementTagNameMap {
998
- 'gs-sequences-by-location': SequencesByLocationComponent;
992
+ 'gs-mutation-filter': MutationFilterComponent;
993
+ }
994
+ interface HTMLElementEventMap {
995
+ 'gs-mutation-filter-changed': CustomEvent<MutationsFilter>;
999
996
  }
1000
997
  }
1001
998
 
@@ -1003,7 +1000,7 @@ declare global {
1003
1000
  declare global {
1004
1001
  namespace JSX {
1005
1002
  interface IntrinsicElements {
1006
- 'gs-sequences-by-location': DetailedHTMLProps<HTMLAttributes<HTMLElement>, HTMLElement>;
1003
+ 'gs-mutation-filter': DetailedHTMLProps<HTMLAttributes<HTMLElement>, HTMLElement>;
1007
1004
  }
1008
1005
  }
1009
1006
  }
@@ -1011,7 +1008,10 @@ declare global {
1011
1008
 
1012
1009
  declare global {
1013
1010
  interface HTMLElementTagNameMap {
1014
- 'gs-statistics': StatisticsComponent;
1011
+ 'gs-lineage-filter': LineageFilterComponent;
1012
+ }
1013
+ interface HTMLElementEventMap {
1014
+ 'gs-lineage-filter-changed': CustomEvent<Record<string, string>>;
1015
1015
  }
1016
1016
  }
1017
1017
 
@@ -1019,7 +1019,7 @@ declare global {
1019
1019
  declare global {
1020
1020
  namespace JSX {
1021
1021
  interface IntrinsicElements {
1022
- 'gs-statistics': DetailedHTMLProps<HTMLAttributes<HTMLElement>, HTMLElement>;
1022
+ 'gs-lineage-filter': DetailedHTMLProps<HTMLAttributes<HTMLElement>, HTMLElement>;
1023
1023
  }
1024
1024
  }
1025
1025
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@genspectrum/dashboard-components",
3
- "version": "0.11.3",
3
+ "version": "0.11.4",
4
4
  "description": "GenSpectrum web components for building dashboards",
5
5
  "type": "module",
6
6
  "license": "AGPL-3.0-only",
@@ -109,7 +109,7 @@
109
109
  "@storybook/preact": "^8.0.9",
110
110
  "@storybook/preact-vite": "^8.0.9",
111
111
  "@storybook/test": "^8.0.0",
112
- "@storybook/test-runner": "^0.20.1",
112
+ "@storybook/test-runner": "^0.21.0",
113
113
  "@storybook/types": "^8.0.9",
114
114
  "@storybook/web-components": "^8.0.9",
115
115
  "@storybook/web-components-vite": "^8.0.9",
@@ -53,7 +53,7 @@ export const AggregateInner: FunctionComponent<AggregateProps> = (componentProps
53
53
  field: initialSortField,
54
54
  direction: initialSortDirection,
55
55
  });
56
- }, [lapisFilter, fields, lapis]);
56
+ }, [lapisFilter, fields, lapis, initialSortField, initialSortDirection]);
57
57
 
58
58
  if (isLoading) {
59
59
  return <LoadingDisplay />;
@@ -45,7 +45,7 @@
45
45
  "division": "Saxony-Anhalt"
46
46
  },
47
47
  {
48
- "count": 109800,
48
+ "count": 109799,
49
49
  "division": null
50
50
  },
51
51
  {
@@ -56,6 +56,10 @@
56
56
  "count": 50650,
57
57
  "division": "Baden-Wuerttemberg"
58
58
  },
59
+ {
60
+ "count": 1,
61
+ "division": "Baden-Württemberg"
62
+ },
59
63
  {
60
64
  "count": 50102,
61
65
  "division": "North Rhine Westphalia"
@@ -4,7 +4,6 @@ import type { GeometryCollection, Topology } from 'topojson-specification';
4
4
  import z from 'zod';
5
5
 
6
6
  import { UserFacingError } from '../components/error-display';
7
- import { useQuery } from '../useQuery';
8
7
 
9
8
  export const mapSourceSchema = z.object({
10
9
  type: z.literal('topojson'),
@@ -13,33 +12,17 @@ export const mapSourceSchema = z.object({
13
12
  });
14
13
  export type MapSource = z.infer<typeof mapSourceSchema>;
15
14
 
16
- export function useGeoJsonMap(mapSource: MapSource) {
17
- const {
18
- data: geojsonData,
19
- error,
20
- isLoading,
21
- } = useQuery(async () => {
22
- switch (mapSource.type) {
23
- case 'topojson':
24
- return await loadTopojsonMap(mapSource);
25
- }
26
- }, [mapSource]);
27
-
28
- if (isLoading) {
29
- return { isLoading };
30
- }
31
-
32
- if (error) {
33
- throw error;
34
- }
35
-
36
- return { geojsonData, isLoading: false as const };
37
- }
38
-
39
15
  export type GeoJsonFeatureProperties = {
40
16
  name: string;
41
17
  };
42
18
 
19
+ export async function loadMapSource(mapSource: MapSource) {
20
+ switch (mapSource.type) {
21
+ case 'topojson':
22
+ return await loadTopojsonMap(mapSource);
23
+ }
24
+ }
25
+
43
26
  async function loadTopojsonMap(
44
27
  mapSource: MapSource,
45
28
  ): Promise<FeatureCollection<GeometryObject, GeoJsonFeatureProperties>> {
@@ -1,24 +1,19 @@
1
- import type { Feature, FeatureCollection, GeometryObject } from 'geojson';
1
+ import type { Feature, Geometry, GeometryObject } from 'geojson';
2
2
  import Leaflet, { type Layer, type LayerGroup } from 'leaflet';
3
3
  import type { FunctionComponent } from 'preact';
4
- import { useEffect, useMemo, useRef } from 'preact/hooks';
4
+ import { useEffect, useRef } from 'preact/hooks';
5
5
 
6
- import { type GeoJsonFeatureProperties, type MapSource, useGeoJsonMap } from './useGeoJsonMap';
7
- import { type AggregateData } from '../../query/queryAggregateData';
6
+ import type { EnhancedGeoJsonFeatureProperties } from '../../query/computeMapLocationData';
8
7
  import { InfoHeadline1, InfoParagraph } from '../components/info';
9
- import { LoadingDisplay } from '../components/loading-display';
10
8
  import { Modal, useModalRef } from '../components/modal';
11
9
  import { formatProportion } from '../shared/table/formatProportion';
12
10
 
13
- type FeatureData = { proportion: number; count: number };
14
-
15
- type EnhancedGeoJsonFeatureProperties = GeoJsonFeatureProperties & {
16
- data: FeatureData | null;
17
- };
18
-
19
11
  type SequencesByLocationMapProps = {
20
- mapSource: MapSource;
21
- locationData: AggregateData;
12
+ locations: Feature<Geometry, EnhancedGeoJsonFeatureProperties>[];
13
+ totalCount: number;
14
+ countOfMatchedLocationData: number;
15
+ nullCount: number;
16
+ unmatchedLocations: string[];
22
17
  enableMapNavigation: boolean;
23
18
  lapisLocationField: string;
24
19
  zoom: number;
@@ -28,25 +23,11 @@ type SequencesByLocationMapProps = {
28
23
  };
29
24
 
30
25
  export const SequencesByLocationMap: FunctionComponent<SequencesByLocationMapProps> = ({
31
- mapSource,
32
- ...otherProps
33
- }) => {
34
- const { isLoading: isLoadingMap, geojsonData } = useGeoJsonMap(mapSource);
35
-
36
- if (isLoadingMap) {
37
- return <LoadingDisplay />;
38
- }
39
-
40
- return <SequencesByLocationMapInner geojsonData={geojsonData} {...otherProps} />;
41
- };
42
-
43
- type SequencesByLocationMapInnerProps = Omit<SequencesByLocationMapProps, 'mapSource'> & {
44
- geojsonData: FeatureCollection<GeometryObject, GeoJsonFeatureProperties>;
45
- };
46
-
47
- export const SequencesByLocationMapInner: FunctionComponent<SequencesByLocationMapInnerProps> = ({
48
- geojsonData,
49
- locationData,
26
+ locations,
27
+ totalCount,
28
+ countOfMatchedLocationData,
29
+ nullCount,
30
+ unmatchedLocations,
50
31
  enableMapNavigation,
51
32
  lapisLocationField,
52
33
  zoom,
@@ -56,22 +37,6 @@ export const SequencesByLocationMapInner: FunctionComponent<SequencesByLocationM
56
37
  }) => {
57
38
  const ref = useRef<HTMLDivElement>(null);
58
39
 
59
- const { locations, totalCount, countOfMatchedLocationData, unmatchedLocations } = useMemo(() => {
60
- const countAndProportionByCountry = buildLookupByLocationField(locationData, lapisLocationField);
61
- const { locations, unmatchedLocations } = matchLocationDataAndGeoJsonFeatures(
62
- geojsonData,
63
- countAndProportionByCountry,
64
- lapisLocationField,
65
- );
66
-
67
- const totalCount = locationData.map((value) => value.count).reduce((sum, b) => sum + b, 0);
68
- const countOfMatchedLocationData = locations
69
- .map((location) => location.properties.data?.count ?? 0)
70
- .reduce((sum, b) => sum + b, 0);
71
-
72
- return { locations, totalCount, countOfMatchedLocationData, unmatchedLocations };
73
- }, [geojsonData, locationData, lapisLocationField]);
74
-
75
40
  useEffect(() => {
76
41
  if (!ref.current) {
77
42
  return;
@@ -103,8 +68,6 @@ export const SequencesByLocationMapInner: FunctionComponent<SequencesByLocationM
103
68
  };
104
69
  }, [ref, locations, enableMapNavigation, lapisLocationField, zoom, offsetX, offsetY]);
105
70
 
106
- const nullCount = locationData.find((row) => row[lapisLocationField] === null)?.count ?? 0;
107
-
108
71
  return (
109
72
  <div className='h-full'>
110
73
  <div ref={ref} className='h-full' />
@@ -172,55 +135,6 @@ const DataMatchInformation: FunctionComponent<DataMatchInformationProps> = ({
172
135
  );
173
136
  };
174
137
 
175
- function buildLookupByLocationField(locationData: AggregateData, lapisLocationField: string) {
176
- return new Map<string, FeatureData>(
177
- locationData
178
- .filter((row) => typeof row[lapisLocationField] === 'string')
179
- .map((row) => [row[lapisLocationField] as string, row]),
180
- );
181
- }
182
-
183
- function matchLocationDataAndGeoJsonFeatures(
184
- geojsonData: FeatureCollection<GeometryObject, GeoJsonFeatureProperties>,
185
- countAndProportionByCountry: Map<string, FeatureData>,
186
- lapisLocationField: string,
187
- ) {
188
- const matchedLocations: string[] = [];
189
-
190
- const locations: Feature<GeometryObject, EnhancedGeoJsonFeatureProperties>[] = geojsonData.features.map(
191
- (feature) => {
192
- const name = feature?.properties?.name;
193
- if (typeof name !== 'string') {
194
- throw new Error(
195
- `GeoJSON feature with id '${feature.id}' does not have 'properties.name' of type string, was: '${name}'`,
196
- );
197
- }
198
-
199
- const data = countAndProportionByCountry.get(name) ?? null;
200
- if (data !== null) {
201
- matchedLocations.push(name);
202
- }
203
- return {
204
- ...feature,
205
- properties: {
206
- ...feature.properties,
207
- data,
208
- },
209
- };
210
- },
211
- );
212
-
213
- const unmatchedLocations = [...countAndProportionByCountry.keys()].filter(
214
- (name) => !matchedLocations.includes(name),
215
- );
216
- if (unmatchedLocations.length > 0) {
217
- const unmatchedLocationsWarning = `gs-map: Found location data from LAPIS (aggregated by "${lapisLocationField}") that could not be matched on locations on the given map. Unmatched location names are: ${unmatchedLocations.map((it) => `"${it}"`).join(', ')}`;
218
- console.warn(unmatchedLocationsWarning); // eslint-disable-line no-console -- We should give some feedback about unmatched location data.
219
- }
220
-
221
- return { locations, unmatchedLocations };
222
- }
223
-
224
138
  function getColor(value: number | undefined): string {
225
139
  if (value === undefined) {
226
140
  return '#DDDDDD';
@@ -1,18 +1,41 @@
1
1
  import { type FunctionComponent } from 'preact';
2
2
 
3
- import type { AggregateData } from '../../query/queryAggregateData';
4
- import { AggregateTable } from '../aggregatedData/aggregate-table';
3
+ import type { EnhancedLocationsTableData } from '../../query/computeMapLocationData';
4
+ import { type AggregateData, compareAscending } from '../../query/queryAggregateData';
5
+ import { Table } from '../components/table';
6
+ import { formatProportion } from '../shared/table/formatProportion';
5
7
 
6
8
  type SequencesByLocationTableProps = {
7
- locationData: AggregateData;
9
+ tableData: AggregateData | EnhancedLocationsTableData;
8
10
  lapisLocationField: string;
9
11
  pageSize: boolean | number;
10
12
  };
11
13
 
12
14
  export const SequencesByLocationTable: FunctionComponent<SequencesByLocationTableProps> = ({
13
- locationData,
15
+ tableData,
14
16
  lapisLocationField,
15
17
  pageSize,
16
18
  }) => {
17
- return <AggregateTable data={locationData} fields={[lapisLocationField]} pageSize={pageSize} />;
19
+ const headers = [
20
+ {
21
+ name: lapisLocationField,
22
+ sort: {
23
+ compare: compareAscending,
24
+ },
25
+ },
26
+ {
27
+ name: 'count',
28
+ sort: true,
29
+ },
30
+ {
31
+ name: 'proportion',
32
+ sort: true,
33
+ formatter: (cell: number) => formatProportion(cell),
34
+ },
35
+ ...('isShownOnMap' in tableData[0]
36
+ ? [{ id: 'isShownOnMap', name: 'shown on map', sort: true, width: '20%' }]
37
+ : []),
38
+ ];
39
+
40
+ return <Table data={tableData} columns={headers} pageSize={pageSize} />;
18
41
  };