Flame Graph: Anchor exact match when clicking a table symbol in search (#111101)

* fixed #110680

* Edit

* Fixed test

---------

Co-authored-by: Samarth Bagga <samarth.bagga@meesho.com>
This commit is contained in:
Samarth Bagga
2025-10-27 14:03:19 +01:00
committed by GitHub
co-authored by Samarth Bagga
parent 7b2ea9a735
commit f9fb2cfd50
3 changed files with 17 additions and 8 deletions
@@ -55,15 +55,15 @@ describe('FlameGraphContainer', () => {
it('should update search when row selected in top table', async () => {
render(<FlameGraphContainerWithProps />);
await userEvent.click((await screen.findAllByTitle('Highlight symbol'))[0]);
expect(screen.getByDisplayValue('net/http.HandlerFunc.ServeHTTP')).toBeInTheDocument();
expect(screen.getByDisplayValue('^net/http\\.HandlerFunc\\.ServeHTTP$')).toBeInTheDocument();
// Unclick the selection so that we can click something else and continue test checks
await userEvent.click((await screen.findAllByTitle('Highlight symbol'))[0]);
await userEvent.click((await screen.findAllByTitle('Highlight symbol'))[1]);
expect(screen.getByDisplayValue('total')).toBeInTheDocument();
expect(screen.getByDisplayValue('^total$')).toBeInTheDocument();
// after it is highlighted it will be the only (first) item in the table so [1] -> [0]
await userEvent.click((await screen.findAllByTitle('Highlight symbol'))[0]);
expect(screen.queryByDisplayValue('total')).not.toBeInTheDocument();
expect(screen.queryByDisplayValue('^total$')).not.toBeInTheDocument();
});
it('should render options', async () => {
@@ -4,7 +4,7 @@ import { useCallback, useEffect, useMemo, useState } from 'react';
import * as React from 'react';
import { useMeasure } from 'react-use';
import { DataFrame, GrafanaTheme2 } from '@grafana/data';
import { DataFrame, GrafanaTheme2, escapeStringForRegex } from '@grafana/data';
import { ThemeContext } from '@grafana/ui';
import FlameGraph from './FlameGraph/FlameGraph';
@@ -189,11 +189,13 @@ const FlameGraphContainer = ({
const onSymbolClick = useCallback(
(symbol: string) => {
if (search === symbol) {
const anchored = `^${escapeStringForRegex(symbol)}$`;
if (search === anchored) {
setSearch('');
} else {
onTableSymbolClick?.(symbol);
setSearch(symbol);
setSearch(anchored);
resetFocus();
}
},
@@ -241,7 +243,13 @@ const FlameGraphContainer = ({
matchedLabels={matchedLabels}
sandwichItem={sandwichItem}
onSandwich={setSandwichItem}
onSearch={setSearch}
onSearch={(str) => {
if (!str) {
setSearch('');
return;
}
setSearch(`^${escapeStringForRegex(str)}$`);
}}
onTableSort={onTableSort}
colorScheme={colorScheme}
/>
@@ -10,6 +10,7 @@ import {
FieldType,
GrafanaTheme2,
MappingType,
escapeStringForRegex,
} from '@grafana/data';
import {
IconButton,
@@ -332,7 +333,7 @@ type ActionCellProps = {
function ActionCell(props: ActionCellProps) {
const styles = getStylesActionCell();
const symbol = props.frame.fields.find((f: Field) => f.name === 'Symbol')?.values[props.rowIndex];
const isSearched = props.search === symbol;
const isSearched = props.search === `^${escapeStringForRegex(String(symbol))}$`;
const isSandwiched = props.sandwichItem === symbol;
return (