@molgenis/vip-report-template 6.0.1 → 6.1.1

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/.husky/pre-commit +0 -3
  2. package/.travis.yml +5 -2
  3. package/index.html +1 -1
  4. package/package.json +23 -23
  5. package/src/App.tsx +27 -68
  6. package/src/__tests__/sample.test.ts +184 -0
  7. package/src/assets/sass/main.scss +12 -47
  8. package/src/components/Breadcrumb.tsx +6 -6
  9. package/src/components/InfoCollapsablePane.tsx +4 -4
  10. package/src/components/SampleTable.tsx +37 -46
  11. package/src/components/VariantInfoNestedTable.tsx +3 -3
  12. package/src/components/VariantsSampleTable.tsx +21 -44
  13. package/src/components/VariantsTable.tsx +2 -3
  14. package/src/components/filter/Filter.tsx +0 -4
  15. package/src/components/record/format/GenotypeField.tsx +4 -15
  16. package/src/index.tsx +43 -1
  17. package/src/store/index.tsx +7 -10
  18. package/src/utils/sample.ts +63 -3
  19. package/src/views/Help.tsx +131 -6
  20. package/src/views/Home.tsx +24 -112
  21. package/src/views/Sample.tsx +21 -17
  22. package/src/views/SampleVariant.tsx +36 -21
  23. package/src/views/SampleVariantConsequence.tsx +44 -33
  24. package/src/views/SampleVariants.tsx +81 -10
  25. package/src/views/Samples.tsx +35 -33
  26. package/src/views/Variant.tsx +48 -42
  27. package/src/views/VariantConsequence.tsx +9 -8
  28. package/src/views/Variants.tsx +8 -2
  29. package/src/views/data/data.tsx +7 -0
  30. package/src/components/filter/FilterIntegerDp.tsx +0 -47
  31. package/src/views/data/SampleData.tsx +0 -13
  32. package/src/views/data/SampleVariantConsequenceData.tsx +0 -13
  33. package/src/views/data/SampleVariantData.tsx +0 -14
  34. package/src/views/data/VariantConsequenceData.tsx +0 -10
  35. package/src/views/data/VariantData.tsx +0 -13
@@ -1,121 +1,33 @@
1
- import { Component, createResource, createSignal, For, Show } from "solid-js";
1
+ import { Component } from "solid-js";
2
2
  import { Breadcrumb } from "../components/Breadcrumb";
3
- import { Item, Phenotype, PhenotypicFeature } from "@molgenis/vip-report-api/src/Api";
4
- import { HpoTerm } from "../components/HpoTerm";
5
- import {
6
- EMPTY_APP_METADATA,
7
- EMPTY_HTS_FILE_METADATA,
8
- EMPTY_PARAMS,
9
- EMPTY_PHENOTYPES,
10
- EMPTY_RECORDS_METADATA,
11
- EMPTY_RECORDS_PAGE,
12
- EMPTY_SAMPLES_PAGE,
13
- fetchAppMetadata,
14
- fetchHtsFileMetadata,
15
- fetchPhenotypes,
16
- fetchRecords,
17
- fetchRecordsMeta,
18
- fetchSamples,
19
- } from "../utils/ApiUtils";
20
- import { getHeaderValue } from "../utils/viewUtils";
21
- import { Loader } from "../components/Loader";
22
- import { VcfHeaderRow } from "../components/VcfHeaderRow";
3
+ import { useNavigate } from "@solidjs/router";
23
4
 
