@genspectrum/dashboard-components 0.11.4 → 0.11.6

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 (28) hide show
  1. package/custom-elements.json +54 -3
  2. package/dist/assets/{mutationOverTimeWorker-Cr-NmYEs.js.map → mutationOverTimeWorker-CWneD7i5.js.map} +1 -1
  3. package/dist/components.d.ts +29 -15
  4. package/dist/components.js +184 -55
  5. package/dist/components.js.map +1 -1
  6. package/dist/style.css +5 -5
  7. package/dist/util.d.ts +21 -18
  8. package/package.json +1 -1
  9. package/src/preact/aggregatedData/__mockData__/aggregatedWith1Field.json +399 -0
  10. package/src/preact/aggregatedData/__mockData__/aggregatedWith2Fields.json +1771 -0
  11. package/src/preact/aggregatedData/aggregate-bar-chart.tsx +177 -0
  12. package/src/preact/aggregatedData/aggregate-table.tsx +24 -2
  13. package/src/preact/aggregatedData/aggregate.stories.tsx +61 -2
  14. package/src/preact/aggregatedData/aggregate.tsx +18 -6
  15. package/src/preact/components/tabs.tsx +19 -39
  16. package/src/preact/mutationsOverTime/mutations-over-time-grid.tsx +1 -1
  17. package/src/preact/shared/charts/colors.ts +1 -1
  18. package/src/query/queryAggregateData.spec.ts +16 -109
  19. package/src/query/queryAggregateData.ts +2 -12
  20. package/src/query/queryGeneralStatistics.ts +2 -2
  21. package/src/utils/temporal.spec.ts +62 -8
  22. package/src/utils/temporalClass.ts +1 -8
  23. package/src/web-components/visualization/gs-aggregate.stories.ts +90 -20
  24. package/src/web-components/visualization/gs-aggregate.tsx +20 -0
  25. package/standalone-bundle/assets/{mutationOverTimeWorker-DIQRmxvC.js.map → mutationOverTimeWorker-x1ipPFL0.js.map} +1 -1
  26. package/standalone-bundle/dashboard-components.js +3771 -3651
  27. package/standalone-bundle/dashboard-components.js.map +1 -1
  28. package/standalone-bundle/style.css +1 -1
@@ -68,15 +68,69 @@ describe('YearMonthDay', () => {
68
68
  });
69
69
 
70
70
  describe('YearWeek', () => {
71
- it('should parse from string', () => {
72
- const underTest = YearWeekClass.parse('2020-W02', cache);
71
+ const examples = [
72
+ {
73
+ string: '2020-W01',
74
+ expectedYear: 2020,
75
+ expectedWeek: 1,
76
+ expectedFirstDay: '2019-12-30',
77
+ expectedLastDay: '2020-01-05',
78
+ expectedText: '2020-W01',
79
+ },
80
+ {
81
+ string: '2020-W53',
82
+ expectedYear: 2020,
83
+ expectedWeek: 53,
84
+ expectedFirstDay: '2020-12-28',
85
+ expectedLastDay: '2021-01-03',
86
+ expectedText: '2020-W53',
87
+ },
88
+ {
89
+ string: '2021-W01',
90
+ expectedYear: 2021,
91
+ expectedWeek: 1,
92
+ expectedFirstDay: '2021-01-04',
93
+ expectedLastDay: '2021-01-10',
94
+ expectedText: '2021-W01',
95
+ },
96
+ {
97
+ string: '2021-W53',
98
+ expectedYear: 2021,
99
+ expectedWeek: 53,
100
+ expectedFirstDay: '2022-01-03',
101
+ expectedLastDay: '2022-01-09',
102
+ expectedText: '2022-W01',
103
+ },
104
+ {
105
+ string: '2022-W01',
106
+ expectedYear: 2022,
107
+ expectedWeek: 1,
108
+ expectedFirstDay: '2022-01-03',
109
+ expectedLastDay: '2022-01-09',
110
+ expectedText: '2022-W01',
111
+ },
112
+ {
113
+ string: '2024-W01',
114
+ expectedYear: 2024,
115
+ expectedWeek: 1,
116
+ expectedFirstDay: '2024-01-01',
117
+ expectedLastDay: '2024-01-07',
118
+ expectedText: '2024-W01',
119
+ },
120
+ ];
73
121
 
74
- expect(underTest.isoYearNumber).equal(2020);
75
- expect(underTest.isoWeekNumber).equal(2);
76
- expect(underTest.firstDay.text).equal('2020-01-06');
77
- expect(underTest.text).equal('2020-W02');
78
- expect(underTest.lastDay.text).equal('2020-01-12');
79
- });
122
+ for (const example of examples) {
123
+ const { string, expectedYear, expectedWeek, expectedFirstDay, expectedLastDay, expectedText } = example;
124
+ it(`should parse ${string} from string`, () => {
125
+ const underTest = YearWeekClass.parse(string, cache);
126
+
127
+ expect(underTest.isoYearNumber).equal(expectedYear);
128
+ expect(underTest.isoWeekNumber).equal(expectedWeek);
129
+ expect(underTest.firstDay.text).equal(expectedFirstDay);
130
+ expect(underTest.text).equal(expectedText);
131
+ expect(underTest.lastDay.text).equal(expectedLastDay);
132
+ });
133
+ }
80
134
  });
