StatusHistory: Add tooltip multi mode (#78703)

This commit is contained in:
Adela Almasan 2023-11-28 15:23:05 -06:00 committed by GitHub
parent a5377f85ce
commit a6c9a9db92
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 117 additions and 30 deletions

View File

@ -20,7 +20,7 @@ export const VizTooltipContent = ({ contentLabelValue, customContent }: Props) =
<div className={styles.wrapper}>
<div>
{contentLabelValue?.map((labelValue, i) => {
const { label, value, color, colorIndicator } = labelValue;
const { label, value, color, colorIndicator, colorPlacement, isActive } = labelValue;
return (
<VizTooltipRow
key={i}
@ -28,7 +28,9 @@ export const VizTooltipContent = ({ contentLabelValue, customContent }: Props) =
value={value}
color={color}
colorIndicator={colorIndicator}
colorPlacement={colorPlacement}
colorFirst={false}
isActive={isActive}
justify={'space-between'}
/>
);

View File

@ -7,7 +7,7 @@ import { useStyles2 } from '../../themes';
import { Tooltip } from '../Tooltip';
import { VizTooltipColorIndicator } from './VizTooltipColorIndicator';
import { LabelValue } from './types';
import { ColorPlacement, LabelValue } from './types';
interface Props extends LabelValue {
justify?: string;
@ -21,6 +21,7 @@ export const VizTooltipRow = ({
value,
color,
colorIndicator,
colorPlacement = ColorPlacement.leading,
justify = 'flex-start',
colorFirst = true,
isActive = false,
@ -65,12 +66,20 @@ export const VizTooltipRow = ({
)}
<div className={styles.valueWrapper}>
{color && !colorFirst && <VizTooltipColorIndicator color={color} colorIndicator={colorIndicator!} />}
{color && !colorFirst && colorPlacement === ColorPlacement.leading && (
<VizTooltipColorIndicator color={color} colorIndicator={colorIndicator!} />
)}
<Tooltip content={value ? value.toString() : ''} interactive={false} show={showValueTooltip}>
<div className={cx(styles.value, isActive)} onMouseEnter={onMouseEnterValue} onMouseLeave={onMouseLeaveValue}>
{value}
</div>
</Tooltip>
{color && !colorFirst && colorPlacement === ColorPlacement.trailing && (
<>
&nbsp;
<VizTooltipColorIndicator color={color} colorIndicator={colorIndicator!} />
</>
)}
</div>
</div>
);

View File

@ -10,7 +10,7 @@ export enum ColorIndicator {
marker_lg = 'marker_lg',
}
export enum LabelValuePlacement {
export enum ColorPlacement {
hidden = 'hidden',
leading = 'leading',
trailing = 'trailing',
@ -21,4 +21,6 @@ export interface LabelValue {
value: string | number | null;
color?: string;
colorIndicator?: ColorIndicator;
colorPlacement?: ColorPlacement;
isActive?: boolean;
}

View File

@ -233,6 +233,8 @@ export const StatusHistoryPanel = ({
alignedData={alignedFrame}
seriesIdx={seriesIdx}
timeZone={timeZone}
mode={options.tooltip.mode}
sortOrder={options.tooltip.sort}
isPinned={isPinned}
/>
);

View File

@ -10,12 +10,17 @@ import {
GrafanaTheme2,
TimeZone,
LinkModel,
FieldType,
arrayUtils,
} from '@grafana/data';
import { SortOrder, TooltipDisplayMode } from '@grafana/schema';
import { useStyles2 } from '@grafana/ui';
import { VizTooltipContent } from '@grafana/ui/src/components/VizTooltip/VizTooltipContent';
import { VizTooltipFooter } from '@grafana/ui/src/components/VizTooltip/VizTooltipFooter';
import { VizTooltipHeader } from '@grafana/ui/src/components/VizTooltip/VizTooltipHeader';
import { LabelValue } from '@grafana/ui/src/components/VizTooltip/types';
import { ColorIndicator, ColorPlacement, LabelValue } from '@grafana/ui/src/components/VizTooltip/types';
import { getDataLinks } from './utils';
interface StatusHistoryTooltipProps {
data: DataFrame[];
@ -24,6 +29,8 @@ interface StatusHistoryTooltipProps {
seriesIdx: number | null | undefined;
timeZone: TimeZone;
isPinned: boolean;
mode?: TooltipDisplayMode;
sortOrder?: SortOrder;
}
function fmt(field: Field, val: number): string {
@ -39,7 +46,8 @@ export const StatusHistoryTooltip2 = ({
dataIdxs,
alignedData,
seriesIdx,
timeZone,
mode = TooltipDisplayMode.Single,
sortOrder = SortOrder.None,
isPinned,
}: StatusHistoryTooltipProps) => {
const styles = useStyles2(getStyles);
@ -51,28 +59,77 @@ export const StatusHistoryTooltip2 = ({
return null;
}
let contentLabelValue: LabelValue[] = [];
const xField = alignedData.fields[0];
let links: Array<LinkModel<Field>> = [];
// Single mode
if (mode === TooltipDisplayMode.Single || isPinned) {
const field = alignedData.fields[seriesIdx!];
const links: Array<LinkModel<Field>> = [];
const linkLookup = new Set<string>();
if (field.getLinks) {
const v = field.values[datapointIdx];
const disp = field.display ? field.display(v) : { text: `${v}`, numeric: +v };
field.getLinks({ calculatedValue: disp, valueRowIndex: datapointIdx }).forEach((link) => {
const key = `${link.title}/${link.href}`;
if (!linkLookup.has(key)) {
links.push(link);
linkLookup.add(key);
}
});
}
links = getDataLinks(field, datapointIdx);
const fieldFmt = field.display || getDisplayProcessor();
const value = field.values[datapointIdx!];
const display = fieldFmt(value);
contentLabelValue = [
{
label: getFieldDisplayName(field),
value: fmt(field, field.values[datapointIdx]),
color: display.color,
colorIndicator: ColorIndicator.value,
colorPlacement: ColorPlacement.trailing,
},
];
}
if (mode === TooltipDisplayMode.Multi && !isPinned) {
const frame = alignedData;
const fields = frame.fields;
const sortIdx: unknown[] = [];
for (let i = 0; i < fields.length; i++) {
const field = frame.fields[i];
if (
!field ||
field === xField ||
field.type === FieldType.time ||
field.config.custom?.hideFrom?.tooltip ||
field.config.custom?.hideFrom?.viz
) {
continue;
}
const fieldFmt = field.display || getDisplayProcessor();
const v = field.values[datapointIdx!];
const display = fieldFmt(v);
sortIdx.push(v);
contentLabelValue.push({
label: getFieldDisplayName(field),
value: fmt(field, field.values[datapointIdx]),
color: display.color,
colorIndicator: ColorIndicator.value,
colorPlacement: ColorPlacement.trailing,
isActive: seriesIdx === i,
});
}
if (sortOrder !== SortOrder.None) {
// create sort reference series array, as Array.sort() mutates the original array
const sortRef = [...contentLabelValue];
const sortFn = arrayUtils.sortValues(sortOrder);
contentLabelValue.sort((a, b) => {
// get compared values indices to retrieve raw values from sortIdx
const aIdx = sortRef.indexOf(a);
const bIdx = sortRef.indexOf(b);
return sortFn(sortIdx[aIdx], sortIdx[bIdx]);
});
}
}
const getHeaderLabel = (): LabelValue => {
return {
label: '',
@ -81,13 +138,7 @@ export const StatusHistoryTooltip2 = ({
};
const getContentLabelValue = () => {
return [
{
label: getFieldDisplayName(field),
value: fmt(field, field.values[datapointIdx]),
color: display.color,
},
];
return contentLabelValue;
};
return (

View File

@ -1,4 +1,5 @@
import { FieldColorModeId, FieldConfigProperty, PanelPlugin } from '@grafana/data';
import { config } from '@grafana/runtime';
import { VisibilityMode } from '@grafana/schema';
import { commonOptionsBuilder } from '@grafana/ui';
@ -80,6 +81,6 @@ export const plugin = new PanelPlugin<Options, FieldConfig>(StatusHistoryPanel)
});
commonOptionsBuilder.addLegendOptions(builder, false);
commonOptionsBuilder.addTooltipOptions(builder, true);
commonOptionsBuilder.addTooltipOptions(builder, !config.featureToggles.newVizTooltips);
})
.setSuggestionsSupplier(new StatusHistorySuggestionsSupplier());

View File

@ -0,0 +1,20 @@
import { Field, LinkModel } from '@grafana/data';
export const getDataLinks = (field: Field, datapointIdx: number) => {
const links: Array<LinkModel<Field>> = [];
const linkLookup = new Set<string>();
if (field.getLinks) {
const v = field.values[datapointIdx];
const disp = field.display ? field.display(v) : { text: `${v}`, numeric: +v };
field.getLinks({ calculatedValue: disp, valueRowIndex: datapointIdx }).forEach((link) => {
const key = `${link.title}/${link.href}`;
if (!linkLookup.has(key)) {
links.push(link);
linkLookup.add(key);
}
});
}
return links;
};