24
5
  export const Home: Component = () => {
25
- const [params] = createSignal(EMPTY_PARAMS);
26
- const [samples] = createResource(params, fetchSamples, { initialValue: EMPTY_SAMPLES_PAGE });
27
- const [records] = createResource(params, fetchRecords, { initialValue: EMPTY_RECORDS_PAGE });
28
- const [recordsMetadata] = createResource(params, fetchRecordsMeta, { initialValue: EMPTY_RECORDS_METADATA });
29
- const [phenotypes] = createResource(params, fetchPhenotypes, { initialValue: EMPTY_PHENOTYPES });
30
- const [htsFileMetadata] = createResource(params, fetchHtsFileMetadata, { initialValue: EMPTY_HTS_FILE_METADATA });
31
- const [appMetadata] = createResource(params, fetchAppMetadata, { initialValue: EMPTY_APP_METADATA });
6
+ const navigate = useNavigate();
32
7
 
33
8
  return (
34
- <Show
35
- when={
36
- !samples.loading &&
37
- !records.loading &&
38
- !recordsMetadata.loading &&
39
- !phenotypes.loading &&
40
- !htsFileMetadata.loading &&
41
- !appMetadata.loading
42
- }
43
- fallback={<Loader />}
44
- >
9
+ <>
45
10
  <Breadcrumb items={[]} />
46
- <div class="table-container">
47
- <table class="table is-narrow">
48
- <thead>
49
- <tr>
50
- <th colSpan={2}>Software metadata</th>
51
- </tr>
52
- </thead>
53
- <tbody>
54
- <tr>
55
- <th>Name:</th>
56
- <td>{appMetadata().name}</td>
57
- </tr>
58
- <tr>
59
- <th>Version:</th>
60
- <td>{appMetadata().version}</td>
61
- </tr>
62
- <tr>
63
- <th>Arguments:</th>
64
- <td>{appMetadata().args}</td>
65
- </tr>
66
- <VcfHeaderRow value={getHeaderValue("VIP_Version", recordsMetadata().lines)} title={"VIP Version"} />
67
- <VcfHeaderRow value={getHeaderValue("VIP_Command", recordsMetadata().lines)} title={"VIP Command"} />
68
- </tbody>
69
- </table>
11
+ <div class="columns is-centered">
12
+ <div class="column is-three-quarters-widescreen">
13
+ <p class="title is-2">Report</p>
14
+ <p class="subtitle is-4">
15
+ Analyze annotated, classified and filtered variants to solve rare-disease patients
16
+ </p>
17
+ <div class="columns">
18
+ <div class="column">
19
+ <div class="buttons are-large">
20
+ <button class="button is-large" onClick={() => navigate("/variants")}>
21
+ Explore Variants without samples
22
+ </button>
23
+ <button class="button is-large is-primary" onClick={() => navigate("/samples")}>
24
+ Explore Variants for samples
25
+ </button>
26
+ </div>
27
+ </div>
28
+ </div>
29
+ </div>
70
30
  </div>
71
- <div class="table-container">
72
- <table class="table is-narrow">
73
- <thead>
74
- <tr>
75
- <th colSpan={2}>Input metadata</th>
76
- </tr>
77
- </thead>
78
- <tbody>
79
- <tr>
80
- <th>Filename:</th>
81
- <td>{htsFileMetadata().uri}</td>
82
- </tr>
83
- <tr>
84
- <th>Assembly:</th>
85
- <td>{htsFileMetadata().genomeAssembly}</td>
86
- </tr>
87
- <tr>
88
- <th>Number of records:</th>
89
- <td>{records().total}</td>
90
- </tr>
91
- <tr>
92
- <th>Number of samples:</th>
93
- <td>{samples().total}</td>
94
- </tr>
95
- <tr>
96
- <th>Phenotypes:</th>
97
- <td>
98
- <For each={phenotypes().items}>
99
- {(item: Item<Phenotype>) => (
100
- <>
101
- <b>{item.data.subject.id}: </b>
102
- <For each={item.data.phenotypicFeaturesList}>
103
- {(phenotypicFeature: PhenotypicFeature, i) => (
104
- <>
105
- {i() > 0 ? ", " : ""}
106
- <HpoTerm ontologyClass={phenotypicFeature.type} />
107
- </>
108
- )}
109
- </For>
110
- <br />
111
- </>
112
- )}
113
- </For>
114
- </td>
115
- </tr>
116
- </tbody>
117
- </table>
118
- </div>
119
- </Show>
31
+ </>
120
32
  );
121
33
  };
@@ -1,26 +1,30 @@
1
1
  import { Component, For, Show } from "solid-js";
2
- import { Link, useRouteData } from "@solidjs/router";
2
+ import { createAsync, RouteSectionProps } from "@solidjs/router";
3
3
  import { Loader } from "../components/Loader";
4
4
  import { Breadcrumb } from "../components/Breadcrumb";
5
- import { SampleRouteData } from "./data/SampleData";
5
+ import { getSample } from "./data/data";
6
6
 
