@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
@@ -6,7 +6,7 @@ import { FieldHeader } from "./FieldHeader";
6
6
  import { Record } from "@molgenis/vip-report-vcf/src/Vcf";
7
7
  import { Item } from "@molgenis/vip-report-api/src/Api";
8
8
  import { isCsqInfo } from "../utils/csqUtils";
9
- import { Link, useLocation } from "@solidjs/router";
9
+ import { useLocation } from "@solidjs/router";
10
10
 
11
11
  function isNonEmptyNestedInfoItem(nestedInfoField: FieldMetadata, index: number, value: Value[] | Value[][]): boolean {
12
12
  const infoField = nestedInfoField.nested?.items[index];
@@ -87,7 +87,7 @@ export const VariantInfoNestedTable: Component<{
87
87
  {isNonEmptyNestedInfoItem(props.infoField, i(), props.infoValue) && (
88
88
  <td>
89
89
  {isCsqInfo(infoFieldItem, "Consequence") ? (
90
- <Link href={`${useLocation().pathname}/consequences/${j()}`}>
90
+ <a href={`${useLocation().pathname}/consequences/${j()}`}>
91
91
  <Info
92
92
  info={{
93
93
  value: Array.isArray(value) ? value[i()] : null,
@@ -97,7 +97,7 @@ export const VariantInfoNestedTable: Component<{
97
97
  infoMeta={infoFieldItem}
98
98
  context={{}}
99
99
  />
100
- </Link>
100
+ </a>
101
101
  ) : (
102
102
  <Info
103
103
  info={{
@@ -2,7 +2,6 @@ import { Genotype, Metadata, Record } from "@molgenis/vip-report-vcf/src/Vcf";
2
2
  import { Ref } from "./record/Ref";
3
3
  import { Chrom } from "./record/Chrom";
4
4
  import { Pos } from "./record/Pos";
5
- import { Link } from "@solidjs/router";
6
5
  import { HtsFileMetadata, Item, Sample } from "@molgenis/vip-report-api/src/Api";
7
6
  import { GenotypeField } from "./record/format/GenotypeField";
8
7
  import { InfoCollapsablePane } from "./InfoCollapsablePane";
@@ -11,6 +10,14 @@ import { FieldMetadata } from "@molgenis/vip-report-vcf/src/MetadataParser";
11
10
  import { FieldHeader } from "./FieldHeader";
12
11
  import { Abbr } from "./Abbr";
13
12
  import { abbreviateHeader } from "../utils/field";
13
+ import {
14
+ getSampleAffectedStatusLabel,
15
+ getSampleFamilyMembersWithoutParents,
16
+ getSampleFather,
17
+ getSampleLabel,
18
+ getSampleMother,
19
+ getSampleSexLabel,
20
+ } from "../utils/sample";
14
21
 
15
22
  export const VariantsSampleTable: Component<{
16
23
  item: Item<Sample>;
@@ -28,26 +35,16 @@ export const VariantsSampleTable: Component<{
28
35
  const [otherFamilyMembers, setOtherFamilyMembers] = createSignal<Sample[]>([]);
29
36
 
30
37
  onMount(() => {
31
- const familyMembers: Sample[] = [];
32
38
  setProband(props.item.data);
33
- samples().forEach((sample) => {
34
- if (
35
- (proband() as Sample).person.maternalId !== "0" &&
36
- sample.person.individualId === (proband() as Sample).person.maternalId
37
- ) {
38
- setMother(sample);
39
- } else if (
40
- (proband() as Sample).person.paternalId !== "0" &&
41
- sample.person.individualId === (proband() as Sample).person.paternalId
42
- ) {
43
- setFather(sample);
44
- } else if (sample.person.individualId !== (proband() as Sample).person.individualId) {
45
- familyMembers.push(sample);
46
- }
47
- });
48
- setOtherFamilyMembers(familyMembers);
39
+ setMother(getSampleMother(proband() as Sample, samples()));
40
+ setFather(getSampleFather(proband() as Sample, samples()));
41
+ setOtherFamilyMembers(getSampleFamilyMembersWithoutParents(proband() as Sample, samples()));
49
42
  });
50
43
 
44
+ function getSampleHeaderDescription(sample: Sample): string {
45
+ return `${getSampleLabel(sample)}: ${getSampleSexLabel(sample)}, ${getSampleAffectedStatusLabel(sample)}`;
46
+ }
47
+
51
48
  return (
52
49
  <div style={{ display: "grid" }}>
53
50
  {/* workaround for https://github.com/jgthms/bulma/issues/2572#issuecomment-523099776 */}
@@ -60,48 +57,28 @@ export const VariantsSampleTable: Component<{
60
57
  <Show when={proband()} keyed>
61
58
  {(proband) => (
62
59
  <th>
63
- <Abbr
64
- title={`${
65
- proband.person.individualId
66
- }: ${proband.person.sex.toLowerCase()}, ${proband.person.affectedStatus.toLowerCase()}`}
67
- value="Proband"
68
- />
60
+ <Abbr title={getSampleHeaderDescription(proband)} value="Proband" />
69
61
  </th>
70
62
  )}
71
63
  </Show>
72
64
  <Show when={mother()} keyed>
73
65
  {(mother) => (
74
66
  <th>
75
- <Abbr
76
- title={`${
77
- mother.person.individualId
78
- }: ${mother.person.sex.toLowerCase()}, ${mother.person.affectedStatus.toLowerCase()}`}
79
- value="Mother"
80
- />
67
+ <Abbr title={getSampleHeaderDescription(mother)} value="Mother" />
81
68
  </th>
82
69
  )}
83
70
  </Show>
84
71
  <Show when={father()} keyed>
85
72
  {(father) => (
86
73
  <th>
87
- <Abbr
88
- title={`${
89
- father.person.individualId
90
- }: ${father.person.sex.toLowerCase()}, ${father.person.affectedStatus.toLowerCase()}`}
91
- value="Father"
92
- />
74
+ <Abbr title={getSampleHeaderDescription(father)} value="Father" />
93
75
  </th>
94
76
  )}
95
77
  </Show>
96
78
  <For each={otherFamilyMembers()}>
97
79
  {(sample: Sample) => (
98
80
  <th>
99
- <Abbr
100
- title={`${
101
- sample.person.individualId
102
- }: ${sample.person.sex.toLowerCase()}, ${sample.person.affectedStatus.toLowerCase()}`}
103
- value={abbreviateHeader(sample.person.individualId)}
104
- />
81
+ <Abbr title={getSampleHeaderDescription(sample)} value={abbreviateHeader(getSampleLabel(sample))} />
105
82
  </th>
106
83
  )}
107
84
  </For>
@@ -115,11 +92,11 @@ export const VariantsSampleTable: Component<{
115
92
  {(record) => (
116
93
  <tr>
117
94
  <td>
118
- <Link href={`/samples/${props.item.id}/variants/${record.id}`}>
95
+ <a href={`/samples/${props.item.id}/variants/${record.id}`}>
119
96
  <Chrom value={record.data.c} />
120
97
  <span>:</span>
121
98
  <Pos value={record.data.p} />
122
- </Link>
99
+ </a>
123
100
  </td>
124
101
  <td>
125
102
  <Ref value={record.data.r} isAbbreviate={true} />
@@ -9,7 +9,6 @@ import { Qual } from "./record/Qual";
9
9
  import { Filter } from "./record/Filter";
10
10
  import { Info } from "./record/Info";
11
11
  import { FieldMetadata } from "@molgenis/vip-report-vcf/src/MetadataParser";
12
- import { Link } from "@solidjs/router";
13
12
  import { HtsFileMetadata, Item } from "@molgenis/vip-report-api/src/Api";
14
13
  import { FieldHeader } from "./FieldHeader";
15
14
  import { InfoCollapsablePane } from "./InfoCollapsablePane";
@@ -76,9 +75,9 @@ export const VariantsTable: Component<{
76
75
  <Chrom value={record.data.c} />
77
76
  </td>
78
77
  <td>
79
- <Link href={`/variants/${record.id}`}>
78
+ <a href={`/variants/${record.id}`}>
80
79
  <Pos value={record.data.p} />
81
- </Link>
80
+ </a>
82
81
  </td>
83
82
  <td>
84
83
  <Id value={record.data.i} />
@@ -2,7 +2,6 @@ import { Component, Match, Switch } from "solid-js";
2
2
  import { FieldMetadata } from "@molgenis/vip-report-vcf/src/MetadataParser";
3
3
  import { FilterCategorical } from "./FilterCategorical";
4
4
  import { FilterIntegerGq } from "./FilterIntegerGq";
5
- import { FilterIntegerDp } from "./FilterIntegerDp";
6
5
  import { Item, Query, Sample } from "@molgenis/vip-report-api/src/Api";
7
6
  import { FilterClinVar } from "./FilterClinVar";
8
7
  import { isAnyCsqInfo } from "../../utils/csqUtils";
@@ -28,9 +27,6 @@ export const Filter: Component<FilterProps> = (props) => {
28
27
  <Match when={props.field.id === "GQ"}>
29
28
  <FilterIntegerGq {...props} />
30
29
  </Match>
31
- <Match when={props.field.id === "DP"}>
32
- <FilterIntegerDp {...props} />
33
- </Match>
34
30
  <Match when={props.field.id === "VIAB"}>
35
31
  <FilterAllelicBalance {...props} />
36
32
  </Match>
@@ -15,18 +15,8 @@ function isAllelicImbalance(genotype: Genotype, allelicBalance: number | undefin
15
15
  return false;
16
16
  }
17
17
 
18
- function getTitle(lowReadDepth: boolean, allelicImbalance: boolean) {
19
- let title = "";
20
- if (lowReadDepth) {
21
- title = "Read depth < 20";
22
- }
23
- if (allelicImbalance) {
24
- if (lowReadDepth) {
25
- title = `${title}, `;
26
- }
27
- title = `${title}Allelic imbalance`;
28
- }
29
- return title;
18
+ function getTitle(allelicImbalance: boolean) {
19
+ return allelicImbalance ? `Allelic imbalance` : ``;
30
20
  }
31
21
 
32
22
  export const GenotypeField: Component<{
@@ -38,7 +28,6 @@ export const GenotypeField: Component<{
38
28
  readDepth: number | undefined | null;
39
29
  }> = (props) => {
40
30
  const allelicImbalance: boolean = isAllelicImbalance(props.genotype, props.allelicBalance);
41
- const lowReadDepth = props.readDepth !== undefined && props.readDepth !== null && props.readDepth < 20;
42
31
  return (
43
32
  <>
44
33
  <For each={props.genotype.a}>
@@ -54,8 +43,8 @@ export const GenotypeField: Component<{
54
43
  </>
55
44
  )}
56
45
  </For>
57
- <Show when={lowReadDepth || allelicImbalance}>
58
- <abbr title={getTitle(lowReadDepth, allelicImbalance)} class="ml-1 is-clickable">
46
+ <Show when={allelicImbalance}>
47
+ <abbr title={getTitle(allelicImbalance)} class="ml-1 is-clickable">
59
48
  <i class="fas fa-circle-exclamation has-text-danger" />
60
49
  </abbr>
61
50
  </Show>
package/src/index.tsx CHANGED
@@ -18,6 +18,19 @@ import {
18
18
  faSearch,
19
19
  } from "@fortawesome/free-solid-svg-icons";
20
20
  import { Provider } from "./store";
21
+ import { ErrorBoundary } from "solid-js";
22
+ import { Error } from "./components/Error";
23
+ import { HashRouter, Route } from "@solidjs/router";
24
+ import { Home } from "./views/Home";
25
+ import { Samples } from "./views/Samples";
26
+ import { Sample } from "./views/Sample";
27
+ import { SampleVariantsView } from "./views/SampleVariants";
28
+ import { SampleVariantView } from "./views/SampleVariant";
29
+ import { SampleVariantConsequenceView } from "./views/SampleVariantConsequence";
30
+ import { VariantsView } from "./views/Variants";
31
+ import { Variant } from "./views/Variant";
32
+ import { VariantConsequence } from "./views/VariantConsequence";
33
+ import { Help } from "./views/Help";
21
34
 
22
35
  library.add(
23
36
  faAngleDown,
@@ -46,7 +59,36 @@ if (document.readyState === "complete") {
46
59
  render(
47
60
  () => (
48
61
  <Provider>
49
- <App />
62
+ <ErrorBoundary fallback={(err) => <Error error={err as unknown} />}>
63
+ <HashRouter root={App}>
64
+ <Route path="/" component={Home} />
65
+ <Route path="/samples">
66
+ <Route path="/" component={Samples} />
67
+ <Route path="/:sampleId">
68
+ <Route path="/" component={Sample} />
69
+ <Route path="/variants">
70
+ <Route path="/" component={SampleVariantsView} />
71
+ <Route path="/:variantId">
72
+ <Route path="/" component={SampleVariantView} />
73
+ <Route path="/consequences">
74
+ <Route path="/:consequenceId" component={SampleVariantConsequenceView} />
75
+ </Route>
76
+ </Route>
77
+ </Route>
78
+ </Route>
79
+ </Route>
80
+ <Route path="/variants">
81
+ <Route path="/" component={VariantsView} />
82
+ <Route path="/:variantId">
83
+ <Route path="/" component={Variant} />
84
+ <Route path="/consequences">
85
+ <Route path="/:consequenceId" component={VariantConsequence} />
86
+ </Route>
87
+ </Route>
88
+ </Route>
89
+ <Route path="/help" component={Help} />
90
+ </HashRouter>
91
+ </ErrorBoundary>
50
92
  </Provider>
51
93
  ),
52
94
  document.body,
@@ -1,4 +1,3 @@
1
- import { hashIntegration, Router } from "@solidjs/router";
2
1
  import { Context, createContext, ParentComponent, useContext } from "solid-js";
3
2
  import { createStore } from "solid-js/store";
4
3
  import { Item, Query, Sample, SortOrder } from "@molgenis/vip-report-api/src/Api";
@@ -67,16 +66,17 @@ export const Provider: ParentComponent = (props) => {
67
66
  setState({ variants: { ...(state.variants || {}), page } });
68
67
  },
69
68
  setVariantsPageSize(pageSize: number) {
70
- setState({ variants: { ...(state.variants || {}), pageSize } });
69
+ setState({ variants: { ...(state.variants || {}), pageSize, page: undefined } });
71
70
  },
72
71
  setVariantsSearchQuery(searchQuery: string) {
73
- setState({ variants: { ...(state.variants || {}), searchQuery } });
72
+ setState({ variants: { ...(state.variants || {}), searchQuery, page: undefined } });
74
73
  },
75
74
  setVariantsFilterQuery(query: Query, key: string) {
76
75
  setState({
77
76
  variants: {
78
77
  ...(state.variants || {}),
79
78
  filterQueries: { ...(state.variants?.filterQueries || {}), [key]: query },
79
+ page: undefined,
80
80
  },
81
81
  });
82
82
  },
@@ -85,6 +85,7 @@ export const Provider: ParentComponent = (props) => {
85
85
  variants: {
86
86
  ...(state.variants || {}),
87
87
  filterQueries: { ...(state.variants?.filterQueries || {}), [key]: undefined },
88
+ page: undefined,
88
89
  },
89
90
  });
90
91
  },
@@ -162,19 +163,15 @@ export const Provider: ParentComponent = (props) => {
162
163
  setState({ samples: { ...(state.samples || {}), page } });
163
164
  },
164
165
  setSampleSearchQuery(searchQuery: string) {
165
- setState({ samples: { ...(state.samples || {}), searchQuery } });
166
+ setState({ samples: { ...(state.samples || {}), searchQuery, page: undefined } });
166
167
  },
167
168
  setSampleProbandFilterValue(probandFilterValue: boolean) {
168
- setState({ samples: { ...(state.samples || {}), probandFilterValue } });
169
+ setState({ samples: { ...(state.samples || {}), probandFilterValue, page: undefined } });
169
170
  },
170
171
  };
171
172
  const store: AppStore = [state, actions];
172
173
 
173
- return (
174
- <Router source={hashIntegration()}>
175
- <StoreContext.Provider value={store}>{props.children}</StoreContext.Provider>
176
- </Router>
177
- );
174
+ return <StoreContext.Provider value={store}>{props.children}</StoreContext.Provider>;
178
175
  };
179
176
 
180
177
  export function useStore() {
@@ -1,5 +1,65 @@
1
- import { Item, Sample } from "@molgenis/vip-report-api/src/Api";
1
+ import { Sample } from "@molgenis/vip-report-api/src/Api";
2
2
 
3
- export function getSampleLabel(sample: Item<Sample>) {
4
- return sample.data.person.individualId;
3
+ export function getSampleLabel(sample: Sample) {
4
+ return sample.person.individualId;
5
+ }
6
+
7
+ export function getSampleSexLabel(sample: Sample): string {
8
+ switch (sample.person.sex) {
9
+ case "FEMALE":
10
+ return "female";
11
+ case "MALE":
12
+ return "male";
13
+ default:
14
+ return "?";
15
+ }
16
+ }
17
+
18
+ export function getSampleAffectedStatusLabel(sample: Sample): string {
19
+ switch (sample.person.affectedStatus) {
20
+ case "AFFECTED":
21
+ return "affected";
22
+ case "UNAFFECTED":
23
+ return "unaffected";
24
+ default:
25
+ return "?";
26
+ }
27
+ }
28
+
29
+ function isFamily(sample: Sample, samples: Sample): boolean {
30
+ return sample.person.familyId === samples.person.familyId;
31
+ }
32
+
33
+ function isSampleMother(sample: Sample, samples: Sample): boolean {
34
+ return isFamily(sample, samples) && samples.person.individualId === sample.person.maternalId;
35
+ }
36
+
37
+ export function getSampleMother(sample: Sample, samples: Sample[]): Sample | undefined {
38
+ if (sample.person.maternalId !== "0") {
39
+ for (const otherSample of samples) {
40
+ if (isSampleMother(sample, otherSample)) return otherSample;
41
+ }
42
+ }
43
+ }
44
+
45
+ function isSampleFather(sample: Sample, samples: Sample): boolean {
46
+ return isFamily(sample, samples) && samples.person.individualId === sample.person.paternalId;
47
+ }
48
+
49
+ export function getSampleFather(sample: Sample, samples: Sample[]): Sample | undefined {
50
+ if (sample.person.paternalId !== "0") {
51
+ for (const otherSample of samples) {
52
+ if (isSampleFather(sample, otherSample)) return otherSample;
53
+ }
54
+ }
55
+ }
56
+
57
+ export function getSampleFamilyMembersWithoutParents(sample: Sample, samples: Sample[]): Sample[] {
58
+ const familyMembersWithoutParents: Sample[] = [];
59
+ for (const otherSample of samples) {
60
+ if (isFamily(sample, otherSample) && !isSampleFather(sample, otherSample) && !isSampleMother(sample, otherSample)) {
61
+ if (sample.person.individualId !== otherSample.person.individualId) familyMembersWithoutParents.push(otherSample);
62
+ }
63
+ }
64
+ return familyMembersWithoutParents;
5
65
  }
@@ -1,13 +1,138 @@
1
- import { Component } from "solid-js";
1
+ import { Component, createResource, createSignal, For, Show } from "solid-js";
2
2
  import { Anchor } from "../components/Anchor";
3
+ import {
4
+ EMPTY_APP_METADATA,
5
+ EMPTY_HTS_FILE_METADATA,
6
+ EMPTY_PARAMS,
7
+ EMPTY_PHENOTYPES,
8
+ EMPTY_RECORDS_METADATA,
9
+ EMPTY_RECORDS_PAGE,
10
+ EMPTY_SAMPLES_PAGE,
11
+ fetchAppMetadata,
12
+ fetchHtsFileMetadata,
13
+ fetchPhenotypes,
14
+ fetchRecords,
15
+ fetchRecordsMeta,
16
+ fetchSamples,
17
+ } from "../utils/ApiUtils";
18
+ import { Loader } from "../components/Loader";
19
+ import { Breadcrumb } from "../components/Breadcrumb";
20
+ import { VcfHeaderRow } from "../components/VcfHeaderRow";
21
+ import { getHeaderValue } from "../utils/viewUtils";
22
+ import { Item, Phenotype, PhenotypicFeature } from "@molgenis/vip-report-api/src/Api";
23
+ import { HpoTerm } from "../components/HpoTerm";
3
24
  export const Help: 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 });
4
32
  return (
5
33
  <>
6
- <span>The documentation for the Variant Interpretation Pipeline is located </span>
7
- <Anchor href={`https://molgenis.github.io/vip/`}>
8
- <span>here</span>
9
- </Anchor>
10
- <span>.</span>
34
+ <Breadcrumb items={[{ text: "Help" }]} />
35
+ <div class="columns">
36
+ <div class="column">
37
+ <p class="title is-3">Documentation</p>
38
+ <span>The documentation for the Variant Interpretation Pipeline is located </span>
39
+ <Anchor href={`https://molgenis.github.io/vip/`}>
40
+ <span>here</span>
41
+ </Anchor>
42
+ <span>.</span>
43
+ </div>
44
+ </div>
45
+
46
+ <Show
47
+ when={
48
+ !samples.loading &&
49
+ !records.loading &&
50
+ !recordsMetadata.loading &&
51
+ !phenotypes.loading &&
52
+ !htsFileMetadata.loading &&
53
+ !appMetadata.loading
54
+ }
55
+ fallback={<Loader />}
56
+ >
57
+ <p class="title is-3">About</p>
58
+ <div class="columns">
59
+ <div class="column">
60
+ <div class="table-container">
61
+ <table class="table is-narrow">
62
+ <thead>
63
+ <tr>
64
+ <th colSpan={2}>Software metadata</th>
65
+ </tr>
66
+ </thead>
67
+ <tbody>
68
+ <tr>
69
+ <th>Name:</th>
70
+ <td>{appMetadata().name}</td>
71
+ </tr>
72
+ <tr>
73
+ <th>Version:</th>
74
+ <td>{appMetadata().version}</td>
75
+ </tr>
76
+ <tr>
77
+ <th>Arguments:</th>
78
+ <td>{appMetadata().args}</td>
79
+ </tr>
80
+ <VcfHeaderRow value={getHeaderValue("VIP_Version", recordsMetadata().lines)} title={"VIP Version"} />
81
+ <VcfHeaderRow value={getHeaderValue("VIP_Command", recordsMetadata().lines)} title={"VIP Command"} />
82
+ </tbody>
83
+ </table>
84
+ </div>
85
+ <div class="table-container">
86
+ <table class="table is-narrow">
87
+ <thead>
88
+ <tr>
89
+ <th colSpan={2}>Input metadata</th>
90
+ </tr>
91
+ </thead>
92
+ <tbody>
93
+ <tr>
94
+ <th>Filename:</th>
95
+ <td>{htsFileMetadata().uri}</td>
96
+ </tr>
97
+ <tr>
98
+ <th>Assembly:</th>
99
+ <td>{htsFileMetadata().genomeAssembly}</td>
100
+ </tr>
101
+ <tr>
102
+ <th>Number of records:</th>
103
+ <td>{records().total}</td>
104
+ </tr>
105
+ <tr>
106
+ <th>Number of samples:</th>
107
+ <td>{samples().total}</td>
108
+ </tr>
109
+ <tr>
110
+ <th>Phenotypes:</th>
111
+ <td>
112
+ <For each={phenotypes().items}>
113
+ {(item: Item<Phenotype>) => (
114
+ <>
115
+ <b>{item.data.subject.id}: </b>
116
+ <For each={item.data.phenotypicFeaturesList}>
117
+ {(phenotypicFeature: PhenotypicFeature, i) => (
118
+ <>
119
+ {i() > 0 ? ", " : ""}
120
+ <HpoTerm ontologyClass={phenotypicFeature.type} />
121
+ </>
122
+ )}
123
+ </For>
124
+ <br />
125
+ </>
126
+ )}
127
+ </For>
128
+ </td>
129
+ </tr>
130
+ </tbody>
131
+ </table>
132
+ </div>
133
+ </div>
134
+ </div>
135
+ </Show>
11
136
  </>
12
137
  );
13
138
  };