@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
package/.husky/pre-commit CHANGED
@@ -1,4 +1 @@
1
- #!/bin/sh
2
- . "$(dirname "$0")/_/husky.sh"
3
-
4
1
  npx lint-staged
package/.travis.yml CHANGED
@@ -27,11 +27,14 @@ deploy:
27
27
  secure: TxQUU8xNTVTqhQ6pYTR+ic7Crv6rPZ7UbRo8HJJOGlFA30Vb/O36kh3Vgwx3fM5oinC1I38pzmHjJ4WVz2qiUZcgNzDHMorQhErbfSWLO8G7XTsVkMkyozPPtgdCCT2Z7FfdTKmY5an+V4ZJlreM83+vlJmUzMoGahZElESBk94QkTnPAqk46whXAf/zToEw7OJsxd2N3uPyPB8+rgg5VMApRBsCegt3KyetiMBIYWX+kJLxXEGK7OnJmxz1SGrYHR87YEDog7awBIhrXNcBWc4Lj55oWEqp3JQlpLnVDhEUCSO8cmQkyIMTYZ3eIKoyrDk9vfAYYbDsRvagFXKTZGvv0ZQv8s7a1lWAadTyvgbmo3cvX/KHfam5pGf2DFEXWIHZgvoIzq8GY6V4sjOEWRG2sAn+jKiNT5jPgG8sG0faP2JVr55WoN4jRthk5ABckyS8PByWrwcLILTeBPuX7DpiKtzUzzRw/qHAGo59+bFyZiKIc5I+S59fnttJ6Vz4jpjsavOzNsgIGUsTs3y1kosNLYoJVcI3RjpgHQuOfzawKb2l22B5wbJ1/1llhrSqYCtEjAhUuruB3bhy+/WiN4ulKp29Ct7/IEN3ctBXdMBm2xCPlsPSTBeXzwJNeWykTnpFx9qykjtSj3CwS8ZDnY3M+/dLhywrI46EGa03YRw=
28
28
  on:
29
29
  tags: true
30
- edge: true
30
+ edge:
31
+ branch: v2.0.3-beta.4 # workaround for https://travis-ci.community/t/builds-suddenly-fail-with-error-installing-dpl/14270/3
31
32
  - provider: releases
32
33
  token:
33
34
  secure: rQ19Q5xN6T+dJp4nDT+B4QREJNCc9HpOdipE7jcAP/PVD49kd3AI4joZD9nBn53a091rl7VHviqzyRvHyvBI00VWGhQOmbUqd45c5h4Vn0qUZno2Wl2M7iuUyllvovQHS0C34nLDSBkKhJv0ESit/xiyyVy8JxwO1mgFcLgsY0cKiupwbhepUw5V2S458pNLW9e4RxT7RIaQWUagYp+PJYRKAYn5AAxih65mv2+wSGQPzcOKJDRSTlDtLaCrfZCNJm/7f3iSAOm1CCA1HLxNO2ACFL4bhnghWPS7O6VyTv1POexgwbH0OQxHmO/pdm3geLrTWX7PaHaZNUB1CHoNXC5FE/J9sUSrjClfGL9qFo5WEkBAgH3a5lLwUoCWZecUJPnyeIEFieg5OSjnXFrTECWo5Ut4g5RtzOWQtTLEwOXQgDBtE3NLkH/DRayO9vliEs9/6CnZ8AndH17cj/GmB//2DTjOMr3yCQVuI5ZeANBAUoXAg/C6kQDTdP8oyLay7UBJnX1aEWWLf3Gwo0UBFE83YIuzqVzIvU8HYgFiPgjxFwKBmebS4qu1n9ils2X0nWaY9KZY4lIjzkxsgsZ2pqt1Z6a5AQsEqXv06Tjy6tB7/I9TG7vl4eTBBJBPsRKMNnTfkE6Zr3oHC+ihWIMolAqyaTriOh23Gs/xzEuK+T8=
34
35
  file: dist/vip-report-template.html
35
36
  on:
36
37
  tags: true
37
- edge: true # opt in to dpl v2
38
+ edge:
39
+ branch: v2.0.3-beta.4 # workaround for https://travis-ci.community/t/builds-suddenly-fail-with-error-installing-dpl/14270/3
40
+
package/index.html CHANGED
@@ -1,5 +1,5 @@
1
1
  <!DOCTYPE html>
