{"version":3,"file":"FlameGraphContainer.mjs","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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"}