mirror of https://github.com/grafana/grafana
Timeline/Status grid panel: Add tooltip support (#35005)
* Timeline/Status grid tooltip support first pass * Tooltips workin * Use getValueFormat to get the duration * Separate boxes highlight from tooltip interpolation * Separate state timeline tooltip component, rely on field display color to retrieve color of series * create an onHover/onLeave API and optimize implementation Co-authored-by: Leon Sorokin <leeoniya@gmail.com>pull/34741/head^2
parent
180bff77a4
commit
7359ba44d0
@ -1,4 +1,4 @@ |
||||
export { VizTooltip, VizTooltipContentProps, VizTooltipProps, ActiveDimensions } from './VizTooltip'; |
||||
export { VizTooltipContainer, VizTooltipContainerProps } from './VizTooltipContainer'; |
||||
export { SeriesTable, SeriesTableProps, SeriesTableRowProps } from './SeriesTable'; |
||||
export { SeriesTable, SeriesTableRow, SeriesTableProps, SeriesTableRowProps } from './SeriesTable'; |
||||
export { TooltipDisplayMode, VizTooltipOptions } from './models.gen'; |
||||
|
@ -0,0 +1,85 @@ |
||||
import React from 'react'; |
||||
import { |
||||
DataFrame, |
||||
FALLBACK_COLOR, |
||||
formattedValueToString, |
||||
getDisplayProcessor, |
||||
getFieldDisplayName, |
||||
getValueFormat, |
||||
TimeZone, |
||||
} from '@grafana/data'; |
||||
import { SeriesTableRow, useTheme2 } from '@grafana/ui'; |
||||
import { findNextStateIndex } from './utils'; |
||||
|
||||
interface StateTimelineTooltipProps { |
||||
data: DataFrame[]; |
||||
alignedData: DataFrame; |
||||
seriesIdx: number; |
||||
datapointIdx: number; |
||||
timeZone: TimeZone; |
||||
} |
||||
|
||||
export const StateTimelineTooltip: React.FC<StateTimelineTooltipProps> = ({ |
||||
data, |
||||
alignedData, |
||||
seriesIdx, |
||||
datapointIdx, |
||||
timeZone, |
||||
}) => { |
||||
const theme = useTheme2(); |
||||
|
||||
const xField = alignedData.fields[0]; |
||||
const xFieldFmt = xField.display || getDisplayProcessor({ field: xField, timeZone, theme }); |
||||
|
||||
const field = alignedData.fields[seriesIdx!]; |
||||
const dataFrameFieldIndex = field.state?.origin; |
||||
const fieldFmt = field.display || getDisplayProcessor({ field, timeZone, theme }); |
||||
const value = field.values.get(datapointIdx!); |
||||
const display = fieldFmt(value); |
||||
const fieldDisplayName = dataFrameFieldIndex |
||||
? getFieldDisplayName( |
||||
data[dataFrameFieldIndex.frameIndex].fields[dataFrameFieldIndex.fieldIndex], |
||||
data[dataFrameFieldIndex.frameIndex], |
||||
data |
||||
) |
||||
: null; |
||||
|
||||
const nextStateIdx = findNextStateIndex(field, datapointIdx!); |
||||
let nextStateTs; |
||||
if (nextStateIdx) { |
||||
nextStateTs = xField.values.get(nextStateIdx!); |
||||
} |
||||
|
||||
const stateTs = xField.values.get(datapointIdx!); |
||||
|
||||
let toFragment = null; |
||||
let durationFragment = null; |
||||
|
||||
if (nextStateTs) { |
||||
const duration = nextStateTs && formattedValueToString(getValueFormat('dtdurationms')(nextStateTs - stateTs, 0)); |
||||
durationFragment = ( |
||||
<> |
||||
<br /> |
||||
<strong>Duration:</strong> {duration} |
||||
</> |
||||
); |
||||
toFragment = ( |
||||
<> |
||||
{' to'} <strong>{xFieldFmt(xField.values.get(nextStateIdx!)).text}</strong> |
||||
</> |
||||
); |
||||
} |
||||
|
||||
return ( |
||||
<div style={{ fontSize: theme.typography.bodySmall.fontSize }}> |
||||
{fieldDisplayName} |
||||
<br /> |
||||
<SeriesTableRow label={display.text} color={display.color || FALLBACK_COLOR} isActive /> |
||||
From <strong>{xFieldFmt(xField.values.get(datapointIdx!)).text}</strong> |
||||
{toFragment} |
||||
{durationFragment} |
||||
</div> |
||||
); |
||||
}; |
||||
|
||||
StateTimelineTooltip.displayName = 'StateTimelineTooltip'; |
Loading…
Reference in new issue