7
- export const Sample: Component = () => {
8
- const { sample } = useRouteData<SampleRouteData>();
7
+ export const Sample: Component<RouteSectionProps> = (props) => {
8
+ const sample = createAsync(() => getSample(Number(props.params.sampleId)));
9
9
 
10
10
  return (
11
- <Show when={!sample.loading} fallback={<Loader />}>
12
- <Breadcrumb items={[{ href: "/samples", text: "Samples" }, { text: sample().data.person.individualId }]} />
13
- <p class="has-text-weight-semibold">Sample</p>
14
- <div class="columns">
15
- <div class="column is-1">
16
- <For each={Object.keys(sample().data.person)}>{(key) => <p>{key}</p>}</For>
17
- </div>
18
- <div class="column is-1">
19
- <For each={Object.values(sample().data.person)}>{(value) => <p>{value}</p>}</For>
20
- </div>
21
- </div>
22
- <br />
23
- <Link href={`/samples/${sample().id}/variants`}>Variants</Link>
11
+ <Show when={sample()} fallback={<Loader />}>
12
+ {(sample) => (
13
+ <>
14
+ <Breadcrumb items={[{ href: "/samples", text: "Samples" }, { text: sample().data.person.individualId }]} />
15
+ <p class="has-text-weight-semibold">Sample</p>
16
+ <div class="columns">
17
+ <div class="column is-1">
18
+ <For each={Object.keys(sample().data.person)}>{(key) => <p>{key}</p>}</For>
19
+ </div>
20
+ <div class="column is-1">
21
+ <For each={Object.values(sample().data.person)}>{(value) => <p>{value}</p>}</For>
22
+ </div>
23
+ </div>
24
+ <br />
25
+ <a href={`/samples/${sample().id}/variants`}>Variants</a>
26
+ </>
27
+ )}
24
28
  </Show>
25
29
  );
26
30
  };
@@ -1,5 +1,5 @@
1
1
  import { Component, createResource, For, Show } from "solid-js";
2
- import { useRouteData } from "@solidjs/router";
2
+ import { createAsync, RouteSectionProps } from "@solidjs/router";
3
3
  import { Loader } from "../components/Loader";
4
4
  import { GenomeBrowser } from "../components/GenomeBrowser";
5
5
  import { fetchPedigreeSamples, fetchRecordsMeta, getRecordLabel } from "../utils/ApiUtils";
@@ -11,36 +11,51 @@ import { getNestedInfoFieldsWithValues } from "../utils/field";
11
11
  import { VariantSampleTable } from "../components/VariantSampleTable";
12
12
  import { Breadcrumb } from "../components/Breadcrumb";
13
13
  import { getRecordSamples } from "../utils/viewUtils";
14
- import { SampleVariantRouteData } from "./data/SampleVariantData";
15
14
  import { getSampleLabel } from "../utils/sample";
16
15
  import { Item, Sample } from "@molgenis/vip-report-api/src/Api";
17
16
  import { Metadata, Record } from "@molgenis/vip-report-vcf/src/Vcf";
18
17
  import { Abbr } from "../components/Abbr";
18
+ import { getSample, getVariant } from "./data/data";
19
19
 
20
- export const SampleVariantView: Component = () => {
21
- const { sample, variant } = useRouteData<SampleVariantRouteData>();
20
+ export const SampleVariantView: Component<RouteSectionProps> = (props) => {
21
+ const sample = createAsync(() => getSample(Number(props.params.sampleId)));
22
+ const variant = createAsync(() => getVariant(Number(props.params.variantId)));
22
23
 
23
24
  const [pedigreeSamples] = createResource(sample, fetchPedigreeSamples);
24
25
  const [recordsMeta] = createResource(fetchRecordsMeta);
25
26
 
26
27
  return (
27
- <Show when={sample() && variant()} fallback={<Loader />}>
28
- <Breadcrumb
29
- items={[
30
- { href: "/samples", text: "Samples" },
31
- { href: `/samples/${sample()!.id}`, text: getSampleLabel(sample()!) },
32
- { href: `/samples/${sample()!.id}/variants`, text: "Variants" },
33
- { text: getRecordLabel(variant()!) },
34
- ]}
35
- />
36
- <Show when={pedigreeSamples() && recordsMeta()} fallback={<Loader />}>
37
- <SampleVariant
38
- sample={sample()!}
39
- pedigreeSamples={pedigreeSamples()!.items}
40
- recordsMeta={recordsMeta()!}
41
- record={variant()!}
42
- />
43
- </Show>
28
+ <Show when={sample()} fallback={<Loader />}>
29
+ {(sample) => (
30
+ <Show when={variant()} fallback={<Loader />}>
31
+ {(variant) => (
32
+ <>
33
+ <Breadcrumb
34
+ items={[
35
+ { href: "/samples", text: "Samples" },
36
+ { href: `/samples/${sample().id}`, text: getSampleLabel(sample().data) },
37
+ { href: `/samples/${sample().id}/variants`, text: "Variants" },
38
+ { text: getRecordLabel(variant()) },
39
+ ]}
40
+ />
41
+ <Show when={pedigreeSamples()} fallback={<Loader />}>
42
+ {(pedigreeSamples) => (
43
+ <Show when={recordsMeta()} fallback={<Loader />}>
44
+ {(recordsMeta) => (
45
+ <SampleVariant
46
+ sample={sample()}
47
+ pedigreeSamples={pedigreeSamples().items}
48
+ recordsMeta={recordsMeta()}
49
+ record={variant()}
50
+ />
51
+ )}
52
+ </Show>
53
+ )}
54
+ </Show>
55
+ </>
56
+ )}
57
+ </Show>
58
+ )}
44
59
  </Show>
45
60
  );
46
61
  };
@@ -1,13 +1,7 @@
1
1
  import { Component, createResource, Show } from "solid-js";
2
- import { useRouteData } from "@solidjs/router";
2
+ import { createAsync, RouteSectionProps } from "@solidjs/router";
3
3
  import { Loader } from "../components/Loader";
4
- import {
5
- fetchDecisionTree,
6
- fetchHtsFileMetadata,
7
- fetchPedigreeSamples,
8
- fetchRecordsMeta,
9
- getRecordLabel,
10
- } from "../utils/ApiUtils";
4
+ import { fetchDecisionTree, fetchPedigreeSamples, fetchRecordsMeta, getRecordLabel } from "../utils/ApiUtils";
11
5
  import { VariantTable } from "../components/VariantTable";
12
6
  import { VariantInfoTable } from "../components/VariantInfoTable";
13
7
  import { VariantSampleTable } from "../components/VariantSampleTable";
@@ -16,41 +10,58 @@ import { ConsequenceTable } from "../components/ConsequenceTable";
16
10
  import { getRecordSamples, getSpecificConsequence } from "../utils/viewUtils";
17
11
  import { DecisionTreePath } from "../components/tree/DecisionTreePath";
18
12
  import { getDecisionTreePath } from "../utils/decisionTreeUtils";
19
- import { SampleVariantConsequenceRouteData } from "./data/SampleVariantConsequenceData";
20
13
  import { getSampleLabel } from "../utils/sample";
21
14
  import { DecisionTree, Item, Sample } from "@molgenis/vip-report-api/src/Api";
22
15
  import { Metadata, Record } from "@molgenis/vip-report-vcf/src/Vcf";
23
16
  import { ValueArray } from "@molgenis/vip-report-vcf/src/ValueParser";
17
+ import { getSample, getVariant } from "./data/data";
24
18
 
25
- export const SampleVariantConsequenceView: Component = () => {
26
- const { sample, variant, consequenceId } = useRouteData<SampleVariantConsequenceRouteData>();
27
-
19
+ export const SampleVariantConsequenceView: Component<RouteSectionProps> = (props) => {
20
+ const sample = createAsync(() => getSample(Number(props.params.sampleId)));
21
+ const variant = createAsync(() => getVariant(Number(props.params.variantId)));
22
+ const consequenceId = () => Number(props.params.consequenceId);
28
23
  const [pedigreeSamples] = createResource(sample, fetchPedigreeSamples);
29
24
  const [recordsMeta] = createResource(fetchRecordsMeta);
30
25
  const [decisionTree] = createResource(fetchDecisionTree, { initialValue: null });
31
- const [htsFileMeta] = createResource(fetchHtsFileMetadata);
32
26
 
33
27
  return (
34
- <Show when={sample() && variant()} fallback={<Loader />}>
35
- <Breadcrumb
36
- items={[
37
- { href: "/samples", text: "Samples" },
38
- { href: `/samples/${sample()!.id}`, text: getSampleLabel(sample()!) },
39
- { href: `/samples/${sample()!.id}/variants`, text: "Variants" },
40
- { href: `/samples/${sample()!.id}/variants/${variant()!.id}`, text: getRecordLabel(variant()!) },
41
- { text: `Consequence #${consequenceId}` },
42
- ]}
43
- />
44
- <Show when={pedigreeSamples() && recordsMeta() && htsFileMeta()} fallback={<Loader />}>
45
- <SampleVariantConsequence
46
- sample={sample()!}
47
- pedigreeSamples={pedigreeSamples()!.items}
48
- recordsMeta={recordsMeta()!}
49
- variant={variant()!}
50
- consequenceId={consequenceId}
51
- decisionTree={decisionTree()}
52
- />
53
- </Show>
28
+ <Show when={sample()} fallback={<Loader />}>
29
+ {(sample) => (
30
+ <Show when={variant()} fallback={<Loader />}>
31
+ {(variant) => (
32
+ <>
33
+ <Breadcrumb
34
+ items={[
35
+ { href: "/samples", text: "Samples" },
36
+ { href: `/samples/${sample().id}`, text: getSampleLabel(sample().data) },
37
+ { href: `/samples/${sample().id}/variants`, text: "Variants" },
38
+ {
39
+ href: `/samples/${sample().id}/variants/${variant().id}`,
40
+ text: getRecordLabel(variant()),
41
+ },
42
+ { text: `Consequence #${consequenceId()}` },
43
+ ]}
44
+ />
45
+ <Show when={pedigreeSamples()} fallback={<Loader />}>
46
+ {(pedigreeSamples) => (
47
+ <Show when={recordsMeta()} fallback={<Loader />}>
48
+ {(recordsMeta) => (
49
+ <SampleVariantConsequence
50
+ sample={sample()}
51
+ pedigreeSamples={pedigreeSamples().items}
52
+ recordsMeta={recordsMeta()}
53
+ variant={variant()}
54
+ consequenceId={consequenceId()}
55
+ decisionTree={decisionTree()}
56
+ />
57
+ )}
58
+ </Show>
59
+ )}
60
+ </Show>
61
+ </>
62
+ )}
63
+ </Show>
64
+ )}
54
65
  </Show>
55
66
  );
56
67
  };
@@ -1,5 +1,4 @@
1
- import { Component, createMemo, createResource, Show } from "solid-js";
2
- import { useRouteData } from "@solidjs/router";
1
+ import { Component, createMemo, createResource, createSignal, onMount, Show } from "solid-js";
3
2
  import {
4
3
  HtsFileMetadata,
5
4
  Item,
@@ -35,16 +34,24 @@ import { Breadcrumb } from "../components/Breadcrumb";
35
34
  import { FieldMetadata } from "@molgenis/vip-report-vcf/src/MetadataParser";
36
35
  import { FilterChangeEvent, FilterClearEvent, Filters } from "../components/filter/Filters";
37
36
  import { DIRECTION_ASCENDING, DIRECTION_DESCENDING } from "../utils/sortUtils";
38
- import { SampleRouteData } from "./data/SampleData";
39
37
  import { useStore } from "../store";
40
38
  import { Metadata } from "@molgenis/vip-report-vcf/src/Vcf";
41
- import { getSampleLabel } from "../utils/sample";
39
+ import {
40
+ getSampleAffectedStatusLabel,
41
+ getSampleFamilyMembersWithoutParents,
42
+ getSampleFather,
43
+ getSampleLabel,
44
+ getSampleMother,
45
+ getSampleSexLabel,
46
+ } from "../utils/sample";
42
47
  import { arrayEquals } from "../utils/utils";
43
48
  import { getAllelicBalanceQuery } from "../components/filter/FilterAllelicBalance";
44
49
  import { RecordsPerPage, RecordsPerPageEvent } from "../components/RecordsPerPage";
50
+ import { createAsync, RouteSectionProps } from "@solidjs/router";
51
+ import { getSample } from "./data/data";
45
52
 
46
- export const SampleVariantsView: Component = () => {
47
- const { sample } = useRouteData<SampleRouteData>();
53
+ export const SampleVariantsView: Component<RouteSectionProps> = (props) => {
54
+ const sample = createAsync(() => getSample(Number(props.params.sampleId)));
48
55
 
49
56
  const [pedigreeSamples] = createResource(sample, fetchPedigreeSamples);
50
57
  const [samplePhenotypes] = createResource(sample, fetchPhenotypicFeatures);
@@ -56,7 +63,7 @@ export const SampleVariantsView: Component = () => {
56
63
  <Breadcrumb
57
64
  items={[
58
65
  { href: "/samples", text: "Samples" },
59
- { href: `/samples/${sample()!.id}`, text: getSampleLabel(sample()!) },
66
+ { href: `/samples/${sample()!.id}`, text: getSampleLabel(sample()!.data) },
60
67
  { text: "Variants" },
61
68
  ]}
62
69
  />
@@ -82,6 +89,20 @@ export const SampleVariants: Component<{
82
89
  }> = (props) => {
83
90
  const [state, actions] = useStore();
84
91
 
92
+ const samples = createMemo(() => [props.sample.data, ...props.pedigreeSamples.map((item) => item.data)]);
93
+
94
+ const [proband, setProband] = createSignal<Sample | undefined>();
95
+ const [father, setFather] = createSignal<Sample | undefined>();
96
+ const [mother, setMother] = createSignal<Sample | undefined>();
97
+ const [otherFamilyMembers, setOtherFamilyMembers] = createSignal<Sample[]>([]);
98
+
99
+ onMount(() => {
100
+ setProband(props.sample.data);
101
+ setMother(getSampleMother(proband() as Sample, samples()));
102
+ setFather(getSampleFather(proband() as Sample, samples()));
103
+ setOtherFamilyMembers(getSampleFamilyMembersWithoutParents(proband() as Sample, samples()));
104
+ });
105
+
85
106
  function getStateVariants() {
86
107
  return state.sampleVariants ? state.sampleVariants[props.sample.id]?.variants : undefined;
87
108
  }
@@ -311,9 +332,51 @@ export const SampleVariants: Component<{
311
332
  },
312
333
  ]);
313
334
 
335
+ function getTitleSampleSexLabel(sample: Sample): string {
336
+ const label = getSampleSexLabel(sample);
337
+ return label !== "?" ? label : "sex:?";
338
+ }
339
+
340
+ function getTitleAffectedStatusLabel(sample: Sample): string {
341
+ const label = getSampleAffectedStatusLabel(sample);
342
+ return label !== "?" ? label : "affected status:?";
343
+ }
344
+
345
+ const title = (): string => {
346
+ return `Reported variants for ${getSampleLabel(props.sample.data)} (${getTitleSampleSexLabel(props.sample.data)} ${getTitleAffectedStatusLabel(props.sample.data)})`;
347
+ };
348
+
349
+ const subtitle = (): string | undefined => {
350
+ const sampleFather = father();
351
+ const sampleMother = mother();
352
+ const sampleOtherFamilyMembers = otherFamilyMembers();
353
+
354
+ if (sampleFather === undefined && sampleMother === undefined && sampleOtherFamilyMembers.length === 0) {
355
+ return undefined;
356
+ }
357
+
358
+ const tokens: string[] = [];
359
+ if (sampleMother !== undefined) {
360
+ tokens.push(`mother (${getTitleAffectedStatusLabel(sampleMother)})`);
361
+ }
362
+ if (sampleFather !== undefined) {
363
+ tokens.push(`father (${getTitleAffectedStatusLabel(sampleFather)})`);
364
+ }
365
+
366
+ for (const familyMember of sampleOtherFamilyMembers) {
367
+ tokens.push(
368
+ `${getSampleLabel(familyMember)} (${getTitleSampleSexLabel(familyMember)} ${getTitleAffectedStatusLabel(familyMember)})`,
369
+ );
370
+ }
371
+
372
+ let str = tokens.pop() as string;
373
+ if (tokens.length > 0) str = `${tokens.join(", ")} and ${str}`;
374
+ return `Includes genotypes for ${str}`;
375
+ };
376
+
314
377
  return (
315
- <div class="columns is-variable is-1">
316
- <div class="column is-1-fullhd is-2">
378
+ <div class="variants columns is-variable is-1">
379
+ <div class="scrolling-div column is-1-fullhd is-2">
317
380
  <SearchBox value={searchQuery()} onInput={onSearchChange} />
318
381
  <Filters
319
382
  fields={filterInfoFields()}
@@ -323,7 +386,15 @@ export const SampleVariants: Component<{
323
386
  onClear={onFilterClear}
324
387
  />
325
388
  </div>
326
- <div class="column">
389
+ <div class="scrolling-div column">
390
+ <div class="columns is-gapless">
391
+ <div class="column">
392
+ <p class="title is-3">{title()}</p>
393
+ <Show when={subtitle()} keyed>
394
+ {(subtitle) => <p class="subtitle is-5">{subtitle}</p>}
395
+ </Show>
396
+ </div>
397
+ </div>
327
398
  <div class="columns is-gapless">
328
399
  <div class="column is-offset-1-fullhd is-3-fullhd is-4">
329
400
  <Show when={records()} fallback={<Loader />} keyed>
@@ -75,42 +75,44 @@ export const Samples: Component = () => {
75
75
  return (
76
76
  <>
77
77
  <Breadcrumb items={[{ text: "Samples" }]} />
78
- <Show when={samples()} fallback={<Loader />} keyed>
79
- {(samples) => (
80
- <>
81
- <div class="columns">
82
- <div class="column is-4 is-offset-3">{<Pager page={samples.page} onPageChange={onPageChange} />}</div>
83
- <div class="column is-2 is-offset-1">
84
- {<span class="is-pulled-right">{samples.page.totalElements} records</span>}
85
- </div>
86
- </div>
78
+ <div class="columns is-centered">
79
+ <div class="column is-three-quarters-widescreen">
80
+ <p class="title is-2">Samples</p>
81
+ <p class="subtitle is-4">Explore samples and sample variants</p>
82
+ <Show when={samples()} fallback={<Loader />} keyed>
83
+ {(samples) => (
84
+ <>
85
+ <div class="columns">
86
+ <div class="column is-4 is-offset-3">{<Pager page={samples.page} onPageChange={onPageChange} />}</div>
87
+ <div class="column is-2 is-offset-1">
88
+ {<span class="is-pulled-right">{samples.page.totalElements} records</span>}
89
+ </div>
90
+ </div>
87
91
 
88
- <div class="columns">
89
- <div class="column is-1-fullhd is-2">
90
- <SearchBox onInput={onSearchChange} value={state.samples?.searchQuery} />
91
- <p class="has-text-weight-semibold">Proband</p>
92
- <div class="field">
93
- <div class="control">
94
- <Checkbox
95
- value={"proband"}
96
- label=""
97
- onChange={onProbandFilterChange}
98
- checked={state.samples?.probandFilterValue}
99
- />
92
+ <div class="columns">
93
+ <div class="column is-2-widescreen is-3">
94
+ <SearchBox onInput={onSearchChange} value={state.samples?.searchQuery} />
95
+ <p class="has-text-weight-semibold">Proband</p>
96
+ <div class="field">
97
+ <div class="control">
98
+ <Checkbox
99
+ value={"proband"}
100
+ label=""
101
+ onChange={onProbandFilterChange}
102
+ checked={state.samples?.probandFilterValue}
103
+ />
104
+ </div>
105
+ </div>
106
+ </div>
107
+ <div class="column">
108
+ {!phenotypes.loading && <SampleTable samples={samples.items} phenotypes={phenotypes().items} />}
100
109
  </div>
101
110
  </div>
102
- </div>
103
- <div class="column">
104
- <span class="is-italic">
105
- Click on an individual id for detailed information for this sample. In this screen a link to the
106
- variants for this sample is available.
107
- </span>
108
- {!phenotypes.loading && <SampleTable samples={samples.items} phenotypes={phenotypes().items} />}
109
- </div>
110
- </div>
111
- </>
112
- )}
113
- </Show>
111
+ </>
112
+ )}
113
+ </Show>
114
+ </div>
115
+ </div>
114
116
  </>
115
117
  );
116
118
  };