UNPKG

@grafana/flamegraph

Version:

Grafana flamegraph visualization component

1 lines • 22 kB
{"version":3,"file":"FlameGraphTopTableContainer.cjs","sources":["../../../src/TopTable/FlameGraphTopTableContainer.tsx"],"sourcesContent":["import { css } from '@emotion/css';\nimport { memo, useMemo, useState } from 'react';\nimport AutoSizer from 'react-virtualized-auto-sizer';\n\nimport {\n applyFieldOverrides,\n type DataFrame,\n type DataLinkClickEvent,\n type Field,\n FieldType,\n type GrafanaTheme2,\n MappingType,\n escapeStringForRegex,\n} from '@grafana/data';\nimport {\n IconButton,\n Table,\n TableCellDisplayMode,\n type TableCustomCellOptions,\n type TableFieldOptions,\n type TableSortByFieldState,\n useStyles2,\n useTheme2,\n} from '@grafana/ui';\n\nimport { diffColorBlindColors, diffDefaultColors } from '../FlameGraph/colors';\nimport { type FlameGraphDataContainer } from '../FlameGraph/dataTransform';\nimport { TOP_TABLE_COLUMN_WIDTH } from '../constants';\nimport { type ColorScheme, ColorSchemeDiff, type TableData } from '../types';\n\ntype Props = {\n data: FlameGraphDataContainer;\n onSymbolClick: (symbol: string) => void;\n // This is used for highlighting the search button in case there is exact match.\n search?: string;\n // We use these to filter out rows in the table if users is doing text search.\n matchedLabels?: Set<string>;\n sandwichItem?: string;\n onSearch: (str: string) => void;\n onSandwich: (str?: string) => void;\n onTableSort?: (sort: string) => void;\n colorScheme: ColorScheme | ColorSchemeDiff;\n};\n\nconst FlameGraphTopTableContainer = memo(\n ({\n data,\n onSymbolClick,\n search,\n matchedLabels,\n onSearch,\n sandwichItem,\n onSandwich,\n onTableSort,\n colorScheme,\n }: Props) => {\n const table = useMemo(() => buildFilteredTable(data, matchedLabels), [data, matchedLabels]);\n\n const styles = useStyles2(getStyles);\n const theme = useTheme2();\n\n const [sort, setSort] = useState<TableSortByFieldState[]>([{ displayName: 'Self', desc: true }]);\n\n return (\n <div className={styles.topTableContainer} data-testid=\"topTable\">\n <AutoSizer style={{ width: '100%' }}>\n {({ width, height }) => {\n if (width < 3 || height < 3) {\n return null;\n }\n\n const frame = buildTableDataFrame(\n data,\n table,\n width,\n onSymbolClick,\n onSearch,\n onSandwich,\n theme,\n colorScheme,\n search,\n sandwichItem\n );\n return (\n <Table\n initialSortBy={sort}\n onSortByChange={(s) => {\n if (s && s.length) {\n onTableSort?.(s[0].displayName + '_' + (s[0].desc ? 'desc' : 'asc'));\n }\n setSort(s);\n }}\n data={frame}\n width={width}\n height={height}\n />\n );\n }}\n </AutoSizer>\n </div>\n );\n }\n);\n\nFlameGraphTopTableContainer.displayName = 'FlameGraphTopTableContainer';\n\nfunction buildFilteredTable(data: FlameGraphDataContainer, matchedLabels?: Set<string>) {\n // Group the data by label, we show only one row per label and sum the values\n // TODO: should be by filename + funcName + linenumber?\n let filteredTable: { [key: string]: TableData } = Object.create(null);\n\n // Track call stack to detect recursive calls\n const callStack: string[] = [];\n\n for (let i = 0; i < data.data.length; i++) {\n const value = data.getValue(i);\n const valueRight = data.getValueRight(i);\n const self = data.getSelf(i);\n const label = data.getLabel(i);\n const level = data.getLevel(i);\n\n // Maintain call stack based on level changes\n while (callStack.length > level) {\n callStack.pop();\n }\n\n // Check if this is a recursive call (same label already in call stack)\n const isRecursive = callStack.some((entry) => entry === label);\n\n // If user is doing text search we filter out labels in the same way we highlight them in flame graph.\n if (!matchedLabels || matchedLabels.has(label)) {\n filteredTable[label] = filteredTable[label] || {};\n filteredTable[label].self = filteredTable[label].self ? filteredTable[label].self + self : self;\n\n // Only add to total if this is not a recursive call\n if (!isRecursive) {\n filteredTable[label].total = filteredTable[label].total ? filteredTable[label].total + value : value;\n filteredTable[label].totalRight = filteredTable[label].totalRight\n ? filteredTable[label].totalRight + valueRight\n : valueRight;\n }\n }\n\n // Add current call to the stack\n callStack.push(label);\n }\n\n return filteredTable;\n}\n\nfunction buildTableDataFrame(\n data: FlameGraphDataContainer,\n table: { [key: string]: TableData },\n width: number,\n onSymbolClick: (str: string) => void,\n onSearch: (str: string) => void,\n onSandwich: (str?: string) => void,\n theme: GrafanaTheme2,\n colorScheme: ColorScheme | ColorSchemeDiff,\n search?: string,\n sandwichItem?: string\n): DataFrame {\n const actionField: Field = createActionField(onSandwich, onSearch, search, sandwichItem);\n\n const symbolField: Field = {\n type: FieldType.string,\n name: 'Symbol',\n values: [],\n config: {\n custom: { width: width - actionColumnWidth - TOP_TABLE_COLUMN_WIDTH * 2 },\n links: [\n {\n title: 'Highlight symbol',\n url: '',\n onClick: (e: DataLinkClickEvent) => {\n const field: Field = e.origin.field;\n const value = field.values[e.origin.rowIndex];\n onSymbolClick(value);\n },\n },\n ],\n },\n };\n\n let frame;\n\n if (data.isDiffFlamegraph()) {\n symbolField.config.custom.width = width - actionColumnWidth - TOP_TABLE_COLUMN_WIDTH * 3;\n\n const baselineField = createNumberField('Baseline', 'percent');\n const comparisonField = createNumberField('Comparison', 'percent');\n const diffField = createNumberField('Diff', 'percent');\n diffField.config.custom.cellOptions.type = TableCellDisplayMode.ColorText;\n\n const [removeColor, addColor] =\n colorScheme === ColorSchemeDiff.DiffColorBlind\n ? [diffColorBlindColors[0], diffColorBlindColors[2]]\n : [diffDefaultColors[0], diffDefaultColors[2]];\n\n diffField.config.mappings = [\n { type: MappingType.ValueToText, options: { [Infinity]: { text: 'new', color: addColor } } },\n { type: MappingType.ValueToText, options: { [-100]: { text: 'removed', color: removeColor } } },\n { type: MappingType.RangeToText, options: { from: 0, to: Infinity, result: { color: addColor } } },\n { type: MappingType.RangeToText, options: { from: -Infinity, to: 0, result: { color: removeColor } } },\n ];\n\n // For this we don't really consider sandwich view even though you can switch it on.\n const levels = data.getLevels();\n const totalTicks = levels.length ? levels[0][0].value : 0;\n const totalTicksRight = levels.length ? levels[0][0].valueRight : undefined;\n\n for (let key in table) {\n actionField.values.push(null);\n symbolField.values.push(key);\n\n const ticksLeft = table[key].total;\n const ticksRight = table[key].totalRight;\n\n // We are iterating over table of the data so totalTicksRight needs to be defined\n const totalTicksLeft = totalTicks - totalTicksRight!;\n\n const percentageLeft = Math.round((10000 * ticksLeft) / totalTicksLeft) / 100;\n const percentageRight = Math.round((10000 * ticksRight) / totalTicksRight!) / 100;\n\n const diff = ((percentageRight - percentageLeft) / percentageLeft) * 100;\n\n diffField.values.push(diff);\n baselineField.values.push(percentageLeft);\n comparisonField.values.push(percentageRight);\n }\n\n frame = {\n fields: [actionField, symbolField, baselineField, comparisonField, diffField],\n length: symbolField.values.length,\n };\n } else {\n const selfField = createNumberField('Self', data.selfField.config.unit);\n const totalField = createNumberField('Total', data.valueField.config.unit);\n\n for (let key in table) {\n actionField.values.push(null);\n symbolField.values.push(key);\n selfField.values.push(table[key].self);\n totalField.values.push(table[key].total);\n }\n\n frame = { fields: [actionField, symbolField, selfField, totalField], length: symbolField.values.length };\n }\n\n const dataFrames = applyFieldOverrides({\n data: [frame],\n fieldConfig: {\n defaults: {},\n overrides: [],\n },\n replaceVariables: (value: string) => value,\n theme,\n });\n\n return dataFrames[0];\n}\n\nfunction createNumberField(name: string, unit?: string): Field {\n const tableFieldOptions: TableFieldOptions = {\n width: TOP_TABLE_COLUMN_WIDTH,\n align: 'auto',\n inspect: false,\n cellOptions: { type: TableCellDisplayMode.Auto },\n };\n\n return {\n type: FieldType.number,\n name,\n values: [],\n config: {\n unit,\n custom: tableFieldOptions,\n },\n };\n}\n\nconst actionColumnWidth = 61;\n\nfunction createActionField(\n onSandwich: (str?: string) => void,\n onSearch: (str: string) => void,\n search?: string,\n sandwichItem?: string\n): Field {\n const options: TableCustomCellOptions = {\n type: TableCellDisplayMode.Custom,\n cellComponent: (props) => {\n return (\n <ActionCell\n frame={props.frame}\n onSandwich={onSandwich}\n onSearch={onSearch}\n search={search}\n sandwichItem={sandwichItem}\n rowIndex={props.rowIndex}\n />\n );\n },\n };\n\n const actionFieldTableConfig: TableFieldOptions = {\n filterable: false,\n width: actionColumnWidth,\n hideHeader: true,\n inspect: false,\n align: 'auto',\n cellOptions: options,\n };\n\n return {\n type: FieldType.number,\n name: 'actions',\n values: [],\n config: {\n custom: actionFieldTableConfig,\n },\n };\n}\n\ntype ActionCellProps = {\n frame: DataFrame;\n rowIndex: number;\n search?: string;\n sandwichItem?: string;\n onSearch: (symbol: string) => void;\n onSandwich: (symbol: string) => void;\n};\n\nfunction ActionCell(props: ActionCellProps) {\n const styles = getStylesActionCell();\n const symbol = props.frame.fields.find((f: Field) => f.name === 'Symbol')?.values[props.rowIndex];\n const isSearched = props.search === `^${escapeStringForRegex(String(symbol))}$`;\n const isSandwiched = props.sandwichItem === symbol;\n\n return (\n <div className={styles.actionCellWrapper}>\n <IconButton\n className={styles.actionCellButton}\n name={'search'}\n variant={isSearched ? 'primary' : 'secondary'}\n tooltip={isSearched ? 'Clear from search' : 'Search for symbol'}\n aria-label={isSearched ? 'Clear from search' : 'Search for symbol'}\n onClick={() => {\n props.onSearch(isSearched ? '' : symbol);\n }}\n />\n <IconButton\n className={styles.actionCellButton}\n name={'gf-show-context'}\n tooltip={isSandwiched ? 'Remove from sandwich view' : 'Show in sandwich view'}\n variant={isSandwiched ? 'primary' : 'secondary'}\n aria-label={isSandwiched ? 'Remove from sandwich view' : 'Show in sandwich view'}\n onClick={() => {\n props.onSandwich(isSandwiched ? undefined : symbol);\n }}\n />\n </div>\n );\n}\n\nconst getStyles = (theme: GrafanaTheme2) => {\n return {\n topTableContainer: css({\n label: 'topTableContainer',\n padding: theme.spacing(1),\n backgroundColor: theme.colors.background.secondary,\n height: '100%',\n }),\n };\n};\n\nconst getStylesActionCell = () => {\n return {\n actionCellWrapper: css({\n label: 'actionCellWrapper',\n display: 'flex',\n height: '24px',\n }),\n actionCellButton: css({\n label: 'actionCellButton',\n marginRight: 0,\n width: '24px',\n }),\n };\n};\n\nexport { buildFilteredTable };\n\nexport default FlameGraphTopTableContainer;\n"],"names":["memo","useMemo","useStyles2","useTheme2","useState","jsx","AutoSizer","Table","data","FieldType","TOP_TABLE_COLUMN_WIDTH","TableCellDisplayMode","ColorSchemeDiff","diffColorBlindColors","diffDefaultColors","MappingType","applyFieldOverrides","escapeStringForRegex","jsxs","IconButton","css"],"mappings":"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"}