Skip to content

Commit ba18a38

Browse files
authored
feat: adding gauge widget (#347)
* feat: adding gauge widget * refactor: fix test and address review comments * refactor: fixing formatting
1 parent 85d4688 commit ba18a38

13 files changed

+214
-7
lines changed

projects/components/src/public-api.ts

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -81,10 +81,6 @@ export * from './filtering/filter-modal/in-filter-modal.component';
8181
// Filter Parser
8282
export * from './filtering/filter/parser/filter-parser-lookup.service';
8383

84-
// Gauge
85-
export * from './gauge/gauge.component';
86-
export * from './gauge/gauge.module';
87-
8884
// Header
8985
export * from './header/application/application-header.component';
9086
export * from './header/application/application-header.module';

projects/observability/src/public-api.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -210,3 +210,8 @@ export * from './shared/dashboard/data/graphql/specifiers/entity-specification.m
210210

211211
// Explorer service
212212
export * from './pages/explorer/explorer-service';
213+
214+
// Gauge
215+
export * from './shared/components/gauge/gauge.component';
216+
export * from './shared/components/gauge/gauge.module';
217+
export * from './shared/dashboard/widgets/gauge/gauge-widget';

projects/components/src/gauge/gauge.module.ts renamed to projects/observability/src/shared/components/gauge/gauge.module.ts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,7 @@
11
import { CommonModule } from '@angular/common';
22
import { NgModule } from '@angular/core';
33
import { FormattingModule } from '@hypertrace/common';
4-
import { LayoutChangeModule } from '../layout/layout-change.module';
5-
import { TooltipModule } from './../tooltip/tooltip.module';
4+
import { LayoutChangeModule, TooltipModule } from '@hypertrace/components';
65
import { GaugeComponent } from './gauge.component';
76

87
@NgModule({
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
import { Color, FormattingModule } from '@hypertrace/common';
2+
import { LoadAsyncModule, TitledContentComponent } from '@hypertrace/components';
3+
import { RENDERER_API } from '@hypertrace/hyperdash-angular';
4+
import { createComponentFactory } from '@ngneat/spectator/jest';
5+
import { MockComponent } from 'ng-mocks';
6+
import { EMPTY, of } from 'rxjs';
7+
import { GaugeComponent } from './../../../components/gauge/gauge.component';
8+
import { GaugeWidgetRendererComponent } from './gauge-widget-renderer.component';
9+
import { GaugeWidgetModel } from './gauge-widget.model';
10+
11+
describe('Gauge widget renderer component', () => {
12+
let mockModel: Partial<GaugeWidgetModel> = {};
13+
const componentFactory = createComponentFactory({
14+
component: GaugeWidgetRendererComponent,
15+
shallow: true,
16+
imports: [FormattingModule, LoadAsyncModule],
17+
providers: [
18+
{
19+
provide: RENDERER_API,
20+
useFactory: () => ({
21+
getTimeRange: jest.fn(),
22+
model: mockModel,
23+
change$: EMPTY,
24+
dataRefresh$: EMPTY,
25+
timeRangeChanged$: EMPTY
26+
})
27+
}
28+
],
29+
declarations: [MockComponent(GaugeComponent), MockComponent(TitledContentComponent)]
30+
});
31+
32+
test('should render provided data with title', () => {
33+
mockModel = {
34+
title: 'Test title',
35+
getData: jest.fn(() =>
36+
of({
37+
value: 5,
38+
maxValue: 10,
39+
thresholds: [
40+
{
41+
start: 0,
42+
end: 6,
43+
label: 'Medium',
44+
color: Color.Brown1
45+
}
46+
]
47+
})
48+
)
49+
};
50+
51+
const spectator = componentFactory();
52+
expect(spectator.query(TitledContentComponent)!.title).toBe('TEST TITLE');
53+
54+
const gaugeComponent = spectator.query(GaugeComponent);
55+
expect(gaugeComponent).toExist();
56+
expect(gaugeComponent!.value).toEqual(5);
57+
expect(gaugeComponent!.maxValue).toEqual(10);
58+
expect(gaugeComponent!.thresholds).toEqual([
59+
{
60+
start: 0,
61+
end: 6,
62+
label: 'Medium',
63+
color: Color.Brown1
64+
}
65+
]);
66+
});
67+
});
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
import { ChangeDetectionStrategy, Component } from '@angular/core';
2+
import { WidgetRenderer } from '@hypertrace/dashboards';
3+
import { Renderer } from '@hypertrace/hyperdash';
4+
import { Observable } from 'rxjs';
5+
import { GaugeWidgetData } from './gauge-widget';
6+
import { GaugeWidgetModel } from './gauge-widget.model';
7+
8+
@Renderer({ modelClass: GaugeWidgetModel })
9+
@Component({
10+
selector: 'ht-gauge-widget-renderer',
11+
changeDetection: ChangeDetectionStrategy.OnPush,
12+
template: `
13+
<ht-titled-content [title]="this.model.title | htDisplayTitle" *htLoadAsync="this.data$ as gaugeData">
14+
<ht-gauge
15+
class="fill-container"
16+
[value]="gaugeData.value"
17+
[maxValue]="gaugeData.maxValue"
18+
[thresholds]="gaugeData.thresholds"
19+
></ht-gauge>
20+
</ht-titled-content>
21+
`
22+
})
23+
export class GaugeWidgetRendererComponent extends WidgetRenderer<GaugeWidgetModel, GaugeWidgetData> {
24+
protected fetchData(): Observable<GaugeWidgetData> {
25+
return this.model.getData();
26+
}
27+
}
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
import { Color } from '@hypertrace/common';
2+
import { createModelFactory } from '@hypertrace/dashboards/testing';
3+
import { MODEL_PROPERTY_TYPES } from '@hypertrace/hyperdash-angular';
4+
import { runFakeRxjs } from '@hypertrace/test-utils';
5+
import { of } from 'rxjs';
6+
import { GaugeWidgetData } from './gauge-widget';
7+
import { GaugeWidgetModel } from './gauge-widget.model';
8+
9+
describe('Gauge widget model', () => {
10+
test('uses colors from color map', () => {
11+
const modelFactory = createModelFactory();
12+
13+
const data: GaugeWidgetData = {
14+
value: 5,
15+
maxValue: 10,
16+
thresholds: [
17+
{
18+
start: 0,
19+
end: 6,
20+
label: 'Medium',
21+
color: Color.Brown1
22+
}
23+
]
24+
};
25+
26+
const spectator = modelFactory(GaugeWidgetModel, {
27+
api: {
28+
getData: () => of(data)
29+
},
30+
providers: [
31+
{
32+
provide: MODEL_PROPERTY_TYPES,
33+
useValue: []
34+
}
35+
],
36+
properties: {
37+
title: 'Test Title'
38+
}
39+
});
40+
41+
runFakeRxjs(({ expectObservable }) => {
42+
expectObservable(spectator.model.getData()).toBe('(x|)', {
43+
x: {
44+
value: 5,
45+
maxValue: 10,
46+
thresholds: [
47+
{
48+
start: 0,
49+
end: 6,
50+
label: 'Medium',
51+
color: Color.Brown1
52+
}
53+
]
54+
}
55+
});
56+
});
57+
});
58+
});
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
import { Model, ModelApi, ModelProperty, STRING_PROPERTY } from '@hypertrace/hyperdash';
2+
import { ModelInject, MODEL_API } from '@hypertrace/hyperdash-angular';
3+
import { Observable } from 'rxjs';
4+
import { GaugeWidgetData } from './gauge-widget';
5+
6+
@Model({
7+
type: 'gauge-widget'
8+
})
9+
export class GaugeWidgetModel {
10+
@ModelProperty({
11+
key: 'title',
12+
type: STRING_PROPERTY.type
13+
})
14+
public title?: string;
15+
16+
@ModelInject(MODEL_API)
17+
private readonly api!: ModelApi;
18+
19+
public getData(): Observable<GaugeWidgetData> {
20+
return this.api.getData<GaugeWidgetData>();
21+
}
22+
}

0 commit comments

Comments
 (0)