sort all resources by "sort_date" column during query
return units when querying rename all usages of "source" page to "explore" adding new explore page. fix dashboard widgets to correctly
This commit is contained in:
parent
28cb91817a
commit
0397a2f0cb
|
@ -113,6 +113,7 @@ func (sr *SqliteRepository) QueryResources(ctx context.Context, query models.Que
|
||||||
Select(fmt.Sprintf("%s.*", TABLE_ALIAS)).
|
Select(fmt.Sprintf("%s.*", TABLE_ALIAS)).
|
||||||
Where(strings.Join(whereClauses, " AND "), whereNamedParameters).
|
Where(strings.Join(whereClauses, " AND "), whereNamedParameters).
|
||||||
Group(fmt.Sprintf("%s.id", TABLE_ALIAS)).
|
Group(fmt.Sprintf("%s.id", TABLE_ALIAS)).
|
||||||
|
Order(fmt.Sprintf("%s.sort_date asc", TABLE_ALIAS)).
|
||||||
Table(strings.Join(fromClauses, ", ")).
|
Table(strings.Join(fromClauses, ", ")).
|
||||||
Find(&results)
|
Find(&results)
|
||||||
|
|
||||||
|
|
|
@ -25,6 +25,7 @@
|
||||||
"q": {
|
"q": {
|
||||||
"select": [
|
"select": [
|
||||||
"valueQuantity.value as data",
|
"valueQuantity.value as data",
|
||||||
|
"valueQuantity.unit as unit",
|
||||||
"(effectiveDateTime | issued).first() as label"
|
"(effectiveDateTime | issued).first() as label"
|
||||||
],
|
],
|
||||||
"from": "Observation",
|
"from": "Observation",
|
||||||
|
@ -50,6 +51,7 @@
|
||||||
"q": {
|
"q": {
|
||||||
"select": [
|
"select": [
|
||||||
"valueQuantity.value as data",
|
"valueQuantity.value as data",
|
||||||
|
"valueQuantity.unit as unit",
|
||||||
"(effectiveDateTime | issued).first() as label"
|
"(effectiveDateTime | issued).first() as label"
|
||||||
],
|
],
|
||||||
"from": "Observation",
|
"from": "Observation",
|
||||||
|
@ -75,7 +77,8 @@
|
||||||
{
|
{
|
||||||
"q": {
|
"q": {
|
||||||
"select": [
|
"select": [
|
||||||
"component.where(code.coding.system = 'http://loinc.org' and code.coding.code = '8462-4').valueQuantity.value as data"
|
"component.where(code.coding.system = 'http://loinc.org' and code.coding.code = '8462-4').valueQuantity.value as data",
|
||||||
|
"component.where(code.coding.system = 'http://loinc.org' and code.coding.code = '8462-4').valueQuantity.unit as unit"
|
||||||
],
|
],
|
||||||
"from": "Observation",
|
"from": "Observation",
|
||||||
"where": {
|
"where": {
|
||||||
|
@ -89,7 +92,8 @@
|
||||||
{
|
{
|
||||||
"q": {
|
"q": {
|
||||||
"select": [
|
"select": [
|
||||||
"component.where(code.coding.system = 'http://loinc.org' and code.coding.code = '8480-6').valueQuantity.value as data"
|
"component.where(code.coding.system = 'http://loinc.org' and code.coding.code = '8480-6').valueQuantity.value as data",
|
||||||
|
"component.where(code.coding.system = 'http://loinc.org' and code.coding.code = '8480-6').valueQuantity.unit as unit"
|
||||||
],
|
],
|
||||||
"from": "Observation",
|
"from": "Observation",
|
||||||
"where": {
|
"where": {
|
||||||
|
|
|
@ -13,6 +13,7 @@ import {PatientProfileComponent} from './pages/patient-profile/patient-profile.c
|
||||||
import {MedicalHistoryComponent} from './pages/medical-history/medical-history.component';
|
import {MedicalHistoryComponent} from './pages/medical-history/medical-history.component';
|
||||||
import {ReportLabsComponent} from './pages/report-labs/report-labs.component';
|
import {ReportLabsComponent} from './pages/report-labs/report-labs.component';
|
||||||
import {ResourceCreatorComponent} from './pages/resource-creator/resource-creator.component';
|
import {ResourceCreatorComponent} from './pages/resource-creator/resource-creator.component';
|
||||||
|
import {ExploreComponent} from './pages/explore/explore.component';
|
||||||
|
|
||||||
const routes: Routes = [
|
const routes: Routes = [
|
||||||
|
|
||||||
|
@ -23,9 +24,13 @@ const routes: Routes = [
|
||||||
|
|
||||||
{ path: '', redirectTo: '/dashboard', pathMatch: 'full' },
|
{ path: '', redirectTo: '/dashboard', pathMatch: 'full' },
|
||||||
{ path: 'dashboard', component: DashboardComponent, canActivate: [ IsAuthenticatedAuthGuard] },
|
{ path: 'dashboard', component: DashboardComponent, canActivate: [ IsAuthenticatedAuthGuard] },
|
||||||
{ path: 'source/:source_id', component: SourceDetailComponent, canActivate: [ IsAuthenticatedAuthGuard] },
|
|
||||||
{ path: 'source/:source_id/resource/:resource_id', component: ResourceDetailComponent, canActivate: [ IsAuthenticatedAuthGuard] },
|
//explore page will replace source/* pages
|
||||||
{ path: 'source/:source_id/resource/:resource_type/:resource_id', component: ResourceDetailComponent, canActivate: [ IsAuthenticatedAuthGuard] },
|
{ path: 'explore', component: ExploreComponent, canActivate: [ IsAuthenticatedAuthGuard] },
|
||||||
|
{ path: 'explore/:source_id', component: SourceDetailComponent, canActivate: [ IsAuthenticatedAuthGuard] },
|
||||||
|
{ path: 'explore/:source_id/resource/:resource_id', component: ResourceDetailComponent, canActivate: [ IsAuthenticatedAuthGuard] },
|
||||||
|
{ path: 'explore/:source_id/resource/:resource_type/:resource_id', component: ResourceDetailComponent, canActivate: [ IsAuthenticatedAuthGuard] },
|
||||||
|
|
||||||
{ path: 'sources', component: MedicalSourcesComponent, canActivate: [ IsAuthenticatedAuthGuard] },
|
{ path: 'sources', component: MedicalSourcesComponent, canActivate: [ IsAuthenticatedAuthGuard] },
|
||||||
{ path: 'sources/callback/:source_type', component: MedicalSourcesComponent, canActivate: [ IsAuthenticatedAuthGuard] },
|
{ path: 'sources/callback/:source_type', component: MedicalSourcesComponent, canActivate: [ IsAuthenticatedAuthGuard] },
|
||||||
{ path: 'resource/create', component: ResourceCreatorComponent, canActivate: [ IsAuthenticatedAuthGuard] },
|
{ path: 'resource/create', component: ResourceCreatorComponent, canActivate: [ IsAuthenticatedAuthGuard] },
|
||||||
|
|
|
@ -34,6 +34,7 @@ import { InfiniteScrollModule } from 'ngx-infinite-scroll';
|
||||||
import { NgSelectModule } from '@ng-select/ng-select';
|
import { NgSelectModule } from '@ng-select/ng-select';
|
||||||
import {HTTP_CLIENT_TOKEN} from "./dependency-injection";
|
import {HTTP_CLIENT_TOKEN} from "./dependency-injection";
|
||||||
import {WidgetsModule} from './widgets/widgets.module';
|
import {WidgetsModule} from './widgets/widgets.module';
|
||||||
|
import { ExploreComponent } from './pages/explore/explore.component';
|
||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
declarations: [
|
declarations: [
|
||||||
|
@ -50,6 +51,7 @@ import {WidgetsModule} from './widgets/widgets.module';
|
||||||
MedicalHistoryComponent,
|
MedicalHistoryComponent,
|
||||||
ReportLabsComponent,
|
ReportLabsComponent,
|
||||||
ResourceCreatorComponent,
|
ResourceCreatorComponent,
|
||||||
|
ExploreComponent,
|
||||||
],
|
],
|
||||||
imports: [
|
imports: [
|
||||||
FormsModule,
|
FormsModule,
|
||||||
|
|
|
@ -19,7 +19,7 @@
|
||||||
<fhir-coding *ngFor="let coding of rowItem.data" [coding]="coding"></fhir-coding>
|
<fhir-coding *ngFor="let coding of rowItem.data" [coding]="coding"></fhir-coding>
|
||||||
</ng-template>
|
</ng-template>
|
||||||
<ng-template #dataTypeReference>
|
<ng-template #dataTypeReference>
|
||||||
<a routerLink="/source/{{displayModel.source_id}}/resource/{{rowItem.data.reference}}">{{rowItem.data.display}}</a>
|
<a routerLink="/explore/{{displayModel.source_id}}/resource/{{rowItem.data.reference}}">{{rowItem.data.display}}</a>
|
||||||
</ng-template>
|
</ng-template>
|
||||||
<ng-template #dataTypeString>{{rowItem.data}}</ng-template>
|
<ng-template #dataTypeString>{{rowItem.data}}</ng-template>
|
||||||
</td>
|
</td>
|
||||||
|
|
|
@ -11,6 +11,6 @@
|
||||||
<fhir-ui-table [displayModel]="displayModel" [tableData]="tableData"></fhir-ui-table>
|
<fhir-ui-table [displayModel]="displayModel" [tableData]="tableData"></fhir-ui-table>
|
||||||
</div>
|
</div>
|
||||||
<div *ngIf="showDetails" class="card-footer">
|
<div *ngIf="showDetails" class="card-footer">
|
||||||
<a class="float-right" routerLink="/source/{{displayModel?.source_id}}/resource/{{displayModel?.source_resource_id}}">details</a>
|
<a class="float-right" routerLink="/explore/{{displayModel?.source_id}}/resource/{{displayModel?.source_resource_id}}">details</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -16,7 +16,7 @@
|
||||||
<fhir-ui-table [displayModel]="displayModel" [tableData]="tableData"></fhir-ui-table>
|
<fhir-ui-table [displayModel]="displayModel" [tableData]="tableData"></fhir-ui-table>
|
||||||
</div>
|
</div>
|
||||||
<div *ngIf="showDetails" class="card-footer">
|
<div *ngIf="showDetails" class="card-footer">
|
||||||
<a class="float-right" routerLink="/source/{{displayModel?.source_id}}/resource/{{displayModel?.source_resource_id}}">details</a>
|
<a class="float-right" routerLink="/explore/{{displayModel?.source_id}}/resource/{{displayModel?.source_resource_id}}">details</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
|
@ -20,6 +20,6 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div *ngIf="showDetails" class="card-footer">
|
<div *ngIf="showDetails" class="card-footer">
|
||||||
<a class="float-right" routerLink="/source/{{displayModel?.source_id}}/resource/{{displayModel?.source_resource_id}}">details</a>
|
<a class="float-right" routerLink="/explore/{{displayModel?.source_id}}/resource/{{displayModel?.source_resource_id}}">details</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -16,6 +16,6 @@
|
||||||
<fhir-ui-table [displayModel]="displayModel" [tableData]="tableData"></fhir-ui-table>
|
<fhir-ui-table [displayModel]="displayModel" [tableData]="tableData"></fhir-ui-table>
|
||||||
</div>
|
</div>
|
||||||
<div *ngIf="showDetails" class="card-footer">
|
<div *ngIf="showDetails" class="card-footer">
|
||||||
<a class="float-right" routerLink="/source/{{displayModel?.source_id}}/resource/{{displayModel?.source_resource_id}}">details</a>
|
<a class="float-right" routerLink="/explore/{{displayModel?.source_id}}/resource/{{displayModel?.source_resource_id}}">details</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -20,6 +20,6 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div *ngIf="showDetails" class="card-footer">
|
<div *ngIf="showDetails" class="card-footer">
|
||||||
<a class="float-right" routerLink="/source/{{displayModel?.source_id}}/resource/{{displayModel?.source_resource_id}}">details</a>
|
<a class="float-right" routerLink="/explore/{{displayModel?.source_id}}/resource/{{displayModel?.source_resource_id}}">details</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -16,7 +16,7 @@
|
||||||
<fhir-ui-table [displayModel]="displayModel" [tableData]="tableData"></fhir-ui-table>
|
<fhir-ui-table [displayModel]="displayModel" [tableData]="tableData"></fhir-ui-table>
|
||||||
</div>
|
</div>
|
||||||
<div *ngIf="showDetails" class="card-footer">
|
<div *ngIf="showDetails" class="card-footer">
|
||||||
<a class="float-right" routerLink="/source/{{displayModel?.source_id}}/resource/{{displayModel?.source_resource_id}}">details</a>
|
<a class="float-right" routerLink="/explore/{{displayModel?.source_id}}/resource/{{displayModel?.source_resource_id}}">details</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
|
@ -16,7 +16,7 @@
|
||||||
<fhir-ui-table [displayModel]="displayModel" [tableData]="tableData"></fhir-ui-table>
|
<fhir-ui-table [displayModel]="displayModel" [tableData]="tableData"></fhir-ui-table>
|
||||||
</div>
|
</div>
|
||||||
<div *ngIf="showDetails" class="card-footer">
|
<div *ngIf="showDetails" class="card-footer">
|
||||||
<a class="float-right" routerLink="/source/{{displayModel?.source_id}}/resource/{{displayModel?.source_resource_id}}">details</a>
|
<a class="float-right" routerLink="/explore/{{displayModel?.source_id}}/resource/{{displayModel?.source_resource_id}}">details</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
|
@ -16,6 +16,6 @@
|
||||||
<fhir-ui-table [displayModel]="displayModel" [tableData]="tableData"></fhir-ui-table>
|
<fhir-ui-table [displayModel]="displayModel" [tableData]="tableData"></fhir-ui-table>
|
||||||
</div>
|
</div>
|
||||||
<div *ngIf="showDetails" class="card-footer">
|
<div *ngIf="showDetails" class="card-footer">
|
||||||
<a class="float-right" routerLink="/source/{{displayModel?.source_id}}/resource/{{displayModel?.source_resource_id}}">details</a>
|
<a class="float-right" routerLink="/explore/{{displayModel?.source_id}}/resource/{{displayModel?.source_resource_id}}">details</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -16,7 +16,7 @@
|
||||||
<fhir-ui-table [displayModel]="displayModel" [tableData]="tableData"></fhir-ui-table>
|
<fhir-ui-table [displayModel]="displayModel" [tableData]="tableData"></fhir-ui-table>
|
||||||
</div>
|
</div>
|
||||||
<div *ngIf="showDetails" class="card-footer">
|
<div *ngIf="showDetails" class="card-footer">
|
||||||
<a class="float-right" routerLink="/source/{{displayModel?.source_id}}/resource/{{displayModel?.source_resource_id}}">details</a>
|
<a class="float-right" routerLink="/explore/{{displayModel?.source_id}}/resource/{{displayModel?.source_resource_id}}">details</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
<div class="row" >
|
<div class="row" >
|
||||||
<!-- Condition Header -->
|
<!-- Condition Header -->
|
||||||
<div class="col-6">
|
<div class="col-6">
|
||||||
<span routerLink="/source/{{firstObservation?.source_id}}/resource/{{firstObservation?.source_resource_id}}">{{observationTitle}}</span>
|
<span routerLink="/explore/{{firstObservation?.source_id}}/resource/{{firstObservation?.source_resource_id}}">{{observationTitle}}</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-6">
|
<div class="col-6">
|
||||||
{{firstObservation | fhirPath: "Observation.effectiveDateTime": "Observation.issued" | date}}
|
{{firstObservation | fhirPath: "Observation.effectiveDateTime": "Observation.issued" | date}}
|
||||||
|
@ -36,7 +36,7 @@
|
||||||
<div #collapse="ngbCollapse" [ngbCollapse]="true">
|
<div #collapse="ngbCollapse" [ngbCollapse]="true">
|
||||||
|
|
||||||
<ul>
|
<ul>
|
||||||
<li class="cursor-pointer tx-indigo" *ngFor="let observation of observations" routerLink="/source/{{observation?.source_id}}/resource/{{observation?.source_resource_id}}">Observation: {{observation | fhirPath: "Observation.effectiveDateTime": "Observation.issued" | date}}</li>
|
<li class="cursor-pointer tx-indigo" *ngFor="let observation of observations" routerLink="/explore/{{observation?.source_id}}/resource/{{observation?.source_resource_id}}">Observation: {{observation | fhirPath: "Observation.effectiveDateTime": "Observation.issued" | date}}</li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
|
@ -76,7 +76,7 @@ export class DashboardComponent implements OnInit {
|
||||||
}
|
}
|
||||||
|
|
||||||
selectSource(selectedSource: Source){
|
selectSource(selectedSource: Source){
|
||||||
this.router.navigateByUrl(`/source/${selectedSource.id}`, {
|
this.router.navigateByUrl(`/explore/${selectedSource.id}`, {
|
||||||
state: selectedSource
|
state: selectedSource
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,73 @@
|
||||||
|
<div class="az-content">
|
||||||
|
<div class="container">
|
||||||
|
<div class="az-content-body pd-lg-l-40 d-flex flex-column">
|
||||||
|
|
||||||
|
<!-- Header Row -->
|
||||||
|
<report-header [reportHeaderTitle]="'Explore'" [reportHeaderSubTitle]="'Explore your Medical Records'"></report-header>
|
||||||
|
|
||||||
|
<ng-container [ngTemplateOutlet]="loading ? isLoadingTemplate : (connectedSources.length == 0) ? emptyReport : report"></ng-container>
|
||||||
|
|
||||||
|
<ng-template #report>
|
||||||
|
<div class="row">
|
||||||
|
<app-medical-sources-card class="col-sm-3 mg-b-20 px-3"
|
||||||
|
*ngFor="let sourceData of connectedSources"
|
||||||
|
[sourceInfo]="sourceData"
|
||||||
|
(onClick)="exploreSource($event)"
|
||||||
|
></app-medical-sources-card>
|
||||||
|
</div>
|
||||||
|
</ng-template>
|
||||||
|
|
||||||
|
<ng-template #emptyReport>
|
||||||
|
<div class="d-flex align-items-center" style="height:100%">
|
||||||
|
<div class="modal-body tx-center pd-y-20 pd-x-20">
|
||||||
|
<h4 class="tx-purple mg-b-20">No Sources Found!</h4>
|
||||||
|
<p class="mg-b-20 mg-x-20">
|
||||||
|
Fasten was unable to find any connected sources. You will need to connect a medical source before you can use this page.
|
||||||
|
</p>
|
||||||
|
<p class="mg-b-20 mg-x-20">
|
||||||
|
Click below to add a new healthcare provider to Fasten.
|
||||||
|
</p>
|
||||||
|
<button [routerLink]="'/sources'" type="button" class="btn btn-purple pd-x-25">Add Source</button>
|
||||||
|
<button [routerLink]="'/resource/create'" type="button" class="btn btn-purple mg-l-10 pd-x-25">Add Condition</button>
|
||||||
|
|
||||||
|
</div><!-- modal-body -->
|
||||||
|
</div>
|
||||||
|
</ng-template>
|
||||||
|
|
||||||
|
<ng-template #isLoadingTemplate>
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-12">
|
||||||
|
<app-loading-spinner [loadingTitle]="'Please wait, loading report...'"></app-loading-spinner>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</ng-template>
|
||||||
|
|
||||||
|
<ng-template #contentModalRef let-modal>
|
||||||
|
<div class="modal-header">
|
||||||
|
<h4 class="modal-title" id="modal-basic-title"></h4>
|
||||||
|
<button type="button" class="btn btn-close" aria-label="Close" (click)="modal.dismiss('Cross click')">
|
||||||
|
<span aria-hidden="true">×</span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="modal-body">
|
||||||
|
<h6>Manage Source</h6>
|
||||||
|
<p>Existing connections can be "Synced", "Reconnected" or "Deleted"</p>
|
||||||
|
<ul>
|
||||||
|
<li><p><strong>Sync</strong> - Download all resources from this healthcare provider, storing them securely in Fasten</p></li>
|
||||||
|
<li><p><strong>Reconnect</strong> - If your healthcare connection has expired, you can use this button to reconnect</p></li>
|
||||||
|
<li><p><strong>Delete</strong> - Delete all resources for this healthcare provider. This will ONLY effect data stored in Fasten</p></li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="modal-footer">
|
||||||
|
<!-- <button (click)="sourceSyncHandler(modalSelectedSourceListItem.source)" type="button" class="btn btn-indigo">Sync</button>-->
|
||||||
|
<!-- <button (click)="connectHandler($event, modalSelectedSourceListItem.source['source_type'])" type="button" class="btn btn-outline-light">Reconnect</button>-->
|
||||||
|
<button type="button" class="btn disabled btn-outline-danger">Delete</button>
|
||||||
|
<button (click)="modal.dismiss('Close click')" type="button" class="btn btn-outline-light">Close</button>
|
||||||
|
</div>
|
||||||
|
</ng-template>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
|
@ -0,0 +1,23 @@
|
||||||
|
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||||
|
|
||||||
|
import { ExploreComponent } from './explore.component';
|
||||||
|
|
||||||
|
describe('ExploreComponent', () => {
|
||||||
|
let component: ExploreComponent;
|
||||||
|
let fixture: ComponentFixture<ExploreComponent>;
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
await TestBed.configureTestingModule({
|
||||||
|
declarations: [ ExploreComponent ]
|
||||||
|
})
|
||||||
|
.compileComponents();
|
||||||
|
|
||||||
|
fixture = TestBed.createComponent(ExploreComponent);
|
||||||
|
component = fixture.componentInstance;
|
||||||
|
fixture.detectChanges();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should create', () => {
|
||||||
|
expect(component).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
|
@ -0,0 +1,62 @@
|
||||||
|
import { Component, OnInit } from '@angular/core';
|
||||||
|
import {FastenApiService} from '../../services/fasten-api.service';
|
||||||
|
import {NgbModal} from '@ng-bootstrap/ng-bootstrap';
|
||||||
|
import {Source} from '../../models/fasten/source';
|
||||||
|
import {forkJoin} from 'rxjs';
|
||||||
|
import {LighthouseService} from '../../services/lighthouse.service';
|
||||||
|
import {SourceListItem} from '../medical-sources/medical-sources.component';
|
||||||
|
import {Router} from '@angular/router';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-explore',
|
||||||
|
templateUrl: './explore.component.html',
|
||||||
|
styleUrls: ['./explore.component.scss']
|
||||||
|
})
|
||||||
|
export class ExploreComponent implements OnInit {
|
||||||
|
loading: boolean = false
|
||||||
|
connectedSources: SourceListItem[] = []
|
||||||
|
constructor(
|
||||||
|
private fastenApi: FastenApiService,
|
||||||
|
private lighthouseApi: LighthouseService,
|
||||||
|
private router: Router
|
||||||
|
) { }
|
||||||
|
|
||||||
|
ngOnInit(): void {
|
||||||
|
this.loading = true
|
||||||
|
this.fastenApi.getSources().subscribe(results => {
|
||||||
|
this.loading = false
|
||||||
|
|
||||||
|
//handle connected sources sources
|
||||||
|
const connectedSources = results as Source[]
|
||||||
|
forkJoin(connectedSources.map((source) => this.lighthouseApi.getLighthouseSource(source.source_type))).subscribe((connectedMetadata) => {
|
||||||
|
for(const ndx in connectedSources){
|
||||||
|
this.connectedSources.push({source: connectedSources[ndx], metadata: connectedMetadata[ndx]})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}, error => {
|
||||||
|
this.loading = false
|
||||||
|
})
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public exploreSource(sourceListItem: SourceListItem, ) {
|
||||||
|
this.router.navigateByUrl(`/source/${sourceListItem.source.id}`, {
|
||||||
|
state: sourceListItem.source
|
||||||
|
});
|
||||||
|
|
||||||
|
// if(this.status[sourceListItem.metadata.source_type] || !sourceListItem.source){
|
||||||
|
// //if this source is currently "loading" dont open the modal window
|
||||||
|
// return
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// this.modalSelectedSourceListItem = sourceListItem
|
||||||
|
// this.modalService.open(contentModalRef, {ariaLabelledBy: 'modal-basic-title'}).result.then((result) => {
|
||||||
|
// this.modalSelectedSourceListItem = null
|
||||||
|
// this.modalCloseResult = `Closed with: ${result}`;
|
||||||
|
// }, (reason) => {
|
||||||
|
// this.modalSelectedSourceListItem = null
|
||||||
|
// this.modalCloseResult = `Dismissed ${this.getDismissReason(reason)}`;
|
||||||
|
// });
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -2,7 +2,7 @@
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<div class="az-content-body">
|
<div class="az-content-body">
|
||||||
<div class="az-content-breadcrumb">
|
<div class="az-content-breadcrumb">
|
||||||
<span class="cursor-pointer" routerLink="/source/{{sourceId}}">{{sourceName}}</span>
|
<span class="cursor-pointer" routerLink="/explore/{{sourceId}}">{{sourceName}}</span>
|
||||||
<span>Resource</span>
|
<span>Resource</span>
|
||||||
<span>{{resource?.source_resource_type}}</span>
|
<span>{{resource?.source_resource_type}}</span>
|
||||||
<span>{{resource?.source_resource_id}}</span>
|
<span>{{resource?.source_resource_id}}</span>
|
||||||
|
|
|
@ -18,7 +18,7 @@
|
||||||
<div class="patient-row row">
|
<div class="patient-row row">
|
||||||
<div class="col-7 patient-name"><h3 class="pull-left text-primary">{{getPatientName()}}</h3></div>
|
<div class="col-7 patient-name"><h3 class="pull-left text-primary">{{getPatientName()}}</h3></div>
|
||||||
<div class="col-5">
|
<div class="col-5">
|
||||||
<a routerLink="/source/{{selectedSource?.id}}/resource/{{selectedPatient?.source_resource_id}}" class="btn btn-indigo btn-icon float-right">
|
<a routerLink="/explore/{{selectedSource?.id}}/resource/{{selectedPatient?.source_resource_id}}" class="btn btn-indigo btn-icon float-right">
|
||||||
<i class="fas fa-info-circle"></i>
|
<i class="fas fa-info-circle"></i>
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -0,0 +1,8 @@
|
||||||
|
import { DatasetLatestEntryPipe } from './dataset-latest-entry.pipe';
|
||||||
|
|
||||||
|
describe('DatasetLatestEntryPipe', () => {
|
||||||
|
it('create an instance', () => {
|
||||||
|
const pipe = new DatasetLatestEntryPipe();
|
||||||
|
expect(pipe).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
|
@ -0,0 +1,44 @@
|
||||||
|
import { Pipe, PipeTransform } from '@angular/core';
|
||||||
|
import {ChartDataset} from 'chart.js';
|
||||||
|
import * as _ from 'lodash';
|
||||||
|
|
||||||
|
@Pipe({
|
||||||
|
name: 'datasetLatestEntry'
|
||||||
|
})
|
||||||
|
export class DatasetLatestEntryPipe implements PipeTransform {
|
||||||
|
|
||||||
|
transform(dataset: ChartDataset<'line'>, round?: number, valLookupKey?: string, unitLookupKey?: string): string {
|
||||||
|
if(!round){
|
||||||
|
round = 0 //round to nearest whole number
|
||||||
|
}
|
||||||
|
let lastItem = dataset?.data?.[dataset?.data?.length -1] || ''
|
||||||
|
// let valueKey = this.chartOptions?.parsing?.['yAxisKey'] || dataset?.parsing?.['key']
|
||||||
|
console.log('latestEntryConfig', lastItem, valLookupKey, unitLookupKey, round)
|
||||||
|
let lastItemUnit = ""
|
||||||
|
let lastItemValue
|
||||||
|
|
||||||
|
if(Array.isArray(lastItem)){
|
||||||
|
lastItemValue = _.flatten(lastItem?.[0]?.[valLookupKey])?.[0] as string
|
||||||
|
lastItemUnit = _.flatten(lastItem?.[0]?.[unitLookupKey])?.[0] as string
|
||||||
|
} else if(typeof lastItem === 'object'){
|
||||||
|
console.log('lastItem-object', lastItem?.[valLookupKey])
|
||||||
|
lastItemValue = lastItem?.[valLookupKey]
|
||||||
|
lastItemUnit = lastItem?.[unitLookupKey]
|
||||||
|
} else {
|
||||||
|
//do nothing
|
||||||
|
}
|
||||||
|
|
||||||
|
lastItemValue = this.roundToDecimalPlaces(lastItemValue, round)
|
||||||
|
if(lastItemUnit){
|
||||||
|
return lastItemValue + ' ' + lastItemUnit
|
||||||
|
} else {
|
||||||
|
return lastItemValue.toString()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
roundToDecimalPlaces(value: string, decimalPlaces: number): string {
|
||||||
|
return parseFloat(value).toFixed(decimalPlaces).toString()
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -5,6 +5,7 @@ import { NgModule } from '@angular/core';
|
||||||
import {FhirPathPipe} from './fhir-path.pipe';
|
import {FhirPathPipe} from './fhir-path.pipe';
|
||||||
import {FilterPipe} from './filter.pipe';
|
import {FilterPipe} from './filter.pipe';
|
||||||
import { ShortDomainPipe } from './short-domain.pipe';
|
import { ShortDomainPipe } from './short-domain.pipe';
|
||||||
|
import { DatasetLatestEntryPipe } from './dataset-latest-entry.pipe';
|
||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
declarations: [
|
declarations: [
|
||||||
|
@ -12,6 +13,7 @@ import { ShortDomainPipe } from './short-domain.pipe';
|
||||||
FhirPathPipe,
|
FhirPathPipe,
|
||||||
FilterPipe,
|
FilterPipe,
|
||||||
ShortDomainPipe,
|
ShortDomainPipe,
|
||||||
|
DatasetLatestEntryPipe,
|
||||||
],
|
],
|
||||||
imports: [
|
imports: [
|
||||||
|
|
||||||
|
@ -19,7 +21,8 @@ import { ShortDomainPipe } from './short-domain.pipe';
|
||||||
exports: [
|
exports: [
|
||||||
FhirPathPipe,
|
FhirPathPipe,
|
||||||
FilterPipe,
|
FilterPipe,
|
||||||
ShortDomainPipe
|
ShortDomainPipe,
|
||||||
|
DatasetLatestEntryPipe
|
||||||
]
|
]
|
||||||
})
|
})
|
||||||
export class PipesModule {}
|
export class PipesModule {}
|
||||||
|
|
|
@ -121,26 +121,6 @@ export class DashboardWidgetComponent implements OnInit, DashboardWidgetComponen
|
||||||
console.log(`Loading COmpleted for ${this.widgetConfig.title_text}, ${this.loading}`)
|
console.log(`Loading COmpleted for ${this.widgetConfig.title_text}, ${this.loading}`)
|
||||||
}
|
}
|
||||||
|
|
||||||
getLastDatasetValue(dataset: ChartDataset<'line'>): string {
|
|
||||||
let lastItem = dataset?.data?.[dataset?.data?.length -1] || ''
|
|
||||||
let valueKey = this.chartOptions?.parsing?.['yAxisKey'] || dataset?.parsing?.['key']
|
|
||||||
console.log('current', lastItem, valueKey)
|
|
||||||
|
|
||||||
if(typeof lastItem === 'string'){
|
|
||||||
console.log('lastItem-string', lastItem)
|
|
||||||
return lastItem
|
|
||||||
} else if(Array.isArray(lastItem)){
|
|
||||||
|
|
||||||
return _.flatten(lastItem?.[0]?.[valueKey])?.[0] as string
|
|
||||||
} else if(typeof lastItem === 'object'){
|
|
||||||
console.log('lastItem-object', lastItem?.[valueKey])
|
|
||||||
return lastItem?.[valueKey]
|
|
||||||
} else {
|
|
||||||
return lastItem.toString()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// This function will process the raw response from the Dashboard Query API call, which requires frontend processing of the select clause.
|
// This function will process the raw response from the Dashboard Query API call, which requires frontend processing of the select clause.
|
||||||
// it will call the fhirPathMapQueryFn which will extract FHIRPath values from the resource_raw field of the ResourceFhir object
|
// it will call the fhirPathMapQueryFn which will extract FHIRPath values from the resource_raw field of the ResourceFhir object
|
||||||
|
|
|
@ -12,7 +12,7 @@
|
||||||
<div class="card card-dashboard-three h-100">
|
<div class="card card-dashboard-three h-100">
|
||||||
<div class="card-header">
|
<div class="card-header">
|
||||||
<p>{{widgetConfig.title_text}}</p>
|
<p>{{widgetConfig.title_text}}</p>
|
||||||
<h6>120/80 <small class="tx-success"><i class="icon ion-md-arrow-up"></i>mmHg</small></h6>
|
<h6>{{chartDatasets?.[0] | datasetLatestEntry: 0:'data' }}/{{chartDatasets?.[1] | datasetLatestEntry: 0:'data' }} <small class="tx-success"><i class="icon ion-md-arrow-up"></i>mmHg</small></h6>
|
||||||
<small>{{widgetConfig.description_text}}</small>
|
<small>{{widgetConfig.description_text}}</small>
|
||||||
</div><!-- card-header -->
|
</div><!-- card-header -->
|
||||||
<div class="card-body d-flex flex-column">
|
<div class="card-body d-flex flex-column">
|
||||||
|
|
|
@ -5,10 +5,11 @@ import {DashboardWidgetComponent} from '../dashboard-widget/dashboard-widget.com
|
||||||
import {CommonModule} from '@angular/common';
|
import {CommonModule} from '@angular/common';
|
||||||
import {LoadingWidgetComponent} from '../loading-widget/loading-widget.component';
|
import {LoadingWidgetComponent} from '../loading-widget/loading-widget.component';
|
||||||
import {EmptyWidgetComponent} from '../empty-widget/empty-widget.component';
|
import {EmptyWidgetComponent} from '../empty-widget/empty-widget.component';
|
||||||
|
import {PipesModule} from '../../pipes/pipes.module';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
standalone: true,
|
standalone: true,
|
||||||
imports: [NgChartsModule, CommonModule, LoadingWidgetComponent, EmptyWidgetComponent],
|
imports: [NgChartsModule, CommonModule, LoadingWidgetComponent, EmptyWidgetComponent, PipesModule],
|
||||||
selector: 'grouped-bar-chart-widget',
|
selector: 'grouped-bar-chart-widget',
|
||||||
templateUrl: './grouped-bar-chart-widget.component.html',
|
templateUrl: './grouped-bar-chart-widget.component.html',
|
||||||
styleUrls: ['./grouped-bar-chart-widget.component.scss']
|
styleUrls: ['./grouped-bar-chart-widget.component.scss']
|
||||||
|
|
|
@ -11,7 +11,7 @@
|
||||||
<ng-template #showChart>
|
<ng-template #showChart>
|
||||||
<div class="card card-dashboard-two h-100">
|
<div class="card card-dashboard-two h-100">
|
||||||
<div class="card-header">
|
<div class="card-header">
|
||||||
<h6>{{getLastDatasetValue(chartDatasets?.[0])}} kg <i class="icon ion-md-trending-up tx-success"></i> <small>18.02%</small></h6>
|
<h6>{{chartDatasets?.[0] | datasetLatestEntry: 2:'data':'unit' }} <i class="icon ion-md-trending-up tx-success"></i> <small>18.02%</small></h6>
|
||||||
<p>{{widgetConfig?.title_text}}</p>
|
<p>{{widgetConfig?.title_text}}</p>
|
||||||
</div><!-- card-header -->
|
</div><!-- card-header -->
|
||||||
<div class="card-body d-flex flex-column">
|
<div class="card-body d-flex flex-column">
|
||||||
|
|
|
@ -7,10 +7,11 @@ import {ChartConfiguration, ChartDataset, ChartOptions} from 'chart.js';
|
||||||
import {CommonModule} from '@angular/common';
|
import {CommonModule} from '@angular/common';
|
||||||
import {LoadingWidgetComponent} from '../loading-widget/loading-widget.component';
|
import {LoadingWidgetComponent} from '../loading-widget/loading-widget.component';
|
||||||
import {EmptyWidgetComponent} from '../empty-widget/empty-widget.component';
|
import {EmptyWidgetComponent} from '../empty-widget/empty-widget.component';
|
||||||
|
import {PipesModule} from '../../pipes/pipes.module';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
standalone: true,
|
standalone: true,
|
||||||
imports: [NgChartsModule, CommonModule, LoadingWidgetComponent, EmptyWidgetComponent],
|
imports: [NgChartsModule, CommonModule, LoadingWidgetComponent, EmptyWidgetComponent, PipesModule],
|
||||||
selector: 'simple-line-chart-widget',
|
selector: 'simple-line-chart-widget',
|
||||||
templateUrl: './simple-line-chart-widget.component.html',
|
templateUrl: './simple-line-chart-widget.component.html',
|
||||||
styleUrls: ['./simple-line-chart-widget.component.scss']
|
styleUrls: ['./simple-line-chart-widget.component.scss']
|
||||||
|
|
Loading…
Reference in New Issue