@grafana/flamegraph 11.6.0-224787 → 11.6.0-225338

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +1 @@
1
- {"version":3,"file":"rendering.js","sources":["../../../src/FlameGraph/rendering.ts"],"sourcesContent":["import { RefObject, useCallback, useEffect, useMemo, useState } from 'react';\nimport color from 'tinycolor2';\n\nimport { GrafanaTheme2 } from '@grafana/data';\nimport { useTheme2 } from '@grafana/ui';\n\nimport {\n BAR_BORDER_WIDTH,\n BAR_TEXT_PADDING_LEFT,\n MUTE_THRESHOLD,\n HIDE_THRESHOLD,\n LABEL_THRESHOLD,\n PIXELS_PER_LEVEL,\n GROUP_STRIP_WIDTH,\n GROUP_STRIP_PADDING,\n GROUP_STRIP_MARGIN_LEFT,\n GROUP_TEXT_OFFSET,\n} from '../constants';\nimport { ClickedItemData, ColorScheme, ColorSchemeDiff, TextAlign } from '../types';\n\nimport { getBarColorByDiff, getBarColorByPackage, getBarColorByValue } from './colors';\nimport { CollapseConfig, CollapsedMap, FlameGraphDataContainer, LevelItem } from './dataTransform';\n\ntype RenderOptions = {\n canvasRef: RefObject<HTMLCanvasElement>;\n data: FlameGraphDataContainer;\n root: LevelItem;\n direction: 'children' | 'parents';\n\n // Depth in number of levels\n depth: number;\n wrapperWidth: number;\n\n // If we are rendering only zoomed in part of the graph.\n rangeMin: number;\n rangeMax: number;\n\n matchedLabels: Set<string> | undefined;\n textAlign: TextAlign;\n\n // Total ticks that will be used for sizing\n totalViewTicks: number;\n // Total ticks that will be used for computing colors as some color scheme (like in diff view) should not be affected\n // by sandwich or focus view.\n totalColorTicks: number;\n // Total ticks used to compute the diff colors\n totalTicksRight: number | undefined;\n colorScheme: ColorScheme | ColorSchemeDiff;\n focusedItemData?: ClickedItemData;\n collapsedMap: CollapsedMap;\n};\n\nexport function useFlameRender(options: RenderOptions) {\n const {\n canvasRef,\n data,\n root,\n depth,\n direction,\n wrapperWidth,\n rangeMin,\n rangeMax,\n matchedLabels,\n textAlign,\n totalViewTicks,\n totalColorTicks,\n totalTicksRight,\n colorScheme,\n focusedItemData,\n collapsedMap,\n } = options;\n const ctx = useSetupCanvas(canvasRef, wrapperWidth, depth);\n const theme = useTheme2();\n\n // There is a bit of dependency injections here that does not add readability, mainly to prevent recomputing some\n // common stuff for all the nodes in the graph when only once is enough. perf/readability tradeoff.\n\n const mutedColor = useMemo(() => {\n const barMutedColor = color(theme.colors.background.secondary);\n return theme.isLight ? barMutedColor.darken(10).toHexString() : barMutedColor.lighten(10).toHexString();\n }, [theme]);\n\n const getBarColor = useColorFunction(\n totalColorTicks,\n totalTicksRight,\n colorScheme,\n theme,\n mutedColor,\n rangeMin,\n rangeMax,\n matchedLabels,\n focusedItemData ? focusedItemData.item.level : 0\n );\n\n const renderFunc = useRenderFunc(ctx, data, getBarColor, textAlign, collapsedMap);\n\n useEffect(() => {\n if (!ctx) {\n return;\n }\n\n ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height);\n\n const mutedPath2D = new Path2D();\n\n //\n // Walk the tree and compute the dimensions for each item in the flamegraph.\n //\n walkTree(\n root,\n direction,\n data,\n totalViewTicks,\n rangeMin,\n rangeMax,\n wrapperWidth,\n collapsedMap,\n (item, x, y, width, height, label, muted) => {\n if (muted) {\n // We do a bit of optimization for muted regions, and we render them all in single fill later on as they don't\n // have labels and are the same color.\n mutedPath2D.rect(x, y, width, height);\n } else {\n renderFunc(item, x, y, width, height, label);\n }\n }\n );\n\n // Only fill the muted rects\n ctx.fillStyle = mutedColor;\n ctx.fill(mutedPath2D);\n }, [\n ctx,\n data,\n root,\n wrapperWidth,\n rangeMin,\n rangeMax,\n totalViewTicks,\n direction,\n renderFunc,\n collapsedMap,\n mutedColor,\n ]);\n}\n\ntype RenderFunc = (item: LevelItem, x: number, y: number, width: number, height: number, label: string) => void;\n\ntype RenderFuncWrap = (\n item: LevelItem,\n x: number,\n y: number,\n width: number,\n height: number,\n label: string,\n muted: boolean\n) => void;\n\n/**\n * Create a render function with some memoization to prevent excesive repainting of the canvas.\n * @param ctx\n * @param data\n * @param getBarColor\n * @param textAlign\n * @param collapsedMap\n */\nfunction useRenderFunc(\n ctx: CanvasRenderingContext2D | undefined,\n data: FlameGraphDataContainer,\n getBarColor: (item: LevelItem, label: string, muted: boolean) => string,\n textAlign: TextAlign,\n collapsedMap: CollapsedMap\n) {\n return useMemo(() => {\n if (!ctx) {\n return () => {};\n }\n\n const renderFunc: RenderFunc = (item, x, y, width, height, label) => {\n ctx.beginPath();\n ctx.rect(x + BAR_BORDER_WIDTH, y, width, height);\n ctx.fillStyle = getBarColor(item, label, false);\n ctx.stroke();\n ctx.fill();\n\n const collapsedItemConfig = collapsedMap.get(item);\n let finalLabel = label;\n if (collapsedItemConfig && collapsedItemConfig.collapsed) {\n const numberOfCollapsedItems = collapsedItemConfig.items.length;\n finalLabel = `(${numberOfCollapsedItems}) ` + label;\n }\n\n if (width >= LABEL_THRESHOLD) {\n if (collapsedItemConfig) {\n renderLabel(\n ctx,\n data,\n finalLabel,\n item,\n width,\n textAlign === 'left' ? x + GROUP_STRIP_MARGIN_LEFT + GROUP_TEXT_OFFSET : x,\n y,\n textAlign\n );\n\n renderGroupingStrip(ctx, x, y, height, item, collapsedItemConfig);\n } else {\n renderLabel(ctx, data, finalLabel, item, width, x, y, textAlign);\n }\n }\n };\n\n return renderFunc;\n }, [ctx, getBarColor, textAlign, data, collapsedMap]);\n}\n\n/**\n * Render small strip on the left side of the bar to indicate that this item is part of a group that can be collapsed.\n * @param ctx\n * @param x\n * @param y\n * @param height\n * @param item\n * @param collapsedItemConfig\n */\nfunction renderGroupingStrip(\n ctx: CanvasRenderingContext2D,\n x: number,\n y: number,\n height: number,\n item: LevelItem,\n collapsedItemConfig: CollapseConfig\n) {\n const groupStripX = x + GROUP_STRIP_MARGIN_LEFT;\n\n // This is to mask the label in case we align it right to left.\n ctx.beginPath();\n ctx.rect(x, y, groupStripX - x + GROUP_STRIP_WIDTH + GROUP_STRIP_PADDING, height);\n ctx.fill();\n\n // For item in a group that can be collapsed, we draw a small strip to mark them. On the items that are at the\n // start or and end of a group we draw just half the strip so 2 groups next to each other are separated\n // visually.\n ctx.beginPath();\n if (collapsedItemConfig.collapsed) {\n ctx.rect(groupStripX, y + height / 4, GROUP_STRIP_WIDTH, height / 2);\n } else {\n if (collapsedItemConfig.items[0] === item) {\n // Top item\n ctx.rect(groupStripX, y + height / 2, GROUP_STRIP_WIDTH, height / 2);\n } else if (collapsedItemConfig.items[collapsedItemConfig.items.length - 1] === item) {\n // Bottom item\n ctx.rect(groupStripX, y, GROUP_STRIP_WIDTH, height / 2);\n } else {\n ctx.rect(groupStripX, y, GROUP_STRIP_WIDTH, height);\n }\n }\n\n ctx.fillStyle = '#666';\n ctx.fill();\n}\n\n/**\n * Exported for testing don't use directly\n * Walks the tree and computes coordinates, dimensions and other data needed for rendering. For each item in the tree\n * it defers the rendering to the renderFunc.\n */\nexport function walkTree(\n root: LevelItem,\n // In sandwich view we use parents direction to show all callers.\n direction: 'children' | 'parents',\n data: FlameGraphDataContainer,\n totalViewTicks: number,\n rangeMin: number,\n rangeMax: number,\n wrapperWidth: number,\n collapsedMap: CollapsedMap,\n renderFunc: RenderFuncWrap\n) {\n // The levelOffset here is to keep track if items that we don't render because they are collapsed into single row.\n // That means we have to render next items with an offset of some rows up in the stack.\n const stack: Array<{ item: LevelItem; levelOffset: number }> = [];\n stack.push({ item: root, levelOffset: 0 });\n\n const pixelsPerTick = (wrapperWidth * window.devicePixelRatio) / totalViewTicks / (rangeMax - rangeMin);\n let collapsedItemRendered: LevelItem | undefined = undefined;\n\n while (stack.length > 0) {\n const { item, levelOffset } = stack.shift()!;\n let curBarTicks = item.value;\n const muted = curBarTicks * pixelsPerTick <= MUTE_THRESHOLD;\n const width = curBarTicks * pixelsPerTick - (muted ? 0 : BAR_BORDER_WIDTH * 2);\n const height = PIXELS_PER_LEVEL;\n\n if (width < HIDE_THRESHOLD) {\n // We don't render nor it's children\n continue;\n }\n\n let offsetModifier = 0;\n let skipRender = false;\n const collapsedItemConfig = collapsedMap.get(item);\n const isCollapsedItem = collapsedItemConfig && collapsedItemConfig.collapsed;\n\n if (isCollapsedItem) {\n if (collapsedItemRendered === collapsedItemConfig.items[0]) {\n offsetModifier = direction === 'children' ? -1 : +1;\n skipRender = true;\n } else {\n // This is a case where we have another collapsed group right after different collapsed group, so we need to\n // reset.\n collapsedItemRendered = undefined;\n }\n } else {\n collapsedItemRendered = undefined;\n }\n\n if (!skipRender) {\n const barX = getBarX(item.start, totalViewTicks, rangeMin, pixelsPerTick);\n const barY = (item.level + levelOffset) * PIXELS_PER_LEVEL;\n\n let label = data.getLabel(item.itemIndexes[0]);\n if (isCollapsedItem) {\n collapsedItemRendered = item;\n }\n\n renderFunc(item, barX, barY, width, height, label, muted);\n }\n\n const nextList = direction === 'children' ? item.children : item.parents;\n if (nextList) {\n stack.unshift(...nextList.map((c) => ({ item: c, levelOffset: levelOffset + offsetModifier })));\n }\n }\n}\n\nfunction useColorFunction(\n totalTicks: number,\n totalTicksRight: number | undefined,\n colorScheme: ColorScheme | ColorSchemeDiff,\n theme: GrafanaTheme2,\n mutedColor: string,\n rangeMin: number,\n rangeMax: number,\n matchedLabels: Set<string> | undefined,\n topLevel: number\n) {\n return useCallback(\n function getColor(item: LevelItem, label: string, muted: boolean) {\n // If collapsed and no search we can quickly return the muted color\n if (muted && !matchedLabels) {\n // Collapsed are always grayed\n return mutedColor;\n }\n\n const barColor =\n item.valueRight !== undefined &&\n (colorScheme === ColorSchemeDiff.Default || colorScheme === ColorSchemeDiff.DiffColorBlind)\n ? getBarColorByDiff(item.value, item.valueRight!, totalTicks, totalTicksRight!, colorScheme)\n : colorScheme === ColorScheme.ValueBased\n ? getBarColorByValue(item.value, totalTicks, rangeMin, rangeMax)\n : getBarColorByPackage(label, theme);\n\n if (matchedLabels) {\n // Means we are searching, we use color for matches and gray the rest\n return matchedLabels.has(label) ? barColor.toHslString() : mutedColor;\n }\n\n // Mute if we are above the focused symbol\n return item.level > topLevel - 1 ? barColor.toHslString() : barColor.lighten(15).toHslString();\n },\n [totalTicks, totalTicksRight, colorScheme, theme, rangeMin, rangeMax, matchedLabels, topLevel, mutedColor]\n );\n}\n\nfunction useSetupCanvas(canvasRef: RefObject<HTMLCanvasElement>, wrapperWidth: number, numberOfLevels: number) {\n const [ctx, setCtx] = useState<CanvasRenderingContext2D>();\n\n useEffect(() => {\n if (!(numberOfLevels && canvasRef.current)) {\n return;\n }\n const ctx = canvasRef.current.getContext('2d')!;\n\n const height = PIXELS_PER_LEVEL * numberOfLevels;\n canvasRef.current.width = Math.round(wrapperWidth * window.devicePixelRatio);\n canvasRef.current.height = Math.round(height);\n canvasRef.current.style.width = `${wrapperWidth}px`;\n canvasRef.current.style.height = `${height / window.devicePixelRatio}px`;\n\n ctx.textBaseline = 'middle';\n ctx.font = 12 * window.devicePixelRatio + 'px monospace';\n ctx.strokeStyle = 'white';\n setCtx(ctx);\n }, [canvasRef, setCtx, wrapperWidth, numberOfLevels]);\n return ctx;\n}\n\n// Renders a text inside the node rectangle. It allows setting alignment of the text left or right which takes effect\n// when text is too long to fit in the rectangle.\nfunction renderLabel(\n ctx: CanvasRenderingContext2D,\n data: FlameGraphDataContainer,\n label: string,\n item: LevelItem,\n width: number,\n x: number,\n y: number,\n textAlign: TextAlign\n) {\n ctx.save();\n ctx.clip(); // so text does not overflow\n ctx.fillStyle = '#222';\n\n const displayValue = data.valueDisplayProcessor(item.value);\n const unit = displayValue.suffix ? displayValue.text + displayValue.suffix : displayValue.text;\n\n // We only measure name here instead of full label because of how we deal with the units and aligning later.\n const measure = ctx.measureText(label);\n const spaceForTextInRect = width - BAR_TEXT_PADDING_LEFT;\n\n let fullLabel = `${label} (${unit})`;\n let labelX = Math.max(x, 0) + BAR_TEXT_PADDING_LEFT;\n\n // We use the desired alignment only if there is not enough space for the text, otherwise we keep left alignment as\n // that will already show full text.\n if (measure.width > spaceForTextInRect) {\n ctx.textAlign = textAlign;\n // If aligned to the right we don't want to take the space with the unit label as the assumption is user wants to\n // mainly see the name. This also reflects how pyro/flamegraph works.\n if (textAlign === 'right') {\n fullLabel = label;\n labelX = x + width - BAR_TEXT_PADDING_LEFT;\n }\n }\n\n ctx.fillText(fullLabel, labelX, y + PIXELS_PER_LEVEL / 2 + 2);\n ctx.restore();\n}\n\n/**\n * Returns the X position of the bar. totalTicks * rangeMin is to adjust for any current zoom. So if we zoom to a\n * section of the graph we align and shift the X coordinates accordingly.\n * @param offset\n * @param totalTicks\n * @param rangeMin\n * @param pixelsPerTick\n */\nexport function getBarX(offset: number, totalTicks: number, rangeMin: number, pixelsPerTick: number) {\n return (offset - totalTicks * rangeMin) * pixelsPerTick;\n}\n"],"names":["ctx"],"mappings":"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"}
1
+ {"version":3,"file":"rendering.js","sources":["../../../src/FlameGraph/rendering.ts"],"sourcesContent":["import { RefObject, useCallback, useEffect, useMemo, useState } from 'react';\nimport color from 'tinycolor2';\n\nimport { GrafanaTheme2 } from '@grafana/data';\nimport { useTheme2 } from '@grafana/ui';\n\nimport {\n BAR_BORDER_WIDTH,\n BAR_TEXT_PADDING_LEFT,\n MUTE_THRESHOLD,\n HIDE_THRESHOLD,\n LABEL_THRESHOLD,\n PIXELS_PER_LEVEL,\n GROUP_STRIP_WIDTH,\n GROUP_STRIP_PADDING,\n GROUP_STRIP_MARGIN_LEFT,\n GROUP_TEXT_OFFSET,\n} from '../constants';\nimport { ClickedItemData, ColorScheme, ColorSchemeDiff, TextAlign } from '../types';\n\nimport { getBarColorByDiff, getBarColorByPackage, getBarColorByValue } from './colors';\nimport { CollapseConfig, CollapsedMap, FlameGraphDataContainer, LevelItem } from './dataTransform';\n\ntype RenderOptions = {\n canvasRef: RefObject<HTMLCanvasElement>;\n data: FlameGraphDataContainer;\n root: LevelItem;\n direction: 'children' | 'parents';\n\n // Depth in number of levels\n depth: number;\n wrapperWidth: number;\n\n // If we are rendering only zoomed in part of the graph.\n rangeMin: number;\n rangeMax: number;\n\n matchedLabels: Set<string> | undefined;\n textAlign: TextAlign;\n\n // Total ticks that will be used for sizing\n totalViewTicks: number;\n // Total ticks that will be used for computing colors as some color scheme (like in diff view) should not be affected\n // by sandwich or focus view.\n totalColorTicks: number;\n // Total ticks used to compute the diff colors\n totalTicksRight: number | undefined;\n colorScheme: ColorScheme | ColorSchemeDiff;\n focusedItemData?: ClickedItemData;\n collapsedMap: CollapsedMap;\n};\n\nexport function useFlameRender(options: RenderOptions) {\n const {\n canvasRef,\n data,\n root,\n depth,\n direction,\n wrapperWidth,\n rangeMin,\n rangeMax,\n matchedLabels,\n textAlign,\n totalViewTicks,\n totalColorTicks,\n totalTicksRight,\n colorScheme,\n focusedItemData,\n collapsedMap,\n } = options;\n const ctx = useSetupCanvas(canvasRef, wrapperWidth, depth);\n const theme = useTheme2();\n\n // There is a bit of dependency injections here that does not add readability, mainly to prevent recomputing some\n // common stuff for all the nodes in the graph when only once is enough. perf/readability tradeoff.\n\n const mutedColor = useMemo(() => {\n const barMutedColor = color(theme.colors.background.secondary);\n return theme.isLight ? barMutedColor.darken(10).toHexString() : barMutedColor.lighten(10).toHexString();\n }, [theme]);\n\n const getBarColor = useColorFunction(\n totalColorTicks,\n totalTicksRight,\n colorScheme,\n theme,\n mutedColor,\n rangeMin,\n rangeMax,\n matchedLabels,\n focusedItemData ? focusedItemData.item.level : 0\n );\n\n const renderFunc = useRenderFunc(ctx, data, getBarColor, textAlign, collapsedMap);\n\n useEffect(() => {\n if (!ctx) {\n return;\n }\n\n ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height);\n\n const mutedPath2D = new Path2D();\n\n //\n // Walk the tree and compute the dimensions for each item in the flamegraph.\n //\n walkTree(\n root,\n direction,\n data,\n totalViewTicks,\n rangeMin,\n rangeMax,\n wrapperWidth,\n collapsedMap,\n (item, x, y, width, height, label, muted) => {\n if (muted) {\n // We do a bit of optimization for muted regions, and we render them all in single fill later on as they don't\n // have labels and are the same color.\n mutedPath2D.rect(x, y, width, height);\n } else {\n renderFunc(item, x, y, width, height, label);\n }\n }\n );\n\n // Only fill the muted rects\n ctx.fillStyle = mutedColor;\n ctx.fill(mutedPath2D);\n }, [\n ctx,\n data,\n root,\n wrapperWidth,\n rangeMin,\n rangeMax,\n totalViewTicks,\n direction,\n renderFunc,\n collapsedMap,\n mutedColor,\n ]);\n}\n\ntype RenderFunc = (item: LevelItem, x: number, y: number, width: number, height: number, label: string) => void;\n\ntype RenderFuncWrap = (\n item: LevelItem,\n x: number,\n y: number,\n width: number,\n height: number,\n label: string,\n muted: boolean\n) => void;\n\n/**\n * Create a render function with some memoization to prevent excesive repainting of the canvas.\n * @param ctx\n * @param data\n * @param getBarColor\n * @param textAlign\n * @param collapsedMap\n */\nfunction useRenderFunc(\n ctx: CanvasRenderingContext2D | undefined,\n data: FlameGraphDataContainer,\n getBarColor: (item: LevelItem, label: string, muted: boolean) => string,\n textAlign: TextAlign,\n collapsedMap: CollapsedMap\n) {\n return useMemo(() => {\n if (!ctx) {\n return () => {};\n }\n\n const renderFunc: RenderFunc = (item, x, y, width, height, label) => {\n ctx.beginPath();\n ctx.rect(x + BAR_BORDER_WIDTH, y, width, height);\n ctx.fillStyle = getBarColor(item, label, false);\n ctx.stroke();\n ctx.fill();\n\n const collapsedItemConfig = collapsedMap.get(item);\n let finalLabel = label;\n if (collapsedItemConfig && collapsedItemConfig.collapsed) {\n const numberOfCollapsedItems = collapsedItemConfig.items.length;\n finalLabel = `(${numberOfCollapsedItems}) ` + label;\n }\n\n if (width >= LABEL_THRESHOLD) {\n if (collapsedItemConfig) {\n renderLabel(\n ctx,\n data,\n finalLabel,\n item,\n width,\n textAlign === 'left' ? x + GROUP_STRIP_MARGIN_LEFT + GROUP_TEXT_OFFSET : x,\n y,\n textAlign\n );\n\n renderGroupingStrip(ctx, x, y, height, item, collapsedItemConfig);\n } else {\n renderLabel(ctx, data, finalLabel, item, width, x, y, textAlign);\n }\n }\n };\n\n return renderFunc;\n }, [ctx, getBarColor, textAlign, data, collapsedMap]);\n}\n\n/**\n * Render small strip on the left side of the bar to indicate that this item is part of a group that can be collapsed.\n * @param ctx\n * @param x\n * @param y\n * @param height\n * @param item\n * @param collapsedItemConfig\n */\nfunction renderGroupingStrip(\n ctx: CanvasRenderingContext2D,\n x: number,\n y: number,\n height: number,\n item: LevelItem,\n collapsedItemConfig: CollapseConfig\n) {\n const groupStripX = x + GROUP_STRIP_MARGIN_LEFT;\n\n // This is to mask the label in case we align it right to left.\n ctx.beginPath();\n ctx.rect(x, y, groupStripX - x + GROUP_STRIP_WIDTH + GROUP_STRIP_PADDING, height);\n ctx.fill();\n\n // For item in a group that can be collapsed, we draw a small strip to mark them. On the items that are at the\n // start or and end of a group we draw just half the strip so 2 groups next to each other are separated\n // visually.\n ctx.beginPath();\n if (collapsedItemConfig.collapsed) {\n ctx.rect(groupStripX, y + height / 4, GROUP_STRIP_WIDTH, height / 2);\n } else {\n if (collapsedItemConfig.items[0] === item) {\n // Top item\n ctx.rect(groupStripX, y + height / 2, GROUP_STRIP_WIDTH, height / 2);\n } else if (collapsedItemConfig.items[collapsedItemConfig.items.length - 1] === item) {\n // Bottom item\n ctx.rect(groupStripX, y, GROUP_STRIP_WIDTH, height / 2);\n } else {\n ctx.rect(groupStripX, y, GROUP_STRIP_WIDTH, height);\n }\n }\n\n ctx.fillStyle = '#666';\n ctx.fill();\n}\n\n/**\n * Exported for testing don't use directly\n * Walks the tree and computes coordinates, dimensions and other data needed for rendering. For each item in the tree\n * it defers the rendering to the renderFunc.\n */\nexport function walkTree(\n root: LevelItem,\n // In sandwich view we use parents direction to show all callers.\n direction: 'children' | 'parents',\n data: FlameGraphDataContainer,\n totalViewTicks: number,\n rangeMin: number,\n rangeMax: number,\n wrapperWidth: number,\n collapsedMap: CollapsedMap,\n renderFunc: RenderFuncWrap\n) {\n // The levelOffset here is to keep track if items that we don't render because they are collapsed into single row.\n // That means we have to render next items with an offset of some rows up in the stack.\n const stack: Array<{ item: LevelItem; levelOffset: number }> = [];\n stack.push({ item: root, levelOffset: 0 });\n\n const pixelsPerTick = (wrapperWidth * window.devicePixelRatio) / totalViewTicks / (rangeMax - rangeMin);\n let collapsedItemRendered: LevelItem | undefined = undefined;\n\n while (stack.length > 0) {\n const { item, levelOffset } = stack.shift()!;\n let curBarTicks = item.value;\n const muted = curBarTicks * pixelsPerTick <= MUTE_THRESHOLD;\n const width = curBarTicks * pixelsPerTick - (muted ? 0 : BAR_BORDER_WIDTH * 2);\n const height = PIXELS_PER_LEVEL;\n\n if (width < HIDE_THRESHOLD) {\n // We don't render nor it's children\n continue;\n }\n\n let offsetModifier = 0;\n let skipRender = false;\n const collapsedItemConfig = collapsedMap.get(item);\n const isCollapsedItem = collapsedItemConfig && collapsedItemConfig.collapsed;\n\n if (isCollapsedItem) {\n if (collapsedItemRendered === collapsedItemConfig.items[0]) {\n offsetModifier = direction === 'children' ? -1 : +1;\n skipRender = true;\n } else {\n // This is a case where we have another collapsed group right after different collapsed group, so we need to\n // reset.\n collapsedItemRendered = undefined;\n }\n } else {\n collapsedItemRendered = undefined;\n }\n\n if (!skipRender) {\n const barX = getBarX(item.start, totalViewTicks, rangeMin, pixelsPerTick);\n const barY = (item.level + levelOffset) * PIXELS_PER_LEVEL;\n\n let label = data.getLabel(item.itemIndexes[0]);\n if (isCollapsedItem) {\n collapsedItemRendered = item;\n }\n\n renderFunc(item, barX, barY, width, height, label, muted);\n }\n\n const nextList = direction === 'children' ? item.children : item.parents;\n if (nextList) {\n stack.unshift(...nextList.map((c) => ({ item: c, levelOffset: levelOffset + offsetModifier })));\n }\n }\n}\n\nfunction useColorFunction(\n totalTicks: number,\n totalTicksRight: number | undefined,\n colorScheme: ColorScheme | ColorSchemeDiff,\n theme: GrafanaTheme2,\n mutedColor: string,\n rangeMin: number,\n rangeMax: number,\n matchedLabels: Set<string> | undefined,\n topLevel: number\n) {\n return useCallback(\n function getColor(item: LevelItem, label: string, muted: boolean) {\n // If collapsed and no search we can quickly return the muted color\n if (muted && !matchedLabels) {\n // Collapsed are always grayed\n return mutedColor;\n }\n\n const barColor =\n item.valueRight !== undefined &&\n (colorScheme === ColorSchemeDiff.Default || colorScheme === ColorSchemeDiff.DiffColorBlind)\n ? getBarColorByDiff(item.value, item.valueRight!, totalTicks, totalTicksRight!, colorScheme)\n : colorScheme === ColorScheme.ValueBased\n ? getBarColorByValue(item.value, totalTicks, rangeMin, rangeMax)\n : getBarColorByPackage(label, theme);\n\n if (matchedLabels) {\n // Means we are searching, we use color for matches and gray the rest\n return matchedLabels.has(label) ? barColor.toHslString() : mutedColor;\n }\n\n // Mute if we are above the focused symbol\n return item.level > topLevel - 1 ? barColor.toHslString() : barColor.lighten(15).toHslString();\n },\n [totalTicks, totalTicksRight, colorScheme, theme, rangeMin, rangeMax, matchedLabels, topLevel, mutedColor]\n );\n}\n\nfunction useSetupCanvas(canvasRef: RefObject<HTMLCanvasElement>, wrapperWidth: number, numberOfLevels: number) {\n const [ctx, setCtx] = useState<CanvasRenderingContext2D>();\n\n useEffect(() => {\n if (!(numberOfLevels && canvasRef.current)) {\n return;\n }\n const ctx = canvasRef.current.getContext('2d')!;\n\n const height = PIXELS_PER_LEVEL * numberOfLevels;\n canvasRef.current.width = Math.round(wrapperWidth * window.devicePixelRatio);\n canvasRef.current.height = Math.round(height);\n canvasRef.current.style.width = `${wrapperWidth}px`;\n canvasRef.current.style.height = `${height / window.devicePixelRatio}px`;\n\n ctx.textBaseline = 'middle';\n ctx.font = 12 * window.devicePixelRatio + 'px monospace';\n ctx.strokeStyle = 'white';\n setCtx(ctx);\n }, [canvasRef, setCtx, wrapperWidth, numberOfLevels]);\n return ctx;\n}\n\n// Renders a text inside the node rectangle. It allows setting alignment of the text left or right which takes effect\n// when text is too long to fit in the rectangle.\nfunction renderLabel(\n ctx: CanvasRenderingContext2D,\n data: FlameGraphDataContainer,\n label: string,\n item: LevelItem,\n width: number,\n x: number,\n y: number,\n textAlign: TextAlign\n) {\n ctx.save();\n ctx.clip(); // so text does not overflow\n ctx.fillStyle = '#222';\n\n const displayValue = data.valueDisplayProcessor(item.value);\n const unit = displayValue.suffix ? displayValue.text + displayValue.suffix : displayValue.text;\n\n // We only measure name here instead of full label because of how we deal with the units and aligning later.\n const measure = ctx.measureText(label);\n const spaceForTextInRect = width - BAR_TEXT_PADDING_LEFT;\n\n let fullLabel = `${label} (${unit})`;\n let labelX = Math.max(x, 0) + BAR_TEXT_PADDING_LEFT;\n\n // We use the desired alignment only if there is not enough space for the text, otherwise we keep left alignment as\n // that will already show full text.\n if (measure.width > spaceForTextInRect) {\n ctx.textAlign = textAlign;\n // If aligned to the right we don't want to take the space with the unit label as the assumption is user wants to\n // mainly see the name. This also reflects how pyro/flamegraph works.\n if (textAlign === 'right') {\n fullLabel = label;\n labelX = x + width - BAR_TEXT_PADDING_LEFT;\n }\n }\n\n ctx.fillText(fullLabel, labelX, y + PIXELS_PER_LEVEL / 2 + 2);\n ctx.restore();\n}\n\n/**\n * Returns the X position of the bar. totalTicks * rangeMin is to adjust for any current zoom. So if we zoom to a\n * section of the graph we align and shift the X coordinates accordingly.\n * @param offset\n * @param totalTicks\n * @param rangeMin\n * @param pixelsPerTick\n */\nexport function getBarX(offset: number, totalTicks: number, rangeMin: number, pixelsPerTick: number) {\n return (offset - totalTicks * rangeMin) * pixelsPerTick;\n}\n"],"names":["ctx"],"mappings":"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"}
@@ -7,7 +7,7 @@ function mergeParentSubtrees(roots, data) {
7
7
  function getParentSubtrees(roots) {
8
8
  return roots.map((r) => {
9
9
  var _a, _b;
10
- if (!((_a = r.parents) == null ? void 0 : _a.length)) {
10
+ if (!((_a = r.parents) == null ? undefined : _a.length)) {
11
11
  return r;
12
12
  }
13
13
  const newRoot = {
@@ -28,7 +28,7 @@ function getParentSubtrees(roots) {
28
28
  newNode.value = args.child.value;
29
29
  args.child.parents = [newNode];
30
30
  }
31
- if ((_b = args.parent.parents) == null ? void 0 : _b.length) {
31
+ if ((_b = args.parent.parents) == null ? undefined : _b.length) {
32
32
  stack.push({ child: newNode, parent: args.parent.parents[0] });
33
33
  }
34
34
  }
@@ -40,7 +40,7 @@ function mergeSubtrees(roots, data, direction = "children") {
40
40
  const oppositeDirection = direction === "parents" ? "children" : "parents";
41
41
  const levels = [];
42
42
  const stack = [
43
- { previous: void 0, items: roots, level: 0 }
43
+ { previous: undefined, items: roots, level: 0 }
44
44
  ];
45
45
  while (stack.length) {
46
46
  const args = stack.shift();
@@ -59,7 +59,7 @@ function mergeSubtrees(roots, data, direction = "children") {
59
59
  levels[args.level].push(newItem);
60
60
  if (args.previous) {
61
61
  newItem[oppositeDirection] = [args.previous];
62
- const prevSiblingsVal = ((_a = args.previous[direction]) == null ? void 0 : _a.reduce((acc, node) => {
62
+ const prevSiblingsVal = ((_a = args.previous[direction]) == null ? undefined : _a.reduce((acc, node) => {
63
63
  return acc + node.value;
64
64
  }, 0)) || 0;
65
65
  newItem.start = args.previous.start + prevSiblingsVal;
@@ -1 +1 @@
1
- {"version":3,"file":"treeTransforms.js","sources":["../../../src/FlameGraph/treeTransforms.ts"],"sourcesContent":["import { groupBy } from 'lodash';\n\nimport { LevelItem } from './dataTransform';\n\ntype DataInterface = {\n getLabel: (index: number) => string;\n};\n\n// Merge parent subtree of the roots for the callers tree in the sandwich view of the flame graph.\nexport function mergeParentSubtrees(roots: LevelItem[], data: DataInterface): LevelItem[][] {\n const newRoots = getParentSubtrees(roots);\n return mergeSubtrees(newRoots, data, 'parents');\n}\n\n// Returns a subtrees per root that will have the parents resized to the same value as the root. When doing callers\n// tree we need to keep proper sizes of the parents, before we merge them, so we correctly attribute to the parents\n// only the value it contributed to the root.\n// So if we have something like:\n// [0/////////////]\n// [1//][4/////][6]\n// [2] [5/////]\n// [6] [6/][8/]\n// [7]\n// Taking all the node with '6' will create:\n// [0][0/]\n// [1][4/]\n// [2][5/][0]\n// [6][6/][6]\n// Which we can later merge.\nfunction getParentSubtrees(roots: LevelItem[]) {\n return roots.map((r) => {\n if (!r.parents?.length) {\n return r;\n }\n\n const newRoot = {\n ...r,\n children: [],\n };\n const stack: Array<{ child: undefined | LevelItem; parent: LevelItem }> = [\n { child: newRoot, parent: r.parents[0] },\n ];\n\n while (stack.length) {\n const args = stack.shift()!;\n const newNode = {\n ...args.parent,\n children: args.child ? [args.child] : [],\n parents: [],\n };\n\n if (args.child) {\n newNode.value = args.child.value;\n args.child.parents = [newNode];\n }\n\n if (args.parent.parents?.length) {\n stack.push({ child: newNode, parent: args.parent.parents[0] });\n }\n }\n return newRoot;\n });\n}\n\n// Merge subtrees into a single tree. Returns an array of levels for easy rendering. It assumes roots are mergeable,\n// meaning they represent the same unit of work (same label). Then we walk the tree in a specified direction,\n// merging nodes with the same label and same parent/child into single bigger node. This copies the tree (and all nodes)\n// as we are creating new merged nodes and modifying the parents/children.\nexport function mergeSubtrees(\n roots: LevelItem[],\n data: DataInterface,\n direction: 'parents' | 'children' = 'children'\n): LevelItem[][] {\n const oppositeDirection = direction === 'parents' ? 'children' : 'parents';\n const levels: LevelItem[][] = [];\n\n // Loop instead of recursion to be sure we don't blow stack size limit and save some memory. Each stack item is\n // basically a list of arrays you would pass to each level of recursion.\n const stack: Array<{ previous: undefined | LevelItem; items: LevelItem[]; level: number }> = [\n { previous: undefined, items: roots, level: 0 },\n ];\n\n while (stack.length) {\n const args = stack.shift()!;\n const indexes = args.items.flatMap((i) => i.itemIndexes);\n const newItem: LevelItem = {\n // We use the items value instead of value from the data frame, cause we could have changed it in the process\n value: args.items.reduce((acc, i) => acc + i.value, 0),\n itemIndexes: indexes,\n // these will change later\n children: [],\n parents: [],\n start: 0,\n level: args.level,\n };\n\n levels[args.level] = levels[args.level] || [];\n levels[args.level].push(newItem);\n\n if (args.previous) {\n // Not the first level, so we need to make sure we update previous items to keep the child/parent relationships\n // and compute correct new start offset for the item.\n newItem[oppositeDirection] = [args.previous];\n const prevSiblingsVal =\n args.previous[direction]?.reduce((acc, node) => {\n return acc + node.value;\n }, 0) || 0;\n newItem.start = args.previous.start + prevSiblingsVal;\n args.previous[direction]!.push(newItem);\n }\n\n const nextItems = args.items.flatMap((i) => i[direction] || []);\n // Group by label which for now is the only identifier by which we decide if node represents the same unit of work.\n const nextGroups = groupBy(nextItems, (c) => data.getLabel(c.itemIndexes[0]));\n for (const g of Object.values(nextGroups)) {\n stack.push({ previous: newItem, items: g, level: args.level + 1 });\n }\n }\n\n // Reverse the levels if we are doing callers tree, so we return levels in the correct order.\n if (direction === 'parents') {\n levels.reverse();\n levels.forEach((level, index) => {\n level.forEach((item) => {\n item.level = index;\n });\n });\n }\n\n return levels;\n}\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"treeTransforms.js","sources":["../../../src/FlameGraph/treeTransforms.ts"],"sourcesContent":["import { groupBy } from 'lodash';\n\nimport { LevelItem } from './dataTransform';\n\ntype DataInterface = {\n getLabel: (index: number) => string;\n};\n\n// Merge parent subtree of the roots for the callers tree in the sandwich view of the flame graph.\nexport function mergeParentSubtrees(roots: LevelItem[], data: DataInterface): LevelItem[][] {\n const newRoots = getParentSubtrees(roots);\n return mergeSubtrees(newRoots, data, 'parents');\n}\n\n// Returns a subtrees per root that will have the parents resized to the same value as the root. When doing callers\n// tree we need to keep proper sizes of the parents, before we merge them, so we correctly attribute to the parents\n// only the value it contributed to the root.\n// So if we have something like:\n// [0/////////////]\n// [1//][4/////][6]\n// [2] [5/////]\n// [6] [6/][8/]\n// [7]\n// Taking all the node with '6' will create:\n// [0][0/]\n// [1][4/]\n// [2][5/][0]\n// [6][6/][6]\n// Which we can later merge.\nfunction getParentSubtrees(roots: LevelItem[]) {\n return roots.map((r) => {\n if (!r.parents?.length) {\n return r;\n }\n\n const newRoot = {\n ...r,\n children: [],\n };\n const stack: Array<{ child: undefined | LevelItem; parent: LevelItem }> = [\n { child: newRoot, parent: r.parents[0] },\n ];\n\n while (stack.length) {\n const args = stack.shift()!;\n const newNode = {\n ...args.parent,\n children: args.child ? [args.child] : [],\n parents: [],\n };\n\n if (args.child) {\n newNode.value = args.child.value;\n args.child.parents = [newNode];\n }\n\n if (args.parent.parents?.length) {\n stack.push({ child: newNode, parent: args.parent.parents[0] });\n }\n }\n return newRoot;\n });\n}\n\n// Merge subtrees into a single tree. Returns an array of levels for easy rendering. It assumes roots are mergeable,\n// meaning they represent the same unit of work (same label). Then we walk the tree in a specified direction,\n// merging nodes with the same label and same parent/child into single bigger node. This copies the tree (and all nodes)\n// as we are creating new merged nodes and modifying the parents/children.\nexport function mergeSubtrees(\n roots: LevelItem[],\n data: DataInterface,\n direction: 'parents' | 'children' = 'children'\n): LevelItem[][] {\n const oppositeDirection = direction === 'parents' ? 'children' : 'parents';\n const levels: LevelItem[][] = [];\n\n // Loop instead of recursion to be sure we don't blow stack size limit and save some memory. Each stack item is\n // basically a list of arrays you would pass to each level of recursion.\n const stack: Array<{ previous: undefined | LevelItem; items: LevelItem[]; level: number }> = [\n { previous: undefined, items: roots, level: 0 },\n ];\n\n while (stack.length) {\n const args = stack.shift()!;\n const indexes = args.items.flatMap((i) => i.itemIndexes);\n const newItem: LevelItem = {\n // We use the items value instead of value from the data frame, cause we could have changed it in the process\n value: args.items.reduce((acc, i) => acc + i.value, 0),\n itemIndexes: indexes,\n // these will change later\n children: [],\n parents: [],\n start: 0,\n level: args.level,\n };\n\n levels[args.level] = levels[args.level] || [];\n levels[args.level].push(newItem);\n\n if (args.previous) {\n // Not the first level, so we need to make sure we update previous items to keep the child/parent relationships\n // and compute correct new start offset for the item.\n newItem[oppositeDirection] = [args.previous];\n const prevSiblingsVal =\n args.previous[direction]?.reduce((acc, node) => {\n return acc + node.value;\n }, 0) || 0;\n newItem.start = args.previous.start + prevSiblingsVal;\n args.previous[direction]!.push(newItem);\n }\n\n const nextItems = args.items.flatMap((i) => i[direction] || []);\n // Group by label which for now is the only identifier by which we decide if node represents the same unit of work.\n const nextGroups = groupBy(nextItems, (c) => data.getLabel(c.itemIndexes[0]));\n for (const g of Object.values(nextGroups)) {\n stack.push({ previous: newItem, items: g, level: args.level + 1 });\n }\n }\n\n // Reverse the levels if we are doing callers tree, so we return levels in the correct order.\n if (direction === 'parents') {\n levels.reverse();\n levels.forEach((level, index) => {\n level.forEach((item) => {\n item.level = index;\n });\n });\n }\n\n return levels;\n}\n"],"names":[],"mappings":"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"}
@@ -54,12 +54,12 @@ const FlameGraphContainer = ({
54
54
  }
55
55
  }, [selectedView, setSelectedView, containerWidth, vertical]);
56
56
  const resetFocus = useCallback(() => {
57
- setFocusedItemData(void 0);
57
+ setFocusedItemData(undefined);
58
58
  setRangeMin(0);
59
59
  setRangeMax(1);
60
60
  }, [setFocusedItemData, setRangeMax, setRangeMin]);
61
61
  const resetSandwich = useCallback(() => {
62
- setSandwichItem(void 0);
62
+ setSandwichItem(undefined);
63
63
  }, [setSandwichItem]);
64
64
  useEffect(() => {
65
65
  var _a;
@@ -69,7 +69,7 @@ const FlameGraphContainer = ({
69
69
  return;
70
70
  }
71
71
  if (dataContainer && focusedItemData) {
72
- const item = (_a = dataContainer.getNodesWithLabel(focusedItemData.label)) == null ? void 0 : _a[0];
72
+ const item = (_a = dataContainer.getNodesWithLabel(focusedItemData.label)) == null ? undefined : _a[0];
73
73
  if (item) {
74
74
  setFocusedItemData({ ...focusedItemData, item });
75
75
  const levels = dataContainer.getLevels();
@@ -97,7 +97,7 @@ const FlameGraphContainer = ({
97
97
  if (search === symbol) {
98
98
  setSearch("");
99
99
  } else {
100
- onTableSymbolClick == null ? void 0 : onTableSymbolClick(symbol);
100
+ onTableSymbolClick == null ? undefined : onTableSymbolClick(symbol);
101
101
  setSearch(symbol);
102
102
  resetFocus();
103
103
  }
@@ -180,7 +180,7 @@ const FlameGraphContainer = ({
180
180
  selectedView,
181
181
  setSelectedView: (view) => {
182
182
  setSelectedView(view);
183
- onViewSelected == null ? void 0 : onViewSelected(view);
183
+ onViewSelected == null ? undefined : onViewSelected(view);
184
184
  },
185
185
  containerWidth,
186
186
  onReset: () => {
@@ -190,7 +190,7 @@ const FlameGraphContainer = ({
190
190
  textAlign,
191
191
  onTextAlignChange: (align) => {
192
192
  setTextAlign(align);
193
- onTextAlignSelected == null ? void 0 : onTextAlignSelected(align);
193
+ onTextAlignSelected == null ? undefined : onTextAlignSelected(align);
194
194
  },
195
195
  showResetButton: Boolean(focusedItemData || sandwichItem),
196
196
  colorScheme,
@@ -208,7 +208,7 @@ const FlameGraphContainer = ({
208
208
  );
209
209
  };
210
210
  function useColorScheme(dataContainer) {
211
- const defaultColorScheme = (dataContainer == null ? void 0 : dataContainer.isDiffFlamegraph()) ? ColorSchemeDiff.Default : ColorScheme.PackageBased;
211
+ const defaultColorScheme = (dataContainer == null ? undefined : dataContainer.isDiffFlamegraph()) ? ColorSchemeDiff.Default : ColorScheme.PackageBased;
212
212
  const [colorScheme, setColorScheme] = useState(defaultColorScheme);
213
213
  useEffect(() => {
214
214
  setColorScheme(defaultColorScheme);
@@ -227,7 +227,7 @@ function useLabelSearch(search, data) {
227
227
  }
228
228
  return foundLabels;
229
229
  }
230
- return void 0;
230
+ return undefined;
231
231
  }, [search, data]);
232
232
  }
233
233
  function getStyles(theme) {
@@ -1 +1 @@
1
- {"version":3,"file":"FlameGraphContainer.js","sources":["../../src/FlameGraphContainer.tsx"],"sourcesContent":["import { css } from '@emotion/css';\nimport uFuzzy from '@leeoniya/ufuzzy';\nimport { useCallback, useEffect, useMemo, useState } from 'react';\nimport * as React from 'react';\nimport { useMeasure } from 'react-use';\n\nimport { DataFrame, GrafanaTheme2 } from '@grafana/data';\nimport { ThemeContext } from '@grafana/ui';\n\nimport FlameGraph from './FlameGraph/FlameGraph';\nimport { GetExtraContextMenuButtonsFunction } from './FlameGraph/FlameGraphContextMenu';\nimport { CollapsedMap, FlameGraphDataContainer } from './FlameGraph/dataTransform';\nimport FlameGraphHeader from './FlameGraphHeader';\nimport FlameGraphTopTableContainer from './TopTable/FlameGraphTopTableContainer';\nimport { MIN_WIDTH_TO_SHOW_BOTH_TOPTABLE_AND_FLAMEGRAPH } from './constants';\nimport { ClickedItemData, ColorScheme, ColorSchemeDiff, SelectedView, TextAlign } from './types';\n\nconst ufuzzy = new uFuzzy();\n\nexport type Props = {\n /**\n * DataFrame with the profile data. The dataFrame needs to have the following fields:\n * label: string - the label of the node\n * level: number - the nesting level of the node\n * value: number - the total value of the node\n * self: number - the self value of the node\n * Optionally if it represents diff of 2 different profiles it can also have fields:\n * valueRight: number - the total value of the node in the right profile\n * selfRight: number - the self value of the node in the right profile\n */\n data?: DataFrame;\n\n /**\n * Whether the header should be sticky and be always visible on the top when scrolling.\n */\n stickyHeader?: boolean;\n\n /**\n * Provides a theme for the visualization on which colors and some sizes are based.\n */\n getTheme: () => GrafanaTheme2;\n\n /**\n * Various interaction hooks that can be used to report on the interaction.\n */\n onTableSymbolClick?: (symbol: string) => void;\n onViewSelected?: (view: string) => void;\n onTextAlignSelected?: (align: string) => void;\n onTableSort?: (sort: string) => void;\n\n /**\n * Elements that will be shown in the header on the right side of the header buttons. Useful for additional\n * functionality.\n */\n extraHeaderElements?: React.ReactNode;\n\n /**\n * Extra buttons that will be shown in the context menu when user clicks on a Node.\n */\n getExtraContextMenuButtons?: GetExtraContextMenuButtonsFunction;\n\n /**\n * If true the flamegraph will be rendered on top of the table.\n */\n vertical?: boolean;\n\n /**\n * If true only the flamegraph will be rendered.\n */\n showFlameGraphOnly?: boolean;\n\n /**\n * Disable behaviour where similar items in the same stack will be collapsed into single item.\n */\n disableCollapsing?: boolean;\n /**\n * Whether or not to keep any focused item when the profile data changes.\n */\n keepFocusOnDataChange?: boolean;\n};\n\nconst FlameGraphContainer = ({\n data,\n onTableSymbolClick,\n onViewSelected,\n onTextAlignSelected,\n onTableSort,\n getTheme,\n stickyHeader,\n extraHeaderElements,\n vertical,\n showFlameGraphOnly,\n disableCollapsing,\n keepFocusOnDataChange,\n getExtraContextMenuButtons,\n}: Props) => {\n const [focusedItemData, setFocusedItemData] = useState<ClickedItemData>();\n\n const [rangeMin, setRangeMin] = useState(0);\n const [rangeMax, setRangeMax] = useState(1);\n const [search, setSearch] = useState('');\n const [selectedView, setSelectedView] = useState(SelectedView.Both);\n const [sizeRef, { width: containerWidth }] = useMeasure<HTMLDivElement>();\n const [textAlign, setTextAlign] = useState<TextAlign>('left');\n // This is a label of the item because in sandwich view we group all items by label and present a merged graph\n const [sandwichItem, setSandwichItem] = useState<string>();\n const [collapsedMap, setCollapsedMap] = useState(new CollapsedMap());\n\n const theme = useMemo(() => getTheme(), [getTheme]);\n const dataContainer = useMemo((): FlameGraphDataContainer | undefined => {\n if (!data) {\n return;\n }\n\n const container = new FlameGraphDataContainer(data, { collapsing: !disableCollapsing }, theme);\n setCollapsedMap(container.getCollapsedMap());\n return container;\n }, [data, theme, disableCollapsing]);\n const [colorScheme, setColorScheme] = useColorScheme(dataContainer);\n const styles = getStyles(theme);\n const matchedLabels = useLabelSearch(search, dataContainer);\n\n // If user resizes window with both as the selected view\n useEffect(() => {\n if (\n containerWidth > 0 &&\n containerWidth < MIN_WIDTH_TO_SHOW_BOTH_TOPTABLE_AND_FLAMEGRAPH &&\n selectedView === SelectedView.Both &&\n !vertical\n ) {\n setSelectedView(SelectedView.FlameGraph);\n }\n }, [selectedView, setSelectedView, containerWidth, vertical]);\n\n const resetFocus = useCallback(() => {\n setFocusedItemData(undefined);\n setRangeMin(0);\n setRangeMax(1);\n }, [setFocusedItemData, setRangeMax, setRangeMin]);\n\n const resetSandwich = useCallback(() => {\n setSandwichItem(undefined);\n }, [setSandwichItem]);\n\n useEffect(() => {\n if (!keepFocusOnDataChange) {\n resetFocus();\n resetSandwich();\n return;\n }\n\n if (dataContainer && focusedItemData) {\n const item = dataContainer.getNodesWithLabel(focusedItemData.label)?.[0];\n\n if (item) {\n setFocusedItemData({ ...focusedItemData, item });\n\n const levels = dataContainer.getLevels();\n const totalViewTicks = levels.length ? levels[0][0].value : 0;\n setRangeMin(item.start / totalViewTicks);\n setRangeMax((item.start + item.value) / totalViewTicks);\n } else {\n setFocusedItemData({\n ...focusedItemData,\n item: {\n start: 0,\n value: 0,\n itemIndexes: [],\n children: [],\n level: 0,\n },\n });\n\n setRangeMin(0);\n setRangeMax(1);\n }\n }\n }, [dataContainer, keepFocusOnDataChange]); // eslint-disable-line react-hooks/exhaustive-deps\n\n const onSymbolClick = useCallback(\n (symbol: string) => {\n if (search === symbol) {\n setSearch('');\n } else {\n onTableSymbolClick?.(symbol);\n setSearch(symbol);\n resetFocus();\n }\n },\n [setSearch, resetFocus, onTableSymbolClick, search]\n );\n\n if (!dataContainer) {\n return null;\n }\n\n const flameGraph = (\n <FlameGraph\n data={dataContainer}\n rangeMin={rangeMin}\n rangeMax={rangeMax}\n matchedLabels={matchedLabels}\n setRangeMin={setRangeMin}\n setRangeMax={setRangeMax}\n onItemFocused={(data) => setFocusedItemData(data)}\n focusedItemData={focusedItemData}\n textAlign={textAlign}\n sandwichItem={sandwichItem}\n onSandwich={(label: string) => {\n resetFocus();\n setSandwichItem(label);\n }}\n onFocusPillClick={resetFocus}\n onSandwichPillClick={resetSandwich}\n colorScheme={colorScheme}\n showFlameGraphOnly={showFlameGraphOnly}\n collapsing={!disableCollapsing}\n getExtraContextMenuButtons={getExtraContextMenuButtons}\n selectedView={selectedView}\n search={search}\n collapsedMap={collapsedMap}\n setCollapsedMap={setCollapsedMap}\n />\n );\n\n const table = (\n <FlameGraphTopTableContainer\n data={dataContainer}\n onSymbolClick={onSymbolClick}\n search={search}\n matchedLabels={matchedLabels}\n sandwichItem={sandwichItem}\n onSandwich={setSandwichItem}\n onSearch={setSearch}\n onTableSort={onTableSort}\n colorScheme={colorScheme}\n />\n );\n\n let body;\n if (showFlameGraphOnly || selectedView === SelectedView.FlameGraph) {\n body = flameGraph;\n } else if (selectedView === SelectedView.TopTable) {\n body = <div className={styles.tableContainer}>{table}</div>;\n } else if (selectedView === SelectedView.Both) {\n if (vertical) {\n body = (\n <div>\n <div className={styles.verticalGraphContainer}>{flameGraph}</div>\n <div className={styles.verticalTableContainer}>{table}</div>\n </div>\n );\n } else {\n body = (\n <div className={styles.horizontalContainer}>\n <div className={styles.horizontalTableContainer}>{table}</div>\n <div className={styles.horizontalGraphContainer}>{flameGraph}</div>\n </div>\n );\n }\n }\n\n return (\n // We add the theme context to bridge the gap if this is rendered in non grafana environment where the context\n // isn't already provided.\n <ThemeContext.Provider value={theme}>\n <div ref={sizeRef} className={styles.container}>\n {!showFlameGraphOnly && (\n <FlameGraphHeader\n search={search}\n setSearch={setSearch}\n selectedView={selectedView}\n setSelectedView={(view) => {\n setSelectedView(view);\n onViewSelected?.(view);\n }}\n containerWidth={containerWidth}\n onReset={() => {\n resetFocus();\n resetSandwich();\n }}\n textAlign={textAlign}\n onTextAlignChange={(align) => {\n setTextAlign(align);\n onTextAlignSelected?.(align);\n }}\n showResetButton={Boolean(focusedItemData || sandwichItem)}\n colorScheme={colorScheme}\n onColorSchemeChange={setColorScheme}\n stickyHeader={Boolean(stickyHeader)}\n extraHeaderElements={extraHeaderElements}\n vertical={vertical}\n isDiffMode={dataContainer.isDiffFlamegraph()}\n setCollapsedMap={setCollapsedMap}\n collapsedMap={collapsedMap}\n />\n )}\n\n <div className={styles.body}>{body}</div>\n </div>\n </ThemeContext.Provider>\n );\n};\n\nfunction useColorScheme(dataContainer: FlameGraphDataContainer | undefined) {\n const defaultColorScheme = dataContainer?.isDiffFlamegraph() ? ColorSchemeDiff.Default : ColorScheme.PackageBased;\n const [colorScheme, setColorScheme] = useState<ColorScheme | ColorSchemeDiff>(defaultColorScheme);\n\n // This makes sure that if we change the data to/from diff profile we reset the color scheme.\n useEffect(() => {\n setColorScheme(defaultColorScheme);\n }, [defaultColorScheme]);\n\n return [colorScheme, setColorScheme] as const;\n}\n\n/**\n * Based on the search string it does a fuzzy search over all the unique labels, so we can highlight them later.\n */\nfunction useLabelSearch(\n search: string | undefined,\n data: FlameGraphDataContainer | undefined\n): Set<string> | undefined {\n return useMemo(() => {\n if (search && data) {\n const foundLabels = new Set<string>();\n let idxs = ufuzzy.filter(data.getUniqueLabels(), search);\n\n if (idxs) {\n for (let idx of idxs) {\n foundLabels.add(data.getUniqueLabels()[idx]);\n }\n }\n\n return foundLabels;\n }\n // In this case undefined means there was no search so no attempt to highlighting anything should be made.\n return undefined;\n }, [search, data]);\n}\n\nfunction getStyles(theme: GrafanaTheme2) {\n return {\n container: css({\n label: 'container',\n overflow: 'auto',\n height: '100%',\n display: 'flex',\n flex: '1 1 0',\n flexDirection: 'column',\n minHeight: 0,\n gap: theme.spacing(1),\n }),\n body: css({\n label: 'body',\n flexGrow: 1,\n }),\n\n tableContainer: css({\n // This is not ideal for dashboard panel where it creates a double scroll. In a panel it should be 100% but then\n // in explore we need a specific height.\n height: 800,\n }),\n\n horizontalContainer: css({\n label: 'horizontalContainer',\n display: 'flex',\n minHeight: 0,\n flexDirection: 'row',\n columnGap: theme.spacing(1),\n width: '100%',\n }),\n\n horizontalGraphContainer: css({\n flexBasis: '50%',\n }),\n\n horizontalTableContainer: css({\n flexBasis: '50%',\n maxHeight: 800,\n }),\n\n verticalGraphContainer: css({\n marginBottom: theme.spacing(1),\n }),\n\n verticalTableContainer: css({\n height: 800,\n }),\n };\n}\n\nexport default FlameGraphContainer;\n"],"names":["data"],"mappings":"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"}
1
+ {"version":3,"file":"FlameGraphContainer.js","sources":["../../src/FlameGraphContainer.tsx"],"sourcesContent":["import { css } from '@emotion/css';\nimport uFuzzy from '@leeoniya/ufuzzy';\nimport { useCallback, useEffect, useMemo, useState } from 'react';\nimport * as React from 'react';\nimport { useMeasure } from 'react-use';\n\nimport { DataFrame, GrafanaTheme2 } from '@grafana/data';\nimport { ThemeContext } from '@grafana/ui';\n\nimport FlameGraph from './FlameGraph/FlameGraph';\nimport { GetExtraContextMenuButtonsFunction } from './FlameGraph/FlameGraphContextMenu';\nimport { CollapsedMap, FlameGraphDataContainer } from './FlameGraph/dataTransform';\nimport FlameGraphHeader from './FlameGraphHeader';\nimport FlameGraphTopTableContainer from './TopTable/FlameGraphTopTableContainer';\nimport { MIN_WIDTH_TO_SHOW_BOTH_TOPTABLE_AND_FLAMEGRAPH } from './constants';\nimport { ClickedItemData, ColorScheme, ColorSchemeDiff, SelectedView, TextAlign } from './types';\n\nconst ufuzzy = new uFuzzy();\n\nexport type Props = {\n /**\n * DataFrame with the profile data. The dataFrame needs to have the following fields:\n * label: string - the label of the node\n * level: number - the nesting level of the node\n * value: number - the total value of the node\n * self: number - the self value of the node\n * Optionally if it represents diff of 2 different profiles it can also have fields:\n * valueRight: number - the total value of the node in the right profile\n * selfRight: number - the self value of the node in the right profile\n */\n data?: DataFrame;\n\n /**\n * Whether the header should be sticky and be always visible on the top when scrolling.\n */\n stickyHeader?: boolean;\n\n /**\n * Provides a theme for the visualization on which colors and some sizes are based.\n */\n getTheme: () => GrafanaTheme2;\n\n /**\n * Various interaction hooks that can be used to report on the interaction.\n */\n onTableSymbolClick?: (symbol: string) => void;\n onViewSelected?: (view: string) => void;\n onTextAlignSelected?: (align: string) => void;\n onTableSort?: (sort: string) => void;\n\n /**\n * Elements that will be shown in the header on the right side of the header buttons. Useful for additional\n * functionality.\n */\n extraHeaderElements?: React.ReactNode;\n\n /**\n * Extra buttons that will be shown in the context menu when user clicks on a Node.\n */\n getExtraContextMenuButtons?: GetExtraContextMenuButtonsFunction;\n\n /**\n * If true the flamegraph will be rendered on top of the table.\n */\n vertical?: boolean;\n\n /**\n * If true only the flamegraph will be rendered.\n */\n showFlameGraphOnly?: boolean;\n\n /**\n * Disable behaviour where similar items in the same stack will be collapsed into single item.\n */\n disableCollapsing?: boolean;\n /**\n * Whether or not to keep any focused item when the profile data changes.\n */\n keepFocusOnDataChange?: boolean;\n};\n\nconst FlameGraphContainer = ({\n data,\n onTableSymbolClick,\n onViewSelected,\n onTextAlignSelected,\n onTableSort,\n getTheme,\n stickyHeader,\n extraHeaderElements,\n vertical,\n showFlameGraphOnly,\n disableCollapsing,\n keepFocusOnDataChange,\n getExtraContextMenuButtons,\n}: Props) => {\n const [focusedItemData, setFocusedItemData] = useState<ClickedItemData>();\n\n const [rangeMin, setRangeMin] = useState(0);\n const [rangeMax, setRangeMax] = useState(1);\n const [search, setSearch] = useState('');\n const [selectedView, setSelectedView] = useState(SelectedView.Both);\n const [sizeRef, { width: containerWidth }] = useMeasure<HTMLDivElement>();\n const [textAlign, setTextAlign] = useState<TextAlign>('left');\n // This is a label of the item because in sandwich view we group all items by label and present a merged graph\n const [sandwichItem, setSandwichItem] = useState<string>();\n const [collapsedMap, setCollapsedMap] = useState(new CollapsedMap());\n\n const theme = useMemo(() => getTheme(), [getTheme]);\n const dataContainer = useMemo((): FlameGraphDataContainer | undefined => {\n if (!data) {\n return;\n }\n\n const container = new FlameGraphDataContainer(data, { collapsing: !disableCollapsing }, theme);\n setCollapsedMap(container.getCollapsedMap());\n return container;\n }, [data, theme, disableCollapsing]);\n const [colorScheme, setColorScheme] = useColorScheme(dataContainer);\n const styles = getStyles(theme);\n const matchedLabels = useLabelSearch(search, dataContainer);\n\n // If user resizes window with both as the selected view\n useEffect(() => {\n if (\n containerWidth > 0 &&\n containerWidth < MIN_WIDTH_TO_SHOW_BOTH_TOPTABLE_AND_FLAMEGRAPH &&\n selectedView === SelectedView.Both &&\n !vertical\n ) {\n setSelectedView(SelectedView.FlameGraph);\n }\n }, [selectedView, setSelectedView, containerWidth, vertical]);\n\n const resetFocus = useCallback(() => {\n setFocusedItemData(undefined);\n setRangeMin(0);\n setRangeMax(1);\n }, [setFocusedItemData, setRangeMax, setRangeMin]);\n\n const resetSandwich = useCallback(() => {\n setSandwichItem(undefined);\n }, [setSandwichItem]);\n\n useEffect(() => {\n if (!keepFocusOnDataChange) {\n resetFocus();\n resetSandwich();\n return;\n }\n\n if (dataContainer && focusedItemData) {\n const item = dataContainer.getNodesWithLabel(focusedItemData.label)?.[0];\n\n if (item) {\n setFocusedItemData({ ...focusedItemData, item });\n\n const levels = dataContainer.getLevels();\n const totalViewTicks = levels.length ? levels[0][0].value : 0;\n setRangeMin(item.start / totalViewTicks);\n setRangeMax((item.start + item.value) / totalViewTicks);\n } else {\n setFocusedItemData({\n ...focusedItemData,\n item: {\n start: 0,\n value: 0,\n itemIndexes: [],\n children: [],\n level: 0,\n },\n });\n\n setRangeMin(0);\n setRangeMax(1);\n }\n }\n }, [dataContainer, keepFocusOnDataChange]); // eslint-disable-line react-hooks/exhaustive-deps\n\n const onSymbolClick = useCallback(\n (symbol: string) => {\n if (search === symbol) {\n setSearch('');\n } else {\n onTableSymbolClick?.(symbol);\n setSearch(symbol);\n resetFocus();\n }\n },\n [setSearch, resetFocus, onTableSymbolClick, search]\n );\n\n if (!dataContainer) {\n return null;\n }\n\n const flameGraph = (\n <FlameGraph\n data={dataContainer}\n rangeMin={rangeMin}\n rangeMax={rangeMax}\n matchedLabels={matchedLabels}\n setRangeMin={setRangeMin}\n setRangeMax={setRangeMax}\n onItemFocused={(data) => setFocusedItemData(data)}\n focusedItemData={focusedItemData}\n textAlign={textAlign}\n sandwichItem={sandwichItem}\n onSandwich={(label: string) => {\n resetFocus();\n setSandwichItem(label);\n }}\n onFocusPillClick={resetFocus}\n onSandwichPillClick={resetSandwich}\n colorScheme={colorScheme}\n showFlameGraphOnly={showFlameGraphOnly}\n collapsing={!disableCollapsing}\n getExtraContextMenuButtons={getExtraContextMenuButtons}\n selectedView={selectedView}\n search={search}\n collapsedMap={collapsedMap}\n setCollapsedMap={setCollapsedMap}\n />\n );\n\n const table = (\n <FlameGraphTopTableContainer\n data={dataContainer}\n onSymbolClick={onSymbolClick}\n search={search}\n matchedLabels={matchedLabels}\n sandwichItem={sandwichItem}\n onSandwich={setSandwichItem}\n onSearch={setSearch}\n onTableSort={onTableSort}\n colorScheme={colorScheme}\n />\n );\n\n let body;\n if (showFlameGraphOnly || selectedView === SelectedView.FlameGraph) {\n body = flameGraph;\n } else if (selectedView === SelectedView.TopTable) {\n body = <div className={styles.tableContainer}>{table}</div>;\n } else if (selectedView === SelectedView.Both) {\n if (vertical) {\n body = (\n <div>\n <div className={styles.verticalGraphContainer}>{flameGraph}</div>\n <div className={styles.verticalTableContainer}>{table}</div>\n </div>\n );\n } else {\n body = (\n <div className={styles.horizontalContainer}>\n <div className={styles.horizontalTableContainer}>{table}</div>\n <div className={styles.horizontalGraphContainer}>{flameGraph}</div>\n </div>\n );\n }\n }\n\n return (\n // We add the theme context to bridge the gap if this is rendered in non grafana environment where the context\n // isn't already provided.\n <ThemeContext.Provider value={theme}>\n <div ref={sizeRef} className={styles.container}>\n {!showFlameGraphOnly && (\n <FlameGraphHeader\n search={search}\n setSearch={setSearch}\n selectedView={selectedView}\n setSelectedView={(view) => {\n setSelectedView(view);\n onViewSelected?.(view);\n }}\n containerWidth={containerWidth}\n onReset={() => {\n resetFocus();\n resetSandwich();\n }}\n textAlign={textAlign}\n onTextAlignChange={(align) => {\n setTextAlign(align);\n onTextAlignSelected?.(align);\n }}\n showResetButton={Boolean(focusedItemData || sandwichItem)}\n colorScheme={colorScheme}\n onColorSchemeChange={setColorScheme}\n stickyHeader={Boolean(stickyHeader)}\n extraHeaderElements={extraHeaderElements}\n vertical={vertical}\n isDiffMode={dataContainer.isDiffFlamegraph()}\n setCollapsedMap={setCollapsedMap}\n collapsedMap={collapsedMap}\n />\n )}\n\n <div className={styles.body}>{body}</div>\n </div>\n </ThemeContext.Provider>\n );\n};\n\nfunction useColorScheme(dataContainer: FlameGraphDataContainer | undefined) {\n const defaultColorScheme = dataContainer?.isDiffFlamegraph() ? ColorSchemeDiff.Default : ColorScheme.PackageBased;\n const [colorScheme, setColorScheme] = useState<ColorScheme | ColorSchemeDiff>(defaultColorScheme);\n\n // This makes sure that if we change the data to/from diff profile we reset the color scheme.\n useEffect(() => {\n setColorScheme(defaultColorScheme);\n }, [defaultColorScheme]);\n\n return [colorScheme, setColorScheme] as const;\n}\n\n/**\n * Based on the search string it does a fuzzy search over all the unique labels, so we can highlight them later.\n */\nfunction useLabelSearch(\n search: string | undefined,\n data: FlameGraphDataContainer | undefined\n): Set<string> | undefined {\n return useMemo(() => {\n if (search && data) {\n const foundLabels = new Set<string>();\n let idxs = ufuzzy.filter(data.getUniqueLabels(), search);\n\n if (idxs) {\n for (let idx of idxs) {\n foundLabels.add(data.getUniqueLabels()[idx]);\n }\n }\n\n return foundLabels;\n }\n // In this case undefined means there was no search so no attempt to highlighting anything should be made.\n return undefined;\n }, [search, data]);\n}\n\nfunction getStyles(theme: GrafanaTheme2) {\n return {\n container: css({\n label: 'container',\n overflow: 'auto',\n height: '100%',\n display: 'flex',\n flex: '1 1 0',\n flexDirection: 'column',\n minHeight: 0,\n gap: theme.spacing(1),\n }),\n body: css({\n label: 'body',\n flexGrow: 1,\n }),\n\n tableContainer: css({\n // This is not ideal for dashboard panel where it creates a double scroll. In a panel it should be 100% but then\n // in explore we need a specific height.\n height: 800,\n }),\n\n horizontalContainer: css({\n label: 'horizontalContainer',\n display: 'flex',\n minHeight: 0,\n flexDirection: 'row',\n columnGap: theme.spacing(1),\n width: '100%',\n }),\n\n horizontalGraphContainer: css({\n flexBasis: '50%',\n }),\n\n horizontalTableContainer: css({\n flexBasis: '50%',\n maxHeight: 800,\n }),\n\n verticalGraphContainer: css({\n marginBottom: theme.spacing(1),\n }),\n\n verticalTableContainer: css({\n height: 800,\n }),\n };\n}\n\nexport default FlameGraphContainer;\n"],"names":["data"],"mappings":"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"}
@@ -61,7 +61,7 @@ const FlameGraphTopTableContainer = memo(
61
61
  initialSortBy: sort,
62
62
  onSortByChange: (s) => {
63
63
  if (s && s.length) {
64
- onTableSort == null ? void 0 : onTableSort(s[0].displayName + "_" + (s[0].desc ? "desc" : "asc"));
64
+ onTableSort == null ? undefined : onTableSort(s[0].displayName + "_" + (s[0].desc ? "desc" : "asc"));
65
65
  }
66
66
  setSort(s);
67
67
  },
@@ -111,7 +111,7 @@ function buildTableDataFrame(data, table, width, onSymbolClick, onSearch, onSand
111
111
  ];
112
112
  const levels = data.getLevels();
113
113
  const totalTicks = levels.length ? levels[0][0].value : 0;
114
- const totalTicksRight = levels.length ? levels[0][0].valueRight : void 0;
114
+ const totalTicksRight = levels.length ? levels[0][0].valueRight : undefined;
115
115
  for (let key in table) {
116
116
  actionField.values.push(null);
117
117
  symbolField.values.push(key);
@@ -206,7 +206,7 @@ function createActionField(onSandwich, onSearch, search, sandwichItem) {
206
206
  function ActionCell(props) {
207
207
  var _a;
208
208
  const styles = getStylesActionCell();
209
- const symbol = (_a = props.frame.fields.find((f) => f.name === "Symbol")) == null ? void 0 : _a.values[props.rowIndex];
209
+ const symbol = (_a = props.frame.fields.find((f) => f.name === "Symbol")) == null ? undefined : _a.values[props.rowIndex];
210
210
  const isSearched = props.search === symbol;
211
211
  const isSandwiched = props.sandwichItem === symbol;
212
212
  return /* @__PURE__ */ jsxs("div", { className: styles.actionCellWrapper, children: [
@@ -232,7 +232,7 @@ function ActionCell(props) {
232
232
  variant: isSandwiched ? "primary" : "secondary",
233
233
  "aria-label": isSandwiched ? "Remove from sandwich view" : "Show in sandwich view",
234
234
  onClick: () => {
235
- props.onSandwich(isSandwiched ? void 0 : symbol);
235
+ props.onSandwich(isSandwiched ? undefined : symbol);
236
236
  }
237
237
  }
238
238
  )
@@ -1 +1 @@
1
- {"version":3,"file":"FlameGraphTopTableContainer.js","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 DataFrame,\n DataLinkClickEvent,\n Field,\n FieldType,\n GrafanaTheme2,\n MappingType,\n} from '@grafana/data';\nimport {\n IconButton,\n Table,\n TableCellDisplayMode,\n TableCustomCellOptions,\n TableFieldOptions,\n TableSortByFieldState,\n useStyles2,\n useTheme2,\n} from '@grafana/ui';\n\nimport { diffColorBlindColors, diffDefaultColors } from '../FlameGraph/colors';\nimport { FlameGraphDataContainer } from '../FlameGraph/dataTransform';\nimport { TOP_TABLE_COLUMN_WIDTH } from '../constants';\nimport { ColorScheme, ColorSchemeDiff, 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(() => {\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 } = {};\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\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 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 return filteredTable;\n }, [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 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 === 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 default FlameGraphTopTableContainer;\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"FlameGraphTopTableContainer.js","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 DataFrame,\n DataLinkClickEvent,\n Field,\n FieldType,\n GrafanaTheme2,\n MappingType,\n} from '@grafana/data';\nimport {\n IconButton,\n Table,\n TableCellDisplayMode,\n TableCustomCellOptions,\n TableFieldOptions,\n TableSortByFieldState,\n useStyles2,\n useTheme2,\n} from '@grafana/ui';\n\nimport { diffColorBlindColors, diffDefaultColors } from '../FlameGraph/colors';\nimport { FlameGraphDataContainer } from '../FlameGraph/dataTransform';\nimport { TOP_TABLE_COLUMN_WIDTH } from '../constants';\nimport { ColorScheme, ColorSchemeDiff, 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(() => {\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 } = {};\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\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 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 return filteredTable;\n }, [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 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 === 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 default FlameGraphTopTableContainer;\n"],"names":[],"mappings":"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"}