mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
Flamegraph: Add diff mode color legend (#87319)
This commit is contained in:
parent
526be4fa2b
commit
9c254c7e1e
@ -82,7 +82,7 @@ const FlameGraphMetadata = React.memo(
|
||||
);
|
||||
}
|
||||
|
||||
return <>{<div className={styles.metadata}>{parts}</div>}</>;
|
||||
return <div className={styles.metadata}>{parts}</div>;
|
||||
}
|
||||
);
|
||||
|
||||
|
@ -65,9 +65,9 @@ export function getBarColorByPackage(label: string, theme: GrafanaTheme2) {
|
||||
}
|
||||
|
||||
// green to red
|
||||
const diffDefaultColors = ['rgb(0, 170, 0)', 'rgb(148, 142, 142)', 'rgb(200, 0, 0)'];
|
||||
export const diffDefaultColors = ['rgb(0, 170, 0)', 'rgb(148, 142, 142)', 'rgb(200, 0, 0)'];
|
||||
export const diffDefaultGradient = `linear-gradient(90deg, ${diffDefaultColors[0]} 0%, ${diffDefaultColors[1]} 50%, ${diffDefaultColors[2]} 100%)`;
|
||||
const diffColorBlindColors = ['rgb(26, 133, 255)', 'rgb(148, 142, 142)', 'rgb(220, 50, 32)'];
|
||||
export const diffColorBlindColors = ['rgb(26, 133, 255)', 'rgb(148, 142, 142)', 'rgb(220, 50, 32)'];
|
||||
export const diffColorBlindGradient = `linear-gradient(90deg, ${diffColorBlindColors[0]} 0%, ${diffColorBlindColors[1]} 50%, ${diffColorBlindColors[2]} 100%)`;
|
||||
|
||||
export function getBarColorByDiff(
|
||||
|
@ -192,6 +192,7 @@ const FlameGraphContainer = ({
|
||||
onSandwich={setSandwichItem}
|
||||
onSearch={setSearch}
|
||||
onTableSort={onTableSort}
|
||||
colorScheme={colorScheme}
|
||||
/>
|
||||
);
|
||||
|
||||
|
@ -129,15 +129,6 @@ function ColorSchemeButton(props: ColorSchemeButtonProps) {
|
||||
</Menu>
|
||||
);
|
||||
|
||||
if (props.isDiffMode) {
|
||||
menu = (
|
||||
<Menu>
|
||||
<Menu.Item label="Default (green to red)" onClick={() => props.onChange(ColorSchemeDiff.Default)} />
|
||||
<Menu.Item label="Color blind (blue to red)" onClick={() => props.onChange(ColorSchemeDiff.DiffColorBlind)} />
|
||||
</Menu>
|
||||
);
|
||||
}
|
||||
|
||||
// Show a bit different gradient as a way to indicate selected value
|
||||
const colorDotStyle =
|
||||
{
|
||||
@ -147,6 +138,25 @@ function ColorSchemeButton(props: ColorSchemeButtonProps) {
|
||||
[ColorSchemeDiff.Default]: styles.colorDotDiffDefault,
|
||||
}[props.value] || styles.colorDotByValue;
|
||||
|
||||
let contents = <span className={cx(styles.colorDot, colorDotStyle)} />;
|
||||
|
||||
if (props.isDiffMode) {
|
||||
menu = (
|
||||
<Menu>
|
||||
<Menu.Item label="Default (green to red)" onClick={() => props.onChange(ColorSchemeDiff.Default)} />
|
||||
<Menu.Item label="Color blind (blue to red)" onClick={() => props.onChange(ColorSchemeDiff.DiffColorBlind)} />
|
||||
</Menu>
|
||||
);
|
||||
|
||||
contents = (
|
||||
<div className={cx(styles.colorDotDiff, colorDotStyle)}>
|
||||
<div>-100% (removed)</div>
|
||||
<div>0%</div>
|
||||
<div>+100% (added)</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<Dropdown overlay={menu}>
|
||||
<Button
|
||||
@ -158,7 +168,7 @@ function ColorSchemeButton(props: ColorSchemeButtonProps) {
|
||||
className={styles.buttonSpacing}
|
||||
aria-label={'Change color scheme'}
|
||||
>
|
||||
<span className={cx(styles.colorDot, colorDotStyle)} />
|
||||
{contents}
|
||||
</Button>
|
||||
</Dropdown>
|
||||
);
|
||||
@ -221,17 +231,16 @@ const getStyles = (theme: GrafanaTheme2) => ({
|
||||
justifyContent: 'space-between',
|
||||
width: '100%',
|
||||
top: 0,
|
||||
gap: theme.spacing(1),
|
||||
marginTop: theme.spacing(1),
|
||||
}),
|
||||
stickyHeader: css({
|
||||
zIndex: theme.zIndex.navbarFixed,
|
||||
position: 'sticky',
|
||||
paddingBottom: theme.spacing(1),
|
||||
paddingTop: theme.spacing(1),
|
||||
background: theme.colors.background.primary,
|
||||
}),
|
||||
inputContainer: css({
|
||||
label: 'inputContainer',
|
||||
marginRight: '20px',
|
||||
flexGrow: 1,
|
||||
minWidth: '150px',
|
||||
maxWidth: '350px',
|
||||
@ -264,6 +273,21 @@ const getStyles = (theme: GrafanaTheme2) => ({
|
||||
// eslint-disable-next-line @grafana/no-border-radius-literal
|
||||
borderRadius: '50%',
|
||||
}),
|
||||
colorDotDiff: css({
|
||||
label: 'colorDotDiff',
|
||||
display: 'flex',
|
||||
width: '200px',
|
||||
height: '12px',
|
||||
color: 'white',
|
||||
fontSize: 9,
|
||||
lineHeight: 1.3,
|
||||
fontWeight: 300,
|
||||
justifyContent: 'space-between',
|
||||
padding: '0 2px',
|
||||
// We have a specific sizing for this so probably makes sense to use hardcoded value here
|
||||
// eslint-disable-next-line @grafana/no-border-radius-literal
|
||||
borderRadius: '2px',
|
||||
}),
|
||||
colorDotByValue: css({
|
||||
label: 'colorDotByValue',
|
||||
background: byValueGradient,
|
||||
|
@ -6,6 +6,7 @@ import { createDataFrame } from '@grafana/data';
|
||||
|
||||
import { FlameGraphDataContainer } from '../FlameGraph/dataTransform';
|
||||
import { data } from '../FlameGraph/testData/dataNestedSet';
|
||||
import { ColorScheme } from '../types';
|
||||
|
||||
import FlameGraphTopTableContainer from './FlameGraphTopTableContainer';
|
||||
|
||||
@ -22,6 +23,7 @@ describe('FlameGraphTopTableContainer', () => {
|
||||
onSymbolClick={jest.fn()}
|
||||
onSearch={onSearch}
|
||||
onSandwich={onSandwich}
|
||||
colorScheme={ColorScheme.ValueBased}
|
||||
/>
|
||||
);
|
||||
|
||||
|
@ -22,9 +22,10 @@ import {
|
||||
useTheme2,
|
||||
} from '@grafana/ui';
|
||||
|
||||
import { diffColorBlindColors, diffDefaultColors } from '../FlameGraph/colors';
|
||||
import { FlameGraphDataContainer } from '../FlameGraph/dataTransform';
|
||||
import { TOP_TABLE_COLUMN_WIDTH } from '../constants';
|
||||
import { TableData } from '../types';
|
||||
import { ColorScheme, ColorSchemeDiff, TableData } from '../types';
|
||||
|
||||
type Props = {
|
||||
data: FlameGraphDataContainer;
|
||||
@ -37,10 +38,21 @@ type Props = {
|
||||
onSearch: (str: string) => void;
|
||||
onSandwich: (str?: string) => void;
|
||||
onTableSort?: (sort: string) => void;
|
||||
colorScheme: ColorScheme | ColorSchemeDiff;
|
||||
};
|
||||
|
||||
const FlameGraphTopTableContainer = React.memo(
|
||||
({ data, onSymbolClick, search, matchedLabels, onSearch, sandwichItem, onSandwich, onTableSort }: Props) => {
|
||||
({
|
||||
data,
|
||||
onSymbolClick,
|
||||
search,
|
||||
matchedLabels,
|
||||
onSearch,
|
||||
sandwichItem,
|
||||
onSandwich,
|
||||
onTableSort,
|
||||
colorScheme,
|
||||
}: Props) => {
|
||||
const table = useMemo(() => {
|
||||
// Group the data by label, we show only one row per label and sum the values
|
||||
// TODO: should be by filename + funcName + linenumber?
|
||||
@ -51,7 +63,7 @@ const FlameGraphTopTableContainer = React.memo(
|
||||
const self = data.getSelf(i);
|
||||
const label = data.getLabel(i);
|
||||
|
||||
// If user is doing text search we filter out labels in the same way we highlight them in flamegraph.
|
||||
// If user is doing text search we filter out labels in the same way we highlight them in flame graph.
|
||||
if (!matchedLabels || matchedLabels.has(label)) {
|
||||
filteredTable[label] = filteredTable[label] || {};
|
||||
filteredTable[label].self = filteredTable[label].self ? filteredTable[label].self + self : self;
|
||||
@ -85,6 +97,7 @@ const FlameGraphTopTableContainer = React.memo(
|
||||
onSearch,
|
||||
onSandwich,
|
||||
theme,
|
||||
colorScheme,
|
||||
search,
|
||||
sandwichItem
|
||||
);
|
||||
@ -119,6 +132,7 @@ function buildTableDataFrame(
|
||||
onSearch: (str: string) => void,
|
||||
onSandwich: (str?: string) => void,
|
||||
theme: GrafanaTheme2,
|
||||
colorScheme: ColorScheme | ColorSchemeDiff,
|
||||
search?: string,
|
||||
sandwichItem?: string
|
||||
): DataFrame {
|
||||
@ -153,11 +167,17 @@ function buildTableDataFrame(
|
||||
const comparisonField = createNumberField('Comparison', 'percent');
|
||||
const diffField = createNumberField('Diff', 'percent');
|
||||
diffField.config.custom.cellOptions.type = TableCellDisplayMode.ColorText;
|
||||
|
||||
const [removeColor, addColor] =
|
||||
colorScheme === ColorSchemeDiff.DiffColorBlind
|
||||
? [diffColorBlindColors[0], diffColorBlindColors[2]]
|
||||
: [diffDefaultColors[0], diffDefaultColors[2]];
|
||||
|
||||
diffField.config.mappings = [
|
||||
{ type: MappingType.ValueToText, options: { [Infinity]: { text: 'new', color: 'red' } } },
|
||||
{ type: MappingType.ValueToText, options: { [-100]: { text: 'removed', color: 'green' } } },
|
||||
{ type: MappingType.RangeToText, options: { from: 0, to: Infinity, result: { color: 'red' } } },
|
||||
{ type: MappingType.RangeToText, options: { from: -Infinity, to: 0, result: { color: 'green' } } },
|
||||
{ type: MappingType.ValueToText, options: { [Infinity]: { text: 'new', color: addColor } } },
|
||||
{ type: MappingType.ValueToText, options: { [-100]: { text: 'removed', color: removeColor } } },
|
||||
{ type: MappingType.RangeToText, options: { from: 0, to: Infinity, result: { color: addColor } } },
|
||||
{ type: MappingType.RangeToText, options: { from: -Infinity, to: 0, result: { color: removeColor } } },
|
||||
];
|
||||
|
||||
// For this we don't really consider sandwich view even though you can switch it on.
|
||||
|
Loading…
Reference in New Issue
Block a user