UI Tweaks (#32)

This commit is contained in:
Jason Kulatunga 2023-01-15 10:25:46 -08:00 committed by GitHub
parent f903c38b55
commit cdf7f83777
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
117 changed files with 2162 additions and 128 deletions

8
.idea/.gitignore vendored Normal file
View File

@ -0,0 +1,8 @@
# Default ignored files
/shelf/
/workspace.xml
# Editor-based HTTP Client requests
/httpRequests/
# Datasource local storage ignored files
/dataSources/
/dataSources.local.xml

12
.idea/dataSources.xml Normal file
View File

@ -0,0 +1,12 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="DataSourceManagerImpl" format="xml" multifile-model="true">
<data-source source="LOCAL" name="fasten.db" uuid="8889ce31-829e-4f3a-9c2d-1121804f3f42">
<driver-ref>sqlite.xerial</driver-ref>
<synchronize>true</synchronize>
<jdbc-driver>org.sqlite.JDBC</jdbc-driver>
<jdbc-url>jdbc:sqlite:$PROJECT_DIR$/fasten.db</jdbc-url>
<working-dir>$ProjectFileDir$</working-dir>
</data-source>
</component>
</project>

10
.idea/fasten-onprem.iml Normal file
View File

@ -0,0 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="JAVA_MODULE" version="4">
<component name="Go" enabled="true" />
<component name="NewModuleRootManager" inherit-compiler-output="true">
<exclude-output />
<content url="file://$MODULE_DIR$" />
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
</component>
</module>

View File

@ -0,0 +1,6 @@
<component name="InspectionProjectProfileManager">
<profile version="1.0">
<option name="myName" value="Project Default" />
<inspection_tool class="TsLint" enabled="true" level="WARNING" enabled_by_default="true" />
</profile>
</component>

6
.idea/misc.xml Normal file
View File

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectRootManager">
<output url="file://$PROJECT_DIR$/out" />
</component>
</project>

8
.idea/modules.xml Normal file
View File

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectModuleManager">
<modules>
<module fileurl="file://$PROJECT_DIR$/.idea/fasten-onprem.iml" filepath="$PROJECT_DIR$/.idea/fasten-onprem.iml" />
</modules>
</component>
</project>

6
.idea/vcs.xml Normal file
View File

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="" vcs="Git" />
</component>
</project>

View File

@ -79,6 +79,7 @@ Next we'll start the processes described above:
# In terminal #1, run the following # In terminal #1, run the following
cd frontend cd frontend
yarn dist -- -c [sandbox|prod] yarn dist -- -c [sandbox|prod]
# eg. yarn dist -- -c prod
# In terminal #2, run the following # In terminal #2, run the following
go mod vendor go mod vendor

View File

@ -3,3 +3,7 @@
- [x] references/links - [x] references/links
- [x] manual sync - [x] manual sync
- fix sources where refresh token is missing (panics) - fix sources where refresh token is missing (panics)
- [ ] Billing Report
- [ ] Contacts/Address Book Report
- [ ] Dashboard Plugins
- [ ]

View File

@ -762,9 +762,6 @@ func (sr *SqliteRepository) AddResourceComposition(ctx context.Context, composit
SourceResourceType: pkg.FhirResourceTypeComposition, SourceResourceType: pkg.FhirResourceTypeComposition,
SourceResourceID: uuid.New().String(), SourceResourceID: uuid.New().String(),
}, },
SortDate: nil, //TOOD: figoure out the sortDate by looking for the earliest sort date for all nested resources
SortTitle: &compositionTitle,
RelatedResourceFhir: resources,
} }
} }
@ -790,6 +787,10 @@ func (sr *SqliteRepository) AddResourceComposition(ctx context.Context, composit
} }
compositionResource.ResourceRaw = rawResourceJson compositionResource.ResourceRaw = rawResourceJson
compositionResource.SortTitle = &compositionTitle
compositionResource.RelatedResourceFhir = utils.SortResourcePtrListByDate(resources)
compositionResource.SortDate = compositionResource.RelatedResourceFhir[0].SortDate
//store the Composition resource //store the Composition resource
_, err = sr.UpsertResource(ctx, compositionResource) _, err = sr.UpsertResource(ctx, compositionResource)
if err != nil { if err != nil {

View File

@ -0,0 +1 @@
<span class="badge float-right" [class]="getBadgeStatusColor(status)">{{status}}</span>

View File

@ -0,0 +1,23 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { BadgeComponent } from './badge.component';
describe('BadgeComponent', () => {
let component: BadgeComponent;
let fixture: ComponentFixture<BadgeComponent>;
beforeEach(async () => {
await TestBed.configureTestingModule({
declarations: [ BadgeComponent ]
})
.compileComponents();
fixture = TestBed.createComponent(BadgeComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});

View File

@ -0,0 +1,117 @@
import {Component, Input, OnInit} from '@angular/core';
@Component({
selector: 'fhir-ui-badge',
templateUrl: './badge.component.html',
styleUrls: ['./badge.component.scss']
})
export class BadgeComponent implements OnInit {
@Input() status: string = ""
constructor() { }
ngOnInit(): void {
}
getBadgeStatusColor(status): string {
let lookup = {
// condition
active: 'badge-primary',
recurrence: '',
relapse: 'badge-info',
inactive: 'badge-secondary',
remission: 'badge-info',
resolved: 'badge-primary',
// immunization
'in-progress': 'badge-warning',
'on-hold': 'badge-secondary',
completed: 'badge-success',
'entered-in-error': 'badge-error',
stopped: 'badge-secondary',
'not-done': 'badge-warning',
// procedure
preparation: 'badge-primary',
suspended: '',
aborted: '',
unknown: 'badge-secondary',
// practitioner
// allergy intolerance
unconfirmed: '',
confirmed: '',
refuted: '',
// appointment
proposed: '',
pending: '',
booked: '',
arrived: '',
fulfilled: '',
cancelled: '',
noshow: '',
'checked-in': '',
waitlist: '',
// care plan
draft: '',
revoked: '',
// care team
// claim
// claim response
// device
available: '',
'not-available': '',
// diagnostic report
registered: '',
partial: '',
preliminary: '',
final: '',
corrected: '',
appended: '',
// document reference
current: '',
superseded: '',
// encounter
planned: '',
triaged: '',
onleave: '',
finished: '',
// explanation of benefit
// family member history
'health-unknown': '',
// goal
accepted: '',
rejected: '',
achieved: '',
sustaining: '',
'on-target': '',
'ahead-of-target': '',
'behind-target': '',
// list
retired: '',
// location
// mediacation
brand: '',
// medication administration
// medication knowledge
// medication statement
intended: '',
'not-taken': '',
// observation
amended: '',
// procedure
// questionnaire
published: '',
// questionnaire response
// research study
'administratively-completed': '',
approved: '',
'closed-to-accrual': '',
'closed-to-accrual-and-intervention': '',
disapproved: '',
'in-review': '',
'temporarily-closed-to-accrual': '',
'temporarily-closed-to-accrual-and-intervention': '',
withdrawn: '',
};
return lookup[status] || 'badge-secondary'
}
}

View File

@ -0,0 +1,7 @@
import { TableRowItem } from './table-row-item';
describe('TableRowItem', () => {
it('should create an instance', () => {
expect(new TableRowItem()).toBeTruthy();
});
});

View File

@ -0,0 +1,16 @@
import {ReferenceModel} from '../../../../../lib/models/datatypes/reference-model';
import {CodingModel} from '../../../../../lib/models/datatypes/coding-model';
export class TableRowItem {
label?: string
data?: string | ReferenceModel | CodingModel | CodingModel[]
data_type?: TableRowItemDataType
enabled?: boolean //determine if this row should be displayed
}
export enum TableRowItemDataType {
String = "string",
Reference = "reference",
Coding = "coding",
CodingList = "codingList"
}

View File

@ -0,0 +1,30 @@
<div class="table-responsive">
<table class="table">
<tbody>
<tr *ngFor="let rowItem of tableData">
<td>
<strong>{{rowItem.label}}</strong>
</td>
<td>
<ng-container [ngTemplateOutlet]="rowItem.data_type == 'reference' ? dataTypeReference :
rowItem.data_type == 'coding'? dataTypeCoding :
rowItem.data_type == 'codingList'? dataTypeCodingList :
dataTypeString"></ng-container>
<ng-template #dataTypeCoding>
<fhir-coding [coding]="rowItem.data"></fhir-coding>
</ng-template>
<ng-template #dataTypeCodingList>
<fhir-coding *ngFor="let coding of rowItem.data" [coding]="coding"></fhir-coding>
</ng-template>
<ng-template #dataTypeReference>
<a routerLink="/source/{{displayModel.source_id}}/resource/{{rowItem.data.reference}}">{{rowItem.data.display}}</a>
</ng-template>
<ng-template #dataTypeString>{{rowItem.data}}</ng-template>
</td>
</tr>
</tbody>
</table>
</div><!-- table-responsive -->

View File

@ -0,0 +1,23 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { TableComponent } from './table.component';
describe('TableComponent', () => {
let component: TableComponent;
let fixture: ComponentFixture<TableComponent>;
beforeEach(async () => {
await TestBed.configureTestingModule({
declarations: [ TableComponent ]
})
.compileComponents();
fixture = TestBed.createComponent(TableComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});

View File

@ -0,0 +1,21 @@
import {Component, Input, OnInit} from '@angular/core';
import {TableRowItem} from './table-row-item';
import {BinaryModel} from '../../../../../lib/models/resources/binary-model';
import {FastenDisplayModel} from '../../../../../lib/models/fasten/fasten-display-model';
@Component({
selector: 'fhir-ui-table',
templateUrl: './table.component.html',
styleUrls: ['./table.component.scss']
})
export class TableComponent implements OnInit {
@Input() tableData: TableRowItem[] = []
@Input() displayModel: FastenDisplayModel
constructor() { }
ngOnInit(): void {
this.tableData = this.tableData.filter((item) => {return item.enabled})
}
}

View File

@ -0,0 +1,3 @@
<div>
<pre>{{displayModel.content}}</pre>
</div>

View File

@ -0,0 +1,23 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { BinaryTextComponent } from './binary-text.component';
describe('BinaryTextComponent', () => {
let component: BinaryTextComponent;
let fixture: ComponentFixture<BinaryTextComponent>;
beforeEach(async () => {
await TestBed.configureTestingModule({
declarations: [ BinaryTextComponent ]
})
.compileComponents();
fixture = TestBed.createComponent(BinaryTextComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});

View File

@ -0,0 +1,17 @@
import {Component, Input, OnInit} from '@angular/core';
import {BinaryModel} from '../../../../../lib/models/resources/binary-model';
@Component({
selector: 'fhir-binary-text',
templateUrl: './binary-text.component.html',
styleUrls: ['./binary-text.component.scss']
})
export class BinaryTextComponent implements OnInit {
@Input() displayModel: BinaryModel
constructor() { }
ngOnInit(): void {
}
}

View File

@ -0,0 +1,6 @@
<div>
<span>{{coding.display}}</span>
<span *ngIf="has_additional_info" [title]="coding.system">
({{coding.code || '?'}})
</span>
</div>

View File

@ -0,0 +1,23 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { CodingComponent } from './coding.component';
describe('CodingComponent', () => {
let component: CodingComponent;
let fixture: ComponentFixture<CodingComponent>;
beforeEach(async () => {
await TestBed.configureTestingModule({
declarations: [ CodingComponent ]
})
.compileComponents();
fixture = TestBed.createComponent(CodingComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});

View File

@ -0,0 +1,19 @@
import {Component, Input, OnInit} from '@angular/core';
import {CodingModel} from '../../../../../lib/models/datatypes/coding-model';
@Component({
selector: 'fhir-coding',
templateUrl: './coding.component.html',
styleUrls: ['./coding.component.scss']
})
export class CodingComponent implements OnInit {
@Input() coding: CodingModel
has_additional_info: boolean = false
constructor() { }
ngOnInit(): void {
this.has_additional_info = !!(this.coding.code || this.coding.system)
}
}

View File

@ -0,0 +1,3 @@
<p>html works!</p>
<div [innerHTML]="contentMarkup"></div>

View File

@ -0,0 +1,23 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { HtmlComponent } from './html.component';
describe('HtmlComponent', () => {
let component: HtmlComponent;
let fixture: ComponentFixture<HtmlComponent>;
beforeEach(async () => {
await TestBed.configureTestingModule({
declarations: [ HtmlComponent ]
})
.compileComponents();
fixture = TestBed.createComponent(HtmlComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});

View File

@ -0,0 +1,20 @@
import {Component, Input, OnInit} from '@angular/core';
import {BinaryModel} from '../../../../../lib/models/resources/binary-model';
import {DomSanitizer, SafeHtml} from '@angular/platform-browser';
@Component({
selector: 'fhir-html',
templateUrl: './html.component.html',
styleUrls: ['./html.component.scss']
})
export class HtmlComponent implements OnInit {
@Input() displayModel: BinaryModel
contentMarkup:SafeHtml;
constructor(private sanitized: DomSanitizer) { }
ngOnInit(): void {
this.contentMarkup = this.sanitized.bypassSecurityTrustHtml(this.displayModel.content);
}
}

View File

@ -0,0 +1,3 @@
<div>
<img src="data:${{displayModel.content_type}};base64,${{displayModel.data}}" alt=""/>
</div>

View File

@ -0,0 +1,23 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { ImgComponent } from './img.component';
describe('ImgComponent', () => {
let component: ImgComponent;
let fixture: ComponentFixture<ImgComponent>;
beforeEach(async () => {
await TestBed.configureTestingModule({
declarations: [ ImgComponent ]
})
.compileComponents();
fixture = TestBed.createComponent(ImgComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});

View File

@ -0,0 +1,17 @@
import {Component, Input, OnInit} from '@angular/core';
import {BinaryModel} from '../../../../../lib/models/resources/binary-model';
@Component({
selector: 'fhir-img',
templateUrl: './img.component.html',
styleUrls: ['./img.component.scss']
})
export class ImgComponent implements OnInit {
@Input() displayModel: BinaryModel
constructor() { }
ngOnInit(): void {
}
}

View File

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

View File

@ -0,0 +1,23 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { MarkdownComponent } from './markdown.component';
describe('MarkdownComponent', () => {
let component: MarkdownComponent;
let fixture: ComponentFixture<MarkdownComponent>;
beforeEach(async () => {
await TestBed.configureTestingModule({
declarations: [ MarkdownComponent ]
})
.compileComponents();
fixture = TestBed.createComponent(MarkdownComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});

View File

@ -0,0 +1,17 @@
import {Component, Input, OnInit} from '@angular/core';
import {BinaryModel} from '../../../../../lib/models/resources/binary-model';
@Component({
selector: 'fhir-markdown',
templateUrl: './markdown.component.html',
styleUrls: ['./markdown.component.scss']
})
export class MarkdownComponent implements OnInit {
@Input() displayModel: BinaryModel
constructor() { }
ngOnInit(): void {
}
}

View File

@ -0,0 +1,10 @@
<div>
<embed
src="data:${{displayModel.content_type}};base64,${{displayModel.data}}"
type="${{displayModel.content_type}}"
[style]="{
width: '100%',
height: height
}"
/>
</div>

View File

@ -0,0 +1,23 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { PdfComponent } from './pdf.component';
describe('PdfComponent', () => {
let component: PdfComponent;
let fixture: ComponentFixture<PdfComponent>;
beforeEach(async () => {
await TestBed.configureTestingModule({
declarations: [ PdfComponent ]
})
.compileComponents();
fixture = TestBed.createComponent(PdfComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});

View File

@ -0,0 +1,21 @@
import {Component, Input, OnInit} from '@angular/core';
import {BinaryModel} from '../../../../../lib/models/resources/binary-model';
@Component({
selector: 'fhir-pdf',
templateUrl: './pdf.component.html',
styleUrls: ['./pdf.component.scss']
})
export class PdfComponent implements OnInit {
@Input() displayModel: BinaryModel
height: number
constructor() { }
ngOnInit(): void {
const maxHeight = 600;
const contentHeight = (1111 * this.displayModel.data.length) / (24996 / 7.5);
this.height = Math.min(maxHeight, contentHeight);
}
}

View File

@ -0,0 +1,8 @@
import {FastenDisplayModel} from '../../../../lib/models/fasten/fasten-display-model';
//all Fhir Resource components must implement this Interface
export interface FhirResourceComponentInterface {
displayModel: FastenDisplayModel;
showDetails: boolean;
markForCheck()
}

View File

@ -0,0 +1,8 @@
import { FhirResourceOutletDirective } from './fhir-resource-outlet.directive';
describe('FhirResourceOutletDirective', () => {
it('should create an instance', () => {
const directive = new FhirResourceOutletDirective();
expect(directive).toBeTruthy();
});
});

View File

@ -0,0 +1,10 @@
import {Directive, ViewContainerRef} from '@angular/core';
@Directive({
selector: '[fhirResourceOutlet]'
})
export class FhirResourceOutletDirective {
constructor(public viewContainerRef: ViewContainerRef) { }
}

View File

@ -0,0 +1 @@
<ng-template fhirResourceOutlet></ng-template>

View File

@ -0,0 +1,23 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { FhirResourceComponent } from './fhir-resource.component';
describe('FhirResourceComponent', () => {
let component: FhirResourceComponent;
let fixture: ComponentFixture<FhirResourceComponent>;
beforeEach(async () => {
await TestBed.configureTestingModule({
declarations: [ FhirResourceComponent ]
})
.compileComponents();
fixture = TestBed.createComponent(FhirResourceComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});

View File

@ -0,0 +1,154 @@
import {
ChangeDetectionStrategy,
Component,
Input,
OnChanges,
OnInit,
SimpleChanges,
Type,
ViewChild
} from '@angular/core';
import {BinaryModel} from '../../../../lib/models/resources/binary-model';
import {FhirResourceOutletDirective} from './fhir-resource-outlet.directive';
import {ResourceType} from '../../../../lib/models/constants';
import {FallbackComponent} from '../resources/fallback/fallback.component';
import {BinaryComponent} from '../resources/binary/binary.component';
import {FhirResourceComponentInterface} from './fhir-resource-component-interface';
import {ImmunizationComponent} from '../resources/immunization/immunization.component';
import {AllergyIntoleranceComponent} from '../resources/allergy-intolerance/allergy-intolerance.component';
import {MedicationComponent} from '../resources/medication/medication.component';
import {MedicationRequestComponent} from '../resources/medication-request/medication-request.component';
import {FastenDisplayModel} from '../../../../lib/models/fasten/fasten-display-model';
import {ProcedureComponent} from '../resources/procedure/procedure.component';
import {DiagnosticReportComponent} from '../resources/diagnostic-report/diagnostic-report.component';
import {PractitionerComponent} from '../resources/practitioner/practitioner.component';
@Component({
selector: 'fhir-resource',
changeDetection: ChangeDetectionStrategy.OnPush,
templateUrl: './fhir-resource.component.html',
styleUrls: ['./fhir-resource.component.scss']
})
export class FhirResourceComponent implements OnInit, OnChanges {
@Input() displayModel: FastenDisplayModel
@Input() showDetails: boolean = true
//location to dynamically load the displayModel
@ViewChild(FhirResourceOutletDirective, {static: true}) fhirResourceOutlet!: FhirResourceOutletDirective;
constructor() { }
ngOnInit(): void {
this.loadComponent()
}
ngOnChanges(changes: SimpleChanges) {
this.loadComponent()
}
loadComponent() {
//clear the current outlet
const viewContainerRef = this.fhirResourceOutlet.viewContainerRef;
viewContainerRef.clear();
let componentType = this.typeLookup(this.displayModel.source_resource_type)
if(componentType != null){
console.log("Attempting to create fhir display component", this.displayModel, componentType)
const componentRef = viewContainerRef.createComponent<FhirResourceComponentInterface>(componentType);
componentRef.instance.displayModel = this.displayModel;
componentRef.instance.showDetails = this.showDetails;
componentRef.instance.markForCheck()
}
}
typeLookup(resourceType: ResourceType): Type<FhirResourceComponentInterface> {
if(!resourceType){
//dont try to render anything if the resourceType isnt set.
return null
}
switch(resourceType) {
// case "Appointment": {
// return ListAppointmentComponent;
// }
case "AllergyIntolerance": {
return AllergyIntoleranceComponent;
}
// case "AdverseEvent": {
// return ListAdverseEventComponent;
// }
case "Binary": {
return BinaryComponent;
}
// case "CarePlan": {
// return ListCarePlanComponent;
// }
// case "Communication": {
// return ListCommunicationComponent;
// }
// case "Condition": {
// return ListConditionComponent;
// }
// case "Coverage": {
// return ListCoverageComponent;
// }
// case "Device": {
// return ListDeviceComponent;
// }
// case "DeviceRequest": {
// return ListDeviceRequestComponent;
// }
case "DiagnosticReport": {
return DiagnosticReportComponent;
}
// case "DocumentReference": {
// return ListDocumentReferenceComponent;
// }
// case "Encounter": {
// return ListEncounterComponent;
// }
// case "Goal": {
// return ListGoalComponent;
// }
case "Immunization": {
return ImmunizationComponent;
}
case "Medication": {
return MedicationComponent;
}
// case "MedicationAdministration": {
// return ListMedicationAdministrationComponent;
// }
// case "MedicationDispense": {
// return ListMedicationDispenseComponent;
// }
case "MedicationRequest": {
return MedicationRequestComponent;
}
// case "NutritionOrder": {
// return ListNutritionOrderComponent;
// }
// case "Observation": {
// return ListObservationComponent;
// }
case "Procedure": {
return ProcedureComponent;
}
// case "Practitioner": {
// return PractitionerComponent;
// }
// case "ServiceRequest": {
// return ListServiceRequestComponent;
// }
default: {
console.warn("Unknown component type, using fallback", resourceType)
return FallbackComponent;
}
}
}
}

View File

@ -0,0 +1,16 @@
<div class="card card-fhir-resource" >
<div class="card-header" (click)="isCollapsed = ! isCollapsed">
<div>
<h6 class="card-title">{{displayModel.title}}</h6>
<p class="card-text tx-gray-400" *ngIf="displayModel.recorded_date"><strong>Recorded on</strong> {{displayModel.recorded_date | date}}</p>
</div>
<fhir-ui-badge class="float-right" [status]="displayModel.status">{{displayModel.status}}</fhir-ui-badge>
</div>
<div #collapse="ngbCollapse" [(ngbCollapse)]="isCollapsed" class="card-body">
<p class="az-content-text mg-b-20">Risk of harmful or undesirable physiological response which is specific to an individual and associated with exposure to a substance.</p>
<fhir-ui-table [displayModel]="displayModel" [tableData]="tableData"></fhir-ui-table>
</div>
<div *ngIf="showDetails" class="card-footer">
<a class="float-right" routerLink="/source/{{displayModel?.source_id}}/resource/{{displayModel?.source_resource_id}}">details</a>
</div>
</div>

View File

@ -0,0 +1,23 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { AllergyIntoleranceComponent } from './allergy-intolerance.component';
describe('AllergyIntoleranceComponent', () => {
let component: AllergyIntoleranceComponent;
let fixture: ComponentFixture<AllergyIntoleranceComponent>;
beforeEach(async () => {
await TestBed.configureTestingModule({
declarations: [ AllergyIntoleranceComponent ]
})
.compileComponents();
fixture = TestBed.createComponent(AllergyIntoleranceComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});

View File

@ -0,0 +1,83 @@
import {ChangeDetectorRef, Component, Input, OnInit} from '@angular/core';
import {FhirResourceComponentInterface} from '../../fhir-resource/fhir-resource-component-interface';
import {TableRowItem, TableRowItemDataType} from '../../common/table/table-row-item';
import {Router} from '@angular/router';
import {AllergyIntoleranceModel} from '../../../../../lib/models/resources/allergy-intolerance-model';
@Component({
selector: 'fhir-allergy-intolerance',
templateUrl: './allergy-intolerance.component.html',
styleUrls: ['./allergy-intolerance.component.scss']
})
export class AllergyIntoleranceComponent implements OnInit, FhirResourceComponentInterface {
@Input() displayModel: AllergyIntoleranceModel
@Input() showDetails: boolean = true
isCollapsed: boolean = false
tableData: TableRowItem[] = []
constructor(public changeRef: ChangeDetectorRef, public router: Router) {}
ngOnInit(): void {
this.tableData = [
{
label: 'Substance',
data: this.displayModel.substance_coding,
data_type: TableRowItemDataType.CodingList,
enabled: !!this.displayModel.substance_coding,
},
{
label: 'Type',
data: this.displayModel.type,
enabled: !!this.displayModel.type,
},
{
label: 'Category',
data: this.displayModel.category?.join(" "),
enabled: !!this.displayModel.category,
},
{
label: 'Patient',
data: this.displayModel.patient,
data_type: TableRowItemDataType.Reference,
enabled: !!this.displayModel.patient,
},
{
label: 'Asserted by',
data: this.displayModel.asserter,
data_type: TableRowItemDataType.Reference,
enabled: !!this.displayModel.asserter,
},
// {
// label: 'Manifestation',
// testId: 'manifestation',
// data: reaction.map((reaction, i) => {
// const manifestations = _get(reaction, 'manifestation', []);
// const severity = _get(reaction, 'severity');
// return manifestations.map((manifestation, j) => {
// return (
// <div key={`item-${i}${j}`} className="d-flex">
// <CodeableConcept fhirData={manifestation} />
// {severity && (
// <span className="ms-4">
// <BadgeSecondary>{severity}</BadgeSecondary>
// </span>
// )}
// </div>
// );
// });
// }),
// status: hasReaction,
// },
// {
// label: 'Notes',
// data: hasNote && <Annotation fhirData={note} />,
// status: this.displayModel.has_nod,
// }
];
}
markForCheck(){
this.changeRef.markForCheck()
}
}

View File

@ -0,0 +1,23 @@
<ng-container [ngTemplateOutlet]="
displayModel.content_type == 'application/pdf' ? showPdf :
displayModel.content_type == 'image/jpeg' ? showImg :
(displayModel.content_type == 'text/html' || displayModel.content_type == 'application/html') ? showHtml :
(displayModel.content_type == 'application/xml' || displayModel.content_type == 'application/json') ? showText :
showEmpty
"></ng-container>
<ng-template #showPdf>
<fhir-pdf [displayModel]="displayModel"></fhir-pdf>
</ng-template>
<ng-template #showImg>
<fhir-img [displayModel]="displayModel"></fhir-img>
</ng-template>
<ng-template #showHtml>
<fhir-html [displayModel]="displayModel"></fhir-html>
</ng-template>
<ng-template #showText>
<fhir-binary-text [displayModel]="displayModel"></fhir-binary-text>
</ng-template>
<ng-template #showEmpty>
Unknown Binary content type {{displayModel.content_type}}
</ng-template>

View File

@ -0,0 +1,23 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { BinaryComponent } from './binary.component';
describe('BinaryComponent', () => {
let component: BinaryComponent;
let fixture: ComponentFixture<BinaryComponent>;
beforeEach(async () => {
await TestBed.configureTestingModule({
declarations: [ BinaryComponent ]
})
.compileComponents();
fixture = TestBed.createComponent(BinaryComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});

View File

@ -0,0 +1,23 @@
import {ChangeDetectorRef, Component, Input, OnInit} from '@angular/core';
import {BinaryModel} from '../../../../../lib/models/resources/binary-model';
import {FhirResourceComponentInterface} from '../../fhir-resource/fhir-resource-component-interface';
import {Router} from '@angular/router';
@Component({
selector: 'fhir-binary',
templateUrl: './binary.component.html',
styleUrls: ['./binary.component.scss']
})
export class BinaryComponent implements OnInit, FhirResourceComponentInterface {
@Input() displayModel: BinaryModel
@Input() showDetails: boolean = true
constructor(public changeRef: ChangeDetectorRef, public router: Router) {}
ngOnInit(): void {
}
markForCheck(){
this.changeRef.markForCheck()
}
}

View File

@ -0,0 +1,21 @@
<div class="card card-fhir-resource" >
<div class="card-header" (click)="isCollapsed = ! isCollapsed">
<div>
<h6 class="card-title">{{displayModel.title}}</h6>
<p class="card-text tx-gray-400" *ngIf="displayModel.effective_datetime"><strong>Start date</strong> {{displayModel.effective_datetime | date}}</p>
</div>
<fhir-ui-badge class="float-right" [status]="displayModel.status">{{displayModel.status}}</fhir-ui-badge>
<!-- <div class="btn-group">-->
<!-- <button class="btn active">Day</button>-->
<!-- <button class="btn">Week</button>-->
<!-- <button class="btn">Month</button>-->
<!-- </div>-->
</div>
<div #collapse="ngbCollapse" [(ngbCollapse)]="isCollapsed" class="card-body">
<p class="az-content-text mg-b-20">An action that is or was performed on or for a patient, practitioner, device, organization, or location. For example, this can be a physical intervention on a patient like an operation, or less invasive like long term services, counseling, or hypnotherapy.</p>
<fhir-ui-table [displayModel]="displayModel" [tableData]="tableData"></fhir-ui-table>
</div>
<div *ngIf="showDetails" class="card-footer">
<a class="float-right" routerLink="/source/{{displayModel?.source_id}}/resource/{{displayModel?.source_resource_id}}">details</a>
</div>
</div>

View File

@ -0,0 +1,23 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { DiagnosticReportComponent } from './diagnostic-report.component';
describe('DiagnosticReportComponent', () => {
let component: DiagnosticReportComponent;
let fixture: ComponentFixture<DiagnosticReportComponent>;
beforeEach(async () => {
await TestBed.configureTestingModule({
declarations: [ DiagnosticReportComponent ]
})
.compileComponents();
fixture = TestBed.createComponent(DiagnosticReportComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});

View File

@ -0,0 +1,50 @@
import {ChangeDetectorRef, Component, Input, OnInit} from '@angular/core';
import {FhirResourceComponentInterface} from '../../fhir-resource/fhir-resource-component-interface';
import {TableRowItem, TableRowItemDataType} from '../../common/table/table-row-item';
import {Router} from '@angular/router';
import {DiagnosticReportModel} from '../../../../../lib/models/resources/diagnostic-report-model';
@Component({
selector: 'app-diagnostic-report',
templateUrl: './diagnostic-report.component.html',
styleUrls: ['./diagnostic-report.component.scss']
})
export class DiagnosticReportComponent implements OnInit, FhirResourceComponentInterface {
@Input() displayModel: DiagnosticReportModel
@Input() showDetails: boolean = true
isCollapsed: boolean = false
tableData: TableRowItem[] = []
constructor(public changeRef: ChangeDetectorRef, public router: Router) {}
ngOnInit(): void {
this.tableData = [
{
label: 'Issued',
data: this.displayModel.issued,
enabled: !!this.displayModel.issued,
},
{
label: 'Category',
data: this.displayModel.category_coding,
data_type: TableRowItemDataType.CodingList,
enabled: this.displayModel.has_category_coding,
},
{
label: 'Performer',
data: this.displayModel.performer,
data_type: TableRowItemDataType.Reference,
enabled: this.displayModel.has_performer,
},
{
label: 'Conclusion',
data: this.displayModel.conclusion,
enabled: !!this.displayModel.conclusion,
},
];
}
markForCheck(){
this.changeRef.markForCheck()
}
}

View File

@ -0,0 +1,2 @@
<strong>fallback</strong>
<pre><code [highlight]="displayModel | json"></code></pre>

View File

@ -0,0 +1,23 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { FallbackComponent } from './fallback.component';
describe('FallbackComponent', () => {
let component: FallbackComponent;
let fixture: ComponentFixture<FallbackComponent>;
beforeEach(async () => {
await TestBed.configureTestingModule({
declarations: [ FallbackComponent ]
})
.compileComponents();
fixture = TestBed.createComponent(FallbackComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});

View File

@ -0,0 +1,23 @@
import {ChangeDetectorRef, Component, Input, OnInit} from '@angular/core';
import {BinaryModel} from '../../../../../lib/models/resources/binary-model';
import {Router} from '@angular/router';
import {FhirResourceComponentInterface} from '../../fhir-resource/fhir-resource-component-interface';
@Component({
selector: 'fhir-fallback',
templateUrl: './fallback.component.html',
styleUrls: ['./fallback.component.scss']
})
export class FallbackComponent implements OnInit, FhirResourceComponentInterface {
@Input() displayModel: BinaryModel
@Input() showDetails: boolean = true
constructor(public changeRef: ChangeDetectorRef, public router: Router) {}
ngOnInit(): void {
}
markForCheck(){
this.changeRef.markForCheck()
}
}

View File

@ -0,0 +1,21 @@
<div class="card card-fhir-resource" >
<div class="card-header" (click)="isCollapsed = ! isCollapsed">
<div>
<h6 class="card-title">{{displayModel.title}}</h6>
<p class="card-text tx-gray-400" *ngIf="displayModel.sort_date"><strong>Start date</strong> {{displayModel.sort_date | date}}</p>
</div>
<fhir-ui-badge class="float-right" [status]="displayModel.status">{{displayModel.status}}</fhir-ui-badge>
<!-- <div class="btn-group">-->
<!-- <button class="btn active">Day</button>-->
<!-- <button class="btn">Week</button>-->
<!-- <button class="btn">Month</button>-->
<!-- </div>-->
</div>
<div #collapse="ngbCollapse" [(ngbCollapse)]="isCollapsed" class="card-body">
<p class="az-content-text mg-b-20">Describes the event of a patient being administered a vaccine or a record of an immunization as reported by a patient, a clinician or another party.</p>
<fhir-ui-table [displayModel]="displayModel" [tableData]="tableData"></fhir-ui-table>
</div>
<div *ngIf="showDetails" class="card-footer">
<a class="float-right" routerLink="/source/{{displayModel?.source_id}}/resource/{{displayModel?.source_resource_id}}">details</a>
</div>
</div>

View File

@ -0,0 +1,23 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { ImmunizationComponent } from './immunization.component';
describe('ImmunizationComponent', () => {
let component: ImmunizationComponent;
let fixture: ComponentFixture<ImmunizationComponent>;
beforeEach(async () => {
await TestBed.configureTestingModule({
declarations: [ ImmunizationComponent ]
})
.compileComponents();
fixture = TestBed.createComponent(ImmunizationComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});

View File

@ -0,0 +1,91 @@
import {ChangeDetectorRef, Component, Input, OnInit} from '@angular/core';
import {FhirResourceComponentInterface} from '../../fhir-resource/fhir-resource-component-interface';
import {Router} from '@angular/router';
import {ImmunizationModel} from '../../../../../lib/models/resources/immunization-model';
import {TableRowItem, TableRowItemDataType} from '../../common/table/table-row-item';
import * as _ from "lodash";
@Component({
selector: 'fhir-immunization',
templateUrl: './immunization.component.html',
styleUrls: ['./immunization.component.scss']
})
export class ImmunizationComponent implements OnInit, FhirResourceComponentInterface {
@Input() displayModel: ImmunizationModel
@Input() showDetails: boolean = true
isCollapsed: boolean = false
tableData: TableRowItem[] = []
constructor(public changeRef: ChangeDetectorRef, public router: Router) {}
ngOnInit(): void {
this.tableData.push( {
label: 'Manufacturer Text',
data: this.displayModel.manufacturer_text,
enabled: !!this.displayModel.manufacturer_text,
},
{
label: 'Manufacturer Text',
data: `${this.displayModel.lot_number}` + this.displayModel.lot_number_expiration_date ? ` expires on ${this.displayModel.lot_number_expiration_date}` : '',
enabled: this.displayModel.has_lot_number,
},
{
label: 'Dosage',
data:
[
_.get(this.displayModel.dose_quantity, 'value'),
_.get(this.displayModel.dose_quantity, 'unit') || _.get(this.displayModel.dose_quantity, 'code'),
].join(' '),
enabled: this.displayModel.has_dose_quantity,
},
{
label: 'Patient',
data: this.displayModel.patient,
data_type: TableRowItemDataType.Reference,
enabled: !!this.displayModel.patient,
},
{
label: 'Requester',
data: this.displayModel.requester,
data_type: TableRowItemDataType.Reference,
enabled: !!this.displayModel.requester,
},
{
label: 'Performer',
data: this.displayModel.performer,
data_type: TableRowItemDataType.Reference,
enabled: !!this.displayModel.performer,
},
// {
// label: 'Note',
// testId: 'note',
// data: note && <Annotation fhirData={note} />,
// status: note,
// },
{
label: 'Route',
data: this.displayModel.route,
data_type: TableRowItemDataType.CodingList,
enabled: this.displayModel.has_route,
},
{
label: 'Location',
data: this.displayModel.location,
enabled: !!this.displayModel.location,
},
{
label: 'Site',
data: this.displayModel.site,
data_type: TableRowItemDataType.CodingList,
enabled: this.displayModel.has_site,
})
}
markForCheck(){
this.changeRef.markForCheck()
}
}

View File

@ -0,0 +1,21 @@
<div class="card card-fhir-resource" >
<div class="card-header" (click)="isCollapsed = ! isCollapsed">
<div>
<h6 class="card-title">{{displayModel.medication_reference.display}}</h6>
<p class="card-text tx-gray-400" *ngIf="displayModel.sort_date"><strong>Start date</strong> {{displayModel.sort_date | date}}</p>
</div>
<fhir-ui-badge class="float-right" [status]="displayModel.status">{{displayModel.status}}</fhir-ui-badge>
<!-- <div class="btn-group">-->
<!-- <button class="btn active">Day</button>-->
<!-- <button class="btn">Week</button>-->
<!-- <button class="btn">Month</button>-->
<!-- </div>-->
</div>
<div #collapse="ngbCollapse" [(ngbCollapse)]="isCollapsed" class="card-body">
<p class="az-content-text mg-b-20">An order or request for both supply of the medication and the instructions for administration of the medication to a patient.</p>
<fhir-ui-table [displayModel]="displayModel" [tableData]="tableData"></fhir-ui-table>
</div>
<div *ngIf="showDetails" class="card-footer">
<a class="float-right" routerLink="/source/{{displayModel?.source_id}}/resource/{{displayModel?.source_resource_id}}">details</a>
</div>
</div>

View File

@ -0,0 +1,23 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { MedicationRequestComponent } from './medication-request.component';
describe('MedicationRequestComponent', () => {
let component: MedicationRequestComponent;
let fixture: ComponentFixture<MedicationRequestComponent>;
beforeEach(async () => {
await TestBed.configureTestingModule({
declarations: [ MedicationRequestComponent ]
})
.compileComponents();
fixture = TestBed.createComponent(MedicationRequestComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});

View File

@ -0,0 +1,67 @@
import {ChangeDetectorRef, Component, Input, OnInit} from '@angular/core';
import {FhirResourceComponentInterface} from '../../fhir-resource/fhir-resource-component-interface';
import {TableRowItem, TableRowItemDataType} from '../../common/table/table-row-item';
import {Router} from '@angular/router';
import {MedicationRequestModel} from '../../../../../lib/models/resources/medication-request-model';
@Component({
selector: 'fhir-medication-request',
templateUrl: './medication-request.component.html',
styleUrls: ['./medication-request.component.scss']
})
export class MedicationRequestComponent implements OnInit, FhirResourceComponentInterface {
@Input() displayModel: MedicationRequestModel
@Input() showDetails: boolean = true
isCollapsed: boolean = false
tableData: TableRowItem[] = []
constructor(public changeRef: ChangeDetectorRef, public router: Router) {}
ngOnInit(): void {
this.tableData = [
{
label: 'Medication',
data: this.displayModel.medication_codeable_concept,
data_type: TableRowItemDataType.Coding,
enabled: !!this.displayModel.medication_codeable_concept,
},
{
label: 'Requester',
data: this.displayModel.requester,
data_type: TableRowItemDataType.Reference,
enabled: !!this.displayModel.requester,
},
{
label: 'Created',
data: this.displayModel.created,
enabled: !!this.displayModel.created,
},
{
label: 'Type of request',
data: this.displayModel.intent,
enabled: !!this.displayModel.intent,
},
{
label: 'Reason',
data: this.displayModel.reason_code,
data_type: TableRowItemDataType.Coding,
enabled: !!this.displayModel.reason_code,
},
// {
// label: 'Dosage',
// testId: 'hasDosageInstruction',
// data:
// hasDosageInstruction &&
// dosageInstruction.map((item, i) => (
// <p key={`dosage-instruction-item-${i}`}>{item.text}</p>
// )),
// status: hasDosageInstruction,
// },
];
}
markForCheck(){
this.changeRef.markForCheck()
}
}

View File

@ -0,0 +1,21 @@
<div class="card card-fhir-resource" >
<div class="card-header" (click)="isCollapsed = ! isCollapsed">
<div>
<h6 class="card-title">{{displayModel.title}}</h6>
<p class="card-text tx-gray-400" *ngIf="displayModel.sort_date"><strong>Start date</strong> {{displayModel.sort_date | date}}</p>
</div>
<fhir-ui-badge class="float-right" [status]="displayModel.status">{{displayModel.status}}</fhir-ui-badge>
<!-- <div class="btn-group">-->
<!-- <button class="btn active">Day</button>-->
<!-- <button class="btn">Week</button>-->
<!-- <button class="btn">Month</button>-->
<!-- </div>-->
</div>
<div #collapse="ngbCollapse" [(ngbCollapse)]="isCollapsed" class="card-body">
<p class="az-content-text mg-b-20">An order or request for both supply of the medication and the instructions for administration of the medication to a patient.</p>
<fhir-ui-table [displayModel]="displayModel" [tableData]="tableData"></fhir-ui-table>
</div>
<div *ngIf="showDetails" class="card-footer">
<a class="float-right" routerLink="/source/{{displayModel?.source_id}}/resource/{{displayModel?.source_resource_id}}">details</a>
</div>
</div>

View File

@ -0,0 +1,23 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { MedicationComponent } from './medication.component';
describe('MedicationComponent', () => {
let component: MedicationComponent;
let fixture: ComponentFixture<MedicationComponent>;
beforeEach(async () => {
await TestBed.configureTestingModule({
declarations: [ MedicationComponent ]
})
.compileComponents();
fixture = TestBed.createComponent(MedicationComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});

View File

@ -0,0 +1,67 @@
import {ChangeDetectorRef, Component, Input, OnInit} from '@angular/core';
import {FhirResourceComponentInterface} from '../../fhir-resource/fhir-resource-component-interface';
import {TableRowItem, TableRowItemDataType} from '../../common/table/table-row-item';
import {Router} from '@angular/router';
import {MedicationModel} from '../../../../../lib/models/resources/medication-model';
@Component({
selector: 'fhir-medication',
templateUrl: './medication.component.html',
styleUrls: ['./medication.component.scss']
})
export class MedicationComponent implements OnInit, FhirResourceComponentInterface {
@Input() displayModel: MedicationModel
@Input() showDetails: boolean = true
isCollapsed: boolean = false
tableData: TableRowItem[] = []
constructor(public changeRef: ChangeDetectorRef, public router: Router) {}
ngOnInit(): void {
this.tableData = [
{
label: 'Manufacturer',
data: this.displayModel.manufacturer,
data_type: TableRowItemDataType.Reference,
enabled: !!this.displayModel.manufacturer,
},
{
label: 'Form',
data: this.displayModel.product_form,
data_type: TableRowItemDataType.CodingList,
enabled: !!this.displayModel.product_form,
},
// {
// label: 'Ingredient',
// data:
// hasProductIngredient &&
// productIngredient.map((item, i) => (
// <Ingredient key={`item-${i}`} {...item} />
// )),
// status: hasProductIngredient,
// },
{
label: 'Package container',
data: this.displayModel.package_coding,
data_type: TableRowItemDataType.CodingList,
enabled: this.displayModel.has_package_coding,
},
// {
// label: 'Images',
// testId: 'product-images',
// data:
// hasImages &&
// images.map((item, i) => (
// <Attachment key={`item-${i}`} fhirData={item} isImage />
// )),
// status: hasImages,
// },
];
}
markForCheck(){
this.changeRef.markForCheck()
}
}

View File

@ -0,0 +1,21 @@
<div class="card card-fhir-resource" >
<div class="card-header" (click)="isCollapsed = ! isCollapsed">
<div>
<h6 class="card-title">{{displayModel.sort_title}}</h6>
<p class="card-text tx-gray-400" *ngIf="displayModel.sort_date"><strong>Date</strong>{{displayModel.sort_date}}</p>
</div>
<fhir-ui-badge class="float-right" [status]="displayModel.status">{{displayModel.status}}</fhir-ui-badge>
<!-- <div class="btn-group">-->
<!-- <button class="btn active">Day</button>-->
<!-- <button class="btn">Week</button>-->
<!-- <button class="btn">Month</button>-->
<!-- </div>-->
</div>
<div #collapse="ngbCollapse" [(ngbCollapse)]="isCollapsed" class="card-body">
<p class="az-content-text mg-b-20">Describes the event of a patient being administered a vaccine or a record of an immunization as reported by a patient, a clinician or another party.</p>
<fhir-ui-table [displayModel]="displayModel" [tableData]="tableData"></fhir-ui-table>
</div>
<div *ngIf="showDetails" class="card-footer">
<a class="float-right" routerLink="/source/{{displayModel?.source_id}}/resource/{{displayModel?.source_resource_id}}">details</a>
</div>
</div>

View File

@ -0,0 +1,23 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { PractitionerComponent } from './practitioner.component';
describe('PractitionerComponent', () => {
let component: PractitionerComponent;
let fixture: ComponentFixture<PractitionerComponent>;
beforeEach(async () => {
await TestBed.configureTestingModule({
declarations: [ PractitionerComponent ]
})
.compileComponents();
fixture = TestBed.createComponent(PractitionerComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});

View File

@ -0,0 +1,70 @@
import {ChangeDetectorRef, Component, Input, OnInit} from '@angular/core';
import {FhirResourceComponentInterface} from '../../fhir-resource/fhir-resource-component-interface';
import {ImmunizationModel} from '../../../../../lib/models/resources/immunization-model';
import {TableRowItem} from '../../common/table/table-row-item';
import {Router} from '@angular/router';
import {PractitionerModel} from '../../../../../lib/models/resources/practitioner-model';
@Component({
selector: 'app-practitioner',
templateUrl: './practitioner.component.html',
styleUrls: ['./practitioner.component.scss']
})
export class PractitionerComponent implements OnInit, FhirResourceComponentInterface {
@Input() displayModel: PractitionerModel
@Input() showDetails: boolean = true
isCollapsed: boolean = false
tableData: TableRowItem[] = []
constructor(public changeRef: ChangeDetectorRef, public router: Router) {}
ngOnInit(): void {
this.tableData = [
// {
// label: 'Identifiers',
// testId: 'identifier',
// data: identifier && <Identifier fhirData={identifier} />,
// status: identifier,
// },
{
label: 'Gender',
data: this.displayModel.gender,
enabled: !!this.displayModel.gender,
},
// {
// label: 'Birth date',
// data: birthDate && <Date fhirData={birthDate} isBlack />,
// status: birthDate,
// },
// {
// label: 'Contact',
// data: isContactData && (
// <PatientContact
// name={contactData.name}
// relationship={contactData.relationship}
// />
// ),
// status: isContactData,
// },
// {
// label: 'Address',
// testId: 'address',
// data: address && <Address fhirData={address} />,
// status: address,
// },
// {
// label: 'Telephone',
// testId: 'telecom',
// data: telecom && <Telecom fhirData={telecom} />,
// status: telecom,
// },
];
}
markForCheck(){
this.changeRef.markForCheck()
}
}

View File

@ -0,0 +1,21 @@
<div class="card card-fhir-resource" >
<div class="card-header" (click)="isCollapsed = ! isCollapsed">
<div>
<h6 class="card-title">{{displayModel.display}}</h6>
<p class="card-text tx-gray-400" *ngIf="displayModel.performed_datetime"><strong>Start date</strong> {{displayModel.performed_datetime | date}}</p>
</div>
<fhir-ui-badge class="float-right" [status]="displayModel.status">{{displayModel.status}}</fhir-ui-badge>
<!-- <div class="btn-group">-->
<!-- <button class="btn active">Day</button>-->
<!-- <button class="btn">Week</button>-->
<!-- <button class="btn">Month</button>-->
<!-- </div>-->
</div>
<div #collapse="ngbCollapse" [(ngbCollapse)]="isCollapsed" class="card-body">
<p class="az-content-text mg-b-20">An action that is or was performed on or for a patient, practitioner, device, organization, or location. For example, this can be a physical intervention on a patient like an operation, or less invasive like long term services, counseling, or hypnotherapy.</p>
<fhir-ui-table [displayModel]="displayModel" [tableData]="tableData"></fhir-ui-table>
</div>
<div *ngIf="showDetails" class="card-footer">
<a class="float-right" routerLink="/source/{{displayModel?.source_id}}/resource/{{displayModel?.source_resource_id}}">details</a>
</div>
</div>

View File

@ -0,0 +1,23 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { ProcedureComponent } from './procedure.component';
describe('ProcedureComponent', () => {
let component: ProcedureComponent;
let fixture: ComponentFixture<ProcedureComponent>;
beforeEach(async () => {
await TestBed.configureTestingModule({
declarations: [ ProcedureComponent ]
})
.compileComponents();
fixture = TestBed.createComponent(ProcedureComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});

View File

@ -0,0 +1,69 @@
import {ChangeDetectorRef, Component, Input, OnInit} from '@angular/core';
import {FhirResourceComponentInterface} from '../../fhir-resource/fhir-resource-component-interface';
import {TableRowItem, TableRowItemDataType} from '../../common/table/table-row-item';
import {Router} from '@angular/router';
import {ProcedureModel} from '../../../../../lib/models/resources/procedure-model';
@Component({
selector: 'app-procedure',
templateUrl: './procedure.component.html',
styleUrls: ['./procedure.component.scss']
})
export class ProcedureComponent implements OnInit, FhirResourceComponentInterface {
@Input() displayModel: ProcedureModel
@Input() showDetails: boolean = true
isCollapsed: boolean = false
tableData: TableRowItem[] = []
constructor(public changeRef: ChangeDetectorRef, public router: Router) {}
ngOnInit(): void {
this.tableData = [
{
label: 'Identification',
data: this.displayModel.coding,
data_type: TableRowItemDataType.CodingList,
enabled: this.displayModel.has_coding,
},
{
label: 'Category',
data: this.displayModel.category,
data_type: TableRowItemDataType.Coding,
enabled: !!this.displayModel.category,
},
{
label: 'Performed by',
data: this.displayModel.performer,
enabled: this.displayModel.has_performer_data,
},
// {
// label: 'Reason procedure performed',
// data: reasonCode && <Annotation fhirData={reasonCode} />,
// status: hasReasonCode,
// },
{
label: 'Location',
data: this.displayModel.location_reference,
data_type: TableRowItemDataType.Reference,
enabled: !!this.displayModel.location_reference,
},
// {
// label: 'Additional information about the procedure',
// data: note && <Annotation fhirData={note} />,
// status: hasNote,
// },
{
label: 'The result of procedure',
data: this.displayModel.outcome,
data_type: TableRowItemDataType.Coding,
enabled: !!this.displayModel.outcome,
},
];
}
markForCheck(){
this.changeRef.markForCheck()
}
}

View File

@ -6,7 +6,7 @@
{{conditionDisplayModel?.sort_title ? conditionDisplayModel?.sort_title : (conditionGroup | fhirPath: "Condition.code.text.first()":"Condition.code.coding.display.first()")}} {{conditionDisplayModel?.sort_title ? conditionDisplayModel?.sort_title : (conditionGroup | fhirPath: "Condition.code.text.first()":"Condition.code.coding.display.first()")}}
</div> </div>
<div class="col-6"> <div class="col-6">
{{conditionGroup | fhirPath: "Condition.onsetPeriod.start":"Condition.onsetDateTime" | date }} - {{conditionGroup | fhirPath: "Condition.onsetPeriod.end" | date}} {{conditionDisplayModel?.sort_date ? (conditionDisplayModel?.sort_date | date) : (conditionGroup | fhirPath: "Condition.onsetPeriod.start":"Condition.onsetDateTime" | date) }} - {{conditionGroup | fhirPath: "Condition.onsetPeriod.end" | date}}
</div> </div>
</div> </div>
</div><!-- card-header --> </div><!-- card-header -->
@ -40,15 +40,17 @@
<!-- </div>--> <!-- </div>-->
</div> </div>
<ng-container *ngIf="conditionGroup.related_resources.length > 0"> <div class="row pt-2" *ngIf="conditionGroup.related_resources.length > 0">
<a class="cursor-pointer tx-indigo" (click)="collapse.toggle()">show all</a> <div class="col-12">
<div #collapse="ngbCollapse" [ngbCollapse]="true"> <a class="cursor-pointer tx-indigo" (click)="collapse.toggle()">show all</a>
<div #collapse="ngbCollapse" [ngbCollapse]="true">
<ul> <ul>
<li class="cursor-pointer tx-indigo" *ngFor="let resourceEntry of resourcesLookup | keyvalue" [routerLink]="resourceEntry.key">{{resourceEntry.value.source_resource_type}} {{resourceEntry.value.sort_title ? '- '+resourceEntry.value.sort_title : '' }} </li> <li class="cursor-pointer tx-indigo" *ngFor="let resourceEntry of resourcesLookup | keyvalue" [routerLink]="resourceEntry.key">{{resourceEntry.value.source_resource_type}} {{resourceEntry.value.sort_title ? '- '+resourceEntry.value.sort_title : '' }} </li>
</ul> </ul>
</div>
</div> </div>
</ng-container> </div>
</div> </div>
@ -67,21 +69,36 @@
<div *ngIf="encounter?.related_resources?.MedicationRequest || encounter?.related_resources?.Medication" class="col-12 mt-2 mb-2"> <div *ngIf="encounter?.related_resources?.MedicationRequest || encounter?.related_resources?.Medication" class="col-12 mt-2 mb-2">
<strong>Medications:</strong> <strong>Medications:</strong>
<ul> <ul>
<li routerLink="/source/{{medication?.source_id}}/resource/{{medication?.source_resource_id}}" *ngFor="let medication of encounter?.related_resources?.MedicationRequest"> <li class="cursor-pointer" [ngbPopover]="medicationRequestPopoverContent" placement="top-left" popoverClass="card-fhir-resource-popover" *ngFor="let medication of encounter?.related_resources?.MedicationRequest">
{{medication.display }} {{medication.display }}
<ng-template #medicationRequestPopoverContent>
<fhir-resource [displayModel]="medication"></fhir-resource>
</ng-template>
</li> </li>
<li routerLink="/source/{{medication?.source_id}}/resource/{{medication?.source_resource_id}}" *ngFor="let medication of encounter?.related_resources?.Medication"> <li class="cursor-pointer" [ngbPopover]="medicationPopoverContent" placement="top-left" popoverClass="card-fhir-resource-popover" *ngFor="let medication of encounter?.related_resources?.Medication">
{{medication.title}} {{medication.title}}
<ng-template #medicationPopoverContent>
<fhir-resource [displayModel]="medication"></fhir-resource>
</ng-template>
</li> </li>
</ul> </ul>
</div> </div>
<div *ngIf="encounter?.related_resources?.Procedure as procedures" class="col-12 mt-2 mb-2"> <div *ngIf="encounter?.related_resources?.Procedure as procedures" class="col-12 mt-2 mb-2">
<strong>Procedures:</strong> <strong>Procedures:</strong>
<ul> <ul>
<li routerLink="/source/{{procedure?.source_id}}/resource/{{procedure?.source_resource_id}}" *ngFor="let procedure of procedures"> <li class="cursor-pointer" [ngbPopover]="procedurePopoverContent" placement="top-left" popoverClass="card-fhir-resource-popover" *ngFor="let procedure of procedures">
{{procedure.display}} {{procedure.display}}
<ng-template #procedurePopoverContent>
<fhir-resource [displayModel]="procedure"></fhir-resource>
</ng-template>
</li> </li>
</ul> </ul>
</div> </div>
@ -90,8 +107,12 @@
<div *ngIf="encounter?.related_resources?.DiagnosticReport as diagnosticReports" class="col-12 mt-2 mb-2"> <div *ngIf="encounter?.related_resources?.DiagnosticReport as diagnosticReports" class="col-12 mt-2 mb-2">
<strong>Tests and Examinations:</strong> <strong>Tests and Examinations:</strong>
<ul> <ul>
<li routerLink="/source/{{diagnosticReport?.source_id}}/resource/{{diagnosticReport?.source_resource_id}}" *ngFor="let diagnosticReport of diagnosticReports"> <li class="cursor-pointer" [ngbPopover]="diagnosticReportPopoverContent" placement="top-left" popoverClass="card-fhir-resource-popover" *ngFor="let diagnosticReport of diagnosticReports">
{{diagnosticReport.title}} {{diagnosticReport.title}}
<ng-template #diagnosticReportPopoverContent>
<fhir-resource [displayModel]="diagnosticReport"></fhir-resource>
</ng-template>
</li> </li>
</ul> </ul>
</div> </div>

View File

@ -10,6 +10,7 @@ import {ProcedureModel} from '../../../lib/models/resources/procedure-model';
import {DeviceModel} from '../../../lib/models/resources/device-model'; import {DeviceModel} from '../../../lib/models/resources/device-model';
import {DiagnosticReportModel} from '../../../lib/models/resources/diagnostic-report-model'; import {DiagnosticReportModel} from '../../../lib/models/resources/diagnostic-report-model';
import {FastenDisplayModel} from '../../../lib/models/fasten/fasten-display-model'; import {FastenDisplayModel} from '../../../lib/models/fasten/fasten-display-model';
import * as _ from "lodash";
@Component({ @Component({
selector: 'app-report-medical-history-condition', selector: 'app-report-medical-history-condition',
@ -68,6 +69,7 @@ export class ReportMedicalHistoryConditionComponent implements OnInit {
//add resources to the lookup table, ensure uniqueness. //add resources to the lookup table, ensure uniqueness.
this.conditionDisplayModel = this.recExtractResources(this.conditionGroup) this.conditionDisplayModel = this.recExtractResources(this.conditionGroup)
let involvedInCareMap: {[resource_id: string]: {displayName: string, role?: string, email?: string}} = {}
//loop though all resources, process display data //loop though all resources, process display data
for(let resourceId in this.resourcesLookup){ for(let resourceId in this.resourcesLookup){
@ -76,24 +78,58 @@ export class ReportMedicalHistoryConditionComponent implements OnInit {
switch(resource.source_resource_type){ switch(resource.source_resource_type){
case ResourceType.CareTeam: case ResourceType.CareTeam:
for(let participant of (resource as CareTeamModel).participants){ for(let participant of (resource as CareTeamModel).participants){
this.involvedInCare.push({ let id = participant.reference || participant.display
displayName: participant.display, involvedInCareMap[id] = _.mergeWith(
role: participant.role {},
}) involvedInCareMap[id],
{
displayName: participant.display,
role: participant.role
},
)
} }
break break
case ResourceType.Practitioner: case ResourceType.Practitioner:
this.involvedInCare.push({ let practitionerModel = resource as PractitionerModel
displayName: `${(resource as PractitionerModel).name?.family }, ${(resource as PractitionerModel).name?.given}`, let id = `${resource.source_resource_type}/${resource.source_resource_id}`
role: `${(resource as PractitionerModel).name?.prefix || (resource as PractitionerModel).name?.suffix}`
}) let telecomEmails =_.find(practitionerModel.telecom, {"system": "email"})
let email = _.get(telecomEmails, '[0].value')
involvedInCareMap[id] = _.mergeWith(
{},
involvedInCareMap[id],
{
displayName: practitionerModel.name?.family && practitionerModel.name?.given ? `${practitionerModel.name?.family }, ${practitionerModel.name?.given}` : practitionerModel.name?.text,
role: practitionerModel.name?.prefix || practitionerModel.name?.suffix,
email: email,
},
)
break break
case ResourceType.Encounter: case ResourceType.Encounter:
this.encounters.push(resource as EncounterModel) this.encounters.push(resource as EncounterModel);
(resource as EncounterModel).participant.map((participant) => {
let id = participant.reference
involvedInCareMap[id] = _.mergeWith(
{},
involvedInCareMap[id],
{
displayName: participant.display,
role: participant.role,
},
)
})
break break
} }
} }
console.log("GENERATED INVOLVED IN CARE MAP", involvedInCareMap)
for(let resourceId in involvedInCareMap){
this.involvedInCare.push(involvedInCareMap[resourceId])
}
} }
/* /*

View File

@ -90,7 +90,7 @@ export class ResourceListComponent implements OnInit, OnChanges {
} }
} }
typeLookup(resourceType: string): Type<any> { typeLookup(resourceType: string): Type<ResourceListComponentInterface> {
if(!resourceType){ if(!resourceType){
//dont try to render anything if the resourceType isnt set. //dont try to render anything if the resourceType isnt set.
return null return null

View File

@ -44,6 +44,26 @@ import { ReportLabsObservationComponent } from './report-labs-observation/report
import { ChartsModule } from 'ng2-charts'; import { ChartsModule } from 'ng2-charts';
import { LoadingSpinnerComponent } from './loading-spinner/loading-spinner.component'; import { LoadingSpinnerComponent } from './loading-spinner/loading-spinner.component';
import {FormsModule} from '@angular/forms'; import {FormsModule} from '@angular/forms';
import { BinaryComponent } from './fhir/resources/binary/binary.component';
import { PdfComponent } from './fhir/datatypes/pdf/pdf.component';
import { ImgComponent } from './fhir/datatypes/img/img.component';
import { BinaryTextComponent } from './fhir/datatypes/binary-text/binary-text.component';
import { MarkdownComponent } from './fhir/datatypes/markdown/markdown.component';
import { HtmlComponent } from './fhir/datatypes/html/html.component';
import { FhirResourceComponent } from './fhir/fhir-resource/fhir-resource.component';
import { FhirResourceOutletDirective } from './fhir/fhir-resource/fhir-resource-outlet.directive';
import { FallbackComponent } from './fhir/resources/fallback/fallback.component';
import {HighlightModule} from 'ngx-highlightjs';
import { ImmunizationComponent } from './fhir/resources/immunization/immunization.component';
import { BadgeComponent } from './fhir/common/badge/badge.component';
import { TableComponent } from './fhir/common/table/table.component';
import { CodingComponent } from './fhir/datatypes/coding/coding.component';
import { AllergyIntoleranceComponent } from './fhir/resources/allergy-intolerance/allergy-intolerance.component';
import { MedicationComponent } from './fhir/resources/medication/medication.component';
import { MedicationRequestComponent } from './fhir/resources/medication-request/medication-request.component';
import { ProcedureComponent } from './fhir/resources/procedure/procedure.component';
import { DiagnosticReportComponent } from './fhir/resources/diagnostic-report/diagnostic-report.component';
import { PractitionerComponent } from './fhir/resources/practitioner/practitioner.component';
@NgModule({ @NgModule({
imports: [ imports: [
@ -54,7 +74,8 @@ import {FormsModule} from '@angular/forms';
FormsModule, FormsModule,
MomentModule, MomentModule,
TreeModule, TreeModule,
ChartsModule ChartsModule,
HighlightModule,
], ],
declarations: [ declarations: [
ComponentsSidebarComponent, ComponentsSidebarComponent,
@ -94,46 +115,67 @@ import {FormsModule} from '@angular/forms';
ReportMedicalHistoryConditionComponent, ReportMedicalHistoryConditionComponent,
ReportLabsObservationComponent, ReportLabsObservationComponent,
LoadingSpinnerComponent, LoadingSpinnerComponent,
BinaryComponent,
PdfComponent,
ImgComponent,
BinaryTextComponent,
MarkdownComponent,
HtmlComponent,
FhirResourceComponent,
FhirResourceOutletDirective,
FallbackComponent,
ImmunizationComponent,
BadgeComponent,
TableComponent,
CodingComponent,
AllergyIntoleranceComponent,
MedicationComponent,
MedicationRequestComponent,
ProcedureComponent,
DiagnosticReportComponent,
PractitionerComponent,
], ],
exports: [ exports: [
ComponentsSidebarComponent, ComponentsSidebarComponent,
ListAllergyIntoleranceComponent, ListAllergyIntoleranceComponent,
ListAdverseEventComponent, ListAdverseEventComponent,
ListCarePlanComponent, ListCarePlanComponent,
ListCommunicationComponent, ListCommunicationComponent,
ListConditionComponent, ListConditionComponent,
ListEncounterComponent, ListEncounterComponent,
ListAppointmentComponent, ListAppointmentComponent,
ListGenericResourceComponent, ListGenericResourceComponent,
ListImmunizationComponent, ListImmunizationComponent,
ListMedicationAdministrationComponent, ListMedicationAdministrationComponent,
ListMedicationComponent, ListMedicationComponent,
ListMedicationDispenseComponent, ListMedicationDispenseComponent,
ListMedicationRequestComponent, ListMedicationRequestComponent,
ListNutritionOrderComponent, ListNutritionOrderComponent,
ListObservationComponent, ListObservationComponent,
ListPatientComponent, ListPatientComponent,
ListProcedureComponent, ListProcedureComponent,
ListDeviceRequestComponent, ListDeviceRequestComponent,
UtilitiesSidebarComponent, UtilitiesSidebarComponent,
ListCoverageComponent, ListCoverageComponent,
ListServiceRequestComponent, ListServiceRequestComponent,
ListDocumentReferenceComponent, ListDocumentReferenceComponent,
ListDeviceComponent, ListDeviceComponent,
ListDiagnosticReportComponent, ListDiagnosticReportComponent,
ListGoalComponent, ListGoalComponent,
ResourceListComponent, ResourceListComponent,
ResourceListOutletDirective, ResourceListOutletDirective,
ToastComponent, ToastComponent,
ReportHeaderComponent, ReportHeaderComponent,
ReportMedicalHistoryEditorComponent, ReportMedicalHistoryEditorComponent,
FhirPathPipe, FhirPathPipe,
FilterPipe, FilterPipe,
ReportMedicalHistoryConditionComponent, ReportMedicalHistoryConditionComponent,
ReportLabsObservationComponent, ReportLabsObservationComponent,
LoadingSpinnerComponent LoadingSpinnerComponent,
BinaryComponent,
] FhirResourceComponent,
FhirResourceOutletDirective
]
}) })
export class SharedModule { } export class SharedModule { }

View File

@ -32,7 +32,7 @@ export class DashboardComponent implements OnInit {
ngOnInit() { ngOnInit() {
this.loading = true this.loading = true
forkJoin([this.fastenApi.getSummary(), this.lighthouseApi.getLighthouseSourceMetadataMap()]).subscribe(results => { forkJoin([this.fastenApi.getSummary(), this.lighthouseApi.getLighthouseSourceMetadataMap(true)]).subscribe(results => {
this.loading = false this.loading = false
let summary = results[0] as Summary let summary = results[0] as Summary
let metadataSource = results[1] as { [name: string]: MetadataSource } let metadataSource = results[1] as { [name: string]: MetadataSource }

View File

@ -79,6 +79,11 @@
<input (keyup)="searchTermChanged($event)" type="text" class="form-control" placeholder="Search Term"> <input (keyup)="searchTermChanged($event)" type="text" class="form-control" placeholder="Search Term">
</div><!-- input-group --> </div><!-- input-group -->
</div><!-- col --> </div><!-- col -->
<!-- <div class="col-lg-4">-->
<!-- <div class="d-flex text-center">-->
<!-- <small>{{this.availableSourceList.length}} of {{this.totalAvailableSourceList}} sources</small>-->
<!-- </div>-->
<!-- </div>-->
</div> </div>

View File

@ -38,6 +38,7 @@ export class MedicalSourcesComponent implements OnInit {
connectedSourceList: SourceListItem[] = [] //source's are populated for this list connectedSourceList: SourceListItem[] = [] //source's are populated for this list
availableSourceList: SourceListItem[] = [] availableSourceList: SourceListItem[] = []
totalAvailableSourceList: number = 0
uploadedFile: File[] = [] uploadedFile: File[] = []
closeResult = ''; closeResult = '';
@ -58,7 +59,7 @@ export class MedicalSourcesComponent implements OnInit {
ngOnInit(): void { ngOnInit(): void {
this.loading = true this.loading = true
forkJoin([this.lighthouseApi.getLighthouseSourceMetadataMap(), this.fastenApi.getSources()]).subscribe(results => { forkJoin([this.lighthouseApi.getLighthouseSourceMetadataMap(true), this.fastenApi.getSources()]).subscribe(results => {
this.loading = false this.loading = false
//handle source metadata map response //handle source metadata map response
this.metadataSources = results[0] as {[name:string]: MetadataSource} this.metadataSources = results[0] as {[name:string]: MetadataSource}
@ -98,6 +99,7 @@ export class MedicalSourcesComponent implements OnInit {
this.callback(callbackSourceType).then(console.log) this.callback(callbackSourceType).then(console.log)
} }
this.totalAvailableSourceList = this.availableSourceList.length
//setup Search //setup Search
const options = { const options = {

View File

@ -143,10 +143,15 @@
<p> <p>
<ng-container *ngFor="let immunization of immunizations; let i = index"> <ng-container *ngFor="let immunization of immunizations; let i = index">
<strong class="tx-indigo">{{immunization | fhirPath: "Immunization.vaccineCode.text" }}</strong><br/> <strong class="cursor-pointer tx-indigo" [ngbPopover]="immunizationPopoverContent" placement="top-left" popoverClass="card-fhir-resource-popover">{{immunization.title }}</strong><br/>
{{immunization | fhirPath: "Immunization.occurrenceDateTime" | date }}<br/> {{immunization.sort_date | date }}<br/>
{{immunization | fhirPath: "Immunization.location.display" }}<br/> {{immunization.location }}<br/>
<br/> <br/>
<ng-template #immunizationPopoverContent>
<fhir-resource [displayModel]="immunization"></fhir-resource>
</ng-template>
</ng-container> </ng-container>
</p> </p>
@ -156,14 +161,14 @@
<p> <p>
<ng-container *ngFor="let allergy of allergyIntolerances; let i = index"> <ng-container *ngFor="let allergy of allergyIntolerances; let i = index">
<strong class="tx-indigo">{{allergy | fhirPath: "AllergyIntolerance.code.text" }}</strong><br/> <strong class="cursor-pointer tx-indigo" [ngbPopover]="allergyIntolerancesPopoverContent" placement="top-left" popoverClass="card-fhir-resource-popover">{{allergy.title}}</strong><br/>
{{allergy | fhirPath: "AllergyIntolerance.occurrenceDateTime" | date }}<br/> {{allergy.recorded_date }}<br/>
<br/> <br/>
</ng-container>
<strong class="tx-indigo">Latex</strong><br/> <ng-template #allergyIntolerancesPopoverContent>
(AV/Historical) with rash and agitation<br/> <fhir-resource [displayModel]="allergy"></fhir-resource>
<br/> </ng-template>
</ng-container>
</p> </p>
</div> </div>

View File

@ -2,6 +2,10 @@ import { Component, OnInit } from '@angular/core';
import {ResourceFhir} from '../../models/fasten/resource_fhir'; import {ResourceFhir} from '../../models/fasten/resource_fhir';
import {FastenApiService} from '../../services/fasten-api.service'; import {FastenApiService} from '../../services/fasten-api.service';
import {forkJoin} from 'rxjs'; import {forkJoin} from 'rxjs';
import {fhirModelFactory} from '../../../lib/models/factory';
import {ResourceType} from '../../../lib/models/constants';
import {ImmunizationModel} from '../../../lib/models/resources/immunization-model';
import {AllergyIntoleranceModel} from '../../../lib/models/resources/allergy-intolerance-model';
@Component({ @Component({
selector: 'app-patient-profile', selector: 'app-patient-profile',
@ -12,8 +16,8 @@ export class PatientProfileComponent implements OnInit {
loading: boolean = false loading: boolean = false
patient: ResourceFhir = null patient: ResourceFhir = null
immunizations: ResourceFhir[] = [] immunizations: ImmunizationModel[] = []
allergyIntolerances: ResourceFhir[] = [] allergyIntolerances: AllergyIntoleranceModel[] = []
constructor( constructor(
private fastenApi: FastenApiService, private fastenApi: FastenApiService,
) { } ) { }
@ -29,8 +33,12 @@ export class PatientProfileComponent implements OnInit {
this.loading = false this.loading = false
console.log(results) console.log(results)
this.patient = results[0][0] this.patient = results[0][0]
this.immunizations = results[1] this.immunizations = results[1].map((immunization) => {
this.allergyIntolerances = results[2] return fhirModelFactory(immunization.source_resource_type as ResourceType, immunization) as ImmunizationModel
})
this.allergyIntolerances = results[2].map((allergy) => {
return fhirModelFactory(allergy.source_resource_type as ResourceType, allergy) as AllergyIntoleranceModel
})
}, error => { }, error => {
this.loading = false this.loading = false
}) })

View File

@ -8,7 +8,13 @@
<span>{{resource?.source_resource_id}}</span> <span>{{resource?.source_resource_id}}</span>
</div> </div>
<pre *ngIf="resource else isLoadingTemplate"><code [highlight]="resource.resource_raw | json"></code></pre> <ng-container *ngIf="displayModel">
<fhir-resource [displayModel]="displayModel" [showDetails]="false"></fhir-resource>
</ng-container>
<ng-container *ngIf="resource else isLoadingTemplate">
<pre><code [highlight]="resource.resource_raw | json"></code></pre>
</ng-container>
<ng-template #isLoadingTemplate> <ng-template #isLoadingTemplate>
<div class="row"> <div class="row">

View File

@ -4,6 +4,7 @@ import {ActivatedRoute, Router} from '@angular/router';
import {ResourceFhir} from '../../models/fasten/resource_fhir'; import {ResourceFhir} from '../../models/fasten/resource_fhir';
import {fhirModelFactory} from '../../../lib/models/factory'; import {fhirModelFactory} from '../../../lib/models/factory';
import {ResourceType} from '../../../lib/models/constants'; import {ResourceType} from '../../../lib/models/constants';
import {FastenDisplayModel} from '../../../lib/models/fasten/fasten-display-model';
@Component({ @Component({
selector: 'app-resource-detail', selector: 'app-resource-detail',
@ -16,6 +17,7 @@ export class ResourceDetailComponent implements OnInit {
sourceId: string = "" sourceId: string = ""
sourceName: string = "" sourceName: string = ""
resource: ResourceFhir = null resource: ResourceFhir = null
displayModel: FastenDisplayModel = null
constructor(private fastenApi: FastenApiService, private router: Router, private route: ActivatedRoute) { constructor(private fastenApi: FastenApiService, private router: Router, private route: ActivatedRoute) {
} }
@ -30,7 +32,8 @@ export class ResourceDetailComponent implements OnInit {
this.sourceName = "unknown" //TODO popualte this this.sourceName = "unknown" //TODO popualte this
try{ try{
let parsed = fhirModelFactory(resourceFhir["source_resource_type"] as ResourceType, resourceFhir) let parsed = fhirModelFactory(resourceFhir.source_resource_type as ResourceType, resourceFhir)
this.displayModel = parsed
console.log("Successfully parsed model", parsed) console.log("Successfully parsed model", parsed)
} catch (e) { } catch (e) {
console.log("FAILED TO PARSE", resourceFhir) console.log("FAILED TO PARSE", resourceFhir)

173
frontend/src/custom.scss Normal file
View File

@ -0,0 +1,173 @@
//Custom
.cursor-pointer {
cursor: pointer;
}
//disable card
.card-disable {
-webkit-filter: grayscale(100%);
filter: grayscale(100%);
background-color: lightgrey !important;
opacity: 0.5;
cursor: auto !important;
}
// if text is too long, we can truncate
.truncate {
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
// toast notifications container
// sticky-top float-right pt-3 pr-3
.toast-container {
position: fixed;
right: 20px;
top: 20px;
z-index: 1000;
}
// Fhir Resource Cards
.card-fhir-resource-popover {
max-width:500px;
}
.card-fhir-resource {
position: relative;
border-color: $gray-300;
.card-header {
padding: 20px;
background-color: transparent;
@include media-breakpoint-up(sm) {
display: flex;
align-items: flex-start;
justify-content: space-between;
}
.card-title {
color: $gray-900;
font-weight: 700;
font-size: 14px;
line-height: 1;
margin-bottom: 3px;
}
.card-text {
margin-bottom: 0;
}
.btn-group {
margin-top: 15px;
@include media-breakpoint-up(sm) { margin-top: 0; }
.btn {
font-size: 12px;
font-weight: 500;
padding: 5px 10px;
min-height: inherit;
background-color: #fff;
color: $gray-600;
border: 1px solid $gray-300;
@include hover-focus() {
background-color: $gray-100;
border-color: $gray-300;
}
+ .btn { margin-left: -1px; }
&.active {
color: $gray-900;
background-color: $gray-200;
border-color: $gray-300;
}
}
}
}
//.card-body {
// padding: 10px 0 20px;
// position: relative;
// overflow: hidden;
//
// .flot-chart-wrapper {
// position: relative;
// margin-left: -28px;
// margin-right: -20px;
// }
//
// .flot-chart {
// width: 100%;
// height: 150px;
//
// @include media-breakpoint-up(sm) { height: 275px; }
// @include media-breakpoint-only(lg) { height: 252px; }
//
// .flot-y-axis > div {
// transform: translateX(50px);
// text-shadow: 1px 1px rgba(#fff, .75);
// color: $body-color;
// font-weight: 700;
// font-size: 11px;
// }
//
// .flot-x-axis > div {
// color: $gray-500;
// font-weight: 500;
// font-size: 11px;
// }
// }
//}
.card-body-top {
display: flex;
align-items: flex-start;
flex-wrap: wrap;
padding-left: 20px;
@include media-breakpoint-up(sm) {
position: absolute;
top: -5px;
left: 20px;
z-index: 5;
padding-left: 0;
}
> div {
flex-basis: 50%;
@include media-breakpoint-up(sm) { flex-basis: auto; }
+ div {
@include media-breakpoint-up(sm) { margin-left: 30px; }
}
}
label {
font-size: 12px;
margin-bottom: 3px;
@include media-breakpoint-up(sm) { font-size: $font-size-base; }
}
h2 {
font-size: 20px; //$font-size-base;
font-weight: 600;
font-family: 'Archivo', $font-family-base;
color: $gray-900;
@include media-breakpoint-up(sm) {
font-size: 24px;
letter-spacing: -.5px;
}
}
}
}

View File

@ -3,4 +3,5 @@ export interface CodingModel {
code?: string code?: string
system?: string system?: string
value?: any value?: any
unit?: string
} }

Some files were not shown because too many files have changed in this diff Show More