@molgenis/vip-report-template 3.0.0-beta → 3.0.0-beta2

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@molgenis/vip-report-template",
3
- "version": "3.0.0-beta",
3
+ "version": "3.0.0-beta2",
4
4
  "description": "Report Template for Variant Call Format (VCF) Report Generator",
5
5
  "scripts": {
6
6
  "build": "vite build",
@@ -2,28 +2,54 @@ import { describe, expect, test } from "vitest";
2
2
  import { FieldMetadata } from "@molgenis/vip-report-vcf/src/MetadataParser";
3
3
  import { Metadata } from "@molgenis/vip-report-vcf/src/Vcf";
4
4
  import { FilterQueries } from "../store";
5
- import { createQuery } from "../utils/query";
6
- import { QueryClause } from "@molgenis/vip-report-api/src/Api";
5
+ import {
6
+ createQuery,
7
+ infoFieldKey,
8
+ infoSelector,
9
+ infoSortPath,
10
+ sampleFieldKey,
11
+ sampleSelector,
12
+ selectorKey,
13
+ } from "../utils/query";
14
+ import { Person, QueryClause } from "@molgenis/vip-report-api/src/Api";
7
15
 
8
16
  describe("query utilities", () => {
17
+ let fieldMetaCsq: FieldMetadata = {
18
+ id: "CSQ",
19
+ number: { type: "NUMBER" },
20
+ type: "STRING",
21
+ };
22
+
9
23
  const fieldMeta1: FieldMetadata = {
10
24
  id: "field1",
11
25
  number: { type: "NUMBER" },
12
26
  type: "CATEGORICAL",
27
+ parent: fieldMetaCsq,
13
28
  };
29
+
14
30
  const fieldMeta2: FieldMetadata = {
15
31
  id: "field2",
16
32
  number: { type: "NUMBER" },
17
33
  type: "CATEGORICAL",
34
+ parent: fieldMetaCsq,
18
35
  };
19
36
 
20
- const fieldMetaCsq: FieldMetadata = {
37
+ fieldMetaCsq = {
21
38
  id: "CSQ",
22
39
  number: { type: "NUMBER" },
23
40
  type: "STRING",
24
41
  nested: { items: [fieldMeta1, fieldMeta2], separator: "|" },
25
42
  };
26
43
 
44
+ const person: Person = {
45
+ familyId: "FAM001",
46
+ individualId: "Patient",
47
+ sex: "FEMALE",
48
+ affectedStatus: "AFFECTED",
49
+ maternalId: "Mother",
50
+ paternalId: "Father",
51
+ };
52
+
27
53
  const meta: Metadata = { info: { CSQ: fieldMetaCsq } } as unknown as Metadata;
28
54
 
29
55
  test("create query", () => {
@@ -96,4 +122,35 @@ describe("query utilities", () => {
96
122
  };
97
123
  expect(createQuery(undefined, filterQueries, meta)).toBe(queryClause);
98
124
  });
125
+
126
+ test("infoSelector", () => {
127
+ expect(infoSelector(fieldMeta1)).toStrictEqual(["n", "CSQ", "field1"]);
128
+ });
129
+
130
+ test("sampleSelector", () => {
131
+ expect(sampleSelector({ id: 1, data: { person: person, index: 0, proband: false } }, fieldMeta1)).toStrictEqual([
132
+ "s",
133
+ 0,
134
+ "CSQ",
135
+ "field1",
136
+ ]);
137
+ });
138
+
139
+ test("selectorKey", () => {
140
+ expect(selectorKey([1, "test", 2, "3"])).toStrictEqual("1/test/2/3");
141
+ });
142
+
143
+ test("infoFieldKey", () => {
144
+ expect(infoFieldKey(fieldMeta1)).toStrictEqual("n/CSQ/field1");
145
+ });
146
+
147
+ test("sampleFieldKey", () => {
148
+ expect(sampleFieldKey({ id: 1, data: { person: person, index: 0, proband: false } }, fieldMeta1)).toStrictEqual(
149
+ "s/0/CSQ/field1"
150
+ );
151
+ });
152
+
153
+ test("infoSortPath", () => {
154
+ expect(infoSortPath(fieldMetaCsq)).toStrictEqual(["n", "CSQ"]);
155
+ });
99
156
  });
@@ -1,14 +1,18 @@
1
1
  import { Component, createSignal, For } from "solid-js";
2
2
  import api from "../Api";
3
3
  import { useNavigate } from "solid-app-router";
4
+ import { useStore } from "../store";
4
5
 
5
6
  export const DatasetDropdown: Component = () => {
7
+ const [, actions] = useStore();
8
+
6
9
  const navigate = useNavigate();
7
10
  const [selectedDataset, setSelectedDataset] = createSignal("GRCh37 Family");
8
11
 
9
12
  function switchIt(datasetName: string) {
10
13
  setSelectedDataset(datasetName);
11
14
  api.selectDataset(datasetName);
15
+ actions.reset();
12
16
  (async () => {
13
17
  navigate(`/`);
14
18
  const samples = await api.getSamples({ query: { selector: ["proband"], operator: "==", args: true } });
@@ -15,19 +15,22 @@ export const Filter: Component<{
15
15
  onChange: (event: FilterChangeEvent) => void;
16
16
  onClear: (event: FilterClearEvent) => void;
17
17
  }> = (props) => {
18
+ const onChange = (event: FilterChangeEvent) => props.onChange(event);
19
+ const onClear = (event: FilterClearEvent) => props.onClear(event);
20
+
18
21
  return (
19
22
  <Switch>
20
23
  <Match when={props.field.id === "DP"}>
21
- <FilterIntegerDp field={props.field} onChange={props.onChange} onClear={props.onClear} query={props.query} />
24
+ <FilterIntegerDp field={props.field} onChange={onChange} onClear={onClear} query={props.query} />
22
25
  </Match>
23
26
  <Match when={props.field.id === "VID"}>
24
- <FilterIntegerVid field={props.field} onChange={props.onChange} onClear={props.onClear} query={props.query} />
27
+ <FilterIntegerVid field={props.field} onChange={onChange} onClear={onClear} query={props.query} />
25
28
  </Match>
26
29
  <Match when={props.field.id === "VIM"}>
27
- <FilterIntegerVim field={props.field} onChange={props.onChange} onClear={props.onClear} query={props.query} />
30
+ <FilterIntegerVim field={props.field} onChange={onChange} onClear={onClear} query={props.query} />
28
31
  </Match>
29
32
  <Match when={props.field.type === "CATEGORICAL"}>
30
- <FilterCategorical field={props.field} onChange={props.onChange} onClear={props.onClear} query={props.query} />
33
+ <FilterCategorical field={props.field} onChange={onChange} onClear={onClear} query={props.query} />
31
34
  </Match>
32
35
  </Switch>
33
36
  );
@@ -13,14 +13,17 @@ export const Filters: Component<{
13
13
  onChange: (event: FilterChangeEvent) => void;
14
14
  onClear: (event: FilterClearEvent) => void;
15
15
  }> = (props) => {
16
+ const onChange = (event: FilterChangeEvent) => props.onChange(event);
17
+ const onClear = (event: FilterClearEvent) => props.onClear(event);
18
+
16
19
  return (
17
20
  <>
18
- <InfoFilters fields={props.fields} queries={props.queries} onChange={props.onChange} onClear={props.onClear} />
21
+ <InfoFilters fields={props.fields} queries={props.queries} onChange={onChange} onClear={onClear} />
19
22
  <SamplesFilters
20
23
  samplesFields={props.samplesFields}
21
24
  queries={props.queries}
22
- onChange={props.onChange}
23
- onClear={props.onClear}
25
+ onChange={onChange}
26
+ onClear={onClear}
24
27
  />
25
28
  </>
26
29
  );
@@ -14,15 +14,15 @@ type AppStateVariants = {
14
14
  sort?: SortOrder | null; // null: do not sort. undefined: sort undefined
15
15
  };
16
16
 
17
- // TODO clear store on dataset change
18
17
  export type AppState = {
19
- variants: AppStateVariants;
20
- samples: {
21
- [key: string]: { variants: AppStateVariants };
18
+ variants?: AppStateVariants;
19
+ samples?: {
20
+ [key: number]: { variants: AppStateVariants };
22
21
  };
23
22
  };
24
23
 
25
24
  export type AppActions = {
25
+ reset(): void;
26
26
  setVariantsPage(page: number): void;
27
27
  setVariantsPageSize(pageSize: number): void;
28
28
  setVariantsSearchQuery(searchQuery: string): void;
@@ -49,58 +49,64 @@ export const Provider: ParentComponent = (props) => {
49
49
  const [state, setState] = createStore(defaultState);
50
50
 
51
51
  function getVariants(sample: Item<Sample>) {
52
- return state.samples[sample.id]?.variants || {};
52
+ return state.samples ? state.samples[sample.id]?.variants || {} : {};
53
53
  }
54
54
 
55
55
  const actions: AppActions = {
56
+ reset() {
57
+ setState({ variants: undefined, samples: undefined });
58
+ },
56
59
  setVariantsPage(page: number) {
57
- setState({ variants: { ...state.variants, page } });
60
+ setState({ variants: { ...(state.variants || {}), page } });
58
61
  },
59
62
  setVariantsPageSize(pageSize: number) {
60
- setState({ variants: { ...state.variants, pageSize } });
63
+ setState({ variants: { ...(state.variants || {}), pageSize } });
61
64
  },
62
65
  setVariantsSearchQuery(searchQuery: string) {
63
- setState({ variants: { ...state.variants, searchQuery } });
66
+ setState({ variants: { ...(state.variants || {}), searchQuery } });
64
67
  },
65
68
  clearVariantsSearchQuery() {
66
- setState({ variants: { ...state.variants, searchQuery: undefined } });
69
+ setState({ variants: { ...(state.variants || {}), searchQuery: undefined } });
67
70
  },
68
71
  setVariantsFilterQuery(query: QueryClause) {
69
72
  setState({
70
73
  variants: {
71
- ...state.variants,
72
- filterQueries: { ...(state.variants.filterQueries || {}), [selectorKey(query.selector)]: query },
74
+ ...(state.variants || {}),
75
+ filterQueries: { ...(state.variants?.filterQueries || {}), [selectorKey(query.selector)]: query },
73
76
  },
74
77
  });
75
78
  },
76
79
  clearVariantsFilterQuery(selector: Selector) {
77
80
  setState({
78
81
  variants: {
79
- ...state.variants,
80
- filterQueries: { ...(state.variants.filterQueries || {}), [selectorKey(selector)]: undefined },
82
+ ...(state.variants || {}),
83
+ filterQueries: { ...(state.variants?.filterQueries || {}), [selectorKey(selector)]: undefined },
81
84
  },
82
85
  });
83
86
  },
84
87
  setVariantsSort(sort: SortOrder | null) {
85
88
  setState({
86
89
  variants: {
87
- ...state.variants,
90
+ ...(state.variants || {}),
88
91
  sort,
89
92
  },
90
93
  });
91
94
  },
92
95
  setSampleVariantsPage(sample: Item<Sample>, page: number) {
93
- setState({ samples: { ...state.samples, [sample.id]: { variants: { ...getVariants(sample), page } } } });
96
+ setState({ samples: { ...(state.samples || {}), [sample.id]: { variants: { ...getVariants(sample), page } } } });
94
97
  },
95
98
  setSampleVariantsPageSize(sample: Item<Sample>, pageSize: number) {
96
99
  setState({
97
- samples: { ...state.samples, [sample.id]: { variants: { ...getVariants(sample), pageSize, page: undefined } } },
100
+ samples: {
101
+ ...(state.samples || {}),
102
+ [sample.id]: { variants: { ...getVariants(sample), pageSize, page: undefined } },
103
+ },
98
104
  });
99
105
  },
100
106
  setSampleVariantsSearchQuery(sample: Item<Sample>, searchQuery: string) {
101
107
  setState({
102
108
  samples: {
103
- ...state.samples,
109
+ ...(state.samples || {}),
104
110
  [sample.id]: { variants: { ...getVariants(sample), searchQuery, page: undefined } },
105
111
  },
106
112
  });
@@ -108,7 +114,7 @@ export const Provider: ParentComponent = (props) => {
108
114
  clearSampleVariantsSearchQuery(sample: Item<Sample>) {
109
115
  setState({
110
116
  samples: {
111
- ...state.samples,
117
+ ...(state.samples || {}),
112
118
  [sample.id]: { variants: { ...getVariants(sample), searchQuery: undefined, page: undefined } },
113
119
  },
114
120
  });
@@ -117,7 +123,7 @@ export const Provider: ParentComponent = (props) => {
117
123
  const variants = getVariants(sample);
118
124
  setState({
119
125
  samples: {
120
- ...state.samples,
126
+ ...(state.samples || {}),
121
127
  [sample.id]: {
122
128
  variants: {
123
129
  ...variants,
@@ -132,7 +138,7 @@ export const Provider: ParentComponent = (props) => {
132
138
  const variants = getVariants(sample);
133
139
  setState({
134
140
  samples: {
135
- ...state.samples,
141
+ ...(state.samples || {}),
136
142
  [sample.id]: {
137
143
  variants: {
138
144
  ...getVariants(sample),
@@ -145,7 +151,7 @@ export const Provider: ParentComponent = (props) => {
145
151
  },
146
152
  setSampleVariantsSort(sample: Item<Sample>, sort: SortOrder | null) {
147
153
  setState({
148
- samples: { ...state.samples, [sample.id]: { variants: { ...getVariants(sample), sort } } },
154
+ samples: { ...(state.samples || {}), [sample.id]: { variants: { ...getVariants(sample), sort } } },
149
155
  });
150
156
  },
151
157
  };
@@ -56,15 +56,19 @@ export const SampleVariants: Component<{
56
56
  }> = (props) => {
57
57
  const [state, actions] = useStore();
58
58
 
59
+ function getStateVariants() {
60
+ return state.samples ? state.samples[props.sample.id]?.variants : undefined;
61
+ }
62
+
59
63
  // state initialization - start
60
- if (state.samples[props.sample.id]?.variants?.page === undefined) {
64
+ if (getStateVariants()?.page === undefined) {
61
65
  actions.setSampleVariantsPage(props.sample, 0);
62
66
  }
63
- if (state.samples[props.sample.id]?.variants?.pageSize === undefined) {
67
+ if (getStateVariants()?.pageSize === undefined) {
64
68
  actions.setSampleVariantsPageSize(props.sample, 20);
65
69
  }
66
70
 
67
- if (state.samples[props.sample.id]?.variants?.filterQueries === undefined) {
71
+ if (getStateVariants()?.filterQueries === undefined) {
68
72
  const hpoField = props.recordsMeta.info?.CSQ?.nested?.items?.find((field) => field.id === "HPO");
69
73
  if (hpoField) {
70
74
  actions.setSampleVariantsFilterQuery(props.sample, {
@@ -92,7 +96,7 @@ export const SampleVariants: Component<{
92
96
  }
93
97
  }
94
98
 
95
- if (state.samples[props.sample.id]?.variants?.sort === undefined) {
99
+ if (getStateVariants()?.sort === undefined) {
96
100
  const capiceScField = props.recordsMeta.info?.CSQ?.nested?.items?.find((field) => field.id === "CAPICE_SC");
97
101
  if (capiceScField) {
98
102
  actions.setSampleVariantsSort(props.sample, {
@@ -137,11 +141,11 @@ export const SampleVariants: Component<{
137
141
  : [];
138
142
  });
139
143
 
140
- const page = () => state.samples[props.sample.id]?.variants?.page;
141
- const pageSize = () => state.samples[props.sample.id]?.variants?.pageSize;
142
- const searchQuery = () => state.samples[props.sample.id]?.variants?.searchQuery;
143
- const filterQueries = () => state.samples[props.sample.id]?.variants?.filterQueries;
144
- const sort = () => state.samples[props.sample.id]?.variants?.sort;
144
+ const page = () => getStateVariants()?.page;
145
+ const pageSize = () => getStateVariants()?.pageSize;
146
+ const searchQuery = () => getStateVariants()?.searchQuery;
147
+ const filterQueries = () => getStateVariants()?.filterQueries;
148
+ const sort = () => getStateVariants()?.sort;
145
149
 
146
150
  const onPageChange = (page: number) => actions.setSampleVariantsPage(props.sample, page);
147
151
  const onSearchChange = (search: string) => actions.setSampleVariantsSearchQuery(props.sample, search);
@@ -35,11 +35,11 @@ export const Variants: Component<{
35
35
  }> = (props) => {
36
36
  const [state, actions] = useStore();
37
37
 
38
- const page = () => state.variants.page;
39
- const pageSize = () => state.variants.pageSize;
40
- const searchQuery = () => state.variants.searchQuery;
41
- const filterQueries = () => state.variants.filterQueries;
42
- const sort = () => state.variants.sort;
38
+ const page = () => state.variants?.page;
39
+ const pageSize = () => state.variants?.pageSize;
40
+ const searchQuery = () => state.variants?.searchQuery;
41
+ const filterQueries = () => state.variants?.filterQueries;
42
+ const sort = () => state.variants?.sort;
43
43
 
44
44
  const onPageChange = (page: number) => actions.setVariantsPage(page);
45
45
  const onSearchChange = (search: string) => actions.setVariantsSearchQuery(search);