diff --git a/projects/components/src/public-api.ts b/projects/components/src/public-api.ts index da39c78a1..83055bbf9 100644 --- a/projects/components/src/public-api.ts +++ b/projects/components/src/public-api.ts @@ -81,10 +81,6 @@ export * from './filtering/filter-modal/in-filter-modal.component'; // Filter Parser export * from './filtering/filter/parser/filter-parser-lookup.service'; -// Gauge -export * from './gauge/gauge.component'; -export * from './gauge/gauge.module'; - // Header export * from './header/application/application-header.component'; export * from './header/application/application-header.module'; diff --git a/projects/observability/src/public-api.ts b/projects/observability/src/public-api.ts index 259fe7d07..6eba4df62 100644 --- a/projects/observability/src/public-api.ts +++ b/projects/observability/src/public-api.ts @@ -210,3 +210,8 @@ export * from './shared/dashboard/data/graphql/specifiers/entity-specification.m // Explorer service export * from './pages/explorer/explorer-service'; + +// Gauge +export * from './shared/components/gauge/gauge.component'; +export * from './shared/components/gauge/gauge.module'; +export * from './shared/dashboard/widgets/gauge/gauge-widget'; diff --git a/projects/components/src/gauge/gauge.component.scss b/projects/observability/src/shared/components/gauge/gauge.component.scss similarity index 100% rename from projects/components/src/gauge/gauge.component.scss rename to projects/observability/src/shared/components/gauge/gauge.component.scss diff --git a/projects/components/src/gauge/gauge.component.test.ts b/projects/observability/src/shared/components/gauge/gauge.component.test.ts similarity index 100% rename from projects/components/src/gauge/gauge.component.test.ts rename to projects/observability/src/shared/components/gauge/gauge.component.test.ts diff --git a/projects/components/src/gauge/gauge.component.ts b/projects/observability/src/shared/components/gauge/gauge.component.ts similarity index 100% rename from projects/components/src/gauge/gauge.component.ts rename to projects/observability/src/shared/components/gauge/gauge.component.ts diff --git a/projects/components/src/gauge/gauge.module.ts b/projects/observability/src/shared/components/gauge/gauge.module.ts similarity index 74% rename from projects/components/src/gauge/gauge.module.ts rename to projects/observability/src/shared/components/gauge/gauge.module.ts index e06f8079d..5961c09c2 100644 --- a/projects/components/src/gauge/gauge.module.ts +++ b/projects/observability/src/shared/components/gauge/gauge.module.ts @@ -1,8 +1,7 @@ import { CommonModule } from '@angular/common'; import { NgModule } from '@angular/core'; import { FormattingModule } from '@hypertrace/common'; -import { LayoutChangeModule } from '../layout/layout-change.module'; -import { TooltipModule } from './../tooltip/tooltip.module'; +import { LayoutChangeModule, TooltipModule } from '@hypertrace/components'; import { GaugeComponent } from './gauge.component'; @NgModule({ diff --git a/projects/observability/src/shared/dashboard/widgets/gauge/gauge-widget-renderer.component.test.ts b/projects/observability/src/shared/dashboard/widgets/gauge/gauge-widget-renderer.component.test.ts new file mode 100644 index 000000000..43ff434ac --- /dev/null +++ b/projects/observability/src/shared/dashboard/widgets/gauge/gauge-widget-renderer.component.test.ts @@ -0,0 +1,67 @@ +import { Color, FormattingModule } from '@hypertrace/common'; +import { LoadAsyncModule, TitledContentComponent } from '@hypertrace/components'; +import { RENDERER_API } from '@hypertrace/hyperdash-angular'; +import { createComponentFactory } from '@ngneat/spectator/jest'; +import { MockComponent } from 'ng-mocks'; +import { EMPTY, of } from 'rxjs'; +import { GaugeComponent } from './../../../components/gauge/gauge.component'; +import { GaugeWidgetRendererComponent } from './gauge-widget-renderer.component'; +import { GaugeWidgetModel } from './gauge-widget.model'; + +describe('Gauge widget renderer component', () => { + let mockModel: Partial = {}; + const componentFactory = createComponentFactory({ + component: GaugeWidgetRendererComponent, + shallow: true, + imports: [FormattingModule, LoadAsyncModule], + providers: [ + { + provide: RENDERER_API, + useFactory: () => ({ + getTimeRange: jest.fn(), + model: mockModel, + change$: EMPTY, + dataRefresh$: EMPTY, + timeRangeChanged$: EMPTY + }) + } + ], + declarations: [MockComponent(GaugeComponent), MockComponent(TitledContentComponent)] + }); + + test('should render provided data with title', () => { + mockModel = { + title: 'Test title', + getData: jest.fn(() => + of({ + value: 5, + maxValue: 10, + thresholds: [ + { + start: 0, + end: 6, + label: 'Medium', + color: Color.Brown1 + } + ] + }) + ) + }; + + const spectator = componentFactory(); + expect(spectator.query(TitledContentComponent)!.title).toBe('TEST TITLE'); + + const gaugeComponent = spectator.query(GaugeComponent); + expect(gaugeComponent).toExist(); + expect(gaugeComponent!.value).toEqual(5); + expect(gaugeComponent!.maxValue).toEqual(10); + expect(gaugeComponent!.thresholds).toEqual([ + { + start: 0, + end: 6, + label: 'Medium', + color: Color.Brown1 + } + ]); + }); +}); diff --git a/projects/observability/src/shared/dashboard/widgets/gauge/gauge-widget-renderer.component.ts b/projects/observability/src/shared/dashboard/widgets/gauge/gauge-widget-renderer.component.ts new file mode 100644 index 000000000..b96a0e3ef --- /dev/null +++ b/projects/observability/src/shared/dashboard/widgets/gauge/gauge-widget-renderer.component.ts @@ -0,0 +1,27 @@ +import { ChangeDetectionStrategy, Component } from '@angular/core'; +import { WidgetRenderer } from '@hypertrace/dashboards'; +import { Renderer } from '@hypertrace/hyperdash'; +import { Observable } from 'rxjs'; +import { GaugeWidgetData } from './gauge-widget'; +import { GaugeWidgetModel } from './gauge-widget.model'; + +@Renderer({ modelClass: GaugeWidgetModel }) +@Component({ + selector: 'ht-gauge-widget-renderer', + changeDetection: ChangeDetectionStrategy.OnPush, + template: ` + + + + ` +}) +export class GaugeWidgetRendererComponent extends WidgetRenderer { + protected fetchData(): Observable { + return this.model.getData(); + } +} diff --git a/projects/observability/src/shared/dashboard/widgets/gauge/gauge-widget.model.test.ts b/projects/observability/src/shared/dashboard/widgets/gauge/gauge-widget.model.test.ts new file mode 100644 index 000000000..dc44f2d34 --- /dev/null +++ b/projects/observability/src/shared/dashboard/widgets/gauge/gauge-widget.model.test.ts @@ -0,0 +1,58 @@ +import { Color } from '@hypertrace/common'; +import { createModelFactory } from '@hypertrace/dashboards/testing'; +import { MODEL_PROPERTY_TYPES } from '@hypertrace/hyperdash-angular'; +import { runFakeRxjs } from '@hypertrace/test-utils'; +import { of } from 'rxjs'; +import { GaugeWidgetData } from './gauge-widget'; +import { GaugeWidgetModel } from './gauge-widget.model'; + +describe('Gauge widget model', () => { + test('uses colors from color map', () => { + const modelFactory = createModelFactory(); + + const data: GaugeWidgetData = { + value: 5, + maxValue: 10, + thresholds: [ + { + start: 0, + end: 6, + label: 'Medium', + color: Color.Brown1 + } + ] + }; + + const spectator = modelFactory(GaugeWidgetModel, { + api: { + getData: () => of(data) + }, + providers: [ + { + provide: MODEL_PROPERTY_TYPES, + useValue: [] + } + ], + properties: { + title: 'Test Title' + } + }); + + runFakeRxjs(({ expectObservable }) => { + expectObservable(spectator.model.getData()).toBe('(x|)', { + x: { + value: 5, + maxValue: 10, + thresholds: [ + { + start: 0, + end: 6, + label: 'Medium', + color: Color.Brown1 + } + ] + } + }); + }); + }); +}); diff --git a/projects/observability/src/shared/dashboard/widgets/gauge/gauge-widget.model.ts b/projects/observability/src/shared/dashboard/widgets/gauge/gauge-widget.model.ts new file mode 100644 index 000000000..c770ce3e3 --- /dev/null +++ b/projects/observability/src/shared/dashboard/widgets/gauge/gauge-widget.model.ts @@ -0,0 +1,22 @@ +import { Model, ModelApi, ModelProperty, STRING_PROPERTY } from '@hypertrace/hyperdash'; +import { ModelInject, MODEL_API } from '@hypertrace/hyperdash-angular'; +import { Observable } from 'rxjs'; +import { GaugeWidgetData } from './gauge-widget'; + +@Model({ + type: 'gauge-widget' +}) +export class GaugeWidgetModel { + @ModelProperty({ + key: 'title', + type: STRING_PROPERTY.type + }) + public title?: string; + + @ModelInject(MODEL_API) + private readonly api!: ModelApi; + + public getData(): Observable { + return this.api.getData(); + } +} diff --git a/projects/observability/src/shared/dashboard/widgets/gauge/gauge-widget.module.ts b/projects/observability/src/shared/dashboard/widgets/gauge/gauge-widget.module.ts new file mode 100644 index 000000000..7c2bfd43a --- /dev/null +++ b/projects/observability/src/shared/dashboard/widgets/gauge/gauge-widget.module.ts @@ -0,0 +1,24 @@ +import { CommonModule } from '@angular/common'; +import { NgModule } from '@angular/core'; +import { FormattingModule } from '@hypertrace/common'; +import { LoadAsyncModule, TitledContentModule } from '@hypertrace/components'; +import { DashboardCoreModule } from '@hypertrace/hyperdash-angular'; +import { GaugeModule } from '../../../components/gauge/gauge.module'; +import { GaugeWidgetRendererComponent } from './gauge-widget-renderer.component'; +import { GaugeWidgetModel } from './gauge-widget.model'; + +@NgModule({ + declarations: [GaugeWidgetRendererComponent], + imports: [ + DashboardCoreModule.with({ + models: [GaugeWidgetModel], + renderers: [GaugeWidgetRendererComponent] + }), + GaugeModule, + CommonModule, + TitledContentModule, + LoadAsyncModule, + FormattingModule + ] +}) +export class GaugeWidgetModule {} diff --git a/projects/observability/src/shared/dashboard/widgets/gauge/gauge-widget.ts b/projects/observability/src/shared/dashboard/widgets/gauge/gauge-widget.ts new file mode 100644 index 000000000..8f0ced071 --- /dev/null +++ b/projects/observability/src/shared/dashboard/widgets/gauge/gauge-widget.ts @@ -0,0 +1,7 @@ +import { GaugeThreshold } from '../../../components/gauge/gauge.component'; + +export interface GaugeWidgetData { + value: number; + maxValue: number; + thresholds: GaugeThreshold[]; +} diff --git a/projects/observability/src/shared/dashboard/widgets/observability-dashboard-widgets.module.ts b/projects/observability/src/shared/dashboard/widgets/observability-dashboard-widgets.module.ts index eecf9cf1c..4cacc0915 100644 --- a/projects/observability/src/shared/dashboard/widgets/observability-dashboard-widgets.module.ts +++ b/projects/observability/src/shared/dashboard/widgets/observability-dashboard-widgets.module.ts @@ -3,6 +3,7 @@ import { ObservabilityTableCellRendererModule } from '../../components/table/obs import { CardListWidgetModule } from './card-list/card-list-widget.module'; import { CartesianWidgetModule } from './charts/cartesian-widget/cartesian-widget.module'; import { DonutWidgetModule } from './donut/donut-widget.module'; +import { GaugeWidgetModule } from './gauge/gauge-widget.module'; import { MetricDisplayWidgetModule } from './metric-display/metric-display-widget.module'; import { RadarWidgetModule } from './radar/radar-widget.module'; import { TopNWidgetModule } from './top-n/top-n-widget.module'; @@ -17,7 +18,8 @@ import { TopologyWidgetModule } from './topology/topology-widget.module'; ObservabilityTableCellRendererModule, DonutWidgetModule, CartesianWidgetModule, - CardListWidgetModule + CardListWidgetModule, + GaugeWidgetModule ] }) export class ObservabilityDashboardWidgetsModule {}