diff --git a/frontend/package.json b/frontend/package.json index e7051977..36bb7053 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -30,6 +30,7 @@ "@panva/oauth4webapi": "^1.1.3", "@swimlane/ngx-datatable": "^20.0.0", "@types/pouchdb": "^6.4.0", + "@types/pouchdb-find": "^7.3.0", "bootstrap": "^4.4.1", "chart.js": "2.9.4", "fhirclient": "^2.5.1", diff --git a/frontend/src/app/pages/dashboard/dashboard.component.html b/frontend/src/app/pages/dashboard/dashboard.component.html index b71f9f22..47a0fd4a 100644 --- a/frontend/src/app/pages/dashboard/dashboard.component.html +++ b/frontend/src/app/pages/dashboard/dashboard.component.html @@ -148,7 +148,7 @@
{{metadataSource[source.source_type]?.display}}

- {{getPatientSummary(patientForSource[source.id]?.payload)}} + {{getPatientSummary(patientForSource[source.id]?.resource_raw)}}

diff --git a/frontend/src/app/pages/dashboard/dashboard.component.ts b/frontend/src/app/pages/dashboard/dashboard.component.ts index 225a9f21..164a8537 100644 --- a/frontend/src/app/pages/dashboard/dashboard.component.ts +++ b/frontend/src/app/pages/dashboard/dashboard.component.ts @@ -1,12 +1,13 @@ import { Component, OnInit } from '@angular/core'; import {FastenApiService} from '../../services/fasten-api.service'; -import {Source} from '../../models/fasten/source'; +import {Source} from '../../../lib/models/database/source'; import {Router} from '@angular/router'; -import {Summary} from '../../models/fasten/summary'; -import {ResourceTypeCounts} from '../../models/fasten/source-summary'; -import {ResourceFhir} from '../../models/fasten/resource_fhir'; +import {ResourceFhir} from '../../../lib/models/database/resource_fhir'; import {forkJoin} from 'rxjs'; import {MetadataSource} from '../../models/fasten/metadata-source'; +import {FastenDbService} from '../../services/fasten-db.service'; +import {Summary} from '../../../lib/models/fasten/summary'; +import {Base64} from '../../../lib/utils/base64'; @Component({ selector: 'app-dashboard', @@ -22,7 +23,11 @@ export class DashboardComponent implements OnInit { metadataSource: { [name: string]: MetadataSource } - constructor(private fastenApi: FastenApiService, private router: Router) { } + constructor( + private fastenApi: FastenApiService, + private fastenDb: FastenDbService, + private router: Router + ) { } ngOnInit() { @@ -44,7 +49,7 @@ export class DashboardComponent implements OnInit { // }) // }) - forkJoin([this.fastenApi.getSummary(), this.fastenApi.getMetadataSources()]).subscribe(results => { + forkJoin([this.fastenDb.GetSummary(), this.fastenApi.getMetadataSources()]).subscribe(results => { let summary = results[0] as Summary let metadataSource = results[1] as { [name: string]: MetadataSource } @@ -59,7 +64,6 @@ export class DashboardComponent implements OnInit { "enabled": true, } - //calculate the number of records summary.resource_type_counts.forEach((resourceTypeInfo) => { this.recordsCount += resourceTypeInfo.count @@ -71,16 +75,13 @@ export class DashboardComponent implements OnInit { summary.patients.forEach((resourceFhir) => { this.patientForSource[resourceFhir.source_id] = resourceFhir }) - - - }); } selectSource(selectedSource: Source){ - this.router.navigateByUrl(`/source/${selectedSource.id}`, { + this.router.navigateByUrl(`/source/${Base64.Encode(selectedSource._id)}`, { state: selectedSource }); } 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 68b92241..d440c975 100644 --- a/frontend/src/app/pages/source-detail/source-detail.component.html +++ b/frontend/src/app/pages/source-detail/source-detail.component.html @@ -18,7 +18,7 @@

{{getPatientName()}}

- +
diff --git a/frontend/src/app/pages/source-detail/source-detail.component.ts b/frontend/src/app/pages/source-detail/source-detail.component.ts index f9f61613..8dd7171a 100644 --- a/frontend/src/app/pages/source-detail/source-detail.component.ts +++ b/frontend/src/app/pages/source-detail/source-detail.component.ts @@ -1,9 +1,10 @@ import {Component, OnInit, ViewChild} from '@angular/core'; import {ActivatedRoute, Router} from '@angular/router'; -import {Source} from '../../models/fasten/source'; -import {FastenApiService} from '../../services/fasten-api.service'; -import {ResourceFhir} from '../../models/fasten/resource_fhir'; +import {Source} from '../../../lib/models/database/source'; +import {FastenDbService} from '../../services/fasten-db.service'; +import {ResourceFhir} from '../../../lib/models/database/resource_fhir'; import {getPath} from '../../components/list-generic-resource/utils'; +import {Base64} from '../../../lib/utils/base64'; @Component({ @@ -19,7 +20,7 @@ export class SourceDetailComponent implements OnInit { resourceTypeCounts: { [name: string]: number } = {} - constructor(private fastenApi: FastenApiService, private router: Router, private route: ActivatedRoute) { + constructor(private fastenDb: FastenDbService, private router: Router, private route: ActivatedRoute) { //check if the current Source was sent over using the router state storage: if(this.router.getCurrentNavigation().extras.state){ this.selectedSource = this.router.getCurrentNavigation().extras.state as Source @@ -28,7 +29,7 @@ export class SourceDetailComponent implements OnInit { ngOnInit(): void { //always request the source summary - this.fastenApi.getSourceSummary(this.route.snapshot.paramMap.get('source_id')).subscribe((sourceSummary) => { + this.fastenDb.GetSourceSummary(Base64.Decode(this.route.snapshot.paramMap.get('source_id'))).then((sourceSummary) => { this.selectedSource = sourceSummary.source; this.selectedPatient = sourceSummary.patient; for(let resourceTypeCount of sourceSummary.resource_type_counts){ @@ -47,24 +48,24 @@ export class SourceDetailComponent implements OnInit { return `${getPath(this.selectedPatient?.payload, 'name.0.family')}, ${getPath(this.selectedPatient?.payload, 'name.0.given').join(' ')}` } getPatientGender(){ - return getPath(this.selectedPatient?.payload, 'gender') + return getPath(this.selectedPatient?.resource_raw, 'gender') } getPatientMRN(){ - return getPath(this.selectedPatient?.payload, 'identifier.0.value') + return getPath(this.selectedPatient?.resource_raw, 'identifier.0.value') } getPatientEmail(){ // @ts-ignore - return (this.selectedPatient?.payload?.telecom || []).filter( + return (this.selectedPatient?.resource_raw?.telecom || []).filter( telecom => telecom.system === 'email', )[0]?.value } getPatientDOB(){ - return getPath(this.selectedPatient?.payload, 'birthDate') + return getPath(this.selectedPatient?.resource_raw, 'birthDate') } getPatientPhone(){ // @ts-ignore - return (this.selectedPatient?.payload?.telecom || []).filter( + return (this.selectedPatient?.resource_raw?.telecom || []).filter( telecom => telecom.system === 'phone', )[0]?.value } @@ -72,9 +73,9 @@ export class SourceDetailComponent implements OnInit { return '' } getPatientAddress(){ - const line = getPath(this.selectedPatient?.payload, 'address.0.line') - const city = getPath(this.selectedPatient?.payload, 'address.0.city') - const state = getPath(this.selectedPatient?.payload, 'address.0.state') + const line = getPath(this.selectedPatient?.resource_raw, 'address.0.line') + const city = getPath(this.selectedPatient?.resource_raw, 'address.0.city') + const state = getPath(this.selectedPatient?.resource_raw, 'address.0.state') return `${line}, ${city}, ${state}` } diff --git a/frontend/src/lib/database/pouchdb_repository.ts b/frontend/src/lib/database/pouchdb_repository.ts index 735a6520..2043da01 100644 --- a/frontend/src/lib/database/pouchdb_repository.ts +++ b/frontend/src/lib/database/pouchdb_repository.ts @@ -1,7 +1,7 @@ import {Source} from '../models/database/source'; import {IDatabasePaginatedResponse, IDatabaseDocument, IDatabaseRepository} from './interface'; import * as PouchDB from 'pouchdb/dist/pouchdb'; -import PouchFind from 'pouchdb/dist/pouchdb.find'; +// import * as PouchFind from 'pouchdb/dist/pouchdb.find'; // import * as PouchDB from 'pouchdb'; import {DocType} from './constants'; import {ResourceFhir} from '../models/database/resource_fhir'; @@ -18,20 +18,20 @@ export class PouchdbRepository implements IDatabaseRepository { localPouchDb: PouchDB.Database constructor(public databaseName: string) { //setup PouchDB Plugins - PouchDB.plugin(PouchFind); //https://pouchdb.com/guides/mango-queries.html + // PouchDB.plugin(PouchFind); //https://pouchdb.com/guides/mango-queries.html this.localPouchDb = new PouchDB(databaseName); //create any necessary indexes // this index allows us to group by source_resource_type - this.localPouchDb.createIndex({ - index: {fields: [ - //global - 'doc_type', - //only relevant for resource_fhir documents - 'source_resource_type', - ]} - }, (msg) => {console.log("DB createIndex complete", msg)}); + // this.localPouchDb.createIndex({ + // index: {fields: [ + // //global + // 'doc_type', + // //only relevant for resource_fhir documents + // 'source_resource_type', + // ]} + // }, (msg) => {console.log("DB createIndex complete", msg)}); } @@ -48,24 +48,28 @@ export class PouchdbRepository implements IDatabaseRepository { summary.sources = await this.GetSources() .then((paginatedResp) => paginatedResp.rows) - summary.patients = await this.GetDB().find({ - selector: { - doc_type: DocType.ResourceFhir, - source_resource_type: "Patient", - } - }) + summary.patients = [] + // summary.patients = await this.GetDB().find({ + // selector: { + // doc_type: DocType.ResourceFhir, + // source_resource_type: "Patient", + // } + // }) - summary.resource_type_counts = await this.findDocumentByPrefix(`${DocType.ResourceFhir}`, true) + summary.resource_type_counts = await this.findDocumentByPrefix(`${DocType.ResourceFhir}`, false) .then((paginatedResp) => { const lookup: {[name: string]: ResourceTypeCounts} = {} - paginatedResp?.rows.forEach((resource: ResourceFhir) => { - let currentResourceStats = lookup[resource.source_resource_type] || { + paginatedResp?.rows.forEach((resourceWrapper) => { + const resourceIdParts = resourceWrapper.id.split(':') + const resourceType = resourceIdParts[2] + + let currentResourceStats = lookup[resourceType] || { count: 0, - source_id: resource.source_id, - resource_type: resource.source_resource_type + source_id: Base64.Decode(resourceIdParts[1]), + resource_type: resourceType } currentResourceStats.count += 1 - lookup[resource.source_resource_type] = currentResourceStats + lookup[resourceType] = currentResourceStats }) const arr = [] @@ -110,17 +114,20 @@ export class PouchdbRepository implements IDatabaseRepository { sourceSummary.patient = await this.findDocumentByPrefix(`${DocType.ResourceFhir}:${Base64.Encode(source_id)}:Patient`, true) .then((paginatedResp) => paginatedResp?.rows[0]) - sourceSummary.resource_type_counts = await this.findDocumentByPrefix(`${DocType.ResourceFhir}:${Base64.Encode(source_id)}`, true) + sourceSummary.resource_type_counts = await this.findDocumentByPrefix(`${DocType.ResourceFhir}:${Base64.Encode(source_id)}`, false) .then((paginatedResp) => { const lookup: {[name: string]: ResourceTypeCounts} = {} - paginatedResp?.rows.forEach((resource: ResourceFhir) => { - let currentResourceStats = lookup[resource.source_resource_type] || { + paginatedResp?.rows.forEach((resourceWrapper) => { + const resourceIdParts = resourceWrapper.id.split(':') + const resourceType = resourceIdParts[2] + + let currentResourceStats = lookup[resourceType] || { count: 0, - source_id: resource.source_id, - resource_type: resource.source_resource_type + source_id: Base64.Decode(resourceIdParts[1]), + resource_type: resourceType } currentResourceStats.count += 1 - lookup[resource.source_resource_type] = currentResourceStats + lookup[resourceType] = currentResourceStats }) const arr = [] diff --git a/frontend/src/app/models/fasten/source-summary.ts b/frontend/src/lib/models/fasten/source-summary.ts similarity index 68% rename from frontend/src/app/models/fasten/source-summary.ts rename to frontend/src/lib/models/fasten/source-summary.ts index 06a5e315..61e56182 100644 --- a/frontend/src/app/models/fasten/source-summary.ts +++ b/frontend/src/lib/models/fasten/source-summary.ts @@ -1,5 +1,5 @@ -import {Source} from './source'; -import {ResourceFhir} from './resource_fhir'; +import {Source} from '../database/source'; +import {ResourceFhir} from '../database/resource_fhir'; export class ResourceTypeCounts { count: number diff --git a/frontend/src/app/models/fasten/summary.ts b/frontend/src/lib/models/fasten/summary.ts similarity index 63% rename from frontend/src/app/models/fasten/summary.ts rename to frontend/src/lib/models/fasten/summary.ts index 989fba14..0ca58e85 100644 --- a/frontend/src/app/models/fasten/summary.ts +++ b/frontend/src/lib/models/fasten/summary.ts @@ -1,6 +1,6 @@ -import {Source} from './source'; +import {Source} from '../database/source'; import {ResourceTypeCounts} from './source-summary'; -import {ResourceFhir} from './resource_fhir'; +import {ResourceFhir} from '../database/resource_fhir'; export class Summary { sources: Source[] diff --git a/frontend/tsconfig.app.json b/frontend/tsconfig.app.json index f758d982..355fd45e 100644 --- a/frontend/tsconfig.app.json +++ b/frontend/tsconfig.app.json @@ -1,6 +1,7 @@ { "extends": "./tsconfig.json", "compilerOptions": { + "skipLibCheck": true, //this is because fhirclient types.d.ts file includes reference to "http" (Node) library "outDir": "./out-tsc/app", "types": [] }, diff --git a/frontend/tsconfig.json b/frontend/tsconfig.json index 651487ff..9cba315d 100644 --- a/frontend/tsconfig.json +++ b/frontend/tsconfig.json @@ -11,9 +11,11 @@ "module": "esnext", "moduleResolution": "node", "importHelpers": true, + "target": "esnext", "typeRoots": ["node_modules/@types"], "lib": [ + "es2019", "es2018", "dom" ] diff --git a/frontend/tsconfig.worker.json b/frontend/tsconfig.worker.json new file mode 100644 index 00000000..28090ba2 --- /dev/null +++ b/frontend/tsconfig.worker.json @@ -0,0 +1,16 @@ +/* To learn more about this file see: https://angular.io/config/tsconfig. */ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "outDir": "./out-tsc/worker", + "lib": [ + "es2019", + "es2018", + "webworker" + ], + "types": [] + }, + "include": [ + "src/**/*.worker.ts" + ] +} diff --git a/frontend/yarn.lock b/frontend/yarn.lock index aab7b253..c1d42a3e 100644 --- a/frontend/yarn.lock +++ b/frontend/yarn.lock @@ -1847,6 +1847,13 @@ dependencies: "@types/pouchdb-core" "*" +"@types/pouchdb-find@^7.3.0": + version "7.3.0" + resolved "https://registry.yarnpkg.com/@types/pouchdb-find/-/pouchdb-find-7.3.0.tgz#b917030e9f4bf6e56bf8c3b9fe4b2a25e989009a" + integrity sha512-sFPli5tBjGX9UfXioik1jUzPdcN84eV82n0lmEFuoPepWqkLjQcyri0eOa++HYOaNPyMDhKFBqEALEZivK2dRg== + dependencies: + "@types/pouchdb-core" "*" + "@types/pouchdb-http@*": version "6.1.3" resolved "https://registry.yarnpkg.com/@types/pouchdb-http/-/pouchdb-http-6.1.3.tgz#09576c0d409da1f8dee34ec5b768415e2472ea52"