Skip to content

Commit

Permalink
Refactor and added all attributes view to homepage
Browse files Browse the repository at this point in the history
  • Loading branch information
adrapereira committed Apr 25, 2024
1 parent 8e9e557 commit 0b1a488
Show file tree
Hide file tree
Showing 7 changed files with 327 additions and 280 deletions.
2 changes: 1 addition & 1 deletion src/components/Explore/ByFrameRepeater.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ export class ByFrameRepeater extends SceneObjectBase<ByFrameRepeaterState> {
let frames = data.series;

if (this.state.groupBy) {
frames = groupSeriesBy(data, this.getGroupByVariable().state.query);
frames = groupSeriesBy(data, this.getGroupByVariable().getValueText());
}

for (let frameIndex = 0; frameIndex < frames.length; frameIndex++) {
Expand Down
167 changes: 10 additions & 157 deletions src/components/Explore/TracesByService/Tabs/AttributesBreakdown.tsx
Original file line number Diff line number Diff line change
@@ -1,43 +1,34 @@
import { css } from '@emotion/css';
import React from 'react';

import { DataFrame, GrafanaTheme2, PanelData } from '@grafana/data';
import { DataFrame, GrafanaTheme2 } from '@grafana/data';
import {
CustomVariable,
PanelBuilders,
PanelOptionsBuilders,
SceneComponentProps,
SceneCSSGridItem,
SceneCSSGridLayout,
SceneDataNode,
SceneFlexItem,
SceneFlexItemLike,
SceneFlexLayout,
sceneGraph,
SceneObject,
SceneObjectBase,
SceneObjectState,
SceneQueryRunner,
SceneVariableSet,
VariableDependencyConfig,
} from '@grafana/scenes';
import { Button, Field, TooltipDisplayMode, useStyles2 } from '@grafana/ui';
import { Button, Field, useStyles2 } from '@grafana/ui';

import { BreakdownLabelSelector } from '../../BreakdownLabelSelector';
import { explorationDS, VAR_ATTRIBUTE_GROUP_BY, VAR_FILTERS, VAR_FILTERS_EXPR } from '../../../../utils/shared';
import { VAR_ATTRIBUTE_GROUP_BY, VAR_FILTERS } from '../../../../utils/shared';

import { ByFrameRepeater } from '../../ByFrameRepeater';
import { LayoutSwitcher } from '../../LayoutSwitcher';
import { TracesByServiceScene } from '../TracesByServiceScene';
import { getColorByIndex, getLabelValue } from '../../../../utils/utils';
import { AddToFiltersGraphAction } from '../../AddToFiltersGraphAction';
import { VARIABLE_ALL_VALUE } from '../../../../constants';
import { buildAllLayout } from '../../layouts/allAttributes';
import { buildNormalLayout } from '../../layouts/attributeBreakdown';

export interface AttributesBreakdownSceneState extends SceneObjectState {
body?: SceneObject;
}

const MAX_PANELS_IN_ALL_ATTRIBUTES_BREAKDOWN = 100;
const ignoredAttributes = ['duration', 'traceDuration'];

export class AttributesBreakdown extends SceneObjectBase<AttributesBreakdownSceneState> {
Expand Down Expand Up @@ -97,8 +88,11 @@ export class AttributesBreakdown extends SceneObjectBase<AttributesBreakdownScen
this.setState({
body:
variable.hasAllValue() || variable.getValue() === VARIABLE_ALL_VALUE
? buildAllLayout(this.getAttributes())
: buildNormalLayout(variable),
? buildAllLayout(this.getAttributes() ?? [], (attribute) => new SelectAttributeAction({ attribute }))
: buildNormalLayout(
variable,
(frame: DataFrame) => new AddToFiltersGraphAction({ frame, variableName: VAR_FILTERS })
),
});
}

Expand Down Expand Up @@ -182,147 +176,6 @@ function getStyles(theme: GrafanaTheme2) {
};
}

function getExpr(attr: string) {
return `{${VAR_FILTERS_EXPR}} | rate() by(${attr})`;
}

function buildQuery(tagKey: string) {
return {
refId: 'A',
query: getExpr(tagKey),
queryType: 'traceql',
tableType: 'spans',
limit: 100,
spss: 10,
filters: [],
};
}

const GRID_TEMPLATE_COLUMNS = 'repeat(auto-fit, minmax(400px, 1fr))';

function buildNormalLayout(variable: CustomVariable) {
const query = buildQuery(variable.getValueText());

return new LayoutSwitcher({
$data: new SceneQueryRunner({
datasource: explorationDS,
maxDataPoints: 300,
queries: [query],
}),
options: [
{ value: 'single', label: 'Single' },
{ value: 'grid', label: 'Grid' },
{ value: 'rows', label: 'Rows' },
],
active: 'grid',
layouts: [
new SceneFlexLayout({
direction: 'column',
children: [
new SceneFlexItem({
minHeight: 300,
body: PanelBuilders.timeseries().build(),
}),
],
}),
new ByFrameRepeater({
body: new SceneCSSGridLayout({
templateColumns: GRID_TEMPLATE_COLUMNS,
autoRows: '200px',
children: [],
}),
getLayoutChild: getLayoutChild(getLabelValue),
}),
new ByFrameRepeater({
body: new SceneCSSGridLayout({
templateColumns: '1fr',
autoRows: '200px',
children: [],
}),
getLayoutChild: getLayoutChild(getLabelValue),
}),
],
});
}

function buildAllLayout(attributes?: string[]) {
const children: SceneFlexItemLike[] = [];

if (!attributes) {
return new SceneFlexLayout({ children });
}

for (const attribute of attributes) {
if (children.length === MAX_PANELS_IN_ALL_ATTRIBUTES_BREAKDOWN) {
break;
}

const vizPanel = PanelBuilders.timeseries()
.setTitle(attribute)
.setData(
new SceneQueryRunner({
maxDataPoints: 250,
datasource: explorationDS,
queries: [buildQuery(attribute)],
})
)
.setHeaderActions(new SelectAttributeAction({ attribute: attribute }))
.build();

vizPanel.addActivationHandler(() => {
vizPanel.onOptionsChange(
PanelOptionsBuilders.timeseries()
.setOption('tooltip', { mode: TooltipDisplayMode.Multi })
.setOption('legend', { showLegend: false })
.build()
);
});

children.push(
new SceneCSSGridItem({
body: vizPanel,
})
);
}
return new LayoutSwitcher({
active: 'grid',
options: [
{ value: 'grid', label: 'Grid' },
{ value: 'rows', label: 'Rows' },
],
layouts: [
new SceneCSSGridLayout({
templateColumns: GRID_TEMPLATE_COLUMNS,
autoRows: '200px',
children: children,
isLazy: true,
}),
new SceneCSSGridLayout({
templateColumns: '1fr',
autoRows: '200px',
// Clone children since a scene object can only have one parent at a time
children: children.map((c) => c.clone()),
isLazy: true,
}),
],
});
}

export function getLayoutChild(getTitle: (df: DataFrame) => string) {
return (data: PanelData, frame: DataFrame, frameIndex: number) => {
const panel = PanelBuilders.timeseries() //
.setOption('legend', { showLegend: true })
.setCustomFieldConfig('fillOpacity', 9)
.setTitle(getTitle(frame))
.setData(new SceneDataNode({ data: { ...data, series: [frame] } }))
.setColor({ mode: 'fixed', fixedColor: getColorByIndex(frameIndex) })
.setHeaderActions(new AddToFiltersGraphAction({ frame, variableName: VAR_FILTERS }));
return new SceneCSSGridItem({
body: panel.build(),
});
};
}

interface SelectAttributeActionState extends SceneObjectState {
attribute: string;
}
Expand Down
83 changes: 83 additions & 0 deletions src/components/Explore/layouts/allAttributes.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
import {
PanelBuilders,
SceneCSSGridItem,
SceneCSSGridLayout,
SceneFlexItemLike,
SceneQueryRunner,
VizPanelState,
} from '@grafana/scenes';
import { explorationDS, VAR_FILTERS_EXPR } from '../../../utils/shared';
import { TooltipDisplayMode } from '@grafana/ui';
import { LayoutSwitcher } from '../LayoutSwitcher';

const MAX_PANELS_IN_ALL_ATTRIBUTES_BREAKDOWN = 100;
const GRID_TEMPLATE_COLUMNS = 'repeat(auto-fit, minmax(400px, 1fr))';

export function buildAllLayout(attributes: string[], actionsFn: (attribute: string) => VizPanelState['headerActions']) {
const children: SceneFlexItemLike[] = [];

for (const attribute of attributes) {
if (children.length === MAX_PANELS_IN_ALL_ATTRIBUTES_BREAKDOWN) {
break;
}

const vizPanel = PanelBuilders.timeseries()
.setTitle(attribute)
.setData(
new SceneQueryRunner({
maxDataPoints: 250,
datasource: explorationDS,
queries: [buildQuery(attribute)],
})
)
.setCustomFieldConfig('axisLabel', 'Errors')
.setHeaderActions(actionsFn(attribute))
.setOption('tooltip', { mode: TooltipDisplayMode.Multi })
.setOption('legend', { showLegend: false })
.build();

children.push(
new SceneCSSGridItem({
body: vizPanel,
})
);
}
return new LayoutSwitcher({
active: 'grid',
options: [
{ value: 'grid', label: 'Grid' },
{ value: 'rows', label: 'Rows' },
],
layouts: [
new SceneCSSGridLayout({
templateColumns: GRID_TEMPLATE_COLUMNS,
autoRows: '200px',
children: children,
isLazy: true,
}),
new SceneCSSGridLayout({
templateColumns: '1fr',
autoRows: '200px',
// Clone children since a scene object can only have one parent at a time
children: children.map((c) => c.clone()),
isLazy: true,
}),
],
});
}

function getExpr(attr: string) {
return `{${VAR_FILTERS_EXPR} && status = error} | rate() by(${attr})`;
}

function buildQuery(tagKey: string) {
return {
refId: 'A',
query: getExpr(tagKey),
queryType: 'traceql',
tableType: 'spans',
limit: 100,
spss: 10,
filters: [],
};
}
Loading

0 comments on commit 0b1a488

Please sign in to comment.