2
- <html lang="en">
2
+ <html lang="en" data-theme="light">
3
3
  <head>
4
4
  <meta charset="utf-8" />
5
5
  <meta name="viewport" content="width=device-width, initial-scale=1" />
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@molgenis/vip-report-template",
3
- "version": "6.0.1",
3
+ "version": "6.1.1",
4
4
  "description": "Report Template for Variant Call Format (VCF) Report Generator",
5
5
  "scripts": {
6
6
  "build": "vite build",
@@ -9,39 +9,39 @@
9
9
  "dev": "vite",
10
10
  "format": "prettier --write src/**/*.{tsx,ts}",
11
11
  "lint": "eslint src/**/*.{tsx,ts}",
12
- "prepare": "husky install",
12
+ "prepare": "husky",
13
13
  "test": "vitest run",
14
14
  "test:watch": "vitest"
15
15
  },
16
16
  "license": "LGPL-3.0",
17
17
  "devDependencies": {
18
- "@molgenis/vite-plugin-inline": "^1.0.21",
19
- "@typescript-eslint/eslint-plugin": "^6.19.1",
20
- "@typescript-eslint/parser": "^6.19.1",
21
- "@vitest/coverage-v8": "^1.2.1",
22
- "bulma": "^0.9.4",
23
- "eslint": "^8.56.0",
18
+ "@molgenis/vite-plugin-inline": "^1.0.24",
19
+ "@typescript-eslint/eslint-plugin": "^7.12.0",
20
+ "@typescript-eslint/parser": "^7.12.0",
21
+ "@vitest/coverage-v8": "^1.6.0",
22
+ "bulma": "^1.0.1",
23
+ "eslint": "^8.57.0",
24
24
  "eslint-config-prettier": "^9.1.0",
25
25
  "eslint-plugin-prettier": "^5.1.3",
26
- "eslint-plugin-solid": "^0.13.1",
27
- "husky": "^9.0.5",
28
- "jsdom": "^24.0.0",
29
- "prettier": "^3.2.4",
30
- "sass": "^1.70.0",
31
- "typescript": "^5.3.3",
32
- "vite": "^5.0.12",
33
- "vite-plugin-solid": "^2.9.1",
34
- "vitest": "^1.2.1"
26
+ "eslint-plugin-solid": "^0.14.0",
27
+ "husky": "^9.0.11",
28
+ "jsdom": "^24.1.0",
29
+ "prettier": "^3.3.1",
30
+ "sass": "^1.77.4",
31
+ "typescript": "^5.4.5",
32
+ "vite": "^5.2.12",
33
+ "vite-plugin-solid": "^2.10.2",
34
+ "vitest": "^1.6.0"
35
35
  },
36
36
  "dependencies": {
37
- "@fortawesome/fontawesome-svg-core": "^6.5.1",
38
- "@fortawesome/free-solid-svg-icons": "^6.5.1",
39
- "@molgenis/vip-report-api": "^5.0.2",
40
- "@molgenis/vip-report-vcf": "^2.0.0",
41
- "@solidjs/router": "^0.9.1",
37
+ "@fortawesome/fontawesome-svg-core": "^6.5.2",
38
+ "@fortawesome/free-solid-svg-icons": "^6.5.2",
39
+ "@molgenis/vip-report-api": "^5.0.4",
40
+ "@molgenis/vip-report-vcf": "^2.0.2",
41
+ "@solidjs/router": "^0.13.5",
42
42
  "base64-js": "^1.5.1",
43
43
  "igv": "^2.15.11",
44
- "solid-js": "^1.8.12"
44
+ "solid-js": "^1.8.17"
45
45
  },
