From b32791dee63e3e0467e8d76fd49889263da0aea8 Mon Sep 17 00:00:00 2001 From: Joey Tawadrous Date: Fri, 17 Jan 2025 11:21:21 +0000 Subject: [PATCH 1/3] Add back and forward support for app actions --- src/components/Explore/GroupBySelector.tsx | 7 ++++++- src/components/Explore/panels/histogram.ts | 2 ++ src/pages/Explore/TraceExploration.tsx | 5 +++++ 3 files changed, 13 insertions(+), 1 deletion(-) diff --git a/src/components/Explore/GroupBySelector.tsx b/src/components/Explore/GroupBySelector.tsx index fea09ab..bc5a61c 100644 --- a/src/components/Explore/GroupBySelector.tsx +++ b/src/components/Explore/GroupBySelector.tsx @@ -8,6 +8,7 @@ import { ALL, ignoredAttributes, maxOptions, MetricFunction, RESOURCE_ATTR, SPAN import { AttributesBreakdownScene } from './TracesByService/Tabs/Breakdown/AttributesBreakdownScene'; import { AttributesComparisonScene } from './TracesByService/Tabs/Comparison/AttributesComparisonScene'; import { getFiltersVariable, getMetricVariable } from 'utils/utils'; +import { locationService } from '@grafana/runtime'; type Props = { options: Array>; @@ -122,7 +123,11 @@ export function GroupBySelector({ options, radioAttributes, value, onChange, sho value={value && getModifiedSelectOptions(otherAttrOptions).some((x) => x.value === value) ? value : null} // remove value from select when radio button clicked placeholder={'Other attributes'} options={getModifiedSelectOptions(otherAttrOptions)} - onChange={(selected) => onChange(selected?.value ?? defaultOnChangeValue)} + onChange={(selected) => { + const newSelected = selected?.value ?? defaultOnChangeValue; + locationService.partial({ 'var-groupBy': newSelected }); + onChange(newSelected); + }} className={styles.select} isClearable onInputChange={(value: string, { action }: InputActionMeta) => { diff --git a/src/components/Explore/panels/histogram.ts b/src/components/Explore/panels/histogram.ts index e62773e..848ac3e 100644 --- a/src/components/Explore/panels/histogram.ts +++ b/src/components/Explore/panels/histogram.ts @@ -2,6 +2,7 @@ import { getTraceByServiceScene, shouldShowSelection } from '../../../utils/util import { ComparisonSelection } from '../../../utils/shared'; import { reportAppInteraction, USER_EVENTS_ACTIONS, USER_EVENTS_PAGES } from '../../../utils/analytics'; import { PanelBuilders, SceneFlexItem, SceneFlexLayout, SceneObject } from '@grafana/scenes'; +import { locationService } from '@grafana/runtime'; export function getHistogramVizPanel(scene: SceneObject, yBuckets: number[]) { const parent = getTraceByServiceScene(scene); @@ -22,6 +23,7 @@ export function getHistogramVizPanel(scene: SceneObject, yBuckets: number[]) { const rawSelection = args[0]; // @ts-ignore const newSelection: ComparisonSelection = { type: 'manual', raw: rawSelection }; + locationService.partial({ 'selection': newSelection }); newSelection.timeRange = { from: Math.round((rawSelection.x?.from || 0) / 1000), diff --git a/src/pages/Explore/TraceExploration.tsx b/src/pages/Explore/TraceExploration.tsx index 91b51a3..71e556d 100644 --- a/src/pages/Explore/TraceExploration.tsx +++ b/src/pages/Explore/TraceExploration.tsx @@ -23,6 +23,7 @@ import { import { LocationService, config, + locationService, // @ts-ignore sidecarServiceSingleton_EXPERIMENTAL, } from '@grafana/runtime'; @@ -189,6 +190,8 @@ export class TraceExploration extends SceneObjectBase { if (!signal || this.state.primarySignal === signal) { return; } + + locationService.partial({ 'primarySignal': signal }); this.setState({ primarySignal: signal }); }; @@ -197,6 +200,8 @@ export class TraceExploration extends SceneObjectBase { if (!metric || variable.getValue() === metric) { return; } + + locationService.partial({ 'var-metric': metric }); variable.changeValueTo(metric); }; From ed8ecf97cf8278f3aaf1b94d5004c9c858df9b4a Mon Sep 17 00:00:00 2001 From: Joey Tawadrous Date: Fri, 31 Jan 2025 09:32:30 +0000 Subject: [PATCH 2/3] Use url sync --- src/components/Explore/GroupBySelector.tsx | 1 - .../TracesByService/TracesByServiceScene.tsx | 4 +++- src/components/Explore/panels/histogram.ts | 6 +++--- src/pages/Explore/TraceExploration.tsx | 13 +++++++------ src/pages/Explore/TraceExplorationPage.tsx | 2 +- src/utils/utils.ts | 10 ++++++++++ 6 files changed, 24 insertions(+), 12 deletions(-) diff --git a/src/components/Explore/GroupBySelector.tsx b/src/components/Explore/GroupBySelector.tsx index bc5a61c..0a89e6c 100644 --- a/src/components/Explore/GroupBySelector.tsx +++ b/src/components/Explore/GroupBySelector.tsx @@ -125,7 +125,6 @@ export function GroupBySelector({ options, radioAttributes, value, onChange, sho options={getModifiedSelectOptions(otherAttrOptions)} onChange={(selected) => { const newSelected = selected?.value ?? defaultOnChangeValue; - locationService.partial({ 'var-groupBy': newSelected }); onChange(newSelected); }} className={styles.select} diff --git a/src/components/Explore/TracesByService/TracesByServiceScene.tsx b/src/components/Explore/TracesByService/TracesByServiceScene.tsx index c8f6654..7c66e6d 100644 --- a/src/components/Explore/TracesByService/TracesByServiceScene.tsx +++ b/src/components/Explore/TracesByService/TracesByServiceScene.tsx @@ -57,7 +57,7 @@ export interface TraceSceneState extends SceneObjectState { } export class TracesByServiceScene extends SceneObjectBase { - protected _urlSync = new SceneObjectUrlSyncConfig(this, { keys: ['actionView', 'selection'] }); + public _urlSync = new SceneObjectUrlSyncConfig(this, { keys: ['actionView', 'selection', 'metric'] }); public constructor(state: MakeOptional) { super({ @@ -76,6 +76,7 @@ export class TracesByServiceScene extends SceneObjectBase { this._subs.add( metricVariable.subscribeToState((newState, prevState) => { if (newState.value !== prevState.value) { + this.setState({ metric: newState.value as MetricFunction }); const selection = getDefaultSelectionForMetric(newState.value as MetricFunction); if (selection) { this.setState({ selection }); @@ -155,6 +156,7 @@ export class TracesByServiceScene extends SceneObjectBase { getUrlState() { return { actionView: this.state.actionView, + metric: this.state.metric, selection: this.state.selection ? JSON.stringify(this.state.selection) : undefined, }; } diff --git a/src/components/Explore/panels/histogram.ts b/src/components/Explore/panels/histogram.ts index 848ac3e..763c0b6 100644 --- a/src/components/Explore/panels/histogram.ts +++ b/src/components/Explore/panels/histogram.ts @@ -2,7 +2,6 @@ import { getTraceByServiceScene, shouldShowSelection } from '../../../utils/util import { ComparisonSelection } from '../../../utils/shared'; import { reportAppInteraction, USER_EVENTS_ACTIONS, USER_EVENTS_PAGES } from '../../../utils/analytics'; import { PanelBuilders, SceneFlexItem, SceneFlexLayout, SceneObject } from '@grafana/scenes'; -import { locationService } from '@grafana/runtime'; export function getHistogramVizPanel(scene: SceneObject, yBuckets: number[]) { const parent = getTraceByServiceScene(scene); @@ -23,7 +22,6 @@ export function getHistogramVizPanel(scene: SceneObject, yBuckets: number[]) { const rawSelection = args[0]; // @ts-ignore const newSelection: ComparisonSelection = { type: 'manual', raw: rawSelection }; - locationService.partial({ 'selection': newSelection }); newSelection.timeRange = { from: Math.round((rawSelection.x?.from || 0) / 1000), @@ -39,7 +37,9 @@ export function getHistogramVizPanel(scene: SceneObject, yBuckets: number[]) { const yTo = yBucketToDuration(args[0].y?.to || 0, yBuckets); newSelection.duration = { from: yFrom, to: yTo }; - parent.setState({ selection: newSelection }); + parent._urlSync.performBrowserHistoryAction(() => { + parent.setState({ selection: newSelection }); + }); if (!shouldShowSelection(parent.state.actionView)) { parent.setActionView('comparison'); } diff --git a/src/pages/Explore/TraceExploration.tsx b/src/pages/Explore/TraceExploration.tsx index 71e556d..af2e63f 100644 --- a/src/pages/Explore/TraceExploration.tsx +++ b/src/pages/Explore/TraceExploration.tsx @@ -23,7 +23,6 @@ import { import { LocationService, config, - locationService, // @ts-ignore sidecarServiceSingleton_EXPERIMENTAL, } from '@grafana/runtime'; @@ -40,7 +39,7 @@ import { VAR_LATENCY_THRESHOLD, VAR_METRIC, } from '../../utils/shared'; -import { getTraceExplorationScene, getFilterSignature, getFiltersVariable } from '../../utils/utils'; +import { getTraceExplorationScene, getFilterSignature, getFiltersVariable, getTraceByServiceSceneAsDescendent } from '../../utils/utils'; import { DetailsScene } from '../../components/Explore/TracesByService/DetailsScene'; import { FilterByVariable } from 'components/Explore/filters/FilterByVariable'; import { getSignalForKey, primarySignalOptions } from './primary-signals'; @@ -191,8 +190,9 @@ export class TraceExploration extends SceneObjectBase { return; } - locationService.partial({ 'primarySignal': signal }); - this.setState({ primarySignal: signal }); + this._urlSync.performBrowserHistoryAction(() => { + this.setState({ primarySignal: signal }); + }); }; public onChangeMetricFunction = (metric: string) => { @@ -201,8 +201,9 @@ export class TraceExploration extends SceneObjectBase { return; } - locationService.partial({ 'var-metric': metric }); - variable.changeValueTo(metric); + getTraceByServiceSceneAsDescendent(this)._urlSync.performBrowserHistoryAction(() => { + variable.changeValueTo(metric); + }); }; public getMetricFunction() { diff --git a/src/pages/Explore/TraceExplorationPage.tsx b/src/pages/Explore/TraceExplorationPage.tsx index 46b0e81..3619ddc 100644 --- a/src/pages/Explore/TraceExplorationPage.tsx +++ b/src/pages/Explore/TraceExplorationPage.tsx @@ -44,7 +44,7 @@ export function TraceExplorationView({ exploration }: { exploration: TraceExplor } return ( - + ); diff --git a/src/utils/utils.ts b/src/utils/utils.ts index 17105b6..43d0a0c 100644 --- a/src/utils/utils.ts +++ b/src/utils/utils.ts @@ -40,6 +40,16 @@ export function getTraceByServiceScene(model: SceneObject): TracesByServiceScene return sceneGraph.getAncestor(model, TracesByServiceScene); } +export function getTraceByServiceSceneAsDescendent(model: SceneObject): TracesByServiceScene { + const scenes = sceneGraph.findDescendents(model, TracesByServiceScene); + + if (!scenes || scenes.length < 1 || !(scenes[0] instanceof TracesByServiceScene)) { + throw new Error('TracesByServiceScene not found'); + } + + return scenes[0]; +} + export function newTracesExploration( locationService: LocationService, initialDS?: string, From dd0b17caa2e5010a02859a2a79f1955df59b908f Mon Sep 17 00:00:00 2001 From: Joey Tawadrous Date: Fri, 31 Jan 2025 09:35:22 +0000 Subject: [PATCH 3/3] Remove import --- src/components/Explore/GroupBySelector.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/src/components/Explore/GroupBySelector.tsx b/src/components/Explore/GroupBySelector.tsx index 0a89e6c..de8a46a 100644 --- a/src/components/Explore/GroupBySelector.tsx +++ b/src/components/Explore/GroupBySelector.tsx @@ -8,7 +8,6 @@ import { ALL, ignoredAttributes, maxOptions, MetricFunction, RESOURCE_ATTR, SPAN import { AttributesBreakdownScene } from './TracesByService/Tabs/Breakdown/AttributesBreakdownScene'; import { AttributesComparisonScene } from './TracesByService/Tabs/Comparison/AttributesComparisonScene'; import { getFiltersVariable, getMetricVariable } from 'utils/utils'; -import { locationService } from '@grafana/runtime'; type Props = { options: Array>;