Adding ability to attach documents (PDFs, text, notes, DICOM) to manually created conditions. (#108)
This commit is contained in:
parent
003e713ccf
commit
41cea8601f
|
@ -46,7 +46,7 @@
|
|||
],
|
||||
"optimization": true,
|
||||
"outputHashing": "all",
|
||||
"sourceMap": false,
|
||||
"sourceMap": true,
|
||||
"namedChunks": false,
|
||||
"extractLicenses": true,
|
||||
"vendorChunk": false,
|
||||
|
|
|
@ -29,6 +29,7 @@
|
|||
"@fortawesome/free-regular-svg-icons": "^6.2.0",
|
||||
"@fortawesome/free-solid-svg-icons": "^6.2.0",
|
||||
"@ng-bootstrap/ng-bootstrap": "10.0.0",
|
||||
"@ng-select/ng-select": "9.1.0",
|
||||
"@panva/oauth4webapi": "1.2.0",
|
||||
"@swimlane/ngx-datatable": "^20.0.0",
|
||||
"@types/fhir": "^0.0.35",
|
||||
|
|
|
@ -31,6 +31,7 @@ import { ReportLabsComponent } from './pages/report-labs/report-labs.component';
|
|||
import {PipesModule} from './pipes/pipes.module';
|
||||
import { ResourceCreatorComponent } from './pages/resource-creator/resource-creator.component';
|
||||
import { InfiniteScrollModule } from 'ngx-infinite-scroll';
|
||||
import { NgSelectModule } from '@ng-select/ng-select';
|
||||
|
||||
@NgModule({
|
||||
declarations: [
|
||||
|
@ -62,7 +63,8 @@ import { InfiniteScrollModule } from 'ngx-infinite-scroll';
|
|||
HighlightModule,
|
||||
MomentModule,
|
||||
PipesModule,
|
||||
InfiniteScrollModule
|
||||
InfiniteScrollModule,
|
||||
NgSelectModule
|
||||
],
|
||||
providers: [
|
||||
{
|
||||
|
|
|
@ -23,6 +23,7 @@ import {FastenDisplayModel} from '../../../../lib/models/fasten/fasten-display-m
|
|||
import {ProcedureComponent} from '../resources/procedure/procedure.component';
|
||||
import {DiagnosticReportComponent} from '../resources/diagnostic-report/diagnostic-report.component';
|
||||
import {PractitionerComponent} from '../resources/practitioner/practitioner.component';
|
||||
import {DocumentReferenceComponent} from '../resources/document-reference/document-reference.component';
|
||||
|
||||
@Component({
|
||||
selector: 'fhir-resource',
|
||||
|
@ -105,9 +106,9 @@ export class FhirResourceComponent implements OnInit, OnChanges {
|
|||
case "DiagnosticReport": {
|
||||
return DiagnosticReportComponent;
|
||||
}
|
||||
// case "DocumentReference": {
|
||||
// return ListDocumentReferenceComponent;
|
||||
// }
|
||||
case "DocumentReference": {
|
||||
return DocumentReferenceComponent;
|
||||
}
|
||||
// case "Encounter": {
|
||||
// return ListEncounterComponent;
|
||||
// }
|
||||
|
|
|
@ -1,8 +1,10 @@
|
|||
<ng-container [ngTemplateOutlet]="
|
||||
displayModel?.content_type == 'application/pdf' ? showPdf :
|
||||
displayModel?.content_type == 'image/jpeg' ? showImg :
|
||||
displayModel?.content_type == 'text/markdown' ? showMarkdown :
|
||||
displayModel?.content_type == 'text/plain' ? showText :
|
||||
(displayModel?.content_type == 'text/html' || displayModel?.content_type == 'application/html') ? showHtml :
|
||||
(displayModel?.content_type == 'application/xml' || displayModel?.content_type == 'application/json') ? showText :
|
||||
(displayModel?.content_type == 'application/xml' || displayModel?.content_type == 'application/json') ? showHighlight :
|
||||
(displayModel?.content_type == 'image/jpeg' || displayModel?.content_type == 'image/png') ? showImg :
|
||||
showEmpty
|
||||
"></ng-container>
|
||||
|
||||
|
@ -15,6 +17,12 @@
|
|||
<ng-template #showHtml>
|
||||
<fhir-html [displayModel]="displayModel"></fhir-html>
|
||||
</ng-template>
|
||||
<ng-template #showMarkdown>
|
||||
<fhir-markdown [displayModel]="displayModel"></fhir-markdown>
|
||||
</ng-template>
|
||||
<ng-template #showHighlight>
|
||||
<pre><code [languages]="['json', 'xml']" [highlight]="displayModel | json"></code></pre>
|
||||
</ng-template>
|
||||
<ng-template #showText>
|
||||
<fhir-binary-text [displayModel]="displayModel"></fhir-binary-text>
|
||||
</ng-template>
|
||||
|
|
|
@ -0,0 +1,25 @@
|
|||
<div class="card card-fhir-resource" >
|
||||
<div class="card-header" (click)="isCollapsed = ! isCollapsed">
|
||||
<div>
|
||||
<h6 class="card-title">{{displayModel?.category?.text}}</h6>
|
||||
<p class="card-text tx-gray-400" *ngIf="displayModel?.created_at"><strong>Created at</strong> {{displayModel?.created_at | 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 *ngIf="!showDetails">
|
||||
<fhir-binary *ngFor="let binaryModel of displayModel.content" [displayModel]="binaryModel"></fhir-binary>
|
||||
</div>
|
||||
</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>
|
|
@ -0,0 +1,23 @@
|
|||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { DocumentReferenceComponent } from './document-reference.component';
|
||||
|
||||
describe('DocumentReferenceComponent', () => {
|
||||
let component: DocumentReferenceComponent;
|
||||
let fixture: ComponentFixture<DocumentReferenceComponent>;
|
||||
|
||||
beforeEach(async () => {
|
||||
await TestBed.configureTestingModule({
|
||||
declarations: [ DocumentReferenceComponent ]
|
||||
})
|
||||
.compileComponents();
|
||||
|
||||
fixture = TestBed.createComponent(DocumentReferenceComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
|
@ -0,0 +1,51 @@
|
|||
import {ChangeDetectorRef, Component, Input, OnInit} from '@angular/core';
|
||||
import {DiagnosticReportModel} from '../../../../../lib/models/resources/diagnostic-report-model';
|
||||
import {TableRowItem, TableRowItemDataType} from '../../common/table/table-row-item';
|
||||
import {Router} from '@angular/router';
|
||||
import {DocumentReferenceModel} from '../../../../../lib/models/resources/document-reference-model';
|
||||
import {FhirResourceComponentInterface} from '../../fhir-resource/fhir-resource-component-interface';
|
||||
|
||||
@Component({
|
||||
selector: 'app-document-reference',
|
||||
templateUrl: './document-reference.component.html',
|
||||
styleUrls: ['./document-reference.component.scss']
|
||||
})
|
||||
export class DocumentReferenceComponent implements OnInit, FhirResourceComponentInterface {
|
||||
@Input() displayModel: DocumentReferenceModel
|
||||
@Input() showDetails: boolean = true
|
||||
isCollapsed: boolean = false
|
||||
tableData: TableRowItem[] = []
|
||||
|
||||
constructor(public changeRef: ChangeDetectorRef, public router: Router) {}
|
||||
|
||||
|
||||
ngOnInit(): void {
|
||||
this.tableData = [
|
||||
{
|
||||
label: 'Description',
|
||||
data: this.displayModel?.description,
|
||||
enabled: !!this.displayModel?.description,
|
||||
},
|
||||
{
|
||||
label: 'Category',
|
||||
data: this.displayModel?.category?.coding,
|
||||
data_type: TableRowItemDataType.CodingList,
|
||||
enabled: !!this.displayModel?.category,
|
||||
},
|
||||
// {
|
||||
// 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()
|
||||
}
|
||||
}
|
|
@ -1,7 +1,7 @@
|
|||
<div class="card card-fhir-resource" >
|
||||
<div class="card-header" (click)="isCollapsed = ! isCollapsed">
|
||||
<div>
|
||||
<h6 class="card-title">{{displayModel?.medication_reference.display}}</h6>
|
||||
<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>
|
||||
|
|
|
@ -22,6 +22,8 @@ export enum NlmSearchType {
|
|||
Vaccine = 'Vaccine',
|
||||
|
||||
Countries = 'Countries',
|
||||
AttachmentFileType = 'AttachmentFileType',
|
||||
AttachmentCategory = 'AttachmentCategory',
|
||||
PrePopulated = 'PrePopulated'
|
||||
|
||||
}
|
||||
|
@ -79,6 +81,17 @@ export class NlmTypeaheadComponent implements ControlValueAccessor {
|
|||
searchOpFn = this.nlmClinicalTableSearchService.searchAllergyReaction
|
||||
this.openOnFocus = true
|
||||
break
|
||||
case NlmSearchType.AttachmentFileType:
|
||||
searchOpFn = this.nlmClinicalTableSearchService.searchAttachmentFileType
|
||||
this.openOnFocus = true
|
||||
this.idResult = true
|
||||
this.editable = false
|
||||
break
|
||||
case NlmSearchType.AttachmentCategory:
|
||||
searchOpFn = this.nlmClinicalTableSearchService.searchAttachmentCategory
|
||||
this.openOnFocus = true
|
||||
this.editable = false
|
||||
break
|
||||
case NlmSearchType.Condition:
|
||||
searchOpFn = this.nlmClinicalTableSearchService.searchCondition
|
||||
break
|
||||
|
|
|
@ -64,6 +64,7 @@ import { DiagnosticReportComponent } from './fhir/resources/diagnostic-report/di
|
|||
import { PractitionerComponent } from './fhir/resources/practitioner/practitioner.component';
|
||||
import {PipesModule} from '../pipes/pipes.module';
|
||||
import { NlmTypeaheadComponent } from './nlm-typeahead/nlm-typeahead.component';
|
||||
import { DocumentReferenceComponent } from './fhir/resources/document-reference/document-reference.component';
|
||||
|
||||
@NgModule({
|
||||
imports: [
|
||||
|
@ -136,6 +137,7 @@ import { NlmTypeaheadComponent } from './nlm-typeahead/nlm-typeahead.component';
|
|||
DiagnosticReportComponent,
|
||||
PractitionerComponent,
|
||||
NlmTypeaheadComponent,
|
||||
DocumentReferenceComponent,
|
||||
],
|
||||
exports: [
|
||||
ComponentsSidebarComponent,
|
||||
|
@ -186,7 +188,8 @@ import { NlmTypeaheadComponent } from './nlm-typeahead/nlm-typeahead.component';
|
|||
ProcedureComponent,
|
||||
DiagnosticReportComponent,
|
||||
PractitionerComponent,
|
||||
NlmTypeaheadComponent
|
||||
NlmTypeaheadComponent,
|
||||
DocumentReferenceComponent,
|
||||
]
|
||||
})
|
||||
|
||||
|
|
|
@ -129,7 +129,8 @@ export interface ResourceCreate {
|
|||
"medications": ResourceCreateMedication[],
|
||||
"procedures": ResourceCreateProcedure[],
|
||||
"practitioners": ResourceCreatePractitioner[],
|
||||
"organizations": ResourceCreateOrganization[]
|
||||
"organizations": ResourceCreateOrganization[],
|
||||
"attachments": ResourceCreateAttachment[],
|
||||
}
|
||||
|
||||
export interface ResourceCreateCondition {
|
||||
|
@ -155,6 +156,7 @@ export interface ResourceCreateMedication {
|
|||
"whystopped": NlmSearchResults
|
||||
"requester": string,
|
||||
"instructions": string
|
||||
"attachments": ResourceCreateAttachment[],
|
||||
}
|
||||
|
||||
export interface ResourceCreateProcedure {
|
||||
|
@ -162,7 +164,8 @@ export interface ResourceCreateProcedure {
|
|||
"whendone": ResourceCreateDate,
|
||||
"comment": string,
|
||||
"performer": string,
|
||||
"location": string
|
||||
"location": string,
|
||||
"attachments": ResourceCreateAttachment[],
|
||||
}
|
||||
|
||||
export interface ResourceCreatePractitioner {
|
||||
|
@ -187,6 +190,18 @@ export interface ResourceCreateOrganization {
|
|||
"address": Address,
|
||||
}
|
||||
|
||||
export interface ResourceCreateAttachment {
|
||||
"id"?: string,
|
||||
"identifier": CodingModel[]
|
||||
"name": string,
|
||||
"category": NlmSearchResults,
|
||||
"file_type": string,
|
||||
"file_name": string,
|
||||
"file_content": string,
|
||||
"file_size": number,
|
||||
}
|
||||
|
||||
|
||||
export interface Address {
|
||||
line1?: string
|
||||
line2?: string
|
||||
|
|
|
@ -134,6 +134,21 @@
|
|||
<textarea formControlName="instructions" rows="3" class="form-control" placeholder="Textarea"></textarea>
|
||||
</div><!-- col -->
|
||||
</div><!-- row -->
|
||||
<div class="row row-sm mg-t-20">
|
||||
<div class="col-12 mg-t-10 mg-lg-t-0">
|
||||
<p class="mg-b-10">Attachments</p>
|
||||
</div><!-- col -->
|
||||
<div class="col-1">
|
||||
<button type="button" (click)="openAttachmentModal(attachmentCreateModal, medicationGroup, 'attachments')" class="btn btn-indigo btn-with-icon">
|
||||
<i class="fas fa-paperclip"></i> Add
|
||||
</button>
|
||||
</div>
|
||||
<div class="col-11">
|
||||
<ng-select class="ng-select-form-control" [readonly]="!attachments.controls.length" appendTo="body" formControlName="attachments" placeholder="Select Attachment" [multiple]="true" [hideSelected]="true">
|
||||
<ng-option *ngFor="let attachment of attachments.controls; let i = index" [value]="attachment.value.id">{{attachment.value.name}} ({{attachment.value.file_name}})</ng-option>
|
||||
</ng-select>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</ng-container>
|
||||
<div class="row pt-2">
|
||||
|
@ -206,6 +221,22 @@
|
|||
<textarea formControlName="comment" class="form-control" placeholder="Input box" rows="3"></textarea>
|
||||
</div><!-- col -->
|
||||
</div><!-- row -->
|
||||
<div class="row row-sm mg-t-20">
|
||||
<div class="col-12 mg-t-10 mg-lg-t-0">
|
||||
<p class="mg-b-10">Attachments</p>
|
||||
</div><!-- col -->
|
||||
|
||||
<div class="col-1">
|
||||
<button type="button" (click)="openAttachmentModal(attachmentCreateModal, procedureGroup, 'attachments')" class="btn btn-indigo btn-with-icon">
|
||||
<i class="fas fa-paperclip"></i> Add
|
||||
</button>
|
||||
</div>
|
||||
<div class="col-11">
|
||||
<ng-select class="ng-select-form-control" [readonly]="!attachments.controls.length" formControlName="attachments" placeholder="Select Attachment" [multiple]="true" [hideSelected]="true">
|
||||
<ng-option *ngFor="let attachment of attachments.controls; let i = index" [value]="attachment.value.id">{{attachment.value.name}} ({{attachment.value.file_name}})</ng-option>
|
||||
</ng-select>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</ng-container>
|
||||
|
||||
|
@ -238,6 +269,9 @@
|
|||
|
||||
<ng-container formArrayName="practitioners">
|
||||
<div class="card mg-t-10 pd-20" [formGroup]="practitionerGroup" *ngFor="let practitionerGroup of practitioners.controls; let i = index">
|
||||
<div *ngIf="debugMode" class="alert alert-warning">
|
||||
<strong>Practitioner Status: {{practitionerGroup.status}}</strong>
|
||||
</div>
|
||||
<div class="tx-right">
|
||||
<span class="cursor-pointer" (click)="deletePractitioner(i)" aria-hidden="true"><i class="fas fa-trash"></i></span>
|
||||
</div>
|
||||
|
@ -305,6 +339,9 @@
|
|||
|
||||
<ng-container formArrayName="locations">
|
||||
<div class="card mg-t-10 pd-20" [formGroup]="organizationGroup" *ngFor="let organizationGroup of organizations.controls; let i = index">
|
||||
<div *ngIf="debugMode" class="alert alert-warning">
|
||||
<strong>Organization Status: {{organizationGroup.status}}</strong>
|
||||
</div>
|
||||
<div class="tx-right">
|
||||
<span class="cursor-pointer" (click)="deleteOrganization(i)" aria-hidden="true"><i class="fas fa-trash"></i></span>
|
||||
</div>
|
||||
|
@ -364,20 +401,42 @@
|
|||
</div>
|
||||
</div>
|
||||
<div #collapse="ngbCollapse" [(ngbCollapse)]="collapsePanel['attachments']" class="card-body">
|
||||
<div class="row row-sm">
|
||||
<div class="col-lg">
|
||||
<p class="mg-b-10">Name</p>
|
||||
<input disabled class="form-control" placeholder="Input box" type="text">
|
||||
</div><!-- col -->
|
||||
<div class="col-lg mg-t-10 mg-lg-t-0">
|
||||
<p class="mg-b-10">Type</p>
|
||||
<input disabled class="form-control" placeholder="Input box" type="text">
|
||||
</div><!-- col -->
|
||||
|
||||
</div><!-- row -->
|
||||
<ng-container formArrayName="locations">
|
||||
<div class="card mg-t-10 pd-20" [formGroup]="attachmentGroup" *ngFor="let attachmentGroup of attachments.controls; let i = index">
|
||||
<div *ngIf="debugMode" class="alert alert-warning">
|
||||
<strong>Attachment Status: {{attachmentGroup.status}}</strong>
|
||||
</div>
|
||||
<div class="tx-right">
|
||||
<span class="cursor-pointer" (click)="deleteAttachment(i)" aria-hidden="true"><i class="fas fa-trash"></i></span>
|
||||
</div>
|
||||
|
||||
<div class="row row-sm">
|
||||
<input formControlName="id" class="form-control" type="hidden">
|
||||
|
||||
<div class="col-lg mg-t-10 mg-lg-t-0">
|
||||
<p class="mg-b-10">Name<span ngbTooltip="required" class="text-danger">*</span></p>
|
||||
<input formControlName="name" readonly class="form-control" placeholder="Input box" type="text">
|
||||
</div><!-- col -->
|
||||
<div class="col-lg mg-t-10 mg-lg-t-0">
|
||||
<p class="mg-b-10">Category</p>
|
||||
<app-nlm-typeahead formControlName="category" searchType="AttachmentCategory" [debugMode]="debugMode"></app-nlm-typeahead>
|
||||
</div><!-- col -->
|
||||
<div class="col-lg mg-t-10 mg-lg-t-0">
|
||||
<p class="mg-b-10">File Type</p>
|
||||
<input readonly class="form-control" formControlName="file_type"/>
|
||||
</div><!-- col -->
|
||||
</div><!-- row -->
|
||||
|
||||
</div>
|
||||
</ng-container>
|
||||
|
||||
|
||||
|
||||
|
||||
<div class="row pt-2">
|
||||
<div class="col-lg-4 col-md-3">
|
||||
<button disabled type="button" class="btn btn-outline-indigo btn-block">Add Note or Attachment</button>
|
||||
<button type="button" (click)="openAttachmentModal(attachmentCreateModal)" class="btn btn-outline-indigo btn-block">Create Attachment/Document</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -541,3 +600,48 @@
|
|||
<button type="button" class="btn btn-az-primary" (click)="modal.dismiss()">Add Location</button>
|
||||
</div>
|
||||
</ng-template>
|
||||
|
||||
|
||||
|
||||
<ng-template #attachmentCreateModal let-modal>
|
||||
<div class="modal-header">
|
||||
<h4 class="modal-title" id="modal-attachment">New Attachment</h4>
|
||||
<button type="button" class="close" aria-label="Close" (click)="modal.close()"><span aria-hidden="true">×</span></button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
|
||||
<div *ngIf="debugMode" class="alert alert-warning">
|
||||
<pre><code [highlight]="newAttachmentForm.getRawValue() | json"></code></pre>
|
||||
<strong>New Attachment Form Status: {{ newAttachmentForm.status }}</strong>
|
||||
</div>
|
||||
|
||||
<div class="row row-sm">
|
||||
<ng-container [formGroup]="newAttachmentForm">
|
||||
|
||||
<div class="col-12">
|
||||
<p class="mg-b-10">Name<span ngbTooltip="required" class="text-danger">*</span></p>
|
||||
<input formControlName="name" class="form-control" type="text">
|
||||
</div><!-- col -->
|
||||
|
||||
<div class="col-6 mg-t-10 mg-lg-t-0">
|
||||
<p class="mg-b-10">Category<span ngbTooltip="required" class="text-danger">*</span></p>
|
||||
<app-nlm-typeahead formControlName="category" searchType="AttachmentCategory" [debugMode]="debugMode"></app-nlm-typeahead>
|
||||
</div><!-- col -->
|
||||
<div class="col-6 mg-t-10 mg-lg-t-0">
|
||||
<p class="mg-b-10">File Type<span ngbTooltip="required" class="text-danger">*</span></p>
|
||||
<app-nlm-typeahead formControlName="file_type" searchType="AttachmentFileType" [debugMode]="debugMode"></app-nlm-typeahead>
|
||||
</div><!-- col -->
|
||||
<div class="col-12 mg-t-10 mg-lg-t-0">
|
||||
<p class="mg-b-10">File<span ngbTooltip="required" class="text-danger">*</span></p>
|
||||
</div><!-- col -->
|
||||
<div class="col-6 mg-t-10 mg-lg-t-0 mg-l-10">
|
||||
<label for="customFile" class="custom-file-label">{{newAttachmentForm.get('file_name').value || 'Choose file'}}</label>
|
||||
<input id="customFile" (change)="onAttachmentFileChange($event)" class="custom-file-input" formControlName="file_name" type="file">
|
||||
</div><!-- col -->
|
||||
</ng-container>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-az-primary" (click)="modal.dismiss()">Create Attachment</button>
|
||||
</div>
|
||||
</ng-template>
|
||||
|
|
|
@ -2,6 +2,7 @@ import {Component, Input, OnInit} from '@angular/core';
|
|||
import {AbstractControl, FormArray, FormControl, FormGroup, Validators} from '@angular/forms';
|
||||
import { ModalDismissReasons, NgbModal } from '@ng-bootstrap/ng-bootstrap';
|
||||
import {
|
||||
ResourceCreateAttachment,
|
||||
ResourceCreateOrganization,
|
||||
ResourceCreatePractitioner,
|
||||
} from '../../models/fasten/resource_create';
|
||||
|
@ -74,6 +75,7 @@ export class ResourceCreatorComponent implements OnInit {
|
|||
procedures: new FormArray([]),
|
||||
practitioners: new FormArray([]),
|
||||
organizations: new FormArray([]),
|
||||
attachments: new FormArray([]),
|
||||
});
|
||||
|
||||
this.resetOrganizationForm()
|
||||
|
@ -95,6 +97,7 @@ export class ResourceCreatorComponent implements OnInit {
|
|||
whystopped: new FormControl(null),
|
||||
requester: new FormControl(null, Validators.required),
|
||||
instructions: new FormControl(null),
|
||||
attachments: new FormControl([]),
|
||||
});
|
||||
|
||||
medicationGroup.get("data").valueChanges.subscribe(val => {
|
||||
|
@ -118,7 +121,8 @@ export class ResourceCreatorComponent implements OnInit {
|
|||
whendone: new FormControl(null, Validators.required),
|
||||
performer: new FormControl(null),
|
||||
location: new FormControl(null),
|
||||
comment: new FormControl('')
|
||||
comment: new FormControl(''),
|
||||
attachments: new FormControl([]),
|
||||
});
|
||||
|
||||
this.procedures.push(procedureGroup);
|
||||
|
@ -181,7 +185,26 @@ export class ResourceCreatorComponent implements OnInit {
|
|||
this.organizations.removeAt(index);
|
||||
}
|
||||
|
||||
get attachments(): FormArray {
|
||||
return this.form.controls["attachments"] as FormArray;
|
||||
}
|
||||
|
||||
addAttachment(attachment: ResourceCreateAttachment){
|
||||
const attachmentGroup = new FormGroup({
|
||||
id: new FormControl(attachment.id, Validators.required),
|
||||
name: new FormControl(attachment.name, Validators.required),
|
||||
category: new FormControl(attachment.category, Validators.required),
|
||||
file_type: new FormControl(attachment.file_type, Validators.required),
|
||||
file_name: new FormControl(attachment.file_name, Validators.required),
|
||||
file_content: new FormControl(attachment.file_content, Validators.required),
|
||||
file_size: new FormControl(attachment.file_size),
|
||||
});
|
||||
|
||||
this.attachments.push(attachmentGroup);
|
||||
}
|
||||
deleteAttachment(index: number) {
|
||||
this.attachments.removeAt(index);
|
||||
}
|
||||
|
||||
|
||||
onSubmit() {
|
||||
|
@ -212,6 +235,8 @@ export class ResourceCreatorComponent implements OnInit {
|
|||
newOrganizationTypeaheadForm: FormGroup
|
||||
newOrganizationForm: FormGroup //ResourceCreateOrganization
|
||||
|
||||
newAttachmentForm: FormGroup
|
||||
|
||||
openPractitionerModal(content, formGroup?: AbstractControl, controlName?: string) {
|
||||
this.resetPractitionerForm()
|
||||
this.modalService.open(content, {
|
||||
|
@ -269,6 +294,37 @@ export class ResourceCreatorComponent implements OnInit {
|
|||
);
|
||||
}
|
||||
|
||||
openAttachmentModal(content, formGroup?: AbstractControl, controlName?: string) {
|
||||
this.resetAttachmentForm()
|
||||
|
||||
this.modalService.open(content, {
|
||||
ariaLabelledBy: 'modal-attachment',
|
||||
beforeDismiss: () => {
|
||||
console.log("validate Attachment form")
|
||||
this.newAttachmentForm.markAllAsTouched()
|
||||
return this.newAttachmentForm.valid
|
||||
},
|
||||
}).result.then(
|
||||
() => {
|
||||
console.log('Closed without saving');
|
||||
},
|
||||
() => {
|
||||
console.log('Closing, saving form');
|
||||
//add this to the list of organization
|
||||
let result = this.newAttachmentForm.getRawValue()
|
||||
result.id = uuidV4();
|
||||
this.addAttachment(result);
|
||||
|
||||
if(formGroup && controlName){
|
||||
|
||||
//add this attachment id to the current FormArray
|
||||
let controlArrayVal = formGroup.get(controlName).getRawValue();
|
||||
controlArrayVal.push(result.id)
|
||||
formGroup.get(controlName).setValue(controlArrayVal);
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
private resetPractitionerForm(){
|
||||
this.newPractitionerTypeaheadForm = new FormGroup({
|
||||
|
@ -376,4 +432,33 @@ export class ResourceCreatorComponent implements OnInit {
|
|||
})
|
||||
|
||||
}
|
||||
|
||||
private resetAttachmentForm(){
|
||||
|
||||
this.newAttachmentForm = new FormGroup({
|
||||
name: new FormControl(null, Validators.required),
|
||||
category: new FormControl(null, Validators.required),
|
||||
file_type: new FormControl(null, Validators.required),
|
||||
file_name: new FormControl(null, Validators.required),
|
||||
file_content: new FormControl(null, Validators.required),
|
||||
file_size: new FormControl(null),
|
||||
})
|
||||
}
|
||||
onAttachmentFileChange($event){
|
||||
console.log("onAttachmentFileChange")
|
||||
let fileInput = $event.target as HTMLInputElement;
|
||||
if (fileInput.files && fileInput.files[0]) {
|
||||
let reader = new FileReader();
|
||||
reader.onloadend = () => {
|
||||
// use a regex to remove data url part
|
||||
const base64String = (reader.result as string).replace('data:', '').replace(/^.+,/, '');
|
||||
this.newAttachmentForm.get('file_content').setValue(base64String)
|
||||
};
|
||||
reader.readAsDataURL(fileInput.files[0]);
|
||||
this.newAttachmentForm.get('file_name').setValue(fileInput.files[0].name)
|
||||
this.newAttachmentForm.get('file_size').setValue(fileInput.files[0].size)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import {
|
||||
ResourceCreate,
|
||||
ResourceCreateCondition, ResourceCreateMedication,
|
||||
ResourceCreateCondition, ResourceCreateAttachment, ResourceCreateMedication,
|
||||
ResourceCreateOrganization, ResourceCreatePractitioner,
|
||||
ResourceCreateProcedure
|
||||
} from '../../models/fasten/resource_create';
|
||||
|
@ -12,13 +12,13 @@ import {
|
|||
BundleEntry,
|
||||
Bundle,
|
||||
Organization,
|
||||
Practitioner, MedicationRequest, Patient, Encounter
|
||||
Practitioner, MedicationRequest, Patient, Encounter, DocumentReference, Media, DiagnosticReport, Reference
|
||||
} from 'fhir/r4';
|
||||
import {uuidV4} from '../../../lib/utils/uuid';
|
||||
|
||||
interface ResourceStorage {
|
||||
[resourceType: string]: {
|
||||
[resourceId: string]: Condition | Patient | MedicationRequest | Organization | FhirLocation | Practitioner | Procedure | Encounter
|
||||
[resourceId: string]: Condition | Patient | MedicationRequest | Organization | FhirLocation | Practitioner | Procedure | Encounter | DocumentReference | Media | DiagnosticReport
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -27,6 +27,21 @@ export function GenerateR4Bundle(resourceCreate: ResourceCreate): Bundle {
|
|||
let resourceStorage: ResourceStorage = {} //{"resourceType": {"resourceId": resourceData}}
|
||||
resourceStorage = placeholderR4Patient(resourceStorage)
|
||||
resourceStorage = resourceCreateConditionToR4Condition(resourceStorage, resourceCreate.condition)
|
||||
|
||||
for(let attachment of resourceCreate.attachments) {
|
||||
if(attachment.file_type == 'application/dicom' ||
|
||||
attachment.category.id == '18726-0' || //Radiology studies (set)
|
||||
attachment.category.id == '27897-8' || // Neuromuscular electrophysiology studies (set)
|
||||
attachment.category.id == '18748-4' // Diagnostic imaging study
|
||||
) {
|
||||
//Diagnostic imaging study (DiagnosticReport -> Media)
|
||||
resourceStorage = resourceAttachmentToR4DiagnosticReport(resourceStorage, attachment)
|
||||
}
|
||||
else {
|
||||
resourceStorage = resourceAttachmentToR4DocumentReference(resourceStorage, attachment)
|
||||
}
|
||||
|
||||
}
|
||||
for(let organization of resourceCreate.organizations) {
|
||||
resourceStorage = resourceCreateOrganizationToR4Organization(resourceStorage, organization)
|
||||
}
|
||||
|
@ -40,6 +55,12 @@ export function GenerateR4Bundle(resourceCreate: ResourceCreate): Bundle {
|
|||
resourceStorage = resourceCreateProcedureToR4Procedure(resourceStorage, procedure)
|
||||
}
|
||||
|
||||
|
||||
//DocumentReference -> (Optional) Binary
|
||||
//DiagnosticReport -> Media
|
||||
//ImagingStudy
|
||||
//ImagingSelection
|
||||
|
||||
console.log("POPULATED RESOURCE STORAGE", resourceStorage)
|
||||
|
||||
let bundle = {
|
||||
|
@ -182,6 +203,11 @@ function resourceCreateProcedureToR4Procedure(resourceStorage: ResourceStorage,
|
|||
reference: `urn:uuid:${findCondition(resourceStorage).id}` //Condition
|
||||
}
|
||||
],
|
||||
report: (resourceCreateProcedure.attachments || []).map(attachmentId => {
|
||||
return {
|
||||
reference: `urn:uuid:${attachmentId}` //DocumentReference or DiagnosticReport
|
||||
}
|
||||
}),
|
||||
performer: [
|
||||
{
|
||||
actor: {
|
||||
|
@ -311,7 +337,7 @@ function resourceCreatePractitionerToR4Practitioner(resourceStorage: ResourceSto
|
|||
return resourceStorage
|
||||
}
|
||||
|
||||
// this model is based on FHIR401 Resource Medication - http://hl7.org/fhir/R4/medication.html
|
||||
// this model is based on FHIR401 Resource Medication - https://www.hl7.org/fhir/R4/MedicationRequest.html
|
||||
function resourceCreateMedicationToR4MedicationRequest(resourceStorage: ResourceStorage, resourceCreateMedication: ResourceCreateMedication): ResourceStorage {
|
||||
resourceStorage['MedicationRequest'] = resourceStorage['MedicationRequest'] || {}
|
||||
|
||||
|
@ -362,6 +388,11 @@ function resourceCreateMedicationToR4MedicationRequest(resourceStorage: Resource
|
|||
requester: {
|
||||
reference: `urn:uuid:${resourceCreateMedication.requester}` // Practitioner
|
||||
},
|
||||
supportingInformation: (resourceCreateMedication.attachments || []).map((attachmentId) => {
|
||||
return {
|
||||
reference: `urn:uuid:${attachmentId}` //DocumentReference or DiagnosticReport
|
||||
}
|
||||
}),
|
||||
reasonReference: [
|
||||
{
|
||||
reference: `urn:uuid:${findCondition(resourceStorage).id}` //Condition
|
||||
|
@ -384,6 +415,98 @@ function resourceCreateMedicationToR4MedicationRequest(resourceStorage: Resource
|
|||
return resourceStorage
|
||||
}
|
||||
|
||||
function resourceAttachmentToR4DocumentReference(resourceStorage: ResourceStorage, resourceAttachment: ResourceCreateAttachment): ResourceStorage {
|
||||
|
||||
resourceStorage['DocumentReference'] = resourceStorage['DocumentReference'] || {}
|
||||
|
||||
let documentReferenceResource = {
|
||||
id: resourceAttachment.id,
|
||||
resourceType: 'DocumentReference',
|
||||
status: 'current',
|
||||
category: [
|
||||
{
|
||||
coding: resourceAttachment.category.identifier || [],
|
||||
text: resourceAttachment.category.text,
|
||||
}
|
||||
],
|
||||
// description: resourceAttachment.description,
|
||||
subject: {
|
||||
reference: `urn:uuid:${findPatient(resourceStorage).id}` //Patient
|
||||
},
|
||||
content: [
|
||||
{
|
||||
attachment: {
|
||||
contentType: resourceAttachment.file_type,
|
||||
data: resourceAttachment.file_content,
|
||||
title: resourceAttachment.name,
|
||||
}
|
||||
}
|
||||
],
|
||||
context: [
|
||||
{
|
||||
related: [
|
||||
{
|
||||
reference: `urn:uuid:${findCondition(resourceStorage).id}` //Condition
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
// date: `${new Date(resourceDocumentReference.date.year,resourceDocumentReference.date.month-1,resourceDocumentReference.date.day).toISOString()}`,
|
||||
} as DocumentReference
|
||||
resourceStorage['DocumentReference'][documentReferenceResource.id] = documentReferenceResource
|
||||
|
||||
//TODO create Binary object?
|
||||
|
||||
return resourceStorage
|
||||
}
|
||||
|
||||
function resourceAttachmentToR4DiagnosticReport(resourceStorage: ResourceStorage, resourceAttachment: ResourceCreateAttachment): ResourceStorage {
|
||||
resourceStorage['Media'] = resourceStorage['Media'] || {}
|
||||
|
||||
let mediaResource = {
|
||||
id: uuidV4(),
|
||||
resourceType: 'Media',
|
||||
status: 'completed',
|
||||
type: {
|
||||
coding: resourceAttachment.category.identifier || [],
|
||||
display: resourceAttachment.category.text,
|
||||
},
|
||||
subject: {
|
||||
reference: `urn:uuid:${findPatient(resourceStorage).id}` //Patient
|
||||
},
|
||||
content: {
|
||||
contentType: resourceAttachment.file_type,
|
||||
data: resourceAttachment.file_content,
|
||||
title: resourceAttachment.name,
|
||||
},
|
||||
} as Media
|
||||
resourceStorage['Media'][mediaResource.id] = mediaResource
|
||||
|
||||
resourceStorage['DiagnosticReport'] = resourceStorage['DiagnosticReport'] || {}
|
||||
let diagnosticReportResource = {
|
||||
id: resourceAttachment.id,
|
||||
resourceType: 'DiagnosticReport',
|
||||
status: 'final',
|
||||
code: {
|
||||
coding: resourceAttachment.category.identifier || [],
|
||||
},
|
||||
subject: {
|
||||
reference: `urn:uuid:${findPatient(resourceStorage).id}` //Patient
|
||||
},
|
||||
media: [
|
||||
{
|
||||
link: {
|
||||
reference: `urn:uuid:${mediaResource.id}` //Media
|
||||
}
|
||||
},
|
||||
],
|
||||
} as DiagnosticReport
|
||||
resourceStorage['DiagnosticReport'][diagnosticReportResource.id] = diagnosticReportResource
|
||||
|
||||
return resourceStorage
|
||||
}
|
||||
|
||||
|
||||
function findCondition(resourceStorage: ResourceStorage): Condition {
|
||||
let [conditionId] = Object.keys(resourceStorage['Condition'])
|
||||
return resourceStorage['Condition'][conditionId] as Condition
|
||||
|
|
|
@ -1242,4 +1242,247 @@ export class NlmClinicalTableSearchService {
|
|||
);
|
||||
}
|
||||
|
||||
|
||||
searchAttachmentFileType(searchTerm: string): Observable<NlmSearchResults[]> {
|
||||
let searchOptions: NlmSearchResults[] = [
|
||||
{
|
||||
id: "application/json",
|
||||
text: "Document - JSON"
|
||||
},
|
||||
{
|
||||
id: "text/markdown",
|
||||
text: "Document - Markdown"
|
||||
},
|
||||
{
|
||||
id: "application/pdf",
|
||||
text: "Document - PDF"
|
||||
},
|
||||
{
|
||||
id: "application/dicom",
|
||||
text: "Image - DICOM"
|
||||
},
|
||||
{
|
||||
id: "text/csv",
|
||||
text: "Document - CSV"
|
||||
},
|
||||
{
|
||||
id: "image/png",
|
||||
text: "Image - PNG"
|
||||
},
|
||||
{
|
||||
id: "image/jpeg",
|
||||
text: "Image - JPEG"
|
||||
},
|
||||
{
|
||||
id: "text/plain",
|
||||
text: "Document - Plain Text"
|
||||
},
|
||||
|
||||
]
|
||||
let result = searchTerm.length == 0 ? searchOptions : searchOptions.filter((v) => v['text'].toLowerCase().indexOf(searchTerm.toLowerCase()) > -1).slice(0, 10)
|
||||
return of(result)
|
||||
}
|
||||
|
||||
//https://build.fhir.org/valueset-referenced-item-category.html
|
||||
searchAttachmentCategory(searchTerm: string): Observable<NlmSearchResults[]> {
|
||||
|
||||
|
||||
//https://tx.fhir.org/r4/ValueSet/$expand?_format=json&filter=Referral&url=http://hl7.org/fhir/ValueSet/document-classcodes
|
||||
let queryParams = {
|
||||
'_format': 'json',
|
||||
'filter':searchTerm,
|
||||
'url': 'http://hl7.org/fhir/ValueSet/document-classcodes'
|
||||
}
|
||||
|
||||
return this._httpClient.get<any>(`https://tx.fhir.org/r4/ValueSet/$expand`, {params: queryParams})
|
||||
.pipe(
|
||||
map((response) => {
|
||||
|
||||
return (response.expansion.contains || []).map((valueSetItem):NlmSearchResults => {
|
||||
return {
|
||||
id: valueSetItem.code,
|
||||
identifier: [valueSetItem],
|
||||
text: valueSetItem.display,
|
||||
}
|
||||
})
|
||||
})
|
||||
)
|
||||
|
||||
// let searchOptions: NlmSearchResults[] = [
|
||||
// {
|
||||
// id: "image",
|
||||
// identifier: [{
|
||||
// code: "image",
|
||||
// display: "Image",
|
||||
// system: "http://terminology.hl7.org/CodeSystem/media-category"
|
||||
// }],
|
||||
// text: "Image"
|
||||
// },
|
||||
// {
|
||||
// id: "11485-0",
|
||||
// identifier: [{
|
||||
// code: "11485-0",
|
||||
// display: "Anesthesia records",
|
||||
// system: "http://loinc.org"
|
||||
// }],
|
||||
// text: "Anesthesia records"
|
||||
// },
|
||||
// {
|
||||
// id: "11488-4",
|
||||
// identifier: [{
|
||||
// code: "11488-4",
|
||||
// display: "Consult note",
|
||||
// system: "http://loinc.org"
|
||||
// }],
|
||||
// text: "Consult note"
|
||||
// },
|
||||
// {
|
||||
// id: "11490-0",
|
||||
// identifier: [{
|
||||
// code: "11490-0",
|
||||
// display: "Physician Discharge summary",
|
||||
// system: "http://loinc.org"
|
||||
// }],
|
||||
// text: "Physician Discharge summary"
|
||||
// },
|
||||
// {
|
||||
// id: "11502-2",
|
||||
// identifier: [{
|
||||
// code: "11502-2",
|
||||
// display: "Laboratory report",
|
||||
// system: "http://loinc.org"
|
||||
// }],
|
||||
// text: "Laboratory report"
|
||||
// },
|
||||
// {
|
||||
// id: "11504-8",
|
||||
// identifier: [{
|
||||
// code: "11504-8",
|
||||
// display: "Surgical operation note",
|
||||
// system: "http://loinc.org"
|
||||
// }],
|
||||
// text: "Surgical operation note"
|
||||
// },
|
||||
// {
|
||||
// id: "11506-3",
|
||||
// identifier: [{
|
||||
// code: "11506-3",
|
||||
// display: "Progress note",
|
||||
// system: "http://loinc.org"
|
||||
// }],
|
||||
// text: "Progress note"
|
||||
// },
|
||||
// {
|
||||
// id: "11505-5",
|
||||
// identifier: [{
|
||||
// code: "11505-5",
|
||||
// display: "Physician procedure note",
|
||||
// system: "http://loinc.org"
|
||||
// }],
|
||||
// text: "Physician procedure note"
|
||||
// },
|
||||
// {
|
||||
// id: "11524-6",
|
||||
// identifier: [{
|
||||
// code: "11524-6",
|
||||
// display: "EKG study",
|
||||
// system: "http://loinc.org"
|
||||
// }],
|
||||
// text: "EKG study"
|
||||
// },
|
||||
// {
|
||||
// id: "11526-1",
|
||||
// identifier: [{
|
||||
// code: "11526-1",
|
||||
// display: "Pathology study",
|
||||
// system: "http://loinc.org"
|
||||
// }],
|
||||
// text: "Pathology study"
|
||||
// },
|
||||
// {
|
||||
// id: "11527-9",
|
||||
// identifier: [{
|
||||
// code: "11527-9",
|
||||
// display: "Psychiatry study",
|
||||
// system: "http://loinc.org"
|
||||
// }],
|
||||
// text: "Psychiatry study"
|
||||
// },
|
||||
// {
|
||||
// id: "11543-6",
|
||||
// identifier: [{
|
||||
// code: "11543-6",
|
||||
// display: "Nursery records",
|
||||
// system: "http://loinc.org"
|
||||
// }],
|
||||
// text: "Nursery records"
|
||||
// },
|
||||
// {
|
||||
// id: "11543-6",
|
||||
// identifier: [{
|
||||
// code: "11543-6",
|
||||
// display: "Nursery records",
|
||||
// system: "http://loinc.org"
|
||||
// }],
|
||||
// text: "Nursery records"
|
||||
// },
|
||||
// {
|
||||
// id: "15508-5",
|
||||
// identifier: [{
|
||||
// code: "15508-5",
|
||||
// display: "Labor and delivery records",
|
||||
// system: "http://loinc.org"
|
||||
// }],
|
||||
// text: "Labor and delivery records"
|
||||
// },
|
||||
// {
|
||||
// id: "18682-5",
|
||||
// identifier: [{
|
||||
// code: "18682-5",
|
||||
// display: "Ambulance records",
|
||||
// system: "http://loinc.org"
|
||||
// }],
|
||||
// text: "Ambulance records"
|
||||
// },
|
||||
// {
|
||||
// id: "18748-4",
|
||||
// identifier: [{
|
||||
// code: "18748-4",
|
||||
// display: "Diagnostic imaging study",
|
||||
// system: "http://loinc.org"
|
||||
// }],
|
||||
// text: "Diagnostic imaging study"
|
||||
// },
|
||||
// {
|
||||
// id: "18761-7",
|
||||
// identifier: [{
|
||||
// code: "18761-7",
|
||||
// display: "Transfer summary note",
|
||||
// system: "http://loinc.org"
|
||||
// }],
|
||||
// text: "Transfer summary note"
|
||||
// },
|
||||
// {
|
||||
// id: "18776-5",
|
||||
// identifier: [{
|
||||
// code: "18776-5",
|
||||
// display: "Plan of care note",
|
||||
// system: "http://loinc.org"
|
||||
// }],
|
||||
// text: "Plan of care note"
|
||||
// },
|
||||
// {
|
||||
// id: "18776-5",
|
||||
// identifier: [{
|
||||
// code: "18776-5",
|
||||
// display: "Plan of care note",
|
||||
// system: "http://loinc.org"
|
||||
// }],
|
||||
// text: "Plan of care note"
|
||||
// }
|
||||
// ]
|
||||
// let result = searchTerm.length == 0 ? searchOptions : searchOptions.filter((v) => v['text'].toLowerCase().indexOf(searchTerm.toLowerCase()) > -1).slice(0, 10)
|
||||
// return of(result)
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -188,3 +188,19 @@ select > optgroup > .divider {
|
|||
}
|
||||
|
||||
|
||||
// ng-select/select2 styles
|
||||
|
||||
ng-select.ng-select-form-control {
|
||||
.ng-select-container {
|
||||
border-radius: 0px;
|
||||
height: 38px;
|
||||
}
|
||||
}
|
||||
|
||||
//ngTypeAhead
|
||||
app-nlm-typeahead {
|
||||
.dropdown-menu.show {
|
||||
max-height: 350px;
|
||||
overflow-y: scroll;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,22 +5,20 @@ import {ReferenceModel} from '../datatypes/reference-model';
|
|||
import {CodingModel} from '../datatypes/coding-model';
|
||||
import {FastenDisplayModel} from '../fasten/fasten-display-model';
|
||||
import {FastenOptions} from '../fasten/fasten-options';
|
||||
import {Attachment} from 'fhir/r4';
|
||||
import {BinaryModel} from './binary-model';
|
||||
|
||||
export class DocumentReferenceModel extends FastenDisplayModel {
|
||||
|
||||
description: string | undefined
|
||||
status: string | undefined
|
||||
category: CodableConceptModel | undefined
|
||||
doc_status: string | undefined
|
||||
type_coding: CodingModel | undefined
|
||||
class_coding: CodingModel | undefined
|
||||
created_at: string | undefined
|
||||
security_label_coding: CodingModel | undefined
|
||||
content: {
|
||||
url: string
|
||||
isUrlBinaryResourceReference: boolean
|
||||
size: string
|
||||
formatCoding: CodingModel
|
||||
} | undefined
|
||||
content: BinaryModel[] | undefined
|
||||
context: {
|
||||
eventCoding: CodingModel
|
||||
facilityTypeCoding: CodingModel
|
||||
|
@ -79,47 +77,12 @@ export class DocumentReferenceModel extends FastenDisplayModel {
|
|||
};
|
||||
|
||||
contentDTO(fhirResource: any, fhirVersion: fhirVersions){
|
||||
this.content = _.get(fhirResource, 'content', []).map((item:any) => {
|
||||
const attachmentUrl = _.get(item, 'attachment.url');
|
||||
let url = attachmentUrl;
|
||||
let isUrlBinaryResourceReference = false;
|
||||
|
||||
// Check if URL ends with "/Binary/someId". If so, swap the url for this reference, and change the flag to render different component.
|
||||
// For now raw link to the resource won't open properly, so it's better to show more valuable info for the user.
|
||||
const regex = /\/(Binary\/[\w-]+$)/gm;
|
||||
// @ts-ignore
|
||||
const matches = Array.from(attachmentUrl.matchAll(regex), m => m[1]);
|
||||
if (matches.length > 0) {
|
||||
url = matches[0];
|
||||
isUrlBinaryResourceReference = true;
|
||||
}
|
||||
|
||||
const size = _.get(item, 'attachment.size');
|
||||
|
||||
let formatCoding = null;
|
||||
switch (fhirVersion) {
|
||||
case fhirVersions.DSTU2: {
|
||||
formatCoding = _.get(item, 'format[0]');
|
||||
break;
|
||||
}
|
||||
case fhirVersions.STU3: {
|
||||
formatCoding = _.get(item, 'format');
|
||||
break;
|
||||
}
|
||||
case fhirVersions.R4: {
|
||||
formatCoding = _.get(item, 'format');
|
||||
break;
|
||||
}
|
||||
default:
|
||||
throw Error('Unrecognized the fhir version property type.');
|
||||
}
|
||||
|
||||
return {
|
||||
url,
|
||||
isUrlBinaryResourceReference,
|
||||
size,
|
||||
formatCoding,
|
||||
};
|
||||
console.log('INSIDE CONTENTDTO', fhirResource)
|
||||
this.category = new CodableConceptModel(_.get(fhirResource, 'category[0]') || {});
|
||||
this.content = _.get(fhirResource, 'content', []).map((content: any) => {
|
||||
const attachment: Attachment = _.get(content, 'attachment');
|
||||
const binaryModel = new BinaryModel(attachment, fhirVersion);
|
||||
return binaryModel;
|
||||
})
|
||||
};
|
||||
|
||||
|
@ -127,19 +90,19 @@ export class DocumentReferenceModel extends FastenDisplayModel {
|
|||
switch (fhirVersion) {
|
||||
case fhirVersions.DSTU2: {
|
||||
this.commonDTO(fhirResource)
|
||||
this.contentDTO(fhirVersion, fhirResource)
|
||||
this.contentDTO(fhirResource,fhirVersion)
|
||||
this.dstu2DTO(fhirResource)
|
||||
return
|
||||
}
|
||||
case fhirVersions.STU3: {
|
||||
this.commonDTO(fhirResource)
|
||||
this.contentDTO(fhirVersion, fhirResource)
|
||||
this.contentDTO(fhirResource,fhirVersion)
|
||||
this.stu3DTO(fhirResource)
|
||||
return
|
||||
}
|
||||
case fhirVersions.R4: {
|
||||
this.commonDTO(fhirResource)
|
||||
this.contentDTO(fhirVersion, fhirResource)
|
||||
this.contentDTO(fhirResource,fhirVersion)
|
||||
this.r4DTO(fhirResource)
|
||||
return
|
||||
}
|
||||
|
|
|
@ -215,5 +215,6 @@
|
|||
@import '~@swimlane/ngx-datatable/assets/icons.css';
|
||||
@import '~@circlon/angular-tree-component/css/angular-tree-component.css';
|
||||
@import '~highlight.js/styles/github.css';
|
||||
@import "~@ng-select/ng-select/themes/default.theme.css";
|
||||
|
||||
@import 'custom';
|
||||
|
|
|
@ -1500,6 +1500,13 @@
|
|||
dependencies:
|
||||
tslib "^2.1.0"
|
||||
|
||||
"@ng-select/ng-select@9.1.0":
|
||||
version "9.1.0"
|
||||
resolved "https://registry.npmjs.org/@ng-select/ng-select/-/ng-select-9.1.0.tgz#c400ea3e90c4dd2e7966e830fcf7d025ea0343fa"
|
||||
integrity sha512-vxSRD2d84H39eqtTJaethlpQ+xkJUU8epQNUr3yPiah23z8MBCqSDE1t0chxi+rXJz7+xoC9qFa1aYnUVFan4w==
|
||||
dependencies:
|
||||
tslib "^2.3.1"
|
||||
|
||||
"@ngtools/webpack@14.2.10":
|
||||
version "14.2.10"
|
||||
resolved "https://registry.npmjs.org/@ngtools/webpack/-/webpack-14.2.10.tgz#d33ff1147d01bd1f5d936a3d1744c81a28e2ca6a"
|
||||
|
@ -7216,6 +7223,11 @@ tslib@^2.0.0, tslib@^2.1.0, tslib@^2.3.0, tslib@^2.4.0:
|
|||
resolved "https://registry.npmjs.org/tslib/-/tslib-2.4.1.tgz#0d0bfbaac2880b91e22df0768e55be9753a5b17e"
|
||||
integrity sha512-tGyy4dAjRIEwI7BzsB0lynWgOpfqjUdq91XXAlIWD2OwKBH7oCl/GZG/HT4BOHrTlPMOASlMQ7veyTqpmRcrNA==
|
||||
|
||||
tslib@^2.3.1:
|
||||
version "2.5.0"
|
||||
resolved "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz#42bfed86f5787aeb41d031866c8f402429e0fddf"
|
||||
integrity sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==
|
||||
|
||||
tslint@~6.1.0:
|
||||
version "6.1.3"
|
||||
resolved "https://registry.npmjs.org/tslint/-/tslint-6.1.3.tgz#5c23b2eccc32487d5523bd3a470e9aa31789d904"
|
||||
|
|
Loading…
Reference in New Issue