Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor: more flexibility with explorer #2548

Merged
merged 13 commits into from
Dec 7, 2023
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import { Model } from '@hypertrace/hyperdash';
import { IntervalValue } from '@hypertrace/observability';

@Model({
type: 'auto-time-duration',
})
export class AutoTimeDurationModel {
public getDuration(): IntervalValue {
return 'AUTO';
}
}
1 change: 1 addition & 0 deletions projects/dashboards/src/public-api.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
// Models
export * from './model/time-duration/time-duration.model';
export * from './model/time-duration/auto-time-duration.model';

// Types
export * from './properties/arrays/array-property-type';
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/* eslint-disable max-lines */
import { Injectable, InjectionToken } from '@angular/core';
import { isEqualIgnoreFunctions } from '@hypertrace/common';
import { TimeDuration, isEqualIgnoreFunctions } from '@hypertrace/common';
import {
CoreTableCellRendererType,
FilterBuilderLookupService,
Expand Down Expand Up @@ -67,6 +67,7 @@ export class ExplorerDashboardBuilder {
'selectable-interval': false,
'series-from-data': true,
'legend-position': LegendPosition.Bottom,
'default-interval': this.buildDefaultIntervalModel(request),
'selection-handler': {
type: 'cartesian-explorer-selection-handler',
'show-context-menu': false,
Expand All @@ -81,6 +82,22 @@ export class ExplorerDashboardBuilder {
});
}

private buildDefaultIntervalModel(request: ExploreVisualizationRequest): ModelJson | undefined {
if (request.interval instanceof TimeDuration) {
return {
type: 'time-duration',
value: request.interval.value,
unit: request.interval.unit,
};
} else if (request.interval === 'AUTO') {
return {
type: 'auto-time-duration',
};
}

return undefined;
}

public buildResultsDashboard(dashboardData: ResultsDashboardData): ExplorerGeneratedDashboard {
return {
json: dashboardData.json,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -166,9 +166,9 @@
gap: 12px;

.legend-entries {
flex-direction: row;
display: flex;
gap: 20px;
flex-flow: row wrap;
justify-content: flex-start;
border: 1px solid $gray-2;
border-radius: 8px;
padding: 8px 20px;
Expand Down Expand Up @@ -214,5 +214,9 @@
.interval-control {
padding: 0 8px;
}

ht-cartesian-interval-control {
align-self: flex-end;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -187,15 +187,13 @@ describe('Cartesian Chart component', () => {
name: 'first',
color: 'blue',
type: CartesianSeriesVisualizationType.Column,
groupName: 'test series',
stacking: true,
},
{
data: [[1, 6]],
name: 'second',
color: 'red',
type: CartesianSeriesVisualizationType.Column,
groupName: 'test series',
stacking: true,
},
],
Expand All @@ -207,11 +205,24 @@ describe('Cartesian Chart component', () => {
expect(chart.query('.reset.hidden')).toExist();

const legendEntriesTitleElement = chart.query('.legend-entries-title') as Element;
chart.click(legendEntriesTitleElement);
expect(legendEntriesTitleElement).not.toExist();

const legendText = chart.queryAll('.legend-text');
expect(legendText.length).toEqual(2);

chart.click(legendText[0]);
tick();
expect(chart.queryAll('.legend-text.active').length).toBe(1);

chart.click(legendText[1]);
tick();
expect(chart.queryAll('.legend-text.active').length).toBe(2);

chart.click(legendEntriesTitleElement);
chart.click(legendText[0]);
tick();
expect(chart.queryAll('.legend-text.active').length).toBe(1);

chart.click(legendText[1]);
tick();
expect(chart.queryAll('.legend-text.active').length).toBe(0);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
} from '@angular/core';
import { DateCoercer, DateFormatter, SubscriptionLifecycle, TimeRange } from '@hypertrace/common';

import { defaults } from 'lodash-es';
import { defaults, groupBy } from 'lodash-es';
import { IntervalValue } from '../interval-select/interval-select.component';
import { LegendPosition } from '../legend/legend.component';
import { ChartTooltipBuilderService } from '../utils/chart-tooltip/chart-tooltip-builder.service';
Expand Down Expand Up @@ -62,6 +62,9 @@
@Input()
public rangeSelectionEnabled: boolean = false;

@Input()
public selectableInterval?: boolean;

@Input()
public intervalOptions?: IntervalValue[];

Expand Down Expand Up @@ -160,10 +163,11 @@
this.chart.withLegend(this.legend);
}

if (this.intervalOptions !== undefined && this.selectedInterval !== undefined) {
if (this.selectedInterval !== undefined) {
this.chart.withIntervalData({
selectableInterval: this.selectableInterval ?? false,
initial: this.selectedInterval,
options: this.intervalOptions,
options: this.intervalOptions ?? [this.selectedInterval],
changeObserver: this.selectedIntervalChange,
});
}
Expand Down Expand Up @@ -204,20 +208,27 @@
}

private convertToDefaultTooltipRenderData(
data: MouseLocationData<TData, Series<TData>>[],
locationData: MouseLocationData<TData, Series<TData>>[],

Check warning on line 211 in projects/observability/src/shared/components/cartesian/cartesian-chart.component.ts

View check run for this annotation

Codecov / codecov/patch

projects/observability/src/shared/components/cartesian/cartesian-chart.component.ts#L211

Added line #L211 was not covered by tests
): DefaultChartTooltipRenderData | undefined {
if (data.length === 0) {
if (locationData.length === 0) {
return undefined;
}

return {
title: this.resolveTooltipTitle(data[0]),
labeledValues: data.map(singleValue => ({
const tooltipGroups = Object.entries(

Check warning on line 217 in projects/observability/src/shared/components/cartesian/cartesian-chart.component.ts

View check run for this annotation

Codecov / codecov/patch

projects/observability/src/shared/components/cartesian/cartesian-chart.component.ts#L217

Added line #L217 was not covered by tests
groupBy(locationData, datum => datum.context.groupName ?? datum.context.name),
).map(([title, groupedData]) => ({

Check warning on line 219 in projects/observability/src/shared/components/cartesian/cartesian-chart.component.ts

View check run for this annotation

Codecov / codecov/patch

projects/observability/src/shared/components/cartesian/cartesian-chart.component.ts#L219

Added line #L219 was not covered by tests
title: title,
labeledValues: groupedData.map(singleValue => ({

Check warning on line 221 in projects/observability/src/shared/components/cartesian/cartesian-chart.component.ts

View check run for this annotation

Codecov / codecov/patch

projects/observability/src/shared/components/cartesian/cartesian-chart.component.ts#L221

Added line #L221 was not covered by tests
label: singleValue.context.name,
value: defaultYDataAccessor<number | string>(singleValue.dataPoint),
units: singleValue.context.units,
color: singleValue.context.getColor?.(singleValue.dataPoint) ?? singleValue.context.color,
})),
}));

return {

Check warning on line 229 in projects/observability/src/shared/components/cartesian/cartesian-chart.component.ts

View check run for this annotation

Codecov / codecov/patch

projects/observability/src/shared/components/cartesian/cartesian-chart.component.ts#L229

Added line #L229 was not covered by tests
title: this.resolveTooltipTitle(locationData[0]),
groups: tooltipGroups,
};
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -86,11 +86,11 @@ export class CartesianAxis<TData = {}> {
if (this.configuration.location === AxisLocation.Bottom || this.configuration.location === AxisLocation.Top) {
const maxTextTickTextLength = this.getMaxTickTextLength(selection);

if (this.configuration.labelOverflow === LabelOverflow.Wrap) {
this.tickTextWrap(selection, maxTextTickTextLength);
} else {
if (this.configuration.labelOverflow === LabelOverflow.Rotate) {
const isLabelRotated = this.rotateAxisTicks(selection, maxTextTickTextLength);
this.removeOverflowedTicks(selection, maxTextTickTextLength, isLabelRotated);
} else {
this.tickTextWrap(selection, maxTextTickTextLength);
}
} else {
this.maybeTruncateAxisTicks(selection);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -446,6 +446,7 @@
this.legend = new CartesianLegend<TData>(
this.activeSeries,
this.injector,
this.scaleBuilder.getDataAccessorForDomain(AxisType.X),
this.intervalData,
this.seriesSummaries,
).draw(this.chartContainerElement, this.legendPosition);
Expand All @@ -456,10 +457,13 @@
});
} else {
// The legend also contains the interval selector, so even without a legend we need to create an element for that
this.legend = new CartesianLegend<TData>([], this.injector, this.intervalData, this.seriesSummaries).draw(
this.chartContainerElement,
LegendPosition.None,
);
this.legend = new CartesianLegend<TData>(

Check warning on line 460 in projects/observability/src/shared/components/cartesian/d3/chart/cartesian-chart.ts

View check run for this annotation

Codecov / codecov/patch

projects/observability/src/shared/components/cartesian/d3/chart/cartesian-chart.ts#L460

Added line #L460 was not covered by tests
[],
this.injector,
this.scaleBuilder.getDataAccessorForDomain(AxisType.X),
this.intervalData,
this.seriesSummaries,
).draw(this.chartContainerElement, LegendPosition.None);
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ export class CartesianIntervalControlComponent {
}

export interface CartesianIntervalData {
selectableInterval: boolean;
options: IntervalValue[];
initial: IntervalValue;
changeObserver: Observer<IntervalValue>;
Expand Down
Loading