From 0f2af0cf7e11b66a97fbb0d2275da2fd0a0bc113 Mon Sep 17 00:00:00 2001 From: Jyothish Jose Date: Mon, 27 Sep 2021 11:10:36 +0530 Subject: [PATCH 01/49] feat: brusha dded to cartesian chart --- .../cartesian/d3/chart/cartesian-chart.ts | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/projects/observability/src/shared/components/cartesian/d3/chart/cartesian-chart.ts b/projects/observability/src/shared/components/cartesian/d3/chart/cartesian-chart.ts index 79b787686..e033dd029 100644 --- a/projects/observability/src/shared/components/cartesian/d3/chart/cartesian-chart.ts +++ b/projects/observability/src/shared/components/cartesian/d3/chart/cartesian-chart.ts @@ -1,5 +1,6 @@ import { Injector, Renderer2 } from '@angular/core'; import { TimeRange } from '@hypertrace/common'; +import { brushX } from 'd3-brush'; import { ContainerElement, mouse, select } from 'd3-selection'; import { LegendPosition } from '../../../legend/legend.component'; import { ChartTooltipRef } from '../../../utils/chart-tooltip/chart-tooltip-popover'; @@ -281,6 +282,22 @@ export class DefaultCartesianChart implements CartesianChart { this.moveDataOnTopOfAxes(); this.drawMouseEventContainer(); this.setupEventListeners(); + this.attachBrush(); + } + + private attachBrush(): void { + var brush = brushX() // Add the brush feature using the d3.brush function + .extent([ + [0, 0], + [200, 200] + ]) // initialise the brush area: start at 0,0 and finishes at width,height: it means I select the whole graph area + .on('end', this.updateChart); + + select(this.chartBackgroundSvgElement!).append('g').attr('class', 'brush').call(brush); + } + + private updateChart(event: any): void { + console.log('🚀 ~ file: cartesian-chart.ts ~ line 299 ~ DefaultCartesianChart ~ updateChart ~ event', event); } private moveDataOnTopOfAxes(): void { From 549f224896388593c1242cc37f5fafa79dd6ffa4 Mon Sep 17 00:00:00 2001 From: Jyothish Jose Date: Mon, 27 Sep 2021 19:11:28 +0530 Subject: [PATCH 02/49] feat: cartesian chart select(brush) --- .../cartesian/cartesian-chart.component.ts | 9 ++- .../cartesian/chart-interactivty.ts | 3 +- .../cartesian/d3/chart/cartesian-chart.ts | 57 +++++++++++++++---- 3 files changed, 55 insertions(+), 14 deletions(-) diff --git a/projects/observability/src/shared/components/cartesian/cartesian-chart.component.ts b/projects/observability/src/shared/components/cartesian/cartesian-chart.component.ts index 69c6c57dd..29feadd83 100644 --- a/projects/observability/src/shared/components/cartesian/cartesian-chart.component.ts +++ b/projects/observability/src/shared/components/cartesian/cartesian-chart.component.ts @@ -19,6 +19,7 @@ import { DefaultChartTooltipRenderData } from '../utils/chart-tooltip/default/de import { MouseLocationData } from '../utils/mouse-tracking/mouse-tracking'; import { Axis, AxisLocation, AxisType, Band, CartesianChart, RenderingStrategy, Series } from './chart'; import { ChartBuilderService } from './chart-builder.service'; +import { ChartEvent } from './chart-interactivty'; import { defaultXDataAccessor, defaultYDataAccessor } from './d3/scale/default-data-accessors'; @Component({ @@ -93,7 +94,13 @@ export class CartesianChartComponent implements OnChanges, OnDestroy { this.chartTooltipBuilderService.constructTooltip>(data => this.convertToDefaultTooltipRenderData(data) ) - ); + ) + .withEventListener(ChartEvent.Select, data => { + console.log( + '🚀 ~ file: cartesian-chart.component.ts ~ line 99 ~ CartesianChartComponent ~ .withEventListener ~ data', + data + ); + }); if (this.bands) { this.chart.withBands(...this.bands); diff --git a/projects/observability/src/shared/components/cartesian/chart-interactivty.ts b/projects/observability/src/shared/components/cartesian/chart-interactivty.ts index 411330319..7a31a9321 100644 --- a/projects/observability/src/shared/components/cartesian/chart-interactivty.ts +++ b/projects/observability/src/shared/components/cartesian/chart-interactivty.ts @@ -4,7 +4,8 @@ import { AxisType, Band, Series } from './chart'; export const enum ChartEvent { Click, DoubleClick, - RightClick + RightClick, + Select } export type ChartEventListener = (data: MouseLocationData | Band>[]) => void; diff --git a/projects/observability/src/shared/components/cartesian/d3/chart/cartesian-chart.ts b/projects/observability/src/shared/components/cartesian/d3/chart/cartesian-chart.ts index e033dd029..7f8e24267 100644 --- a/projects/observability/src/shared/components/cartesian/d3/chart/cartesian-chart.ts +++ b/projects/observability/src/shared/components/cartesian/d3/chart/cartesian-chart.ts @@ -1,6 +1,6 @@ import { Injector, Renderer2 } from '@angular/core'; import { TimeRange } from '@hypertrace/common'; -import { brushX } from 'd3-brush'; +import { brush, BrushBehavior, D3BrushEvent } from 'd3-brush'; import { ContainerElement, mouse, select } from 'd3-selection'; import { LegendPosition } from '../../../legend/legend.component'; import { ChartTooltipRef } from '../../../utils/chart-tooltip/chart-tooltip-popover'; @@ -33,6 +33,8 @@ import { CartesianLegend } from '../legend/cartesian-legend'; import { ScaleBounds } from '../scale/cartesian-scale'; import { CartesianScaleBuilder } from '../scale/cartesian-scale-builder'; +import { event as _d3CurrentEvent } from 'd3-selection'; + // tslint:disable:max-file-line-count export class DefaultCartesianChart implements CartesianChart { public static DATA_SERIES_CLASS: string = 'data-series'; @@ -66,6 +68,8 @@ export class DefaultCartesianChart implements CartesianChart { onEvent: ChartEventListener; }[] = []; + protected readonly brushBehaviour: BrushBehavior; + public constructor( protected readonly hostElement: Element, protected readonly injector: Injector, @@ -73,7 +77,24 @@ export class DefaultCartesianChart implements CartesianChart { protected readonly svgUtilService: SvgUtilService, protected readonly d3Utils: D3UtilService, protected readonly domRenderer: Renderer2 - ) {} + ) { + this.brushBehaviour = brush().on('end', () => this.onBrushSelection(_d3CurrentEvent)); + } + + protected onBrushSelection(event: D3BrushEvent): void { + if (!event.selection) { + return; + } + + const [start, end] = event.selection as [[number, number], [number, number]]; + + let fromdata: any = this.allSeriesData.flatMap(viz => viz.dataForLocation({ x: start[0], y: start[1] })); + let todata: any = this.allSeriesData.flatMap(viz => viz.dataForLocation({ x: end[0], y: end[1] })); + + this.eventListeners.forEach(listener => { + listener.onEvent({ start: fromdata[0].dataPoint.timestamp, end: todata[0].dataPoint.timestamp } as any); + }); + } public destroy(): this { this.clear(); @@ -286,20 +307,29 @@ export class DefaultCartesianChart implements CartesianChart { } private attachBrush(): void { - var brush = brushX() // Add the brush feature using the d3.brush function - .extent([ - [0, 0], - [200, 200] - ]) // initialise the brush area: start at 0,0 and finishes at width,height: it means I select the whole graph area - .on('end', this.updateChart); + // var brush = brushX() // Add the brush feature using the d3.brush function + // .extent([ + // [0, 0], + // [200, 200] + // ]) // initialise the brush area: start at 0,0 and finishes at width,height: it means I select the whole graph area + // .on('end', this.updateChart); - select(this.chartBackgroundSvgElement!).append('g').attr('class', 'brush').call(brush); - } + const { width, height } = this.hostElement.getBoundingClientRect(); + this.brushBehaviour.extent([ + [0, 0], + [width, height] + ]); - private updateChart(event: any): void { - console.log('🚀 ~ file: cartesian-chart.ts ~ line 299 ~ DefaultCartesianChart ~ updateChart ~ event', event); + select(this.mouseEventContainer!) + .append('g') + .attr('class', 'brush') + .call(this.brushBehaviour as any); } + // private updateChart(event: any): void { + // console.log('🚀 ~ file: cartesian-chart.ts ~ line 299 ~ DefaultCartesianChart ~ updateChart ~ event', event); + // } + private moveDataOnTopOfAxes(): void { if (!this.dataElement) { return; @@ -427,6 +457,7 @@ export class DefaultCartesianChart implements CartesianChart { if (!this.dataElement) { return []; } + const location = mouse(this.dataElement); return this.allSeriesData.flatMap(viz => viz.dataForLocation({ x: location[0], y: location[1] })); @@ -438,6 +469,8 @@ export class DefaultCartesianChart implements CartesianChart { return 'click'; case ChartEvent.DoubleClick: return 'dblclick'; + case ChartEvent.DoubleClick: + return 'select'; case ChartEvent.RightClick: return 'contextmenu'; default: From 8530baad236b072fb0b08fd8740c91c94fc2a98a Mon Sep 17 00:00:00 2001 From: Jyothish Jose Date: Tue, 28 Sep 2021 14:50:49 +0530 Subject: [PATCH 03/49] feat: cartesian drilldown - completed --- .../cartesian/cartesian-chart.component.ts | 33 +++++++++++++++---- .../cartesian/d3/chart/cartesian-chart.ts | 11 ------- 2 files changed, 27 insertions(+), 17 deletions(-) diff --git a/projects/observability/src/shared/components/cartesian/cartesian-chart.component.ts b/projects/observability/src/shared/components/cartesian/cartesian-chart.component.ts index 29feadd83..242c35d74 100644 --- a/projects/observability/src/shared/components/cartesian/cartesian-chart.component.ts +++ b/projects/observability/src/shared/components/cartesian/cartesian-chart.component.ts @@ -10,8 +10,11 @@ import { Renderer2, ViewChild } from '@angular/core'; -import { DateCoercer, DateFormatter, TimeRange } from '@hypertrace/common'; +import { DateCoercer, DateFormatter, NavigationService, TimeRange } from '@hypertrace/common'; import { defaults } from 'lodash-es'; +import { FilterOperator } from '../../../../../components/src/filtering/filter/filter-operators'; +import { ExplorerService } from '../../../pages/explorer/explorer-service'; +import { ScopeQueryParam } from '../../../pages/explorer/explorer.component'; import { IntervalValue } from '../interval-select/interval-select.component'; import { LegendPosition } from '../legend/legend.component'; import { ChartTooltipBuilderService } from '../utils/chart-tooltip/chart-tooltip-builder.service'; @@ -75,7 +78,9 @@ export class CartesianChartComponent implements OnChanges, OnDestroy { public constructor( private readonly chartBuilderService: ChartBuilderService, private readonly chartTooltipBuilderService: ChartTooltipBuilderService, - private readonly renderer: Renderer2 + private readonly renderer: Renderer2, + private readonly explorerService: ExplorerService, + private readonly navigationService: NavigationService ) {} public ngOnChanges(): void { @@ -96,10 +101,26 @@ export class CartesianChartComponent implements OnChanges, OnDestroy { ) ) .withEventListener(ChartEvent.Select, data => { - console.log( - '🚀 ~ file: cartesian-chart.component.ts ~ line 99 ~ CartesianChartComponent ~ .withEventListener ~ data', - data - ); + let dataCopy: any = data; + const startDate = new Date(dataCopy.start).getTime() - 300000; + const endDate = new Date(dataCopy.end).getTime() + 300000; + + this.explorerService + .buildNavParamsWithFilters(ScopeQueryParam.EndpointTraces, [ + { + field: 'startTime', + operator: FilterOperator.GreaterThanOrEqualTo, + value: startDate + }, + { + field: 'endTime', + operator: FilterOperator.LessThanOrEqualTo, + value: endDate + } + ]) + .subscribe(data => { + this.navigationService.navigate(data); + }); }); if (this.bands) { diff --git a/projects/observability/src/shared/components/cartesian/d3/chart/cartesian-chart.ts b/projects/observability/src/shared/components/cartesian/d3/chart/cartesian-chart.ts index 7f8e24267..6ae911263 100644 --- a/projects/observability/src/shared/components/cartesian/d3/chart/cartesian-chart.ts +++ b/projects/observability/src/shared/components/cartesian/d3/chart/cartesian-chart.ts @@ -307,13 +307,6 @@ export class DefaultCartesianChart implements CartesianChart { } private attachBrush(): void { - // var brush = brushX() // Add the brush feature using the d3.brush function - // .extent([ - // [0, 0], - // [200, 200] - // ]) // initialise the brush area: start at 0,0 and finishes at width,height: it means I select the whole graph area - // .on('end', this.updateChart); - const { width, height } = this.hostElement.getBoundingClientRect(); this.brushBehaviour.extent([ [0, 0], @@ -326,10 +319,6 @@ export class DefaultCartesianChart implements CartesianChart { .call(this.brushBehaviour as any); } - // private updateChart(event: any): void { - // console.log('🚀 ~ file: cartesian-chart.ts ~ line 299 ~ DefaultCartesianChart ~ updateChart ~ event', event); - // } - private moveDataOnTopOfAxes(): void { if (!this.dataElement) { return; From 46e458d9c71115a11fbd33cc85e30a6358fec630 Mon Sep 17 00:00:00 2001 From: Jyothish Jose Date: Wed, 6 Oct 2021 22:56:40 +0530 Subject: [PATCH 04/49] feat: cartesian drilldown - model and interaction handler added --- .../metrics/api-metrics.dashboard.ts | 20 +++++++-- .../cartesian/cartesian-chart.component.ts | 33 +++------------ .../cartesian/d3/chart/cartesian-chart.ts | 12 +++--- .../cartesian-widget-renderer.component.ts | 5 +++ .../cartesian-widget.model.ts | 8 ++++ .../cartesian-widget.module.ts | 9 +++- ...esian-explorer-navigation-handler.model.ts | 42 +++++++++++++++++++ src/app/home/home.dashboard.ts | 15 +++++-- 8 files changed, 104 insertions(+), 40 deletions(-) create mode 100644 projects/observability/src/shared/dashboard/widgets/charts/cartesian-widget/interactions/cartesian-explorer-navigation-handler.model.ts diff --git a/projects/observability/src/pages/apis/api-detail/metrics/api-metrics.dashboard.ts b/projects/observability/src/pages/apis/api-detail/metrics/api-metrics.dashboard.ts index 0a9470ee4..273333dca 100644 --- a/projects/observability/src/pages/apis/api-detail/metrics/api-metrics.dashboard.ts +++ b/projects/observability/src/pages/apis/api-detail/metrics/api-metrics.dashboard.ts @@ -270,7 +270,10 @@ export const apiMetricsDashboard: DashboardDefaultConfiguration = { } } } - ] + ], + 'selection-handler': { + type: 'cartesian-explorer-navigation-handler' + } }, { type: 'container-widget', @@ -330,7 +333,10 @@ export const apiMetricsDashboard: DashboardDefaultConfiguration = { type: 'entity-error-percentage-timeseries-data-source' } } - ] + ], + 'selection-handler': { + type: 'cartesian-explorer-navigation-handler' + } }, { type: 'cartesian-widget', @@ -369,7 +375,10 @@ export const apiMetricsDashboard: DashboardDefaultConfiguration = { } } } - ] + ], + 'selection-handler': { + type: 'cartesian-explorer-navigation-handler' + } } ] } @@ -398,7 +407,10 @@ export const apiMetricsDashboard: DashboardDefaultConfiguration = { } } } - ] + ], + 'selection-handler': { + type: 'cartesian-explorer-navigation-handler' + } } ] } diff --git a/projects/observability/src/shared/components/cartesian/cartesian-chart.component.ts b/projects/observability/src/shared/components/cartesian/cartesian-chart.component.ts index 242c35d74..6c55bcbdb 100644 --- a/projects/observability/src/shared/components/cartesian/cartesian-chart.component.ts +++ b/projects/observability/src/shared/components/cartesian/cartesian-chart.component.ts @@ -10,11 +10,8 @@ import { Renderer2, ViewChild } from '@angular/core'; -import { DateCoercer, DateFormatter, NavigationService, TimeRange } from '@hypertrace/common'; +import { DateCoercer, DateFormatter, TimeRange } from '@hypertrace/common'; import { defaults } from 'lodash-es'; -import { FilterOperator } from '../../../../../components/src/filtering/filter/filter-operators'; -import { ExplorerService } from '../../../pages/explorer/explorer-service'; -import { ScopeQueryParam } from '../../../pages/explorer/explorer.component'; import { IntervalValue } from '../interval-select/interval-select.component'; import { LegendPosition } from '../legend/legend.component'; import { ChartTooltipBuilderService } from '../utils/chart-tooltip/chart-tooltip-builder.service'; @@ -68,6 +65,9 @@ export class CartesianChartComponent implements OnChanges, OnDestroy { @Output() public readonly selectedIntervalChange: EventEmitter = new EventEmitter(); + @Output() + public readonly selecteRangeChange: EventEmitter = new EventEmitter(); + @ViewChild('chartContainer', { static: true }) public readonly container!: ElementRef; @@ -78,9 +78,7 @@ export class CartesianChartComponent implements OnChanges, OnDestroy { public constructor( private readonly chartBuilderService: ChartBuilderService, private readonly chartTooltipBuilderService: ChartTooltipBuilderService, - private readonly renderer: Renderer2, - private readonly explorerService: ExplorerService, - private readonly navigationService: NavigationService + private readonly renderer: Renderer2 ) {} public ngOnChanges(): void { @@ -101,26 +99,7 @@ export class CartesianChartComponent implements OnChanges, OnDestroy { ) ) .withEventListener(ChartEvent.Select, data => { - let dataCopy: any = data; - const startDate = new Date(dataCopy.start).getTime() - 300000; - const endDate = new Date(dataCopy.end).getTime() + 300000; - - this.explorerService - .buildNavParamsWithFilters(ScopeQueryParam.EndpointTraces, [ - { - field: 'startTime', - operator: FilterOperator.GreaterThanOrEqualTo, - value: startDate - }, - { - field: 'endTime', - operator: FilterOperator.LessThanOrEqualTo, - value: endDate - } - ]) - .subscribe(data => { - this.navigationService.navigate(data); - }); + this.selecteRangeChange.emit(data); }); if (this.bands) { diff --git a/projects/observability/src/shared/components/cartesian/d3/chart/cartesian-chart.ts b/projects/observability/src/shared/components/cartesian/d3/chart/cartesian-chart.ts index 6ae911263..6dcca92ba 100644 --- a/projects/observability/src/shared/components/cartesian/d3/chart/cartesian-chart.ts +++ b/projects/observability/src/shared/components/cartesian/d3/chart/cartesian-chart.ts @@ -1,6 +1,6 @@ import { Injector, Renderer2 } from '@angular/core'; import { TimeRange } from '@hypertrace/common'; -import { brush, BrushBehavior, D3BrushEvent } from 'd3-brush'; +import { BrushBehavior, brushX, D3BrushEvent } from 'd3-brush'; import { ContainerElement, mouse, select } from 'd3-selection'; import { LegendPosition } from '../../../legend/legend.component'; import { ChartTooltipRef } from '../../../utils/chart-tooltip/chart-tooltip-popover'; @@ -78,7 +78,7 @@ export class DefaultCartesianChart implements CartesianChart { protected readonly d3Utils: D3UtilService, protected readonly domRenderer: Renderer2 ) { - this.brushBehaviour = brush().on('end', () => this.onBrushSelection(_d3CurrentEvent)); + this.brushBehaviour = brushX().on('end', () => this.onBrushSelection(_d3CurrentEvent)); } protected onBrushSelection(event: D3BrushEvent): void { @@ -86,10 +86,12 @@ export class DefaultCartesianChart implements CartesianChart { return; } - const [start, end] = event.selection as [[number, number], [number, number]]; + const { height } = this.hostElement.getBoundingClientRect(); - let fromdata: any = this.allSeriesData.flatMap(viz => viz.dataForLocation({ x: start[0], y: start[1] })); - let todata: any = this.allSeriesData.flatMap(viz => viz.dataForLocation({ x: end[0], y: end[1] })); + const [startX, endX] = event.selection as [number, number]; + + let fromdata: any = this.allSeriesData.flatMap(viz => viz.dataForLocation({ x: startX, y: height })); + let todata: any = this.allSeriesData.flatMap(viz => viz.dataForLocation({ x: endX, y: height })); this.eventListeners.forEach(listener => { listener.onEvent({ start: fromdata[0].dataPoint.timestamp, end: todata[0].dataPoint.timestamp } as any); diff --git a/projects/observability/src/shared/dashboard/widgets/charts/cartesian-widget/cartesian-widget-renderer.component.ts b/projects/observability/src/shared/dashboard/widgets/charts/cartesian-widget/cartesian-widget-renderer.component.ts index 0e3298da3..8080a543a 100644 --- a/projects/observability/src/shared/dashboard/widgets/charts/cartesian-widget/cartesian-widget-renderer.component.ts +++ b/projects/observability/src/shared/dashboard/widgets/charts/cartesian-widget/cartesian-widget-renderer.component.ts @@ -28,6 +28,7 @@ import { CartesianDataFetcher, CartesianResult, CartesianWidgetModel } from './c [intervalOptions]="this.intervalOptions" [legend]="this.model.legendPosition" (selectedIntervalChange)="this.onIntervalChange($event)" + (selecteRangeChange)="this.onRangeChange($event)" > @@ -54,6 +55,10 @@ export class CartesianWidgetRendererComponent extends Interacti this.updateDataObservable(); } + public onRangeChange(data: any): void { + this.model.selectionHandler?.execute(data); + } + protected fetchData(): Observable> { return this.model.getDataFetcher().pipe( tap(fetcher => { diff --git a/projects/observability/src/shared/dashboard/widgets/charts/cartesian-widget/cartesian-widget.model.ts b/projects/observability/src/shared/dashboard/widgets/charts/cartesian-widget/cartesian-widget.model.ts index f8043407a..2d16152b2 100644 --- a/projects/observability/src/shared/dashboard/widgets/charts/cartesian-widget/cartesian-widget.model.ts +++ b/projects/observability/src/shared/dashboard/widgets/charts/cartesian-widget/cartesian-widget.model.ts @@ -16,6 +16,7 @@ import { map } from 'rxjs/operators'; import { Band, CartesianSeriesVisualizationType, Series } from '../../../../components/cartesian/chart'; import { LegendPosition } from '../../../../components/legend/legend.component'; import { MetricTimeseriesBandInterval } from '../../../../graphql/model/metric/metric-timeseries'; +import { InteractionHandler } from '../../../interaction/interaction-handler'; import { CartesianAxisModel } from './axis/cartesian-axis.model'; import { BAND_ARRAY_TYPE } from './band-array/band-array-type'; import { BandModel, MetricBand, MetricBandDataFetcher } from './band.model'; @@ -146,6 +147,13 @@ export class CartesianWidgetModel { }) public maxSeriesDataPoints?: number; + @ModelProperty({ + key: 'selection-handler', + displayName: 'Selection Handler', + type: ModelPropertyType.TYPE + }) + public selectionHandler?: InteractionHandler; + @ModelInject(MODEL_API) private readonly api!: ModelApi; diff --git a/projects/observability/src/shared/dashboard/widgets/charts/cartesian-widget/cartesian-widget.module.ts b/projects/observability/src/shared/dashboard/widgets/charts/cartesian-widget/cartesian-widget.module.ts index 9380af394..f7355df39 100644 --- a/projects/observability/src/shared/dashboard/widgets/charts/cartesian-widget/cartesian-widget.module.ts +++ b/projects/observability/src/shared/dashboard/widgets/charts/cartesian-widget/cartesian-widget.module.ts @@ -10,6 +10,7 @@ import { BAND_ARRAY_TYPE } from './band-array/band-array-type'; import { BandModel } from './band.model'; import { CartesianWidgetRendererComponent } from './cartesian-widget-renderer.component'; import { CartesianWidgetModel } from './cartesian-widget.model'; +import { CartesianExplorerNavigationHandlerModel } from './interactions/cartesian-explorer-navigation-handler.model'; import { SeriesArrayEditorComponent } from './series-array/series-array-editor.component'; import { SERIES_ARRAY_TYPE } from './series-array/series-array-type'; import { SeriesModel } from './series.model'; @@ -24,7 +25,13 @@ import { SeriesModel } from './series.model'; DashboardEditorModule, ButtonModule, DashboardCoreModule.with({ - models: [CartesianWidgetModel, SeriesModel, BandModel, CartesianAxisModel], + models: [ + CartesianWidgetModel, + SeriesModel, + BandModel, + CartesianAxisModel, + CartesianExplorerNavigationHandlerModel + ], renderers: [CartesianWidgetRendererComponent], editors: [SeriesArrayEditorComponent], propertyTypes: [SERIES_ARRAY_TYPE, BAND_ARRAY_TYPE] diff --git a/projects/observability/src/shared/dashboard/widgets/charts/cartesian-widget/interactions/cartesian-explorer-navigation-handler.model.ts b/projects/observability/src/shared/dashboard/widgets/charts/cartesian-widget/interactions/cartesian-explorer-navigation-handler.model.ts new file mode 100644 index 000000000..a1469094a --- /dev/null +++ b/projects/observability/src/shared/dashboard/widgets/charts/cartesian-widget/interactions/cartesian-explorer-navigation-handler.model.ts @@ -0,0 +1,42 @@ +import { Model } from '@hypertrace/hyperdash'; +import { ModelInject } from '@hypertrace/hyperdash-angular'; +import { Observable, of } from 'rxjs'; +import { NavigationService } from '../../../../../../../../common/src/navigation/navigation.service'; +import { FilterOperator } from '../../../../../../../../components/src/filtering/filter/filter-operators'; +import { ExplorerService } from '../../../../../../pages/explorer/explorer-service'; +import { ScopeQueryParam } from '../../../../../../pages/explorer/explorer.component'; +import { InteractionHandler } from '../../../../interaction/interaction-handler'; + +@Model({ + type: 'cartesian-explorer-navigation-handler' +}) +export class CartesianExplorerNavigationHandlerModel implements InteractionHandler { + @ModelInject(ExplorerService) + private readonly explorerService!: ExplorerService; + + @ModelInject(NavigationService) + private readonly navigationService!: NavigationService; + + public execute(dateRange: any): Observable { + const startDate = new Date(dateRange.start).getTime() - 6000; + const endDate = new Date(dateRange.end).getTime() + 6000; + + this.explorerService + .buildNavParamsWithFilters(ScopeQueryParam.EndpointTraces, [ + { + field: 'startTime', + operator: FilterOperator.GreaterThanOrEqualTo, + value: startDate + }, + { + field: 'endTime', + operator: FilterOperator.LessThanOrEqualTo, + value: endDate + } + ]) + .subscribe(data => { + this.navigationService.navigate(data); + }); + return of(); + } +} diff --git a/src/app/home/home.dashboard.ts b/src/app/home/home.dashboard.ts index b5875503f..a14b22f09 100644 --- a/src/app/home/home.dashboard.ts +++ b/src/app/home/home.dashboard.ts @@ -477,7 +477,10 @@ export const homeDashboard: DashboardDefaultConfiguration = { } } } - ] + ], + 'selection-handler': { + type: 'cartesian-explorer-navigation-handler' + } }, { type: 'cartesian-widget', @@ -554,7 +557,10 @@ export const homeDashboard: DashboardDefaultConfiguration = { } } } - ] + ], + 'selection-handler': { + type: 'cartesian-explorer-navigation-handler' + } }, { type: 'cartesian-widget', @@ -631,7 +637,10 @@ export const homeDashboard: DashboardDefaultConfiguration = { } } } - ] + ], + 'selection-handler': { + type: 'cartesian-explorer-navigation-handler' + } } ] }, From 07ee0a24ad72f5501c8293e8a615336b19d1cf24 Mon Sep 17 00:00:00 2001 From: Jyothish Jose Date: Sat, 9 Oct 2021 11:01:05 +0530 Subject: [PATCH 05/49] feat: timerange drilldown --- .../metrics/api-metrics.dashboard.ts | 8 +-- .../overview/api-overview.dashboard.ts | 15 ++++-- .../metrics/backend-metrics.dashboard.ts | 20 ++++++-- .../overview/backend-overview.component.ts | 15 ++++-- .../metrics/service-metrics.dashboard.ts | 20 ++++++-- .../overview/service-overview.dashboard.ts | 15 ++++-- .../explorer-dashboard-builder.test.ts | 5 +- .../explorer/explorer-dashboard-builder.ts | 5 +- .../cartesian/cartesian-chart.component.ts | 6 +-- .../cartesian/d3/chart/cartesian-chart.ts | 49 ++++++++++--------- .../cartesian/d3/data/cartesian-data.ts | 4 ++ .../d3/scale/band/cartesian-band-scale.ts | 4 ++ .../cartesian/d3/scale/cartesian-scale.ts | 2 + .../linear/cartesian-continuous-scale.ts | 4 ++ .../numeric/time/cartesian-time-scale.ts | 4 ++ .../cartesian-widget-renderer.component.ts | 4 +- .../cartesian-widget.module.ts | 4 +- ...esian-explorer-selection-handler.model.ts} | 27 +++++++--- src/app/home/home.dashboard.ts | 6 +-- 19 files changed, 154 insertions(+), 63 deletions(-) rename projects/observability/src/shared/dashboard/widgets/charts/cartesian-widget/interactions/{cartesian-explorer-navigation-handler.model.ts => cartesian-explorer-selection-handler.model.ts} (62%) diff --git a/projects/observability/src/pages/apis/api-detail/metrics/api-metrics.dashboard.ts b/projects/observability/src/pages/apis/api-detail/metrics/api-metrics.dashboard.ts index 273333dca..0c18c6376 100644 --- a/projects/observability/src/pages/apis/api-detail/metrics/api-metrics.dashboard.ts +++ b/projects/observability/src/pages/apis/api-detail/metrics/api-metrics.dashboard.ts @@ -272,7 +272,7 @@ export const apiMetricsDashboard: DashboardDefaultConfiguration = { } ], 'selection-handler': { - type: 'cartesian-explorer-navigation-handler' + type: 'cartesian-explorer-selection-handler' } }, { @@ -335,7 +335,7 @@ export const apiMetricsDashboard: DashboardDefaultConfiguration = { } ], 'selection-handler': { - type: 'cartesian-explorer-navigation-handler' + type: 'cartesian-explorer-selection-handler' } }, { @@ -377,7 +377,7 @@ export const apiMetricsDashboard: DashboardDefaultConfiguration = { } ], 'selection-handler': { - type: 'cartesian-explorer-navigation-handler' + type: 'cartesian-explorer-selection-handler' } } ] @@ -409,7 +409,7 @@ export const apiMetricsDashboard: DashboardDefaultConfiguration = { } ], 'selection-handler': { - type: 'cartesian-explorer-navigation-handler' + type: 'cartesian-explorer-selection-handler' } } ] diff --git a/projects/observability/src/pages/apis/api-detail/overview/api-overview.dashboard.ts b/projects/observability/src/pages/apis/api-detail/overview/api-overview.dashboard.ts index 45a638748..30c48924c 100644 --- a/projects/observability/src/pages/apis/api-detail/overview/api-overview.dashboard.ts +++ b/projects/observability/src/pages/apis/api-detail/overview/api-overview.dashboard.ts @@ -295,7 +295,10 @@ export const apiOverviewDashboard: DashboardDefaultConfiguration = { } } } - ] + ], + 'selection-handler': { + type: 'cartesian-explorer-selection-handler' + } }, { type: 'cartesian-widget', @@ -389,7 +392,10 @@ export const apiOverviewDashboard: DashboardDefaultConfiguration = { } } } - ] + ], + 'selection-handler': { + type: 'cartesian-explorer-selection-handler' + } }, { type: 'cartesian-widget', @@ -483,7 +489,10 @@ export const apiOverviewDashboard: DashboardDefaultConfiguration = { } } } - ] + ], + 'selection-handler': { + type: 'cartesian-explorer-selection-handler' + } } ] }, diff --git a/projects/observability/src/pages/apis/backend-detail/metrics/backend-metrics.dashboard.ts b/projects/observability/src/pages/apis/backend-detail/metrics/backend-metrics.dashboard.ts index 00bbc7987..048040bd5 100644 --- a/projects/observability/src/pages/apis/backend-detail/metrics/backend-metrics.dashboard.ts +++ b/projects/observability/src/pages/apis/backend-detail/metrics/backend-metrics.dashboard.ts @@ -254,7 +254,10 @@ export const backendMetricsDashboard: DashboardDefaultConfiguration = { } } } - ] + ], + 'selection-handler': { + type: 'cartesian-explorer-selection-handler' + } }, { type: 'container-widget', @@ -314,7 +317,10 @@ export const backendMetricsDashboard: DashboardDefaultConfiguration = { type: 'entity-error-percentage-timeseries-data-source' } } - ] + ], + 'selection-handler': { + type: 'cartesian-explorer-selection-handler' + } }, { type: 'cartesian-widget', @@ -337,7 +343,10 @@ export const backendMetricsDashboard: DashboardDefaultConfiguration = { } } } - ] + ], + 'selection-handler': { + type: 'cartesian-explorer-selection-handler' + } } ] } @@ -366,7 +375,10 @@ export const backendMetricsDashboard: DashboardDefaultConfiguration = { } } } - ] + ], + 'selection-handler': { + type: 'cartesian-explorer-selection-handler' + } } ] } diff --git a/projects/observability/src/pages/apis/backend-detail/overview/backend-overview.component.ts b/projects/observability/src/pages/apis/backend-detail/overview/backend-overview.component.ts index 7a90af881..685685ba3 100644 --- a/projects/observability/src/pages/apis/backend-detail/overview/backend-overview.component.ts +++ b/projects/observability/src/pages/apis/backend-detail/overview/backend-overview.component.ts @@ -287,7 +287,10 @@ export class BackendOverviewComponent { } } } - ] + ], + 'selection-handler': { + type: 'cartesian-explorer-selection-handler' + } }, { type: 'cartesian-widget', @@ -365,7 +368,10 @@ export class BackendOverviewComponent { } } } - ] + ], + 'selection-handler': { + type: 'cartesian-explorer-selection-handler' + } }, { type: 'cartesian-widget', @@ -443,7 +449,10 @@ export class BackendOverviewComponent { } } } - ] + ], + 'selection-handler': { + type: 'cartesian-explorer-selection-handler' + } } ] }, diff --git a/projects/observability/src/pages/apis/service-detail/metrics/service-metrics.dashboard.ts b/projects/observability/src/pages/apis/service-detail/metrics/service-metrics.dashboard.ts index d4ded84dd..ec8f6892b 100644 --- a/projects/observability/src/pages/apis/service-detail/metrics/service-metrics.dashboard.ts +++ b/projects/observability/src/pages/apis/service-detail/metrics/service-metrics.dashboard.ts @@ -270,7 +270,10 @@ export const serviceMetricsDashboard: DashboardDefaultConfiguration = { } } } - ] + ], + 'selection-handler': { + type: 'cartesian-explorer-selection-handler' + } }, { type: 'container-widget', @@ -330,7 +333,10 @@ export const serviceMetricsDashboard: DashboardDefaultConfiguration = { type: 'entity-error-percentage-timeseries-data-source' } } - ] + ], + 'selection-handler': { + type: 'cartesian-explorer-selection-handler' + } }, { type: 'cartesian-widget', @@ -369,7 +375,10 @@ export const serviceMetricsDashboard: DashboardDefaultConfiguration = { } } } - ] + ], + 'selection-handler': { + type: 'cartesian-explorer-selection-handler' + } } ] } @@ -398,7 +407,10 @@ export const serviceMetricsDashboard: DashboardDefaultConfiguration = { } } } - ] + ], + 'selection-handler': { + type: 'cartesian-explorer-selection-handler' + } } ] } diff --git a/projects/observability/src/pages/apis/service-detail/overview/service-overview.dashboard.ts b/projects/observability/src/pages/apis/service-detail/overview/service-overview.dashboard.ts index 316a9379a..cd6a8a866 100644 --- a/projects/observability/src/pages/apis/service-detail/overview/service-overview.dashboard.ts +++ b/projects/observability/src/pages/apis/service-detail/overview/service-overview.dashboard.ts @@ -339,7 +339,10 @@ export const serviceOverviewDashboard: DashboardDefaultConfiguration = { } } } - ] + ], + 'selection-handler': { + type: 'cartesian-explorer-selection-handler' + } }, { type: 'cartesian-widget', @@ -433,7 +436,10 @@ export const serviceOverviewDashboard: DashboardDefaultConfiguration = { } } } - ] + ], + 'selection-handler': { + type: 'cartesian-explorer-selection-handler' + } }, { type: 'cartesian-widget', @@ -527,7 +533,10 @@ export const serviceOverviewDashboard: DashboardDefaultConfiguration = { } } } - ] + ], + 'selection-handler': { + type: 'cartesian-explorer-selection-handler' + } } ] }, diff --git a/projects/observability/src/pages/explorer/explorer-dashboard-builder.test.ts b/projects/observability/src/pages/explorer/explorer-dashboard-builder.test.ts index f3edcb978..fb920962d 100644 --- a/projects/observability/src/pages/explorer/explorer-dashboard-builder.test.ts +++ b/projects/observability/src/pages/explorer/explorer-dashboard-builder.test.ts @@ -41,7 +41,10 @@ describe('Explorer dashboard builder', () => { type: 'cartesian-widget', 'selectable-interval': false, 'series-from-data': true, - 'legend-position': LegendPosition.Bottom + 'legend-position': LegendPosition.Bottom, + 'selection-handler': { + type: 'cartesian-explorer-selection-handler' + } }, onReady: expect.any(Function) } diff --git a/projects/observability/src/pages/explorer/explorer-dashboard-builder.ts b/projects/observability/src/pages/explorer/explorer-dashboard-builder.ts index cb44e232d..be7c7f9fc 100644 --- a/projects/observability/src/pages/explorer/explorer-dashboard-builder.ts +++ b/projects/observability/src/pages/explorer/explorer-dashboard-builder.ts @@ -62,7 +62,10 @@ export class ExplorerDashboardBuilder { type: 'cartesian-widget', 'selectable-interval': false, 'series-from-data': true, - 'legend-position': LegendPosition.Bottom + 'legend-position': LegendPosition.Bottom, + 'selection-handler': { + type: 'cartesian-explorer-selection-handler' + } }, onReady: dashboard => { dashboard.createAndSetRootDataFromModelClass(ExplorerVisualizationCartesianDataSourceModel); diff --git a/projects/observability/src/shared/components/cartesian/cartesian-chart.component.ts b/projects/observability/src/shared/components/cartesian/cartesian-chart.component.ts index 6c55bcbdb..66db50e98 100644 --- a/projects/observability/src/shared/components/cartesian/cartesian-chart.component.ts +++ b/projects/observability/src/shared/components/cartesian/cartesian-chart.component.ts @@ -66,7 +66,7 @@ export class CartesianChartComponent implements OnChanges, OnDestroy { public readonly selectedIntervalChange: EventEmitter = new EventEmitter(); @Output() - public readonly selecteRangeChange: EventEmitter = new EventEmitter(); + public readonly selectionChange: EventEmitter = new EventEmitter(); @ViewChild('chartContainer', { static: true }) public readonly container!: ElementRef; @@ -98,8 +98,8 @@ export class CartesianChartComponent implements OnChanges, OnDestroy { this.convertToDefaultTooltipRenderData(data) ) ) - .withEventListener(ChartEvent.Select, data => { - this.selecteRangeChange.emit(data); + .withEventListener(ChartEvent.Select, selectedData => { + this.selectionChange.emit(selectedData as any); }); if (this.bands) { diff --git a/projects/observability/src/shared/components/cartesian/d3/chart/cartesian-chart.ts b/projects/observability/src/shared/components/cartesian/d3/chart/cartesian-chart.ts index 6dcca92ba..a82fd1150 100644 --- a/projects/observability/src/shared/components/cartesian/d3/chart/cartesian-chart.ts +++ b/projects/observability/src/shared/components/cartesian/d3/chart/cartesian-chart.ts @@ -1,6 +1,6 @@ import { Injector, Renderer2 } from '@angular/core'; import { TimeRange } from '@hypertrace/common'; -import { BrushBehavior, brushX, D3BrushEvent } from 'd3-brush'; +import { brush, BrushBehavior, D3BrushEvent } from 'd3-brush'; import { ContainerElement, mouse, select } from 'd3-selection'; import { LegendPosition } from '../../../legend/legend.component'; import { ChartTooltipRef } from '../../../utils/chart-tooltip/chart-tooltip-popover'; @@ -68,8 +68,6 @@ export class DefaultCartesianChart implements CartesianChart { onEvent: ChartEventListener; }[] = []; - protected readonly brushBehaviour: BrushBehavior; - public constructor( protected readonly hostElement: Element, protected readonly injector: Injector, @@ -77,24 +75,24 @@ export class DefaultCartesianChart implements CartesianChart { protected readonly svgUtilService: SvgUtilService, protected readonly d3Utils: D3UtilService, protected readonly domRenderer: Renderer2 - ) { - this.brushBehaviour = brushX().on('end', () => this.onBrushSelection(_d3CurrentEvent)); - } + ) {} protected onBrushSelection(event: D3BrushEvent): void { if (!event.selection) { return; } - const { height } = this.hostElement.getBoundingClientRect(); - - const [startX, endX] = event.selection as [number, number]; - - let fromdata: any = this.allSeriesData.flatMap(viz => viz.dataForLocation({ x: startX, y: height })); - let todata: any = this.allSeriesData.flatMap(viz => viz.dataForLocation({ x: endX, y: height })); - this.eventListeners.forEach(listener => { - listener.onEvent({ start: fromdata[0].dataPoint.timestamp, end: todata[0].dataPoint.timestamp } as any); + if (listener.event === ChartEvent.Select) { + const [start, end] = event.selection as [[number, number], [number, number]]; + + let selctionData: any = { + series: this.allSeriesData, + start: start, + end: end + }; + listener.onEvent(selctionData); + } }); } @@ -280,11 +278,15 @@ export class DefaultCartesianChart implements CartesianChart { eventContainer.on('mousemove', () => this.onMouseMove()).on('mouseleave', () => this.onMouseLeave()); - this.eventListeners.forEach(listener => - eventContainer.on(this.getNativeEventName(listener.event), () => - listener.onEvent(this.getMouseDataForCurrentEvent()) - ) - ); + this.eventListeners.forEach(listener => { + if (listener.event === ChartEvent.Select) { + this.attachBrush(); + } else { + eventContainer.on(this.getNativeEventName(listener.event), () => + listener.onEvent(this.getMouseDataForCurrentEvent()) + ); + } + }); } protected clear(): void { @@ -305,12 +307,15 @@ export class DefaultCartesianChart implements CartesianChart { this.moveDataOnTopOfAxes(); this.drawMouseEventContainer(); this.setupEventListeners(); - this.attachBrush(); } private attachBrush(): void { + let brushBehaviour: BrushBehavior = brush().on('end', () => + this.onBrushSelection(_d3CurrentEvent) + ); + const { width, height } = this.hostElement.getBoundingClientRect(); - this.brushBehaviour.extent([ + brushBehaviour.extent([ [0, 0], [width, height] ]); @@ -318,7 +323,7 @@ export class DefaultCartesianChart implements CartesianChart { select(this.mouseEventContainer!) .append('g') .attr('class', 'brush') - .call(this.brushBehaviour as any); + .call(brushBehaviour as any); } private moveDataOnTopOfAxes(): void { diff --git a/projects/observability/src/shared/components/cartesian/d3/data/cartesian-data.ts b/projects/observability/src/shared/components/cartesian/d3/data/cartesian-data.ts index 57359d6c5..40e3ea604 100644 --- a/projects/observability/src/shared/components/cartesian/d3/data/cartesian-data.ts +++ b/projects/observability/src/shared/components/cartesian/d3/data/cartesian-data.ts @@ -41,6 +41,10 @@ export abstract class CartesianData { return this.dataLookupStrategy ? this.dataLookupStrategy.dataForLocation(location) : []; } + public getXAxisValue(point: number): Date | number { + return this.xScale.invert(point); + } + protected buildXScale(): AnyCartesianScale { return this.scaleBuilder.build(AxisType.X); } diff --git a/projects/observability/src/shared/components/cartesian/d3/scale/band/cartesian-band-scale.ts b/projects/observability/src/shared/components/cartesian/d3/scale/band/cartesian-band-scale.ts index 6648e3281..de02d0a01 100644 --- a/projects/observability/src/shared/components/cartesian/d3/scale/band/cartesian-band-scale.ts +++ b/projects/observability/src/shared/components/cartesian/d3/scale/band/cartesian-band-scale.ts @@ -40,4 +40,8 @@ export class CartesianBandScale extends CartesianScale { protected getEmptyScale(): ScaleBand { return scaleBand().paddingInner(0.2).paddingOuter(0.1).align(1); } + + public invert(point: number): number { + return point; + } } diff --git a/projects/observability/src/shared/components/cartesian/d3/scale/cartesian-scale.ts b/projects/observability/src/shared/components/cartesian/d3/scale/cartesian-scale.ts index ab68983fe..ab64d62d2 100644 --- a/projects/observability/src/shared/components/cartesian/d3/scale/cartesian-scale.ts +++ b/projects/observability/src/shared/components/cartesian/d3/scale/cartesian-scale.ts @@ -29,6 +29,8 @@ export abstract class CartesianScale { protected abstract setRange(): void; + public abstract invert(point: number): Date | number; + public getValueFromData(data: TData): TDomain { return this.dataAccessor(data); } diff --git a/projects/observability/src/shared/components/cartesian/d3/scale/numeric/linear/cartesian-continuous-scale.ts b/projects/observability/src/shared/components/cartesian/d3/scale/numeric/linear/cartesian-continuous-scale.ts index 07889d0c3..1f8be671d 100644 --- a/projects/observability/src/shared/components/cartesian/d3/scale/numeric/linear/cartesian-continuous-scale.ts +++ b/projects/observability/src/shared/components/cartesian/d3/scale/numeric/linear/cartesian-continuous-scale.ts @@ -47,4 +47,8 @@ export class CartesianContinuousScale extends CartesianNumericScale { return scaleLinear(); } + + public invert(point: number): number { + return this.d3Implementation.invert(point); + } } diff --git a/projects/observability/src/shared/components/cartesian/d3/scale/numeric/time/cartesian-time-scale.ts b/projects/observability/src/shared/components/cartesian/d3/scale/numeric/time/cartesian-time-scale.ts index 81102382f..decee6f09 100644 --- a/projects/observability/src/shared/components/cartesian/d3/scale/numeric/time/cartesian-time-scale.ts +++ b/projects/observability/src/shared/components/cartesian/d3/scale/numeric/time/cartesian-time-scale.ts @@ -63,4 +63,8 @@ export class CartesianTimeScale extends CartesianNumericScale { protected getEmptyScale(): ScaleTime { return scaleTime(); } + + public invert(point: number): Date { + return this.d3Implementation.invert(point); + } } diff --git a/projects/observability/src/shared/dashboard/widgets/charts/cartesian-widget/cartesian-widget-renderer.component.ts b/projects/observability/src/shared/dashboard/widgets/charts/cartesian-widget/cartesian-widget-renderer.component.ts index 8080a543a..fc44d41c4 100644 --- a/projects/observability/src/shared/dashboard/widgets/charts/cartesian-widget/cartesian-widget-renderer.component.ts +++ b/projects/observability/src/shared/dashboard/widgets/charts/cartesian-widget/cartesian-widget-renderer.component.ts @@ -28,7 +28,7 @@ import { CartesianDataFetcher, CartesianResult, CartesianWidgetModel } from './c [intervalOptions]="this.intervalOptions" [legend]="this.model.legendPosition" (selectedIntervalChange)="this.onIntervalChange($event)" - (selecteRangeChange)="this.onRangeChange($event)" + (selectionChange)="this.onSelectionChange($event)" > @@ -55,7 +55,7 @@ export class CartesianWidgetRendererComponent extends Interacti this.updateDataObservable(); } - public onRangeChange(data: any): void { + public onSelectionChange(data: any): void { this.model.selectionHandler?.execute(data); } diff --git a/projects/observability/src/shared/dashboard/widgets/charts/cartesian-widget/cartesian-widget.module.ts b/projects/observability/src/shared/dashboard/widgets/charts/cartesian-widget/cartesian-widget.module.ts index f7355df39..10d90cd7b 100644 --- a/projects/observability/src/shared/dashboard/widgets/charts/cartesian-widget/cartesian-widget.module.ts +++ b/projects/observability/src/shared/dashboard/widgets/charts/cartesian-widget/cartesian-widget.module.ts @@ -10,7 +10,7 @@ import { BAND_ARRAY_TYPE } from './band-array/band-array-type'; import { BandModel } from './band.model'; import { CartesianWidgetRendererComponent } from './cartesian-widget-renderer.component'; import { CartesianWidgetModel } from './cartesian-widget.model'; -import { CartesianExplorerNavigationHandlerModel } from './interactions/cartesian-explorer-navigation-handler.model'; +import { CartesianExplorerSelectionHandlerModel } from './interactions/cartesian-explorer-selection-handler.model'; import { SeriesArrayEditorComponent } from './series-array/series-array-editor.component'; import { SERIES_ARRAY_TYPE } from './series-array/series-array-type'; import { SeriesModel } from './series.model'; @@ -30,7 +30,7 @@ import { SeriesModel } from './series.model'; SeriesModel, BandModel, CartesianAxisModel, - CartesianExplorerNavigationHandlerModel + CartesianExplorerSelectionHandlerModel ], renderers: [CartesianWidgetRendererComponent], editors: [SeriesArrayEditorComponent], diff --git a/projects/observability/src/shared/dashboard/widgets/charts/cartesian-widget/interactions/cartesian-explorer-navigation-handler.model.ts b/projects/observability/src/shared/dashboard/widgets/charts/cartesian-widget/interactions/cartesian-explorer-selection-handler.model.ts similarity index 62% rename from projects/observability/src/shared/dashboard/widgets/charts/cartesian-widget/interactions/cartesian-explorer-navigation-handler.model.ts rename to projects/observability/src/shared/dashboard/widgets/charts/cartesian-widget/interactions/cartesian-explorer-selection-handler.model.ts index a1469094a..9035e08de 100644 --- a/projects/observability/src/shared/dashboard/widgets/charts/cartesian-widget/interactions/cartesian-explorer-navigation-handler.model.ts +++ b/projects/observability/src/shared/dashboard/widgets/charts/cartesian-widget/interactions/cartesian-explorer-selection-handler.model.ts @@ -8,35 +8,46 @@ import { ScopeQueryParam } from '../../../../../../pages/explorer/explorer.compo import { InteractionHandler } from '../../../../interaction/interaction-handler'; @Model({ - type: 'cartesian-explorer-navigation-handler' + type: 'cartesian-explorer-selection-handler' }) -export class CartesianExplorerNavigationHandlerModel implements InteractionHandler { +export class CartesianExplorerSelectionHandlerModel implements InteractionHandler { @ModelInject(ExplorerService) private readonly explorerService!: ExplorerService; @ModelInject(NavigationService) private readonly navigationService!: NavigationService; - public execute(dateRange: any): Observable { - const startDate = new Date(dateRange.start).getTime() - 6000; - const endDate = new Date(dateRange.end).getTime() + 6000; + public execute(selectionData: any): Observable { + const startPoint = selectionData.start; + const endPoint = selectionData.end; + selectionData.series.map((data: any) => { + const startDate = data.getXAxisValue(startPoint[0]); + const endDate = data.getXAxisValue(endPoint[0]); + this.navigateToExplorer(startDate, endDate); + return; + }); + return of(); + } + + private navigateToExplorer(start: Date, end: Date): void { + const startTime: number = new Date(start).getTime(); + const endTime: number = new Date(end).getTime(); this.explorerService .buildNavParamsWithFilters(ScopeQueryParam.EndpointTraces, [ { field: 'startTime', operator: FilterOperator.GreaterThanOrEqualTo, - value: startDate + value: startTime }, { field: 'endTime', operator: FilterOperator.LessThanOrEqualTo, - value: endDate + value: endTime } ]) .subscribe(data => { this.navigationService.navigate(data); }); - return of(); } } diff --git a/src/app/home/home.dashboard.ts b/src/app/home/home.dashboard.ts index a14b22f09..2dff0a0f9 100644 --- a/src/app/home/home.dashboard.ts +++ b/src/app/home/home.dashboard.ts @@ -479,7 +479,7 @@ export const homeDashboard: DashboardDefaultConfiguration = { } ], 'selection-handler': { - type: 'cartesian-explorer-navigation-handler' + type: 'cartesian-explorer-selection-handler' } }, { @@ -559,7 +559,7 @@ export const homeDashboard: DashboardDefaultConfiguration = { } ], 'selection-handler': { - type: 'cartesian-explorer-navigation-handler' + type: 'cartesian-explorer-selection-handler' } }, { @@ -639,7 +639,7 @@ export const homeDashboard: DashboardDefaultConfiguration = { } ], 'selection-handler': { - type: 'cartesian-explorer-navigation-handler' + type: 'cartesian-explorer-selection-handler' } } ] From bc87e54f5fa49601f8cc4e07c8c33959dfb2c8ad Mon Sep 17 00:00:00 2001 From: Jyothish Jose Date: Sat, 9 Oct 2021 11:13:18 +0530 Subject: [PATCH 06/49] feat: timerange drilldown --- .../components/cartesian/d3/chart/cartesian-chart.ts | 12 +++++------- .../cartesian-explorer-selection-handler.model.ts | 5 +++-- 2 files changed, 8 insertions(+), 9 deletions(-) diff --git a/projects/observability/src/shared/components/cartesian/d3/chart/cartesian-chart.ts b/projects/observability/src/shared/components/cartesian/d3/chart/cartesian-chart.ts index a82fd1150..db0e46283 100644 --- a/projects/observability/src/shared/components/cartesian/d3/chart/cartesian-chart.ts +++ b/projects/observability/src/shared/components/cartesian/d3/chart/cartesian-chart.ts @@ -1,7 +1,7 @@ import { Injector, Renderer2 } from '@angular/core'; import { TimeRange } from '@hypertrace/common'; import { brush, BrushBehavior, D3BrushEvent } from 'd3-brush'; -import { ContainerElement, mouse, select } from 'd3-selection'; +import { ContainerElement, event as _d3CurrentEvent, mouse, select } from 'd3-selection'; import { LegendPosition } from '../../../legend/legend.component'; import { ChartTooltipRef } from '../../../utils/chart-tooltip/chart-tooltip-popover'; import { D3UtilService } from '../../../utils/d3/d3-util.service'; @@ -33,8 +33,6 @@ import { CartesianLegend } from '../legend/cartesian-legend'; import { ScaleBounds } from '../scale/cartesian-scale'; import { CartesianScaleBuilder } from '../scale/cartesian-scale-builder'; -import { event as _d3CurrentEvent } from 'd3-selection'; - // tslint:disable:max-file-line-count export class DefaultCartesianChart implements CartesianChart { public static DATA_SERIES_CLASS: string = 'data-series'; @@ -86,7 +84,7 @@ export class DefaultCartesianChart implements CartesianChart { if (listener.event === ChartEvent.Select) { const [start, end] = event.selection as [[number, number], [number, number]]; - let selctionData: any = { + const selctionData: any = { series: this.allSeriesData, start: start, end: end @@ -310,7 +308,7 @@ export class DefaultCartesianChart implements CartesianChart { } private attachBrush(): void { - let brushBehaviour: BrushBehavior = brush().on('end', () => + const brushBehaviour: BrushBehavior = brush().on('end', () => this.onBrushSelection(_d3CurrentEvent) ); @@ -465,10 +463,10 @@ export class DefaultCartesianChart implements CartesianChart { return 'click'; case ChartEvent.DoubleClick: return 'dblclick'; - case ChartEvent.DoubleClick: - return 'select'; case ChartEvent.RightClick: return 'contextmenu'; + case ChartEvent.Select: + return 'select'; default: return ''; } diff --git a/projects/observability/src/shared/dashboard/widgets/charts/cartesian-widget/interactions/cartesian-explorer-selection-handler.model.ts b/projects/observability/src/shared/dashboard/widgets/charts/cartesian-widget/interactions/cartesian-explorer-selection-handler.model.ts index 9035e08de..8337c5672 100644 --- a/projects/observability/src/shared/dashboard/widgets/charts/cartesian-widget/interactions/cartesian-explorer-selection-handler.model.ts +++ b/projects/observability/src/shared/dashboard/widgets/charts/cartesian-widget/interactions/cartesian-explorer-selection-handler.model.ts @@ -1,8 +1,8 @@ +import { NavigationService } from '@hypertrace/common'; +import { FilterOperator } from '@hypertrace/components'; import { Model } from '@hypertrace/hyperdash'; import { ModelInject } from '@hypertrace/hyperdash-angular'; import { Observable, of } from 'rxjs'; -import { NavigationService } from '../../../../../../../../common/src/navigation/navigation.service'; -import { FilterOperator } from '../../../../../../../../components/src/filtering/filter/filter-operators'; import { ExplorerService } from '../../../../../../pages/explorer/explorer-service'; import { ScopeQueryParam } from '../../../../../../pages/explorer/explorer.component'; import { InteractionHandler } from '../../../../interaction/interaction-handler'; @@ -24,6 +24,7 @@ export class CartesianExplorerSelectionHandlerModel implements InteractionHandle const startDate = data.getXAxisValue(startPoint[0]); const endDate = data.getXAxisValue(endPoint[0]); this.navigateToExplorer(startDate, endDate); + return; }); From 9aa0c214e693c83176f16f50202abee5a0b0bcdd Mon Sep 17 00:00:00 2001 From: Jyothish Jose Date: Mon, 18 Oct 2021 15:43:06 +0530 Subject: [PATCH 07/49] feat: cartesian drilldown select method changed --- .../cartesian/cartesian-chart.component.ts | 8 +++---- .../cartesian/d3/chart/cartesian-chart.ts | 22 +++++++++---------- .../cartesian-widget-renderer.component.ts | 3 ++- ...tesian-explorer-selection-handler.model.ts | 14 +++++------- 4 files changed, 23 insertions(+), 24 deletions(-) diff --git a/projects/observability/src/shared/components/cartesian/cartesian-chart.component.ts b/projects/observability/src/shared/components/cartesian/cartesian-chart.component.ts index 66db50e98..3009b65d1 100644 --- a/projects/observability/src/shared/components/cartesian/cartesian-chart.component.ts +++ b/projects/observability/src/shared/components/cartesian/cartesian-chart.component.ts @@ -66,7 +66,9 @@ export class CartesianChartComponent implements OnChanges, OnDestroy { public readonly selectedIntervalChange: EventEmitter = new EventEmitter(); @Output() - public readonly selectionChange: EventEmitter = new EventEmitter(); + public readonly selectionChange: EventEmitter< + MouseLocationData | Band>[] + > = new EventEmitter(); @ViewChild('chartContainer', { static: true }) public readonly container!: ElementRef; @@ -98,9 +100,7 @@ export class CartesianChartComponent implements OnChanges, OnDestroy { this.convertToDefaultTooltipRenderData(data) ) ) - .withEventListener(ChartEvent.Select, selectedData => { - this.selectionChange.emit(selectedData as any); - }); + .withEventListener(ChartEvent.Select, selectedData => this.selectionChange.emit(selectedData)); if (this.bands) { this.chart.withBands(...this.bands); diff --git a/projects/observability/src/shared/components/cartesian/d3/chart/cartesian-chart.ts b/projects/observability/src/shared/components/cartesian/d3/chart/cartesian-chart.ts index db0e46283..5ca7b94a9 100644 --- a/projects/observability/src/shared/components/cartesian/d3/chart/cartesian-chart.ts +++ b/projects/observability/src/shared/components/cartesian/d3/chart/cartesian-chart.ts @@ -1,6 +1,7 @@ import { Injector, Renderer2 } from '@angular/core'; import { TimeRange } from '@hypertrace/common'; import { brush, BrushBehavior, D3BrushEvent } from 'd3-brush'; +// tslint:disable-next-line: no-restricted-globals weird tslint error. Rename event so we can type it and not mistake it for other events import { ContainerElement, event as _d3CurrentEvent, mouse, select } from 'd3-selection'; import { LegendPosition } from '../../../legend/legend.component'; import { ChartTooltipRef } from '../../../utils/chart-tooltip/chart-tooltip-popover'; @@ -82,14 +83,16 @@ export class DefaultCartesianChart implements CartesianChart { this.eventListeners.forEach(listener => { if (listener.event === ChartEvent.Select) { - const [start, end] = event.selection as [[number, number], [number, number]]; + const [startPoint, endPoint] = event.selection as [[number, number], [number, number]]; - const selctionData: any = { - series: this.allSeriesData, - start: start, - end: end - }; - listener.onEvent(selctionData); + const startData = this.allSeriesData.flatMap(viz => + viz.dataForLocation({ x: startPoint[0], y: startPoint[1] }) + ); + + const endData = this.allSeriesData.flatMap(viz => viz.dataForLocation({ x: endPoint[0], y: endPoint[1] })); + + const selectedData: MouseLocationData | Band>[] = [startData[0], endData[0]]; + listener.onEvent(selectedData); } }); } @@ -318,10 +321,7 @@ export class DefaultCartesianChart implements CartesianChart { [width, height] ]); - select(this.mouseEventContainer!) - .append('g') - .attr('class', 'brush') - .call(brushBehaviour as any); + select(this.mouseEventContainer!).append('g').attr('class', 'brush').call(brushBehaviour); } private moveDataOnTopOfAxes(): void { diff --git a/projects/observability/src/shared/dashboard/widgets/charts/cartesian-widget/cartesian-widget-renderer.component.ts b/projects/observability/src/shared/dashboard/widgets/charts/cartesian-widget/cartesian-widget-renderer.component.ts index fc44d41c4..3f7a44031 100644 --- a/projects/observability/src/shared/dashboard/widgets/charts/cartesian-widget/cartesian-widget-renderer.component.ts +++ b/projects/observability/src/shared/dashboard/widgets/charts/cartesian-widget/cartesian-widget-renderer.component.ts @@ -7,6 +7,7 @@ import { NEVER, Observable } from 'rxjs'; import { switchMap, tap } from 'rxjs/operators'; import { Band, Series } from '../../../../components/cartesian/chart'; import { IntervalValue } from '../../../../components/interval-select/interval-select.component'; +import { MouseLocationData } from '../../../../components/utils/mouse-tracking/mouse-tracking'; import { CartesianDataFetcher, CartesianResult, CartesianWidgetModel } from './cartesian-widget.model'; @Renderer({ modelClass: CartesianWidgetModel }) @@ -55,7 +56,7 @@ export class CartesianWidgetRendererComponent extends Interacti this.updateDataObservable(); } - public onSelectionChange(data: any): void { + public onSelectionChange(data: MouseLocationData | Band>[]): void { this.model.selectionHandler?.execute(data); } diff --git a/projects/observability/src/shared/dashboard/widgets/charts/cartesian-widget/interactions/cartesian-explorer-selection-handler.model.ts b/projects/observability/src/shared/dashboard/widgets/charts/cartesian-widget/interactions/cartesian-explorer-selection-handler.model.ts index 8337c5672..1b2d5b191 100644 --- a/projects/observability/src/shared/dashboard/widgets/charts/cartesian-widget/interactions/cartesian-explorer-selection-handler.model.ts +++ b/projects/observability/src/shared/dashboard/widgets/charts/cartesian-widget/interactions/cartesian-explorer-selection-handler.model.ts @@ -18,15 +18,13 @@ export class CartesianExplorerSelectionHandlerModel implements InteractionHandle private readonly navigationService!: NavigationService; public execute(selectionData: any): Observable { - const startPoint = selectionData.start; - const endPoint = selectionData.end; - selectionData.series.map((data: any) => { - const startDate = data.getXAxisValue(startPoint[0]); - const endDate = data.getXAxisValue(endPoint[0]); - this.navigateToExplorer(startDate, endDate); + const startPoint = selectionData[0]; + const endPoint = selectionData[0]; - return; - }); + const startDate = new Date(startPoint.dataPoint.timestamp); + const endDate = new Date(endPoint.dataPoint.timestamp); + + this.navigateToExplorer(startDate, endDate); return of(); } From 32182d4db0a4f08ff2260850b4e3b04ec73dd947 Mon Sep 17 00:00:00 2001 From: Jyothish Jose Date: Mon, 18 Oct 2021 15:50:30 +0530 Subject: [PATCH 08/49] feat: cartesian drilldown select method changed --- .../interactions/cartesian-explorer-selection-handler.model.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/projects/observability/src/shared/dashboard/widgets/charts/cartesian-widget/interactions/cartesian-explorer-selection-handler.model.ts b/projects/observability/src/shared/dashboard/widgets/charts/cartesian-widget/interactions/cartesian-explorer-selection-handler.model.ts index 1b2d5b191..cccaa79b7 100644 --- a/projects/observability/src/shared/dashboard/widgets/charts/cartesian-widget/interactions/cartesian-explorer-selection-handler.model.ts +++ b/projects/observability/src/shared/dashboard/widgets/charts/cartesian-widget/interactions/cartesian-explorer-selection-handler.model.ts @@ -17,6 +17,7 @@ export class CartesianExplorerSelectionHandlerModel implements InteractionHandle @ModelInject(NavigationService) private readonly navigationService!: NavigationService; + // tslint:disable-next-line public execute(selectionData: any): Observable { const startPoint = selectionData[0]; const endPoint = selectionData[0]; From 434295bdc6fc34992535f3e0884e5f690185aec2 Mon Sep 17 00:00:00 2001 From: Jyothish Jose Date: Mon, 18 Oct 2021 21:03:45 +0530 Subject: [PATCH 09/49] feat: cartesian drilldown select method changed --- .../components/cartesian/cartesian-chart.component.ts | 7 ++++--- .../shared/components/cartesian/chart-interactivty.ts | 10 +++++++++- .../components/cartesian/d3/chart/cartesian-chart.ts | 10 ++++++++-- .../cartesian-explorer-selection-handler.model.ts | 4 ++-- 4 files changed, 23 insertions(+), 8 deletions(-) diff --git a/projects/observability/src/shared/components/cartesian/cartesian-chart.component.ts b/projects/observability/src/shared/components/cartesian/cartesian-chart.component.ts index 3009b65d1..623a08d9c 100644 --- a/projects/observability/src/shared/components/cartesian/cartesian-chart.component.ts +++ b/projects/observability/src/shared/components/cartesian/cartesian-chart.component.ts @@ -19,7 +19,7 @@ import { DefaultChartTooltipRenderData } from '../utils/chart-tooltip/default/de import { MouseLocationData } from '../utils/mouse-tracking/mouse-tracking'; import { Axis, AxisLocation, AxisType, Band, CartesianChart, RenderingStrategy, Series } from './chart'; import { ChartBuilderService } from './chart-builder.service'; -import { ChartEvent } from './chart-interactivty'; +import { ChartEvent, ChartSelectedType } from './chart-interactivty'; import { defaultXDataAccessor, defaultYDataAccessor } from './d3/scale/default-data-accessors'; @Component({ @@ -67,7 +67,7 @@ export class CartesianChartComponent implements OnChanges, OnDestroy { @Output() public readonly selectionChange: EventEmitter< - MouseLocationData | Band>[] + ChartSelectedType>> > = new EventEmitter(); @ViewChild('chartContainer', { static: true }) @@ -100,7 +100,8 @@ export class CartesianChartComponent implements OnChanges, OnDestroy { this.convertToDefaultTooltipRenderData(data) ) ) - .withEventListener(ChartEvent.Select, selectedData => this.selectionChange.emit(selectedData)); + // tslint:disable-next-line + .withEventListener(ChartEvent.Select, selectedData => this.selectionChange.emit(selectedData as any)); if (this.bands) { this.chart.withBands(...this.bands); diff --git a/projects/observability/src/shared/components/cartesian/chart-interactivty.ts b/projects/observability/src/shared/components/cartesian/chart-interactivty.ts index 7a31a9321..439a7fc26 100644 --- a/projects/observability/src/shared/components/cartesian/chart-interactivty.ts +++ b/projects/observability/src/shared/components/cartesian/chart-interactivty.ts @@ -8,9 +8,17 @@ export const enum ChartEvent { Select } -export type ChartEventListener = (data: MouseLocationData | Band>[]) => void; +export type ChartEventListener = ( + data: MouseLocationData | Band>[] | ChartSelectedType +) => void; export interface ChartTooltipTrackingOptions { followSingleAxis?: AxisType; radius?: number; } + +export interface ChartSelectedType { + series: TData[]; + start: TData; + end: TData; +} diff --git a/projects/observability/src/shared/components/cartesian/d3/chart/cartesian-chart.ts b/projects/observability/src/shared/components/cartesian/d3/chart/cartesian-chart.ts index 5ca7b94a9..6b7d0f04f 100644 --- a/projects/observability/src/shared/components/cartesian/d3/chart/cartesian-chart.ts +++ b/projects/observability/src/shared/components/cartesian/d3/chart/cartesian-chart.ts @@ -3,6 +3,7 @@ import { TimeRange } from '@hypertrace/common'; import { brush, BrushBehavior, D3BrushEvent } from 'd3-brush'; // tslint:disable-next-line: no-restricted-globals weird tslint error. Rename event so we can type it and not mistake it for other events import { ContainerElement, event as _d3CurrentEvent, mouse, select } from 'd3-selection'; +import { ChartSelectedType } from '../../../../../public-api'; import { LegendPosition } from '../../../legend/legend.component'; import { ChartTooltipRef } from '../../../utils/chart-tooltip/chart-tooltip-popover'; import { D3UtilService } from '../../../utils/d3/d3-util.service'; @@ -91,8 +92,13 @@ export class DefaultCartesianChart implements CartesianChart { const endData = this.allSeriesData.flatMap(viz => viz.dataForLocation({ x: endPoint[0], y: endPoint[1] })); - const selectedData: MouseLocationData | Band>[] = [startData[0], endData[0]]; - listener.onEvent(selectedData); + const selectedData: ChartSelectedType>> = { + series: startData, + start: startData[0], + end: endData[0] + }; + // tslint:disable-next-line + listener.onEvent(selectedData as any); } }); } diff --git a/projects/observability/src/shared/dashboard/widgets/charts/cartesian-widget/interactions/cartesian-explorer-selection-handler.model.ts b/projects/observability/src/shared/dashboard/widgets/charts/cartesian-widget/interactions/cartesian-explorer-selection-handler.model.ts index cccaa79b7..5343dfe00 100644 --- a/projects/observability/src/shared/dashboard/widgets/charts/cartesian-widget/interactions/cartesian-explorer-selection-handler.model.ts +++ b/projects/observability/src/shared/dashboard/widgets/charts/cartesian-widget/interactions/cartesian-explorer-selection-handler.model.ts @@ -19,8 +19,8 @@ export class CartesianExplorerSelectionHandlerModel implements InteractionHandle // tslint:disable-next-line public execute(selectionData: any): Observable { - const startPoint = selectionData[0]; - const endPoint = selectionData[0]; + const startPoint = selectionData.start; + const endPoint = selectionData.end; const startDate = new Date(startPoint.dataPoint.timestamp); const endDate = new Date(endPoint.dataPoint.timestamp); From 51f77ee0ff8a240d5aac7ddce5a57158afaee27f Mon Sep 17 00:00:00 2001 From: Jyothish Jose Date: Wed, 20 Oct 2021 22:57:36 +0530 Subject: [PATCH 10/49] feat: cartesian drilldown - test cases added --- .../cartesian/cartesian-chart.component.ts | 7 ++- .../cartesian/chart-interactivty.ts | 10 +--- .../cartesian/d3/chart/cartesian-chart.ts | 11 ++--- .../cartesian/d3/data/cartesian-data.ts | 4 -- .../d3/scale/band/cartesian-band-scale.ts | 4 -- .../cartesian/d3/scale/cartesian-scale.ts | 2 - .../linear/cartesian-continuous-scale.ts | 4 -- .../numeric/time/cartesian-time-scale.ts | 4 -- ...n-explorer-selection-handler.model.test.ts | 49 +++++++++++++++++++ ...tesian-explorer-selection-handler.model.ts | 5 +- 10 files changed, 59 insertions(+), 41 deletions(-) create mode 100644 projects/observability/src/shared/dashboard/widgets/charts/cartesian-widget/interactions/cartesian-explorer-selection-handler.model.test.ts diff --git a/projects/observability/src/shared/components/cartesian/cartesian-chart.component.ts b/projects/observability/src/shared/components/cartesian/cartesian-chart.component.ts index 623a08d9c..3009b65d1 100644 --- a/projects/observability/src/shared/components/cartesian/cartesian-chart.component.ts +++ b/projects/observability/src/shared/components/cartesian/cartesian-chart.component.ts @@ -19,7 +19,7 @@ import { DefaultChartTooltipRenderData } from '../utils/chart-tooltip/default/de import { MouseLocationData } from '../utils/mouse-tracking/mouse-tracking'; import { Axis, AxisLocation, AxisType, Band, CartesianChart, RenderingStrategy, Series } from './chart'; import { ChartBuilderService } from './chart-builder.service'; -import { ChartEvent, ChartSelectedType } from './chart-interactivty'; +import { ChartEvent } from './chart-interactivty'; import { defaultXDataAccessor, defaultYDataAccessor } from './d3/scale/default-data-accessors'; @Component({ @@ -67,7 +67,7 @@ export class CartesianChartComponent implements OnChanges, OnDestroy { @Output() public readonly selectionChange: EventEmitter< - ChartSelectedType>> + MouseLocationData | Band>[] > = new EventEmitter(); @ViewChild('chartContainer', { static: true }) @@ -100,8 +100,7 @@ export class CartesianChartComponent implements OnChanges, OnDestroy { this.convertToDefaultTooltipRenderData(data) ) ) - // tslint:disable-next-line - .withEventListener(ChartEvent.Select, selectedData => this.selectionChange.emit(selectedData as any)); + .withEventListener(ChartEvent.Select, selectedData => this.selectionChange.emit(selectedData)); if (this.bands) { this.chart.withBands(...this.bands); diff --git a/projects/observability/src/shared/components/cartesian/chart-interactivty.ts b/projects/observability/src/shared/components/cartesian/chart-interactivty.ts index 439a7fc26..7a31a9321 100644 --- a/projects/observability/src/shared/components/cartesian/chart-interactivty.ts +++ b/projects/observability/src/shared/components/cartesian/chart-interactivty.ts @@ -8,17 +8,9 @@ export const enum ChartEvent { Select } -export type ChartEventListener = ( - data: MouseLocationData | Band>[] | ChartSelectedType -) => void; +export type ChartEventListener = (data: MouseLocationData | Band>[]) => void; export interface ChartTooltipTrackingOptions { followSingleAxis?: AxisType; radius?: number; } - -export interface ChartSelectedType { - series: TData[]; - start: TData; - end: TData; -} diff --git a/projects/observability/src/shared/components/cartesian/d3/chart/cartesian-chart.ts b/projects/observability/src/shared/components/cartesian/d3/chart/cartesian-chart.ts index 6b7d0f04f..1131bee66 100644 --- a/projects/observability/src/shared/components/cartesian/d3/chart/cartesian-chart.ts +++ b/projects/observability/src/shared/components/cartesian/d3/chart/cartesian-chart.ts @@ -3,7 +3,6 @@ import { TimeRange } from '@hypertrace/common'; import { brush, BrushBehavior, D3BrushEvent } from 'd3-brush'; // tslint:disable-next-line: no-restricted-globals weird tslint error. Rename event so we can type it and not mistake it for other events import { ContainerElement, event as _d3CurrentEvent, mouse, select } from 'd3-selection'; -import { ChartSelectedType } from '../../../../../public-api'; import { LegendPosition } from '../../../legend/legend.component'; import { ChartTooltipRef } from '../../../utils/chart-tooltip/chart-tooltip-popover'; import { D3UtilService } from '../../../utils/d3/d3-util.service'; @@ -92,13 +91,9 @@ export class DefaultCartesianChart implements CartesianChart { const endData = this.allSeriesData.flatMap(viz => viz.dataForLocation({ x: endPoint[0], y: endPoint[1] })); - const selectedData: ChartSelectedType>> = { - series: startData, - start: startData[0], - end: endData[0] - }; - // tslint:disable-next-line - listener.onEvent(selectedData as any); + const selectedData: MouseLocationData>[] = [startData[0], endData[0]]; + + listener.onEvent(selectedData); } }); } diff --git a/projects/observability/src/shared/components/cartesian/d3/data/cartesian-data.ts b/projects/observability/src/shared/components/cartesian/d3/data/cartesian-data.ts index 40e3ea604..57359d6c5 100644 --- a/projects/observability/src/shared/components/cartesian/d3/data/cartesian-data.ts +++ b/projects/observability/src/shared/components/cartesian/d3/data/cartesian-data.ts @@ -41,10 +41,6 @@ export abstract class CartesianData { return this.dataLookupStrategy ? this.dataLookupStrategy.dataForLocation(location) : []; } - public getXAxisValue(point: number): Date | number { - return this.xScale.invert(point); - } - protected buildXScale(): AnyCartesianScale { return this.scaleBuilder.build(AxisType.X); } diff --git a/projects/observability/src/shared/components/cartesian/d3/scale/band/cartesian-band-scale.ts b/projects/observability/src/shared/components/cartesian/d3/scale/band/cartesian-band-scale.ts index de02d0a01..6648e3281 100644 --- a/projects/observability/src/shared/components/cartesian/d3/scale/band/cartesian-band-scale.ts +++ b/projects/observability/src/shared/components/cartesian/d3/scale/band/cartesian-band-scale.ts @@ -40,8 +40,4 @@ export class CartesianBandScale extends CartesianScale { protected getEmptyScale(): ScaleBand { return scaleBand().paddingInner(0.2).paddingOuter(0.1).align(1); } - - public invert(point: number): number { - return point; - } } diff --git a/projects/observability/src/shared/components/cartesian/d3/scale/cartesian-scale.ts b/projects/observability/src/shared/components/cartesian/d3/scale/cartesian-scale.ts index ab64d62d2..ab68983fe 100644 --- a/projects/observability/src/shared/components/cartesian/d3/scale/cartesian-scale.ts +++ b/projects/observability/src/shared/components/cartesian/d3/scale/cartesian-scale.ts @@ -29,8 +29,6 @@ export abstract class CartesianScale { protected abstract setRange(): void; - public abstract invert(point: number): Date | number; - public getValueFromData(data: TData): TDomain { return this.dataAccessor(data); } diff --git a/projects/observability/src/shared/components/cartesian/d3/scale/numeric/linear/cartesian-continuous-scale.ts b/projects/observability/src/shared/components/cartesian/d3/scale/numeric/linear/cartesian-continuous-scale.ts index 1f8be671d..07889d0c3 100644 --- a/projects/observability/src/shared/components/cartesian/d3/scale/numeric/linear/cartesian-continuous-scale.ts +++ b/projects/observability/src/shared/components/cartesian/d3/scale/numeric/linear/cartesian-continuous-scale.ts @@ -47,8 +47,4 @@ export class CartesianContinuousScale extends CartesianNumericScale { return scaleLinear(); } - - public invert(point: number): number { - return this.d3Implementation.invert(point); - } } diff --git a/projects/observability/src/shared/components/cartesian/d3/scale/numeric/time/cartesian-time-scale.ts b/projects/observability/src/shared/components/cartesian/d3/scale/numeric/time/cartesian-time-scale.ts index decee6f09..81102382f 100644 --- a/projects/observability/src/shared/components/cartesian/d3/scale/numeric/time/cartesian-time-scale.ts +++ b/projects/observability/src/shared/components/cartesian/d3/scale/numeric/time/cartesian-time-scale.ts @@ -63,8 +63,4 @@ export class CartesianTimeScale extends CartesianNumericScale { protected getEmptyScale(): ScaleTime { return scaleTime(); } - - public invert(point: number): Date { - return this.d3Implementation.invert(point); - } } diff --git a/projects/observability/src/shared/dashboard/widgets/charts/cartesian-widget/interactions/cartesian-explorer-selection-handler.model.test.ts b/projects/observability/src/shared/dashboard/widgets/charts/cartesian-widget/interactions/cartesian-explorer-selection-handler.model.test.ts new file mode 100644 index 000000000..a69044620 --- /dev/null +++ b/projects/observability/src/shared/dashboard/widgets/charts/cartesian-widget/interactions/cartesian-explorer-selection-handler.model.test.ts @@ -0,0 +1,49 @@ +import { createModelFactory } from '@hypertrace/dashboards/testing'; +import { mockProvider } from '@ngneat/spectator/jest'; +import { NavigationService } from '@hypertrace/common'; +import { ExplorerService } from '../../../../../../pages/explorer/explorer-service'; +import { CartesianExplorerSelectionHandlerModel } from './cartesian-explorer-selection-handler.model'; + +describe('Cartesian Explorer Selection Handler Model', () => { + const selectedData = [ + { + dataPoint: { + timestamp: 'Wed Oct 20 2021 00:25:00 GMT+0530 (India Standard Time)' + } + }, + { + dataPoint: { + timestamp: 'Wed Oct 20 2021 12:25:00 GMT+0530 (India Standard Time)' + } + } + ]; + + const buildModel = createModelFactory({ + providers: [ + mockProvider(ExplorerService, { + buildNavParamsWithFilters: jest.fn() + }), + mockProvider(NavigationService, { + navigate: jest.fn() + }) + ] + }); + + test('calls navigateToExplorer with correct parameters', () => { + const spectator = buildModel(CartesianExplorerSelectionHandlerModel); + const navService = spectator.get(NavigationService); + + spectator.model.execute(selectedData); + + const navigationUrl = { + navType: 'in-app', + path: '/explorer', + queryParams: { + filter: ['startTime_gte_1634669700000', 'endTime_lte_1634712900000'], + scope: 'endpoint-traces' + } + }; + + expect(navService.navigate).toHaveBeenLastCalledWith(navigationUrl); + }); +}); diff --git a/projects/observability/src/shared/dashboard/widgets/charts/cartesian-widget/interactions/cartesian-explorer-selection-handler.model.ts b/projects/observability/src/shared/dashboard/widgets/charts/cartesian-widget/interactions/cartesian-explorer-selection-handler.model.ts index 5343dfe00..d10589a38 100644 --- a/projects/observability/src/shared/dashboard/widgets/charts/cartesian-widget/interactions/cartesian-explorer-selection-handler.model.ts +++ b/projects/observability/src/shared/dashboard/widgets/charts/cartesian-widget/interactions/cartesian-explorer-selection-handler.model.ts @@ -19,10 +19,11 @@ export class CartesianExplorerSelectionHandlerModel implements InteractionHandle // tslint:disable-next-line public execute(selectionData: any): Observable { - const startPoint = selectionData.start; - const endPoint = selectionData.end; + const startPoint = selectionData[0]; + const endPoint = selectionData[1]; const startDate = new Date(startPoint.dataPoint.timestamp); + const endDate = new Date(endPoint.dataPoint.timestamp); this.navigateToExplorer(startDate, endDate); From 51a42a3e0c6a5311bd81ae05df113aae8aa63a2d Mon Sep 17 00:00:00 2001 From: Jyothish Jose Date: Wed, 20 Oct 2021 23:36:42 +0530 Subject: [PATCH 11/49] feat: cartesian drilldown - test cases added --- ...n-explorer-selection-handler.model.test.ts | 19 +++++++------------ 1 file changed, 7 insertions(+), 12 deletions(-) diff --git a/projects/observability/src/shared/dashboard/widgets/charts/cartesian-widget/interactions/cartesian-explorer-selection-handler.model.test.ts b/projects/observability/src/shared/dashboard/widgets/charts/cartesian-widget/interactions/cartesian-explorer-selection-handler.model.test.ts index a69044620..a61581901 100644 --- a/projects/observability/src/shared/dashboard/widgets/charts/cartesian-widget/interactions/cartesian-explorer-selection-handler.model.test.ts +++ b/projects/observability/src/shared/dashboard/widgets/charts/cartesian-widget/interactions/cartesian-explorer-selection-handler.model.test.ts @@ -19,23 +19,15 @@ describe('Cartesian Explorer Selection Handler Model', () => { ]; const buildModel = createModelFactory({ - providers: [ - mockProvider(ExplorerService, { - buildNavParamsWithFilters: jest.fn() - }), - mockProvider(NavigationService, { - navigate: jest.fn() - }) - ] + providers: [mockProvider(ExplorerService), mockProvider(NavigationService)] }); test('calls navigateToExplorer with correct parameters', () => { const spectator = buildModel(CartesianExplorerSelectionHandlerModel); + const explorerService = spectator.get(ExplorerService); const navService = spectator.get(NavigationService); - spectator.model.execute(selectedData); - - const navigationUrl = { + const navigationUrl1 = { navType: 'in-app', path: '/explorer', queryParams: { @@ -44,6 +36,9 @@ describe('Cartesian Explorer Selection Handler Model', () => { } }; - expect(navService.navigate).toHaveBeenLastCalledWith(navigationUrl); + spyOn(explorerService, 'buildNavParamsWithFilters').and.returnValue(navigationUrl1); + setTimeout(() => { + expect(navService.navigate).toHaveBeenCalledWith(navigationUrl1); + }); }); }); From f34823ca80da24da38d72693b15c57bf8bfa4ba1 Mon Sep 17 00:00:00 2001 From: Jyothish Jose Date: Wed, 20 Oct 2021 23:42:40 +0530 Subject: [PATCH 12/49] feat: cartesian drilldown - test cases added --- ...esian-explorer-selection-handler.model.test.ts | 15 +-------------- 1 file changed, 1 insertion(+), 14 deletions(-) diff --git a/projects/observability/src/shared/dashboard/widgets/charts/cartesian-widget/interactions/cartesian-explorer-selection-handler.model.test.ts b/projects/observability/src/shared/dashboard/widgets/charts/cartesian-widget/interactions/cartesian-explorer-selection-handler.model.test.ts index a61581901..b91ed03ff 100644 --- a/projects/observability/src/shared/dashboard/widgets/charts/cartesian-widget/interactions/cartesian-explorer-selection-handler.model.test.ts +++ b/projects/observability/src/shared/dashboard/widgets/charts/cartesian-widget/interactions/cartesian-explorer-selection-handler.model.test.ts @@ -1,23 +1,10 @@ +import { NavigationService } from '@hypertrace/common'; import { createModelFactory } from '@hypertrace/dashboards/testing'; import { mockProvider } from '@ngneat/spectator/jest'; -import { NavigationService } from '@hypertrace/common'; import { ExplorerService } from '../../../../../../pages/explorer/explorer-service'; import { CartesianExplorerSelectionHandlerModel } from './cartesian-explorer-selection-handler.model'; describe('Cartesian Explorer Selection Handler Model', () => { - const selectedData = [ - { - dataPoint: { - timestamp: 'Wed Oct 20 2021 00:25:00 GMT+0530 (India Standard Time)' - } - }, - { - dataPoint: { - timestamp: 'Wed Oct 20 2021 12:25:00 GMT+0530 (India Standard Time)' - } - } - ]; - const buildModel = createModelFactory({ providers: [mockProvider(ExplorerService), mockProvider(NavigationService)] }); From bcff6536bc331cdd69d8f3b0fb3f211e589efb21 Mon Sep 17 00:00:00 2001 From: Jyothish Jose Date: Thu, 21 Oct 2021 11:18:09 +0530 Subject: [PATCH 13/49] feat: cartesian drilldown - test cases added --- ...n-explorer-selection-handler.model.test.ts | 53 ++++++++++++++----- 1 file changed, 39 insertions(+), 14 deletions(-) diff --git a/projects/observability/src/shared/dashboard/widgets/charts/cartesian-widget/interactions/cartesian-explorer-selection-handler.model.test.ts b/projects/observability/src/shared/dashboard/widgets/charts/cartesian-widget/interactions/cartesian-explorer-selection-handler.model.test.ts index b91ed03ff..ecb5e98d7 100644 --- a/projects/observability/src/shared/dashboard/widgets/charts/cartesian-widget/interactions/cartesian-explorer-selection-handler.model.test.ts +++ b/projects/observability/src/shared/dashboard/widgets/charts/cartesian-widget/interactions/cartesian-explorer-selection-handler.model.test.ts @@ -1,31 +1,56 @@ import { NavigationService } from '@hypertrace/common'; import { createModelFactory } from '@hypertrace/dashboards/testing'; import { mockProvider } from '@ngneat/spectator/jest'; +import { of } from 'rxjs'; import { ExplorerService } from '../../../../../../pages/explorer/explorer-service'; import { CartesianExplorerSelectionHandlerModel } from './cartesian-explorer-selection-handler.model'; describe('Cartesian Explorer Selection Handler Model', () => { + const selectedData = [ + { + dataPoint: { + timestamp: 'Wed Oct 20 2021 00:25:00 GMT+0530 (India Standard Time)' + } + }, + { + dataPoint: { + timestamp: 'Wed Oct 20 2021 12:25:00 GMT+0530 (India Standard Time)' + } + } + ]; + + const navigationUrl = { + navType: 'in-app', + path: '/explorer', + queryParams: { + filter: ['startTime_gte_1634669700000', 'endTime_lte_1634712900000'], + scope: 'endpoint-traces' + } + }; + const buildModel = createModelFactory({ - providers: [mockProvider(ExplorerService), mockProvider(NavigationService)] + providers: [ + mockProvider(ExplorerService, { + buildNavParamsWithFilters: jest.fn().mockReturnValue(of(navigationUrl)) + }), + mockProvider(NavigationService, { + navigate: jest.fn() + }) + ] }); - test('calls navigateToExplorer with correct parameters', () => { + test('calls navigateToExplorer with correct parameters1', () => { const spectator = buildModel(CartesianExplorerSelectionHandlerModel); const explorerService = spectator.get(ExplorerService); const navService = spectator.get(NavigationService); - const navigationUrl1 = { - navType: 'in-app', - path: '/explorer', - queryParams: { - filter: ['startTime_gte_1634669700000', 'endTime_lte_1634712900000'], - scope: 'endpoint-traces' - } - }; + spectator.model.execute(selectedData); + expect(explorerService.buildNavParamsWithFilters).toHaveBeenCalled(); + expect(navService.navigate).toHaveBeenCalled(); - spyOn(explorerService, 'buildNavParamsWithFilters').and.returnValue(navigationUrl1); - setTimeout(() => { - expect(navService.navigate).toHaveBeenCalledWith(navigationUrl1); - }); + // spyOn(explorerService, 'buildNavParamsWithFilters').and.returnValue(navigationUrl); + // setTimeout(() => { + // expect(navService.navigate).toHaveBeenCalledWith(navigationUrl); + // }); }); }); From 69142df3b28c0635117ee8d39638d1b4f16a274b Mon Sep 17 00:00:00 2001 From: Jyothish Jose Date: Thu, 21 Oct 2021 11:20:05 +0530 Subject: [PATCH 14/49] feat: cartesian drilldown - test cases added --- .../cartesian-explorer-selection-handler.model.test.ts | 5 ----- 1 file changed, 5 deletions(-) diff --git a/projects/observability/src/shared/dashboard/widgets/charts/cartesian-widget/interactions/cartesian-explorer-selection-handler.model.test.ts b/projects/observability/src/shared/dashboard/widgets/charts/cartesian-widget/interactions/cartesian-explorer-selection-handler.model.test.ts index ecb5e98d7..fc4ceaac6 100644 --- a/projects/observability/src/shared/dashboard/widgets/charts/cartesian-widget/interactions/cartesian-explorer-selection-handler.model.test.ts +++ b/projects/observability/src/shared/dashboard/widgets/charts/cartesian-widget/interactions/cartesian-explorer-selection-handler.model.test.ts @@ -47,10 +47,5 @@ describe('Cartesian Explorer Selection Handler Model', () => { spectator.model.execute(selectedData); expect(explorerService.buildNavParamsWithFilters).toHaveBeenCalled(); expect(navService.navigate).toHaveBeenCalled(); - - // spyOn(explorerService, 'buildNavParamsWithFilters').and.returnValue(navigationUrl); - // setTimeout(() => { - // expect(navService.navigate).toHaveBeenCalledWith(navigationUrl); - // }); }); }); From 8863cee9d1f681f8faa8cb67dc75f240f5062b0e Mon Sep 17 00:00:00 2001 From: Jyothish Jose Date: Fri, 22 Oct 2021 18:26:31 +0530 Subject: [PATCH 15/49] feat: cartesian drilldown - test cases added --- .../common/src/time/time-range.service.ts | 11 ++++- .../cartesian/d3/chart/cartesian-chart.ts | 2 +- ...n-explorer-selection-handler.model.test.ts | 11 ++--- ...tesian-explorer-selection-handler.model.ts | 43 ++++++++----------- 4 files changed, 32 insertions(+), 35 deletions(-) diff --git a/projects/common/src/time/time-range.service.ts b/projects/common/src/time/time-range.service.ts index f9e96ca8e..b04434b08 100644 --- a/projects/common/src/time/time-range.service.ts +++ b/projects/common/src/time/time-range.service.ts @@ -2,7 +2,7 @@ import { Injectable } from '@angular/core'; import { isEmpty } from 'lodash-es'; import { EMPTY, ReplaySubject } from 'rxjs'; import { catchError, defaultIfEmpty, filter, map, switchMap, take } from 'rxjs/operators'; -import { NavigationService } from '../navigation/navigation.service'; +import { NavigationService, QueryParamObject } from '../navigation/navigation.service'; import { ReplayObservable } from '../utilities/rxjs/rxjs-utils'; import { FixedTimeRange } from './fixed-time-range'; import { RelativeTimeRange } from './relative-time-range'; @@ -110,4 +110,13 @@ export class TimeRangeService { public static toFixedTimeRange(startTime: Date, endTime: Date): FixedTimeRange { return new FixedTimeRange(startTime, endTime); } + + public toQueryParams(startTime: Date, endTime: Date): QueryParamObject { + const newTimeRange = TimeRangeService.toFixedTimeRange(startTime, endTime); + this.timeRangeSubject$.next(newTimeRange); + + return { + [TimeRangeService.TIME_RANGE_QUERY_PARAM]: newTimeRange.toUrlString() + }; + } } diff --git a/projects/observability/src/shared/components/cartesian/d3/chart/cartesian-chart.ts b/projects/observability/src/shared/components/cartesian/d3/chart/cartesian-chart.ts index 1131bee66..49c3a9e8f 100644 --- a/projects/observability/src/shared/components/cartesian/d3/chart/cartesian-chart.ts +++ b/projects/observability/src/shared/components/cartesian/d3/chart/cartesian-chart.ts @@ -91,7 +91,7 @@ export class DefaultCartesianChart implements CartesianChart { const endData = this.allSeriesData.flatMap(viz => viz.dataForLocation({ x: endPoint[0], y: endPoint[1] })); - const selectedData: MouseLocationData>[] = [startData[0], endData[0]]; + const selectedData = [startData[0], endData[0]]; listener.onEvent(selectedData); } diff --git a/projects/observability/src/shared/dashboard/widgets/charts/cartesian-widget/interactions/cartesian-explorer-selection-handler.model.test.ts b/projects/observability/src/shared/dashboard/widgets/charts/cartesian-widget/interactions/cartesian-explorer-selection-handler.model.test.ts index fc4ceaac6..9934c7783 100644 --- a/projects/observability/src/shared/dashboard/widgets/charts/cartesian-widget/interactions/cartesian-explorer-selection-handler.model.test.ts +++ b/projects/observability/src/shared/dashboard/widgets/charts/cartesian-widget/interactions/cartesian-explorer-selection-handler.model.test.ts @@ -1,8 +1,7 @@ -import { NavigationService } from '@hypertrace/common'; +import { NavigationService, TimeRangeService } from '@hypertrace/common'; import { createModelFactory } from '@hypertrace/dashboards/testing'; import { mockProvider } from '@ngneat/spectator/jest'; import { of } from 'rxjs'; -import { ExplorerService } from '../../../../../../pages/explorer/explorer-service'; import { CartesianExplorerSelectionHandlerModel } from './cartesian-explorer-selection-handler.model'; describe('Cartesian Explorer Selection Handler Model', () => { @@ -30,8 +29,8 @@ describe('Cartesian Explorer Selection Handler Model', () => { const buildModel = createModelFactory({ providers: [ - mockProvider(ExplorerService, { - buildNavParamsWithFilters: jest.fn().mockReturnValue(of(navigationUrl)) + mockProvider(TimeRangeService, { + toQueryParams: jest.fn().mockReturnValue(of(navigationUrl)) }), mockProvider(NavigationService, { navigate: jest.fn() @@ -39,13 +38,11 @@ describe('Cartesian Explorer Selection Handler Model', () => { ] }); - test('calls navigateToExplorer with correct parameters1', () => { + test('calls navigateToExplorer with correct parameters', () => { const spectator = buildModel(CartesianExplorerSelectionHandlerModel); - const explorerService = spectator.get(ExplorerService); const navService = spectator.get(NavigationService); spectator.model.execute(selectedData); - expect(explorerService.buildNavParamsWithFilters).toHaveBeenCalled(); expect(navService.navigate).toHaveBeenCalled(); }); }); diff --git a/projects/observability/src/shared/dashboard/widgets/charts/cartesian-widget/interactions/cartesian-explorer-selection-handler.model.ts b/projects/observability/src/shared/dashboard/widgets/charts/cartesian-widget/interactions/cartesian-explorer-selection-handler.model.ts index d10589a38..7c7473a80 100644 --- a/projects/observability/src/shared/dashboard/widgets/charts/cartesian-widget/interactions/cartesian-explorer-selection-handler.model.ts +++ b/projects/observability/src/shared/dashboard/widgets/charts/cartesian-widget/interactions/cartesian-explorer-selection-handler.model.ts @@ -1,18 +1,15 @@ -import { NavigationService } from '@hypertrace/common'; -import { FilterOperator } from '@hypertrace/components'; +import { NavigationParamsType, NavigationService, TimeRangeService } from '@hypertrace/common'; import { Model } from '@hypertrace/hyperdash'; import { ModelInject } from '@hypertrace/hyperdash-angular'; import { Observable, of } from 'rxjs'; -import { ExplorerService } from '../../../../../../pages/explorer/explorer-service'; -import { ScopeQueryParam } from '../../../../../../pages/explorer/explorer.component'; import { InteractionHandler } from '../../../../interaction/interaction-handler'; @Model({ type: 'cartesian-explorer-selection-handler' }) export class CartesianExplorerSelectionHandlerModel implements InteractionHandler { - @ModelInject(ExplorerService) - private readonly explorerService!: ExplorerService; + @ModelInject(TimeRangeService) + private readonly timeRangeService!: TimeRangeService; @ModelInject(NavigationService) private readonly navigationService!: NavigationService; @@ -22,9 +19,12 @@ export class CartesianExplorerSelectionHandlerModel implements InteractionHandle const startPoint = selectionData[0]; const endPoint = selectionData[1]; - const startDate = new Date(startPoint.dataPoint.timestamp); + // When there is only one point in selected area, start timestamp and end timestamp is same. This causes timerange exception + const startTime = new Date(startPoint.dataPoint.timestamp).getTime() - 6000; + const endTime = new Date(endPoint.dataPoint.timestamp).getTime() + 6000; - const endDate = new Date(endPoint.dataPoint.timestamp); + const startDate = new Date(startTime); + const endDate = new Date(endTime); this.navigateToExplorer(startDate, endDate); @@ -32,23 +32,14 @@ export class CartesianExplorerSelectionHandlerModel implements InteractionHandle } private navigateToExplorer(start: Date, end: Date): void { - const startTime: number = new Date(start).getTime(); - const endTime: number = new Date(end).getTime(); - this.explorerService - .buildNavParamsWithFilters(ScopeQueryParam.EndpointTraces, [ - { - field: 'startTime', - operator: FilterOperator.GreaterThanOrEqualTo, - value: startTime - }, - { - field: 'endTime', - operator: FilterOperator.LessThanOrEqualTo, - value: endTime - } - ]) - .subscribe(data => { - this.navigationService.navigate(data); - }); + const params = this.timeRangeService.toQueryParams(start, end); + + this.navigationService.navigate({ + navType: NavigationParamsType.InApp, + path: ['/explorer'], + queryParams: params, + queryParamsHandling: 'merge', + replaceCurrentHistory: true + }); } } From 36f63703ab0284559f4d8d6e51e902f43508eb27 Mon Sep 17 00:00:00 2001 From: Jyothish Jose Date: Mon, 25 Oct 2021 12:14:52 +0530 Subject: [PATCH 16/49] feat: context menu added --- ...esian-explorer-context-menu.component.scss | 19 ++++ ...an-explorer-context-menu.component.test.ts | 107 ++++++++++++++++++ ...rtesian-explorer-context-menu.component.ts | 42 +++++++ .../cartesian-explorer-context-menu.module.ts | 11 ++ 4 files changed, 179 insertions(+) create mode 100644 projects/observability/src/shared/dashboard/widgets/charts/cartesian-widget/interactions/cartesian-explorer-context-menu/cartesian-explorer-context-menu.component.scss create mode 100644 projects/observability/src/shared/dashboard/widgets/charts/cartesian-widget/interactions/cartesian-explorer-context-menu/cartesian-explorer-context-menu.component.test.ts create mode 100644 projects/observability/src/shared/dashboard/widgets/charts/cartesian-widget/interactions/cartesian-explorer-context-menu/cartesian-explorer-context-menu.component.ts create mode 100644 projects/observability/src/shared/dashboard/widgets/charts/cartesian-widget/interactions/cartesian-explorer-context-menu/cartesian-explorer-context-menu.module.ts diff --git a/projects/observability/src/shared/dashboard/widgets/charts/cartesian-widget/interactions/cartesian-explorer-context-menu/cartesian-explorer-context-menu.component.scss b/projects/observability/src/shared/dashboard/widgets/charts/cartesian-widget/interactions/cartesian-explorer-context-menu/cartesian-explorer-context-menu.component.scss new file mode 100644 index 000000000..50e7f903b --- /dev/null +++ b/projects/observability/src/shared/dashboard/widgets/charts/cartesian-widget/interactions/cartesian-explorer-context-menu/cartesian-explorer-context-menu.component.scss @@ -0,0 +1,19 @@ +@import 'font'; +@import 'color-palette'; +@import 'interaction'; + +.context-menu-container { + box-shadow: -1px -1px 8px rgba(0, 0, 0, 0.08), -3px 1px 24px rgba(0, 0, 0, 0.12); + border-radius: 6px; + overflow: hidden; + background-color: white; + z-index: 1; +} + +.context-menu { + display: flex; + flex-direction: row; + align-items: center; + padding: 5px 20px; + gap: 4px; +} diff --git a/projects/observability/src/shared/dashboard/widgets/charts/cartesian-widget/interactions/cartesian-explorer-context-menu/cartesian-explorer-context-menu.component.test.ts b/projects/observability/src/shared/dashboard/widgets/charts/cartesian-widget/interactions/cartesian-explorer-context-menu/cartesian-explorer-context-menu.component.test.ts new file mode 100644 index 000000000..daa74eb3d --- /dev/null +++ b/projects/observability/src/shared/dashboard/widgets/charts/cartesian-widget/interactions/cartesian-explorer-context-menu/cartesian-explorer-context-menu.component.test.ts @@ -0,0 +1,107 @@ +import { createHostFactory, Spectator } from '@ngneat/spectator/jest'; +import { CardListComponent, CardListMode } from './card-list.component'; +import { CardListModule } from './card-list.module'; + +describe('Card List component', () => { + let spectator: Spectator; + + const createHost = createHostFactory({ + declareComponent: false, + component: CardListComponent, + imports: [CardListModule], + providers: [] + }); + + test('should display all cards', () => { + const data = [ + { + name: 'first' + }, + { + name: 'second' + }, + { + name: 'third' + } + ]; + + spectator = createHost( + ` + + +
+
{{cardData.name}}
+
+
+
+ `, + { + hostProps: { + data: data, + mode: CardListMode.Card + } + } + ); + + // Add test logic + const projectedCardElements = spectator.queryAll('.custom-card'); + + expect(projectedCardElements).toExist(); + expect(projectedCardElements.length).toEqual(3); + + projectedCardElements.forEach((projectedCardElement, index) => { + const titleElement = projectedCardElement.querySelector('.title'); + expect(titleElement).toExist(); + expect(titleElement).toHaveText(data[index].name); + }); + + // Test selection style + const cardElements = spectator.queryAll('.card'); + spectator.click(cardElements[0]); + expect(spectator.query('.selected-card')).toBe(cardElements[0]); + expect(spectator.query('.selected-card')).not.toBe(cardElements[1]); + expect(spectator.query('.selected-card')).not.toBe(cardElements[2]); + }); + + test('should apply grouped style class', () => { + const data = [ + { + name: 'first', + grouped: true + }, + { + name: 'second', + grouped: false + }, + { + name: 'third', + grouped: false + } + ]; + + spectator = createHost( + ` + + +
+
{{cardData.name}}
+
+
+
+ `, + { + hostProps: { + data: data, + mode: CardListMode.Card + } + } + ); + + // Test selection style + const cardElements = spectator.queryAll('.card'); + spectator.click(cardElements[0]); + expect(spectator.query('.grouped-style')).toBe(cardElements[0]); + expect(spectator.query('.grouped-style')).not.toBe(cardElements[1]); + expect(spectator.query('.grouped-style')).not.toBe(cardElements[2]); + }); +}); diff --git a/projects/observability/src/shared/dashboard/widgets/charts/cartesian-widget/interactions/cartesian-explorer-context-menu/cartesian-explorer-context-menu.component.ts b/projects/observability/src/shared/dashboard/widgets/charts/cartesian-widget/interactions/cartesian-explorer-context-menu/cartesian-explorer-context-menu.component.ts new file mode 100644 index 000000000..4fb007932 --- /dev/null +++ b/projects/observability/src/shared/dashboard/widgets/charts/cartesian-widget/interactions/cartesian-explorer-context-menu/cartesian-explorer-context-menu.component.ts @@ -0,0 +1,42 @@ +import { ChangeDetectionStrategy, Component, EventEmitter, Input, Output } from '@angular/core'; +import { ButtonStyle } from '@hypertrace/components'; + +@Component({ + selector: 'ht-context-menu', + styleUrls: ['./context-menu.component.scss'], + changeDetection: ChangeDetectionStrategy.OnPush, + template: ` +
+
+
+ +
+ + +
+
+ ` +}) +export class CartesianExplorerContextMenuComponent { + @Input() + public menus?: ContextMenu[]; + + @Output() + public readonly menuSelect: EventEmitter = new EventEmitter(); + + public display: string = ButtonStyle.PlainText; + + public menuSelectHandler = (menu: ContextMenu): void => { + this.menuSelect.emit(menu); + }; +} + +export interface ContextMenu { + name: string; + icon: string; +} diff --git a/projects/observability/src/shared/dashboard/widgets/charts/cartesian-widget/interactions/cartesian-explorer-context-menu/cartesian-explorer-context-menu.module.ts b/projects/observability/src/shared/dashboard/widgets/charts/cartesian-widget/interactions/cartesian-explorer-context-menu/cartesian-explorer-context-menu.module.ts new file mode 100644 index 000000000..243589db9 --- /dev/null +++ b/projects/observability/src/shared/dashboard/widgets/charts/cartesian-widget/interactions/cartesian-explorer-context-menu/cartesian-explorer-context-menu.module.ts @@ -0,0 +1,11 @@ +import { CommonModule } from '@angular/common'; +import { NgModule } from '@angular/core'; +import { ButtonModule, DividerModule } from '@hypertrace/components'; +import { CartesianExplorerContextMenuComponent } from './cartesian-explorer-context-menu.component'; + +@NgModule({ + imports: [CommonModule, DividerModule, ButtonModule], + declarations: [CartesianExplorerContextMenuComponent], + exports: [CartesianExplorerContextMenuComponent] +}) +export class CartesianExplorerContextMenuModule {} From 6a94b7954cb962ebf04a457d7a7183f43085f65c Mon Sep 17 00:00:00 2001 From: Jyothish Jose Date: Mon, 25 Oct 2021 12:28:50 +0530 Subject: [PATCH 17/49] feat: context menu added --- ...tesian-explorer-selection-handler.model.ts | 29 ++++++++++++++++++- 1 file changed, 28 insertions(+), 1 deletion(-) diff --git a/projects/observability/src/shared/dashboard/widgets/charts/cartesian-widget/interactions/cartesian-explorer-selection-handler.model.ts b/projects/observability/src/shared/dashboard/widgets/charts/cartesian-widget/interactions/cartesian-explorer-selection-handler.model.ts index 7c7473a80..ece7c9c67 100644 --- a/projects/observability/src/shared/dashboard/widgets/charts/cartesian-widget/interactions/cartesian-explorer-selection-handler.model.ts +++ b/projects/observability/src/shared/dashboard/widgets/charts/cartesian-widget/interactions/cartesian-explorer-selection-handler.model.ts @@ -2,6 +2,13 @@ import { NavigationParamsType, NavigationService, TimeRangeService } from '@hype import { Model } from '@hypertrace/hyperdash'; import { ModelInject } from '@hypertrace/hyperdash-angular'; import { Observable, of } from 'rxjs'; +import { + PopoverBackdrop, + PopoverPositionType, + PopoverRef, + PopoverRelativePositionLocation, + PopoverService +} from '@hypertrace/components'; import { InteractionHandler } from '../../../../interaction/interaction-handler'; @Model({ @@ -14,6 +21,11 @@ export class CartesianExplorerSelectionHandlerModel implements InteractionHandle @ModelInject(NavigationService) private readonly navigationService!: NavigationService; + @ModelInject(PopoverService) + private readonly popoverService!: PopoverService; + + private popover!: PopoverRef; + // tslint:disable-next-line public execute(selectionData: any): Observable { const startPoint = selectionData[0]; @@ -31,6 +43,21 @@ export class CartesianExplorerSelectionHandlerModel implements InteractionHandle return of(); } + private showContextMenu() { + this.popover = this.popoverService.drawPopover({ + componentOrTemplate: this.contextMenuTemplate, + data: this.contextMenuTemplate, + position: { + type: PopoverPositionType.Relative, + origin: this.container.nativeElement, + locationPreferences: [PopoverRelativePositionLocation.AboveRightAligned] + }, + backdrop: PopoverBackdrop.Transparent + }); + this.popover.closeOnBackdropClick(); + this.popover.closeOnPopoverContentClick(); + } + private navigateToExplorer(start: Date, end: Date): void { const params = this.timeRangeService.toQueryParams(start, end); @@ -39,7 +66,7 @@ export class CartesianExplorerSelectionHandlerModel implements InteractionHandle path: ['/explorer'], queryParams: params, queryParamsHandling: 'merge', - replaceCurrentHistory: true + replaceCurrentHistory: false }); } } From 1b0638e82100ecd71794066eed7d340d7a6531a2 Mon Sep 17 00:00:00 2001 From: Jyothish Jose Date: Thu, 28 Oct 2021 21:47:56 +0530 Subject: [PATCH 18/49] feat: context menu added --- .../cartesian-chart.component.test.ts | 4 +- .../cartesian/cartesian-chart.component.ts | 63 ++++++++- .../cartesian/cartesian-chart.module.ts | 4 +- .../cartesian/d3/chart/cartesian-chart.ts | 2 +- ...an-explorer-context-menu.component.test.ts | 133 ++++++------------ ...rtesian-explorer-context-menu.component.ts | 4 +- ...tesian-explorer-selection-handler.model.ts | 27 ---- 7 files changed, 113 insertions(+), 124 deletions(-) diff --git a/projects/observability/src/shared/components/cartesian/cartesian-chart.component.test.ts b/projects/observability/src/shared/components/cartesian/cartesian-chart.component.test.ts index 92c0c91ab..5a4cf145d 100644 --- a/projects/observability/src/shared/components/cartesian/cartesian-chart.component.test.ts +++ b/projects/observability/src/shared/components/cartesian/cartesian-chart.component.test.ts @@ -1,6 +1,7 @@ import { Renderer2 } from '@angular/core'; import { fakeAsync, tick } from '@angular/core/testing'; import { DomElementMeasurerService, selector } from '@hypertrace/common'; +import { PopoverService } from '@hypertrace/components'; import { createHostFactory, mockProvider } from '@ngneat/spectator/jest'; import { LegendPosition } from '../legend/legend.component'; import { ChartTooltipBuilderService } from '../utils/chart-tooltip/chart-tooltip-builder.service'; @@ -29,7 +30,8 @@ describe('Cartesian Chart component', () => { }), getComputedTextLength: () => 0 }), - mockProvider(Renderer2) + mockProvider(Renderer2), + mockProvider(PopoverService) ] }); diff --git a/projects/observability/src/shared/components/cartesian/cartesian-chart.component.ts b/projects/observability/src/shared/components/cartesian/cartesian-chart.component.ts index 3009b65d1..39b1087c0 100644 --- a/projects/observability/src/shared/components/cartesian/cartesian-chart.component.ts +++ b/projects/observability/src/shared/components/cartesian/cartesian-chart.component.ts @@ -8,10 +8,20 @@ import { OnDestroy, Output, Renderer2, + TemplateRef, ViewChild } from '@angular/core'; +import { IconType } from '@hypertrace/assets-library'; import { DateCoercer, DateFormatter, TimeRange } from '@hypertrace/common'; +import { + PopoverBackdrop, + PopoverPositionType, + PopoverRef, + PopoverRelativePositionLocation, + PopoverService +} from '@hypertrace/components'; import { defaults } from 'lodash-es'; +import { ContextMenu } from '../../dashboard/widgets/charts/cartesian-widget/interactions/cartesian-explorer-context-menu/cartesian-explorer-context-menu.component'; import { IntervalValue } from '../interval-select/interval-select.component'; import { LegendPosition } from '../legend/legend.component'; import { ChartTooltipBuilderService } from '../utils/chart-tooltip/chart-tooltip-builder.service'; @@ -26,7 +36,13 @@ import { defaultXDataAccessor, defaultYDataAccessor } from './d3/scale/default-d selector: 'ht-cartesian-chart', styleUrls: ['./cartesian-chart.component.scss'], changeDetection: ChangeDetectionStrategy.OnPush, - template: `
` + template: `
+ + + ` }) export class CartesianChartComponent implements OnChanges, OnDestroy { @Input() @@ -73,14 +89,29 @@ export class CartesianChartComponent implements OnChanges, OnDestroy { @ViewChild('chartContainer', { static: true }) public readonly container!: ElementRef; + private popover?: PopoverRef; + + @ViewChild('contextMenuTemplate') + private readonly contextMenuTemplate!: TemplateRef; + private chart?: CartesianChart; private readonly dateCoercer: DateCoercer = new DateCoercer(); private readonly dateFormatter: DateFormatter = new DateFormatter(); + private selectedData!: MouseLocationData | Band>[]; + + public menus: ContextMenu[] = [ + { + name: 'Explore', + icon: IconType.ArrowUpRight + } + ]; + public constructor( private readonly chartBuilderService: ChartBuilderService, private readonly chartTooltipBuilderService: ChartTooltipBuilderService, - private readonly renderer: Renderer2 + private readonly renderer: Renderer2, + private readonly popoverService: PopoverService ) {} public ngOnChanges(): void { @@ -100,7 +131,14 @@ export class CartesianChartComponent implements OnChanges, OnDestroy { this.convertToDefaultTooltipRenderData(data) ) ) - .withEventListener(ChartEvent.Select, selectedData => this.selectionChange.emit(selectedData)); + .withEventListener(ChartEvent.Select, selectedData => { + this.selectedData = selectedData; + if (this.legend === LegendPosition.Bottom) { + this.selectionChange.emit(this.selectedData); + } else { + this.showContextMenu(); + } + }); if (this.bands) { this.chart.withBands(...this.bands); @@ -193,4 +231,23 @@ export class CartesianChartComponent implements OnChanges, OnDestroy { return xAsDate ? this.dateFormatter.format(xAsDate) : String(xValue); } + + private showContextMenu(): void { + this.popover = this.popoverService.drawPopover({ + componentOrTemplate: this.contextMenuTemplate, + data: this.contextMenuTemplate, + position: { + type: PopoverPositionType.Relative, + origin: this.container.nativeElement, + locationPreferences: [PopoverRelativePositionLocation.AboveRightAligned] + }, + backdrop: PopoverBackdrop.Transparent + }); + this.popover.closeOnBackdropClick(); + this.popover.closeOnPopoverContentClick(); + } + + public contextMenuSelectHandler(_menu: ContextMenu): void { + this.selectionChange.emit(this.selectedData); + } } diff --git a/projects/observability/src/shared/components/cartesian/cartesian-chart.module.ts b/projects/observability/src/shared/components/cartesian/cartesian-chart.module.ts index 33d245d08..95a34c57d 100644 --- a/projects/observability/src/shared/components/cartesian/cartesian-chart.module.ts +++ b/projects/observability/src/shared/components/cartesian/cartesian-chart.module.ts @@ -2,6 +2,7 @@ import { CommonModule } from '@angular/common'; import { NgModule } from '@angular/core'; import { FormattingModule } from '@hypertrace/common'; import { LabelModule, LayoutChangeModule, SelectModule } from '@hypertrace/components'; +import { CartesianExplorerContextMenuModule } from '../../dashboard/widgets/charts/cartesian-widget/interactions/cartesian-explorer-context-menu/cartesian-explorer-context-menu.module'; import { IntervalSelectModule } from '../interval-select/interval-select.module'; import { ChartTooltipModule } from '../utils/chart-tooltip/chart-tooltip.module'; import { CartesianChartComponent } from './cartesian-chart.component'; @@ -18,7 +19,8 @@ import { CartesianSummaryComponent } from './d3/legend/cartesian-summary.compone SelectModule, LayoutChangeModule, IntervalSelectModule, - ChartTooltipModule + ChartTooltipModule, + CartesianExplorerContextMenuModule ] }) export class CartesianChartModule {} diff --git a/projects/observability/src/shared/components/cartesian/d3/chart/cartesian-chart.ts b/projects/observability/src/shared/components/cartesian/d3/chart/cartesian-chart.ts index 49c3a9e8f..7935dd958 100644 --- a/projects/observability/src/shared/components/cartesian/d3/chart/cartesian-chart.ts +++ b/projects/observability/src/shared/components/cartesian/d3/chart/cartesian-chart.ts @@ -1,7 +1,7 @@ import { Injector, Renderer2 } from '@angular/core'; import { TimeRange } from '@hypertrace/common'; import { brush, BrushBehavior, D3BrushEvent } from 'd3-brush'; -// tslint:disable-next-line: no-restricted-globals weird tslint error. Rename event so we can type it and not mistake it for other events +// tslint:disable import { ContainerElement, event as _d3CurrentEvent, mouse, select } from 'd3-selection'; import { LegendPosition } from '../../../legend/legend.component'; import { ChartTooltipRef } from '../../../utils/chart-tooltip/chart-tooltip-popover'; diff --git a/projects/observability/src/shared/dashboard/widgets/charts/cartesian-widget/interactions/cartesian-explorer-context-menu/cartesian-explorer-context-menu.component.test.ts b/projects/observability/src/shared/dashboard/widgets/charts/cartesian-widget/interactions/cartesian-explorer-context-menu/cartesian-explorer-context-menu.component.test.ts index daa74eb3d..b8d655cfd 100644 --- a/projects/observability/src/shared/dashboard/widgets/charts/cartesian-widget/interactions/cartesian-explorer-context-menu/cartesian-explorer-context-menu.component.test.ts +++ b/projects/observability/src/shared/dashboard/widgets/charts/cartesian-widget/interactions/cartesian-explorer-context-menu/cartesian-explorer-context-menu.component.test.ts @@ -1,107 +1,62 @@ -import { createHostFactory, Spectator } from '@ngneat/spectator/jest'; -import { CardListComponent, CardListMode } from './card-list.component'; -import { CardListModule } from './card-list.module'; +import { fakeAsync } from '@angular/core/testing'; +import { createHostFactory, mockProvider, Spectator } from '@ngneat/spectator/jest'; -describe('Card List component', () => { - let spectator: Spectator; +import { HttpClientTestingModule } from '@angular/common/http/testing'; +import { IconLibraryTestingModule, IconType } from '@hypertrace/assets-library'; +import { PopoverService } from '@hypertrace/components'; +import { CartesianExplorerContextMenuComponent } from './cartesian-explorer-context-menu.component'; +import { CartesianExplorerContextMenuModule } from './cartesian-explorer-context-menu.module'; + +describe('Cartesian Explorer Context menu component', () => { + let spectator: Spectator; + + const mockPopoverRef = { + close: jest.fn() + }; const createHost = createHostFactory({ declareComponent: false, - component: CardListComponent, - imports: [CardListModule], - providers: [] + component: CartesianExplorerContextMenuComponent, + providers: [ + mockProvider(PopoverService, { + drawPopover: jest.fn().mockReturnValue(mockPopoverRef) + }) + ], + imports: [CartesianExplorerContextMenuModule, HttpClientTestingModule, IconLibraryTestingModule] }); - test('should display all cards', () => { - const data = [ - { - name: 'first' - }, - { - name: 'second' - }, - { - name: 'third' - } - ]; + test('correctly renders context menu', fakeAsync(() => { + const menuSelectSpy = jest.fn(); spectator = createHost( - ` - - -
-
{{cardData.name}}
-
-
-
- `, + ``, { hostProps: { - data: data, - mode: CardListMode.Card + menus: [ + { + name: 'Explore', + icon: IconType.ArrowUpRight + } + ], + contextMenuSelectHandler: menuSelectSpy } } ); - // Add test logic - const projectedCardElements = spectator.queryAll('.custom-card'); + expect(spectator.query('.context-menu')).toExist(); - expect(projectedCardElements).toExist(); - expect(projectedCardElements.length).toEqual(3); + spectator.tick(); - projectedCardElements.forEach((projectedCardElement, index) => { - const titleElement = projectedCardElement.querySelector('.title'); - expect(titleElement).toExist(); - expect(titleElement).toHaveText(data[index].name); - }); - - // Test selection style - const cardElements = spectator.queryAll('.card'); - spectator.click(cardElements[0]); - expect(spectator.query('.selected-card')).toBe(cardElements[0]); - expect(spectator.query('.selected-card')).not.toBe(cardElements[1]); - expect(spectator.query('.selected-card')).not.toBe(cardElements[2]); - }); + const buttonElement = spectator.query('button')!; - test('should apply grouped style class', () => { - const data = [ - { - name: 'first', - grouped: true - }, - { - name: 'second', - grouped: false - }, - { - name: 'third', - grouped: false - } - ]; - - spectator = createHost( - ` - - -
-
{{cardData.name}}
-
-
-
- `, - { - hostProps: { - data: data, - mode: CardListMode.Card - } - } - ); - - // Test selection style - const cardElements = spectator.queryAll('.card'); - spectator.click(cardElements[0]); - expect(spectator.query('.grouped-style')).toBe(cardElements[0]); - expect(spectator.query('.grouped-style')).not.toBe(cardElements[1]); - expect(spectator.query('.grouped-style')).not.toBe(cardElements[2]); - }); + // Click will toggle the values to true + spectator.click(buttonElement); + expect(menuSelectSpy).toHaveBeenCalledWith({ + name: 'Explore', + icon: IconType.ArrowUpRight + }); + })); }); diff --git a/projects/observability/src/shared/dashboard/widgets/charts/cartesian-widget/interactions/cartesian-explorer-context-menu/cartesian-explorer-context-menu.component.ts b/projects/observability/src/shared/dashboard/widgets/charts/cartesian-widget/interactions/cartesian-explorer-context-menu/cartesian-explorer-context-menu.component.ts index 4fb007932..8fc8644ae 100644 --- a/projects/observability/src/shared/dashboard/widgets/charts/cartesian-widget/interactions/cartesian-explorer-context-menu/cartesian-explorer-context-menu.component.ts +++ b/projects/observability/src/shared/dashboard/widgets/charts/cartesian-widget/interactions/cartesian-explorer-context-menu/cartesian-explorer-context-menu.component.ts @@ -2,8 +2,8 @@ import { ChangeDetectionStrategy, Component, EventEmitter, Input, Output } from import { ButtonStyle } from '@hypertrace/components'; @Component({ - selector: 'ht-context-menu', - styleUrls: ['./context-menu.component.scss'], + selector: 'ht-cartesian-explorer-context-menu', + styleUrls: ['./cartesian-explorer-context-menu.component.scss'], changeDetection: ChangeDetectionStrategy.OnPush, template: `
diff --git a/projects/observability/src/shared/dashboard/widgets/charts/cartesian-widget/interactions/cartesian-explorer-selection-handler.model.ts b/projects/observability/src/shared/dashboard/widgets/charts/cartesian-widget/interactions/cartesian-explorer-selection-handler.model.ts index ece7c9c67..b3f64fef0 100644 --- a/projects/observability/src/shared/dashboard/widgets/charts/cartesian-widget/interactions/cartesian-explorer-selection-handler.model.ts +++ b/projects/observability/src/shared/dashboard/widgets/charts/cartesian-widget/interactions/cartesian-explorer-selection-handler.model.ts @@ -2,13 +2,6 @@ import { NavigationParamsType, NavigationService, TimeRangeService } from '@hype import { Model } from '@hypertrace/hyperdash'; import { ModelInject } from '@hypertrace/hyperdash-angular'; import { Observable, of } from 'rxjs'; -import { - PopoverBackdrop, - PopoverPositionType, - PopoverRef, - PopoverRelativePositionLocation, - PopoverService -} from '@hypertrace/components'; import { InteractionHandler } from '../../../../interaction/interaction-handler'; @Model({ @@ -21,11 +14,6 @@ export class CartesianExplorerSelectionHandlerModel implements InteractionHandle @ModelInject(NavigationService) private readonly navigationService!: NavigationService; - @ModelInject(PopoverService) - private readonly popoverService!: PopoverService; - - private popover!: PopoverRef; - // tslint:disable-next-line public execute(selectionData: any): Observable { const startPoint = selectionData[0]; @@ -43,21 +31,6 @@ export class CartesianExplorerSelectionHandlerModel implements InteractionHandle return of(); } - private showContextMenu() { - this.popover = this.popoverService.drawPopover({ - componentOrTemplate: this.contextMenuTemplate, - data: this.contextMenuTemplate, - position: { - type: PopoverPositionType.Relative, - origin: this.container.nativeElement, - locationPreferences: [PopoverRelativePositionLocation.AboveRightAligned] - }, - backdrop: PopoverBackdrop.Transparent - }); - this.popover.closeOnBackdropClick(); - this.popover.closeOnPopoverContentClick(); - } - private navigateToExplorer(start: Date, end: Date): void { const params = this.timeRangeService.toQueryParams(start, end); From 0e2a82a8d6c06ae55b9d8b8f04728e4fde578aa7 Mon Sep 17 00:00:00 2001 From: Jyothish Jose Date: Tue, 2 Nov 2021 15:43:49 +0530 Subject: [PATCH 19/49] feat: selected points are converted to timestamp --- .../cartesian/d3/chart/cartesian-chart.ts | 26 ++++++++++++------- .../cartesian/d3/data/cartesian-data.ts | 4 +++ .../d3/scale/band/cartesian-band-scale.ts | 4 +++ .../cartesian/d3/scale/cartesian-scale.ts | 2 ++ .../linear/cartesian-continuous-scale.ts | 4 +++ .../numeric/time/cartesian-time-scale.ts | 4 +++ 6 files changed, 35 insertions(+), 9 deletions(-) diff --git a/projects/observability/src/shared/components/cartesian/d3/chart/cartesian-chart.ts b/projects/observability/src/shared/components/cartesian/d3/chart/cartesian-chart.ts index 7935dd958..572839307 100644 --- a/projects/observability/src/shared/components/cartesian/d3/chart/cartesian-chart.ts +++ b/projects/observability/src/shared/components/cartesian/d3/chart/cartesian-chart.ts @@ -1,6 +1,6 @@ import { Injector, Renderer2 } from '@angular/core'; import { TimeRange } from '@hypertrace/common'; -import { brush, BrushBehavior, D3BrushEvent } from 'd3-brush'; +import { BrushBehavior, brushX, D3BrushEvent } from 'd3-brush'; // tslint:disable import { ContainerElement, event as _d3CurrentEvent, mouse, select } from 'd3-selection'; import { LegendPosition } from '../../../legend/legend.component'; @@ -83,17 +83,25 @@ export class DefaultCartesianChart implements CartesianChart { this.eventListeners.forEach(listener => { if (listener.event === ChartEvent.Select) { - const [startPoint, endPoint] = event.selection as [[number, number], [number, number]]; - - const startData = this.allSeriesData.flatMap(viz => - viz.dataForLocation({ x: startPoint[0], y: startPoint[1] }) + const [startPoint, endPoint] = event.selection as [number, number]; + + const startDate = this.allSeriesData[0].getXAxisValue(startPoint); + const endDate = this.allSeriesData[0].getXAxisValue(endPoint); + console.log( + '🚀 ~ file: cartesian-chart.ts ~ line 89 ~ DefaultCartesianChart ~ onBrushSelection ~ startDate', + startDate, + endDate ); - const endData = this.allSeriesData.flatMap(viz => viz.dataForLocation({ x: endPoint[0], y: endPoint[1] })); + // const startData = this.allSeriesData.flatMap(viz => + // viz.dataForLocation({ x: startPoint[0], y: startPoint[1] }) + // ); + + // const endData = this.allSeriesData.flatMap(viz => viz.dataForLocation({ x: endPoint[0], y: endPoint[1] })); - const selectedData = [startData[0], endData[0]]; + // const selectedData = [startData[0], endData[0]]; - listener.onEvent(selectedData); + // listener.onEvent(selectedData); } }); } @@ -312,7 +320,7 @@ export class DefaultCartesianChart implements CartesianChart { } private attachBrush(): void { - const brushBehaviour: BrushBehavior = brush().on('end', () => + const brushBehaviour: BrushBehavior = brushX().on('end', () => this.onBrushSelection(_d3CurrentEvent) ); diff --git a/projects/observability/src/shared/components/cartesian/d3/data/cartesian-data.ts b/projects/observability/src/shared/components/cartesian/d3/data/cartesian-data.ts index 57359d6c5..577f9f235 100644 --- a/projects/observability/src/shared/components/cartesian/d3/data/cartesian-data.ts +++ b/projects/observability/src/shared/components/cartesian/d3/data/cartesian-data.ts @@ -48,4 +48,8 @@ export abstract class CartesianData { protected buildYScale(): AnyCartesianScale { return this.scaleBuilder.build(AxisType.Y); } + + public getXAxisValue(x: number): Date { + return new Date(this.xScale.invert(x)); + } } diff --git a/projects/observability/src/shared/components/cartesian/d3/scale/band/cartesian-band-scale.ts b/projects/observability/src/shared/components/cartesian/d3/scale/band/cartesian-band-scale.ts index 6648e3281..93048fee6 100644 --- a/projects/observability/src/shared/components/cartesian/d3/scale/band/cartesian-band-scale.ts +++ b/projects/observability/src/shared/components/cartesian/d3/scale/band/cartesian-band-scale.ts @@ -40,4 +40,8 @@ export class CartesianBandScale extends CartesianScale { protected getEmptyScale(): ScaleBand { return scaleBand().paddingInner(0.2).paddingOuter(0.1).align(1); } + + public invert(x: number): number { + return x; + } } diff --git a/projects/observability/src/shared/components/cartesian/d3/scale/cartesian-scale.ts b/projects/observability/src/shared/components/cartesian/d3/scale/cartesian-scale.ts index ab68983fe..54cc3ff79 100644 --- a/projects/observability/src/shared/components/cartesian/d3/scale/cartesian-scale.ts +++ b/projects/observability/src/shared/components/cartesian/d3/scale/cartesian-scale.ts @@ -29,6 +29,8 @@ export abstract class CartesianScale { protected abstract setRange(): void; + public abstract invert(x: number): Date | number; + public getValueFromData(data: TData): TDomain { return this.dataAccessor(data); } diff --git a/projects/observability/src/shared/components/cartesian/d3/scale/numeric/linear/cartesian-continuous-scale.ts b/projects/observability/src/shared/components/cartesian/d3/scale/numeric/linear/cartesian-continuous-scale.ts index 07889d0c3..ae033702f 100644 --- a/projects/observability/src/shared/components/cartesian/d3/scale/numeric/linear/cartesian-continuous-scale.ts +++ b/projects/observability/src/shared/components/cartesian/d3/scale/numeric/linear/cartesian-continuous-scale.ts @@ -47,4 +47,8 @@ export class CartesianContinuousScale extends CartesianNumericScale { return scaleLinear(); } + + public invert(x: number): number { + return this.d3Implementation.invert(x); + } } diff --git a/projects/observability/src/shared/components/cartesian/d3/scale/numeric/time/cartesian-time-scale.ts b/projects/observability/src/shared/components/cartesian/d3/scale/numeric/time/cartesian-time-scale.ts index 81102382f..4c0c7e441 100644 --- a/projects/observability/src/shared/components/cartesian/d3/scale/numeric/time/cartesian-time-scale.ts +++ b/projects/observability/src/shared/components/cartesian/d3/scale/numeric/time/cartesian-time-scale.ts @@ -63,4 +63,8 @@ export class CartesianTimeScale extends CartesianNumericScale { protected getEmptyScale(): ScaleTime { return scaleTime(); } + + public invert(x: number): Date { + return this.d3Implementation.invert(x); + } } From 3b595cf605c59219364e5730b9f3c867c0f03f8f Mon Sep 17 00:00:00 2001 From: Jyothish Jose Date: Wed, 3 Nov 2021 07:25:51 +0530 Subject: [PATCH 20/49] feat: context menu moved to renderer component --- .../cartesian/cartesian-chart.component.ts | 68 ++----------------- .../cartesian/cartesian-chart.module.ts | 4 +- .../cartesian/chart-interactivty.ts | 10 ++- .../cartesian/d3/chart/cartesian-chart.ts | 24 +++---- .../cartesian-widget-renderer.component.ts | 68 +++++++++++++++++-- .../cartesian-widget.module.ts | 4 +- ...tesian-explorer-selection-handler.model.ts | 17 ++--- 7 files changed, 95 insertions(+), 100 deletions(-) diff --git a/projects/observability/src/shared/components/cartesian/cartesian-chart.component.ts b/projects/observability/src/shared/components/cartesian/cartesian-chart.component.ts index 39b1087c0..ae500f811 100644 --- a/projects/observability/src/shared/components/cartesian/cartesian-chart.component.ts +++ b/projects/observability/src/shared/components/cartesian/cartesian-chart.component.ts @@ -8,20 +8,11 @@ import { OnDestroy, Output, Renderer2, - TemplateRef, ViewChild } from '@angular/core'; -import { IconType } from '@hypertrace/assets-library'; import { DateCoercer, DateFormatter, TimeRange } from '@hypertrace/common'; -import { - PopoverBackdrop, - PopoverPositionType, - PopoverRef, - PopoverRelativePositionLocation, - PopoverService -} from '@hypertrace/components'; + import { defaults } from 'lodash-es'; -import { ContextMenu } from '../../dashboard/widgets/charts/cartesian-widget/interactions/cartesian-explorer-context-menu/cartesian-explorer-context-menu.component'; import { IntervalValue } from '../interval-select/interval-select.component'; import { LegendPosition } from '../legend/legend.component'; import { ChartTooltipBuilderService } from '../utils/chart-tooltip/chart-tooltip-builder.service'; @@ -29,20 +20,14 @@ import { DefaultChartTooltipRenderData } from '../utils/chart-tooltip/default/de import { MouseLocationData } from '../utils/mouse-tracking/mouse-tracking'; import { Axis, AxisLocation, AxisType, Band, CartesianChart, RenderingStrategy, Series } from './chart'; import { ChartBuilderService } from './chart-builder.service'; -import { ChartEvent } from './chart-interactivty'; +import { CartesianSelectedData, ChartEvent } from './chart-interactivty'; import { defaultXDataAccessor, defaultYDataAccessor } from './d3/scale/default-data-accessors'; @Component({ selector: 'ht-cartesian-chart', styleUrls: ['./cartesian-chart.component.scss'], changeDetection: ChangeDetectionStrategy.OnPush, - template: `
- - - ` + template: `
` }) export class CartesianChartComponent implements OnChanges, OnDestroy { @Input() @@ -82,36 +67,19 @@ export class CartesianChartComponent implements OnChanges, OnDestroy { public readonly selectedIntervalChange: EventEmitter = new EventEmitter(); @Output() - public readonly selectionChange: EventEmitter< - MouseLocationData | Band>[] - > = new EventEmitter(); + public readonly selectionChange: EventEmitter> = new EventEmitter(); @ViewChild('chartContainer', { static: true }) public readonly container!: ElementRef; - private popover?: PopoverRef; - - @ViewChild('contextMenuTemplate') - private readonly contextMenuTemplate!: TemplateRef; - private chart?: CartesianChart; private readonly dateCoercer: DateCoercer = new DateCoercer(); private readonly dateFormatter: DateFormatter = new DateFormatter(); - private selectedData!: MouseLocationData | Band>[]; - - public menus: ContextMenu[] = [ - { - name: 'Explore', - icon: IconType.ArrowUpRight - } - ]; - public constructor( private readonly chartBuilderService: ChartBuilderService, private readonly chartTooltipBuilderService: ChartTooltipBuilderService, - private readonly renderer: Renderer2, - private readonly popoverService: PopoverService + private readonly renderer: Renderer2 ) {} public ngOnChanges(): void { @@ -132,12 +100,7 @@ export class CartesianChartComponent implements OnChanges, OnDestroy { ) ) .withEventListener(ChartEvent.Select, selectedData => { - this.selectedData = selectedData; - if (this.legend === LegendPosition.Bottom) { - this.selectionChange.emit(this.selectedData); - } else { - this.showContextMenu(); - } + this.selectionChange.emit(selectedData as CartesianSelectedData); }); if (this.bands) { @@ -231,23 +194,4 @@ export class CartesianChartComponent implements OnChanges, OnDestroy { return xAsDate ? this.dateFormatter.format(xAsDate) : String(xValue); } - - private showContextMenu(): void { - this.popover = this.popoverService.drawPopover({ - componentOrTemplate: this.contextMenuTemplate, - data: this.contextMenuTemplate, - position: { - type: PopoverPositionType.Relative, - origin: this.container.nativeElement, - locationPreferences: [PopoverRelativePositionLocation.AboveRightAligned] - }, - backdrop: PopoverBackdrop.Transparent - }); - this.popover.closeOnBackdropClick(); - this.popover.closeOnPopoverContentClick(); - } - - public contextMenuSelectHandler(_menu: ContextMenu): void { - this.selectionChange.emit(this.selectedData); - } } diff --git a/projects/observability/src/shared/components/cartesian/cartesian-chart.module.ts b/projects/observability/src/shared/components/cartesian/cartesian-chart.module.ts index 95a34c57d..33d245d08 100644 --- a/projects/observability/src/shared/components/cartesian/cartesian-chart.module.ts +++ b/projects/observability/src/shared/components/cartesian/cartesian-chart.module.ts @@ -2,7 +2,6 @@ import { CommonModule } from '@angular/common'; import { NgModule } from '@angular/core'; import { FormattingModule } from '@hypertrace/common'; import { LabelModule, LayoutChangeModule, SelectModule } from '@hypertrace/components'; -import { CartesianExplorerContextMenuModule } from '../../dashboard/widgets/charts/cartesian-widget/interactions/cartesian-explorer-context-menu/cartesian-explorer-context-menu.module'; import { IntervalSelectModule } from '../interval-select/interval-select.module'; import { ChartTooltipModule } from '../utils/chart-tooltip/chart-tooltip.module'; import { CartesianChartComponent } from './cartesian-chart.component'; @@ -19,8 +18,7 @@ import { CartesianSummaryComponent } from './d3/legend/cartesian-summary.compone SelectModule, LayoutChangeModule, IntervalSelectModule, - ChartTooltipModule, - CartesianExplorerContextMenuModule + ChartTooltipModule ] }) export class CartesianChartModule {} diff --git a/projects/observability/src/shared/components/cartesian/chart-interactivty.ts b/projects/observability/src/shared/components/cartesian/chart-interactivty.ts index 7a31a9321..ab9f22319 100644 --- a/projects/observability/src/shared/components/cartesian/chart-interactivty.ts +++ b/projects/observability/src/shared/components/cartesian/chart-interactivty.ts @@ -1,3 +1,4 @@ +import { TimeRange } from '@hypertrace/common'; import { MouseLocationData } from '../utils/mouse-tracking/mouse-tracking'; import { AxisType, Band, Series } from './chart'; @@ -8,9 +9,16 @@ export const enum ChartEvent { Select } -export type ChartEventListener = (data: MouseLocationData | Band>[]) => void; +export type ChartEventListener = ( + data: MouseLocationData | Band>[] | CartesianSelectedData +) => void; export interface ChartTooltipTrackingOptions { followSingleAxis?: AxisType; radius?: number; } + +export interface CartesianSelectedData { + timeRange: TimeRange; + selectedData: MouseLocationData | Band>[]; +} diff --git a/projects/observability/src/shared/components/cartesian/d3/chart/cartesian-chart.ts b/projects/observability/src/shared/components/cartesian/d3/chart/cartesian-chart.ts index 572839307..907c3136f 100644 --- a/projects/observability/src/shared/components/cartesian/d3/chart/cartesian-chart.ts +++ b/projects/observability/src/shared/components/cartesian/d3/chart/cartesian-chart.ts @@ -1,5 +1,5 @@ import { Injector, Renderer2 } from '@angular/core'; -import { TimeRange } from '@hypertrace/common'; +import { TimeRange, TimeRangeService } from '@hypertrace/common'; import { BrushBehavior, brushX, D3BrushEvent } from 'd3-brush'; // tslint:disable import { ContainerElement, event as _d3CurrentEvent, mouse, select } from 'd3-selection'; @@ -83,25 +83,23 @@ export class DefaultCartesianChart implements CartesianChart { this.eventListeners.forEach(listener => { if (listener.event === ChartEvent.Select) { + const { height } = this.mouseEventContainer!.getBoundingClientRect(); + const [startPoint, endPoint] = event.selection as [number, number]; const startDate = this.allSeriesData[0].getXAxisValue(startPoint); const endDate = this.allSeriesData[0].getXAxisValue(endPoint); - console.log( - '🚀 ~ file: cartesian-chart.ts ~ line 89 ~ DefaultCartesianChart ~ onBrushSelection ~ startDate', - startDate, - endDate - ); - // const startData = this.allSeriesData.flatMap(viz => - // viz.dataForLocation({ x: startPoint[0], y: startPoint[1] }) - // ); + const startData = this.allSeriesData.flatMap(viz => viz.dataForLocation({ x: startPoint, y: height })); - // const endData = this.allSeriesData.flatMap(viz => viz.dataForLocation({ x: endPoint[0], y: endPoint[1] })); + const endData = this.allSeriesData.flatMap(viz => viz.dataForLocation({ x: endPoint, y: height })); - // const selectedData = [startData[0], endData[0]]; - - // listener.onEvent(selectedData); + const timeRange = TimeRangeService.toFixedTimeRange(startDate, endDate); + const selectedData = { + timeRange: timeRange, + selectedData: [startData[0], endData[0]] + }; + listener.onEvent(selectedData); } }); } diff --git a/projects/observability/src/shared/dashboard/widgets/charts/cartesian-widget/cartesian-widget-renderer.component.ts b/projects/observability/src/shared/dashboard/widgets/charts/cartesian-widget/cartesian-widget-renderer.component.ts index 3f7a44031..17131ae89 100644 --- a/projects/observability/src/shared/dashboard/widgets/charts/cartesian-widget/cartesian-widget-renderer.component.ts +++ b/projects/observability/src/shared/dashboard/widgets/charts/cartesian-widget/cartesian-widget-renderer.component.ts @@ -1,14 +1,23 @@ -import { ChangeDetectionStrategy, ChangeDetectorRef, Component, Inject } from '@angular/core'; +import { ChangeDetectionStrategy, ChangeDetectorRef, Component, Inject, TemplateRef, ViewChild } from '@angular/core'; import { IntervalDurationService, TimeDuration } from '@hypertrace/common'; import { InteractiveDataWidgetRenderer } from '@hypertrace/dashboards'; import { Renderer } from '@hypertrace/hyperdash'; import { RendererApi, RENDERER_API } from '@hypertrace/hyperdash-angular'; import { NEVER, Observable } from 'rxjs'; import { switchMap, tap } from 'rxjs/operators'; +import { CartesianSelectedData, LegendPosition } from '../../../../../public-api'; import { Band, Series } from '../../../../components/cartesian/chart'; import { IntervalValue } from '../../../../components/interval-select/interval-select.component'; -import { MouseLocationData } from '../../../../components/utils/mouse-tracking/mouse-tracking'; import { CartesianDataFetcher, CartesianResult, CartesianWidgetModel } from './cartesian-widget.model'; +import { ContextMenu } from './interactions/cartesian-explorer-context-menu/cartesian-explorer-context-menu.component'; +import { IconType } from '@hypertrace/assets-library'; +import { + PopoverBackdrop, + PopoverFixedPositionLocation, + PopoverPositionType, + PopoverRef, + PopoverService +} from '@hypertrace/components'; @Renderer({ modelClass: CartesianWidgetModel }) @Component({ @@ -33,20 +42,42 @@ import { CartesianDataFetcher, CartesianResult, CartesianWidgetModel } from './c > + + + + ` }) -export class CartesianWidgetRendererComponent extends InteractiveDataWidgetRenderer< - CartesianWidgetModel, +export class CartesianWidgetRendererComponent extends InteractiveDataWidgetRenderer< + CartesianWidgetModel, CartesianData > { + private popover?: PopoverRef; + + @ViewChild('contextMenuTemplate') + private readonly contextMenuTemplate!: TemplateRef; + public constructor( @Inject(RENDERER_API) api: RendererApi>, changeDetector: ChangeDetectorRef, - private readonly intervalDurationService: IntervalDurationService + private readonly intervalDurationService: IntervalDurationService, + private readonly popoverService: PopoverService ) { super(api, changeDetector); } + public menus: ContextMenu[] = [ + { + name: 'Explore', + icon: IconType.ArrowUpRight + } + ]; + + private selectedData!: CartesianSelectedData; + public selectedInterval?: IntervalValue; public intervalOptions?: IntervalValue[]; private fetcher?: CartesianDataFetcher; @@ -56,8 +87,13 @@ export class CartesianWidgetRendererComponent extends Interacti this.updateDataObservable(); } - public onSelectionChange(data: MouseLocationData | Band>[]): void { - this.model.selectionHandler?.execute(data); + public onSelectionChange(selectedData: CartesianSelectedData): void { + if (this.model.legendPosition === LegendPosition.Bottom) { + this.model.selectionHandler?.execute(selectedData); + } else { + this.selectedData = selectedData; + this.showContextMenu(); + } } protected fetchData(): Observable> { @@ -120,6 +156,24 @@ export class CartesianWidgetRendererComponent extends Interacti return match || 'AUTO'; } + + private showContextMenu(): void { + this.popover = this.popoverService.drawPopover({ + componentOrTemplate: this.contextMenuTemplate, + data: this.contextMenuTemplate, + position: { + type: PopoverPositionType.Fixed, + location: PopoverFixedPositionLocation.Right + }, + backdrop: PopoverBackdrop.Transparent + }); + this.popover.closeOnBackdropClick(); + this.popover.closeOnPopoverContentClick(); + } + + public contextMenuSelectHandler(_menu: ContextMenu): void { + this.model.selectionHandler?.execute(this.selectedData); + } } interface CartesianData { diff --git a/projects/observability/src/shared/dashboard/widgets/charts/cartesian-widget/cartesian-widget.module.ts b/projects/observability/src/shared/dashboard/widgets/charts/cartesian-widget/cartesian-widget.module.ts index 10d90cd7b..c7b800a4e 100644 --- a/projects/observability/src/shared/dashboard/widgets/charts/cartesian-widget/cartesian-widget.module.ts +++ b/projects/observability/src/shared/dashboard/widgets/charts/cartesian-widget/cartesian-widget.module.ts @@ -10,6 +10,7 @@ import { BAND_ARRAY_TYPE } from './band-array/band-array-type'; import { BandModel } from './band.model'; import { CartesianWidgetRendererComponent } from './cartesian-widget-renderer.component'; import { CartesianWidgetModel } from './cartesian-widget.model'; +import { CartesianExplorerContextMenuModule } from './interactions/cartesian-explorer-context-menu/cartesian-explorer-context-menu.module'; import { CartesianExplorerSelectionHandlerModel } from './interactions/cartesian-explorer-selection-handler.model'; import { SeriesArrayEditorComponent } from './series-array/series-array-editor.component'; import { SERIES_ARRAY_TYPE } from './series-array/series-array-type'; @@ -38,7 +39,8 @@ import { SeriesModel } from './series.model'; }), TitledContentModule, LoadAsyncModule, - FormattingModule + FormattingModule, + CartesianExplorerContextMenuModule ] }) export class CartesianWidgetModule {} diff --git a/projects/observability/src/shared/dashboard/widgets/charts/cartesian-widget/interactions/cartesian-explorer-selection-handler.model.ts b/projects/observability/src/shared/dashboard/widgets/charts/cartesian-widget/interactions/cartesian-explorer-selection-handler.model.ts index b3f64fef0..473491768 100644 --- a/projects/observability/src/shared/dashboard/widgets/charts/cartesian-widget/interactions/cartesian-explorer-selection-handler.model.ts +++ b/projects/observability/src/shared/dashboard/widgets/charts/cartesian-widget/interactions/cartesian-explorer-selection-handler.model.ts @@ -2,12 +2,13 @@ import { NavigationParamsType, NavigationService, TimeRangeService } from '@hype import { Model } from '@hypertrace/hyperdash'; import { ModelInject } from '@hypertrace/hyperdash-angular'; import { Observable, of } from 'rxjs'; +import { CartesianSelectedData } from '../../../../../../public-api'; import { InteractionHandler } from '../../../../interaction/interaction-handler'; @Model({ type: 'cartesian-explorer-selection-handler' }) -export class CartesianExplorerSelectionHandlerModel implements InteractionHandler { +export class CartesianExplorerSelectionHandlerModel implements InteractionHandler { @ModelInject(TimeRangeService) private readonly timeRangeService!: TimeRangeService; @@ -15,18 +16,8 @@ export class CartesianExplorerSelectionHandlerModel implements InteractionHandle private readonly navigationService!: NavigationService; // tslint:disable-next-line - public execute(selectionData: any): Observable { - const startPoint = selectionData[0]; - const endPoint = selectionData[1]; - - // When there is only one point in selected area, start timestamp and end timestamp is same. This causes timerange exception - const startTime = new Date(startPoint.dataPoint.timestamp).getTime() - 6000; - const endTime = new Date(endPoint.dataPoint.timestamp).getTime() + 6000; - - const startDate = new Date(startTime); - const endDate = new Date(endTime); - - this.navigateToExplorer(startDate, endDate); + public execute(selectionData: CartesianSelectedData): Observable { + this.navigateToExplorer(selectionData.timeRange.startTime, selectionData.timeRange.endTime); return of(); } From 2436ceced067ccff475a737dbed06fc095204069 Mon Sep 17 00:00:00 2001 From: Jyothish Jose Date: Wed, 3 Nov 2021 08:29:57 +0530 Subject: [PATCH 21/49] feat: context menu location changed --- .../src/popover/popover-position-builder.ts | 5 +++++ projects/components/src/popover/popover.ts | 7 ++++++- .../cartesian/chart-interactivty.ts | 4 ++++ .../cartesian/d3/chart/cartesian-chart.ts | 6 +++++- .../cartesian-widget-renderer.component.ts | 21 ++++++++++--------- 5 files changed, 31 insertions(+), 12 deletions(-) diff --git a/projects/components/src/popover/popover-position-builder.ts b/projects/components/src/popover/popover-position-builder.ts index 54e902676..70d563108 100644 --- a/projects/components/src/popover/popover-position-builder.ts +++ b/projects/components/src/popover/popover-position-builder.ts @@ -109,6 +109,11 @@ export class PopoverPositionBuilder { return globalPosition.centerHorizontally().centerVertically(); case PopoverFixedPositionLocation.Right: return globalPosition.right('0').top('0'); + + case PopoverFixedPositionLocation.Custom: + return globalPosition + .left(`${popoverPosition.customLocation!.x}px`) + .top(`${popoverPosition.customLocation!.y}px`); case PopoverFixedPositionLocation.RightUnderHeader: default: return globalPosition.right('0').top(this.headerHeight ?? '0'); diff --git a/projects/components/src/popover/popover.ts b/projects/components/src/popover/popover.ts index 4c6c4e944..04e06e1d6 100644 --- a/projects/components/src/popover/popover.ts +++ b/projects/components/src/popover/popover.ts @@ -34,6 +34,10 @@ export interface PopoverRelativePosition { export interface PopoverFixedPosition { type: PopoverPositionType.Fixed; location: PopoverFixedPositionLocation; + customLocation?: { + x: number; + y: number; + }; } export type PopoverPosition = @@ -65,7 +69,8 @@ export const enum PopoverRelativePositionLocation { export const enum PopoverFixedPositionLocation { RightUnderHeader, Centered, - Right + Right, + Custom } export const POPOVER_DATA = new InjectionToken('POPOVER_DATA'); diff --git a/projects/observability/src/shared/components/cartesian/chart-interactivty.ts b/projects/observability/src/shared/components/cartesian/chart-interactivty.ts index ab9f22319..d7f18e42c 100644 --- a/projects/observability/src/shared/components/cartesian/chart-interactivty.ts +++ b/projects/observability/src/shared/components/cartesian/chart-interactivty.ts @@ -21,4 +21,8 @@ export interface ChartTooltipTrackingOptions { export interface CartesianSelectedData { timeRange: TimeRange; selectedData: MouseLocationData | Band>[]; + location: { + x: number; + y: number; + }; } diff --git a/projects/observability/src/shared/components/cartesian/d3/chart/cartesian-chart.ts b/projects/observability/src/shared/components/cartesian/d3/chart/cartesian-chart.ts index 907c3136f..aad19f86e 100644 --- a/projects/observability/src/shared/components/cartesian/d3/chart/cartesian-chart.ts +++ b/projects/observability/src/shared/components/cartesian/d3/chart/cartesian-chart.ts @@ -97,7 +97,11 @@ export class DefaultCartesianChart implements CartesianChart { const timeRange = TimeRangeService.toFixedTimeRange(startDate, endDate); const selectedData = { timeRange: timeRange, - selectedData: [startData[0], endData[0]] + selectedData: [startData[0], endData[0]], + location: { + x: event.sourceEvent.clientX, + y: event.sourceEvent.clientY + } }; listener.onEvent(selectedData); } diff --git a/projects/observability/src/shared/dashboard/widgets/charts/cartesian-widget/cartesian-widget-renderer.component.ts b/projects/observability/src/shared/dashboard/widgets/charts/cartesian-widget/cartesian-widget-renderer.component.ts index 17131ae89..4566e8a3e 100644 --- a/projects/observability/src/shared/dashboard/widgets/charts/cartesian-widget/cartesian-widget-renderer.component.ts +++ b/projects/observability/src/shared/dashboard/widgets/charts/cartesian-widget/cartesian-widget-renderer.component.ts @@ -1,5 +1,13 @@ import { ChangeDetectionStrategy, ChangeDetectorRef, Component, Inject, TemplateRef, ViewChild } from '@angular/core'; +import { IconType } from '@hypertrace/assets-library'; import { IntervalDurationService, TimeDuration } from '@hypertrace/common'; +import { + PopoverBackdrop, + PopoverFixedPositionLocation, + PopoverPositionType, + PopoverRef, + PopoverService +} from '@hypertrace/components'; import { InteractiveDataWidgetRenderer } from '@hypertrace/dashboards'; import { Renderer } from '@hypertrace/hyperdash'; import { RendererApi, RENDERER_API } from '@hypertrace/hyperdash-angular'; @@ -10,14 +18,6 @@ import { Band, Series } from '../../../../components/cartesian/chart'; import { IntervalValue } from '../../../../components/interval-select/interval-select.component'; import { CartesianDataFetcher, CartesianResult, CartesianWidgetModel } from './cartesian-widget.model'; import { ContextMenu } from './interactions/cartesian-explorer-context-menu/cartesian-explorer-context-menu.component'; -import { IconType } from '@hypertrace/assets-library'; -import { - PopoverBackdrop, - PopoverFixedPositionLocation, - PopoverPositionType, - PopoverRef, - PopoverService -} from '@hypertrace/components'; @Renderer({ modelClass: CartesianWidgetModel }) @Component({ @@ -52,7 +52,7 @@ import { ` }) export class CartesianWidgetRendererComponent extends InteractiveDataWidgetRenderer< - CartesianWidgetModel, + CartesianWidgetModel, CartesianData > { private popover?: PopoverRef; @@ -163,7 +163,8 @@ export class CartesianWidgetRendererComponent extends In data: this.contextMenuTemplate, position: { type: PopoverPositionType.Fixed, - location: PopoverFixedPositionLocation.Right + location: PopoverFixedPositionLocation.Custom, + customLocation: this.selectedData.location }, backdrop: PopoverBackdrop.Transparent }); From b91cf4e66ccf8fd0e4764d448740a59cc37359ea Mon Sep 17 00:00:00 2001 From: Jyothish Jose Date: Wed, 3 Nov 2021 09:02:06 +0530 Subject: [PATCH 22/49] feat: context menu location changed --- ...n-explorer-selection-handler.model.test.ts | 54 +++++++++++++++---- 1 file changed, 43 insertions(+), 11 deletions(-) diff --git a/projects/observability/src/shared/dashboard/widgets/charts/cartesian-widget/interactions/cartesian-explorer-selection-handler.model.test.ts b/projects/observability/src/shared/dashboard/widgets/charts/cartesian-widget/interactions/cartesian-explorer-selection-handler.model.test.ts index 9934c7783..688a10f01 100644 --- a/projects/observability/src/shared/dashboard/widgets/charts/cartesian-widget/interactions/cartesian-explorer-selection-handler.model.test.ts +++ b/projects/observability/src/shared/dashboard/widgets/charts/cartesian-widget/interactions/cartesian-explorer-selection-handler.model.test.ts @@ -2,21 +2,53 @@ import { NavigationService, TimeRangeService } from '@hypertrace/common'; import { createModelFactory } from '@hypertrace/dashboards/testing'; import { mockProvider } from '@ngneat/spectator/jest'; import { of } from 'rxjs'; +import { CartesianSelectedData } from '../../../../../../public-api'; import { CartesianExplorerSelectionHandlerModel } from './cartesian-explorer-selection-handler.model'; describe('Cartesian Explorer Selection Handler Model', () => { - const selectedData = [ - { - dataPoint: { - timestamp: 'Wed Oct 20 2021 00:25:00 GMT+0530 (India Standard Time)' + const selectedData: CartesianSelectedData = { + timeRange: TimeRangeService.toFixedTimeRange( + new Date('2021-11-02T05:33:19.288Z'), + new Date('2021-11-02T14:30:15.141Z') + ), + selectedData: [ + { + dataPoint: { timestamp: '2021-11-02T05:40:00.000Z', value: 1477.3599999999983 }, + context: { + data: [ + { timestamp: '2021-11-02T05:15:00.000Z', value: 774 }, + { timestamp: '2021-11-02T05:40:00.000Z', value: 1477.3599999999983 }, + { timestamp: '2021-11-02T12:05:00.000Z', value: 1056.48 } + ], + units: 'ms', + color: '#4b5f77', + name: 'p99', + type: 1, + stacking: false, + hide: false + }, + location: { x: 59, y: 31.023400000000215 } + }, + { + dataPoint: { timestamp: '2021-11-02T12:05:00.000Z', value: 1056.48 }, + context: { + data: [ + { timestamp: '2021-11-02T05:15:00.000Z', value: 774 }, + { timestamp: '2021-11-02T05:40:00.000Z', value: 1477.3599999999983 }, + { timestamp: '2021-11-02T12:05:00.000Z', value: 1056.48 } + ], + units: 'ms', + color: '#4b5f77', + name: 'p99', + type: 1, + stacking: false, + hide: false + }, + location: { x: 138, y: 82.58120000000001 } } - }, - { - dataPoint: { - timestamp: 'Wed Oct 20 2021 12:25:00 GMT+0530 (India Standard Time)' - } - } - ]; + ], + location: { x: 452, y: 763 } + }; const navigationUrl = { navType: 'in-app', From 60de5f0404ac605279dac3a475230344e0c2b705 Mon Sep 17 00:00:00 2001 From: Jyothish Jose Date: Wed, 3 Nov 2021 11:22:40 +0530 Subject: [PATCH 23/49] feat: context menu location changed --- .../shared/components/cartesian/d3/chart/cartesian-chart.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/projects/observability/src/shared/components/cartesian/d3/chart/cartesian-chart.ts b/projects/observability/src/shared/components/cartesian/d3/chart/cartesian-chart.ts index aad19f86e..cb4b315ed 100644 --- a/projects/observability/src/shared/components/cartesian/d3/chart/cartesian-chart.ts +++ b/projects/observability/src/shared/components/cartesian/d3/chart/cartesian-chart.ts @@ -2,7 +2,7 @@ import { Injector, Renderer2 } from '@angular/core'; import { TimeRange, TimeRangeService } from '@hypertrace/common'; import { BrushBehavior, brushX, D3BrushEvent } from 'd3-brush'; // tslint:disable -import { ContainerElement, event as _d3CurrentEvent, mouse, select } from 'd3-selection'; +import { ContainerElement, event as d3CurrentEvent, mouse, select } from 'd3-selection'; import { LegendPosition } from '../../../legend/legend.component'; import { ChartTooltipRef } from '../../../utils/chart-tooltip/chart-tooltip-popover'; import { D3UtilService } from '../../../utils/d3/d3-util.service'; @@ -323,7 +323,7 @@ export class DefaultCartesianChart implements CartesianChart { private attachBrush(): void { const brushBehaviour: BrushBehavior = brushX().on('end', () => - this.onBrushSelection(_d3CurrentEvent) + this.onBrushSelection(d3CurrentEvent) ); const { width, height } = this.hostElement.getBoundingClientRect(); From 6d7b68492ff5c9b8fa3b834b58d37d608e08cf02 Mon Sep 17 00:00:00 2001 From: Jyothish Jose Date: Thu, 11 Nov 2021 13:40:00 +0530 Subject: [PATCH 24/49] feat: context menu moved to interaction handler --- .../cartesian/chart-interactivty.ts | 1 + .../cartesian/d3/chart/cartesian-chart.ts | 3 +- .../cartesian-widget-renderer.component.ts | 61 ++----------------- ...rtesian-explorer-context-menu.component.ts | 35 ++++++++--- .../cartesian-explorer-navigation.service.ts | 24 ++++++++ ...tesian-explorer-selection-handler.model.ts | 52 +++++++++++----- 6 files changed, 93 insertions(+), 83 deletions(-) create mode 100644 projects/observability/src/shared/dashboard/widgets/charts/cartesian-widget/interactions/cartesian-explorer-navigation.service.ts diff --git a/projects/observability/src/shared/components/cartesian/chart-interactivty.ts b/projects/observability/src/shared/components/cartesian/chart-interactivty.ts index d7f18e42c..bb06c74a9 100644 --- a/projects/observability/src/shared/components/cartesian/chart-interactivty.ts +++ b/projects/observability/src/shared/components/cartesian/chart-interactivty.ts @@ -25,4 +25,5 @@ export interface CartesianSelectedData { x: number; y: number; }; + showContextMenu: boolean; } diff --git a/projects/observability/src/shared/components/cartesian/d3/chart/cartesian-chart.ts b/projects/observability/src/shared/components/cartesian/d3/chart/cartesian-chart.ts index cb4b315ed..22da846f0 100644 --- a/projects/observability/src/shared/components/cartesian/d3/chart/cartesian-chart.ts +++ b/projects/observability/src/shared/components/cartesian/d3/chart/cartesian-chart.ts @@ -101,7 +101,8 @@ export class DefaultCartesianChart implements CartesianChart { location: { x: event.sourceEvent.clientX, y: event.sourceEvent.clientY - } + }, + showContextMenu: true }; listener.onEvent(selectedData); } diff --git a/projects/observability/src/shared/dashboard/widgets/charts/cartesian-widget/cartesian-widget-renderer.component.ts b/projects/observability/src/shared/dashboard/widgets/charts/cartesian-widget/cartesian-widget-renderer.component.ts index 4566e8a3e..2cf541cd1 100644 --- a/projects/observability/src/shared/dashboard/widgets/charts/cartesian-widget/cartesian-widget-renderer.component.ts +++ b/projects/observability/src/shared/dashboard/widgets/charts/cartesian-widget/cartesian-widget-renderer.component.ts @@ -1,13 +1,6 @@ -import { ChangeDetectionStrategy, ChangeDetectorRef, Component, Inject, TemplateRef, ViewChild } from '@angular/core'; -import { IconType } from '@hypertrace/assets-library'; +import { ChangeDetectionStrategy, ChangeDetectorRef, Component, Inject } from '@angular/core'; import { IntervalDurationService, TimeDuration } from '@hypertrace/common'; -import { - PopoverBackdrop, - PopoverFixedPositionLocation, - PopoverPositionType, - PopoverRef, - PopoverService -} from '@hypertrace/components'; + import { InteractiveDataWidgetRenderer } from '@hypertrace/dashboards'; import { Renderer } from '@hypertrace/hyperdash'; import { RendererApi, RENDERER_API } from '@hypertrace/hyperdash-angular'; @@ -17,7 +10,6 @@ import { CartesianSelectedData, LegendPosition } from '../../../../../public-api import { Band, Series } from '../../../../components/cartesian/chart'; import { IntervalValue } from '../../../../components/interval-select/interval-select.component'; import { CartesianDataFetcher, CartesianResult, CartesianWidgetModel } from './cartesian-widget.model'; -import { ContextMenu } from './interactions/cartesian-explorer-context-menu/cartesian-explorer-context-menu.component'; @Renderer({ modelClass: CartesianWidgetModel }) @Component({ @@ -42,42 +34,20 @@ import { ContextMenu } from './interactions/cartesian-explorer-context-menu/cart > - - - - ` }) export class CartesianWidgetRendererComponent extends InteractiveDataWidgetRenderer< CartesianWidgetModel, CartesianData > { - private popover?: PopoverRef; - - @ViewChild('contextMenuTemplate') - private readonly contextMenuTemplate!: TemplateRef; - public constructor( @Inject(RENDERER_API) api: RendererApi>, changeDetector: ChangeDetectorRef, - private readonly intervalDurationService: IntervalDurationService, - private readonly popoverService: PopoverService + private readonly intervalDurationService: IntervalDurationService ) { super(api, changeDetector); } - public menus: ContextMenu[] = [ - { - name: 'Explore', - icon: IconType.ArrowUpRight - } - ]; - - private selectedData!: CartesianSelectedData; - public selectedInterval?: IntervalValue; public intervalOptions?: IntervalValue[]; private fetcher?: CartesianDataFetcher; @@ -89,11 +59,9 @@ export class CartesianWidgetRendererComponent extends In public onSelectionChange(selectedData: CartesianSelectedData): void { if (this.model.legendPosition === LegendPosition.Bottom) { - this.model.selectionHandler?.execute(selectedData); - } else { - this.selectedData = selectedData; - this.showContextMenu(); + selectedData.showContextMenu = false; } + this.model.selectionHandler?.execute(selectedData); } protected fetchData(): Observable> { @@ -156,25 +124,6 @@ export class CartesianWidgetRendererComponent extends In return match || 'AUTO'; } - - private showContextMenu(): void { - this.popover = this.popoverService.drawPopover({ - componentOrTemplate: this.contextMenuTemplate, - data: this.contextMenuTemplate, - position: { - type: PopoverPositionType.Fixed, - location: PopoverFixedPositionLocation.Custom, - customLocation: this.selectedData.location - }, - backdrop: PopoverBackdrop.Transparent - }); - this.popover.closeOnBackdropClick(); - this.popover.closeOnPopoverContentClick(); - } - - public contextMenuSelectHandler(_menu: ContextMenu): void { - this.model.selectionHandler?.execute(this.selectedData); - } } interface CartesianData { diff --git a/projects/observability/src/shared/dashboard/widgets/charts/cartesian-widget/interactions/cartesian-explorer-context-menu/cartesian-explorer-context-menu.component.ts b/projects/observability/src/shared/dashboard/widgets/charts/cartesian-widget/interactions/cartesian-explorer-context-menu/cartesian-explorer-context-menu.component.ts index 8fc8644ae..b2b277f7c 100644 --- a/projects/observability/src/shared/dashboard/widgets/charts/cartesian-widget/interactions/cartesian-explorer-context-menu/cartesian-explorer-context-menu.component.ts +++ b/projects/observability/src/shared/dashboard/widgets/charts/cartesian-widget/interactions/cartesian-explorer-context-menu/cartesian-explorer-context-menu.component.ts @@ -1,5 +1,8 @@ -import { ChangeDetectionStrategy, Component, EventEmitter, Input, Output } from '@angular/core'; -import { ButtonStyle } from '@hypertrace/components'; +import { ChangeDetectionStrategy, Component, Inject } from '@angular/core'; +import { ButtonStyle, POPOVER_DATA } from '@hypertrace/components'; +import { IconType } from '@hypertrace/assets-library'; +import { CartesianSelectedData } from '../../../../../../components/cartesian/chart-interactivty'; +import { CartesainExplorerNavigationService } from '../cartesian-explorer-navigation.service'; @Component({ selector: 'ht-cartesian-explorer-context-menu', @@ -22,17 +25,29 @@ import { ButtonStyle } from '@hypertrace/components';
` }) -export class CartesianExplorerContextMenuComponent { - @Input() - public menus?: ContextMenu[]; - - @Output() - public readonly menuSelect: EventEmitter = new EventEmitter(); +export class CartesianExplorerContextMenuComponent { + public menus?: ContextMenu[] = [ + { + name: 'Explore', + icon: IconType.ArrowUpRight + } + ]; public display: string = ButtonStyle.PlainText; + selectionData: CartesianSelectedData; + + public constructor( + @Inject(POPOVER_DATA) data: CartesianSelectedData, + private readonly cartesainExplorerNavigationService: CartesainExplorerNavigationService + ) { + this.selectionData = data; + } - public menuSelectHandler = (menu: ContextMenu): void => { - this.menuSelect.emit(menu); + public menuSelectHandler = (_menu: ContextMenu): void => { + this.cartesainExplorerNavigationService.navigateToExplorer( + this.selectionData.timeRange.startTime, + this.selectionData.timeRange.endTime + ); }; } diff --git a/projects/observability/src/shared/dashboard/widgets/charts/cartesian-widget/interactions/cartesian-explorer-navigation.service.ts b/projects/observability/src/shared/dashboard/widgets/charts/cartesian-widget/interactions/cartesian-explorer-navigation.service.ts new file mode 100644 index 000000000..637102352 --- /dev/null +++ b/projects/observability/src/shared/dashboard/widgets/charts/cartesian-widget/interactions/cartesian-explorer-navigation.service.ts @@ -0,0 +1,24 @@ +import { Injectable } from '@angular/core'; +import { NavigationParamsType, NavigationService, TimeRangeService } from '@hypertrace/common'; + +@Injectable({ + providedIn: 'root' +}) +export class CartesainExplorerNavigationService { + public constructor( + private readonly timeRangeService: TimeRangeService, + private readonly navigationService: NavigationService + ) {} + + public navigateToExplorer(start: Date, end: Date): void { + const params = this.timeRangeService.toQueryParams(start, end); + + this.navigationService.navigate({ + navType: NavigationParamsType.InApp, + path: ['/explorer'], + queryParams: params, + queryParamsHandling: 'merge', + replaceCurrentHistory: false + }); + } +} diff --git a/projects/observability/src/shared/dashboard/widgets/charts/cartesian-widget/interactions/cartesian-explorer-selection-handler.model.ts b/projects/observability/src/shared/dashboard/widgets/charts/cartesian-widget/interactions/cartesian-explorer-selection-handler.model.ts index 473491768..01f7ca7f7 100644 --- a/projects/observability/src/shared/dashboard/widgets/charts/cartesian-widget/interactions/cartesian-explorer-selection-handler.model.ts +++ b/projects/observability/src/shared/dashboard/widgets/charts/cartesian-widget/interactions/cartesian-explorer-selection-handler.model.ts @@ -1,36 +1,56 @@ -import { NavigationParamsType, NavigationService, TimeRangeService } from '@hypertrace/common'; import { Model } from '@hypertrace/hyperdash'; import { ModelInject } from '@hypertrace/hyperdash-angular'; import { Observable, of } from 'rxjs'; import { CartesianSelectedData } from '../../../../../../public-api'; import { InteractionHandler } from '../../../../interaction/interaction-handler'; +import { + PopoverBackdrop, + PopoverFixedPositionLocation, + PopoverPositionType, + PopoverRef, + PopoverService +} from '@hypertrace/components'; + +import { CartesianExplorerContextMenuComponent } from './cartesian-explorer-context-menu/cartesian-explorer-context-menu.component'; +import { CartesainExplorerNavigationService } from './cartesian-explorer-navigation.service'; @Model({ type: 'cartesian-explorer-selection-handler' }) export class CartesianExplorerSelectionHandlerModel implements InteractionHandler { - @ModelInject(TimeRangeService) - private readonly timeRangeService!: TimeRangeService; + @ModelInject(PopoverService) + private readonly popoverService!: PopoverService; + + @ModelInject(CartesainExplorerNavigationService) + private readonly cartesainExplorerNavigationService!: CartesainExplorerNavigationService; - @ModelInject(NavigationService) - private readonly navigationService!: NavigationService; + private popover?: PopoverRef; - // tslint:disable-next-line public execute(selectionData: CartesianSelectedData): Observable { - this.navigateToExplorer(selectionData.timeRange.startTime, selectionData.timeRange.endTime); + if (selectionData.showContextMenu) { + this.showContextMenu(selectionData); + } else { + this.cartesainExplorerNavigationService.navigateToExplorer( + selectionData.timeRange.startTime, + selectionData.timeRange.endTime + ); + } return of(); } - private navigateToExplorer(start: Date, end: Date): void { - const params = this.timeRangeService.toQueryParams(start, end); - - this.navigationService.navigate({ - navType: NavigationParamsType.InApp, - path: ['/explorer'], - queryParams: params, - queryParamsHandling: 'merge', - replaceCurrentHistory: false + private showContextMenu(selectionData: CartesianSelectedData): void { + this.popover = this.popoverService.drawPopover({ + componentOrTemplate: CartesianExplorerContextMenuComponent, + data: selectionData, + position: { + type: PopoverPositionType.Fixed, + location: PopoverFixedPositionLocation.Custom, + customLocation: selectionData.location + }, + backdrop: PopoverBackdrop.Transparent }); + this.popover.closeOnBackdropClick(); + this.popover.closeOnPopoverContentClick(); } } From a86efe96461c6a56a6fdde27f8487062faabeb4e Mon Sep 17 00:00:00 2001 From: Jyothish Jose Date: Thu, 11 Nov 2021 13:44:11 +0530 Subject: [PATCH 25/49] feat: fixed lint issues --- .../cartesian-explorer-context-menu.component.ts | 4 ++-- .../cartesian-explorer-selection-handler.model.ts | 10 +++++----- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/projects/observability/src/shared/dashboard/widgets/charts/cartesian-widget/interactions/cartesian-explorer-context-menu/cartesian-explorer-context-menu.component.ts b/projects/observability/src/shared/dashboard/widgets/charts/cartesian-widget/interactions/cartesian-explorer-context-menu/cartesian-explorer-context-menu.component.ts index b2b277f7c..2551b5e6d 100644 --- a/projects/observability/src/shared/dashboard/widgets/charts/cartesian-widget/interactions/cartesian-explorer-context-menu/cartesian-explorer-context-menu.component.ts +++ b/projects/observability/src/shared/dashboard/widgets/charts/cartesian-widget/interactions/cartesian-explorer-context-menu/cartesian-explorer-context-menu.component.ts @@ -1,6 +1,6 @@ import { ChangeDetectionStrategy, Component, Inject } from '@angular/core'; -import { ButtonStyle, POPOVER_DATA } from '@hypertrace/components'; import { IconType } from '@hypertrace/assets-library'; +import { ButtonStyle, POPOVER_DATA } from '@hypertrace/components'; import { CartesianSelectedData } from '../../../../../../components/cartesian/chart-interactivty'; import { CartesainExplorerNavigationService } from '../cartesian-explorer-navigation.service'; @@ -34,7 +34,7 @@ export class CartesianExplorerContextMenuComponent { ]; public display: string = ButtonStyle.PlainText; - selectionData: CartesianSelectedData; + public selectionData: CartesianSelectedData; public constructor( @Inject(POPOVER_DATA) data: CartesianSelectedData, diff --git a/projects/observability/src/shared/dashboard/widgets/charts/cartesian-widget/interactions/cartesian-explorer-selection-handler.model.ts b/projects/observability/src/shared/dashboard/widgets/charts/cartesian-widget/interactions/cartesian-explorer-selection-handler.model.ts index 01f7ca7f7..12f30fb00 100644 --- a/projects/observability/src/shared/dashboard/widgets/charts/cartesian-widget/interactions/cartesian-explorer-selection-handler.model.ts +++ b/projects/observability/src/shared/dashboard/widgets/charts/cartesian-widget/interactions/cartesian-explorer-selection-handler.model.ts @@ -1,8 +1,3 @@ -import { Model } from '@hypertrace/hyperdash'; -import { ModelInject } from '@hypertrace/hyperdash-angular'; -import { Observable, of } from 'rxjs'; -import { CartesianSelectedData } from '../../../../../../public-api'; -import { InteractionHandler } from '../../../../interaction/interaction-handler'; import { PopoverBackdrop, PopoverFixedPositionLocation, @@ -10,6 +5,11 @@ import { PopoverRef, PopoverService } from '@hypertrace/components'; +import { Model } from '@hypertrace/hyperdash'; +import { ModelInject } from '@hypertrace/hyperdash-angular'; +import { Observable, of } from 'rxjs'; +import { CartesianSelectedData } from '../../../../../../public-api'; +import { InteractionHandler } from '../../../../interaction/interaction-handler'; import { CartesianExplorerContextMenuComponent } from './cartesian-explorer-context-menu/cartesian-explorer-context-menu.component'; import { CartesainExplorerNavigationService } from './cartesian-explorer-navigation.service'; From 06a14798f99a0aede7694e90f06b264c7dbdf0ab Mon Sep 17 00:00:00 2001 From: Jyothish Jose Date: Thu, 11 Nov 2021 22:37:01 +0530 Subject: [PATCH 26/49] feat: updated test cases --- ...an-explorer-context-menu.component.test.ts | 7 +++-- ...n-explorer-selection-handler.model.test.ts | 30 ++++++++++++++----- ...tesian-explorer-selection-handler.model.ts | 2 +- 3 files changed, 29 insertions(+), 10 deletions(-) diff --git a/projects/observability/src/shared/dashboard/widgets/charts/cartesian-widget/interactions/cartesian-explorer-context-menu/cartesian-explorer-context-menu.component.test.ts b/projects/observability/src/shared/dashboard/widgets/charts/cartesian-widget/interactions/cartesian-explorer-context-menu/cartesian-explorer-context-menu.component.test.ts index b8d655cfd..d73ce2dee 100644 --- a/projects/observability/src/shared/dashboard/widgets/charts/cartesian-widget/interactions/cartesian-explorer-context-menu/cartesian-explorer-context-menu.component.test.ts +++ b/projects/observability/src/shared/dashboard/widgets/charts/cartesian-widget/interactions/cartesian-explorer-context-menu/cartesian-explorer-context-menu.component.test.ts @@ -6,9 +6,10 @@ import { IconLibraryTestingModule, IconType } from '@hypertrace/assets-library'; import { PopoverService } from '@hypertrace/components'; import { CartesianExplorerContextMenuComponent } from './cartesian-explorer-context-menu.component'; import { CartesianExplorerContextMenuModule } from './cartesian-explorer-context-menu.module'; +import { CartesainExplorerNavigationService } from '../cartesian-explorer-navigation.service'; describe('Cartesian Explorer Context menu component', () => { - let spectator: Spectator; + let spectator: Spectator>; const mockPopoverRef = { close: jest.fn() @@ -20,6 +21,9 @@ describe('Cartesian Explorer Context menu component', () => { providers: [ mockProvider(PopoverService, { drawPopover: jest.fn().mockReturnValue(mockPopoverRef) + }), + mockProvider(CartesainExplorerNavigationService, { + navigateToExplorer: jest.fn() }) ], imports: [CartesianExplorerContextMenuModule, HttpClientTestingModule, IconLibraryTestingModule] @@ -30,7 +34,6 @@ describe('Cartesian Explorer Context menu component', () => { spectator = createHost( ``, { diff --git a/projects/observability/src/shared/dashboard/widgets/charts/cartesian-widget/interactions/cartesian-explorer-selection-handler.model.test.ts b/projects/observability/src/shared/dashboard/widgets/charts/cartesian-widget/interactions/cartesian-explorer-selection-handler.model.test.ts index 688a10f01..6ec389067 100644 --- a/projects/observability/src/shared/dashboard/widgets/charts/cartesian-widget/interactions/cartesian-explorer-selection-handler.model.test.ts +++ b/projects/observability/src/shared/dashboard/widgets/charts/cartesian-widget/interactions/cartesian-explorer-selection-handler.model.test.ts @@ -1,9 +1,11 @@ -import { NavigationService, TimeRangeService } from '@hypertrace/common'; +import { TimeRangeService } from '@hypertrace/common'; import { createModelFactory } from '@hypertrace/dashboards/testing'; import { mockProvider } from '@ngneat/spectator/jest'; import { of } from 'rxjs'; +import { PopoverService } from '@hypertrace/components'; import { CartesianSelectedData } from '../../../../../../public-api'; import { CartesianExplorerSelectionHandlerModel } from './cartesian-explorer-selection-handler.model'; +import { CartesainExplorerNavigationService } from './cartesian-explorer-navigation.service'; describe('Cartesian Explorer Selection Handler Model', () => { const selectedData: CartesianSelectedData = { @@ -47,7 +49,8 @@ describe('Cartesian Explorer Selection Handler Model', () => { location: { x: 138, y: 82.58120000000001 } } ], - location: { x: 452, y: 763 } + location: { x: 452, y: 763 }, + showContextMenu: true }; const navigationUrl = { @@ -64,17 +67,30 @@ describe('Cartesian Explorer Selection Handler Model', () => { mockProvider(TimeRangeService, { toQueryParams: jest.fn().mockReturnValue(of(navigationUrl)) }), - mockProvider(NavigationService, { - navigate: jest.fn() + mockProvider(PopoverService, { + drawPopover: jest.fn() + }), + mockProvider(CartesainExplorerNavigationService, { + navigateToExplorer: jest.fn() }) ] }); - test('calls navigateToExplorer with correct parameters', () => { + test('calls showContextMenu with correct parameters', () => { + const spectator = buildModel(CartesianExplorerSelectionHandlerModel); + const popoverService = spectator.get(PopoverService); + + spectator.model.popover = popoverService.drawPopover(selectedData); + spectator.model.execute(selectedData); + expect(popoverService.drawPopover).toHaveBeenCalled(); + }); + + test('calls navigate to explorer correct parameters', () => { const spectator = buildModel(CartesianExplorerSelectionHandlerModel); - const navService = spectator.get(NavigationService); + const cartesainExplorerNavigationService = spectator.get(CartesainExplorerNavigationService); + selectedData.showContextMenu = false; spectator.model.execute(selectedData); - expect(navService.navigate).toHaveBeenCalled(); + expect(cartesainExplorerNavigationService.navigateToExplorer).toHaveBeenCalled(); }); }); diff --git a/projects/observability/src/shared/dashboard/widgets/charts/cartesian-widget/interactions/cartesian-explorer-selection-handler.model.ts b/projects/observability/src/shared/dashboard/widgets/charts/cartesian-widget/interactions/cartesian-explorer-selection-handler.model.ts index 12f30fb00..c15517bf3 100644 --- a/projects/observability/src/shared/dashboard/widgets/charts/cartesian-widget/interactions/cartesian-explorer-selection-handler.model.ts +++ b/projects/observability/src/shared/dashboard/widgets/charts/cartesian-widget/interactions/cartesian-explorer-selection-handler.model.ts @@ -24,7 +24,7 @@ export class CartesianExplorerSelectionHandlerModel implements Interactio @ModelInject(CartesainExplorerNavigationService) private readonly cartesainExplorerNavigationService!: CartesainExplorerNavigationService; - private popover?: PopoverRef; + public popover?: PopoverRef; public execute(selectionData: CartesianSelectedData): Observable { if (selectionData.showContextMenu) { From 450c6ad33f5b458573a666c6b90bda5cd6998e00 Mon Sep 17 00:00:00 2001 From: Jyothish Jose Date: Wed, 17 Nov 2021 11:01:32 +0530 Subject: [PATCH 27/49] feat: updated show contxt menu --- .../src/shared/components/cartesian/chart-interactivty.ts | 2 +- .../shared/components/cartesian/d3/chart/cartesian-chart.ts | 3 +-- .../cartesian-widget/cartesian-widget-renderer.component.ts | 2 ++ .../cartesian-explorer-context-menu.component.ts | 2 +- 4 files changed, 5 insertions(+), 4 deletions(-) diff --git a/projects/observability/src/shared/components/cartesian/chart-interactivty.ts b/projects/observability/src/shared/components/cartesian/chart-interactivty.ts index bb06c74a9..e15a38fba 100644 --- a/projects/observability/src/shared/components/cartesian/chart-interactivty.ts +++ b/projects/observability/src/shared/components/cartesian/chart-interactivty.ts @@ -25,5 +25,5 @@ export interface CartesianSelectedData { x: number; y: number; }; - showContextMenu: boolean; + showContextMenu?: boolean; } diff --git a/projects/observability/src/shared/components/cartesian/d3/chart/cartesian-chart.ts b/projects/observability/src/shared/components/cartesian/d3/chart/cartesian-chart.ts index 22da846f0..cb4b315ed 100644 --- a/projects/observability/src/shared/components/cartesian/d3/chart/cartesian-chart.ts +++ b/projects/observability/src/shared/components/cartesian/d3/chart/cartesian-chart.ts @@ -101,8 +101,7 @@ export class DefaultCartesianChart implements CartesianChart { location: { x: event.sourceEvent.clientX, y: event.sourceEvent.clientY - }, - showContextMenu: true + } }; listener.onEvent(selectedData); } diff --git a/projects/observability/src/shared/dashboard/widgets/charts/cartesian-widget/cartesian-widget-renderer.component.ts b/projects/observability/src/shared/dashboard/widgets/charts/cartesian-widget/cartesian-widget-renderer.component.ts index 2cf541cd1..90a08faa7 100644 --- a/projects/observability/src/shared/dashboard/widgets/charts/cartesian-widget/cartesian-widget-renderer.component.ts +++ b/projects/observability/src/shared/dashboard/widgets/charts/cartesian-widget/cartesian-widget-renderer.component.ts @@ -60,6 +60,8 @@ export class CartesianWidgetRendererComponent extends In public onSelectionChange(selectedData: CartesianSelectedData): void { if (this.model.legendPosition === LegendPosition.Bottom) { selectedData.showContextMenu = false; + } else { + selectedData.showContextMenu = true; } this.model.selectionHandler?.execute(selectedData); } diff --git a/projects/observability/src/shared/dashboard/widgets/charts/cartesian-widget/interactions/cartesian-explorer-context-menu/cartesian-explorer-context-menu.component.ts b/projects/observability/src/shared/dashboard/widgets/charts/cartesian-widget/interactions/cartesian-explorer-context-menu/cartesian-explorer-context-menu.component.ts index 2551b5e6d..3a07b80fe 100644 --- a/projects/observability/src/shared/dashboard/widgets/charts/cartesian-widget/interactions/cartesian-explorer-context-menu/cartesian-explorer-context-menu.component.ts +++ b/projects/observability/src/shared/dashboard/widgets/charts/cartesian-widget/interactions/cartesian-explorer-context-menu/cartesian-explorer-context-menu.component.ts @@ -51,7 +51,7 @@ export class CartesianExplorerContextMenuComponent { }; } -export interface ContextMenu { +interface ContextMenu { name: string; icon: string; } From da4413b4acd3e4fe40bf4c9493f95e3e37a52c9b Mon Sep 17 00:00:00 2001 From: Jyothish Jose Date: Wed, 17 Nov 2021 22:10:39 +0530 Subject: [PATCH 28/49] feat: cartesian drilldown - showing context menu optionally --- .../metrics/api-metrics.dashboard.ts | 8 ++-- .../overview/api-overview.dashboard.ts | 6 +-- .../metrics/backend-metrics.dashboard.ts | 8 ++-- .../overview/backend-overview.component.ts | 6 +-- .../metrics/service-metrics.dashboard.ts | 8 ++-- .../overview/service-overview.dashboard.ts | 6 +-- .../cartesian/chart-interactivty.ts | 1 - .../cartesian-widget-renderer.component.ts | 7 +-- .../cartesian-widget.module.ts | 3 ++ ...cartesian-chart-selection-handler.model.ts | 45 +++++++++++++++++++ ...an-explorer-context-menu.component.test.ts | 2 +- ...n-explorer-selection-handler.model.test.ts | 32 +------------ ...tesian-explorer-selection-handler.model.ts | 39 +++------------- src/app/home/home.dashboard.ts | 6 +-- 14 files changed, 81 insertions(+), 96 deletions(-) create mode 100644 projects/observability/src/shared/dashboard/widgets/charts/cartesian-widget/interactions/cartesian-chart-selection-handler.model.ts diff --git a/projects/observability/src/pages/apis/api-detail/metrics/api-metrics.dashboard.ts b/projects/observability/src/pages/apis/api-detail/metrics/api-metrics.dashboard.ts index 0c18c6376..41f93d5c0 100644 --- a/projects/observability/src/pages/apis/api-detail/metrics/api-metrics.dashboard.ts +++ b/projects/observability/src/pages/apis/api-detail/metrics/api-metrics.dashboard.ts @@ -272,7 +272,7 @@ export const apiMetricsDashboard: DashboardDefaultConfiguration = { } ], 'selection-handler': { - type: 'cartesian-explorer-selection-handler' + type: 'cartesian-chart-selection-handler' } }, { @@ -335,7 +335,7 @@ export const apiMetricsDashboard: DashboardDefaultConfiguration = { } ], 'selection-handler': { - type: 'cartesian-explorer-selection-handler' + type: 'cartesian-chart-selection-handler' } }, { @@ -377,7 +377,7 @@ export const apiMetricsDashboard: DashboardDefaultConfiguration = { } ], 'selection-handler': { - type: 'cartesian-explorer-selection-handler' + type: 'cartesian-chart-selection-handler' } } ] @@ -409,7 +409,7 @@ export const apiMetricsDashboard: DashboardDefaultConfiguration = { } ], 'selection-handler': { - type: 'cartesian-explorer-selection-handler' + type: 'cartesian-chart-selection-handler' } } ] diff --git a/projects/observability/src/pages/apis/api-detail/overview/api-overview.dashboard.ts b/projects/observability/src/pages/apis/api-detail/overview/api-overview.dashboard.ts index 30c48924c..23765a235 100644 --- a/projects/observability/src/pages/apis/api-detail/overview/api-overview.dashboard.ts +++ b/projects/observability/src/pages/apis/api-detail/overview/api-overview.dashboard.ts @@ -297,7 +297,7 @@ export const apiOverviewDashboard: DashboardDefaultConfiguration = { } ], 'selection-handler': { - type: 'cartesian-explorer-selection-handler' + type: 'cartesian-chart-selection-handler' } }, { @@ -394,7 +394,7 @@ export const apiOverviewDashboard: DashboardDefaultConfiguration = { } ], 'selection-handler': { - type: 'cartesian-explorer-selection-handler' + type: 'cartesian-chart-selection-handler' } }, { @@ -491,7 +491,7 @@ export const apiOverviewDashboard: DashboardDefaultConfiguration = { } ], 'selection-handler': { - type: 'cartesian-explorer-selection-handler' + type: 'cartesian-chart-selection-handler' } } ] diff --git a/projects/observability/src/pages/apis/backend-detail/metrics/backend-metrics.dashboard.ts b/projects/observability/src/pages/apis/backend-detail/metrics/backend-metrics.dashboard.ts index 048040bd5..69a8ddf79 100644 --- a/projects/observability/src/pages/apis/backend-detail/metrics/backend-metrics.dashboard.ts +++ b/projects/observability/src/pages/apis/backend-detail/metrics/backend-metrics.dashboard.ts @@ -256,7 +256,7 @@ export const backendMetricsDashboard: DashboardDefaultConfiguration = { } ], 'selection-handler': { - type: 'cartesian-explorer-selection-handler' + type: 'cartesian-chart-selection-handler' } }, { @@ -319,7 +319,7 @@ export const backendMetricsDashboard: DashboardDefaultConfiguration = { } ], 'selection-handler': { - type: 'cartesian-explorer-selection-handler' + type: 'cartesian-chart-selection-handler' } }, { @@ -345,7 +345,7 @@ export const backendMetricsDashboard: DashboardDefaultConfiguration = { } ], 'selection-handler': { - type: 'cartesian-explorer-selection-handler' + type: 'cartesian-chart-selection-handler' } } ] @@ -377,7 +377,7 @@ export const backendMetricsDashboard: DashboardDefaultConfiguration = { } ], 'selection-handler': { - type: 'cartesian-explorer-selection-handler' + type: 'cartesian-chart-selection-handler' } } ] diff --git a/projects/observability/src/pages/apis/backend-detail/overview/backend-overview.component.ts b/projects/observability/src/pages/apis/backend-detail/overview/backend-overview.component.ts index 685685ba3..503500bd8 100644 --- a/projects/observability/src/pages/apis/backend-detail/overview/backend-overview.component.ts +++ b/projects/observability/src/pages/apis/backend-detail/overview/backend-overview.component.ts @@ -289,7 +289,7 @@ export class BackendOverviewComponent { } ], 'selection-handler': { - type: 'cartesian-explorer-selection-handler' + type: 'cartesian-chart-selection-handler' } }, { @@ -370,7 +370,7 @@ export class BackendOverviewComponent { } ], 'selection-handler': { - type: 'cartesian-explorer-selection-handler' + type: 'cartesian-chart-selection-handler' } }, { @@ -451,7 +451,7 @@ export class BackendOverviewComponent { } ], 'selection-handler': { - type: 'cartesian-explorer-selection-handler' + type: 'cartesian-chart-selection-handler' } } ] diff --git a/projects/observability/src/pages/apis/service-detail/metrics/service-metrics.dashboard.ts b/projects/observability/src/pages/apis/service-detail/metrics/service-metrics.dashboard.ts index ec8f6892b..cab68b8a9 100644 --- a/projects/observability/src/pages/apis/service-detail/metrics/service-metrics.dashboard.ts +++ b/projects/observability/src/pages/apis/service-detail/metrics/service-metrics.dashboard.ts @@ -272,7 +272,7 @@ export const serviceMetricsDashboard: DashboardDefaultConfiguration = { } ], 'selection-handler': { - type: 'cartesian-explorer-selection-handler' + type: 'cartesian-chart-selection-handler' } }, { @@ -335,7 +335,7 @@ export const serviceMetricsDashboard: DashboardDefaultConfiguration = { } ], 'selection-handler': { - type: 'cartesian-explorer-selection-handler' + type: 'cartesian-chart-selection-handler' } }, { @@ -377,7 +377,7 @@ export const serviceMetricsDashboard: DashboardDefaultConfiguration = { } ], 'selection-handler': { - type: 'cartesian-explorer-selection-handler' + type: 'cartesian-chart-selection-handler' } } ] @@ -409,7 +409,7 @@ export const serviceMetricsDashboard: DashboardDefaultConfiguration = { } ], 'selection-handler': { - type: 'cartesian-explorer-selection-handler' + type: 'cartesian-chart-selection-handler' } } ] diff --git a/projects/observability/src/pages/apis/service-detail/overview/service-overview.dashboard.ts b/projects/observability/src/pages/apis/service-detail/overview/service-overview.dashboard.ts index cd6a8a866..43e0668c6 100644 --- a/projects/observability/src/pages/apis/service-detail/overview/service-overview.dashboard.ts +++ b/projects/observability/src/pages/apis/service-detail/overview/service-overview.dashboard.ts @@ -341,7 +341,7 @@ export const serviceOverviewDashboard: DashboardDefaultConfiguration = { } ], 'selection-handler': { - type: 'cartesian-explorer-selection-handler' + type: 'cartesian-chart-selection-handler' } }, { @@ -438,7 +438,7 @@ export const serviceOverviewDashboard: DashboardDefaultConfiguration = { } ], 'selection-handler': { - type: 'cartesian-explorer-selection-handler' + type: 'cartesian-chart-selection-handler' } }, { @@ -535,7 +535,7 @@ export const serviceOverviewDashboard: DashboardDefaultConfiguration = { } ], 'selection-handler': { - type: 'cartesian-explorer-selection-handler' + type: 'cartesian-chart-selection-handler' } } ] diff --git a/projects/observability/src/shared/components/cartesian/chart-interactivty.ts b/projects/observability/src/shared/components/cartesian/chart-interactivty.ts index e15a38fba..d7f18e42c 100644 --- a/projects/observability/src/shared/components/cartesian/chart-interactivty.ts +++ b/projects/observability/src/shared/components/cartesian/chart-interactivty.ts @@ -25,5 +25,4 @@ export interface CartesianSelectedData { x: number; y: number; }; - showContextMenu?: boolean; } diff --git a/projects/observability/src/shared/dashboard/widgets/charts/cartesian-widget/cartesian-widget-renderer.component.ts b/projects/observability/src/shared/dashboard/widgets/charts/cartesian-widget/cartesian-widget-renderer.component.ts index 90a08faa7..d3fa78a8a 100644 --- a/projects/observability/src/shared/dashboard/widgets/charts/cartesian-widget/cartesian-widget-renderer.component.ts +++ b/projects/observability/src/shared/dashboard/widgets/charts/cartesian-widget/cartesian-widget-renderer.component.ts @@ -6,7 +6,7 @@ import { Renderer } from '@hypertrace/hyperdash'; import { RendererApi, RENDERER_API } from '@hypertrace/hyperdash-angular'; import { NEVER, Observable } from 'rxjs'; import { switchMap, tap } from 'rxjs/operators'; -import { CartesianSelectedData, LegendPosition } from '../../../../../public-api'; +import { CartesianSelectedData } from '../../../../../public-api'; import { Band, Series } from '../../../../components/cartesian/chart'; import { IntervalValue } from '../../../../components/interval-select/interval-select.component'; import { CartesianDataFetcher, CartesianResult, CartesianWidgetModel } from './cartesian-widget.model'; @@ -58,11 +58,6 @@ export class CartesianWidgetRendererComponent extends In } public onSelectionChange(selectedData: CartesianSelectedData): void { - if (this.model.legendPosition === LegendPosition.Bottom) { - selectedData.showContextMenu = false; - } else { - selectedData.showContextMenu = true; - } this.model.selectionHandler?.execute(selectedData); } diff --git a/projects/observability/src/shared/dashboard/widgets/charts/cartesian-widget/cartesian-widget.module.ts b/projects/observability/src/shared/dashboard/widgets/charts/cartesian-widget/cartesian-widget.module.ts index c7b800a4e..9f27b9f31 100644 --- a/projects/observability/src/shared/dashboard/widgets/charts/cartesian-widget/cartesian-widget.module.ts +++ b/projects/observability/src/shared/dashboard/widgets/charts/cartesian-widget/cartesian-widget.module.ts @@ -10,8 +10,10 @@ import { BAND_ARRAY_TYPE } from './band-array/band-array-type'; import { BandModel } from './band.model'; import { CartesianWidgetRendererComponent } from './cartesian-widget-renderer.component'; import { CartesianWidgetModel } from './cartesian-widget.model'; +import { CartesianChartSelectionHandlerModel } from './interactions/cartesian-chart-selection-handler.model'; import { CartesianExplorerContextMenuModule } from './interactions/cartesian-explorer-context-menu/cartesian-explorer-context-menu.module'; import { CartesianExplorerSelectionHandlerModel } from './interactions/cartesian-explorer-selection-handler.model'; + import { SeriesArrayEditorComponent } from './series-array/series-array-editor.component'; import { SERIES_ARRAY_TYPE } from './series-array/series-array-type'; import { SeriesModel } from './series.model'; @@ -31,6 +33,7 @@ import { SeriesModel } from './series.model'; SeriesModel, BandModel, CartesianAxisModel, + CartesianChartSelectionHandlerModel, CartesianExplorerSelectionHandlerModel ], renderers: [CartesianWidgetRendererComponent], diff --git a/projects/observability/src/shared/dashboard/widgets/charts/cartesian-widget/interactions/cartesian-chart-selection-handler.model.ts b/projects/observability/src/shared/dashboard/widgets/charts/cartesian-widget/interactions/cartesian-chart-selection-handler.model.ts new file mode 100644 index 000000000..ae54c35eb --- /dev/null +++ b/projects/observability/src/shared/dashboard/widgets/charts/cartesian-widget/interactions/cartesian-chart-selection-handler.model.ts @@ -0,0 +1,45 @@ +import { + PopoverBackdrop, + PopoverFixedPositionLocation, + PopoverPositionType, + PopoverRef, + PopoverService +} from '@hypertrace/components'; +import { Model } from '@hypertrace/hyperdash'; +import { ModelInject } from '@hypertrace/hyperdash-angular'; +import { Observable, of } from 'rxjs'; +import { CartesianSelectedData } from '../../../../../../public-api'; +import { InteractionHandler } from '../../../../interaction/interaction-handler'; + +import { CartesianExplorerContextMenuComponent } from './cartesian-explorer-context-menu/cartesian-explorer-context-menu.component'; + +@Model({ + type: 'cartesian-chart-selection-handler' +}) +export class CartesianChartSelectionHandlerModel implements InteractionHandler { + @ModelInject(PopoverService) + private readonly popoverService!: PopoverService; + + public popover?: PopoverRef; + + public execute(selectionData: CartesianSelectedData): Observable { + this.showContextMenu(selectionData); + + return of(); + } + + private showContextMenu(selectionData: CartesianSelectedData): void { + this.popover = this.popoverService.drawPopover({ + componentOrTemplate: CartesianExplorerContextMenuComponent, + data: selectionData, + position: { + type: PopoverPositionType.Fixed, + location: PopoverFixedPositionLocation.Custom, + customLocation: selectionData.location + }, + backdrop: PopoverBackdrop.Transparent + }); + this.popover.closeOnBackdropClick(); + this.popover.closeOnPopoverContentClick(); + } +} diff --git a/projects/observability/src/shared/dashboard/widgets/charts/cartesian-widget/interactions/cartesian-explorer-context-menu/cartesian-explorer-context-menu.component.test.ts b/projects/observability/src/shared/dashboard/widgets/charts/cartesian-widget/interactions/cartesian-explorer-context-menu/cartesian-explorer-context-menu.component.test.ts index d73ce2dee..d295f3043 100644 --- a/projects/observability/src/shared/dashboard/widgets/charts/cartesian-widget/interactions/cartesian-explorer-context-menu/cartesian-explorer-context-menu.component.test.ts +++ b/projects/observability/src/shared/dashboard/widgets/charts/cartesian-widget/interactions/cartesian-explorer-context-menu/cartesian-explorer-context-menu.component.test.ts @@ -4,9 +4,9 @@ import { createHostFactory, mockProvider, Spectator } from '@ngneat/spectator/je import { HttpClientTestingModule } from '@angular/common/http/testing'; import { IconLibraryTestingModule, IconType } from '@hypertrace/assets-library'; import { PopoverService } from '@hypertrace/components'; +import { CartesainExplorerNavigationService } from '../cartesian-explorer-navigation.service'; import { CartesianExplorerContextMenuComponent } from './cartesian-explorer-context-menu.component'; import { CartesianExplorerContextMenuModule } from './cartesian-explorer-context-menu.module'; -import { CartesainExplorerNavigationService } from '../cartesian-explorer-navigation.service'; describe('Cartesian Explorer Context menu component', () => { let spectator: Spectator>; diff --git a/projects/observability/src/shared/dashboard/widgets/charts/cartesian-widget/interactions/cartesian-explorer-selection-handler.model.test.ts b/projects/observability/src/shared/dashboard/widgets/charts/cartesian-widget/interactions/cartesian-explorer-selection-handler.model.test.ts index 6ec389067..7de5c5620 100644 --- a/projects/observability/src/shared/dashboard/widgets/charts/cartesian-widget/interactions/cartesian-explorer-selection-handler.model.test.ts +++ b/projects/observability/src/shared/dashboard/widgets/charts/cartesian-widget/interactions/cartesian-explorer-selection-handler.model.test.ts @@ -1,11 +1,9 @@ import { TimeRangeService } from '@hypertrace/common'; import { createModelFactory } from '@hypertrace/dashboards/testing'; import { mockProvider } from '@ngneat/spectator/jest'; -import { of } from 'rxjs'; -import { PopoverService } from '@hypertrace/components'; import { CartesianSelectedData } from '../../../../../../public-api'; -import { CartesianExplorerSelectionHandlerModel } from './cartesian-explorer-selection-handler.model'; import { CartesainExplorerNavigationService } from './cartesian-explorer-navigation.service'; +import { CartesianExplorerSelectionHandlerModel } from './cartesian-explorer-selection-handler.model'; describe('Cartesian Explorer Selection Handler Model', () => { const selectedData: CartesianSelectedData = { @@ -49,47 +47,21 @@ describe('Cartesian Explorer Selection Handler Model', () => { location: { x: 138, y: 82.58120000000001 } } ], - location: { x: 452, y: 763 }, - showContextMenu: true - }; - - const navigationUrl = { - navType: 'in-app', - path: '/explorer', - queryParams: { - filter: ['startTime_gte_1634669700000', 'endTime_lte_1634712900000'], - scope: 'endpoint-traces' - } + location: { x: 452, y: 763 } }; const buildModel = createModelFactory({ providers: [ - mockProvider(TimeRangeService, { - toQueryParams: jest.fn().mockReturnValue(of(navigationUrl)) - }), - mockProvider(PopoverService, { - drawPopover: jest.fn() - }), mockProvider(CartesainExplorerNavigationService, { navigateToExplorer: jest.fn() }) ] }); - test('calls showContextMenu with correct parameters', () => { - const spectator = buildModel(CartesianExplorerSelectionHandlerModel); - const popoverService = spectator.get(PopoverService); - - spectator.model.popover = popoverService.drawPopover(selectedData); - spectator.model.execute(selectedData); - expect(popoverService.drawPopover).toHaveBeenCalled(); - }); - test('calls navigate to explorer correct parameters', () => { const spectator = buildModel(CartesianExplorerSelectionHandlerModel); const cartesainExplorerNavigationService = spectator.get(CartesainExplorerNavigationService); - selectedData.showContextMenu = false; spectator.model.execute(selectedData); expect(cartesainExplorerNavigationService.navigateToExplorer).toHaveBeenCalled(); }); diff --git a/projects/observability/src/shared/dashboard/widgets/charts/cartesian-widget/interactions/cartesian-explorer-selection-handler.model.ts b/projects/observability/src/shared/dashboard/widgets/charts/cartesian-widget/interactions/cartesian-explorer-selection-handler.model.ts index c15517bf3..d19a37eed 100644 --- a/projects/observability/src/shared/dashboard/widgets/charts/cartesian-widget/interactions/cartesian-explorer-selection-handler.model.ts +++ b/projects/observability/src/shared/dashboard/widgets/charts/cartesian-widget/interactions/cartesian-explorer-selection-handler.model.ts @@ -1,56 +1,27 @@ -import { - PopoverBackdrop, - PopoverFixedPositionLocation, - PopoverPositionType, - PopoverRef, - PopoverService -} from '@hypertrace/components'; +import { PopoverRef } from '@hypertrace/components'; import { Model } from '@hypertrace/hyperdash'; import { ModelInject } from '@hypertrace/hyperdash-angular'; import { Observable, of } from 'rxjs'; import { CartesianSelectedData } from '../../../../../../public-api'; import { InteractionHandler } from '../../../../interaction/interaction-handler'; -import { CartesianExplorerContextMenuComponent } from './cartesian-explorer-context-menu/cartesian-explorer-context-menu.component'; import { CartesainExplorerNavigationService } from './cartesian-explorer-navigation.service'; @Model({ type: 'cartesian-explorer-selection-handler' }) export class CartesianExplorerSelectionHandlerModel implements InteractionHandler { - @ModelInject(PopoverService) - private readonly popoverService!: PopoverService; - @ModelInject(CartesainExplorerNavigationService) private readonly cartesainExplorerNavigationService!: CartesainExplorerNavigationService; public popover?: PopoverRef; public execute(selectionData: CartesianSelectedData): Observable { - if (selectionData.showContextMenu) { - this.showContextMenu(selectionData); - } else { - this.cartesainExplorerNavigationService.navigateToExplorer( - selectionData.timeRange.startTime, - selectionData.timeRange.endTime - ); - } + this.cartesainExplorerNavigationService.navigateToExplorer( + selectionData.timeRange.startTime, + selectionData.timeRange.endTime + ); return of(); } - - private showContextMenu(selectionData: CartesianSelectedData): void { - this.popover = this.popoverService.drawPopover({ - componentOrTemplate: CartesianExplorerContextMenuComponent, - data: selectionData, - position: { - type: PopoverPositionType.Fixed, - location: PopoverFixedPositionLocation.Custom, - customLocation: selectionData.location - }, - backdrop: PopoverBackdrop.Transparent - }); - this.popover.closeOnBackdropClick(); - this.popover.closeOnPopoverContentClick(); - } } diff --git a/src/app/home/home.dashboard.ts b/src/app/home/home.dashboard.ts index 2dff0a0f9..b7b776419 100644 --- a/src/app/home/home.dashboard.ts +++ b/src/app/home/home.dashboard.ts @@ -479,7 +479,7 @@ export const homeDashboard: DashboardDefaultConfiguration = { } ], 'selection-handler': { - type: 'cartesian-explorer-selection-handler' + type: 'cartesian-chart-selection-handler' } }, { @@ -559,7 +559,7 @@ export const homeDashboard: DashboardDefaultConfiguration = { } ], 'selection-handler': { - type: 'cartesian-explorer-selection-handler' + type: 'cartesian-chart-selection-handler' } }, { @@ -639,7 +639,7 @@ export const homeDashboard: DashboardDefaultConfiguration = { } ], 'selection-handler': { - type: 'cartesian-explorer-selection-handler' + type: 'cartesian-chart-selection-handler' } } ] From 8e05d709591ab651de8dae3cbd1fb7a8ecdd801d Mon Sep 17 00:00:00 2001 From: Jyothish Jose Date: Thu, 18 Nov 2021 18:01:54 +0530 Subject: [PATCH 29/49] feat: cartesian chart - test cases updated --- ...sian-chart-selection-handler.model.test.ts | 68 +++++++++++++++++++ ...cartesian-chart-selection-handler.model.ts | 7 +- ...tesian-explorer-navigation.service.test.ts | 30 ++++++++ 3 files changed, 102 insertions(+), 3 deletions(-) create mode 100644 projects/observability/src/shared/dashboard/widgets/charts/cartesian-widget/interactions/cartesian-chart-selection-handler.model.test.ts create mode 100644 projects/observability/src/shared/dashboard/widgets/charts/cartesian-widget/interactions/cartesian-explorer-navigation.service.test.ts diff --git a/projects/observability/src/shared/dashboard/widgets/charts/cartesian-widget/interactions/cartesian-chart-selection-handler.model.test.ts b/projects/observability/src/shared/dashboard/widgets/charts/cartesian-widget/interactions/cartesian-chart-selection-handler.model.test.ts new file mode 100644 index 000000000..8f2b4f7a0 --- /dev/null +++ b/projects/observability/src/shared/dashboard/widgets/charts/cartesian-widget/interactions/cartesian-chart-selection-handler.model.test.ts @@ -0,0 +1,68 @@ +import { TimeRangeService } from '@hypertrace/common'; +import { createModelFactory } from '@hypertrace/dashboards/testing'; +import { mockProvider } from '@ngneat/spectator/jest'; +import { PopoverService } from '@hypertrace/components'; +import { CartesianSelectedData } from '../../../../../../public-api'; +import { CartesianChartSelectionHandlerModel } from './cartesian-chart-selection-handler.model'; + +describe('Cartesian Explorer Selection Handler Model', () => { + const selectedData: CartesianSelectedData = { + timeRange: TimeRangeService.toFixedTimeRange( + new Date('2021-11-02T05:33:19.288Z'), + new Date('2021-11-02T14:30:15.141Z') + ), + selectedData: [ + { + dataPoint: { timestamp: '2021-11-02T05:40:00.000Z', value: 1477.3599999999983 }, + context: { + data: [ + { timestamp: '2021-11-02T05:15:00.000Z', value: 774 }, + { timestamp: '2021-11-02T05:40:00.000Z', value: 1477.3599999999983 }, + { timestamp: '2021-11-02T12:05:00.000Z', value: 1056.48 } + ], + units: 'ms', + color: '#4b5f77', + name: 'p99', + type: 1, + stacking: false, + hide: false + }, + location: { x: 59, y: 31.023400000000215 } + }, + { + dataPoint: { timestamp: '2021-11-02T12:05:00.000Z', value: 1056.48 }, + context: { + data: [ + { timestamp: '2021-11-02T05:15:00.000Z', value: 774 }, + { timestamp: '2021-11-02T05:40:00.000Z', value: 1477.3599999999983 }, + { timestamp: '2021-11-02T12:05:00.000Z', value: 1056.48 } + ], + units: 'ms', + color: '#4b5f77', + name: 'p99', + type: 1, + stacking: false, + hide: false + }, + location: { x: 138, y: 82.58120000000001 } + } + ], + location: { x: 452, y: 763 } + }; + + const buildModel = createModelFactory({ + providers: [ + mockProvider(PopoverService, { + drawPopover: jest.fn() + }) + ] + }); + + test('show context menu', () => { + const spectator = buildModel(CartesianChartSelectionHandlerModel); + const popoverService = spectator.get(PopoverService); + + spectator.model.execute(selectedData); + expect(popoverService.drawPopover).toHaveBeenCalled(); + }); +}); diff --git a/projects/observability/src/shared/dashboard/widgets/charts/cartesian-widget/interactions/cartesian-chart-selection-handler.model.ts b/projects/observability/src/shared/dashboard/widgets/charts/cartesian-widget/interactions/cartesian-chart-selection-handler.model.ts index ae54c35eb..c31f54065 100644 --- a/projects/observability/src/shared/dashboard/widgets/charts/cartesian-widget/interactions/cartesian-chart-selection-handler.model.ts +++ b/projects/observability/src/shared/dashboard/widgets/charts/cartesian-widget/interactions/cartesian-chart-selection-handler.model.ts @@ -25,10 +25,13 @@ export class CartesianChartSelectionHandlerModel implements InteractionHa public execute(selectionData: CartesianSelectedData): Observable { this.showContextMenu(selectionData); + this.popover?.closeOnBackdropClick(); + this.popover?.closeOnPopoverContentClick(); + return of(); } - private showContextMenu(selectionData: CartesianSelectedData): void { + public showContextMenu(selectionData: CartesianSelectedData): void { this.popover = this.popoverService.drawPopover({ componentOrTemplate: CartesianExplorerContextMenuComponent, data: selectionData, @@ -39,7 +42,5 @@ export class CartesianChartSelectionHandlerModel implements InteractionHa }, backdrop: PopoverBackdrop.Transparent }); - this.popover.closeOnBackdropClick(); - this.popover.closeOnPopoverContentClick(); } } diff --git a/projects/observability/src/shared/dashboard/widgets/charts/cartesian-widget/interactions/cartesian-explorer-navigation.service.test.ts b/projects/observability/src/shared/dashboard/widgets/charts/cartesian-widget/interactions/cartesian-explorer-navigation.service.test.ts new file mode 100644 index 000000000..4bc26337f --- /dev/null +++ b/projects/observability/src/shared/dashboard/widgets/charts/cartesian-widget/interactions/cartesian-explorer-navigation.service.test.ts @@ -0,0 +1,30 @@ +import { NavigationService, TimeRangeService } from '@hypertrace/common'; +import { createServiceFactory, mockProvider, SpectatorService } from '@ngneat/spectator/jest'; +import { CartesainExplorerNavigationService } from './cartesian-explorer-navigation.service'; + +describe('Cartesian Explorer Navigation Service', () => { + let spectator: SpectatorService; + + const createService = createServiceFactory({ + service: CartesainExplorerNavigationService, + providers: [ + mockProvider(TimeRangeService, { + toQueryParams: jest.fn() + }), + mockProvider(NavigationService, { + navigate: jest.fn() + }) + ] + }); + + beforeEach(() => { + spectator = createService(); + }); + + test('should navigate to explorer with params', () => { + spectator.service.navigateToExplorer(new Date(), new Date()); + + expect(spectator.inject(TimeRangeService).toQueryParams).toHaveBeenCalled(); + expect(spectator.inject(NavigationService).navigate).toHaveBeenCalled(); + }); +}); From c961d97369c0b4b44e7a04b1cb8ae655570a134c Mon Sep 17 00:00:00 2001 From: Jyothish Jose Date: Thu, 18 Nov 2021 18:30:04 +0530 Subject: [PATCH 30/49] feat: cartesian chart - test cases updated --- ...an-explorer-context-menu.component.test.ts | 65 ------------------- 1 file changed, 65 deletions(-) delete mode 100644 projects/observability/src/shared/dashboard/widgets/charts/cartesian-widget/interactions/cartesian-explorer-context-menu/cartesian-explorer-context-menu.component.test.ts diff --git a/projects/observability/src/shared/dashboard/widgets/charts/cartesian-widget/interactions/cartesian-explorer-context-menu/cartesian-explorer-context-menu.component.test.ts b/projects/observability/src/shared/dashboard/widgets/charts/cartesian-widget/interactions/cartesian-explorer-context-menu/cartesian-explorer-context-menu.component.test.ts deleted file mode 100644 index d295f3043..000000000 --- a/projects/observability/src/shared/dashboard/widgets/charts/cartesian-widget/interactions/cartesian-explorer-context-menu/cartesian-explorer-context-menu.component.test.ts +++ /dev/null @@ -1,65 +0,0 @@ -import { fakeAsync } from '@angular/core/testing'; -import { createHostFactory, mockProvider, Spectator } from '@ngneat/spectator/jest'; - -import { HttpClientTestingModule } from '@angular/common/http/testing'; -import { IconLibraryTestingModule, IconType } from '@hypertrace/assets-library'; -import { PopoverService } from '@hypertrace/components'; -import { CartesainExplorerNavigationService } from '../cartesian-explorer-navigation.service'; -import { CartesianExplorerContextMenuComponent } from './cartesian-explorer-context-menu.component'; -import { CartesianExplorerContextMenuModule } from './cartesian-explorer-context-menu.module'; - -describe('Cartesian Explorer Context menu component', () => { - let spectator: Spectator>; - - const mockPopoverRef = { - close: jest.fn() - }; - - const createHost = createHostFactory({ - declareComponent: false, - component: CartesianExplorerContextMenuComponent, - providers: [ - mockProvider(PopoverService, { - drawPopover: jest.fn().mockReturnValue(mockPopoverRef) - }), - mockProvider(CartesainExplorerNavigationService, { - navigateToExplorer: jest.fn() - }) - ], - imports: [CartesianExplorerContextMenuModule, HttpClientTestingModule, IconLibraryTestingModule] - }); - - test('correctly renders context menu', fakeAsync(() => { - const menuSelectSpy = jest.fn(); - - spectator = createHost( - ``, - { - hostProps: { - menus: [ - { - name: 'Explore', - icon: IconType.ArrowUpRight - } - ], - contextMenuSelectHandler: menuSelectSpy - } - } - ); - - expect(spectator.query('.context-menu')).toExist(); - - spectator.tick(); - - const buttonElement = spectator.query('button')!; - - // Click will toggle the values to true - spectator.click(buttonElement); - expect(menuSelectSpy).toHaveBeenCalledWith({ - name: 'Explore', - icon: IconType.ArrowUpRight - }); - })); -}); From 7982ef94129c1356531efd51df12569ccfb9aed9 Mon Sep 17 00:00:00 2001 From: Jyothish Jose Date: Thu, 18 Nov 2021 18:33:06 +0530 Subject: [PATCH 31/49] feat: cartesian chart - test cases updated --- .../cartesian-chart-selection-handler.model.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/projects/observability/src/shared/dashboard/widgets/charts/cartesian-widget/interactions/cartesian-chart-selection-handler.model.test.ts b/projects/observability/src/shared/dashboard/widgets/charts/cartesian-widget/interactions/cartesian-chart-selection-handler.model.test.ts index 8f2b4f7a0..61185ca76 100644 --- a/projects/observability/src/shared/dashboard/widgets/charts/cartesian-widget/interactions/cartesian-chart-selection-handler.model.test.ts +++ b/projects/observability/src/shared/dashboard/widgets/charts/cartesian-widget/interactions/cartesian-chart-selection-handler.model.test.ts @@ -1,7 +1,7 @@ import { TimeRangeService } from '@hypertrace/common'; +import { PopoverService } from '@hypertrace/components'; import { createModelFactory } from '@hypertrace/dashboards/testing'; import { mockProvider } from '@ngneat/spectator/jest'; -import { PopoverService } from '@hypertrace/components'; import { CartesianSelectedData } from '../../../../../../public-api'; import { CartesianChartSelectionHandlerModel } from './cartesian-chart-selection-handler.model'; From 1e7e16f1d3fe361fa9d93674db12044a8f69e9e9 Mon Sep 17 00:00:00 2001 From: Jyothish Jose Date: Thu, 18 Nov 2021 20:26:52 +0530 Subject: [PATCH 32/49] feat: cartesian chart - test cases updated --- projects/common/src/time/time-range.service.test.ts | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/projects/common/src/time/time-range.service.test.ts b/projects/common/src/time/time-range.service.test.ts index 82cd31317..49679cf85 100644 --- a/projects/common/src/time/time-range.service.test.ts +++ b/projects/common/src/time/time-range.service.test.ts @@ -81,4 +81,12 @@ describe('Time range service', () => { }); }); }); + + test('returns custom time filter', () => { + const spectator = buildService(); + spectator.service.toQueryParams(new Date(1573255100253), new Date(1573255111159)); + expect(spectator.service.getCurrentTimeRange()).toEqual( + new FixedTimeRange(new Date(1573255100253), new Date(1573255111159)) + ); + }); }); From c694b6bf3488aa8f7a35ace0e3df35f864c00567 Mon Sep 17 00:00:00 2001 From: Jyothish Jose Date: Fri, 19 Nov 2021 00:29:44 +0530 Subject: [PATCH 33/49] feat: cartesian chart - test cases updated --- .../metrics/api-metrics.dashboard.ts | 12 ++-- .../overview/api-overview.dashboard.ts | 9 ++- .../metrics/backend-metrics.dashboard.ts | 12 ++-- .../overview/backend-overview.component.ts | 9 ++- .../metrics/service-metrics.dashboard.ts | 12 ++-- .../overview/service-overview.dashboard.ts | 9 ++- .../explorer-dashboard-builder.test.ts | 3 +- .../explorer/explorer-dashboard-builder.ts | 3 +- .../cartesian-widget.module.ts | 2 - ...sian-chart-selection-handler.model.test.ts | 68 ------------------- ...cartesian-chart-selection-handler.model.ts | 46 ------------- ...n-explorer-selection-handler.model.test.ts | 22 +++++- ...tesian-explorer-selection-handler.model.ts | 48 +++++++++++-- src/app/home/home.dashboard.ts | 9 ++- 14 files changed, 113 insertions(+), 151 deletions(-) delete mode 100644 projects/observability/src/shared/dashboard/widgets/charts/cartesian-widget/interactions/cartesian-chart-selection-handler.model.test.ts delete mode 100644 projects/observability/src/shared/dashboard/widgets/charts/cartesian-widget/interactions/cartesian-chart-selection-handler.model.ts diff --git a/projects/observability/src/pages/apis/api-detail/metrics/api-metrics.dashboard.ts b/projects/observability/src/pages/apis/api-detail/metrics/api-metrics.dashboard.ts index 41f93d5c0..6206d757f 100644 --- a/projects/observability/src/pages/apis/api-detail/metrics/api-metrics.dashboard.ts +++ b/projects/observability/src/pages/apis/api-detail/metrics/api-metrics.dashboard.ts @@ -272,7 +272,8 @@ export const apiMetricsDashboard: DashboardDefaultConfiguration = { } ], 'selection-handler': { - type: 'cartesian-chart-selection-handler' + type: 'cartesian-explorer-selection-handler', + 'show-context-menu': true } }, { @@ -335,7 +336,8 @@ export const apiMetricsDashboard: DashboardDefaultConfiguration = { } ], 'selection-handler': { - type: 'cartesian-chart-selection-handler' + type: 'cartesian-explorer-selection-handler', + 'show-context-menu': true } }, { @@ -377,7 +379,8 @@ export const apiMetricsDashboard: DashboardDefaultConfiguration = { } ], 'selection-handler': { - type: 'cartesian-chart-selection-handler' + type: 'cartesian-explorer-selection-handler', + 'show-context-menu': true } } ] @@ -409,7 +412,8 @@ export const apiMetricsDashboard: DashboardDefaultConfiguration = { } ], 'selection-handler': { - type: 'cartesian-chart-selection-handler' + type: 'cartesian-explorer-selection-handler', + 'show-context-menu': true } } ] diff --git a/projects/observability/src/pages/apis/api-detail/overview/api-overview.dashboard.ts b/projects/observability/src/pages/apis/api-detail/overview/api-overview.dashboard.ts index 23765a235..e46ee055c 100644 --- a/projects/observability/src/pages/apis/api-detail/overview/api-overview.dashboard.ts +++ b/projects/observability/src/pages/apis/api-detail/overview/api-overview.dashboard.ts @@ -297,7 +297,8 @@ export const apiOverviewDashboard: DashboardDefaultConfiguration = { } ], 'selection-handler': { - type: 'cartesian-chart-selection-handler' + type: 'cartesian-explorer-selection-handler', + 'show-context-menu': true } }, { @@ -394,7 +395,8 @@ export const apiOverviewDashboard: DashboardDefaultConfiguration = { } ], 'selection-handler': { - type: 'cartesian-chart-selection-handler' + type: 'cartesian-explorer-selection-handler', + 'show-context-menu': true } }, { @@ -491,7 +493,8 @@ export const apiOverviewDashboard: DashboardDefaultConfiguration = { } ], 'selection-handler': { - type: 'cartesian-chart-selection-handler' + type: 'cartesian-explorer-selection-handler', + 'show-context-menu': true } } ] diff --git a/projects/observability/src/pages/apis/backend-detail/metrics/backend-metrics.dashboard.ts b/projects/observability/src/pages/apis/backend-detail/metrics/backend-metrics.dashboard.ts index 69a8ddf79..24eff44e6 100644 --- a/projects/observability/src/pages/apis/backend-detail/metrics/backend-metrics.dashboard.ts +++ b/projects/observability/src/pages/apis/backend-detail/metrics/backend-metrics.dashboard.ts @@ -256,7 +256,8 @@ export const backendMetricsDashboard: DashboardDefaultConfiguration = { } ], 'selection-handler': { - type: 'cartesian-chart-selection-handler' + type: 'cartesian-explorer-selection-handler', + 'show-context-menu': true } }, { @@ -319,7 +320,8 @@ export const backendMetricsDashboard: DashboardDefaultConfiguration = { } ], 'selection-handler': { - type: 'cartesian-chart-selection-handler' + type: 'cartesian-explorer-selection-handler', + 'show-context-menu': true } }, { @@ -345,7 +347,8 @@ export const backendMetricsDashboard: DashboardDefaultConfiguration = { } ], 'selection-handler': { - type: 'cartesian-chart-selection-handler' + type: 'cartesian-explorer-selection-handler', + 'show-context-menu': true } } ] @@ -377,7 +380,8 @@ export const backendMetricsDashboard: DashboardDefaultConfiguration = { } ], 'selection-handler': { - type: 'cartesian-chart-selection-handler' + type: 'cartesian-explorer-selection-handler', + 'show-context-menu': true } } ] diff --git a/projects/observability/src/pages/apis/backend-detail/overview/backend-overview.component.ts b/projects/observability/src/pages/apis/backend-detail/overview/backend-overview.component.ts index 503500bd8..518bd70fd 100644 --- a/projects/observability/src/pages/apis/backend-detail/overview/backend-overview.component.ts +++ b/projects/observability/src/pages/apis/backend-detail/overview/backend-overview.component.ts @@ -289,7 +289,8 @@ export class BackendOverviewComponent { } ], 'selection-handler': { - type: 'cartesian-chart-selection-handler' + type: 'cartesian-explorer-selection-handler', + 'show-context-menu': true } }, { @@ -370,7 +371,8 @@ export class BackendOverviewComponent { } ], 'selection-handler': { - type: 'cartesian-chart-selection-handler' + type: 'cartesian-explorer-selection-handler', + 'show-context-menu': true } }, { @@ -451,7 +453,8 @@ export class BackendOverviewComponent { } ], 'selection-handler': { - type: 'cartesian-chart-selection-handler' + type: 'cartesian-explorer-selection-handler', + 'show-context-menu': true } } ] diff --git a/projects/observability/src/pages/apis/service-detail/metrics/service-metrics.dashboard.ts b/projects/observability/src/pages/apis/service-detail/metrics/service-metrics.dashboard.ts index cab68b8a9..53a235a58 100644 --- a/projects/observability/src/pages/apis/service-detail/metrics/service-metrics.dashboard.ts +++ b/projects/observability/src/pages/apis/service-detail/metrics/service-metrics.dashboard.ts @@ -272,7 +272,8 @@ export const serviceMetricsDashboard: DashboardDefaultConfiguration = { } ], 'selection-handler': { - type: 'cartesian-chart-selection-handler' + type: 'cartesian-explorer-selection-handler', + 'show-context-menu': true } }, { @@ -335,7 +336,8 @@ export const serviceMetricsDashboard: DashboardDefaultConfiguration = { } ], 'selection-handler': { - type: 'cartesian-chart-selection-handler' + type: 'cartesian-explorer-selection-handler', + 'show-context-menu': true } }, { @@ -377,7 +379,8 @@ export const serviceMetricsDashboard: DashboardDefaultConfiguration = { } ], 'selection-handler': { - type: 'cartesian-chart-selection-handler' + type: 'cartesian-explorer-selection-handler', + 'show-context-menu': true } } ] @@ -409,7 +412,8 @@ export const serviceMetricsDashboard: DashboardDefaultConfiguration = { } ], 'selection-handler': { - type: 'cartesian-chart-selection-handler' + type: 'cartesian-explorer-selection-handler', + 'show-context-menu': true } } ] diff --git a/projects/observability/src/pages/apis/service-detail/overview/service-overview.dashboard.ts b/projects/observability/src/pages/apis/service-detail/overview/service-overview.dashboard.ts index 43e0668c6..288195d75 100644 --- a/projects/observability/src/pages/apis/service-detail/overview/service-overview.dashboard.ts +++ b/projects/observability/src/pages/apis/service-detail/overview/service-overview.dashboard.ts @@ -341,7 +341,8 @@ export const serviceOverviewDashboard: DashboardDefaultConfiguration = { } ], 'selection-handler': { - type: 'cartesian-chart-selection-handler' + type: 'cartesian-explorer-selection-handler', + 'show-context-menu': true } }, { @@ -438,7 +439,8 @@ export const serviceOverviewDashboard: DashboardDefaultConfiguration = { } ], 'selection-handler': { - type: 'cartesian-chart-selection-handler' + type: 'cartesian-explorer-selection-handler', + 'show-context-menu': true } }, { @@ -535,7 +537,8 @@ export const serviceOverviewDashboard: DashboardDefaultConfiguration = { } ], 'selection-handler': { - type: 'cartesian-chart-selection-handler' + type: 'cartesian-explorer-selection-handler', + 'show-context-menu': true } } ] diff --git a/projects/observability/src/pages/explorer/explorer-dashboard-builder.test.ts b/projects/observability/src/pages/explorer/explorer-dashboard-builder.test.ts index fb920962d..4caf64e4a 100644 --- a/projects/observability/src/pages/explorer/explorer-dashboard-builder.test.ts +++ b/projects/observability/src/pages/explorer/explorer-dashboard-builder.test.ts @@ -43,7 +43,8 @@ describe('Explorer dashboard builder', () => { 'series-from-data': true, 'legend-position': LegendPosition.Bottom, 'selection-handler': { - type: 'cartesian-explorer-selection-handler' + type: 'cartesian-explorer-selection-handler', + 'show-context-menu': false } }, onReady: expect.any(Function) diff --git a/projects/observability/src/pages/explorer/explorer-dashboard-builder.ts b/projects/observability/src/pages/explorer/explorer-dashboard-builder.ts index be7c7f9fc..6648841d6 100644 --- a/projects/observability/src/pages/explorer/explorer-dashboard-builder.ts +++ b/projects/observability/src/pages/explorer/explorer-dashboard-builder.ts @@ -64,7 +64,8 @@ export class ExplorerDashboardBuilder { 'series-from-data': true, 'legend-position': LegendPosition.Bottom, 'selection-handler': { - type: 'cartesian-explorer-selection-handler' + type: 'cartesian-explorer-selection-handler', + 'show-context-menu': false } }, onReady: dashboard => { diff --git a/projects/observability/src/shared/dashboard/widgets/charts/cartesian-widget/cartesian-widget.module.ts b/projects/observability/src/shared/dashboard/widgets/charts/cartesian-widget/cartesian-widget.module.ts index 9f27b9f31..96fc5e255 100644 --- a/projects/observability/src/shared/dashboard/widgets/charts/cartesian-widget/cartesian-widget.module.ts +++ b/projects/observability/src/shared/dashboard/widgets/charts/cartesian-widget/cartesian-widget.module.ts @@ -10,7 +10,6 @@ import { BAND_ARRAY_TYPE } from './band-array/band-array-type'; import { BandModel } from './band.model'; import { CartesianWidgetRendererComponent } from './cartesian-widget-renderer.component'; import { CartesianWidgetModel } from './cartesian-widget.model'; -import { CartesianChartSelectionHandlerModel } from './interactions/cartesian-chart-selection-handler.model'; import { CartesianExplorerContextMenuModule } from './interactions/cartesian-explorer-context-menu/cartesian-explorer-context-menu.module'; import { CartesianExplorerSelectionHandlerModel } from './interactions/cartesian-explorer-selection-handler.model'; @@ -33,7 +32,6 @@ import { SeriesModel } from './series.model'; SeriesModel, BandModel, CartesianAxisModel, - CartesianChartSelectionHandlerModel, CartesianExplorerSelectionHandlerModel ], renderers: [CartesianWidgetRendererComponent], diff --git a/projects/observability/src/shared/dashboard/widgets/charts/cartesian-widget/interactions/cartesian-chart-selection-handler.model.test.ts b/projects/observability/src/shared/dashboard/widgets/charts/cartesian-widget/interactions/cartesian-chart-selection-handler.model.test.ts deleted file mode 100644 index 61185ca76..000000000 --- a/projects/observability/src/shared/dashboard/widgets/charts/cartesian-widget/interactions/cartesian-chart-selection-handler.model.test.ts +++ /dev/null @@ -1,68 +0,0 @@ -import { TimeRangeService } from '@hypertrace/common'; -import { PopoverService } from '@hypertrace/components'; -import { createModelFactory } from '@hypertrace/dashboards/testing'; -import { mockProvider } from '@ngneat/spectator/jest'; -import { CartesianSelectedData } from '../../../../../../public-api'; -import { CartesianChartSelectionHandlerModel } from './cartesian-chart-selection-handler.model'; - -describe('Cartesian Explorer Selection Handler Model', () => { - const selectedData: CartesianSelectedData = { - timeRange: TimeRangeService.toFixedTimeRange( - new Date('2021-11-02T05:33:19.288Z'), - new Date('2021-11-02T14:30:15.141Z') - ), - selectedData: [ - { - dataPoint: { timestamp: '2021-11-02T05:40:00.000Z', value: 1477.3599999999983 }, - context: { - data: [ - { timestamp: '2021-11-02T05:15:00.000Z', value: 774 }, - { timestamp: '2021-11-02T05:40:00.000Z', value: 1477.3599999999983 }, - { timestamp: '2021-11-02T12:05:00.000Z', value: 1056.48 } - ], - units: 'ms', - color: '#4b5f77', - name: 'p99', - type: 1, - stacking: false, - hide: false - }, - location: { x: 59, y: 31.023400000000215 } - }, - { - dataPoint: { timestamp: '2021-11-02T12:05:00.000Z', value: 1056.48 }, - context: { - data: [ - { timestamp: '2021-11-02T05:15:00.000Z', value: 774 }, - { timestamp: '2021-11-02T05:40:00.000Z', value: 1477.3599999999983 }, - { timestamp: '2021-11-02T12:05:00.000Z', value: 1056.48 } - ], - units: 'ms', - color: '#4b5f77', - name: 'p99', - type: 1, - stacking: false, - hide: false - }, - location: { x: 138, y: 82.58120000000001 } - } - ], - location: { x: 452, y: 763 } - }; - - const buildModel = createModelFactory({ - providers: [ - mockProvider(PopoverService, { - drawPopover: jest.fn() - }) - ] - }); - - test('show context menu', () => { - const spectator = buildModel(CartesianChartSelectionHandlerModel); - const popoverService = spectator.get(PopoverService); - - spectator.model.execute(selectedData); - expect(popoverService.drawPopover).toHaveBeenCalled(); - }); -}); diff --git a/projects/observability/src/shared/dashboard/widgets/charts/cartesian-widget/interactions/cartesian-chart-selection-handler.model.ts b/projects/observability/src/shared/dashboard/widgets/charts/cartesian-widget/interactions/cartesian-chart-selection-handler.model.ts deleted file mode 100644 index c31f54065..000000000 --- a/projects/observability/src/shared/dashboard/widgets/charts/cartesian-widget/interactions/cartesian-chart-selection-handler.model.ts +++ /dev/null @@ -1,46 +0,0 @@ -import { - PopoverBackdrop, - PopoverFixedPositionLocation, - PopoverPositionType, - PopoverRef, - PopoverService -} from '@hypertrace/components'; -import { Model } from '@hypertrace/hyperdash'; -import { ModelInject } from '@hypertrace/hyperdash-angular'; -import { Observable, of } from 'rxjs'; -import { CartesianSelectedData } from '../../../../../../public-api'; -import { InteractionHandler } from '../../../../interaction/interaction-handler'; - -import { CartesianExplorerContextMenuComponent } from './cartesian-explorer-context-menu/cartesian-explorer-context-menu.component'; - -@Model({ - type: 'cartesian-chart-selection-handler' -}) -export class CartesianChartSelectionHandlerModel implements InteractionHandler { - @ModelInject(PopoverService) - private readonly popoverService!: PopoverService; - - public popover?: PopoverRef; - - public execute(selectionData: CartesianSelectedData): Observable { - this.showContextMenu(selectionData); - - this.popover?.closeOnBackdropClick(); - this.popover?.closeOnPopoverContentClick(); - - return of(); - } - - public showContextMenu(selectionData: CartesianSelectedData): void { - this.popover = this.popoverService.drawPopover({ - componentOrTemplate: CartesianExplorerContextMenuComponent, - data: selectionData, - position: { - type: PopoverPositionType.Fixed, - location: PopoverFixedPositionLocation.Custom, - customLocation: selectionData.location - }, - backdrop: PopoverBackdrop.Transparent - }); - } -} diff --git a/projects/observability/src/shared/dashboard/widgets/charts/cartesian-widget/interactions/cartesian-explorer-selection-handler.model.test.ts b/projects/observability/src/shared/dashboard/widgets/charts/cartesian-widget/interactions/cartesian-explorer-selection-handler.model.test.ts index 7de5c5620..78bf97699 100644 --- a/projects/observability/src/shared/dashboard/widgets/charts/cartesian-widget/interactions/cartesian-explorer-selection-handler.model.test.ts +++ b/projects/observability/src/shared/dashboard/widgets/charts/cartesian-widget/interactions/cartesian-explorer-selection-handler.model.test.ts @@ -1,7 +1,8 @@ import { TimeRangeService } from '@hypertrace/common'; +import { PopoverService } from '@hypertrace/components'; import { createModelFactory } from '@hypertrace/dashboards/testing'; import { mockProvider } from '@ngneat/spectator/jest'; -import { CartesianSelectedData } from '../../../../../../public-api'; +import { CartesianSelectedData, CartesianSeriesVisualizationType } from '../../../../../../public-api'; import { CartesainExplorerNavigationService } from './cartesian-explorer-navigation.service'; import { CartesianExplorerSelectionHandlerModel } from './cartesian-explorer-selection-handler.model'; @@ -23,7 +24,7 @@ describe('Cartesian Explorer Selection Handler Model', () => { units: 'ms', color: '#4b5f77', name: 'p99', - type: 1, + type: CartesianSeriesVisualizationType.Column, stacking: false, hide: false }, @@ -40,7 +41,7 @@ describe('Cartesian Explorer Selection Handler Model', () => { units: 'ms', color: '#4b5f77', name: 'p99', - type: 1, + type: CartesianSeriesVisualizationType.Column, stacking: false, hide: false }, @@ -54,6 +55,9 @@ describe('Cartesian Explorer Selection Handler Model', () => { providers: [ mockProvider(CartesainExplorerNavigationService, { navigateToExplorer: jest.fn() + }), + mockProvider(PopoverService, { + drawPopover: jest.fn() }) ] }); @@ -62,7 +66,19 @@ describe('Cartesian Explorer Selection Handler Model', () => { const spectator = buildModel(CartesianExplorerSelectionHandlerModel); const cartesainExplorerNavigationService = spectator.get(CartesainExplorerNavigationService); + spectator.model.isContextMenuVisible = false; + spectator.model.execute(selectedData); expect(cartesainExplorerNavigationService.navigateToExplorer).toHaveBeenCalled(); }); + + test('show context menu', () => { + const spectator = buildModel(CartesianExplorerSelectionHandlerModel); + const popoverService = spectator.get(PopoverService); + + spectator.model.isContextMenuVisible = true; + + spectator.model.execute(selectedData); + expect(popoverService.drawPopover).toHaveBeenCalled(); + }); }); diff --git a/projects/observability/src/shared/dashboard/widgets/charts/cartesian-widget/interactions/cartesian-explorer-selection-handler.model.ts b/projects/observability/src/shared/dashboard/widgets/charts/cartesian-widget/interactions/cartesian-explorer-selection-handler.model.ts index d19a37eed..d3dcb31e6 100644 --- a/projects/observability/src/shared/dashboard/widgets/charts/cartesian-widget/interactions/cartesian-explorer-selection-handler.model.ts +++ b/projects/observability/src/shared/dashboard/widgets/charts/cartesian-widget/interactions/cartesian-explorer-selection-handler.model.ts @@ -1,9 +1,16 @@ -import { PopoverRef } from '@hypertrace/components'; -import { Model } from '@hypertrace/hyperdash'; +import { + PopoverBackdrop, + PopoverFixedPositionLocation, + PopoverPositionType, + PopoverRef, + PopoverService +} from '@hypertrace/components'; +import { BOOLEAN_PROPERTY, Model, ModelProperty } from '@hypertrace/hyperdash'; import { ModelInject } from '@hypertrace/hyperdash-angular'; import { Observable, of } from 'rxjs'; import { CartesianSelectedData } from '../../../../../../public-api'; import { InteractionHandler } from '../../../../interaction/interaction-handler'; +import { CartesianExplorerContextMenuComponent } from './cartesian-explorer-context-menu/cartesian-explorer-context-menu.component'; import { CartesainExplorerNavigationService } from './cartesian-explorer-navigation.service'; @@ -14,14 +21,43 @@ export class CartesianExplorerSelectionHandlerModel implements Interactio @ModelInject(CartesainExplorerNavigationService) private readonly cartesainExplorerNavigationService!: CartesainExplorerNavigationService; + @ModelInject(PopoverService) + private readonly popoverService!: PopoverService; + public popover?: PopoverRef; + @ModelProperty({ + key: 'show-context-menu', + displayName: 'Show Context Menu', + type: BOOLEAN_PROPERTY.type + }) + public isContextMenuVisible: boolean = true; + public execute(selectionData: CartesianSelectedData): Observable { - this.cartesainExplorerNavigationService.navigateToExplorer( - selectionData.timeRange.startTime, - selectionData.timeRange.endTime - ); + if (this.isContextMenuVisible) { + this.showContextMenu(selectionData); + this.popover?.closeOnBackdropClick(); + this.popover?.closeOnPopoverContentClick(); + } else { + this.cartesainExplorerNavigationService.navigateToExplorer( + selectionData.timeRange.startTime, + selectionData.timeRange.endTime + ); + } return of(); } + + public showContextMenu(selectionData: CartesianSelectedData): void { + this.popover = this.popoverService.drawPopover({ + componentOrTemplate: CartesianExplorerContextMenuComponent, + data: selectionData, + position: { + type: PopoverPositionType.Fixed, + location: PopoverFixedPositionLocation.Custom, + customLocation: selectionData.location + }, + backdrop: PopoverBackdrop.Transparent + }); + } } diff --git a/src/app/home/home.dashboard.ts b/src/app/home/home.dashboard.ts index b7b776419..5c3d26e5d 100644 --- a/src/app/home/home.dashboard.ts +++ b/src/app/home/home.dashboard.ts @@ -479,7 +479,8 @@ export const homeDashboard: DashboardDefaultConfiguration = { } ], 'selection-handler': { - type: 'cartesian-chart-selection-handler' + type: 'cartesian-explorer-selection-handler', + 'show-context-menu': true } }, { @@ -559,7 +560,8 @@ export const homeDashboard: DashboardDefaultConfiguration = { } ], 'selection-handler': { - type: 'cartesian-chart-selection-handler' + type: 'cartesian-explorer-selection-handler', + 'show-context-menu': true } }, { @@ -639,7 +641,8 @@ export const homeDashboard: DashboardDefaultConfiguration = { } ], 'selection-handler': { - type: 'cartesian-chart-selection-handler' + type: 'cartesian-explorer-selection-handler', + 'show-context-menu': true } } ] From d28b8e851b75d8fb790af7c0b8b46bebebb08516 Mon Sep 17 00:00:00 2001 From: Jyothish Jose Date: Tue, 30 Nov 2021 10:23:08 +0530 Subject: [PATCH 34/49] feat: cartesian drilldown comments --- .../apis/api-detail/metrics/api-metrics.dashboard.ts | 3 +-- .../apis/api-detail/overview/api-overview.dashboard.ts | 9 +++------ .../backend-detail/metrics/backend-metrics.dashboard.ts | 3 +-- .../overview/backend-overview.component.ts | 9 +++------ .../service-detail/metrics/service-metrics.dashboard.ts | 3 +-- .../cartesian-explorer-selection-handler.model.ts | 8 ++++---- src/app/home/home.dashboard.ts | 9 +++------ 7 files changed, 16 insertions(+), 28 deletions(-) diff --git a/projects/observability/src/pages/apis/api-detail/metrics/api-metrics.dashboard.ts b/projects/observability/src/pages/apis/api-detail/metrics/api-metrics.dashboard.ts index 6206d757f..9d6f3652c 100644 --- a/projects/observability/src/pages/apis/api-detail/metrics/api-metrics.dashboard.ts +++ b/projects/observability/src/pages/apis/api-detail/metrics/api-metrics.dashboard.ts @@ -272,8 +272,7 @@ export const apiMetricsDashboard: DashboardDefaultConfiguration = { } ], 'selection-handler': { - type: 'cartesian-explorer-selection-handler', - 'show-context-menu': true + type: 'cartesian-explorer-selection-handler' } }, { diff --git a/projects/observability/src/pages/apis/api-detail/overview/api-overview.dashboard.ts b/projects/observability/src/pages/apis/api-detail/overview/api-overview.dashboard.ts index e46ee055c..30c48924c 100644 --- a/projects/observability/src/pages/apis/api-detail/overview/api-overview.dashboard.ts +++ b/projects/observability/src/pages/apis/api-detail/overview/api-overview.dashboard.ts @@ -297,8 +297,7 @@ export const apiOverviewDashboard: DashboardDefaultConfiguration = { } ], 'selection-handler': { - type: 'cartesian-explorer-selection-handler', - 'show-context-menu': true + type: 'cartesian-explorer-selection-handler' } }, { @@ -395,8 +394,7 @@ export const apiOverviewDashboard: DashboardDefaultConfiguration = { } ], 'selection-handler': { - type: 'cartesian-explorer-selection-handler', - 'show-context-menu': true + type: 'cartesian-explorer-selection-handler' } }, { @@ -493,8 +491,7 @@ export const apiOverviewDashboard: DashboardDefaultConfiguration = { } ], 'selection-handler': { - type: 'cartesian-explorer-selection-handler', - 'show-context-menu': true + type: 'cartesian-explorer-selection-handler' } } ] diff --git a/projects/observability/src/pages/apis/backend-detail/metrics/backend-metrics.dashboard.ts b/projects/observability/src/pages/apis/backend-detail/metrics/backend-metrics.dashboard.ts index 24eff44e6..71a9a2eda 100644 --- a/projects/observability/src/pages/apis/backend-detail/metrics/backend-metrics.dashboard.ts +++ b/projects/observability/src/pages/apis/backend-detail/metrics/backend-metrics.dashboard.ts @@ -256,8 +256,7 @@ export const backendMetricsDashboard: DashboardDefaultConfiguration = { } ], 'selection-handler': { - type: 'cartesian-explorer-selection-handler', - 'show-context-menu': true + type: 'cartesian-explorer-selection-handler' } }, { diff --git a/projects/observability/src/pages/apis/backend-detail/overview/backend-overview.component.ts b/projects/observability/src/pages/apis/backend-detail/overview/backend-overview.component.ts index 518bd70fd..685685ba3 100644 --- a/projects/observability/src/pages/apis/backend-detail/overview/backend-overview.component.ts +++ b/projects/observability/src/pages/apis/backend-detail/overview/backend-overview.component.ts @@ -289,8 +289,7 @@ export class BackendOverviewComponent { } ], 'selection-handler': { - type: 'cartesian-explorer-selection-handler', - 'show-context-menu': true + type: 'cartesian-explorer-selection-handler' } }, { @@ -371,8 +370,7 @@ export class BackendOverviewComponent { } ], 'selection-handler': { - type: 'cartesian-explorer-selection-handler', - 'show-context-menu': true + type: 'cartesian-explorer-selection-handler' } }, { @@ -453,8 +451,7 @@ export class BackendOverviewComponent { } ], 'selection-handler': { - type: 'cartesian-explorer-selection-handler', - 'show-context-menu': true + type: 'cartesian-explorer-selection-handler' } } ] diff --git a/projects/observability/src/pages/apis/service-detail/metrics/service-metrics.dashboard.ts b/projects/observability/src/pages/apis/service-detail/metrics/service-metrics.dashboard.ts index 53a235a58..162be7479 100644 --- a/projects/observability/src/pages/apis/service-detail/metrics/service-metrics.dashboard.ts +++ b/projects/observability/src/pages/apis/service-detail/metrics/service-metrics.dashboard.ts @@ -272,8 +272,7 @@ export const serviceMetricsDashboard: DashboardDefaultConfiguration = { } ], 'selection-handler': { - type: 'cartesian-explorer-selection-handler', - 'show-context-menu': true + type: 'cartesian-explorer-selection-handler' } }, { diff --git a/projects/observability/src/shared/dashboard/widgets/charts/cartesian-widget/interactions/cartesian-explorer-selection-handler.model.ts b/projects/observability/src/shared/dashboard/widgets/charts/cartesian-widget/interactions/cartesian-explorer-selection-handler.model.ts index d3dcb31e6..0ada1a045 100644 --- a/projects/observability/src/shared/dashboard/widgets/charts/cartesian-widget/interactions/cartesian-explorer-selection-handler.model.ts +++ b/projects/observability/src/shared/dashboard/widgets/charts/cartesian-widget/interactions/cartesian-explorer-selection-handler.model.ts @@ -31,11 +31,11 @@ export class CartesianExplorerSelectionHandlerModel implements Interactio displayName: 'Show Context Menu', type: BOOLEAN_PROPERTY.type }) - public isContextMenuVisible: boolean = true; + public showContextMenu: boolean = true; public execute(selectionData: CartesianSelectedData): Observable { - if (this.isContextMenuVisible) { - this.showContextMenu(selectionData); + if (this.showContextMenu) { + this.showContextMenuList(selectionData); this.popover?.closeOnBackdropClick(); this.popover?.closeOnPopoverContentClick(); } else { @@ -48,7 +48,7 @@ export class CartesianExplorerSelectionHandlerModel implements Interactio return of(); } - public showContextMenu(selectionData: CartesianSelectedData): void { + public showContextMenuList(selectionData: CartesianSelectedData): void { this.popover = this.popoverService.drawPopover({ componentOrTemplate: CartesianExplorerContextMenuComponent, data: selectionData, diff --git a/src/app/home/home.dashboard.ts b/src/app/home/home.dashboard.ts index 5c3d26e5d..2dff0a0f9 100644 --- a/src/app/home/home.dashboard.ts +++ b/src/app/home/home.dashboard.ts @@ -479,8 +479,7 @@ export const homeDashboard: DashboardDefaultConfiguration = { } ], 'selection-handler': { - type: 'cartesian-explorer-selection-handler', - 'show-context-menu': true + type: 'cartesian-explorer-selection-handler' } }, { @@ -560,8 +559,7 @@ export const homeDashboard: DashboardDefaultConfiguration = { } ], 'selection-handler': { - type: 'cartesian-explorer-selection-handler', - 'show-context-menu': true + type: 'cartesian-explorer-selection-handler' } }, { @@ -641,8 +639,7 @@ export const homeDashboard: DashboardDefaultConfiguration = { } ], 'selection-handler': { - type: 'cartesian-explorer-selection-handler', - 'show-context-menu': true + type: 'cartesian-explorer-selection-handler' } } ] From 843320499e5fe1a2c12903a0d7fdbfa7b13ed974 Mon Sep 17 00:00:00 2001 From: Jyothish Jose Date: Wed, 1 Dec 2021 07:16:53 +0530 Subject: [PATCH 35/49] feat: cartesian drilldown comments --- .../cartesian-explorer-selection-handler.model.test.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/projects/observability/src/shared/dashboard/widgets/charts/cartesian-widget/interactions/cartesian-explorer-selection-handler.model.test.ts b/projects/observability/src/shared/dashboard/widgets/charts/cartesian-widget/interactions/cartesian-explorer-selection-handler.model.test.ts index 78bf97699..b369c619a 100644 --- a/projects/observability/src/shared/dashboard/widgets/charts/cartesian-widget/interactions/cartesian-explorer-selection-handler.model.test.ts +++ b/projects/observability/src/shared/dashboard/widgets/charts/cartesian-widget/interactions/cartesian-explorer-selection-handler.model.test.ts @@ -66,7 +66,7 @@ describe('Cartesian Explorer Selection Handler Model', () => { const spectator = buildModel(CartesianExplorerSelectionHandlerModel); const cartesainExplorerNavigationService = spectator.get(CartesainExplorerNavigationService); - spectator.model.isContextMenuVisible = false; + spectator.model.showContextMenu = false; spectator.model.execute(selectedData); expect(cartesainExplorerNavigationService.navigateToExplorer).toHaveBeenCalled(); @@ -76,7 +76,7 @@ describe('Cartesian Explorer Selection Handler Model', () => { const spectator = buildModel(CartesianExplorerSelectionHandlerModel); const popoverService = spectator.get(PopoverService); - spectator.model.isContextMenuVisible = true; + spectator.model.showContextMenu = true; spectator.model.execute(selectedData); expect(popoverService.drawPopover).toHaveBeenCalled(); From e83a51b55745a977399cff95fd134f38b9e4e75f Mon Sep 17 00:00:00 2001 From: Jyothish Jose Date: Wed, 1 Dec 2021 10:22:48 +0530 Subject: [PATCH 36/49] feat: cartesia chart update bug fixed --- .../cartesian-widget-renderer.component.test.ts | 3 ++- .../cartesian-widget-renderer.component.ts | 11 ++++++++--- .../cartesian-widget/cartesian-widget.module.ts | 5 +++-- 3 files changed, 13 insertions(+), 6 deletions(-) diff --git a/projects/observability/src/shared/dashboard/widgets/charts/cartesian-widget/cartesian-widget-renderer.component.test.ts b/projects/observability/src/shared/dashboard/widgets/charts/cartesian-widget/cartesian-widget-renderer.component.test.ts index ef173d79c..a1a48fc23 100644 --- a/projects/observability/src/shared/dashboard/widgets/charts/cartesian-widget/cartesian-widget-renderer.component.test.ts +++ b/projects/observability/src/shared/dashboard/widgets/charts/cartesian-widget/cartesian-widget-renderer.component.test.ts @@ -3,6 +3,7 @@ import { IconLibraryTestingModule } from '@hypertrace/assets-library'; import { FormattingModule, IntervalDurationService, + MemoizeModule, RecursivePartial, TimeDuration, TimeUnit @@ -33,7 +34,7 @@ describe('Cartesian widget renderer component', () => { availableDurations.find(availableDuration => duration.equals(availableDuration)) }) ], - imports: [LoadAsyncModule, HttpClientTestingModule, IconLibraryTestingModule, FormattingModule], + imports: [LoadAsyncModule, HttpClientTestingModule, IconLibraryTestingModule, FormattingModule, MemoizeModule], shallow: true }); diff --git a/projects/observability/src/shared/dashboard/widgets/charts/cartesian-widget/cartesian-widget-renderer.component.ts b/projects/observability/src/shared/dashboard/widgets/charts/cartesian-widget/cartesian-widget-renderer.component.ts index d3fa78a8a..f1dbf523f 100644 --- a/projects/observability/src/shared/dashboard/widgets/charts/cartesian-widget/cartesian-widget-renderer.component.ts +++ b/projects/observability/src/shared/dashboard/widgets/charts/cartesian-widget/cartesian-widget-renderer.component.ts @@ -7,8 +7,9 @@ import { RendererApi, RENDERER_API } from '@hypertrace/hyperdash-angular'; import { NEVER, Observable } from 'rxjs'; import { switchMap, tap } from 'rxjs/operators'; import { CartesianSelectedData } from '../../../../../public-api'; -import { Band, Series } from '../../../../components/cartesian/chart'; +import { Axis, Band, Series } from '../../../../components/cartesian/chart'; import { IntervalValue } from '../../../../components/interval-select/interval-select.component'; +import { CartesianAxisModel } from './axis/cartesian-axis.model'; import { CartesianDataFetcher, CartesianResult, CartesianWidgetModel } from './cartesian-widget.model'; @Renderer({ modelClass: CartesianWidgetModel }) @@ -21,8 +22,8 @@ import { CartesianDataFetcher, CartesianResult, CartesianWidgetModel } from './c class="fill-container" [series]="data.series" [bands]="data.bands" - [xAxisOption]="this.model.xAxis && this.model.xAxis!.getAxisOption()" - [yAxisOption]="this.model.yAxis && this.model.yAxis!.getAxisOption()" + [xAxisOption]="this.getAxisOption | htMemoize: this.model?.xAxis" + [yAxisOption]="this.getAxisOption | htMemoize: this.model?.yAxis" [showXAxis]="this.model.showXAxis" [showYAxis]="this.model.showYAxis" [timeRange]="this.timeRange" @@ -61,6 +62,10 @@ export class CartesianWidgetRendererComponent extends In this.model.selectionHandler?.execute(selectedData); } + public getAxisOption(axis: CartesianAxisModel): Partial { + return axis?.getAxisOption(); + } + protected fetchData(): Observable> { return this.model.getDataFetcher().pipe( tap(fetcher => { diff --git a/projects/observability/src/shared/dashboard/widgets/charts/cartesian-widget/cartesian-widget.module.ts b/projects/observability/src/shared/dashboard/widgets/charts/cartesian-widget/cartesian-widget.module.ts index 96fc5e255..6d450aab1 100644 --- a/projects/observability/src/shared/dashboard/widgets/charts/cartesian-widget/cartesian-widget.module.ts +++ b/projects/observability/src/shared/dashboard/widgets/charts/cartesian-widget/cartesian-widget.module.ts @@ -1,6 +1,6 @@ import { CommonModule } from '@angular/common'; import { NgModule } from '@angular/core'; -import { FormattingModule } from '@hypertrace/common'; +import { FormattingModule, MemoizeModule } from '@hypertrace/common'; import { ButtonModule, LabelModule, LoadAsyncModule, TitledContentModule } from '@hypertrace/components'; import { DashboardPropertyEditorsModule } from '@hypertrace/dashboards'; import { DashboardCoreModule, DashboardEditorModule } from '@hypertrace/hyperdash-angular'; @@ -41,7 +41,8 @@ import { SeriesModel } from './series.model'; TitledContentModule, LoadAsyncModule, FormattingModule, - CartesianExplorerContextMenuModule + CartesianExplorerContextMenuModule, + MemoizeModule ] }) export class CartesianWidgetModule {} From 2c4f9bead0e1aa1e9e785794987a5275b65ac96a Mon Sep 17 00:00:00 2001 From: Jyothish Jose Date: Tue, 7 Dec 2021 20:18:56 +0530 Subject: [PATCH 37/49] feat: context menu test cases updated --- ...artesian-widget-renderer.component.test.ts | 63 +++++++++ ...an-explorer-context-menu.component.test.ts | 121 ++++++++++++++++++ ...rtesian-explorer-context-menu.component.ts | 2 +- 3 files changed, 185 insertions(+), 1 deletion(-) create mode 100644 projects/observability/src/shared/dashboard/widgets/charts/cartesian-widget/interactions/cartesian-explorer-context-menu/cartesian-explorer-context-menu.component.test.ts diff --git a/projects/observability/src/shared/dashboard/widgets/charts/cartesian-widget/cartesian-widget-renderer.component.test.ts b/projects/observability/src/shared/dashboard/widgets/charts/cartesian-widget/cartesian-widget-renderer.component.test.ts index a1a48fc23..065005143 100644 --- a/projects/observability/src/shared/dashboard/widgets/charts/cartesian-widget/cartesian-widget-renderer.component.test.ts +++ b/projects/observability/src/shared/dashboard/widgets/charts/cartesian-widget/cartesian-widget-renderer.component.test.ts @@ -6,6 +6,7 @@ import { MemoizeModule, RecursivePartial, TimeDuration, + TimeRangeService, TimeUnit } from '@hypertrace/common'; import { LoadAsyncModule } from '@hypertrace/components'; @@ -15,12 +16,58 @@ import { ModelApi } from '@hypertrace/hyperdash'; import { runFakeRxjs } from '@hypertrace/test-utils'; import { createComponentFactory, mockProvider } from '@ngneat/spectator/jest'; import { of } from 'rxjs'; +import { CartesianSelectedData } from '../../../../../public-api'; import { CartesianSeriesVisualizationType } from '../../../../components/cartesian/chart'; import { CartesianWidgetRendererComponent } from './cartesian-widget-renderer.component'; import { CartesianWidgetModel } from './cartesian-widget.model'; +import { CartesainExplorerNavigationService } from './interactions/cartesian-explorer-navigation.service'; import { MetricSeriesDataFetcher, SeriesModel } from './series.model'; describe('Cartesian widget renderer component', () => { + const selectedData: CartesianSelectedData = { + timeRange: TimeRangeService.toFixedTimeRange( + new Date('2021-11-02T05:33:19.288Z'), + new Date('2021-11-02T14:30:15.141Z') + ), + selectedData: [ + { + dataPoint: { timestamp: '2021-11-02T05:40:00.000Z', value: 1477.3599999999983 }, + context: { + data: [ + { timestamp: '2021-11-02T05:15:00.000Z', value: 774 }, + { timestamp: '2021-11-02T05:40:00.000Z', value: 1477.3599999999983 }, + { timestamp: '2021-11-02T12:05:00.000Z', value: 1056.48 } + ], + units: 'ms', + color: '#4b5f77', + name: 'p99', + type: CartesianSeriesVisualizationType.Column, + stacking: false, + hide: false + }, + location: { x: 59, y: 31.023400000000215 } + }, + { + dataPoint: { timestamp: '2021-11-02T12:05:00.000Z', value: 1056.48 }, + context: { + data: [ + { timestamp: '2021-11-02T05:15:00.000Z', value: 774 }, + { timestamp: '2021-11-02T05:40:00.000Z', value: 1477.3599999999983 }, + { timestamp: '2021-11-02T12:05:00.000Z', value: 1056.48 } + ], + units: 'ms', + color: '#4b5f77', + name: 'p99', + type: CartesianSeriesVisualizationType.Column, + stacking: false, + hide: false + }, + location: { x: 138, y: 82.58120000000001 } + } + ], + location: { x: 452, y: 763 } + }; + const buildComponent = createComponentFactory({ component: CartesianWidgetRendererComponent, providers: [ @@ -208,4 +255,20 @@ describe('Cartesian widget renderer component', () => { spectator.component.onIntervalChange('AUTO'); expect(fetcher.getData).toHaveBeenLastCalledWith(undefined); }); + + // test('calls selection handler on selection change', () => { + // const fetcher = fetcherFactory([]); + // const series = seriesFactory({}, fetcher); + // const mockModel = cartesianModelFactory({ + // series: [series], + // maxSeriesDataPoints: 20 + // }); + // const spectator = buildComponent({ + // providers: [...mockDashboardWidgetProviders(mockModel)] + // }); + + // spectator.component.onSelectionChange(selectedData); + + // expect(spectator.component.model.selectionHandler?.execute).toHaveBeenCalledWith(selectedData); + // }); }); diff --git a/projects/observability/src/shared/dashboard/widgets/charts/cartesian-widget/interactions/cartesian-explorer-context-menu/cartesian-explorer-context-menu.component.test.ts b/projects/observability/src/shared/dashboard/widgets/charts/cartesian-widget/interactions/cartesian-explorer-context-menu/cartesian-explorer-context-menu.component.test.ts new file mode 100644 index 000000000..eb5c2f3c0 --- /dev/null +++ b/projects/observability/src/shared/dashboard/widgets/charts/cartesian-widget/interactions/cartesian-explorer-context-menu/cartesian-explorer-context-menu.component.test.ts @@ -0,0 +1,121 @@ +import { ChangeDetectionStrategy, Component, Inject, Injector, Optional } from '@angular/core'; +import { ButtonComponent, DividerComponent, POPOVER_DATA } from '@hypertrace/components'; +import { createHostFactory, mockProvider, Spectator } from '@ngneat/spectator/jest'; +import { MockComponent } from 'ng-mocks'; +import { CartesainExplorerNavigationService } from '../cartesian-explorer-navigation.service'; +import { CartesianExplorerContextMenuComponent, ContextMenu } from './cartesian-explorer-context-menu.component'; +import { IconType } from '@hypertrace/assets-library'; +import { CartesianSelectedData, CartesianSeriesVisualizationType } from '../../../../../../../public-api'; +import { TimeRangeService } from '@hypertrace/common'; + +@Component({ + // tslint:disable-next-line:component-selector + selector: 'test-context-menu-content', + changeDetection: ChangeDetectionStrategy.OnPush, + template: `
Test Component Content
` +}) +class TestComponent { + public constructor( + public readonly injector: Injector, + @Optional() @Inject(POPOVER_DATA) public readonly data: unknown + ) {} +} + +describe('Sheet Overlay component', () => { + const menu: ContextMenu = { + name: 'Explore', + icon: IconType.ArrowUpRight + }; + + const selectedData: CartesianSelectedData = { + timeRange: TimeRangeService.toFixedTimeRange( + new Date('2021-11-02T05:33:19.288Z'), + new Date('2021-11-02T14:30:15.141Z') + ), + selectedData: [ + { + dataPoint: { timestamp: '2021-11-02T05:40:00.000Z', value: 1477.3599999999983 }, + context: { + data: [ + { timestamp: '2021-11-02T05:15:00.000Z', value: 774 }, + { timestamp: '2021-11-02T05:40:00.000Z', value: 1477.3599999999983 }, + { timestamp: '2021-11-02T12:05:00.000Z', value: 1056.48 } + ], + units: 'ms', + color: '#4b5f77', + name: 'p99', + type: CartesianSeriesVisualizationType.Column, + stacking: false, + hide: false + }, + location: { x: 59, y: 31.023400000000215 } + }, + { + dataPoint: { timestamp: '2021-11-02T12:05:00.000Z', value: 1056.48 }, + context: { + data: [ + { timestamp: '2021-11-02T05:15:00.000Z', value: 774 }, + { timestamp: '2021-11-02T05:40:00.000Z', value: 1477.3599999999983 }, + { timestamp: '2021-11-02T12:05:00.000Z', value: 1056.48 } + ], + units: 'ms', + color: '#4b5f77', + name: 'p99', + type: CartesianSeriesVisualizationType.Column, + stacking: false, + hide: false + }, + location: { x: 138, y: 82.58120000000001 } + } + ], + location: { x: 452, y: 763 } + }; + let spectator: Spectator>; + + const createHost = createHostFactory({ + component: CartesianExplorerContextMenuComponent, + declarations: [MockComponent(ButtonComponent), MockComponent(DividerComponent), TestComponent], + shallow: true, + template: ` + + + `, + providers: [ + mockProvider(CartesainExplorerNavigationService, { + navigateToExplorer: jest.fn() + }) + ] + }); + + const createConfiguredHost = (_configOverrides: any = {}) => + createHost(undefined, { + providers: [ + { + provide: POPOVER_DATA, + deps: [Injector], + useFactory: (injector: Injector) => ({ + injector: Injector.create({ + providers: [ + { + provide: POPOVER_DATA, + useValue: {} + } + ], + // Normally, this would be a root injector when this is invoked from a service + parent: injector + }) + }) + } + ] + }); + + test('should display the title', () => { + spectator = createConfiguredHost({ + data: selectedData + }); + + spectator.component.menuSelectHandler(menu); + + expect(1).toBe(1); + }); +}); diff --git a/projects/observability/src/shared/dashboard/widgets/charts/cartesian-widget/interactions/cartesian-explorer-context-menu/cartesian-explorer-context-menu.component.ts b/projects/observability/src/shared/dashboard/widgets/charts/cartesian-widget/interactions/cartesian-explorer-context-menu/cartesian-explorer-context-menu.component.ts index 3a07b80fe..2551b5e6d 100644 --- a/projects/observability/src/shared/dashboard/widgets/charts/cartesian-widget/interactions/cartesian-explorer-context-menu/cartesian-explorer-context-menu.component.ts +++ b/projects/observability/src/shared/dashboard/widgets/charts/cartesian-widget/interactions/cartesian-explorer-context-menu/cartesian-explorer-context-menu.component.ts @@ -51,7 +51,7 @@ export class CartesianExplorerContextMenuComponent { }; } -interface ContextMenu { +export interface ContextMenu { name: string; icon: string; } From 5c5dc7a37d13c5dbd53c04ba6c2fb4e57ad53788 Mon Sep 17 00:00:00 2001 From: Jyothish Jose Date: Tue, 7 Dec 2021 20:37:04 +0530 Subject: [PATCH 38/49] feat: context menu test cases updated --- ...artesian-widget-renderer.component.test.ts | 27 +++++++++---------- ...an-explorer-context-menu.component.test.ts | 4 ++- 2 files changed, 16 insertions(+), 15 deletions(-) diff --git a/projects/observability/src/shared/dashboard/widgets/charts/cartesian-widget/cartesian-widget-renderer.component.test.ts b/projects/observability/src/shared/dashboard/widgets/charts/cartesian-widget/cartesian-widget-renderer.component.test.ts index 065005143..9fa98d284 100644 --- a/projects/observability/src/shared/dashboard/widgets/charts/cartesian-widget/cartesian-widget-renderer.component.test.ts +++ b/projects/observability/src/shared/dashboard/widgets/charts/cartesian-widget/cartesian-widget-renderer.component.test.ts @@ -20,7 +20,6 @@ import { CartesianSelectedData } from '../../../../../public-api'; import { CartesianSeriesVisualizationType } from '../../../../components/cartesian/chart'; import { CartesianWidgetRendererComponent } from './cartesian-widget-renderer.component'; import { CartesianWidgetModel } from './cartesian-widget.model'; -import { CartesainExplorerNavigationService } from './interactions/cartesian-explorer-navigation.service'; import { MetricSeriesDataFetcher, SeriesModel } from './series.model'; describe('Cartesian widget renderer component', () => { @@ -256,19 +255,19 @@ describe('Cartesian widget renderer component', () => { expect(fetcher.getData).toHaveBeenLastCalledWith(undefined); }); - // test('calls selection handler on selection change', () => { - // const fetcher = fetcherFactory([]); - // const series = seriesFactory({}, fetcher); - // const mockModel = cartesianModelFactory({ - // series: [series], - // maxSeriesDataPoints: 20 - // }); - // const spectator = buildComponent({ - // providers: [...mockDashboardWidgetProviders(mockModel)] - // }); + test('calls selection handler on selection change', () => { + const fetcher = fetcherFactory([]); + const series = seriesFactory({}, fetcher); + const mockModel = cartesianModelFactory({ + series: [series], + maxSeriesDataPoints: 20 + }); + const spectator = buildComponent({ + providers: [...mockDashboardWidgetProviders(mockModel)] + }); - // spectator.component.onSelectionChange(selectedData); + spectator.component.onSelectionChange(selectedData); - // expect(spectator.component.model.selectionHandler?.execute).toHaveBeenCalledWith(selectedData); - // }); + expect(spectator.component).toBeTruthy(); + }); }); diff --git a/projects/observability/src/shared/dashboard/widgets/charts/cartesian-widget/interactions/cartesian-explorer-context-menu/cartesian-explorer-context-menu.component.test.ts b/projects/observability/src/shared/dashboard/widgets/charts/cartesian-widget/interactions/cartesian-explorer-context-menu/cartesian-explorer-context-menu.component.test.ts index eb5c2f3c0..aae85978a 100644 --- a/projects/observability/src/shared/dashboard/widgets/charts/cartesian-widget/interactions/cartesian-explorer-context-menu/cartesian-explorer-context-menu.component.test.ts +++ b/projects/observability/src/shared/dashboard/widgets/charts/cartesian-widget/interactions/cartesian-explorer-context-menu/cartesian-explorer-context-menu.component.test.ts @@ -114,8 +114,10 @@ describe('Sheet Overlay component', () => { data: selectedData }); + spectator.component.selectionData = selectedData; + spectator.component.menuSelectHandler(menu); - expect(1).toBe(1); + expect(spectator.inject(CartesainExplorerNavigationService).navigateToExplorer).toHaveBeenCalled(); }); }); From 0907153446e75aedaf08e102c2e1118f1f8f834b Mon Sep 17 00:00:00 2001 From: Jyothish Jose Date: Tue, 7 Dec 2021 20:43:56 +0530 Subject: [PATCH 39/49] feat: context menu test cases updated --- .../cartesian-explorer-context-menu.component.test.ts | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/projects/observability/src/shared/dashboard/widgets/charts/cartesian-widget/interactions/cartesian-explorer-context-menu/cartesian-explorer-context-menu.component.test.ts b/projects/observability/src/shared/dashboard/widgets/charts/cartesian-widget/interactions/cartesian-explorer-context-menu/cartesian-explorer-context-menu.component.test.ts index aae85978a..2781bdec0 100644 --- a/projects/observability/src/shared/dashboard/widgets/charts/cartesian-widget/interactions/cartesian-explorer-context-menu/cartesian-explorer-context-menu.component.test.ts +++ b/projects/observability/src/shared/dashboard/widgets/charts/cartesian-widget/interactions/cartesian-explorer-context-menu/cartesian-explorer-context-menu.component.test.ts @@ -1,12 +1,12 @@ import { ChangeDetectionStrategy, Component, Inject, Injector, Optional } from '@angular/core'; +import { IconType } from '@hypertrace/assets-library'; +import { TimeRangeService } from '@hypertrace/common'; import { ButtonComponent, DividerComponent, POPOVER_DATA } from '@hypertrace/components'; import { createHostFactory, mockProvider, Spectator } from '@ngneat/spectator/jest'; import { MockComponent } from 'ng-mocks'; +import { CartesianSelectedData, CartesianSeriesVisualizationType } from '../../../../../../../public-api'; import { CartesainExplorerNavigationService } from '../cartesian-explorer-navigation.service'; import { CartesianExplorerContextMenuComponent, ContextMenu } from './cartesian-explorer-context-menu.component'; -import { IconType } from '@hypertrace/assets-library'; -import { CartesianSelectedData, CartesianSeriesVisualizationType } from '../../../../../../../public-api'; -import { TimeRangeService } from '@hypertrace/common'; @Component({ // tslint:disable-next-line:component-selector @@ -87,7 +87,7 @@ describe('Sheet Overlay component', () => { ] }); - const createConfiguredHost = (_configOverrides: any = {}) => + const createConfiguredHost = ({}) => createHost(undefined, { providers: [ { @@ -109,7 +109,7 @@ describe('Sheet Overlay component', () => { ] }); - test('should display the title', () => { + test('should navigate to explorer on click explore menu', () => { spectator = createConfiguredHost({ data: selectedData }); From a6f6fadf8e19d18e2737eedc89d79456be2d6068 Mon Sep 17 00:00:00 2001 From: Jyothish Jose Date: Wed, 5 Jan 2022 10:27:05 +0530 Subject: [PATCH 40/49] feat: set time range option added --- .../common/src/time/time-range.service.ts | 3 +-- ...an-explorer-context-menu.component.test.ts | 3 +++ ...rtesian-explorer-context-menu.component.ts | 20 ++++++++++++++----- 3 files changed, 19 insertions(+), 7 deletions(-) diff --git a/projects/common/src/time/time-range.service.ts b/projects/common/src/time/time-range.service.ts index b04434b08..583773d78 100644 --- a/projects/common/src/time/time-range.service.ts +++ b/projects/common/src/time/time-range.service.ts @@ -112,8 +112,7 @@ export class TimeRangeService { } public toQueryParams(startTime: Date, endTime: Date): QueryParamObject { - const newTimeRange = TimeRangeService.toFixedTimeRange(startTime, endTime); - this.timeRangeSubject$.next(newTimeRange); + const newTimeRange = new FixedTimeRange(startTime, endTime); return { [TimeRangeService.TIME_RANGE_QUERY_PARAM]: newTimeRange.toUrlString() diff --git a/projects/observability/src/shared/dashboard/widgets/charts/cartesian-widget/interactions/cartesian-explorer-context-menu/cartesian-explorer-context-menu.component.test.ts b/projects/observability/src/shared/dashboard/widgets/charts/cartesian-widget/interactions/cartesian-explorer-context-menu/cartesian-explorer-context-menu.component.test.ts index 2781bdec0..894f1c0ca 100644 --- a/projects/observability/src/shared/dashboard/widgets/charts/cartesian-widget/interactions/cartesian-explorer-context-menu/cartesian-explorer-context-menu.component.test.ts +++ b/projects/observability/src/shared/dashboard/widgets/charts/cartesian-widget/interactions/cartesian-explorer-context-menu/cartesian-explorer-context-menu.component.test.ts @@ -83,6 +83,9 @@ describe('Sheet Overlay component', () => { providers: [ mockProvider(CartesainExplorerNavigationService, { navigateToExplorer: jest.fn() + }), + mockProvider(TimeRangeService, { + toQueryParams: jest.fn() }) ] }); diff --git a/projects/observability/src/shared/dashboard/widgets/charts/cartesian-widget/interactions/cartesian-explorer-context-menu/cartesian-explorer-context-menu.component.ts b/projects/observability/src/shared/dashboard/widgets/charts/cartesian-widget/interactions/cartesian-explorer-context-menu/cartesian-explorer-context-menu.component.ts index 2551b5e6d..b5beefb9a 100644 --- a/projects/observability/src/shared/dashboard/widgets/charts/cartesian-widget/interactions/cartesian-explorer-context-menu/cartesian-explorer-context-menu.component.ts +++ b/projects/observability/src/shared/dashboard/widgets/charts/cartesian-widget/interactions/cartesian-explorer-context-menu/cartesian-explorer-context-menu.component.ts @@ -1,5 +1,6 @@ import { ChangeDetectionStrategy, Component, Inject } from '@angular/core'; import { IconType } from '@hypertrace/assets-library'; +import { TimeRangeService } from '@hypertrace/common'; import { ButtonStyle, POPOVER_DATA } from '@hypertrace/components'; import { CartesianSelectedData } from '../../../../../../components/cartesian/chart-interactivty'; import { CartesainExplorerNavigationService } from '../cartesian-explorer-navigation.service'; @@ -27,6 +28,10 @@ import { CartesainExplorerNavigationService } from '../cartesian-explorer-naviga }) export class CartesianExplorerContextMenuComponent { public menus?: ContextMenu[] = [ + { + name: 'Set Time Range', + icon: IconType.Alarm + }, { name: 'Explore', icon: IconType.ArrowUpRight @@ -38,16 +43,21 @@ export class CartesianExplorerContextMenuComponent { public constructor( @Inject(POPOVER_DATA) data: CartesianSelectedData, - private readonly cartesainExplorerNavigationService: CartesainExplorerNavigationService + private readonly cartesainExplorerNavigationService: CartesainExplorerNavigationService, + private readonly timeRangeService: TimeRangeService ) { this.selectionData = data; } public menuSelectHandler = (_menu: ContextMenu): void => { - this.cartesainExplorerNavigationService.navigateToExplorer( - this.selectionData.timeRange.startTime, - this.selectionData.timeRange.endTime - ); + this.timeRangeService.setFixedRange(this.selectionData.timeRange.startTime, this.selectionData.timeRange.endTime); + + if (_menu.name === 'Explore') { + this.cartesainExplorerNavigationService.navigateToExplorer( + this.selectionData.timeRange.startTime, + this.selectionData.timeRange.endTime + ); + } }; } From 82ea0d2fd901ed6c1f695889bef59f7a540c2375 Mon Sep 17 00:00:00 2001 From: Jyothish Jose Date: Mon, 10 Jan 2022 15:12:24 +0530 Subject: [PATCH 41/49] feat: context menu navigation handler added --- ...an-explorer-context-menu.component.test.ts | 17 +++++++---- ...rtesian-explorer-context-menu.component.ts | 30 +++++++++---------- .../cartesian-explorer-navigation.service.ts | 1 + 3 files changed, 26 insertions(+), 22 deletions(-) diff --git a/projects/observability/src/shared/dashboard/widgets/charts/cartesian-widget/interactions/cartesian-explorer-context-menu/cartesian-explorer-context-menu.component.test.ts b/projects/observability/src/shared/dashboard/widgets/charts/cartesian-widget/interactions/cartesian-explorer-context-menu/cartesian-explorer-context-menu.component.test.ts index 894f1c0ca..a52719c2a 100644 --- a/projects/observability/src/shared/dashboard/widgets/charts/cartesian-widget/interactions/cartesian-explorer-context-menu/cartesian-explorer-context-menu.component.test.ts +++ b/projects/observability/src/shared/dashboard/widgets/charts/cartesian-widget/interactions/cartesian-explorer-context-menu/cartesian-explorer-context-menu.component.test.ts @@ -22,11 +22,6 @@ class TestComponent { } describe('Sheet Overlay component', () => { - const menu: ContextMenu = { - name: 'Explore', - icon: IconType.ArrowUpRight - }; - const selectedData: CartesianSelectedData = { timeRange: TimeRangeService.toFixedTimeRange( new Date('2021-11-02T05:33:19.288Z'), @@ -119,7 +114,17 @@ describe('Sheet Overlay component', () => { spectator.component.selectionData = selectedData; - spectator.component.menuSelectHandler(menu); + const menu: ContextMenu = { + name: 'Explore', + icon: IconType.ArrowUpRight, + onClick: () => { + spectator + .inject(CartesainExplorerNavigationService) + .navigateToExplorer(selectedData.timeRange.startTime, selectedData.timeRange.endTime); + } + }; + + menu.onClick(); expect(spectator.inject(CartesainExplorerNavigationService).navigateToExplorer).toHaveBeenCalled(); }); diff --git a/projects/observability/src/shared/dashboard/widgets/charts/cartesian-widget/interactions/cartesian-explorer-context-menu/cartesian-explorer-context-menu.component.ts b/projects/observability/src/shared/dashboard/widgets/charts/cartesian-widget/interactions/cartesian-explorer-context-menu/cartesian-explorer-context-menu.component.ts index b5beefb9a..c91ffc4af 100644 --- a/projects/observability/src/shared/dashboard/widgets/charts/cartesian-widget/interactions/cartesian-explorer-context-menu/cartesian-explorer-context-menu.component.ts +++ b/projects/observability/src/shared/dashboard/widgets/charts/cartesian-widget/interactions/cartesian-explorer-context-menu/cartesian-explorer-context-menu.component.ts @@ -13,12 +13,7 @@ import { CartesainExplorerNavigationService } from '../cartesian-explorer-naviga
- +
@@ -30,11 +25,13 @@ export class CartesianExplorerContextMenuComponent { public menus?: ContextMenu[] = [ { name: 'Set Time Range', - icon: IconType.Alarm + icon: IconType.Alarm, + onClick: () => this.setTimeRangeHandler() }, { name: 'Explore', - icon: IconType.ArrowUpRight + icon: IconType.ArrowUpRight, + onClick: () => this.explorerNavigationHandler() } ]; @@ -49,19 +46,20 @@ export class CartesianExplorerContextMenuComponent { this.selectionData = data; } - public menuSelectHandler = (_menu: ContextMenu): void => { - this.timeRangeService.setFixedRange(this.selectionData.timeRange.startTime, this.selectionData.timeRange.endTime); + public readonly explorerNavigationHandler = () => { + this.cartesainExplorerNavigationService.navigateToExplorer( + this.selectionData.timeRange.startTime, + this.selectionData.timeRange.endTime + ); + }; - if (_menu.name === 'Explore') { - this.cartesainExplorerNavigationService.navigateToExplorer( - this.selectionData.timeRange.startTime, - this.selectionData.timeRange.endTime - ); - } + public readonly setTimeRangeHandler = () => { + this.timeRangeService.setFixedRange(this.selectionData.timeRange.startTime, this.selectionData.timeRange.endTime); }; } export interface ContextMenu { name: string; icon: string; + onClick(): void; } diff --git a/projects/observability/src/shared/dashboard/widgets/charts/cartesian-widget/interactions/cartesian-explorer-navigation.service.ts b/projects/observability/src/shared/dashboard/widgets/charts/cartesian-widget/interactions/cartesian-explorer-navigation.service.ts index 637102352..d33c6d167 100644 --- a/projects/observability/src/shared/dashboard/widgets/charts/cartesian-widget/interactions/cartesian-explorer-navigation.service.ts +++ b/projects/observability/src/shared/dashboard/widgets/charts/cartesian-widget/interactions/cartesian-explorer-navigation.service.ts @@ -11,6 +11,7 @@ export class CartesainExplorerNavigationService { ) {} public navigateToExplorer(start: Date, end: Date): void { + this.timeRangeService.setFixedRange(start, end); const params = this.timeRangeService.toQueryParams(start, end); this.navigationService.navigate({ From 8f39e00906dd92e92ce8f6fb45b8aa7e60780992 Mon Sep 17 00:00:00 2001 From: Jyothish Jose Date: Fri, 14 Jan 2022 10:28:19 +0530 Subject: [PATCH 42/49] feat: updated imports and test cases --- .../components/cartesian/cartesian-chart.component.ts | 6 ++++-- .../cartesian-widget-renderer.component.test.ts | 7 +++++-- .../cartesian-explorer-context-menu.component.test.ts | 2 +- .../cartesian-explorer-selection-handler.model.test.ts | 2 +- .../cartesian-explorer-selection-handler.model.ts | 2 +- 5 files changed, 12 insertions(+), 7 deletions(-) diff --git a/projects/observability/src/shared/components/cartesian/cartesian-chart.component.ts b/projects/observability/src/shared/components/cartesian/cartesian-chart.component.ts index ae500f811..130b8d530 100644 --- a/projects/observability/src/shared/components/cartesian/cartesian-chart.component.ts +++ b/projects/observability/src/shared/components/cartesian/cartesian-chart.component.ts @@ -67,7 +67,9 @@ export class CartesianChartComponent implements OnChanges, OnDestroy { public readonly selectedIntervalChange: EventEmitter = new EventEmitter(); @Output() - public readonly selectionChange: EventEmitter> = new EventEmitter(); + public readonly selectionChange: EventEmitter< + MouseLocationData | Band>[] | CartesianSelectedData + > = new EventEmitter(); @ViewChild('chartContainer', { static: true }) public readonly container!: ElementRef; @@ -100,7 +102,7 @@ export class CartesianChartComponent implements OnChanges, OnDestroy { ) ) .withEventListener(ChartEvent.Select, selectedData => { - this.selectionChange.emit(selectedData as CartesianSelectedData); + this.selectionChange.emit(selectedData); }); if (this.bands) { diff --git a/projects/observability/src/shared/dashboard/widgets/charts/cartesian-widget/cartesian-widget-renderer.component.test.ts b/projects/observability/src/shared/dashboard/widgets/charts/cartesian-widget/cartesian-widget-renderer.component.test.ts index 9fa98d284..9e132ee05 100644 --- a/projects/observability/src/shared/dashboard/widgets/charts/cartesian-widget/cartesian-widget-renderer.component.test.ts +++ b/projects/observability/src/shared/dashboard/widgets/charts/cartesian-widget/cartesian-widget-renderer.component.test.ts @@ -260,7 +260,10 @@ describe('Cartesian widget renderer component', () => { const series = seriesFactory({}, fetcher); const mockModel = cartesianModelFactory({ series: [series], - maxSeriesDataPoints: 20 + maxSeriesDataPoints: 20, + selectionHandler: { + execute: jest.fn() + } }); const spectator = buildComponent({ providers: [...mockDashboardWidgetProviders(mockModel)] @@ -268,6 +271,6 @@ describe('Cartesian widget renderer component', () => { spectator.component.onSelectionChange(selectedData); - expect(spectator.component).toBeTruthy(); + expect(spectator.component.model.selectionHandler?.execute).toHaveBeenCalled(); }); }); diff --git a/projects/observability/src/shared/dashboard/widgets/charts/cartesian-widget/interactions/cartesian-explorer-context-menu/cartesian-explorer-context-menu.component.test.ts b/projects/observability/src/shared/dashboard/widgets/charts/cartesian-widget/interactions/cartesian-explorer-context-menu/cartesian-explorer-context-menu.component.test.ts index a52719c2a..a45ced8c4 100644 --- a/projects/observability/src/shared/dashboard/widgets/charts/cartesian-widget/interactions/cartesian-explorer-context-menu/cartesian-explorer-context-menu.component.test.ts +++ b/projects/observability/src/shared/dashboard/widgets/charts/cartesian-widget/interactions/cartesian-explorer-context-menu/cartesian-explorer-context-menu.component.test.ts @@ -2,9 +2,9 @@ import { ChangeDetectionStrategy, Component, Inject, Injector, Optional } from ' import { IconType } from '@hypertrace/assets-library'; import { TimeRangeService } from '@hypertrace/common'; import { ButtonComponent, DividerComponent, POPOVER_DATA } from '@hypertrace/components'; +import { CartesianSelectedData, CartesianSeriesVisualizationType } from '@hypertrace/observability'; import { createHostFactory, mockProvider, Spectator } from '@ngneat/spectator/jest'; import { MockComponent } from 'ng-mocks'; -import { CartesianSelectedData, CartesianSeriesVisualizationType } from '../../../../../../../public-api'; import { CartesainExplorerNavigationService } from '../cartesian-explorer-navigation.service'; import { CartesianExplorerContextMenuComponent, ContextMenu } from './cartesian-explorer-context-menu.component'; diff --git a/projects/observability/src/shared/dashboard/widgets/charts/cartesian-widget/interactions/cartesian-explorer-selection-handler.model.test.ts b/projects/observability/src/shared/dashboard/widgets/charts/cartesian-widget/interactions/cartesian-explorer-selection-handler.model.test.ts index b369c619a..cc47dab56 100644 --- a/projects/observability/src/shared/dashboard/widgets/charts/cartesian-widget/interactions/cartesian-explorer-selection-handler.model.test.ts +++ b/projects/observability/src/shared/dashboard/widgets/charts/cartesian-widget/interactions/cartesian-explorer-selection-handler.model.test.ts @@ -1,8 +1,8 @@ import { TimeRangeService } from '@hypertrace/common'; import { PopoverService } from '@hypertrace/components'; import { createModelFactory } from '@hypertrace/dashboards/testing'; +import { CartesianSelectedData, CartesianSeriesVisualizationType } from '@hypertrace/observability'; import { mockProvider } from '@ngneat/spectator/jest'; -import { CartesianSelectedData, CartesianSeriesVisualizationType } from '../../../../../../public-api'; import { CartesainExplorerNavigationService } from './cartesian-explorer-navigation.service'; import { CartesianExplorerSelectionHandlerModel } from './cartesian-explorer-selection-handler.model'; diff --git a/projects/observability/src/shared/dashboard/widgets/charts/cartesian-widget/interactions/cartesian-explorer-selection-handler.model.ts b/projects/observability/src/shared/dashboard/widgets/charts/cartesian-widget/interactions/cartesian-explorer-selection-handler.model.ts index 0ada1a045..914838253 100644 --- a/projects/observability/src/shared/dashboard/widgets/charts/cartesian-widget/interactions/cartesian-explorer-selection-handler.model.ts +++ b/projects/observability/src/shared/dashboard/widgets/charts/cartesian-widget/interactions/cartesian-explorer-selection-handler.model.ts @@ -7,8 +7,8 @@ import { } from '@hypertrace/components'; import { BOOLEAN_PROPERTY, Model, ModelProperty } from '@hypertrace/hyperdash'; import { ModelInject } from '@hypertrace/hyperdash-angular'; +import { CartesianSelectedData } from '@hypertrace/observability'; import { Observable, of } from 'rxjs'; -import { CartesianSelectedData } from '../../../../../../public-api'; import { InteractionHandler } from '../../../../interaction/interaction-handler'; import { CartesianExplorerContextMenuComponent } from './cartesian-explorer-context-menu/cartesian-explorer-context-menu.component'; From 35fa74ffd3ad085fe50912d0d6edb3f82844a6c8 Mon Sep 17 00:00:00 2001 From: Jyothish Jose Date: Mon, 17 Jan 2022 08:02:46 +0530 Subject: [PATCH 43/49] feat: updated imports and test cases --- ...an-explorer-context-menu.component.test.ts | 19 +++---------------- 1 file changed, 3 insertions(+), 16 deletions(-) diff --git a/projects/observability/src/shared/dashboard/widgets/charts/cartesian-widget/interactions/cartesian-explorer-context-menu/cartesian-explorer-context-menu.component.test.ts b/projects/observability/src/shared/dashboard/widgets/charts/cartesian-widget/interactions/cartesian-explorer-context-menu/cartesian-explorer-context-menu.component.test.ts index a45ced8c4..d21b1457b 100644 --- a/projects/observability/src/shared/dashboard/widgets/charts/cartesian-widget/interactions/cartesian-explorer-context-menu/cartesian-explorer-context-menu.component.test.ts +++ b/projects/observability/src/shared/dashboard/widgets/charts/cartesian-widget/interactions/cartesian-explorer-context-menu/cartesian-explorer-context-menu.component.test.ts @@ -1,4 +1,4 @@ -import { ChangeDetectionStrategy, Component, Inject, Injector, Optional } from '@angular/core'; +import { Injector } from '@angular/core'; import { IconType } from '@hypertrace/assets-library'; import { TimeRangeService } from '@hypertrace/common'; import { ButtonComponent, DividerComponent, POPOVER_DATA } from '@hypertrace/components'; @@ -8,20 +8,7 @@ import { MockComponent } from 'ng-mocks'; import { CartesainExplorerNavigationService } from '../cartesian-explorer-navigation.service'; import { CartesianExplorerContextMenuComponent, ContextMenu } from './cartesian-explorer-context-menu.component'; -@Component({ - // tslint:disable-next-line:component-selector - selector: 'test-context-menu-content', - changeDetection: ChangeDetectionStrategy.OnPush, - template: `
Test Component Content
` -}) -class TestComponent { - public constructor( - public readonly injector: Injector, - @Optional() @Inject(POPOVER_DATA) public readonly data: unknown - ) {} -} - -describe('Sheet Overlay component', () => { +describe('Cartesian context menu component', () => { const selectedData: CartesianSelectedData = { timeRange: TimeRangeService.toFixedTimeRange( new Date('2021-11-02T05:33:19.288Z'), @@ -69,7 +56,7 @@ describe('Sheet Overlay component', () => { const createHost = createHostFactory({ component: CartesianExplorerContextMenuComponent, - declarations: [MockComponent(ButtonComponent), MockComponent(DividerComponent), TestComponent], + declarations: [MockComponent(ButtonComponent), MockComponent(DividerComponent)], shallow: true, template: ` From 3017b4f8324082c53abb16d6c5c5d050c7a6df0c Mon Sep 17 00:00:00 2001 From: Jyothish Jose Date: Mon, 17 Jan 2022 10:25:57 +0530 Subject: [PATCH 44/49] feat: updated imports and test cases --- ...an-explorer-context-menu.component.test.ts | 118 +++++++++++------- ...rtesian-explorer-context-menu.component.ts | 2 +- 2 files changed, 76 insertions(+), 44 deletions(-) diff --git a/projects/observability/src/shared/dashboard/widgets/charts/cartesian-widget/interactions/cartesian-explorer-context-menu/cartesian-explorer-context-menu.component.test.ts b/projects/observability/src/shared/dashboard/widgets/charts/cartesian-widget/interactions/cartesian-explorer-context-menu/cartesian-explorer-context-menu.component.test.ts index d21b1457b..d05be6472 100644 --- a/projects/observability/src/shared/dashboard/widgets/charts/cartesian-widget/interactions/cartesian-explorer-context-menu/cartesian-explorer-context-menu.component.test.ts +++ b/projects/observability/src/shared/dashboard/widgets/charts/cartesian-widget/interactions/cartesian-explorer-context-menu/cartesian-explorer-context-menu.component.test.ts @@ -1,12 +1,12 @@ -import { Injector } from '@angular/core'; +import { StaticProvider } from '@angular/core'; import { IconType } from '@hypertrace/assets-library'; import { TimeRangeService } from '@hypertrace/common'; import { ButtonComponent, DividerComponent, POPOVER_DATA } from '@hypertrace/components'; import { CartesianSelectedData, CartesianSeriesVisualizationType } from '@hypertrace/observability'; -import { createHostFactory, mockProvider, Spectator } from '@ngneat/spectator/jest'; +import { createComponentFactory, mockProvider, Spectator } from '@ngneat/spectator/jest'; import { MockComponent } from 'ng-mocks'; import { CartesainExplorerNavigationService } from '../cartesian-explorer-navigation.service'; -import { CartesianExplorerContextMenuComponent, ContextMenu } from './cartesian-explorer-context-menu.component'; +import { CartesianExplorerContextMenuComponent } from './cartesian-explorer-context-menu.component'; describe('Cartesian context menu component', () => { const selectedData: CartesianSelectedData = { @@ -54,65 +54,97 @@ describe('Cartesian context menu component', () => { }; let spectator: Spectator>; - const createHost = createHostFactory({ + const createComponent = createComponentFactory({ component: CartesianExplorerContextMenuComponent, declarations: [MockComponent(ButtonComponent), MockComponent(DividerComponent)], shallow: true, - template: ` - - - `, providers: [ mockProvider(CartesainExplorerNavigationService, { navigateToExplorer: jest.fn() }), mockProvider(TimeRangeService, { - toQueryParams: jest.fn() + toQueryParams: jest.fn(), + setFixedRange: jest.fn() }) ] }); - const createConfiguredHost = ({}) => - createHost(undefined, { - providers: [ - { - provide: POPOVER_DATA, - deps: [Injector], - useFactory: (injector: Injector) => ({ - injector: Injector.create({ - providers: [ - { - provide: POPOVER_DATA, - useValue: {} - } - ], - // Normally, this would be a root injector when this is invoked from a service - parent: injector - }) - }) - } - ] - }); + const buildProviders = (data: CartesianSelectedData): { providers: StaticProvider[] } => ({ + providers: [ + { + provide: POPOVER_DATA, + useValue: data + } + ] + }); test('should navigate to explorer on click explore menu', () => { - spectator = createConfiguredHost({ - data: selectedData - }); + spectator = createComponent(buildProviders(selectedData)); spectator.component.selectionData = selectedData; - - const menu: ContextMenu = { - name: 'Explore', - icon: IconType.ArrowUpRight, - onClick: () => { - spectator - .inject(CartesainExplorerNavigationService) - .navigateToExplorer(selectedData.timeRange.startTime, selectedData.timeRange.endTime); + spectator.component.menus = [ + { + name: 'Set Time Range', + icon: IconType.Alarm, + onClick: () => { + spectator + .inject(TimeRangeService) + .setFixedRange(selectedData.timeRange.startTime, selectedData.timeRange.endTime); + } + }, + { + name: 'Explore', + icon: IconType.ArrowUpRight, + onClick: () => { + spectator + .inject(CartesainExplorerNavigationService) + .navigateToExplorer(selectedData.timeRange.startTime, selectedData.timeRange.endTime); + } } - }; + ]; + + const buttons = spectator.queryAll(ButtonComponent); + expect(buttons.length).toBe(2); + + const exploreMenu = spectator.queryAll('ht-button')[1]; - menu.onClick(); + spectator.click(exploreMenu); expect(spectator.inject(CartesainExplorerNavigationService).navigateToExplorer).toHaveBeenCalled(); }); + + test('should change timerange on click timerange menu', () => { + spectator = createComponent(buildProviders(selectedData)); + + spectator.component.selectionData = selectedData; + spectator.component.menus = [ + { + name: 'Set Time Range', + icon: IconType.Alarm, + onClick: () => { + spectator + .inject(TimeRangeService) + .setFixedRange(selectedData.timeRange.startTime, selectedData.timeRange.endTime); + } + }, + { + name: 'Explore', + icon: IconType.ArrowUpRight, + onClick: () => { + spectator + .inject(CartesainExplorerNavigationService) + .navigateToExplorer(selectedData.timeRange.startTime, selectedData.timeRange.endTime); + } + } + ]; + + const buttons = spectator.queryAll(ButtonComponent); + expect(buttons.length).toBe(2); + + const timerangeMenu = spectator.queryAll('ht-button')[0]; + + spectator.click(timerangeMenu); + + expect(spectator.inject(TimeRangeService).setFixedRange).toHaveBeenCalled(); + }); }); diff --git a/projects/observability/src/shared/dashboard/widgets/charts/cartesian-widget/interactions/cartesian-explorer-context-menu/cartesian-explorer-context-menu.component.ts b/projects/observability/src/shared/dashboard/widgets/charts/cartesian-widget/interactions/cartesian-explorer-context-menu/cartesian-explorer-context-menu.component.ts index c91ffc4af..91da869ec 100644 --- a/projects/observability/src/shared/dashboard/widgets/charts/cartesian-widget/interactions/cartesian-explorer-context-menu/cartesian-explorer-context-menu.component.ts +++ b/projects/observability/src/shared/dashboard/widgets/charts/cartesian-widget/interactions/cartesian-explorer-context-menu/cartesian-explorer-context-menu.component.ts @@ -58,7 +58,7 @@ export class CartesianExplorerContextMenuComponent { }; } -export interface ContextMenu { +interface ContextMenu { name: string; icon: string; onClick(): void; From 1c71ad66a18ea470ebd0b4d48669a857b2e11ddb Mon Sep 17 00:00:00 2001 From: Jyothish Jose Date: Mon, 17 Jan 2022 11:25:24 +0530 Subject: [PATCH 45/49] feat: updated imports and test cases --- projects/common/src/time/time-range.service.test.ts | 12 ++++++++---- projects/common/src/time/time-range.service.ts | 2 +- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/projects/common/src/time/time-range.service.test.ts b/projects/common/src/time/time-range.service.test.ts index 49679cf85..630bc89e8 100644 --- a/projects/common/src/time/time-range.service.test.ts +++ b/projects/common/src/time/time-range.service.test.ts @@ -28,6 +28,8 @@ describe('Time range service', () => { ] }); + beforeEach(() => {}); + test('throws error when asking for time range before initialization', () => { const spectator = buildService(); expect(() => spectator.service.getCurrentTimeRange()).toThrow(); @@ -84,9 +86,11 @@ describe('Time range service', () => { test('returns custom time filter', () => { const spectator = buildService(); - spectator.service.toQueryParams(new Date(1573255100253), new Date(1573255111159)); - expect(spectator.service.getCurrentTimeRange()).toEqual( - new FixedTimeRange(new Date(1573255100253), new Date(1573255111159)) - ); + expect(spectator.service.toQueryParams(new Date(1642296703000), new Date(1642396703000))).toStrictEqual({ + [TimeRangeService.TIME_RANGE_QUERY_PARAM]: new FixedTimeRange( + new Date(1642296703000), + new Date(1642396703000) + ).toUrlString() + }); }); }); diff --git a/projects/common/src/time/time-range.service.ts b/projects/common/src/time/time-range.service.ts index 583773d78..f70a9f46c 100644 --- a/projects/common/src/time/time-range.service.ts +++ b/projects/common/src/time/time-range.service.ts @@ -15,7 +15,7 @@ import { TimeUnit } from './time-unit.type'; providedIn: 'root' }) export class TimeRangeService { - private static readonly TIME_RANGE_QUERY_PARAM: string = 'time'; + public static readonly TIME_RANGE_QUERY_PARAM: string = 'time'; private readonly defaultTimeRange: TimeRange = new RelativeTimeRange(new TimeDuration(1, TimeUnit.Hour)); private readonly timeRangeSubject$: ReplaySubject = new ReplaySubject(1); From f3e86aac6f25f41f8ce127bf52c052368e187fa3 Mon Sep 17 00:00:00 2001 From: Jyothish Jose Date: Mon, 17 Jan 2022 11:37:48 +0530 Subject: [PATCH 46/49] feat: updated imports and test cases --- projects/common/src/time/time-range.service.test.ts | 2 -- 1 file changed, 2 deletions(-) diff --git a/projects/common/src/time/time-range.service.test.ts b/projects/common/src/time/time-range.service.test.ts index 630bc89e8..620e1ad84 100644 --- a/projects/common/src/time/time-range.service.test.ts +++ b/projects/common/src/time/time-range.service.test.ts @@ -28,8 +28,6 @@ describe('Time range service', () => { ] }); - beforeEach(() => {}); - test('throws error when asking for time range before initialization', () => { const spectator = buildService(); expect(() => spectator.service.getCurrentTimeRange()).toThrow(); From f224c1b9ca0ce50d78908b9f41d1327c59e85767 Mon Sep 17 00:00:00 2001 From: Jyothish Jose Date: Wed, 19 Jan 2022 10:23:17 +0530 Subject: [PATCH 47/49] feat: updated imports and test cases --- projects/common/src/time/time-range.service.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/projects/common/src/time/time-range.service.ts b/projects/common/src/time/time-range.service.ts index f70a9f46c..583773d78 100644 --- a/projects/common/src/time/time-range.service.ts +++ b/projects/common/src/time/time-range.service.ts @@ -15,7 +15,7 @@ import { TimeUnit } from './time-unit.type'; providedIn: 'root' }) export class TimeRangeService { - public static readonly TIME_RANGE_QUERY_PARAM: string = 'time'; + private static readonly TIME_RANGE_QUERY_PARAM: string = 'time'; private readonly defaultTimeRange: TimeRange = new RelativeTimeRange(new TimeDuration(1, TimeUnit.Hour)); private readonly timeRangeSubject$: ReplaySubject = new ReplaySubject(1); From e5e37318efbd755aa143e790b0a11f71a2ed62ef Mon Sep 17 00:00:00 2001 From: Jyothish Jose Date: Wed, 19 Jan 2022 10:38:51 +0530 Subject: [PATCH 48/49] feat: updated imports and test cases --- .../src/time/time-range.service.test.ts | 5 +---- ...an-explorer-context-menu.component.test.ts | 21 ------------------- 2 files changed, 1 insertion(+), 25 deletions(-) diff --git a/projects/common/src/time/time-range.service.test.ts b/projects/common/src/time/time-range.service.test.ts index 620e1ad84..f6b37c48e 100644 --- a/projects/common/src/time/time-range.service.test.ts +++ b/projects/common/src/time/time-range.service.test.ts @@ -85,10 +85,7 @@ describe('Time range service', () => { test('returns custom time filter', () => { const spectator = buildService(); expect(spectator.service.toQueryParams(new Date(1642296703000), new Date(1642396703000))).toStrictEqual({ - [TimeRangeService.TIME_RANGE_QUERY_PARAM]: new FixedTimeRange( - new Date(1642296703000), - new Date(1642396703000) - ).toUrlString() + ['time']: new FixedTimeRange(new Date(1642296703000), new Date(1642396703000)).toUrlString() }); }); }); diff --git a/projects/observability/src/shared/dashboard/widgets/charts/cartesian-widget/interactions/cartesian-explorer-context-menu/cartesian-explorer-context-menu.component.test.ts b/projects/observability/src/shared/dashboard/widgets/charts/cartesian-widget/interactions/cartesian-explorer-context-menu/cartesian-explorer-context-menu.component.test.ts index d05be6472..10acfce5e 100644 --- a/projects/observability/src/shared/dashboard/widgets/charts/cartesian-widget/interactions/cartesian-explorer-context-menu/cartesian-explorer-context-menu.component.test.ts +++ b/projects/observability/src/shared/dashboard/widgets/charts/cartesian-widget/interactions/cartesian-explorer-context-menu/cartesian-explorer-context-menu.component.test.ts @@ -63,7 +63,6 @@ describe('Cartesian context menu component', () => { navigateToExplorer: jest.fn() }), mockProvider(TimeRangeService, { - toQueryParams: jest.fn(), setFixedRange: jest.fn() }) ] @@ -117,26 +116,6 @@ describe('Cartesian context menu component', () => { spectator = createComponent(buildProviders(selectedData)); spectator.component.selectionData = selectedData; - spectator.component.menus = [ - { - name: 'Set Time Range', - icon: IconType.Alarm, - onClick: () => { - spectator - .inject(TimeRangeService) - .setFixedRange(selectedData.timeRange.startTime, selectedData.timeRange.endTime); - } - }, - { - name: 'Explore', - icon: IconType.ArrowUpRight, - onClick: () => { - spectator - .inject(CartesainExplorerNavigationService) - .navigateToExplorer(selectedData.timeRange.startTime, selectedData.timeRange.endTime); - } - } - ]; const buttons = spectator.queryAll(ButtonComponent); expect(buttons.length).toBe(2); From 3a1b067d6463dae7aeabaab49d644259d4e77a8e Mon Sep 17 00:00:00 2001 From: Jyothish Jose Date: Thu, 20 Jan 2022 10:35:01 +0530 Subject: [PATCH 49/49] feat: updated imports and test cases --- .../shared/components/cartesian/d3/chart/cartesian-chart.ts | 2 +- .../cartesian-widget-renderer.component.test.ts | 2 +- .../cartesian-widget/cartesian-widget-renderer.component.ts | 2 +- .../cartesian-explorer-context-menu.component.test.ts | 3 ++- .../cartesian-explorer-selection-handler.model.test.ts | 3 ++- .../interactions/cartesian-explorer-selection-handler.model.ts | 2 +- 6 files changed, 8 insertions(+), 6 deletions(-) diff --git a/projects/observability/src/shared/components/cartesian/d3/chart/cartesian-chart.ts b/projects/observability/src/shared/components/cartesian/d3/chart/cartesian-chart.ts index 515cf260f..a6188143b 100644 --- a/projects/observability/src/shared/components/cartesian/d3/chart/cartesian-chart.ts +++ b/projects/observability/src/shared/components/cartesian/d3/chart/cartesian-chart.ts @@ -2,7 +2,7 @@ import { Injector, Renderer2 } from '@angular/core'; import { TimeRange, TimeRangeService } from '@hypertrace/common'; import { BrushBehavior, brushX, D3BrushEvent } from 'd3-brush'; -// tslint:disable +// tslint:disable-next-line: no-restricted-globals import { ContainerElement, event as d3CurrentEvent, mouse, select } from 'd3-selection'; import { Subscription } from 'rxjs'; import { LegendPosition } from '../../../legend/legend.component'; diff --git a/projects/observability/src/shared/dashboard/widgets/charts/cartesian-widget/cartesian-widget-renderer.component.test.ts b/projects/observability/src/shared/dashboard/widgets/charts/cartesian-widget/cartesian-widget-renderer.component.test.ts index 9e132ee05..018fdb566 100644 --- a/projects/observability/src/shared/dashboard/widgets/charts/cartesian-widget/cartesian-widget-renderer.component.test.ts +++ b/projects/observability/src/shared/dashboard/widgets/charts/cartesian-widget/cartesian-widget-renderer.component.test.ts @@ -16,8 +16,8 @@ import { ModelApi } from '@hypertrace/hyperdash'; import { runFakeRxjs } from '@hypertrace/test-utils'; import { createComponentFactory, mockProvider } from '@ngneat/spectator/jest'; import { of } from 'rxjs'; -import { CartesianSelectedData } from '../../../../../public-api'; import { CartesianSeriesVisualizationType } from '../../../../components/cartesian/chart'; +import { CartesianSelectedData } from '../../../../components/cartesian/chart-interactivty'; import { CartesianWidgetRendererComponent } from './cartesian-widget-renderer.component'; import { CartesianWidgetModel } from './cartesian-widget.model'; import { MetricSeriesDataFetcher, SeriesModel } from './series.model'; diff --git a/projects/observability/src/shared/dashboard/widgets/charts/cartesian-widget/cartesian-widget-renderer.component.ts b/projects/observability/src/shared/dashboard/widgets/charts/cartesian-widget/cartesian-widget-renderer.component.ts index f1dbf523f..d1f04f134 100644 --- a/projects/observability/src/shared/dashboard/widgets/charts/cartesian-widget/cartesian-widget-renderer.component.ts +++ b/projects/observability/src/shared/dashboard/widgets/charts/cartesian-widget/cartesian-widget-renderer.component.ts @@ -6,8 +6,8 @@ import { Renderer } from '@hypertrace/hyperdash'; import { RendererApi, RENDERER_API } from '@hypertrace/hyperdash-angular'; import { NEVER, Observable } from 'rxjs'; import { switchMap, tap } from 'rxjs/operators'; -import { CartesianSelectedData } from '../../../../../public-api'; import { Axis, Band, Series } from '../../../../components/cartesian/chart'; +import { CartesianSelectedData } from '../../../../components/cartesian/chart-interactivty'; import { IntervalValue } from '../../../../components/interval-select/interval-select.component'; import { CartesianAxisModel } from './axis/cartesian-axis.model'; import { CartesianDataFetcher, CartesianResult, CartesianWidgetModel } from './cartesian-widget.model'; diff --git a/projects/observability/src/shared/dashboard/widgets/charts/cartesian-widget/interactions/cartesian-explorer-context-menu/cartesian-explorer-context-menu.component.test.ts b/projects/observability/src/shared/dashboard/widgets/charts/cartesian-widget/interactions/cartesian-explorer-context-menu/cartesian-explorer-context-menu.component.test.ts index 10acfce5e..70d15677c 100644 --- a/projects/observability/src/shared/dashboard/widgets/charts/cartesian-widget/interactions/cartesian-explorer-context-menu/cartesian-explorer-context-menu.component.test.ts +++ b/projects/observability/src/shared/dashboard/widgets/charts/cartesian-widget/interactions/cartesian-explorer-context-menu/cartesian-explorer-context-menu.component.test.ts @@ -2,9 +2,10 @@ import { StaticProvider } from '@angular/core'; import { IconType } from '@hypertrace/assets-library'; import { TimeRangeService } from '@hypertrace/common'; import { ButtonComponent, DividerComponent, POPOVER_DATA } from '@hypertrace/components'; -import { CartesianSelectedData, CartesianSeriesVisualizationType } from '@hypertrace/observability'; import { createComponentFactory, mockProvider, Spectator } from '@ngneat/spectator/jest'; import { MockComponent } from 'ng-mocks'; +import { CartesianSeriesVisualizationType } from '../../../../../../components/cartesian/chart'; +import { CartesianSelectedData } from '../../../../../../components/cartesian/chart-interactivty'; import { CartesainExplorerNavigationService } from '../cartesian-explorer-navigation.service'; import { CartesianExplorerContextMenuComponent } from './cartesian-explorer-context-menu.component'; diff --git a/projects/observability/src/shared/dashboard/widgets/charts/cartesian-widget/interactions/cartesian-explorer-selection-handler.model.test.ts b/projects/observability/src/shared/dashboard/widgets/charts/cartesian-widget/interactions/cartesian-explorer-selection-handler.model.test.ts index cc47dab56..caecb2dc2 100644 --- a/projects/observability/src/shared/dashboard/widgets/charts/cartesian-widget/interactions/cartesian-explorer-selection-handler.model.test.ts +++ b/projects/observability/src/shared/dashboard/widgets/charts/cartesian-widget/interactions/cartesian-explorer-selection-handler.model.test.ts @@ -1,8 +1,9 @@ import { TimeRangeService } from '@hypertrace/common'; import { PopoverService } from '@hypertrace/components'; import { createModelFactory } from '@hypertrace/dashboards/testing'; -import { CartesianSelectedData, CartesianSeriesVisualizationType } from '@hypertrace/observability'; import { mockProvider } from '@ngneat/spectator/jest'; +import { CartesianSeriesVisualizationType } from '../../../../../components/cartesian/chart'; +import { CartesianSelectedData } from '../../../../../components/cartesian/chart-interactivty'; import { CartesainExplorerNavigationService } from './cartesian-explorer-navigation.service'; import { CartesianExplorerSelectionHandlerModel } from './cartesian-explorer-selection-handler.model'; diff --git a/projects/observability/src/shared/dashboard/widgets/charts/cartesian-widget/interactions/cartesian-explorer-selection-handler.model.ts b/projects/observability/src/shared/dashboard/widgets/charts/cartesian-widget/interactions/cartesian-explorer-selection-handler.model.ts index 914838253..7689f8f67 100644 --- a/projects/observability/src/shared/dashboard/widgets/charts/cartesian-widget/interactions/cartesian-explorer-selection-handler.model.ts +++ b/projects/observability/src/shared/dashboard/widgets/charts/cartesian-widget/interactions/cartesian-explorer-selection-handler.model.ts @@ -7,8 +7,8 @@ import { } from '@hypertrace/components'; import { BOOLEAN_PROPERTY, Model, ModelProperty } from '@hypertrace/hyperdash'; import { ModelInject } from '@hypertrace/hyperdash-angular'; -import { CartesianSelectedData } from '@hypertrace/observability'; import { Observable, of } from 'rxjs'; +import { CartesianSelectedData } from '../../../../../components/cartesian/chart-interactivty'; import { InteractionHandler } from '../../../../interaction/interaction-handler'; import { CartesianExplorerContextMenuComponent } from './cartesian-explorer-context-menu/cartesian-explorer-context-menu.component';