81
135
 
82
136
  describe('YearMonth', () => {
@@ -171,14 +171,7 @@ export class YearWeekClass implements YearWeek {
171
171
  }
172
172
 
173
173
  get lastDay(): YearMonthDayClass {
174
- const firstDay = dayjs()
175
- .year(this.isoYearNumber)
176
- .startOf('year')
177
- .add((this.isoWeekNumber - 1) * 7, 'day')
178
- .startOf('week')
179
- .add(1, 'day');
180
- const lastDay = firstDay.add(6, 'day');
181
-
174
+ const lastDay = this.firstDay.dayjs.add(6, 'days');
182
175
  return this.cache.getYearMonthDay(lastDay.format('YYYY-MM-DD'));
183
176
  }
184
177
 
@@ -4,6 +4,8 @@ import { html } from 'lit';
4
4
  import { withComponentDocs } from '../../../.storybook/ComponentDocsBlock';
5
5
  import { AGGREGATED_ENDPOINT, LAPIS_URL } from '../../constants';
6
6
  import aggregatedData from '../../preact/aggregatedData/__mockData__/aggregated.json';
7
+ import aggregatedDataWith1Field from '../../preact/aggregatedData/__mockData__/aggregatedWith1Field.json';
8
+ import aggregatedDataWith2Fields from '../../preact/aggregatedData/__mockData__/aggregatedWith2Fields.json';
7
9
  import type { AggregateProps } from '../../preact/aggregatedData/aggregate';
8
10
 
9
11
  import './gs-aggregate';
@@ -19,6 +21,7 @@ const codeExample = `
19
21
  initialSortField="count"
20
22
  initialSortDirection="descending"
21
23
  pageSize="10"
24
+ maxNumberOfBars="50"
22
25
  ></gs-aggregate>`;
23
26
 
24
27
  const meta: Meta<Required<AggregateProps>> = {
@@ -27,7 +30,7 @@ const meta: Meta<Required<AggregateProps>> = {
27
30
  argTypes: {
28
31
  fields: [{ control: 'object' }],
29
32
  views: {
30
- options: ['table'],
33
+ options: ['table', 'bar'],
31
34
  control: { type: 'check' },
32
35
  },
33
36
  width: { control: 'text' },
@@ -40,24 +43,6 @@ const meta: Meta<Required<AggregateProps>> = {
40
43
  },
41
44
  },
42
45
  parameters: withComponentDocs({
43
- fetchMock: {
44
- mocks: [
45
- {
46
- matcher: {
47
- name: 'aggregatedData',
48
- url: AGGREGATED_ENDPOINT,
49
- body: {
50
- fields: ['division', 'host'],
51
- country: 'USA',
52
- },
53
- },
54
- response: {
55
- status: 200,
56
- body: aggregatedData,
57
- },
58
- },
59
- ],
60
- },
61
46
  componentDocs: {
62
47
  opensShadowDom: true,
63
48
  expectsChildren: false,
@@ -81,12 +66,33 @@ export const Table: StoryObj<Required<AggregateProps>> = {
81
66
  .initialSortField=${args.initialSortField}
82
67
  .initialSortDirection=${args.initialSortDirection}
83
68
  .pageSize=${args.pageSize}
69
+ .maxNumberOfBars=${args.maxNumberOfBars}
84
70
  ></gs-aggregate>
85
71
  </gs-app>
86
72
  `,
73
+ parameters: {
74
+ fetchMock: {
75
+ mocks: [
76
+ {
77
+ matcher: {
78
+ name: 'aggregatedData',
79
+ url: AGGREGATED_ENDPOINT,
80
+ body: {
81
+ fields: ['division', 'host'],
82
+ country: 'USA',
83
+ },
84
+ },
85
+ response: {
86
+ status: 200,
87
+ body: aggregatedData,
88
+ },
89
+ },
90
+ ],
91
+ },
92
+ },
87
93
  args: {
88
94
  fields: ['division', 'host'],
89
- views: ['table'],
95
+ views: ['table', 'bar'],
90
96
  lapisFilter: {
91
97
  country: 'USA',
92
98
  },
@@ -95,5 +101,69 @@ export const Table: StoryObj<Required<AggregateProps>> = {
95
101
  initialSortField: 'count',
96
102
  initialSortDirection: 'descending',
97
103
  pageSize: 10,
104
+ maxNumberOfBars: 10,
105
+ },
106
+ };
107
+
108
+ export const BarChartWithOneField: StoryObj<Required<AggregateProps>> = {
109
+ ...Table,
110
+ args: {
111
+ ...Table.args,
112
+ fields: ['division'],
113
+ views: ['bar', 'table'],
114
+ },
115
+ parameters: {
116
+ fetchMock: {
117
+ mocks: [
118
+ {
119
+ matcher: {
120
+ name: 'aggregatedData',
121
+ url: AGGREGATED_ENDPOINT,
122
+ body: {
123
+ fields: ['division'],
124
+ country: 'USA',
125
+ },
126
+ },
127
+ response: {
128
+ status: 200,
129
+ body: aggregatedDataWith1Field,
130
+ },
131
+ },
132
+ ],
133
+ },
134
+ },
135
+ };
136
+
137
+ export const BarChartWithTwoFields: StoryObj<Required<AggregateProps>> = {
138
+ ...Table,
139
+ args: {
140
+ ...Table.args,
141
+ fields: ['division', 'nextstrainClade'],
142
+ lapisFilter: {
143
+ country: 'Germany',
144
+ dateTo: '2022-02-01',
145
+ },
146
+ views: ['bar', 'table'],
147
+ },
148
+ parameters: {
149
+ fetchMock: {
150
+ mocks: [
151
+ {
152
+ matcher: {
153
+ name: 'aggregatedData',
154
+ url: AGGREGATED_ENDPOINT,
155
+ body: {
156
+ fields: ['division', 'nextstrainClade'],
157
+ country: 'Germany',
158
+ dateTo: '2022-02-01',
159
+ },
160
+ },
161
+ response: {
162
+ status: 200,
163
+ body: aggregatedDataWith2Fields,
164
+ },
165
+ },
166
+ ],
167
+ },
98
168
  },
99
169
  };
@@ -20,6 +20,16 @@ import { PreactLitAdapterWithGridJsStyles } from '../PreactLitAdapterWithGridJsS
20
20
  * along with the aggregated value and its proportion.
21
21
  * The proportion represents the ratio of the aggregated value to the total count of the data
22
22
  * (considering the applied filter).
23
+ *
24
+ * ### Bar Chart View
25
+ *
26
+ * In the bar chart view, the data is presented in vertical bars.
27
+ * The bar chart is supported when `fields` contains one or two entries.
28
+ * The first field will be used as the y-axis.
29
+ * If a second field is provided, it's values will be stacked along the x-axis for each key on the y-axis.
30
+ *
31
+ * The chart shows the bars with the highest aggregated `count`.
32
+ * The number of bars can be adjusted with the `maxNumberOfBars` property.
23
33
  */
24
34
  @customElement('gs-aggregate')
25
35
  export class AggregateComponent extends PreactLitAdapterWithGridJsStyles {
@@ -87,6 +97,12 @@ export class AggregateComponent extends PreactLitAdapterWithGridJsStyles {
87
97
  @property({ type: Object })
88
98
  pageSize: boolean | number = false;
89
99
 
100
+ /**
101
+ * The maximum number of bars to display in the bar chart view.
102
+ */
103
+ @property({ type: Object })
104
+ maxNumberOfBars: number = 20;
105
+
90
106
  override render() {
91
107
  return (
92
108
  <Aggregate
@@ -98,6 +114,7 @@ export class AggregateComponent extends PreactLitAdapterWithGridJsStyles {
98
114
  initialSortField={this.initialSortField}
99
115
  initialSortDirection={this.initialSortDirection}
100
116
  pageSize={this.pageSize}
117
+ maxNumberOfBars={this.maxNumberOfBars}
101
118
  />
102
119
  );
103
120
  }
@@ -131,4 +148,7 @@ type InitialSortDirectionMatches = Expect<
131
148
  Equals<typeof AggregateComponent.prototype.initialSortDirection, AggregateProps['initialSortDirection']>
132
149
  >;
133
150
  type PageSizeMatches = Expect<Equals<typeof AggregateComponent.prototype.pageSize, AggregateProps['pageSize']>>;
151
+ type MaxNumberOfBarsMatches = Expect<
152
+ Equals<typeof AggregateComponent.prototype.maxNumberOfBars, AggregateProps['maxNumberOfBars']>
153
+ >;
134
154
  /* eslint-enable @typescript-eslint/no-unused-vars, no-unused-vars */