creating FHIR components based on generic list

see https://github.com/synthetichealth/fhir-visualizers/blob/master/src/index.js
This commit is contained in:
Jason Kulatunga 2022-09-16 06:58:41 -07:00
parent 5f71891970
commit 48c8873f18
35 changed files with 407 additions and 503 deletions

View File

@ -24,7 +24,7 @@
"@fortawesome/free-solid-svg-icons": "^6.2.0", "@fortawesome/free-solid-svg-icons": "^6.2.0",
"@ng-bootstrap/ng-bootstrap": "10.0.0", "@ng-bootstrap/ng-bootstrap": "10.0.0",
"@panva/oauth4webapi": "^1.1.3", "@panva/oauth4webapi": "^1.1.3",
"angular-datatables": "^14.0.0", "@swimlane/ngx-datatable": "^20.0.0",
"bootstrap": "^4.4.1", "bootstrap": "^4.4.1",
"chart.js": "2.9.4", "chart.js": "2.9.4",
"fhirclient": "^2.5.1", "fhirclient": "^2.5.1",
@ -3329,6 +3329,20 @@
"yarn": ">= 1.13.0" "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": { "node_modules/@tootallnate/once": {
"version": "2.0.0", "version": "2.0.0",
"resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-2.0.0.tgz", "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-2.0.0.tgz",
@ -3950,87 +3964,6 @@
"ajv": "^6.9.1" "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": { "node_modules/ansi-colors": {
"version": "4.1.3", "version": "4.1.3",
"resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.3.tgz", "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.3.tgz",
@ -4166,6 +4099,7 @@
"version": "3.0.0", "version": "3.0.0",
"resolved": "https://registry.npmjs.org/aria-query/-/aria-query-3.0.0.tgz", "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-3.0.0.tgz",
"integrity": "sha512-majUxHgLehQTeSA+hClx+DY09OVUqG3GtezWkF1krgLGNdlDu9l9V8DaqNMWbq4Eddc8wsyDA0hpDUtnYxQEXw==", "integrity": "sha512-majUxHgLehQTeSA+hClx+DY09OVUqG3GtezWkF1krgLGNdlDu9l9V8DaqNMWbq4Eddc8wsyDA0hpDUtnYxQEXw==",
"dev": true,
"dependencies": { "dependencies": {
"ast-types-flow": "0.0.7", "ast-types-flow": "0.0.7",
"commander": "^2.11.0" "commander": "^2.11.0"
@ -4234,7 +4168,8 @@
"node_modules/ast-types-flow": { "node_modules/ast-types-flow": {
"version": "0.0.7", "version": "0.0.7",
"resolved": "https://registry.npmjs.org/ast-types-flow/-/ast-types-flow-0.0.7.tgz", "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": { "node_modules/asynckit": {
"version": "0.4.0", "version": "0.4.0",
@ -4315,6 +4250,7 @@
"version": "2.0.2", "version": "2.0.2",
"resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-2.0.2.tgz", "resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-2.0.2.tgz",
"integrity": "sha512-MCeek8ZH7hKyO1rWUbKNQBbl4l2eY0ntk7OGi+q0RlafrCnfPxC06WZA+uebCfmYp4mNU9jRBP1AhGyf8+W3ww==", "integrity": "sha512-MCeek8ZH7hKyO1rWUbKNQBbl4l2eY0ntk7OGi+q0RlafrCnfPxC06WZA+uebCfmYp4mNU9jRBP1AhGyf8+W3ww==",
"dev": true,
"dependencies": { "dependencies": {
"ast-types-flow": "0.0.7" "ast-types-flow": "0.0.7"
} }
@ -5134,7 +5070,8 @@
"node_modules/commander": { "node_modules/commander": {
"version": "2.20.3", "version": "2.20.3",
"resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", "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": { "node_modules/commondir": {
"version": "1.0.1", "version": "1.0.1",
@ -5721,6 +5658,7 @@
"version": "0.7.3", "version": "0.7.3",
"resolved": "https://registry.npmjs.org/css-selector-tokenizer/-/css-selector-tokenizer-0.7.3.tgz", "resolved": "https://registry.npmjs.org/css-selector-tokenizer/-/css-selector-tokenizer-0.7.3.tgz",
"integrity": "sha512-jWQv3oCEL5kMErj4wRnK/OPoBi0D+P1FR2cDCKYPaMeD2eW3/mttav8HT4hT1CKopiJI/psEULjkClhvJo4Lvg==", "integrity": "sha512-jWQv3oCEL5kMErj4wRnK/OPoBi0D+P1FR2cDCKYPaMeD2eW3/mttav8HT4hT1CKopiJI/psEULjkClhvJo4Lvg==",
"dev": true,
"dependencies": { "dependencies": {
"cssesc": "^3.0.0", "cssesc": "^3.0.0",
"fastparse": "^1.1.2" "fastparse": "^1.1.2"
@ -5751,6 +5689,7 @@
"version": "1.4.0", "version": "1.4.0",
"resolved": "https://registry.npmjs.org/cssauron/-/cssauron-1.4.0.tgz", "resolved": "https://registry.npmjs.org/cssauron/-/cssauron-1.4.0.tgz",
"integrity": "sha512-Ht70DcFBh+/ekjVrYS2PlDMdSQEl3OFNmjK6lcn49HptBgilXf/Zwg4uFh9Xn0pX3Q8YOkSjIFOfK2osvdqpBw==", "integrity": "sha512-Ht70DcFBh+/ekjVrYS2PlDMdSQEl3OFNmjK6lcn49HptBgilXf/Zwg4uFh9Xn0pX3Q8YOkSjIFOfK2osvdqpBw==",
"dev": true,
"dependencies": { "dependencies": {
"through": "X.X.X" "through": "X.X.X"
} }
@ -5769,6 +5708,7 @@
"version": "3.0.0", "version": "3.0.0",
"resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz", "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,
"bin": { "bin": {
"cssesc": "bin/cssesc" "cssesc": "bin/cssesc"
}, },
@ -5785,7 +5725,8 @@
"node_modules/damerau-levenshtein": { "node_modules/damerau-levenshtein": {
"version": "1.0.8", "version": "1.0.8",
"resolved": "https://registry.npmjs.org/damerau-levenshtein/-/damerau-levenshtein-1.0.8.tgz", "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": { "node_modules/dashdash": {
"version": "1.14.1", "version": "1.14.1",
@ -7154,7 +7095,8 @@
"node_modules/fastparse": { "node_modules/fastparse": {
"version": "1.1.2", "version": "1.1.2",
"resolved": "https://registry.npmjs.org/fastparse/-/fastparse-1.1.2.tgz", "resolved": "https://registry.npmjs.org/fastparse/-/fastparse-1.1.2.tgz",
"integrity": "sha512-483XLLxTVIwWK3QTrMGRqUfUpoOs/0hbQrl2oz4J0pAcm3A3bu84wxTFqGqkJzewCLdME38xJLJAxBABfQT8sQ==" "integrity": "sha512-483XLLxTVIwWK3QTrMGRqUfUpoOs/0hbQrl2oz4J0pAcm3A3bu84wxTFqGqkJzewCLdME38xJLJAxBABfQT8sQ==",
"dev": true
}, },
"node_modules/fastq": { "node_modules/fastq": {
"version": "1.13.0", "version": "1.13.0",
@ -12580,6 +12522,7 @@
"version": "1.0.1", "version": "1.0.1",
"resolved": "https://registry.npmjs.org/semver-dsl/-/semver-dsl-1.0.1.tgz", "resolved": "https://registry.npmjs.org/semver-dsl/-/semver-dsl-1.0.1.tgz",
"integrity": "sha512-e8BOaTo007E3dMuQQTnPdalbKTABKNS7UxoBIDnwOqRa+QwMrCPjynB8zAlPF6xlqUfdLPPLIJ13hJNmhtq8Ng==", "integrity": "sha512-e8BOaTo007E3dMuQQTnPdalbKTABKNS7UxoBIDnwOqRa+QwMrCPjynB8zAlPF6xlqUfdLPPLIJ13hJNmhtq8Ng==",
"dev": true,
"dependencies": { "dependencies": {
"semver": "^5.3.0" "semver": "^5.3.0"
} }
@ -12588,6 +12531,7 @@
"version": "5.7.1", "version": "5.7.1",
"resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz",
"integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==",
"dev": true,
"bin": { "bin": {
"semver": "bin/semver" "semver": "bin/semver"
} }
@ -13092,7 +13036,8 @@
"node_modules/sprintf-js": { "node_modules/sprintf-js": {
"version": "1.1.2", "version": "1.1.2",
"resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.1.2.tgz", "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": { "node_modules/sshpk": {
"version": "1.17.0", "version": "1.17.0",
@ -13419,7 +13364,8 @@
"node_modules/through": { "node_modules/through": {
"version": "2.3.8", "version": "2.3.8",
"resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", "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": { "node_modules/thunky": {
"version": "1.1.0", "version": "1.1.0",
@ -16837,6 +16783,14 @@
"jsonc-parser": "3.1.0" "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": { "@tootallnate/once": {
"version": "2.0.0", "version": "2.0.0",
"resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-2.0.0.tgz", "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-2.0.0.tgz",
@ -17407,67 +17361,6 @@
"integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==",
"dev": true "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": { "ansi-colors": {
"version": "4.1.3", "version": "4.1.3",
"resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.3.tgz", "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.3.tgz",
@ -17574,6 +17467,7 @@
"version": "3.0.0", "version": "3.0.0",
"resolved": "https://registry.npmjs.org/aria-query/-/aria-query-3.0.0.tgz", "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-3.0.0.tgz",
"integrity": "sha512-majUxHgLehQTeSA+hClx+DY09OVUqG3GtezWkF1krgLGNdlDu9l9V8DaqNMWbq4Eddc8wsyDA0hpDUtnYxQEXw==", "integrity": "sha512-majUxHgLehQTeSA+hClx+DY09OVUqG3GtezWkF1krgLGNdlDu9l9V8DaqNMWbq4Eddc8wsyDA0hpDUtnYxQEXw==",
"dev": true,
"requires": { "requires": {
"ast-types-flow": "0.0.7", "ast-types-flow": "0.0.7",
"commander": "^2.11.0" "commander": "^2.11.0"
@ -17630,7 +17524,8 @@
"ast-types-flow": { "ast-types-flow": {
"version": "0.0.7", "version": "0.0.7",
"resolved": "https://registry.npmjs.org/ast-types-flow/-/ast-types-flow-0.0.7.tgz", "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": { "asynckit": {
"version": "0.4.0", "version": "0.4.0",
@ -17680,6 +17575,7 @@
"version": "2.0.2", "version": "2.0.2",
"resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-2.0.2.tgz", "resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-2.0.2.tgz",
"integrity": "sha512-MCeek8ZH7hKyO1rWUbKNQBbl4l2eY0ntk7OGi+q0RlafrCnfPxC06WZA+uebCfmYp4mNU9jRBP1AhGyf8+W3ww==", "integrity": "sha512-MCeek8ZH7hKyO1rWUbKNQBbl4l2eY0ntk7OGi+q0RlafrCnfPxC06WZA+uebCfmYp4mNU9jRBP1AhGyf8+W3ww==",
"dev": true,
"requires": { "requires": {
"ast-types-flow": "0.0.7" "ast-types-flow": "0.0.7"
} }
@ -18299,7 +18195,8 @@
"commander": { "commander": {
"version": "2.20.3", "version": "2.20.3",
"resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", "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": { "commondir": {
"version": "1.0.1", "version": "1.0.1",
@ -18752,6 +18649,7 @@
"version": "0.7.3", "version": "0.7.3",
"resolved": "https://registry.npmjs.org/css-selector-tokenizer/-/css-selector-tokenizer-0.7.3.tgz", "resolved": "https://registry.npmjs.org/css-selector-tokenizer/-/css-selector-tokenizer-0.7.3.tgz",
"integrity": "sha512-jWQv3oCEL5kMErj4wRnK/OPoBi0D+P1FR2cDCKYPaMeD2eW3/mttav8HT4hT1CKopiJI/psEULjkClhvJo4Lvg==", "integrity": "sha512-jWQv3oCEL5kMErj4wRnK/OPoBi0D+P1FR2cDCKYPaMeD2eW3/mttav8HT4hT1CKopiJI/psEULjkClhvJo4Lvg==",
"dev": true,
"requires": { "requires": {
"cssesc": "^3.0.0", "cssesc": "^3.0.0",
"fastparse": "^1.1.2" "fastparse": "^1.1.2"
@ -18767,6 +18665,7 @@
"version": "1.4.0", "version": "1.4.0",
"resolved": "https://registry.npmjs.org/cssauron/-/cssauron-1.4.0.tgz", "resolved": "https://registry.npmjs.org/cssauron/-/cssauron-1.4.0.tgz",
"integrity": "sha512-Ht70DcFBh+/ekjVrYS2PlDMdSQEl3OFNmjK6lcn49HptBgilXf/Zwg4uFh9Xn0pX3Q8YOkSjIFOfK2osvdqpBw==", "integrity": "sha512-Ht70DcFBh+/ekjVrYS2PlDMdSQEl3OFNmjK6lcn49HptBgilXf/Zwg4uFh9Xn0pX3Q8YOkSjIFOfK2osvdqpBw==",
"dev": true,
"requires": { "requires": {
"through": "X.X.X" "through": "X.X.X"
} }
@ -18780,7 +18679,8 @@
"cssesc": { "cssesc": {
"version": "3.0.0", "version": "3.0.0",
"resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz", "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": { "custom-event": {
"version": "1.0.1", "version": "1.0.1",
@ -18791,7 +18691,8 @@
"damerau-levenshtein": { "damerau-levenshtein": {
"version": "1.0.8", "version": "1.0.8",
"resolved": "https://registry.npmjs.org/damerau-levenshtein/-/damerau-levenshtein-1.0.8.tgz", "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": { "dashdash": {
"version": "1.14.1", "version": "1.14.1",
@ -19739,7 +19640,8 @@
"fastparse": { "fastparse": {
"version": "1.1.2", "version": "1.1.2",
"resolved": "https://registry.npmjs.org/fastparse/-/fastparse-1.1.2.tgz", "resolved": "https://registry.npmjs.org/fastparse/-/fastparse-1.1.2.tgz",
"integrity": "sha512-483XLLxTVIwWK3QTrMGRqUfUpoOs/0hbQrl2oz4J0pAcm3A3bu84wxTFqGqkJzewCLdME38xJLJAxBABfQT8sQ==" "integrity": "sha512-483XLLxTVIwWK3QTrMGRqUfUpoOs/0hbQrl2oz4J0pAcm3A3bu84wxTFqGqkJzewCLdME38xJLJAxBABfQT8sQ==",
"dev": true
}, },
"fastq": { "fastq": {
"version": "1.13.0", "version": "1.13.0",
@ -23719,6 +23621,7 @@
"version": "1.0.1", "version": "1.0.1",
"resolved": "https://registry.npmjs.org/semver-dsl/-/semver-dsl-1.0.1.tgz", "resolved": "https://registry.npmjs.org/semver-dsl/-/semver-dsl-1.0.1.tgz",
"integrity": "sha512-e8BOaTo007E3dMuQQTnPdalbKTABKNS7UxoBIDnwOqRa+QwMrCPjynB8zAlPF6xlqUfdLPPLIJ13hJNmhtq8Ng==", "integrity": "sha512-e8BOaTo007E3dMuQQTnPdalbKTABKNS7UxoBIDnwOqRa+QwMrCPjynB8zAlPF6xlqUfdLPPLIJ13hJNmhtq8Ng==",
"dev": true,
"requires": { "requires": {
"semver": "^5.3.0" "semver": "^5.3.0"
}, },
@ -23726,7 +23629,8 @@
"semver": { "semver": {
"version": "5.7.1", "version": "5.7.1",
"resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", "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": { "sprintf-js": {
"version": "1.1.2", "version": "1.1.2",
"resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.1.2.tgz", "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.1.2.tgz",
"integrity": "sha512-VE0SOVEHCk7Qc8ulkWw3ntAzXuqf7S2lvwQaDLRnUeIEaKNQJzV6BwmLKhOqT61aGhfUMrXeaBk+oDGCzvhcug==" "integrity": "sha512-VE0SOVEHCk7Qc8ulkWw3ntAzXuqf7S2lvwQaDLRnUeIEaKNQJzV6BwmLKhOqT61aGhfUMrXeaBk+oDGCzvhcug==",
"dev": true
}, },
"sshpk": { "sshpk": {
"version": "1.17.0", "version": "1.17.0",
@ -24379,7 +24284,8 @@
"through": { "through": {
"version": "2.3.8", "version": "2.3.8",
"resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz",
"integrity": "sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==" "integrity": "sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==",
"dev": true
}, },
"thunky": { "thunky": {
"version": "1.1.0", "version": "1.1.0",

View File

@ -28,7 +28,7 @@
"@fortawesome/free-solid-svg-icons": "^6.2.0", "@fortawesome/free-solid-svg-icons": "^6.2.0",
"@ng-bootstrap/ng-bootstrap": "10.0.0", "@ng-bootstrap/ng-bootstrap": "10.0.0",
"@panva/oauth4webapi": "^1.1.3", "@panva/oauth4webapi": "^1.1.3",
"angular-datatables": "^14.0.0", "@swimlane/ngx-datatable": "^20.0.0",
"bootstrap": "^4.4.1", "bootstrap": "^4.4.1",
"chart.js": "2.9.4", "chart.js": "2.9.4",
"fhirclient": "^2.5.1", "fhirclient": "^2.5.1",

View File

@ -1,26 +0,0 @@
<p class="mg-b-20">A clinical condition, problem, diagnosis, or other event, situation, issue, or clinical concept that has risen to a level of concern.</p>
<div class="table-responsive">
<table class="table table-bordered mg-b-0">
<thead>
<tr>
<th>Condition</th>
<th>Clinical Status</th>
<th>Verification Status</th>
<th>Onset Date</th>
</tr>
</thead>
<tbody>
<tr *ngFor="let condition of conditionList">
<td>
{{condition.name}}
<small class="text-muted float-right">
{{ condition.nameCode}} {{ condition.nameCodeSystem }}
</small>
</td>
<td class="align-middle">{{condition.clinicalStatus}}</td>
<td class="align-middle">{{condition.verificationStatus}}</td>
<td class="align-middle">{{condition.onset | date:'M/d/yy'}}</td>
</tr>
</tbody>
</table>
</div>

View File

@ -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<ListConditionComponent>;
beforeEach(async () => {
await TestBed.configureTestingModule({
declarations: [ ListConditionComponent ]
})
.compileComponents();
fixture = TestBed.createComponent(ListConditionComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});

View File

@ -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)
})
}
}

View File

@ -1,27 +0,0 @@
<p class="mg-b-20">A clinical condition, problem, diagnosis, or other event, situation, issue, or clinical concept that has risen to a level of concern.</p>
<div class="table-responsive">
<table class="table table-bordered mg-b-0">
<thead>
<tr>
<th>Type</th>
<th>Reason</th>
<th>Class</th>
<th>Status</th>
<th>Time</th>
</tr>
</thead>
<tbody>
<tr *ngFor="let encounter of encounterList">
<td>
<b *ngIf="encounter.encounterType">{{encounter.encounterType}}</b>
<span *ngIf="!encounter.encounterType && encounter.encounterClass" class="text-muted">{{encounter.encounterClass}} encounter</span>
<small *ngIf="!encounter.encounterType && !encounter.encounterClass" class="text-muted">N/A</small>
</td>
<td class="align-middle">{{encounter.reason ? encounter.reason : 'N/A' }}</td>
<td class="align-middle">{{encounter.encounterClass ? encounter.encounterClass : 'N/A' }}</td>
<td class="align-middle">{{encounter.status ? encounter.status : 'N/A'}}</td>
<td class="align-middle">-</td>
</tr>
</tbody>
</table>
</div>

View File

@ -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<ListEncounterComponent>;
beforeEach(async () => {
await TestBed.configureTestingModule({
declarations: [ ListEncounterComponent ]
})
.compileComponents();
fixture = TestBed.createComponent(ListEncounterComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});

View File

@ -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)
})
}
}

View File

@ -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] }
]
}

View File

@ -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] }
]
}

View File

@ -0,0 +1,14 @@
<div>
<ngx-datatable
#table
class="bootstrap"
[columns]="columns"
[columnMode]="ColumnMode.force"
[headerHeight]="50"
[footerHeight]="50"
rowHeight="auto"
[limit]="10"
[rows]="rows"
>
</ngx-datatable>
</div>

View File

@ -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<ListGenericResourceComponent>;
beforeEach(async () => {
await TestBed.configureTestingModule({
declarations: [ ListGenericResourceComponent ]
})
.compileComponents();
fixture = TestBed.createComponent(ListGenericResourceComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});

View File

@ -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
///////////////////////////////////////////////////////////////////////////////////////

View File

@ -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 }
]
}

View File

@ -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] }
]
}

View File

@ -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 }
]
}

View File

@ -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 }
]
}

View File

@ -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] }
]
}

View File

@ -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();
};

View File

@ -1,19 +0,0 @@
<p class="mg-b-20">A clinical condition, problem, diagnosis, or other event, situation, issue, or clinical concept that has risen to a level of concern.</p>
<div class="table-responsive">
<table class="table table-bordered mg-b-0">
<thead>
<tr>
<th>Type</th>
<th>Status</th>
<th>Date</th>
</tr>
</thead>
<tbody>
<tr *ngFor="let immunization of immunizationList">
<td>{{immunization.immunizationType}}</td>
<td class="align-middle">{{immunization.status || '-'}}</td>
<td class="align-middle">{{immunization.date }}</td>
</tr>
</tbody>
</table>
</div>

View File

@ -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<ListImmunizationComponent>;
beforeEach(async () => {
await TestBed.configureTestingModule({
declarations: [ ListImmunizationComponent ]
})
.compileComponents();
fixture = TestBed.createComponent(ListImmunizationComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});

View File

@ -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)
})
}
}

View File

@ -1 +0,0 @@
<p>list-observation works!</p>

View File

@ -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<ListObservationComponent>;
beforeEach(async () => {
await TestBed.configureTestingModule({
declarations: [ ListObservationComponent ]
})
.compileComponents();
fixture = TestBed.createComponent(ListObservationComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});

View File

@ -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 {
}
}

View File

@ -3,19 +3,25 @@ import { ComponentsSidebarComponent } from './components-sidebar/components-side
import { RouterModule } from '@angular/router'; import { RouterModule } from '@angular/router';
import { UtilitiesSidebarComponent } from './utilities-sidebar/utilities-sidebar.component'; import { UtilitiesSidebarComponent } from './utilities-sidebar/utilities-sidebar.component';
import { ListPatientComponent } from './list-patient/list-patient.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 { 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 { ListCarePlanComponent } from './list-care-plan/list-care-plan.component';
import {BrowserModule} from '@angular/platform-browser'; 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({ @NgModule({
imports: [ imports: [
RouterModule, RouterModule,
BrowserModule, BrowserModule,
NgxDatatableModule
], ],
declarations: [ declarations: [
ComponentsSidebarComponent, ComponentsSidebarComponent,
@ -25,20 +31,28 @@ import { ListGenericResourceComponent } from './list-generic-resource/list-gener
ListExplanationOfBenefitComponent, ListExplanationOfBenefitComponent,
ListImmunizationComponent, ListImmunizationComponent,
ListEncounterComponent, ListEncounterComponent,
ListConditionComponent,
ListCarePlanComponent, ListCarePlanComponent,
ListGenericResourceComponent ListGenericResourceComponent,
ListMedicationComponent,
ListProcedureComponent,
ListConditionComponent,
ListMedicationRequestComponent
], ],
exports: [ exports: [
ComponentsSidebarComponent, ComponentsSidebarComponent,
UtilitiesSidebarComponent, UtilitiesSidebarComponent,
ListPatientComponent, ListPatientComponent,
ListObservationComponent,
ListExplanationOfBenefitComponent, ListExplanationOfBenefitComponent,
ListImmunizationComponent, ListImmunizationComponent,
ListEncounterComponent, ListEncounterComponent,
ListCarePlanComponent,
ListGenericResourceComponent,
ListMedicationComponent,
ListObservationComponent,
ListProcedureComponent,
ListConditionComponent, ListConditionComponent,
ListCarePlanComponent ListMedicationRequestComponent
] ]
}) })

View File

@ -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
}
}
}
}
}

View File

@ -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)
}
}

View File

@ -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)
}
}

View File

@ -20,7 +20,10 @@
<app-list-care-plan *ngIf="selectedResourceType == 'CarePlan'" [resourceList]="selectedResources"></app-list-care-plan> <app-list-care-plan *ngIf="selectedResourceType == 'CarePlan'" [resourceList]="selectedResources"></app-list-care-plan>
<app-list-encounter *ngIf="selectedResourceType == 'Encounter'" [resourceList]="selectedResources"></app-list-encounter> <app-list-encounter *ngIf="selectedResourceType == 'Encounter'" [resourceList]="selectedResources"></app-list-encounter>
<app-list-immunization *ngIf="selectedResourceType == 'Immunization'" [resourceList]="selectedResources"></app-list-immunization> <app-list-immunization *ngIf="selectedResourceType == 'Immunization'" [resourceList]="selectedResources"></app-list-immunization>
<app-list-medication *ngIf="selectedResourceType == 'Medication'" [resourceList]="selectedResources"></app-list-medication>
<app-list-medication-request *ngIf="selectedResourceType == 'MedicationRequest'" [resourceList]="selectedResources"></app-list-medication-request>
<app-list-observation *ngIf="selectedResourceType == 'Observation'" [resourceList]="selectedResources"></app-list-observation>
<app-list-procedure *ngIf="selectedResourceType == 'Procedure'" [resourceList]="selectedResources"></app-list-procedure>
</div><!-- az-content-body --> </div><!-- az-content-body -->
</div><!-- container --> </div><!-- container -->

View File

@ -206,3 +206,7 @@
//@import "~datatables.net-dt/css/jquery.dataTables.css"; //@import "~datatables.net-dt/css/jquery.dataTables.css";
//@import '~@fullcalendar/core/main.css'; //@import '~@fullcalendar/core/main.css';
//@import '~perfect-scrollbar/css/perfect-scrollbar.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';