46
46
  "lint-staged": {
47
47
  "src/**/*.{tsx,ts}": [
package/src/App.tsx CHANGED
@@ -1,25 +1,9 @@
1
- import { Component, ErrorBoundary, onMount } from "solid-js";
2
- import { Link, Route, Routes, useLocation, useNavigate } from "@solidjs/router";
3
- import { VariantsView } from "./views/Variants";
4
- import { Variant } from "./views/Variant";
5
- import VariantData from "./views/data/VariantData";
6
- import { Samples } from "./views/Samples";
7
- import SampleData from "./views/data/SampleData";
8
- import { Sample } from "./views/Sample";
9
- import { VariantConsequence } from "./views/VariantConsequence";
10
- import { SampleVariantConsequenceView } from "./views/SampleVariantConsequence";
11
- import { SampleVariantsView } from "./views/SampleVariants";
12
- import { Error } from "./components/Error";
13
- import SampleVariantData from "./views/data/SampleVariantData";
14
- import { SampleVariantView } from "./views/SampleVariant";
15
- import { Home } from "./views/Home";
1
+ import { onMount, ParentComponent } from "solid-js";
2
+ import { useLocation, useNavigate } from "@solidjs/router";
16
3
  import api from "./Api";
17
4
  import { DatasetDropdown } from "./components/DatasetDropdown";
18
- import SampleVariantConsequenceData from "./views/data/SampleVariantConsequenceData";
19
- import VariantConsequenceData from "./views/data/VariantConsequenceData";
20
- import { Help } from "./views/Help";
21
5
 
22
- const App: Component = () => {
6
+ const App: ParentComponent = (props) => {
23
7
  const navigate = useNavigate();
24
8
  const location = useLocation();
25
9
 
@@ -44,63 +28,38 @@ const App: Component = () => {
44
28
  <>
45
29
  <nav class="navbar is-fixed-top is-light" role="navigation" aria-label="main navigation">
46
30
  <div class="navbar-brand">
47
- <Link class="navbar-item has-text-weight-semibold" href="/">
48
- VCF Report
49
- </Link>
31
+ <a class="navbar-item has-text-weight-semibold" href="/">
32
+ Variant Interpretation Pipeline
33
+ </a>
50
34
  </div>
51
35
  <div class="navbar-menu">
52
- <div class="navbar-start">
53
- <Link class="navbar-item" href="/samples">
54
- Samples
55
- </Link>
56
- <Link class="navbar-item" href="/variants">
57
- Variants
58
- </Link>
59
- {api.isDatasetSupport() && <DatasetDropdown />}
36
+ <div class="navbar-item has-dropdown is-hoverable">
37
+ <a class="navbar-link" href="/">
38
+ Report
39
+ </a>
40
+ <div class="navbar-dropdown">
41
+ <a class="navbar-item" href="/samples">
42
+ Samples
43
+ </a>
44
+ <hr class="navbar-divider" />
45
+ <a class="navbar-item" href="/variants">
46
+ Variants
47
+ </a>
48
+ </div>
60
49
  </div>
50
+ {api.isDatasetSupport() && (
51
+ <div class="navbar-start">
52
+ <DatasetDropdown />
53
+ </div>
54
+ )}
61
55
  <div class="navbar-end">
62
- <Link class="navbar-item" href="/help">
56
+ <a class="navbar-item" href="/help">
63
57
  Help
64
- </Link>
58
+ </a>
65
59
  </div>
66
60
  </div>
67
61
  </nav>
68
- <div class="container is-fluid">
69
- <ErrorBoundary fallback={(err) => <Error error={err as unknown} />}>
70
- <Routes>
71
- <Route path="/" element={<Home />} />
72
- <Route path="/samples">
73
- <Route path="/" element={<Samples />} />
74
- <Route path="/:sampleId" data={SampleData}>
75
- <Route path="/" element={<Sample />} />
76
- <Route path="/variants">
77
- <Route path="/" element={<SampleVariantsView />} />
78
- <Route path="/:variantId" data={SampleVariantData}>
79
- <Route path="/" element={<SampleVariantView />} />
80
- <Route path="/consequences">
81
- <Route
82
- path="/:consequenceId"
83
- element={<SampleVariantConsequenceView />}
84
- data={SampleVariantConsequenceData}
85
- />
86
- </Route>
87
- </Route>
88
- </Route>
89
- </Route>
90
- </Route>
91
- <Route path="/variants">
92
- <Route path="/" element={<VariantsView />} />
93
- <Route path="/:variantId" data={VariantData}>
94
- <Route path="/" element={<Variant />} />
95
- <Route path="/consequences">
96
- <Route path="/:consequenceId" element={<VariantConsequence />} data={VariantConsequenceData} />
97
- </Route>
98
- </Route>
99
- </Route>
100
- <Route path="/help" element={<Help />} />
101
- </Routes>
102
- </ErrorBoundary>
103
- </div>
62
+ <div class="container is-fluid">{props.children}</div>
104
63
  </>
105
64
  );
106
65
  };
@@ -0,0 +1,184 @@
1
+ import { describe, expect, test } from "vitest";
2
+ import {
3
+ getSampleAffectedStatusLabel,
4
+ getSampleFamilyMembersWithoutParents,
5
+ getSampleFather,
6
+ getSampleLabel,
7
+ getSampleMother,
8
+ getSampleSexLabel,
9
+ } from "../utils/sample";
10
+ import { Sample } from "@molgenis/vip-report-api/src/Api";
11
+
12
+ describe("sample utilities", () => {
13
+ const sample = {
14
+ person: {
15
+ familyId: "fam0",
16
+ individualId: "0",
17
+ maternalId: "1",
18
+ paternalId: "2",
19
+ },
20
+ } as Sample;
21
+ const motherSample = {
22
+ person: {
23
+ familyId: "fam0",
24
+ individualId: "1",
25
+ },
26
+ } as Sample;
27
+ const fatherSample = {
28
+ person: {
29
+ familyId: "fam0",
30
+ individualId: "2",
31
+ },
32
+ } as Sample;
33
+ const siblingSample = {
34
+ person: {
35
+ familyId: "fam0",
36
+ individualId: "3",
37
+ maternalId: "1",
38
+ paternalId: "2",
39
+ },
40
+ } as Sample;
41
+ const otherMotherSample = {
42
+ person: {
43
+ familyId: "fam1",
44
+ individualId: "1",
45
+ },
46
+ } as Sample;
47
+ const otherFatherSample = {
48
+ person: {
49
+ familyId: "fam1",
50
+ individualId: "2",
51
+ },
52
+ } as Sample;
53
+ const otherSiblingSample = {
54
+ person: {
55
+ familyId: "fam1",
56
+ individualId: "3",
57
+ maternalId: "1",
58
+ paternalId: "2",
59
+ },
60
+ } as Sample;
61
+
62
+ test("getSampleLabel", () => {
63
+ const individualId = "sample_label";
64
+ const sample = {
65
+ person: {
66
+ individualId: individualId,
67
+ },
68
+ } as Sample;
69
+ expect(getSampleLabel(sample)).toBe(individualId);
70
+ });
71
+
72
+ test("getSampleSexLabel:FEMALE", () => {
73
+ const sample = {
74
+ person: {
75
+ sex: "FEMALE",
76
+ },
77
+ } as Sample;
78
+ expect(getSampleSexLabel(sample)).toBe("female");
79
+ });
80
+
81
+ test("getSampleSexLabel:MALE", () => {
82
+ const sample = {
83
+ person: {
84
+ sex: "MALE",
85
+ },
86
+ } as Sample;
87
+ expect(getSampleSexLabel(sample)).toBe("male");
88
+ });
89
+
90
+ test("getSampleSexLabel:OTHER_SEX", () => {
91
+ const sample = {
92
+ person: {
93
+ sex: "OTHER_SEX",
94
+ },
95
+ } as Sample;
96
+ expect(getSampleSexLabel(sample)).toBe("?");
97
+ });
98
+
99
+ test("getSampleSexLabel:UNKNOWN_SEX", () => {
100
+ const sample = {
101
+ person: {
102
+ sex: "UNKNOWN_SEX",
103
+ },
104
+ } as Sample;
105
+ expect(getSampleSexLabel(sample)).toBe("?");
106
+ });
107
+
108
+ test("getSampleAffectedStatusLabel:AFFECTED", () => {
109
+ const sample = {
110
+ person: {
111
+ affectedStatus: "AFFECTED",
112
+ },
113
+ } as Sample;
114
+ expect(getSampleAffectedStatusLabel(sample)).toBe("affected");
115
+ });
116
+
117
+ test("getSampleAffectedStatusLabel:UNAFFECTED", () => {
118
+ const sample = {
119
+ person: {
120
+ affectedStatus: "UNAFFECTED",
121
+ },
122
+ } as Sample;
123
+ expect(getSampleAffectedStatusLabel(sample)).toBe("unaffected");
124
+ });
125
+
126
+ test("getSampleAffectedStatusLabel:MISSING", () => {
127
+ const sample = {
128
+ person: {
129
+ affectedStatus: "MISSING",
130
+ },
131
+ } as Sample;
132
+ expect(getSampleAffectedStatusLabel(sample)).toBe("?");
133
+ });
134
+
135
+ test("getSampleMother", () => {
136
+ expect(
137
+ getSampleMother(sample, [
138
+ sample,
139
+ otherSiblingSample,
140
+ otherFatherSample,
141
+ otherMotherSample,
142
+ siblingSample,
143
+ fatherSample,
144
+ motherSample,
145
+ ]),
146
+ ).toStrictEqual(motherSample);
147
+ });
148
+
149
+ test("getSampleMother:undefined", () => {
150
+ expect(getSampleMother(sample, [sample, otherSiblingSample, otherFatherSample, otherMotherSample])).toBeUndefined();
151
+ });
152
+
153
+ test("getSampleFather", () => {
154
+ expect(
155
+ getSampleFather(sample, [
156
+ sample,
157
+ otherSiblingSample,
158
+ otherMotherSample,
159
+ otherFatherSample,
160
+ siblingSample,
161
+ motherSample,
162
+ fatherSample,
163
+ ]),
164
+ ).toStrictEqual(fatherSample);
165
+ });
166
+
167
+ test("getSampleFather:undefined", () => {
168
+ expect(getSampleFather(sample, [sample, otherSiblingSample, otherMotherSample, otherFatherSample])).toBeUndefined();
169
+ });
170
+
171
+ test("getSampleFamilyMembersWithoutParents", () => {
172
+ expect(
173
+ getSampleFamilyMembersWithoutParents(sample, [
174
+ sample,
175
+ otherSiblingSample,
176
+ otherMotherSample,
177
+ otherFatherSample,
178
+ siblingSample,
179
+ motherSample,
180
+ fatherSample,
181
+ ]),
182
+ ).toStrictEqual([siblingSample]);
183
+ });
184
+ });
@@ -1,50 +1,9 @@
1
1
  @charset "utf-8";
2
- $gap: 8px;
3
-
4
- $notification-padding: 0.75rem 0.75rem 0.75rem 0.75rem;
5
- $notification-padding-ltr: 0.75rem 0.75rem 0.75rem 0.75rem;
6
- $notification-padding-rtl: 0.75rem 0.75rem 0.75rem 0.75rem;
7
-
8
- @import "bulma/sass/utilities/initial-variables";
9
- @import "bulma/sass/utilities/functions";
10
- @import "bulma/sass/utilities/derived-variables";
11
- @import "bulma/sass/utilities/mixins";
12
- @import "bulma/sass/utilities/controls";
13
- @import "bulma/sass/utilities/extends";
14
-
15
- @import "bulma/sass/base/minireset";
16
- @import "bulma/sass/base/generic";
17
- @import "bulma/sass/base/animations";
18
-
19
- @import "bulma/sass/elements/button";
20
- @import "bulma/sass/elements/container";
21
- @import "bulma/sass/elements/icon";
22
- @import "bulma/sass/elements/notification";
23
- @import "bulma/sass/elements/table";
24
- @import "bulma/sass/elements/title";
25
-
26
- @import "bulma/sass/form/shared";
27
- @import "bulma/sass/form/input-textarea";
28
- @import "bulma/sass/form/checkbox-radio";
29
- @import "bulma/sass/form/select";
30
- @import "bulma/sass/form/tools";
31
-
32
- @import "bulma/sass/grid/columns";
33
-
34
- @import "bulma/sass/components/breadcrumb";
35
- @import "bulma/sass/components/card";
36
- @import "bulma/sass/components/navbar";
37
- @import "bulma/sass/components/pagination";
38
-
39
- @import "bulma/sass/helpers/color";
40
- @import "bulma/sass/helpers/flexbox";
41
- @import "bulma/sass/helpers/float";
42
- @import "bulma/sass/helpers/other";
43
- @import "bulma/sass/helpers/overflow";
44
- @import "bulma/sass/helpers/position";
45
- @import "bulma/sass/helpers/spacing";
46
- @import "bulma/sass/helpers/typography";
47
- @import "bulma/sass/helpers/visibility";
2
+
3
+ @use "bulma/sass" with(
4
+ $gap: 8px,
5
+ $notification-padding: 0.75rem 0.75rem,
6
+ );
48
7
 
49
8
  html {
50
9
  font-size: 13px;
@@ -92,7 +51,7 @@ td {
92
51
  }
93
52
 
94
53
  .pagination-ellipsis {
95
- min-width: $pagination-min-width;
54
+ min-width: 2.5em;
96
55
  }
97
56
 
98
57
  .container {
@@ -120,4 +79,10 @@ table.is-borderless td,
120
79
 
121
80
  .inline-control-text {
122
81
  line-height: 32.5px
82
+ }
83
+
84
+ .scrolling-div {
85
+ margin-top: 8px;
86
+ overflow-y: auto;
87
+ max-height: calc(100vh - 78px) !important;
123
88
  }
@@ -1,4 +1,3 @@
1
- import { Link } from "@solidjs/router";
2
1
  import { Component, For } from "solid-js";
3
2
 
4
3
  export type BreadCrumbItem = { href?: string; text: string };
@@ -9,19 +8,20 @@ export const Breadcrumb: Component<{
9
8
  return (
10
9
  <div class="columns is-gapless">
11
10
  <div class="column">
12
- <nav class="breadcrumb">
11
+ <nav class="breadcrumb has-succeeds-separator">
13
12
  <ul>
14
13
  <li classList={{ "is-active": props.items.length === 0 }}>
15
- <Link href="/">
16
- <span class="icon">
14
+ <a href="/">
15
+ <span class="icon is-small mr-2">
17
16
  <i class="fas fa-home" />
18
17
  </span>
19
- </Link>
18
+ <span>Report</span>
19
+ </a>
20
20
  </li>
21
21
  <For each={props.items}>
22
22
  {(link, i) => (
23
23
  <li classList={{ "is-active": i() === props.items.length - 1 }}>
24
- <Link href={link.href || "#"}>{link.text}</Link>
24
+ <a href={link.href || "#"}>{link.text}</a>
25
25
  </li>
26
26
  )}
27
27
  </For>
@@ -6,7 +6,7 @@ import { ValueArray } from "@molgenis/vip-report-vcf/src/ValueParser";
6
6
  import { Info } from "./record/Info";
7
7
  import { FieldValue } from "./record/field/Field";
8
8
  import { isCsqInfo } from "../utils/csqUtils";
9
- import { Link, useLocation } from "@solidjs/router";
9
+ import { useLocation } from "@solidjs/router";
10
10
 
11
11
  export const InfoCollapsablePane: Component<{
12
12
  fields: FieldMetadata[];
@@ -58,8 +58,8 @@ export const InfoCollapsablePane: Component<{
58
58
  <>
59
59
  {j() != 0 && collapsed() && <br />}
60
60
  {(j() == 0 || collapsed()) &&
61
- (isCsqInfo(field, "Consequence") ? (
62
- <Link href={`${useLocation().pathname}/${props.record.id}/consequences/${j()}`}>
61
+ (isCsqInfo(field, "VIPC") ? (
62
+ <a href={`${useLocation().pathname}/${props.record.id}/consequences/${j()}`}>
63
63
  <Info
64
64
  info={value}
65
65
  infoMeta={field}
@@ -68,7 +68,7 @@ export const InfoCollapsablePane: Component<{
68
68
  isPossibleCompound: props.isPossibleCompound,
69
69
  }}
70
70
  />
71
- </Link>
71
+ </a>
72
72
  ) : (
73
73
  <Info
74
74
  info={value}
@@ -1,40 +1,15 @@
1
- import { Link } from "@solidjs/router";
1
+ import { useNavigate } from "@solidjs/router";
2
2
  import { Component, createMemo, For, Show } from "solid-js";
3
3
  import { Item, Phenotype, PhenotypicFeature, Sample } from "@molgenis/vip-report-api/src/Api";
4
4
  import { HpoTerm } from "./HpoTerm";
5
5
  import { Anchor } from "./Anchor";
6
-
7
- function getAffectedStatusLabel(affectedStatus: string) {
8
- let label;
9
- switch (affectedStatus) {
10
- case "AFFECTED":
11
- label = "Affected";
12
- break;
13
- case "UNAFFECTED":
14
- label = "Unaffected";
15
- break;
16
- default:
17
- label = "?";
18
- break;
19
- }
20
- return label;
21
- }
22
-
23
- function getSexLabel(sex: string) {
24
- let label;
25
- switch (sex) {
26
- case "MALE":
27
- label = "Male";
28
- break;
29
- case "FEMALE":
30
- label = "Female";
31
- break;
32
- default:
33
- label = "?";
34
- break;
35
- }
36
- return label;
37
- }
6
+ import {
7
+ getSampleAffectedStatusLabel,
8
+ getSampleFather,
9
+ getSampleLabel,
10
+ getSampleMother,
11
+ getSampleSexLabel,
12
+ } from "../utils/sample";
38
13
 
39
14
  function mapPhenotypes(phenotypes: Item<Phenotype>[]) {
40
15
  const phenoMap: { [key: string]: PhenotypicFeature[] } = {};
@@ -48,11 +23,23 @@ export const SampleTable: Component<{
48
23
  samples: Item<Sample>[];
49
24
  phenotypes: Item<Phenotype>[];
50
25
  }> = (props) => {
26
+ const navigate = useNavigate();
27
+ const samples = createMemo(() => props.samples.map((item) => item.data));
51
28
  const phenoMap = createMemo(() => mapPhenotypes(props.phenotypes));
52
29
 
53
- function getPhenotypes(sampleId: string) {
54
- return phenoMap()[sampleId] !== undefined ? phenoMap()[sampleId] : [];
55
- }
30
+ const samplePhenotypes = (sample: Sample): PhenotypicFeature[] => {
31
+ return phenoMap()[sample.person.individualId] ?? [];
32
+ };
33
+
34
+ const sampleFatherLabel = (sample: Sample): string => {
35
+ const sampleFather = getSampleFather(sample, samples());
36
+ return sampleFather ? getSampleLabel(sampleFather) : "";
37
+ };
38
+
39
+ const sampleMotherLabel = (sample: Sample): string => {
40
+ const sampleMother = getSampleMother(sample, samples());
41
+ return sampleMother ? getSampleLabel(sampleMother) : "";
42
+ };
56
43
 
57
44
  return (
58
45
  <div style={{ display: "grid" }}>
@@ -70,6 +57,7 @@ export const SampleTable: Component<{
70
57
  <th>Affected</th>
71
58
  <th>Phenotypes</th>
72
59
  <th>VIBE</th>
60
+ <th />
73
61
  </tr>
74
62
  </thead>
75
63
  <tbody>
@@ -78,15 +66,15 @@ export const SampleTable: Component<{
78
66
  <tr>
79
67
  <td>{sample.data.person.familyId}</td>
80
68
  <td>
81
- <Link href={`/samples/${sample.id}`}>{sample.data.person.individualId}</Link>
69
+ <a href={`/samples/${sample.id}`}>{getSampleLabel(sample.data)}</a>
82
70
  </td>
83
- <td>{sample.data.person.paternalId}</td>
84
- <td>{sample.data.person.maternalId}</td>
71
+ <td>{sampleFatherLabel(sample.data)}</td>
72
+ <td>{sampleMotherLabel(sample.data)}</td>
85
73
  <td>{sample.data.proband === true ? "True" : "False"}</td>
86
- <td>{getSexLabel(sample.data.person.sex)}</td>
87
- <td>{getAffectedStatusLabel(sample.data.person.affectedStatus)}</td>
74
+ <td>{getSampleSexLabel(sample.data)}</td>
75
+ <td>{getSampleAffectedStatusLabel(sample.data)}</td>
88
76
  <td>
89
- <For each={getPhenotypes(sample.data.person.individualId)}>
77
+ <For each={samplePhenotypes(sample.data)}>
90
78
  {(phenotypicFeature: PhenotypicFeature, i) => (
91
79
  <>
92
80
  {i() > 0 ? ", " : ""}
@@ -96,11 +84,9 @@ export const SampleTable: Component<{
96
84
  </For>
97
85
  </td>
98
86
  <td>
99
- <Show when={getPhenotypes(sample.data.person.individualId).length > 0}>
87
+ <Show when={samplePhenotypes(sample.data).length > 0}>
100
88
  <Anchor
101
- href={`https://vibe.molgeniscloud.org/?phenotypes=${getPhenotypes(
102
- sample.data.person.individualId,
103
- )
89
+ href={`https://vibe.molgeniscloud.org/?phenotypes=${samplePhenotypes(sample.data)
104
90
  .map((feature) => feature.type.id)
105
91
  .join(",")}`}
106
92
  >
@@ -108,6 +94,11 @@ export const SampleTable: Component<{
108
94
  </Anchor>
109
95
  </Show>
110
96
  </td>
97
+ <td>
98
+ <button class="button is-primary py-1" onClick={() => navigate(`/samples/${sample.id}/variants`)}>
99
+ Explore Variants
100
+ </button>
101
+ </td>
111
102
  </tr>
112
103
  )}
113
104
  </For>