diff --git a/backend/pkg/web/handler/dashboard/testing.json b/backend/pkg/web/handler/dashboard/testing.json new file mode 100644 index 00000000..ab2cdf60 --- /dev/null +++ b/backend/pkg/web/handler/dashboard/testing.json @@ -0,0 +1,17 @@ +{ + "id": "updated", + "schema_version": "1.0", + "title": "Updated Dashboard", + "description": "An example dashboard to show-off the power of Fasten widgets", + "widgets": [ + { + "title_text": "Records Summary", + "description_text": "Track key metrics for your chronic disease (eg. Diabetes). The data within this widget is not reflective of your health record, and is only present for demonstrational purposes.", + "x": 0, + "y": 0, + "width": 8, + "height": 6, + "item_type": "records-summary-widget" + } + ] +} diff --git a/frontend/src/app/components/gridstack/gridstack.component.ts b/frontend/src/app/components/gridstack/gridstack.component.ts index 940b178d..b0dc1e32 100644 --- a/frontend/src/app/components/gridstack/gridstack.component.ts +++ b/frontend/src/app/components/gridstack/gridstack.component.ts @@ -11,15 +11,7 @@ import { GridHTMLElement, GridItemHTMLElement, GridStack, GridStackNode, GridSta import { GridItemCompHTMLElement, GridstackItemComponent } from './gridstack-item.component'; import {CommonModule} from '@angular/common'; -import {WidgetsModule} from '../../widgets/widgets.module'; -import {ComplexLineWidgetComponent} from '../../widgets/complex-line-widget/complex-line-widget.component'; -import {DashboardWidgetComponent} from '../../widgets/dashboard-widget/dashboard-widget.component'; -import {DonutChartWidgetComponent} from '../../widgets/donut-chart-widget/donut-chart-widget.component'; -import {DualGaugesWidgetComponent} from '../../widgets/dual-gauges-widget/dual-gauges-widget.component'; -import {GroupedBarChartWidgetComponent} from '../../widgets/grouped-bar-chart-widget/grouped-bar-chart-widget.component'; -import {PatientVitalsWidgetComponent} from '../../widgets/patient-vitals-widget/patient-vitals-widget.component'; -import {SimpleLineChartWidgetComponent} from '../../widgets/simple-line-chart-widget/simple-line-chart-widget.component'; -import {TableWidgetComponent} from '../../widgets/table-widget/table-widget.component'; +import {WidgetsModule, WidgetComponents} from '../../widgets/widgets.module'; import {DashboardWidgetComponentInterface} from '../../widgets/dashboard-widget-component-interface'; /** events handlers emitters signature for different events */ @@ -137,16 +129,7 @@ export class GridstackComponent implements OnInit, AfterContentInit, OnDestroy { ) { // register all our dynamic components created in the grid - GridstackComponent.addComponentToSelectorType([ - ComplexLineWidgetComponent, - DashboardWidgetComponent, - DonutChartWidgetComponent, - DualGaugesWidgetComponent, - GroupedBarChartWidgetComponent, - PatientVitalsWidgetComponent, - SimpleLineChartWidgetComponent, - TableWidgetComponent, - ]); + GridstackComponent.addComponentToSelectorType(WidgetComponents()); // set globally our method to create the right widget type GridStack.addRemoveCB = gsCreateNgComponents; GridStack.saveCB = gsSaveAdditionalNgInfo; diff --git a/frontend/src/app/models/widget/dashboard-widget-config.ts b/frontend/src/app/models/widget/dashboard-widget-config.ts index 0f0fed36..7fa94a47 100644 --- a/frontend/src/app/models/widget/dashboard-widget-config.ts +++ b/frontend/src/app/models/widget/dashboard-widget-config.ts @@ -3,7 +3,7 @@ import * as _ from 'lodash'; export class DashboardWidgetConfig { id?: string - item_type: "complex-line-widget" | "donut-chart-widget" | "dual-gauges-widget" | "grouped-bar-chart-widget" | "patient-vitals-widget" | "simple-line-chart-widget" | "table-widget" + item_type: "complex-line-widget" | "donut-chart-widget" | "dual-gauges-widget" | "grouped-bar-chart-widget" | "patient-vitals-widget" | "simple-line-chart-widget" | "table-widget" | "records-summary-widget" title_text: string description_text: string diff --git a/frontend/src/app/widgets/records-summary-widget/records-summary-widget.component.html b/frontend/src/app/widgets/records-summary-widget/records-summary-widget.component.html new file mode 100644 index 00000000..6efe2a8e --- /dev/null +++ b/frontend/src/app/widgets/records-summary-widget/records-summary-widget.component.html @@ -0,0 +1,185 @@ + + + + + + + + + + + +
+
+
Medical Records
+
+
+ +
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
Allergies
+
+
7
+ Records +
+
+
+
Clinical Notes
+
+
85
+ Records +
+
+
+
Care Plans
+ Appointments
Medical Conditions
Health Goals
Orders
+
+
83
+ Records +
+
+
+
Care Team
+ Primary Care Provider
Provider Details
+
+
8
+ Records +
+
+
+
Demographic Information
+
+
3
+ Records +
+
+
+
Lab Results
+
+
3
+ Records +
+
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
Health Goals
+
+
2
+ Records +
+
+
+
Health Issues
+ Conditions +
+
6
+ Records +
+
+
+
Immunizations
+
+
9
+ Records +
+
+
+
Implants
+
+
22
+ Records +
+
+
+
Medications
+
+
22
+ Records +
+
+
+
Procedures
+
+
22
+ Records +
+
+
+
+
+
+
diff --git a/frontend/src/app/widgets/records-summary-widget/records-summary-widget.component.scss b/frontend/src/app/widgets/records-summary-widget/records-summary-widget.component.scss new file mode 100644 index 00000000..e69de29b diff --git a/frontend/src/app/widgets/records-summary-widget/records-summary-widget.component.spec.ts b/frontend/src/app/widgets/records-summary-widget/records-summary-widget.component.spec.ts new file mode 100644 index 00000000..45cbf865 --- /dev/null +++ b/frontend/src/app/widgets/records-summary-widget/records-summary-widget.component.spec.ts @@ -0,0 +1,23 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { RecordsSummaryWidgetComponent } from './records-summary-widget.component'; + +describe('RecordsSummaryWidgetComponent', () => { + let component: RecordsSummaryWidgetComponent; + let fixture: ComponentFixture; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + declarations: [ RecordsSummaryWidgetComponent ] + }) + .compileComponents(); + + fixture = TestBed.createComponent(RecordsSummaryWidgetComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/frontend/src/app/widgets/records-summary-widget/records-summary-widget.component.ts b/frontend/src/app/widgets/records-summary-widget/records-summary-widget.component.ts new file mode 100644 index 00000000..7f66ab5f --- /dev/null +++ b/frontend/src/app/widgets/records-summary-widget/records-summary-widget.component.ts @@ -0,0 +1,38 @@ +import { Component, OnInit } from '@angular/core'; +import {NgChartsModule} from 'ng2-charts'; +import {CommonModule} from '@angular/common'; +import {MomentModule} from 'ngx-moment'; +import {LoadingWidgetComponent} from '../loading-widget/loading-widget.component'; +import {EmptyWidgetComponent} from '../empty-widget/empty-widget.component'; +import {DashboardWidgetComponent} from '../dashboard-widget/dashboard-widget.component'; +import {DashboardWidgetConfig} from '../../models/widget/dashboard-widget-config'; + +@Component({ + standalone: true, + imports: [CommonModule, LoadingWidgetComponent, EmptyWidgetComponent], + selector: 'records-summary-widget', + templateUrl: './records-summary-widget.component.html', + styleUrls: ['./records-summary-widget.component.scss'] +}) +export class RecordsSummaryWidgetComponent extends DashboardWidgetComponent implements OnInit { + + // constructor() { } + + ngOnInit(): void { + //manually define the widget config, rather than pull from the configuration file + this.widgetConfig = { + id: 'records-summary-widget', + item_type: 'records-summary-widget', + description_text: 'Displays a summary of patient records', + width: 4, + height: 5, + title_text: 'Medical Records', + queries: [] + + } as DashboardWidgetConfig + super.ngOnInit(); + this.loading = false + this.isEmpty = false + } + +} diff --git a/frontend/src/app/widgets/records-summary-widget/records-summary-widget.stories.ts b/frontend/src/app/widgets/records-summary-widget/records-summary-widget.stories.ts new file mode 100644 index 00000000..ba19076c --- /dev/null +++ b/frontend/src/app/widgets/records-summary-widget/records-summary-widget.stories.ts @@ -0,0 +1,50 @@ +import type { Meta, StoryObj } from '@storybook/angular'; +import {RecordsSummaryWidgetComponent} from './records-summary-widget.component'; +import {applicationConfig, moduleMetadata} from '@storybook/angular'; +import {HttpClient, HttpClientModule} from '@angular/common/http'; +import {HTTP_CLIENT_TOKEN} from '../../dependency-injection'; +import {importProvidersFrom} from '@angular/core'; +import {CommonModule} from '@angular/common'; + +// More on how to set up stories at: https://storybook.js.org/docs/angular/writing-stories/introduction +const meta: Meta = { + title: 'Widget/RecordsSummaryWidget', + component: RecordsSummaryWidgetComponent, + decorators: [ + applicationConfig({ + providers: [ + { + provide: HttpClient, + useClass: HttpClient + }, + { + provide: HTTP_CLIENT_TOKEN, + useClass: HttpClient, + }, + importProvidersFrom(HttpClientModule) + ] + }), + moduleMetadata({ + imports: [CommonModule, HttpClientModule], + }) + ], + tags: ['autodocs'], + render: (args: RecordsSummaryWidgetComponent) => ({ + props: { + backgroundColor: null, + ...args, + }, + }), + argTypes: { + }, +}; + +export default meta; +type Story = StoryObj; + +// More on writing stories with args: https://storybook.js.org/docs/angular/writing-stories/args +export const Example: Story = { + args: { + } +}; + diff --git a/frontend/src/app/widgets/widgets.module.ts b/frontend/src/app/widgets/widgets.module.ts index 61aaae00..ff941ada 100644 --- a/frontend/src/app/widgets/widgets.module.ts +++ b/frontend/src/app/widgets/widgets.module.ts @@ -1,4 +1,4 @@ -import { NgModule } from '@angular/core'; +import {Component, NgModule, Type} from '@angular/core'; import {ComplexLineWidgetComponent} from './complex-line-widget/complex-line-widget.component'; import {DonutChartWidgetComponent} from './donut-chart-widget/donut-chart-widget.component'; import {DualGaugesWidgetComponent} from './dual-gauges-widget/dual-gauges-widget.component'; @@ -9,6 +9,7 @@ import {TableWidgetComponent} from './table-widget/table-widget.component'; import { LoadingWidgetComponent } from './loading-widget/loading-widget.component'; import { EmptyWidgetComponent } from './empty-widget/empty-widget.component'; import {DashboardWidgetComponent} from './dashboard-widget/dashboard-widget.component'; +import { RecordsSummaryWidgetComponent } from './records-summary-widget/records-summary-widget.component'; @NgModule({ imports: [ @@ -18,13 +19,15 @@ import {DashboardWidgetComponent} from './dashboard-widget/dashboard-widget.comp DualGaugesWidgetComponent, GroupedBarChartWidgetComponent, PatientVitalsWidgetComponent, + RecordsSummaryWidgetComponent, SimpleLineChartWidgetComponent, TableWidgetComponent, LoadingWidgetComponent, EmptyWidgetComponent ], - declarations: [], + declarations: [ + ], exports: [ //standalone components ComplexLineWidgetComponent, @@ -32,6 +35,7 @@ import {DashboardWidgetComponent} from './dashboard-widget/dashboard-widget.comp DualGaugesWidgetComponent, GroupedBarChartWidgetComponent, PatientVitalsWidgetComponent, + RecordsSummaryWidgetComponent, SimpleLineChartWidgetComponent, TableWidgetComponent, LoadingWidgetComponent, @@ -41,3 +45,20 @@ import {DashboardWidgetComponent} from './dashboard-widget/dashboard-widget.comp }) export class WidgetsModule { } + +//when adding widgets to this list, you must also register the widget id in +// frontend/src/app/models/widget/dashboard-widget-config.ts +export function WidgetComponents(): Type[] { + return [ + ComplexLineWidgetComponent, + DonutChartWidgetComponent, + DualGaugesWidgetComponent, + GroupedBarChartWidgetComponent, + PatientVitalsWidgetComponent, + RecordsSummaryWidgetComponent, + SimpleLineChartWidgetComponent, + TableWidgetComponent, + LoadingWidgetComponent, + EmptyWidgetComponent + ] +} diff --git a/frontend/src/assets/icons/allergies.svg b/frontend/src/assets/icons/allergies.svg new file mode 100644 index 00000000..91afa991 --- /dev/null +++ b/frontend/src/assets/icons/allergies.svg @@ -0,0 +1,41 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/frontend/src/assets/icons/careplans.svg b/frontend/src/assets/icons/careplans.svg new file mode 100644 index 00000000..54606699 --- /dev/null +++ b/frontend/src/assets/icons/careplans.svg @@ -0,0 +1,26 @@ + + + + + + + + + + + + + + diff --git a/frontend/src/assets/icons/careteam.svg b/frontend/src/assets/icons/careteam.svg new file mode 100644 index 00000000..0682ff46 --- /dev/null +++ b/frontend/src/assets/icons/careteam.svg @@ -0,0 +1,40 @@ + + + + + + + + + + + + + + + + diff --git a/frontend/src/assets/icons/clinicalnotes.svg b/frontend/src/assets/icons/clinicalnotes.svg new file mode 100644 index 00000000..b6e568f1 --- /dev/null +++ b/frontend/src/assets/icons/clinicalnotes.svg @@ -0,0 +1,48 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/frontend/src/assets/icons/conditions.svg b/frontend/src/assets/icons/conditions.svg new file mode 100644 index 00000000..16c1e624 --- /dev/null +++ b/frontend/src/assets/icons/conditions.svg @@ -0,0 +1,45 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/frontend/src/assets/icons/demographics.svg b/frontend/src/assets/icons/demographics.svg new file mode 100644 index 00000000..58659850 --- /dev/null +++ b/frontend/src/assets/icons/demographics.svg @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + + + + diff --git a/frontend/src/assets/icons/healthgoals.svg b/frontend/src/assets/icons/healthgoals.svg new file mode 100644 index 00000000..54606699 --- /dev/null +++ b/frontend/src/assets/icons/healthgoals.svg @@ -0,0 +1,26 @@ + + + + + + + + + + + + + + diff --git a/frontend/src/assets/icons/immunizations.svg b/frontend/src/assets/icons/immunizations.svg new file mode 100644 index 00000000..7962104f --- /dev/null +++ b/frontend/src/assets/icons/immunizations.svg @@ -0,0 +1,29 @@ + + + + + + + + + + + + + + + + + diff --git a/frontend/src/assets/icons/implants.svg b/frontend/src/assets/icons/implants.svg new file mode 100644 index 00000000..7e2e9f57 --- /dev/null +++ b/frontend/src/assets/icons/implants.svg @@ -0,0 +1,25 @@ + + + + + + + + + + + + + diff --git a/frontend/src/assets/icons/labresults.svg b/frontend/src/assets/icons/labresults.svg new file mode 100644 index 00000000..316eba2f --- /dev/null +++ b/frontend/src/assets/icons/labresults.svg @@ -0,0 +1,29 @@ + + + + + + + + + + + + + diff --git a/frontend/src/assets/icons/medications.svg b/frontend/src/assets/icons/medications.svg new file mode 100644 index 00000000..86ba60fc --- /dev/null +++ b/frontend/src/assets/icons/medications.svg @@ -0,0 +1,24 @@ + + + + + + + + + + + + + + + + diff --git a/frontend/src/assets/icons/procedures.svg b/frontend/src/assets/icons/procedures.svg new file mode 100644 index 00000000..6bdd9345 --- /dev/null +++ b/frontend/src/assets/icons/procedures.svg @@ -0,0 +1,17 @@ + + + + + + + + + diff --git a/frontend/src/assets/icons/proxyinformation.svg b/frontend/src/assets/icons/proxyinformation.svg new file mode 100644 index 00000000..49685a4d --- /dev/null +++ b/frontend/src/assets/icons/proxyinformation.svg @@ -0,0 +1,27 @@ + + + + + + + + + + + + + + + diff --git a/frontend/src/assets/icons/visits.svg b/frontend/src/assets/icons/visits.svg new file mode 100644 index 00000000..08450155 --- /dev/null +++ b/frontend/src/assets/icons/visits.svg @@ -0,0 +1,24 @@ + + + + + + + + + + + + diff --git a/frontend/src/assets/icons/vitalsigns.svg b/frontend/src/assets/icons/vitalsigns.svg new file mode 100644 index 00000000..4e4f7ece --- /dev/null +++ b/frontend/src/assets/icons/vitalsigns.svg @@ -0,0 +1,33 @@ + + + + + + + + + + + + +