working app, everything except login and metadata is stored in browser storage.
This commit is contained in:
parent
17fa95008a
commit
99a9ac67d7
|
@ -18,7 +18,7 @@ const routes: Routes = [
|
||||||
{ path: '', redirectTo: '/dashboard', pathMatch: 'full' },
|
{ path: '', redirectTo: '/dashboard', pathMatch: 'full' },
|
||||||
{ path: 'dashboard', component: DashboardComponent, canActivate: [ CanActivateAuthGuard] },
|
{ path: 'dashboard', component: DashboardComponent, canActivate: [ CanActivateAuthGuard] },
|
||||||
{ path: 'source/:source_id', component: SourceDetailComponent, canActivate: [ CanActivateAuthGuard] },
|
{ path: 'source/:source_id', component: SourceDetailComponent, canActivate: [ CanActivateAuthGuard] },
|
||||||
{ path: 'source/:source_id/resource/:resource_id', component: ResourceDetailComponent, canActivate: [ CanActivateAuthGuard] },
|
{ path: 'resource/:resource_id', component: ResourceDetailComponent, canActivate: [ CanActivateAuthGuard] },
|
||||||
{ path: 'sources', component: MedicalSourcesComponent, canActivate: [ CanActivateAuthGuard] },
|
{ path: 'sources', component: MedicalSourcesComponent, canActivate: [ CanActivateAuthGuard] },
|
||||||
{ path: 'sources/callback/:source_type', component: MedicalSourcesComponent, canActivate: [ CanActivateAuthGuard] },
|
{ path: 'sources/callback/:source_type', component: MedicalSourcesComponent, canActivate: [ CanActivateAuthGuard] },
|
||||||
|
|
||||||
|
|
|
@ -9,6 +9,6 @@
|
||||||
|
|
||||||
<ul class="list-group">
|
<ul class="list-group">
|
||||||
<li class="list-group-item" *ngFor="let resource of resourceList">
|
<li class="list-group-item" *ngFor="let resource of resourceList">
|
||||||
<a routerLink="/source/{{resource.source_id}}/resource/{{resource.source_resource_id}}">{{resource.source_resource_id}}</a>
|
<a routerLink="/resource/{{getResourceIdEncoded(resource)}}">{{resource.source_resource_id}}</a>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
|
|
|
@ -1,7 +1,8 @@
|
||||||
import {ChangeDetectorRef, Component, Input, OnInit} from '@angular/core';
|
import {ChangeDetectorRef, Component, Input, OnInit} from '@angular/core';
|
||||||
import {ResourceFhir} from '../../models/fasten/resource_fhir';
|
import {ResourceFhir} from '../../../lib/models/database/resource_fhir';
|
||||||
import {ResourceListComponentInterface} from '../list-generic-resource/list-generic-resource.component';
|
import {ResourceListComponentInterface} from '../list-generic-resource/list-generic-resource.component';
|
||||||
import {Router} from '@angular/router';
|
import {Router} from '@angular/router';
|
||||||
|
import {Base64} from '../../../lib/utils/base64';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-list-fallback-resource',
|
selector: 'app-list-fallback-resource',
|
||||||
|
@ -21,4 +22,10 @@ export class ListFallbackResourceComponent implements OnInit, ResourceListCompo
|
||||||
markForCheck(){
|
markForCheck(){
|
||||||
this.changeRef.markForCheck()
|
this.changeRef.markForCheck()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//TODO this should eb moved to a Pipe
|
||||||
|
getResourceIdEncoded(resource: ResourceFhir){
|
||||||
|
return Base64.Encode(resource._id)
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
import {ChangeDetectorRef, Component, Input, OnChanges, OnInit, SimpleChanges, ViewChild} from '@angular/core';
|
import {ChangeDetectorRef, Component, Input, OnInit, ViewChild} from '@angular/core';
|
||||||
import {DatatableComponent, ColumnMode, SelectionType} from '@swimlane/ngx-datatable';
|
import {DatatableComponent, ColumnMode, SelectionType} from '@swimlane/ngx-datatable';
|
||||||
import {ResourceFhir} from '../../models/fasten/resource_fhir';
|
import {ResourceFhir} from '../../../lib/models/database/resource_fhir';
|
||||||
import {FORMATTERS, getPath, obsValue, attributeXTime} from './utils';
|
import {FORMATTERS, getPath, obsValue, attributeXTime} from './utils';
|
||||||
import {observableToBeFn} from 'rxjs/internal/testing/TestScheduler';
|
|
||||||
import {Router} from '@angular/router';
|
import {Router} from '@angular/router';
|
||||||
|
import {Base64} from '../../../lib/utils/base64';
|
||||||
|
|
||||||
//all Resource list components must implement this Interface
|
//all Resource list components must implement this Interface
|
||||||
export interface ResourceListComponentInterface {
|
export interface ResourceListComponentInterface {
|
||||||
|
@ -61,6 +61,7 @@ export class ListGenericResourceComponent implements OnInit, ResourceListCompone
|
||||||
|
|
||||||
this.rows = this.resourceList.map((resource) => {
|
this.rows = this.resourceList.map((resource) => {
|
||||||
let row = {
|
let row = {
|
||||||
|
_id: resource._id,
|
||||||
source_id: resource.source_id,
|
source_id: resource.source_id,
|
||||||
source_resource_type: resource.source_resource_type,
|
source_resource_type: resource.source_resource_type,
|
||||||
source_resource_id: resource.source_resource_id
|
source_resource_id: resource.source_resource_id
|
||||||
|
@ -68,7 +69,7 @@ export class ListGenericResourceComponent implements OnInit, ResourceListCompone
|
||||||
|
|
||||||
this.columnDefinitions.forEach((defn) => {
|
this.columnDefinitions.forEach((defn) => {
|
||||||
try{
|
try{
|
||||||
let resourceProp = defn.getter(resource.payload)
|
let resourceProp = defn.getter(resource.resource_raw)
|
||||||
let resourceFormatted = defn.format ? FORMATTERS[defn.format](resourceProp) : resourceProp
|
let resourceFormatted = defn.format ? FORMATTERS[defn.format](resourceProp) : resourceProp
|
||||||
row[defn.title.replace(/[^A-Z0-9]/ig, "_")] = resourceFormatted
|
row[defn.title.replace(/[^A-Z0-9]/ig, "_")] = resourceFormatted
|
||||||
}catch (e){
|
}catch (e){
|
||||||
|
@ -79,9 +80,14 @@ export class ListGenericResourceComponent implements OnInit, ResourceListCompone
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The selected object is NOT a ResourceFHIR, its actually a dynamically created row object
|
||||||
|
* created in renderList()
|
||||||
|
* @param selected
|
||||||
|
*/
|
||||||
onSelect({ selected }) {
|
onSelect({ selected }) {
|
||||||
console.log('Select Event', selected);
|
console.log('Select Event', selected);
|
||||||
this.router.navigateByUrl(`/source/${selected[0].source_id}/resource/${selected[0].source_resource_id}`);
|
this.router.navigateByUrl(`/resource/${Base64.Encode(selected[0]._id)}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
import {ChangeDetectionStrategy, Component, Input, OnChanges, OnInit, SimpleChanges, Type, ViewChild} from '@angular/core';
|
import {ChangeDetectionStrategy, Component, Input, OnChanges, OnInit, SimpleChanges, Type, ViewChild} from '@angular/core';
|
||||||
import {FastenApiService} from '../../services/fasten-api.service';
|
import {FastenDbService} from '../../services/fasten-db.service';
|
||||||
import {Source} from '../../models/fasten/source';
|
import {Source} from '../../../lib/models/database/source';
|
||||||
import {Observable, of} from 'rxjs';
|
import {Observable, of} from 'rxjs';
|
||||||
import {ResourceFhir} from '../../models/fasten/resource_fhir';
|
import {ResourceFhir} from '../../../lib/models/database/resource_fhir';
|
||||||
import {ListAdverseEventComponent} from '../list-generic-resource/list-adverse-event.component';
|
import {ListAdverseEventComponent} from '../list-generic-resource/list-adverse-event.component';
|
||||||
import {ListCommunicationComponent} from '../list-generic-resource/list-communication.component';
|
import {ListCommunicationComponent} from '../list-generic-resource/list-communication.component';
|
||||||
import {ListConditionComponent} from '../list-generic-resource/list-condition.component';
|
import {ListConditionComponent} from '../list-generic-resource/list-condition.component';
|
||||||
|
@ -49,7 +49,7 @@ export class ResourceListComponent implements OnInit, OnChanges {
|
||||||
@ViewChild(ResourceListOutletDirective, {static: true}) resourceListOutlet!: ResourceListOutletDirective;
|
@ViewChild(ResourceListOutletDirective, {static: true}) resourceListOutlet!: ResourceListOutletDirective;
|
||||||
|
|
||||||
|
|
||||||
constructor(private fastenApi: FastenApiService) { }
|
constructor(private fastenDb: FastenDbService) { }
|
||||||
|
|
||||||
ngOnInit(): void {
|
ngOnInit(): void {
|
||||||
this.loadComponent()
|
this.loadComponent()
|
||||||
|
@ -63,7 +63,7 @@ export class ResourceListComponent implements OnInit, OnChanges {
|
||||||
const viewContainerRef = this.resourceListOutlet.viewContainerRef;
|
const viewContainerRef = this.resourceListOutlet.viewContainerRef;
|
||||||
viewContainerRef.clear();
|
viewContainerRef.clear();
|
||||||
|
|
||||||
this.getResources().subscribe((resourceList) => {
|
this.getResources().then((resourceList) => {
|
||||||
let componentType = this.typeLookup(this.resourceListType)
|
let componentType = this.typeLookup(this.resourceListType)
|
||||||
if(componentType != null){
|
if(componentType != null){
|
||||||
console.log("Attempting to create component", this.resourceListType, componentType)
|
console.log("Attempting to create component", this.resourceListType, componentType)
|
||||||
|
@ -75,18 +75,19 @@ export class ResourceListComponent implements OnInit, OnChanges {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
getResources(): Observable<ResourceFhir[]>{
|
getResources(): Promise<ResourceFhir[]>{
|
||||||
|
|
||||||
if(this.resourceListType && !this.resourceListCache[this.resourceListType]){
|
if(this.resourceListType && !this.resourceListCache[this.resourceListType]){
|
||||||
// this resource type list has not been downloaded yet, do so now
|
// this resource type list has not been downloaded yet, do so now
|
||||||
return this.fastenApi.getResources(this.resourceListType, this.source.id)
|
return this.fastenDb.GetResourcesForSource(this.source._id, this.resourceListType)
|
||||||
.pipe(map((resourceList: ResourceFhir[]) => {
|
.then((paginatedResponse) => {
|
||||||
|
let resourceList = paginatedResponse.rows as ResourceFhir[]
|
||||||
//cache this response so we can skip the request next time
|
//cache this response so we can skip the request next time
|
||||||
this.resourceListCache[this.resourceListType] = resourceList
|
this.resourceListCache[this.resourceListType] = resourceList
|
||||||
return resourceList
|
return resourceList
|
||||||
}))
|
})
|
||||||
} else {
|
} else {
|
||||||
return of(this.resourceListCache[this.resourceListType] || [])
|
return Promise.resolve(this.resourceListCache[this.resourceListType] || [])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -3,11 +3,11 @@
|
||||||
<div class="az-content-body">
|
<div class="az-content-body">
|
||||||
<div class="az-content-breadcrumb">
|
<div class="az-content-breadcrumb">
|
||||||
<span>Resource</span>
|
<span>Resource</span>
|
||||||
<span>{{resource.source_resource_type}}</span>
|
<span>{{resource?.source_resource_type}}</span>
|
||||||
<span>{{resource.source_resource_id}}</span>
|
<span>{{resource?.source_resource_id}}</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<pre *ngIf="resource"><code [highlight]="resource.payload | json"></code></pre>
|
<pre *ngIf="resource"><code [highlight]="resource.resource_raw | json"></code></pre>
|
||||||
|
|
||||||
</div><!-- az-content-body -->
|
</div><!-- az-content-body -->
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
import { Component, OnInit } from '@angular/core';
|
import { Component, OnInit } from '@angular/core';
|
||||||
import {FastenApiService} from '../../services/fasten-api.service';
|
import {FastenDbService} from '../../services/fasten-db.service';
|
||||||
import {ActivatedRoute, Router} from '@angular/router';
|
import {ActivatedRoute, Router} from '@angular/router';
|
||||||
import {Source} from '../../models/fasten/source';
|
import {ResourceFhir} from '../../../lib/models/database/resource_fhir';
|
||||||
import {ResourceFhir} from '../../models/fasten/resource_fhir';
|
import {Base64} from '../../../lib/utils/base64';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-resource-detail',
|
selector: 'app-resource-detail',
|
||||||
|
@ -13,12 +13,13 @@ export class ResourceDetailComponent implements OnInit {
|
||||||
|
|
||||||
resource: ResourceFhir = null
|
resource: ResourceFhir = null
|
||||||
|
|
||||||
constructor(private fastenApi: FastenApiService, private router: Router, private route: ActivatedRoute) {
|
constructor(private fastenDb: FastenDbService, private router: Router, private route: ActivatedRoute) {
|
||||||
}
|
}
|
||||||
|
|
||||||
ngOnInit(): void {
|
ngOnInit(): void {
|
||||||
//always request the resource by id
|
//always request the resource by id
|
||||||
this.fastenApi.getResourceBySourceId(this.route.snapshot.paramMap.get('source_id'), this.route.snapshot.paramMap.get('resource_id')).subscribe((resourceFhir) => {
|
this.fastenDb.GetResource(Base64.Decode(this.route.snapshot.paramMap.get('resource_id')))
|
||||||
|
.then((resourceFhir) => {
|
||||||
this.resource = resourceFhir;
|
this.resource = resourceFhir;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -45,7 +45,7 @@ export class SourceDetailComponent implements OnInit {
|
||||||
//functions to call on patient
|
//functions to call on patient
|
||||||
getPatientName(){
|
getPatientName(){
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
return `${getPath(this.selectedPatient?.payload, 'name.0.family')}, ${getPath(this.selectedPatient?.payload, 'name.0.given').join(' ')}`
|
return `${getPath(this.selectedPatient?.resource_raw, 'name.0.family')}, ${getPath(this.selectedPatient?.resource_raw, 'name.0.given').join(' ')}`
|
||||||
}
|
}
|
||||||
getPatientGender(){
|
getPatientGender(){
|
||||||
return getPath(this.selectedPatient?.resource_raw, 'gender')
|
return getPath(this.selectedPatient?.resource_raw, 'gender')
|
||||||
|
|
|
@ -42,4 +42,5 @@ export interface IDatabaseRepository {
|
||||||
CreateResources(resources: ResourceFhir[]): Promise<string[]>
|
CreateResources(resources: ResourceFhir[]): Promise<string[]>
|
||||||
GetResource(resource_id: string): Promise<ResourceFhir>
|
GetResource(resource_id: string): Promise<ResourceFhir>
|
||||||
GetResources(): Promise<IDatabasePaginatedResponse>
|
GetResources(): Promise<IDatabasePaginatedResponse>
|
||||||
|
GetResourcesForSource(source_id: string, source_resource_type?: string): Promise<IDatabasePaginatedResponse>
|
||||||
}
|
}
|
||||||
|
|
|
@ -183,6 +183,23 @@ export class PouchdbRepository implements IDatabaseRepository {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async GetResourcesForSource(source_id: string, source_resource_type?: string): Promise<IDatabasePaginatedResponse> {
|
||||||
|
let prefix = `${DocType.ResourceFhir}:${Base64.Encode(source_id)}`
|
||||||
|
if(source_resource_type){
|
||||||
|
prefix += `:${source_resource_type}`
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.findDocumentByPrefix(prefix, true)
|
||||||
|
.then((docWrapper) => {
|
||||||
|
|
||||||
|
docWrapper.rows = docWrapper.rows.map((result) => {
|
||||||
|
return new ResourceFhir(result.doc)
|
||||||
|
})
|
||||||
|
return docWrapper
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////////////
|
||||||
// CRUD Operators
|
// CRUD Operators
|
||||||
|
|
Loading…
Reference in New Issue