diff --git a/frontend/package-lock.json b/frontend/package-lock.json
index 56160af6..d1eb424d 100644
--- a/frontend/package-lock.json
+++ b/frontend/package-lock.json
@@ -24,7 +24,7 @@
"@fortawesome/free-solid-svg-icons": "^6.2.0",
"@ng-bootstrap/ng-bootstrap": "10.0.0",
"@panva/oauth4webapi": "^1.1.3",
- "angular-datatables": "^14.0.0",
+ "@swimlane/ngx-datatable": "^20.0.0",
"bootstrap": "^4.4.1",
"chart.js": "2.9.4",
"fhirclient": "^2.5.1",
@@ -3329,6 +3329,20 @@
"yarn": ">= 1.13.0"
}
},
+ "node_modules/@swimlane/ngx-datatable": {
+ "version": "20.0.0",
+ "resolved": "https://registry.npmjs.org/@swimlane/ngx-datatable/-/ngx-datatable-20.0.0.tgz",
+ "integrity": "sha512-fok9xzOA5UqhmoRKHpEz25k2wXD/ZGtAAeTQqkn/FpyLgPtdWV2OF/wNIyIZaDJ8jBlNoeHTnJnkDONnFGV93A==",
+ "dependencies": {
+ "tslib": "^2.0.0"
+ },
+ "peerDependencies": {
+ "@angular/common": ">=11.0.2",
+ "@angular/core": ">=11.0.2",
+ "@angular/platform-browser": ">=11.0.2",
+ "rxjs": "^6.6.3"
+ }
+ },
"node_modules/@tootallnate/once": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-2.0.0.tgz",
@@ -3950,87 +3964,6 @@
"ajv": "^6.9.1"
}
},
- "node_modules/angular-datatables": {
- "version": "14.0.0",
- "resolved": "https://registry.npmjs.org/angular-datatables/-/angular-datatables-14.0.0.tgz",
- "integrity": "sha512-IdJdS/IGAFKcWKCM3PrgHt8YIyCGxUKaPQGQom+5YvAcIMKuRwgB7aYT2H3+zUsJBNms2Yaeh95ABNT+yqOwLQ==",
- "dependencies": {
- "codelyzer": "^6.0.2"
- },
- "engines": {
- "node": ">=8.9.0"
- }
- },
- "node_modules/angular-datatables/node_modules/@angular/compiler": {
- "version": "9.0.0",
- "resolved": "https://registry.npmjs.org/@angular/compiler/-/compiler-9.0.0.tgz",
- "integrity": "sha512-ctjwuntPfZZT2mNj2NDIVu51t9cvbhl/16epc5xEwyzyDt76pX9UgwvY+MbXrf/C/FWwdtmNtfP698BKI+9leQ==",
- "peerDependencies": {
- "tslib": "^1.10.0"
- }
- },
- "node_modules/angular-datatables/node_modules/@angular/core": {
- "version": "9.0.0",
- "resolved": "https://registry.npmjs.org/@angular/core/-/core-9.0.0.tgz",
- "integrity": "sha512-6Pxgsrf0qF9iFFqmIcWmjJGkkCaCm6V5QNnxMy2KloO3SDq6QuMVRbN9RtC8Urmo25LP+eZ6ZgYqFYpdD8Hd9w==",
- "peerDependencies": {
- "rxjs": "^6.5.3",
- "tslib": "^1.10.0",
- "zone.js": "~0.10.2"
- }
- },
- "node_modules/angular-datatables/node_modules/app-root-path": {
- "version": "3.1.0",
- "resolved": "https://registry.npmjs.org/app-root-path/-/app-root-path-3.1.0.tgz",
- "integrity": "sha512-biN3PwB2gUtjaYy/isrU3aNWI5w+fAfvHkSvCKeQGxhmYpwKFUxudR3Yya+KqVRHBmEDYh+/lTozYCFbmzX4nA==",
- "engines": {
- "node": ">= 6.0.0"
- }
- },
- "node_modules/angular-datatables/node_modules/codelyzer": {
- "version": "6.0.2",
- "resolved": "https://registry.npmjs.org/codelyzer/-/codelyzer-6.0.2.tgz",
- "integrity": "sha512-v3+E0Ucu2xWJMOJ2fA/q9pDT/hlxHftHGPUay1/1cTgyPV5JTHFdO9hqo837Sx2s9vKBMTt5gO+lhF95PO6J+g==",
- "dependencies": {
- "@angular/compiler": "9.0.0",
- "@angular/core": "9.0.0",
- "app-root-path": "^3.0.0",
- "aria-query": "^3.0.0",
- "axobject-query": "2.0.2",
- "css-selector-tokenizer": "^0.7.1",
- "cssauron": "^1.4.0",
- "damerau-levenshtein": "^1.0.4",
- "rxjs": "^6.5.3",
- "semver-dsl": "^1.0.1",
- "source-map": "^0.5.7",
- "sprintf-js": "^1.1.2",
- "tslib": "^1.10.0",
- "zone.js": "~0.10.3"
- },
- "peerDependencies": {
- "@angular/compiler": ">=2.3.1 <13.0.0 || ^12.0.0-next || ^12.1.0-next || ^12.2.0-next",
- "@angular/core": ">=2.3.1 <13.0.0 || ^12.0.0-next || ^12.1.0-next || ^12.2.0-next",
- "tslint": "^5.0.0 || ^6.0.0"
- }
- },
- "node_modules/angular-datatables/node_modules/source-map": {
- "version": "0.5.7",
- "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
- "integrity": "sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==",
- "engines": {
- "node": ">=0.10.0"
- }
- },
- "node_modules/angular-datatables/node_modules/tslib": {
- "version": "1.14.1",
- "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz",
- "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg=="
- },
- "node_modules/angular-datatables/node_modules/zone.js": {
- "version": "0.10.3",
- "resolved": "https://registry.npmjs.org/zone.js/-/zone.js-0.10.3.tgz",
- "integrity": "sha512-LXVLVEq0NNOqK/fLJo3d0kfzd4sxwn2/h67/02pjCjfKDxgx1i9QqpvtHD8CrBnSSwMw5+dy11O7FRX5mkO7Cg=="
- },
"node_modules/ansi-colors": {
"version": "4.1.3",
"resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.3.tgz",
@@ -4166,6 +4099,7 @@
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/aria-query/-/aria-query-3.0.0.tgz",
"integrity": "sha512-majUxHgLehQTeSA+hClx+DY09OVUqG3GtezWkF1krgLGNdlDu9l9V8DaqNMWbq4Eddc8wsyDA0hpDUtnYxQEXw==",
+ "dev": true,
"dependencies": {
"ast-types-flow": "0.0.7",
"commander": "^2.11.0"
@@ -4234,7 +4168,8 @@
"node_modules/ast-types-flow": {
"version": "0.0.7",
"resolved": "https://registry.npmjs.org/ast-types-flow/-/ast-types-flow-0.0.7.tgz",
- "integrity": "sha512-eBvWn1lvIApYMhzQMsu9ciLfkBY499mFZlNqG+/9WR7PVlroQw0vG30cOQQbaKz3sCEc44TAOu2ykzqXSNnwag=="
+ "integrity": "sha512-eBvWn1lvIApYMhzQMsu9ciLfkBY499mFZlNqG+/9WR7PVlroQw0vG30cOQQbaKz3sCEc44TAOu2ykzqXSNnwag==",
+ "dev": true
},
"node_modules/asynckit": {
"version": "0.4.0",
@@ -4315,6 +4250,7 @@
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-2.0.2.tgz",
"integrity": "sha512-MCeek8ZH7hKyO1rWUbKNQBbl4l2eY0ntk7OGi+q0RlafrCnfPxC06WZA+uebCfmYp4mNU9jRBP1AhGyf8+W3ww==",
+ "dev": true,
"dependencies": {
"ast-types-flow": "0.0.7"
}
@@ -5134,7 +5070,8 @@
"node_modules/commander": {
"version": "2.20.3",
"resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz",
- "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ=="
+ "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==",
+ "dev": true
},
"node_modules/commondir": {
"version": "1.0.1",
@@ -5721,6 +5658,7 @@
"version": "0.7.3",
"resolved": "https://registry.npmjs.org/css-selector-tokenizer/-/css-selector-tokenizer-0.7.3.tgz",
"integrity": "sha512-jWQv3oCEL5kMErj4wRnK/OPoBi0D+P1FR2cDCKYPaMeD2eW3/mttav8HT4hT1CKopiJI/psEULjkClhvJo4Lvg==",
+ "dev": true,
"dependencies": {
"cssesc": "^3.0.0",
"fastparse": "^1.1.2"
@@ -5751,6 +5689,7 @@
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/cssauron/-/cssauron-1.4.0.tgz",
"integrity": "sha512-Ht70DcFBh+/ekjVrYS2PlDMdSQEl3OFNmjK6lcn49HptBgilXf/Zwg4uFh9Xn0pX3Q8YOkSjIFOfK2osvdqpBw==",
+ "dev": true,
"dependencies": {
"through": "X.X.X"
}
@@ -5769,6 +5708,7 @@
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz",
"integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==",
+ "dev": true,
"bin": {
"cssesc": "bin/cssesc"
},
@@ -5785,7 +5725,8 @@
"node_modules/damerau-levenshtein": {
"version": "1.0.8",
"resolved": "https://registry.npmjs.org/damerau-levenshtein/-/damerau-levenshtein-1.0.8.tgz",
- "integrity": "sha512-sdQSFB7+llfUcQHUQO3+B8ERRj0Oa4w9POWMI/puGtuf7gFywGmkaLCElnudfTiKZV+NvHqL0ifzdrI8Ro7ESA=="
+ "integrity": "sha512-sdQSFB7+llfUcQHUQO3+B8ERRj0Oa4w9POWMI/puGtuf7gFywGmkaLCElnudfTiKZV+NvHqL0ifzdrI8Ro7ESA==",
+ "dev": true
},
"node_modules/dashdash": {
"version": "1.14.1",
@@ -7154,7 +7095,8 @@
"node_modules/fastparse": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/fastparse/-/fastparse-1.1.2.tgz",
- "integrity": "sha512-483XLLxTVIwWK3QTrMGRqUfUpoOs/0hbQrl2oz4J0pAcm3A3bu84wxTFqGqkJzewCLdME38xJLJAxBABfQT8sQ=="
+ "integrity": "sha512-483XLLxTVIwWK3QTrMGRqUfUpoOs/0hbQrl2oz4J0pAcm3A3bu84wxTFqGqkJzewCLdME38xJLJAxBABfQT8sQ==",
+ "dev": true
},
"node_modules/fastq": {
"version": "1.13.0",
@@ -12580,6 +12522,7 @@
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/semver-dsl/-/semver-dsl-1.0.1.tgz",
"integrity": "sha512-e8BOaTo007E3dMuQQTnPdalbKTABKNS7UxoBIDnwOqRa+QwMrCPjynB8zAlPF6xlqUfdLPPLIJ13hJNmhtq8Ng==",
+ "dev": true,
"dependencies": {
"semver": "^5.3.0"
}
@@ -12588,6 +12531,7 @@
"version": "5.7.1",
"resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz",
"integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==",
+ "dev": true,
"bin": {
"semver": "bin/semver"
}
@@ -13092,7 +13036,8 @@
"node_modules/sprintf-js": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.1.2.tgz",
- "integrity": "sha512-VE0SOVEHCk7Qc8ulkWw3ntAzXuqf7S2lvwQaDLRnUeIEaKNQJzV6BwmLKhOqT61aGhfUMrXeaBk+oDGCzvhcug=="
+ "integrity": "sha512-VE0SOVEHCk7Qc8ulkWw3ntAzXuqf7S2lvwQaDLRnUeIEaKNQJzV6BwmLKhOqT61aGhfUMrXeaBk+oDGCzvhcug==",
+ "dev": true
},
"node_modules/sshpk": {
"version": "1.17.0",
@@ -13419,7 +13364,8 @@
"node_modules/through": {
"version": "2.3.8",
"resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz",
- "integrity": "sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg=="
+ "integrity": "sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==",
+ "dev": true
},
"node_modules/thunky": {
"version": "1.1.0",
@@ -16837,6 +16783,14 @@
"jsonc-parser": "3.1.0"
}
},
+ "@swimlane/ngx-datatable": {
+ "version": "20.0.0",
+ "resolved": "https://registry.npmjs.org/@swimlane/ngx-datatable/-/ngx-datatable-20.0.0.tgz",
+ "integrity": "sha512-fok9xzOA5UqhmoRKHpEz25k2wXD/ZGtAAeTQqkn/FpyLgPtdWV2OF/wNIyIZaDJ8jBlNoeHTnJnkDONnFGV93A==",
+ "requires": {
+ "tslib": "^2.0.0"
+ }
+ },
"@tootallnate/once": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-2.0.0.tgz",
@@ -17407,67 +17361,6 @@
"integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==",
"dev": true
},
- "angular-datatables": {
- "version": "14.0.0",
- "resolved": "https://registry.npmjs.org/angular-datatables/-/angular-datatables-14.0.0.tgz",
- "integrity": "sha512-IdJdS/IGAFKcWKCM3PrgHt8YIyCGxUKaPQGQom+5YvAcIMKuRwgB7aYT2H3+zUsJBNms2Yaeh95ABNT+yqOwLQ==",
- "requires": {
- "codelyzer": "^6.0.2"
- },
- "dependencies": {
- "@angular/compiler": {
- "version": "9.0.0",
- "resolved": "https://registry.npmjs.org/@angular/compiler/-/compiler-9.0.0.tgz",
- "integrity": "sha512-ctjwuntPfZZT2mNj2NDIVu51t9cvbhl/16epc5xEwyzyDt76pX9UgwvY+MbXrf/C/FWwdtmNtfP698BKI+9leQ=="
- },
- "@angular/core": {
- "version": "9.0.0",
- "resolved": "https://registry.npmjs.org/@angular/core/-/core-9.0.0.tgz",
- "integrity": "sha512-6Pxgsrf0qF9iFFqmIcWmjJGkkCaCm6V5QNnxMy2KloO3SDq6QuMVRbN9RtC8Urmo25LP+eZ6ZgYqFYpdD8Hd9w=="
- },
- "app-root-path": {
- "version": "3.1.0",
- "resolved": "https://registry.npmjs.org/app-root-path/-/app-root-path-3.1.0.tgz",
- "integrity": "sha512-biN3PwB2gUtjaYy/isrU3aNWI5w+fAfvHkSvCKeQGxhmYpwKFUxudR3Yya+KqVRHBmEDYh+/lTozYCFbmzX4nA=="
- },
- "codelyzer": {
- "version": "6.0.2",
- "resolved": "https://registry.npmjs.org/codelyzer/-/codelyzer-6.0.2.tgz",
- "integrity": "sha512-v3+E0Ucu2xWJMOJ2fA/q9pDT/hlxHftHGPUay1/1cTgyPV5JTHFdO9hqo837Sx2s9vKBMTt5gO+lhF95PO6J+g==",
- "requires": {
- "@angular/compiler": "9.0.0",
- "@angular/core": "9.0.0",
- "app-root-path": "^3.0.0",
- "aria-query": "^3.0.0",
- "axobject-query": "2.0.2",
- "css-selector-tokenizer": "^0.7.1",
- "cssauron": "^1.4.0",
- "damerau-levenshtein": "^1.0.4",
- "rxjs": "^6.5.3",
- "semver-dsl": "^1.0.1",
- "source-map": "^0.5.7",
- "sprintf-js": "^1.1.2",
- "tslib": "^1.10.0",
- "zone.js": "~0.10.3"
- }
- },
- "source-map": {
- "version": "0.5.7",
- "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
- "integrity": "sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ=="
- },
- "tslib": {
- "version": "1.14.1",
- "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz",
- "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg=="
- },
- "zone.js": {
- "version": "0.10.3",
- "resolved": "https://registry.npmjs.org/zone.js/-/zone.js-0.10.3.tgz",
- "integrity": "sha512-LXVLVEq0NNOqK/fLJo3d0kfzd4sxwn2/h67/02pjCjfKDxgx1i9QqpvtHD8CrBnSSwMw5+dy11O7FRX5mkO7Cg=="
- }
- }
- },
"ansi-colors": {
"version": "4.1.3",
"resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.3.tgz",
@@ -17574,6 +17467,7 @@
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/aria-query/-/aria-query-3.0.0.tgz",
"integrity": "sha512-majUxHgLehQTeSA+hClx+DY09OVUqG3GtezWkF1krgLGNdlDu9l9V8DaqNMWbq4Eddc8wsyDA0hpDUtnYxQEXw==",
+ "dev": true,
"requires": {
"ast-types-flow": "0.0.7",
"commander": "^2.11.0"
@@ -17630,7 +17524,8 @@
"ast-types-flow": {
"version": "0.0.7",
"resolved": "https://registry.npmjs.org/ast-types-flow/-/ast-types-flow-0.0.7.tgz",
- "integrity": "sha512-eBvWn1lvIApYMhzQMsu9ciLfkBY499mFZlNqG+/9WR7PVlroQw0vG30cOQQbaKz3sCEc44TAOu2ykzqXSNnwag=="
+ "integrity": "sha512-eBvWn1lvIApYMhzQMsu9ciLfkBY499mFZlNqG+/9WR7PVlroQw0vG30cOQQbaKz3sCEc44TAOu2ykzqXSNnwag==",
+ "dev": true
},
"asynckit": {
"version": "0.4.0",
@@ -17680,6 +17575,7 @@
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-2.0.2.tgz",
"integrity": "sha512-MCeek8ZH7hKyO1rWUbKNQBbl4l2eY0ntk7OGi+q0RlafrCnfPxC06WZA+uebCfmYp4mNU9jRBP1AhGyf8+W3ww==",
+ "dev": true,
"requires": {
"ast-types-flow": "0.0.7"
}
@@ -18299,7 +18195,8 @@
"commander": {
"version": "2.20.3",
"resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz",
- "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ=="
+ "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==",
+ "dev": true
},
"commondir": {
"version": "1.0.1",
@@ -18752,6 +18649,7 @@
"version": "0.7.3",
"resolved": "https://registry.npmjs.org/css-selector-tokenizer/-/css-selector-tokenizer-0.7.3.tgz",
"integrity": "sha512-jWQv3oCEL5kMErj4wRnK/OPoBi0D+P1FR2cDCKYPaMeD2eW3/mttav8HT4hT1CKopiJI/psEULjkClhvJo4Lvg==",
+ "dev": true,
"requires": {
"cssesc": "^3.0.0",
"fastparse": "^1.1.2"
@@ -18767,6 +18665,7 @@
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/cssauron/-/cssauron-1.4.0.tgz",
"integrity": "sha512-Ht70DcFBh+/ekjVrYS2PlDMdSQEl3OFNmjK6lcn49HptBgilXf/Zwg4uFh9Xn0pX3Q8YOkSjIFOfK2osvdqpBw==",
+ "dev": true,
"requires": {
"through": "X.X.X"
}
@@ -18780,7 +18679,8 @@
"cssesc": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz",
- "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg=="
+ "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==",
+ "dev": true
},
"custom-event": {
"version": "1.0.1",
@@ -18791,7 +18691,8 @@
"damerau-levenshtein": {
"version": "1.0.8",
"resolved": "https://registry.npmjs.org/damerau-levenshtein/-/damerau-levenshtein-1.0.8.tgz",
- "integrity": "sha512-sdQSFB7+llfUcQHUQO3+B8ERRj0Oa4w9POWMI/puGtuf7gFywGmkaLCElnudfTiKZV+NvHqL0ifzdrI8Ro7ESA=="
+ "integrity": "sha512-sdQSFB7+llfUcQHUQO3+B8ERRj0Oa4w9POWMI/puGtuf7gFywGmkaLCElnudfTiKZV+NvHqL0ifzdrI8Ro7ESA==",
+ "dev": true
},
"dashdash": {
"version": "1.14.1",
@@ -19739,7 +19640,8 @@
"fastparse": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/fastparse/-/fastparse-1.1.2.tgz",
- "integrity": "sha512-483XLLxTVIwWK3QTrMGRqUfUpoOs/0hbQrl2oz4J0pAcm3A3bu84wxTFqGqkJzewCLdME38xJLJAxBABfQT8sQ=="
+ "integrity": "sha512-483XLLxTVIwWK3QTrMGRqUfUpoOs/0hbQrl2oz4J0pAcm3A3bu84wxTFqGqkJzewCLdME38xJLJAxBABfQT8sQ==",
+ "dev": true
},
"fastq": {
"version": "1.13.0",
@@ -23719,6 +23621,7 @@
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/semver-dsl/-/semver-dsl-1.0.1.tgz",
"integrity": "sha512-e8BOaTo007E3dMuQQTnPdalbKTABKNS7UxoBIDnwOqRa+QwMrCPjynB8zAlPF6xlqUfdLPPLIJ13hJNmhtq8Ng==",
+ "dev": true,
"requires": {
"semver": "^5.3.0"
},
@@ -23726,7 +23629,8 @@
"semver": {
"version": "5.7.1",
"resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz",
- "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ=="
+ "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==",
+ "dev": true
}
}
},
@@ -24153,7 +24057,8 @@
"sprintf-js": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.1.2.tgz",
- "integrity": "sha512-VE0SOVEHCk7Qc8ulkWw3ntAzXuqf7S2lvwQaDLRnUeIEaKNQJzV6BwmLKhOqT61aGhfUMrXeaBk+oDGCzvhcug=="
+ "integrity": "sha512-VE0SOVEHCk7Qc8ulkWw3ntAzXuqf7S2lvwQaDLRnUeIEaKNQJzV6BwmLKhOqT61aGhfUMrXeaBk+oDGCzvhcug==",
+ "dev": true
},
"sshpk": {
"version": "1.17.0",
@@ -24379,7 +24284,8 @@
"through": {
"version": "2.3.8",
"resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz",
- "integrity": "sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg=="
+ "integrity": "sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==",
+ "dev": true
},
"thunky": {
"version": "1.1.0",
diff --git a/frontend/package.json b/frontend/package.json
index 6a90dba3..7ec96b3a 100644
--- a/frontend/package.json
+++ b/frontend/package.json
@@ -28,7 +28,7 @@
"@fortawesome/free-solid-svg-icons": "^6.2.0",
"@ng-bootstrap/ng-bootstrap": "10.0.0",
"@panva/oauth4webapi": "^1.1.3",
- "angular-datatables": "^14.0.0",
+ "@swimlane/ngx-datatable": "^20.0.0",
"bootstrap": "^4.4.1",
"chart.js": "2.9.4",
"fhirclient": "^2.5.1",
diff --git a/frontend/src/app/components/list-condition/list-condition.component.html b/frontend/src/app/components/list-condition/list-condition.component.html
deleted file mode 100644
index 2333cb58..00000000
--- a/frontend/src/app/components/list-condition/list-condition.component.html
+++ /dev/null
@@ -1,26 +0,0 @@
-
A clinical condition, problem, diagnosis, or other event, situation, issue, or clinical concept that has risen to a level of concern.
-
-
-
-
- Condition |
- Clinical Status |
- Verification Status |
- Onset Date |
-
-
-
-
-
- {{condition.name}}
-
- {{ condition.nameCode}} {{ condition.nameCodeSystem }}
-
- |
- {{condition.clinicalStatus}} |
- {{condition.verificationStatus}} |
- {{condition.onset | date:'M/d/yy'}} |
-
-
-
-
diff --git a/frontend/src/app/components/list-condition/list-condition.component.spec.ts b/frontend/src/app/components/list-condition/list-condition.component.spec.ts
deleted file mode 100644
index b93b5956..00000000
--- a/frontend/src/app/components/list-condition/list-condition.component.spec.ts
+++ /dev/null
@@ -1,23 +0,0 @@
-import { ComponentFixture, TestBed } from '@angular/core/testing';
-
-import { ListConditionComponent } from './list-condition.component';
-
-describe('ListConditionComponent', () => {
- let component: ListConditionComponent;
- let fixture: ComponentFixture;
-
- beforeEach(async () => {
- await TestBed.configureTestingModule({
- declarations: [ ListConditionComponent ]
- })
- .compileComponents();
-
- fixture = TestBed.createComponent(ListConditionComponent);
- component = fixture.componentInstance;
- fixture.detectChanges();
- });
-
- it('should create', () => {
- expect(component).toBeTruthy();
- });
-});
diff --git a/frontend/src/app/components/list-condition/list-condition.component.ts b/frontend/src/app/components/list-condition/list-condition.component.ts
deleted file mode 100644
index 5c3eb8ee..00000000
--- a/frontend/src/app/components/list-condition/list-condition.component.ts
+++ /dev/null
@@ -1,25 +0,0 @@
-import {Component, Input, OnInit} from '@angular/core';
-import {ResourceFhir} from '../../models/fasten/resource_fhir';
-import {Condition} from '../../models/display/condition';
-
-@Component({
- selector: 'app-list-condition',
- templateUrl: './list-condition.component.html',
- styleUrls: ['./list-condition.component.scss']
-})
-export class ListConditionComponent implements OnInit {
-
- @Input() resourceList: ResourceFhir[] = []
- conditionList: Condition[] = []
-
- constructor() { }
-
- ngOnInit(): void {
- let _conditions = this.conditionList
- this.resourceList.forEach((resource) => {
- let cond = new Condition(resource.payload)
- _conditions.push(cond)
- })
- }
-
-}
diff --git a/frontend/src/app/components/list-encounter/list-encounter.component.html b/frontend/src/app/components/list-encounter/list-encounter.component.html
deleted file mode 100644
index 1338dd8a..00000000
--- a/frontend/src/app/components/list-encounter/list-encounter.component.html
+++ /dev/null
@@ -1,27 +0,0 @@
-A clinical condition, problem, diagnosis, or other event, situation, issue, or clinical concept that has risen to a level of concern.
-
-
-
-
- Type |
- Reason |
- Class |
- Status |
- Time |
-
-
-
-
-
- {{encounter.encounterType}}
- {{encounter.encounterClass}} encounter
- N/A
- |
- {{encounter.reason ? encounter.reason : 'N/A' }} |
- {{encounter.encounterClass ? encounter.encounterClass : 'N/A' }} |
- {{encounter.status ? encounter.status : 'N/A'}} |
- - |
-
-
-
-
diff --git a/frontend/src/app/components/list-encounter/list-encounter.component.scss b/frontend/src/app/components/list-encounter/list-encounter.component.scss
deleted file mode 100644
index e69de29b..00000000
diff --git a/frontend/src/app/components/list-encounter/list-encounter.component.spec.ts b/frontend/src/app/components/list-encounter/list-encounter.component.spec.ts
deleted file mode 100644
index fb71a5a7..00000000
--- a/frontend/src/app/components/list-encounter/list-encounter.component.spec.ts
+++ /dev/null
@@ -1,23 +0,0 @@
-import { ComponentFixture, TestBed } from '@angular/core/testing';
-
-import { ListEncounterComponent } from './list-encounter.component';
-
-describe('ListEncounterComponent', () => {
- let component: ListEncounterComponent;
- let fixture: ComponentFixture;
-
- beforeEach(async () => {
- await TestBed.configureTestingModule({
- declarations: [ ListEncounterComponent ]
- })
- .compileComponents();
-
- fixture = TestBed.createComponent(ListEncounterComponent);
- component = fixture.componentInstance;
- fixture.detectChanges();
- });
-
- it('should create', () => {
- expect(component).toBeTruthy();
- });
-});
diff --git a/frontend/src/app/components/list-encounter/list-encounter.component.ts b/frontend/src/app/components/list-encounter/list-encounter.component.ts
deleted file mode 100644
index d7f155ba..00000000
--- a/frontend/src/app/components/list-encounter/list-encounter.component.ts
+++ /dev/null
@@ -1,25 +0,0 @@
-import {Component, Input, OnInit} from '@angular/core';
-import {ResourceFhir} from '../../models/fasten/resource_fhir';
-import {Condition} from '../../models/display/condition';
-import {Encounter} from '../../models/display/encounter';
-
-@Component({
- selector: 'app-list-encounter',
- templateUrl: './list-encounter.component.html',
- styleUrls: ['./list-encounter.component.scss']
-})
-export class ListEncounterComponent implements OnInit {
-
- @Input() resourceList: ResourceFhir[] = []
- encounterList: Encounter[] = []
-
- constructor() { }
-
- ngOnInit(): void {
- let _encounterList = this.encounterList
- this.resourceList.forEach((resource) => {
- let encounter = new Encounter(resource.payload)
- _encounterList.push(encounter)
- })
- }
-}
diff --git a/frontend/src/app/components/list-generic-resource/list-condition.component.ts b/frontend/src/app/components/list-generic-resource/list-condition.component.ts
new file mode 100644
index 00000000..186e32b7
--- /dev/null
+++ b/frontend/src/app/components/list-generic-resource/list-condition.component.ts
@@ -0,0 +1,18 @@
+import {Component} from '@angular/core';
+import {GenericColumnDefn, ListGenericResourceComponent} from './list-generic-resource.component';
+
+@Component({
+ selector: 'app-list-condition',
+ templateUrl: './list-generic-resource.component.html',
+ styleUrls: ['./list-generic-resource.component.scss']
+})
+export class ListConditionComponent extends ListGenericResourceComponent {
+ columnDefinitions: GenericColumnDefn[] = [
+ { title: 'Condition', versions: '*', format: 'code', getter: c => c.code.coding[0] },
+ { title: 'Date of Onset', versions: '*', format: 'date', getter: c => c.onsetDateTime },
+ { title: 'Date Resolved', 'versions': '*', format: 'date', getter: c => c.abatementDateTime, defaultValue: 'N/A' },
+ { title: 'Recorded Date', versions: '*', format: 'date', getter: c => c.recordedDate },
+ { title: 'Severity', versions: '*', format: 'code', getter: c => c.severity.coding[0] },
+ { title: 'Body Site', versions: '*', format: 'code', getter: c => c.bodySite[0].coding[0] }
+ ]
+}
diff --git a/frontend/src/app/components/list-generic-resource/list-encounter.component.ts b/frontend/src/app/components/list-generic-resource/list-encounter.component.ts
new file mode 100644
index 00000000..78d1375b
--- /dev/null
+++ b/frontend/src/app/components/list-generic-resource/list-encounter.component.ts
@@ -0,0 +1,16 @@
+import {Component} from '@angular/core';
+import {GenericColumnDefn, ListGenericResourceComponent} from './list-generic-resource.component';
+
+@Component({
+ selector: 'app-list-encounter',
+ templateUrl: './list-generic-resource.component.html',
+ styleUrls: ['./list-generic-resource.component.scss']
+})
+export class ListEncounterComponent extends ListGenericResourceComponent {
+ columnDefinitions: GenericColumnDefn[] = [
+ { title: 'Encounter', versions: '*', format: 'code', getter: e => e.type[0].coding[0] },
+ { title: 'Period', versions: '*', format: 'period', getter: e => e.period },
+ { title: 'Diagnosis', versions: '*', getter: e => e.diagnosis?.map(d => d.condition?.reference).join()},
+ { title: 'Discharge Disposition', versions: '*', format: 'code', getter: e => e.hospitalization?.dischargeDisposition.coding[0] }
+ ]
+}
diff --git a/frontend/src/app/components/list-generic-resource/list-generic-resource.component.html b/frontend/src/app/components/list-generic-resource/list-generic-resource.component.html
new file mode 100644
index 00000000..49fd66d6
--- /dev/null
+++ b/frontend/src/app/components/list-generic-resource/list-generic-resource.component.html
@@ -0,0 +1,14 @@
+
+
+
+
diff --git a/frontend/src/app/components/list-condition/list-condition.component.scss b/frontend/src/app/components/list-generic-resource/list-generic-resource.component.scss
similarity index 100%
rename from frontend/src/app/components/list-condition/list-condition.component.scss
rename to frontend/src/app/components/list-generic-resource/list-generic-resource.component.scss
diff --git a/frontend/src/app/components/list-generic-resource/list-generic-resource.component.spec.ts b/frontend/src/app/components/list-generic-resource/list-generic-resource.component.spec.ts
new file mode 100644
index 00000000..c58051c8
--- /dev/null
+++ b/frontend/src/app/components/list-generic-resource/list-generic-resource.component.spec.ts
@@ -0,0 +1,23 @@
+import { ComponentFixture, TestBed } from '@angular/core/testing';
+
+import { ListGenericResourceComponent } from './list-generic-resource.component';
+
+describe('ListGenericResourceComponent', () => {
+ let component: ListGenericResourceComponent;
+ let fixture: ComponentFixture;
+
+ beforeEach(async () => {
+ await TestBed.configureTestingModule({
+ declarations: [ ListGenericResourceComponent ]
+ })
+ .compileComponents();
+
+ fixture = TestBed.createComponent(ListGenericResourceComponent);
+ component = fixture.componentInstance;
+ fixture.detectChanges();
+ });
+
+ it('should create', () => {
+ expect(component).toBeTruthy();
+ });
+});
diff --git a/frontend/src/app/components/list-generic-resource/list-generic-resource.component.ts b/frontend/src/app/components/list-generic-resource/list-generic-resource.component.ts
new file mode 100644
index 00000000..d7782f9c
--- /dev/null
+++ b/frontend/src/app/components/list-generic-resource/list-generic-resource.component.ts
@@ -0,0 +1,74 @@
+import {Component, Input, OnInit, ViewChild} from '@angular/core';
+import {DatatableComponent, ColumnMode} from '@swimlane/ngx-datatable';
+import {ResourceFhir} from '../../models/fasten/resource_fhir';
+import {FORMATTERS, getPath, obsValue, attributeXTime} from './utils';
+import {observableToBeFn} from 'rxjs/internal/testing/TestScheduler';
+
+export class GenericColumnDefn {
+ title: string
+ prop?: string
+ versions?: string
+ format?: string
+ getter: Function
+ defaultValue?: string
+}
+
+@Component({
+ selector: 'app-list-generic-resource',
+ templateUrl: './list-generic-resource.component.html',
+ styleUrls: ['./list-generic-resource.component.scss']
+})
+export class ListGenericResourceComponent implements OnInit {
+
+ @Input() resourceList: ResourceFhir[] = []
+
+ // description: string
+ // c: ListGenericResourceComponentColumn[] = []
+ columnDefinitions: GenericColumnDefn[] = []
+
+ // datatable properties (DO NOT CHANGE)
+ @ViewChild(DatatableComponent) table: DatatableComponent;
+ rows = [];
+ columns = []; //{ prop: 'name' }, { name: 'Company' }, { name: 'Gender' }
+ ColumnMode = ColumnMode;
+
+ constructor() {}
+
+ ngOnInit(): void {
+ this.columns = this.columnDefinitions.map((defn) => {
+ let column = {name: defn.title, prop: defn.title.replace(/[^A-Z0-9]/ig, "_")}
+ return column
+ })
+
+ this.rows = this.resourceList.map((resource) => {
+ let row = {}
+
+ this.columnDefinitions.forEach((defn) => {
+ let resourceProp = defn.getter(resource.payload)
+ let resourceFormatted = defn.format ? FORMATTERS[defn.format](resourceProp) : resourceProp
+ row[defn.title.replace(/[^A-Z0-9]/ig, "_")] = resourceFormatted
+ //TODO: handle defaultValue
+ })
+
+ console.log("ROW:", row)
+
+ return row
+ })
+ }
+}
+
+///////////////////////////////////////////////////////////////////////////////////////
+// START OVERRIDES
+///////////////////////////////////////////////////////////////////////////////////////
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/frontend/src/app/components/list-generic-resource/list-immunization.component.ts b/frontend/src/app/components/list-generic-resource/list-immunization.component.ts
new file mode 100644
index 00000000..eb7677b8
--- /dev/null
+++ b/frontend/src/app/components/list-generic-resource/list-immunization.component.ts
@@ -0,0 +1,15 @@
+import {Component} from '@angular/core';
+import {GenericColumnDefn, ListGenericResourceComponent} from './list-generic-resource.component';
+
+@Component({
+ selector: 'app-list-immunization',
+ templateUrl: './list-generic-resource.component.html',
+ styleUrls: ['./list-generic-resource.component.scss']
+})
+export class ListImmunizationComponent extends ListGenericResourceComponent {
+ columnDefinitions: GenericColumnDefn[] = [
+ { title: 'Vaccine', versions: '*', format: 'code', getter: i => i.vaccineCode.coding[0] },
+ { title: 'Date Given', versions: '*', format: 'date', getter: i => i.date || i.occurrenceDateTime || i.occurrenceStringe },
+ { title: 'Date Recorded', versions: '*', format: 'date', getter: i => i.recorded }
+ ]
+}
diff --git a/frontend/src/app/components/list-generic-resource/list-medication-request.component.ts b/frontend/src/app/components/list-generic-resource/list-medication-request.component.ts
new file mode 100644
index 00000000..dc842b2b
--- /dev/null
+++ b/frontend/src/app/components/list-generic-resource/list-medication-request.component.ts
@@ -0,0 +1,19 @@
+import {Component} from '@angular/core';
+import {GenericColumnDefn, ListGenericResourceComponent} from './list-generic-resource.component';
+
+@Component({
+ selector: 'app-list-medication-request',
+ templateUrl: './list-generic-resource.component.html',
+ styleUrls: ['./list-generic-resource.component.scss']
+})
+export class ListMedicationRequestComponent extends ListGenericResourceComponent {
+ columnDefinitions: GenericColumnDefn[] = [
+ { title: 'Medication', versions: '*', format: 'code', getter: m => m.medicationCodeableConcept?.coding[0] },
+ { title: 'Dosage Timing', versions: '*', format: 'period', getter: m => m.dosageInstruction[0]?.timing.repeat.boundsPeriod},
+ { title: 'Dosage Date', versions: '*', format: 'date', getter: m => m.dosageInstruction[0]?.timing.event},
+ { title: 'Author Date', versions: '*', format: 'date', getter: m => m.authoredOn },
+ { title: 'Do Not Perform', versions: '*', getter: m => m.doNotPerform},
+ { title: 'Reason', versions: '*', format: 'code', getter: m => m.reasonCode[0]?.coding[0] },
+ { title: 'Route', versions: '*', format: 'code', getter: m => m.dosageInstruction[0]?.route.coding[0] }
+ ]
+}
diff --git a/frontend/src/app/components/list-generic-resource/list-medication.component.ts b/frontend/src/app/components/list-generic-resource/list-medication.component.ts
new file mode 100644
index 00000000..043ac2fc
--- /dev/null
+++ b/frontend/src/app/components/list-generic-resource/list-medication.component.ts
@@ -0,0 +1,15 @@
+import {Component} from '@angular/core';
+import {GenericColumnDefn, ListGenericResourceComponent} from './list-generic-resource.component';
+
+@Component({
+ selector: 'app-list-medication',
+ templateUrl: './list-generic-resource.component.html',
+ styleUrls: ['./list-generic-resource.component.scss']
+})
+export class ListMedicationComponent extends ListGenericResourceComponent {
+ columnDefinitions: GenericColumnDefn[] = [
+ { title: 'Medication', versions: '*', format: 'code', getter: c => c.medicationCodeableConcept.coding[0] },
+ { title: 'Date Prescribed', versions: '*', format: 'date', getter: c => c.authoredOn },
+ { title: 'Status', 'versions': '*', getter: c => c.status }
+ ]
+}
diff --git a/frontend/src/app/components/list-generic-resource/list-observation.component.ts b/frontend/src/app/components/list-generic-resource/list-observation.component.ts
new file mode 100644
index 00000000..33bc5a41
--- /dev/null
+++ b/frontend/src/app/components/list-generic-resource/list-observation.component.ts
@@ -0,0 +1,18 @@
+import {Component} from '@angular/core';
+import {attributeXTime, obsValue} from './utils';
+import {GenericColumnDefn, ListGenericResourceComponent} from './list-generic-resource.component';
+
+@Component({
+ selector: 'app-list-observation',
+ templateUrl: './list-generic-resource.component.html',
+ styleUrls: ['./list-generic-resource.component.scss']
+})
+export class ListObservationComponent extends ListGenericResourceComponent {
+ columnDefinitions: GenericColumnDefn[] = [
+ { title: 'Observation', versions: '*', format: 'code', getter: o => o.code.coding[0] },
+ { title: 'Value', versions: '*', getter: o => obsValue(o) },
+ { title: 'Effective', 'versions': '*', getter: o => attributeXTime(o,'effective') },
+ { title: 'Issued Date', 'versions': '*', format: 'date', getter: o => o.issued },
+ { title: 'ID', versions: '*', getter: o => o.id }
+ ]
+}
diff --git a/frontend/src/app/components/list-generic-resource/list-procedure.component.ts b/frontend/src/app/components/list-generic-resource/list-procedure.component.ts
new file mode 100644
index 00000000..c9cad4ea
--- /dev/null
+++ b/frontend/src/app/components/list-generic-resource/list-procedure.component.ts
@@ -0,0 +1,20 @@
+import {Component} from '@angular/core';
+import {attributeXTime} from './utils';
+import {GenericColumnDefn, ListGenericResourceComponent} from './list-generic-resource.component';
+
+@Component({
+ selector: 'app-list-procedure',
+ templateUrl: './list-generic-resource.component.html',
+ styleUrls: ['./list-generic-resource.component.scss']
+})
+export class ListProcedureComponent extends ListGenericResourceComponent {
+ columnDefinitions: GenericColumnDefn[] = [
+ { title: 'Procedure', versions: '*', format: 'code', getter: p => p.code.coding[0] },
+ { title: 'Performed', versions: '*', getter: p => attributeXTime(p,'performed') },
+ { title: 'ID', versions: '*', getter: p => p.id },
+ { title: 'Recorded', versions: '*', format: 'dateTime', getter: p => p.extension?.recorded },
+ { title: 'Reason', versions: '*', format: 'code', getter: p => p.reasonCode?.coding[0] },
+ { title: 'Status', versions: '*', getter: p => p.status },
+ { title: 'Status Reason', versions: '*', format: 'code', getter: p => p.statusReason?.coding[0] }
+ ]
+}
diff --git a/frontend/src/app/components/list-generic-resource/utils.ts b/frontend/src/app/components/list-generic-resource/utils.ts
new file mode 100644
index 00000000..debe355d
--- /dev/null
+++ b/frontend/src/app/components/list-generic-resource/utils.ts
@@ -0,0 +1,80 @@
+import * as moment from 'moment'
+
+/**
+ * Walks thru an object (ar array) and returns the value found at the provided
+ * path. This function is very simple so it intentionally does not support any
+ * argument polymorphism, meaning that the path can only be a dot-separated
+ * string. If the path is invalid returns undefined.
+ * @param {Object} obj The object (or Array) to walk through
+ * @param {String} path The path (eg. "a.b.4.c")
+ * @returns {*} Whatever is found in the path or undefined
+ */
+export function getPath(obj, path = ""): string {
+ return path.split(".").reduce((out, key) => out ? out[key] : undefined, obj)
+}
+
+export const FORMATTERS = {
+ date: (str) => str ? moment(str).format('YYYY-MM-DD') : '',
+ time: (str) => str ? moment(str).format('HH:mm:ss') : '',
+ dateTime: (str) => str ? moment(str).format('YYYY-MM-DD - h:mm:ss a') : '',
+ numberWithCommas: (str) => str ? str.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",") : '',
+ code: (code) => code ? `${code.code}: ${code.display ? code.display : ''}` : '',
+ period: (period) => period ? `${moment(period.start).format('YYYY-MM-DD - h:mm:ss a')} -> ${moment(period.end).format('YYYY-MM-DD - h:mm:ss a')}` : ''
+};
+
+export function round(num, digits) {
+ return Number.parseFloat(num).toFixed(digits);
+}
+
+export function obsValue(entry){
+ if (entry == null) {
+ return '';
+ } else if (entry.valueQuantity) {
+ return round(entry.valueQuantity.value, 2) + ' ' + entry.valueQuantity.code;
+ } else if (entry.valueCodeableConcept) {
+ return entry.valueCodeableConcept.coding[0].display;
+ } else if (entry.valueString) {
+ return entry.valueString;
+ }
+
+ if (entry.code.coding[0].display === "Blood Pressure") {
+
+ if (!entry.component[0].valueQuantity) {
+ return ''; // WTF!!
+ }
+
+ const v1 = Number.parseFloat(entry.component[0].valueQuantity.value);
+ const v2 = Number.parseFloat(entry.component[1].valueQuantity.value);
+
+ const s1 = v1.toFixed(0);
+ const s2 = v2.toFixed(0);
+
+ if (v1 > v2) {
+ return s1 + ' / ' + s2 + ' mmHg';
+ } else {
+ return s2 + ' / ' + s1 + ' mmHg';
+ }
+ }
+
+ return '';
+}
+
+export function attributeXTime(entry, type) {
+ if (entry == null) {
+ return '';
+ } else if (entry[`${type}DateTime`]) {
+ return FORMATTERS['dateTime'](entry[`${type}DateTime`])
+ } else if (entry[`${type}Period`]) {
+ return FORMATTERS['period'](entry[`${type}Period`])
+ }
+ return '';
+}
+
+export function duration(period) {
+ if (!period.end) {
+ return '';
+ }
+ let start = moment(period.start);
+ let end = moment(period.end);
+ return moment.duration( start.diff(end) ).humanize();
+};
diff --git a/frontend/src/app/components/list-immunization/list-immunization.component.html b/frontend/src/app/components/list-immunization/list-immunization.component.html
deleted file mode 100644
index c8e744d2..00000000
--- a/frontend/src/app/components/list-immunization/list-immunization.component.html
+++ /dev/null
@@ -1,19 +0,0 @@
-A clinical condition, problem, diagnosis, or other event, situation, issue, or clinical concept that has risen to a level of concern.
-
-
-
-
- Type |
- Status |
- Date |
-
-
-
-
- {{immunization.immunizationType}} |
- {{immunization.status || '-'}} |
- {{immunization.date }} |
-
-
-
-
diff --git a/frontend/src/app/components/list-immunization/list-immunization.component.scss b/frontend/src/app/components/list-immunization/list-immunization.component.scss
deleted file mode 100644
index e69de29b..00000000
diff --git a/frontend/src/app/components/list-immunization/list-immunization.component.spec.ts b/frontend/src/app/components/list-immunization/list-immunization.component.spec.ts
deleted file mode 100644
index fc3b7df7..00000000
--- a/frontend/src/app/components/list-immunization/list-immunization.component.spec.ts
+++ /dev/null
@@ -1,23 +0,0 @@
-import { ComponentFixture, TestBed } from '@angular/core/testing';
-
-import { ListImmunizationComponent } from './list-immunization.component';
-
-describe('ListImmunizationComponent', () => {
- let component: ListImmunizationComponent;
- let fixture: ComponentFixture;
-
- beforeEach(async () => {
- await TestBed.configureTestingModule({
- declarations: [ ListImmunizationComponent ]
- })
- .compileComponents();
-
- fixture = TestBed.createComponent(ListImmunizationComponent);
- component = fixture.componentInstance;
- fixture.detectChanges();
- });
-
- it('should create', () => {
- expect(component).toBeTruthy();
- });
-});
diff --git a/frontend/src/app/components/list-immunization/list-immunization.component.ts b/frontend/src/app/components/list-immunization/list-immunization.component.ts
deleted file mode 100644
index d775989b..00000000
--- a/frontend/src/app/components/list-immunization/list-immunization.component.ts
+++ /dev/null
@@ -1,26 +0,0 @@
-import {Component, Input, OnInit} from '@angular/core';
-import {ResourceFhir} from '../../models/fasten/resource_fhir';
-import {Encounter} from '../../models/display/encounter';
-import {Immunization} from '../../models/display/immunization';
-
-@Component({
- selector: 'app-list-immunization',
- templateUrl: './list-immunization.component.html',
- styleUrls: ['./list-immunization.component.scss']
-})
-export class ListImmunizationComponent implements OnInit {
-
- @Input() resourceList: ResourceFhir[] = []
- immunizationList: Immunization[] = []
-
- constructor() { }
-
- ngOnInit(): void {
- let _immunizationList = this.immunizationList
- this.resourceList.forEach((resource) => {
- let immunization = new Immunization(resource.payload)
- _immunizationList.push(immunization)
- })
- }
-
-}
diff --git a/frontend/src/app/components/list-observation/list-observation.component.html b/frontend/src/app/components/list-observation/list-observation.component.html
deleted file mode 100644
index 9b021645..00000000
--- a/frontend/src/app/components/list-observation/list-observation.component.html
+++ /dev/null
@@ -1 +0,0 @@
-list-observation works!
diff --git a/frontend/src/app/components/list-observation/list-observation.component.scss b/frontend/src/app/components/list-observation/list-observation.component.scss
deleted file mode 100644
index e69de29b..00000000
diff --git a/frontend/src/app/components/list-observation/list-observation.component.spec.ts b/frontend/src/app/components/list-observation/list-observation.component.spec.ts
deleted file mode 100644
index 62ad026e..00000000
--- a/frontend/src/app/components/list-observation/list-observation.component.spec.ts
+++ /dev/null
@@ -1,23 +0,0 @@
-import { ComponentFixture, TestBed } from '@angular/core/testing';
-
-import { ListObservationComponent } from './list-observation.component';
-
-describe('ListObservationComponent', () => {
- let component: ListObservationComponent;
- let fixture: ComponentFixture;
-
- beforeEach(async () => {
- await TestBed.configureTestingModule({
- declarations: [ ListObservationComponent ]
- })
- .compileComponents();
-
- fixture = TestBed.createComponent(ListObservationComponent);
- component = fixture.componentInstance;
- fixture.detectChanges();
- });
-
- it('should create', () => {
- expect(component).toBeTruthy();
- });
-});
diff --git a/frontend/src/app/components/list-observation/list-observation.component.ts b/frontend/src/app/components/list-observation/list-observation.component.ts
deleted file mode 100644
index 66aeb62f..00000000
--- a/frontend/src/app/components/list-observation/list-observation.component.ts
+++ /dev/null
@@ -1,15 +0,0 @@
-import { Component, OnInit } from '@angular/core';
-
-@Component({
- selector: 'app-list-observation',
- templateUrl: './list-observation.component.html',
- styleUrls: ['./list-observation.component.scss']
-})
-export class ListObservationComponent implements OnInit {
-
- constructor() { }
-
- ngOnInit(): void {
- }
-
-}
diff --git a/frontend/src/app/components/shared.module.ts b/frontend/src/app/components/shared.module.ts
index a6478632..3adb13dc 100644
--- a/frontend/src/app/components/shared.module.ts
+++ b/frontend/src/app/components/shared.module.ts
@@ -3,19 +3,25 @@ import { ComponentsSidebarComponent } from './components-sidebar/components-side
import { RouterModule } from '@angular/router';
import { UtilitiesSidebarComponent } from './utilities-sidebar/utilities-sidebar.component';
import { ListPatientComponent } from './list-patient/list-patient.component';
-import { ListObservationComponent } from './list-observation/list-observation.component';
import { ListExplanationOfBenefitComponent } from './list-explanation-of-benefit/list-explanation-of-benefit.component';
-import { ListImmunizationComponent } from './list-immunization/list-immunization.component';
-import { ListEncounterComponent } from './list-encounter/list-encounter.component';
-import { ListConditionComponent } from './list-condition/list-condition.component';
import { ListCarePlanComponent } from './list-care-plan/list-care-plan.component';
import {BrowserModule} from '@angular/platform-browser';
-import { ListGenericResourceComponent } from './list-generic-resource/list-generic-resource.component';
+import { ListGenericResourceComponent,} from './list-generic-resource/list-generic-resource.component';
+import {ListConditionComponent} from './list-generic-resource/list-condition.component'
+import {ListEncounterComponent} from './list-generic-resource/list-encounter.component'
+import {ListMedicationComponent} from './list-generic-resource/list-medication.component'
+import {ListObservationComponent} from './list-generic-resource/list-observation.component'
+import {ListProcedureComponent} from './list-generic-resource/list-procedure.component'
+import {ListImmunizationComponent} from './list-generic-resource/list-immunization.component'
+import {ListMedicationRequestComponent} from './list-generic-resource/list-medication-request.component'
+
+import { NgxDatatableModule } from '@swimlane/ngx-datatable';
@NgModule({
imports: [
RouterModule,
BrowserModule,
+ NgxDatatableModule
],
declarations: [
ComponentsSidebarComponent,
@@ -25,20 +31,28 @@ import { ListGenericResourceComponent } from './list-generic-resource/list-gener
ListExplanationOfBenefitComponent,
ListImmunizationComponent,
ListEncounterComponent,
- ListConditionComponent,
ListCarePlanComponent,
- ListGenericResourceComponent
+ ListGenericResourceComponent,
+ ListMedicationComponent,
+ ListProcedureComponent,
+ ListConditionComponent,
+ ListMedicationRequestComponent
],
exports: [
ComponentsSidebarComponent,
UtilitiesSidebarComponent,
ListPatientComponent,
- ListObservationComponent,
ListExplanationOfBenefitComponent,
ListImmunizationComponent,
ListEncounterComponent,
+ ListCarePlanComponent,
+ ListGenericResourceComponent,
+ ListMedicationComponent,
+ ListObservationComponent,
+ ListProcedureComponent,
ListConditionComponent,
- ListCarePlanComponent
+ ListMedicationRequestComponent
+
]
})
diff --git a/frontend/src/app/models/display/condition.ts b/frontend/src/app/models/display/condition.ts
deleted file mode 100644
index ebd52b4d..00000000
--- a/frontend/src/app/models/display/condition.ts
+++ /dev/null
@@ -1,45 +0,0 @@
-import {getCodeOrConcept} from '../../fhir/utils';
-import {CODE_SYSTEMS} from '../../fhir/constants';
-
-export class Condition {
- name: string
- nameCode: string
- nameCodeSystem: string
- clinicalStatus: string
- verificationStatus: string
- onset: string
-
- constructor(resourcePayload: any) {
- this.populateConditionName(resourcePayload)
- this.clinicalStatus = getCodeOrConcept(resourcePayload.clinicalStatus)
- this.verificationStatus = getCodeOrConcept(resourcePayload.verificationStatus)
- this.onset = resourcePayload.onsetDateTime
- }
-
- populateConditionName(resourePayload: any){
- if (resourePayload.code) {
- if (resourePayload.code.text) {
- this.name = resourePayload.code.text;
- }
- if (Array.isArray(resourePayload.code.coding) && resourePayload.code.coding.length) {
- let c = resourePayload.code.coding[0]
-
- this.nameCodeSystem = c.system
- for (let key in CODE_SYSTEMS) {
- if (CODE_SYSTEMS[key].url === c.system) {
- this.nameCodeSystem = `(${key})`;
- break;
- }
- }
-
- if (c.display) {
- this.name = c.display
- }
- if (c.code) {
- this.nameCode = c.code
- }
- }
- }
- }
-
-}
diff --git a/frontend/src/app/models/display/immunization.ts b/frontend/src/app/models/display/immunization.ts
deleted file mode 100644
index 246318bb..00000000
--- a/frontend/src/app/models/display/immunization.ts
+++ /dev/null
@@ -1,14 +0,0 @@
-import {getPath} from '../../fhir/utils';
-import * as moment from 'moment'
-
-export class Immunization {
- immunizationType: string
- status: string
- date: moment.Moment
-
- constructor(resourcePayload: any) {
- this.immunizationType = getPath(resourcePayload, "vaccineCode.coding.0.display")
- this.status = resourcePayload.status || "-"
- this.date = moment(resourcePayload.date || resourcePayload.occurrenceDateTime || resourcePayload.occurrenceString)
- }
-}
diff --git a/frontend/src/app/models/display/observation.ts b/frontend/src/app/models/display/observation.ts
deleted file mode 100644
index 00622842..00000000
--- a/frontend/src/app/models/display/observation.ts
+++ /dev/null
@@ -1,20 +0,0 @@
-import * as moment from 'moment';
-import {getPath} from '../../fhir/utils';
-
-export class Observation {
- code: string
- status: string
- date: moment.Moment
-
-// { title: 'Observation', versions: '*', format: 'code', getter: o => o.code.coding[0] },
-// { title: 'Value', versions: '*', getter: o => obsValue(o) },
-// { title: 'Effective', 'versions': '*', getter: o => attributeXTime(o,'effective') },
-// { title: 'Issued Date', 'versions': '*', format: 'date', getter: o => o.issued },
-// { title: 'ID', versions: '*', getter: o => o.id }
-
- constructor(resourcePayload: any) {
- this.code = getPath(resourcePayload, "code.coding[0].display")
- this.status = resourcePayload.status || "-"
- this.date = moment(resourcePayload.date || resourcePayload.occurrenceDateTime || resourcePayload.occurrenceString)
- }
-}
diff --git a/frontend/src/app/pages/source-detail/source-detail.component.html b/frontend/src/app/pages/source-detail/source-detail.component.html
index 1192b9e3..0d46804b 100644
--- a/frontend/src/app/pages/source-detail/source-detail.component.html
+++ b/frontend/src/app/pages/source-detail/source-detail.component.html
@@ -20,7 +20,10 @@
-
+
+
+
+
diff --git a/frontend/src/styles.scss b/frontend/src/styles.scss
index 580fe4c1..f82c0ca2 100644
--- a/frontend/src/styles.scss
+++ b/frontend/src/styles.scss
@@ -206,3 +206,7 @@
//@import "~datatables.net-dt/css/jquery.dataTables.css";
//@import '~@fullcalendar/core/main.css';
//@import '~perfect-scrollbar/css/perfect-scrollbar.css';
+
+@import '~@swimlane/ngx-datatable/index.css';
+@import '~@swimlane/ngx-datatable/themes/bootstrap.css';
+@import '~@swimlane/ngx-datatable/assets/icons.css';