@molgenis/vip-report-template 5.1.5 → 5.2.0

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": "5.1.5",
3
+ "version": "5.2.0",
4
4
  "description": "Report Template for Variant Call Format (VCF) Report Generator",
5
5
  "scripts": {
6
6
  "build": "vite build",
@@ -116,4 +116,8 @@ table.is-borderless td,
116
116
  transform: translateX(-50%) translateX(-1px) !important;
117
117
  border-left-width: 2px !important;
118
118
  border-right-width: 2px !important;
119
+ }
120
+
121
+ .inline-control-text {
122
+ line-height: 32.5px
119
123
  }
@@ -0,0 +1,29 @@
1
+ import { Component, For } from "solid-js";
2
+ export type RecordsPerPageEvent = { number: number };
3
+
4
+ export const RecordsPerPage: Component<{
5
+ initialValue: number;
6
+ onChange: (event: RecordsPerPageEvent) => void;
7
+ }> = (props) => {
8
+ const options = [10, 20, 50, 100];
9
+ const onRecordsPerPageChange = (event: Event) => {
10
+ props.onChange({ number: Number((event.target as HTMLInputElement).value) });
11
+ };
12
+
13
+ return (
14
+ <div class="control">
15
+ <span class="inline-control-text mr-2">Records per page</span>
16
+ <div class="select">
17
+ <select onChange={onRecordsPerPageChange}>
18
+ <For each={options}>
19
+ {(option) => (
20
+ <option value={option} selected={option == props.initialValue}>
21
+ {option}
22
+ </option>
23
+ )}
24
+ </For>
25
+ </select>
26
+ </div>
27
+ </div>
28
+ );
29
+ };
@@ -32,26 +32,20 @@ export const Sort: Component<{
32
32
  };
33
33
 
34
34
  return (
35
- <div class="field is-horizontal">
36
- <div class="field-label is-normal">
37
- <label class="label">Sort by:</label>
38
- </div>
39
- <div class="field-body">
40
- <div class="field">
41
- <div class="select">
42
- <select onChange={onSortChange}>
43
- <option value="-1">Position</option>
44
- <For each={sortableOptions()}>
45
- {(option, i) => (
46
- <option value={i()} selected={option.selected === true}>
47
- {option.order.field.label || option.order.field.id}{" "}
48
- {option.order.direction === DIRECTION_ASCENDING ? "(ascending)" : "(descending)"}
49
- </option>
50
- )}
51
- </For>
52
- </select>
53
- </div>
54
- </div>
35
+ <div class="control">
36
+ <span class="inline-control-text mr-2">Sort by</span>
37
+ <div class="select">
38
+ <select onChange={onSortChange}>
39
+ <option value="-1">{"Position"}</option>
40
+ <For each={sortableOptions()}>
41
+ {(option, i) => (
42
+ <option value={i()} selected={option.selected === true}>
43
+ {option.order.field.label || option.order.field.id}{" "}
44
+ {option.order.direction === DIRECTION_ASCENDING ? "(ascending)" : "(descending)"}
45
+ </option>
46
+ )}
47
+ </For>
48
+ </select>
55
49
  </div>
56
50
  </div>
57
51
  );
@@ -71,7 +71,7 @@ export const FilterAllelicBalance: Component<{
71
71
  return (
72
72
  <div class="control">
73
73
  <Checkbox
74
- desc="Filter variants with allelic imbalance; For hetrozygote calls: AB < 0.2 or AB > 0.8 and for homozygote calls: AB > 0.02 are consided allelic imbalance"
74
+ desc="Filter variants with allelic imbalance; For hetrozygote calls: AB < 0.2 or AB > 0.8 and for homozygote calls: AB > 0.02 are considered allelic imbalance"
75
75
  label="No allelic imbalance"
76
76
  checked={props.query && props.query.args !== undefined}
77
77
  onChange={onFilterChange}
@@ -13,7 +13,7 @@ export const FilterIntegerDp: Component<FilterProps> = (props) => {
13
13
  query: {
14
14
  selector: fieldSelector,
15
15
  operator: ">=",
16
- args: 10,
16
+ args: 20,
17
17
  },
18
18
  });
19
19
  else props.onClear({ key: selectorKey(fieldSelector) });
@@ -22,9 +22,9 @@ export const FilterIntegerDp: Component<FilterProps> = (props) => {
22
22
  return (
23
23
  <div class="control">
24
24
  <Checkbox
25
- desc="Sequencing depth >= 10"
26
- label="Depth >= 10"
27
- checked={props.query && props.query.args === 10}
25
+ desc="Sequencing depth >= 20"
26
+ label="Depth >= 20"
27
+ checked={props.query && props.query.args === 20}
28
28
  onChange={onFilterChange}
29
29
  />
30
30
  </div>
@@ -10,6 +10,7 @@ import { GnomAD } from "./info/GnomAD";
10
10
  import { isAnyCsqInfo, isCsqInfo } from "../../utils/csqUtils";
11
11
  import { Vkgl } from "./info/Vkgl";
12
12
  import { InheritanceModes } from "./info/InheritanceModes";
13
+ import { Hpo } from "./info/Hpo";
13
14
 
14
15
  export const Info: Component<{
15
16
  info: FieldValue;
@@ -42,6 +43,9 @@ export const Info: Component<{
42
43
  <Match when={isCsqInfo(props.infoMeta, "VKGL_CL")}>
43
44
  <Vkgl {...props} />
44
45
  </Match>
46
+ <Match when={isCsqInfo(props.infoMeta, "HPO")}>
47
+ <Hpo {...props} />
48
+ </Match>
45
49
  </Switch>
46
50
  );
47
51
  };
@@ -0,0 +1,36 @@
1
+ import { Component, createMemo, For, Show } from "solid-js";
2
+ import { Anchor } from "../../Anchor";
3
+ import { FieldProps } from "../field/Field";
4
+ import { ValueFlag, ValueString } from "@molgenis/vip-report-vcf/src/ValueParser";
5
+ import { getCsqInfo, getCsqInfoIndex } from "../../../utils/csqUtils";
6
+ import { Abbr } from "../../Abbr";
7
+ import { FieldSingleValue } from "../field/FieldSingleValue";
8
+ import { FieldValueString } from "../field/FieldValueString";
9
+
10
+ type HpoTerm = {
11
+ id: string;
12
+ href: string;
13
+ };
14
+
15
+ export const Hpo: Component<FieldProps> = (props) => {
16
+ const hpoTerms = (): HpoTerm[] =>
17
+ (props.info.value as string[]).map((hpoTermId) => ({
18
+ id: hpoTermId,
19
+ href: `https://hpo.jax.org/app/browse/term/${encodeURI(hpoTermId)}`,
20
+ }));
21
+
22
+ return (
23
+ <>
24
+ <For each={hpoTerms()}>
25
+ {(hpoTerm, i) => (
26
+ <>
27
+ {i() !== 0 && <span>, </span>}
28
+ <Anchor href={hpoTerm.href}>
29
+ <FieldValueString value={hpoTerm.id} />
30
+ </Anchor>
31
+ </>
32
+ )}
33
+ </For>
34
+ </>
35
+ );
36
+ };
@@ -25,6 +25,7 @@ import { Metadata } from "@molgenis/vip-report-vcf/src/Vcf";
25
25
  import { getSampleLabel } from "../utils/sample";
26
26
  import { arrayEquals } from "../utils/utils";
27
27
  import { getAllelicBalanceQuery } from "../components/filter/FilterAllelicBalance";
28
+ import { RecordsPerPage, RecordsPerPageEvent } from "../components/RecordsPerPage";
28
29
 
29
30
  export const SampleVariantsView: Component = () => {
30
31
  const { sample } = useRouteData<SampleRouteData>();
@@ -137,7 +138,7 @@ export const SampleVariants: Component<{
137
138
  if (viabField) {
138
139
  actions.setSampleVariantsFilterQuery(
139
140
  props.sample,
140
- getAllelicBalanceQuery(props.sample.id),
141
+ getAllelicBalanceQuery(props.sample.data.index),
141
142
  selectorKey(["s", props.sample.data.index, ...selector(viabField)])
142
143
  );
143
144
  }
@@ -200,6 +201,8 @@ export const SampleVariants: Component<{
200
201
  const onFilterClear = (event: FilterClearEvent) => actions.clearSampleVariantsFilterQuery(props.sample, event.key);
201
202
  const onSortChange = (event: SortEvent) => actions.setSampleVariantsSort(props.sample, event.order);
202
203
  const onSortClear = () => actions.setSampleVariantsSort(props.sample, null);
204
+ const onRecordsPerPageChange = (event: RecordsPerPageEvent) =>
205
+ actions.setSampleVariantsPageSize(props.sample, event.number);
203
206
 
204
207
  const params = (): Params => {
205
208
  return {
@@ -231,7 +234,7 @@ export const SampleVariants: Component<{
231
234
  ]);
232
235
 
233
236
  return (
234
- <div class="columns">
237
+ <div class="columns is-variable is-1">
235
238
  <div class="column is-1-fullhd is-2">
236
239
  <SearchBox value={searchQuery()} onInput={onSearchChange} />
237
240
  <Filters
@@ -243,9 +246,13 @@ export const SampleVariants: Component<{
243
246
  />
244
247
  </div>
245
248
  <div class="column">
246
- <div class="columns">
249
+ <div class="columns is-gapless">
247
250
  <div class="column is-offset-1-fullhd is-3-fullhd is-4">
248
- {infoFields().length > 0 && <Sort options={sortOptions()} onChange={onSortChange} onClear={onSortClear} />}
251
+ <Show when={records()} fallback={<Loader />} keyed>
252
+ {(records) => (
253
+ <span class="is-pulled-left inline-control-text ml-2">{records.page.totalElements} records</span>
254
+ )}
255
+ </Show>
249
256
  </div>
250
257
  <div class="column is-4">
251
258
  <Show when={records()} fallback={<Loader />} keyed>
@@ -253,41 +260,45 @@ export const SampleVariants: Component<{
253
260
  </Show>
254
261
  </div>
255
262
  <div class="column">
256
- <div class="columns">
257
- <div class="column is-10">
258
- <Show when={records()} fallback={<Loader />} keyed>
259
- {(records) => (
260
- <span class="is-pulled-right" style={{ margin: "auto" }}>
261
- {records.page.totalElements} records
262
- </span>
263
- )}
264
- </Show>
265
- </div>
266
- <div class="column">
267
- <div class="is-pulled-right">
268
- <RecordDownload
269
- recordsMetadata={props.recordsMeta}
270
- query={params().query}
271
- samples={[props.sample.data, ...props.pedigreeSamples.map((item) => item.data)]}
272
- />
273
- </div>
274
- </div>
263
+ <div class="field is-grouped is-grouped-right">
264
+ {infoFields().length > 0 && (
265
+ <Sort options={sortOptions()} onChange={onSortChange} onClear={onSortClear} />
266
+ )}
267
+ <RecordDownload
268
+ recordsMetadata={props.recordsMeta}
269
+ query={params().query}
270
+ samples={[props.sample.data, ...props.pedigreeSamples.map((item) => item.data)]}
271
+ />
275
272
  </div>
276
273
  </div>
277
274
  </div>
278
- <div class="columns">
279
- <Show when={records()} fallback={<Loader />} keyed>
280
- {(records) => (
281
- <VariantsSampleTable
282
- item={props.sample}
283
- pedigreeSamples={props.pedigreeSamples}
284
- records={records.items}
285
- recordsMetadata={props.recordsMeta}
286
- nestedFields={infoFields()}
287
- htsFileMeta={props.htsFileMeta}
288
- />
289
- )}
290
- </Show>
275
+ <div class="columns is-gapless">
276
+ <div class="column is-full">
277
+ <Show when={records()} fallback={<Loader />} keyed>
278
+ {(records) => (
279
+ <>
280
+ <VariantsSampleTable
281
+ item={props.sample}
282
+ pedigreeSamples={props.pedigreeSamples}
283
+ records={records.items}
284
+ recordsMetadata={props.recordsMeta}
285
+ nestedFields={infoFields()}
286
+ htsFileMeta={props.htsFileMeta}
287
+ />
288
+ <div class="columns is-gapless">
289
+ <div class="column">
290
+ <div class="field is-grouped is-grouped-right">
291
+ <RecordsPerPage
292
+ initialValue={getStateVariants()?.pageSize || 20}
293
+ onChange={onRecordsPerPageChange}
294
+ />
295
+ </div>
296
+ </div>
297
+ </div>
298
+ </>
299
+ )}
300
+ </Show>
301
+ </div>
291
302
  </div>
292
303
  </div>
293
304
  </div>
@@ -16,6 +16,7 @@ import { Loader } from "../components/Loader";
16
16
  import { Metadata } from "@molgenis/vip-report-vcf/src/Vcf";
17
17
  import { arrayEquals } from "../utils/utils";
18
18
  import { FilterChangeEvent, FilterClearEvent } from "../components/filter/Filters";
19
+ import { RecordsPerPage, RecordsPerPageEvent } from "../components/RecordsPerPage";
19
20
 
20
21
  export const VariantsView: Component = () => {
21
22
  const [recordsMeta] = createResource(fetchRecordsMeta);
@@ -49,7 +50,7 @@ export const Variants: Component<{
49
50
  const onFilterClear = (event: FilterClearEvent) => actions.clearVariantsFilterQuery(event.key);
50
51
  const onSortChange = (event: SortEvent) => actions.setVariantsSort(event.order);
51
52
  const onSortClear = () => actions.setVariantsSort(null);
52
-
53
+ const onRecordsPerPageChange = (event: RecordsPerPageEvent) => actions.setVariantsPageSize(event.number);
53
54
  const params = (): Params => {
54
55
  return {
55
56
  query: createQuery(searchQuery(), filterQueries(), props.recordsMeta) || undefined,
@@ -81,49 +82,60 @@ export const Variants: Component<{
81
82
  };
82
83
 
83
84
  return (
84
- <Show when={records()} fallback={<Loader />}>
85
- <div class="columns">
86
- <div class="column is-1-fullhd is-2">
87
- <SearchBox onInput={onSearchChange} />
88
- <InfoFilters
89
- fields={flattenFieldMetadata(props.recordsMeta.info)}
90
- queries={filterQueries()}
91
- onChange={onFilterChange}
92
- onClear={onFilterClear}
93
- />
94
- </div>
95
- <div class="column">
96
- <div class="columns">
97
- <div class="column is-offset-1-fullhd is-3-fullhd is-4">
85
+ <div class="columns is-variable is-1">
86
+ <div class="column is-1-fullhd is-2">
87
+ <SearchBox onInput={onSearchChange} />
88
+ <InfoFilters
89
+ fields={flattenFieldMetadata(props.recordsMeta.info)}
90
+ queries={filterQueries()}
91
+ onChange={onFilterChange}
92
+ onClear={onFilterClear}
93
+ />
94
+ </div>
95
+ <div class="column">
96
+ <div class="columns is-gapless">
97
+ <div class="column is-offset-1-fullhd is-3-fullhd is-4">
98
+ <Show when={records()} fallback={<Loader />} keyed>
99
+ {(records) => (
100
+ <span class="is-pulled-left inline-control-text ml-2">{records.page.totalElements} records</span>
101
+ )}
102
+ </Show>
103
+ </div>
104
+ <div class="column is-4">
105
+ <Show when={records()} fallback={<Loader />} keyed>
106
+ {(records) => <Pager page={records.page} onPageChange={onPageChange} />}
107
+ </Show>
108
+ </div>
109
+ <div class="column">
110
+ <div class="field is-grouped is-grouped-right">
98
111
  <Sort options={sortOptions()} onChange={onSortChange} onClear={onSortClear} />
99
- </div>
100
- <div class="column is-4">
101
- <Pager page={records()!.page} onPageChange={onPageChange} />
102
- </div>
103
- <div class="column">
104
- <div class="columns">
105
- <div class="column is-10">
106
- <span class="is-pulled-right" style={{ margin: "auto" }}>
107
- {records()!.page.totalElements} records
108
- </span>
109
- </div>
110
- <div class="column">
111
- <div class="is-pulled-right">
112
- <RecordDownload recordsMetadata={props.recordsMeta} query={params().query} />
113
- </div>
114
- </div>
115
- </div>
112
+ <RecordDownload recordsMetadata={props.recordsMeta} query={params().query} />
116
113
  </div>
117
114
  </div>
118
- <div class="columns">
119
- <VariantsTable
120
- records={records()!.items}
121
- recordsMetadata={props.recordsMeta}
122
- htsFileMeta={props.htsFileMeta}
123
- />
115
+ </div>
116
+ <div class="columns is-gapless">
117
+ <div class="column is-full">
118
+ <Show when={records()} fallback={<Loader />} keyed>
119
+ {(records) => (
120
+ <>
121
+ <VariantsTable
122
+ records={records.items}
123
+ recordsMetadata={props.recordsMeta}
124
+ htsFileMeta={props.htsFileMeta}
125
+ />
126
+ <div class="columns is-gapless">
127
+ <div class="column">
128
+ <div class="field is-grouped is-grouped-right">
129
+ <RecordsPerPage initialValue={pageSize() || 20} onChange={onRecordsPerPageChange} />
130
+ </div>
131
+ </div>
132
+ </div>
133
+ </>
134
+ )}
135
+ </Show>
124
136
  </div>
125
137
  </div>
126
138
  </div>
127
- </Show>
139
+ </div>
128
140
  );
129
141
  };
package/vite.config.ts CHANGED
@@ -4,6 +4,10 @@ import inlinePlugin from "@molgenis/vite-plugin-inline/src/vite-plugin-inline.js
4
4
 
5
5
  export default defineConfig({
6
6
  plugins: [solidPlugin(), inlinePlugin()],
7
+ esbuild: {
8
+ // @molgenis/vite-plugin-inline requires ascii input and cannot handle UTF-8 input
9
+ charset: "ascii",
10
+ },
7
11
  build: {
8
12
  polyfillDynamicImport: false,
9
13
  // inline plugin build options