mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
StateTimeline: Fix tooltip showing erroneously in shared crosshair dashboards (#55809)
* StateTimeline: Fix shared crosshair * Fix for StatusHistory also
This commit is contained in:
parent
21d9cf0db4
commit
b622a87aee
@ -1,6 +1,6 @@
|
|||||||
import { Dispatch, MutableRefObject, SetStateAction } from 'react';
|
import { Dispatch, MutableRefObject, SetStateAction } from 'react';
|
||||||
|
|
||||||
import { CartesianCoords2D } from '@grafana/data';
|
import { CartesianCoords2D, DashboardCursorSync } from '@grafana/data';
|
||||||
|
|
||||||
import { positionTooltip } from '../plugins/TooltipPlugin';
|
import { positionTooltip } from '../plugins/TooltipPlugin';
|
||||||
|
|
||||||
@ -21,6 +21,9 @@ type SetupConfigParams = {
|
|||||||
setCoords: Dispatch<SetStateAction<{ viewport: CartesianCoords2D; canvas: CartesianCoords2D } | null>>;
|
setCoords: Dispatch<SetStateAction<{ viewport: CartesianCoords2D; canvas: CartesianCoords2D } | null>>;
|
||||||
setHover: Dispatch<SetStateAction<HoverEvent | undefined>>;
|
setHover: Dispatch<SetStateAction<HoverEvent | undefined>>;
|
||||||
isToolTipOpen: MutableRefObject<boolean>;
|
isToolTipOpen: MutableRefObject<boolean>;
|
||||||
|
isActive: boolean;
|
||||||
|
setIsActive: Dispatch<SetStateAction<boolean>>;
|
||||||
|
sync?: (() => DashboardCursorSync) | undefined;
|
||||||
};
|
};
|
||||||
|
|
||||||
// This applies config hooks to setup tooltip listener. Ideally this could happen in the same `prepConfig` function
|
// This applies config hooks to setup tooltip listener. Ideally this could happen in the same `prepConfig` function
|
||||||
@ -33,13 +36,26 @@ export const addTooltipSupport = ({
|
|||||||
setCoords,
|
setCoords,
|
||||||
setHover,
|
setHover,
|
||||||
isToolTipOpen,
|
isToolTipOpen,
|
||||||
|
isActive,
|
||||||
|
setIsActive,
|
||||||
|
sync,
|
||||||
}: SetupConfigParams): UPlotConfigBuilder => {
|
}: SetupConfigParams): UPlotConfigBuilder => {
|
||||||
// Ensure tooltip is closed on config changes
|
// Ensure tooltip is closed on config changes
|
||||||
isToolTipOpen.current = false;
|
isToolTipOpen.current = false;
|
||||||
|
|
||||||
|
const onMouseEnter = () => {
|
||||||
|
if (setIsActive) {
|
||||||
|
setIsActive(true);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
const onMouseLeave = () => {
|
const onMouseLeave = () => {
|
||||||
if (!isToolTipOpen.current) {
|
if (!isToolTipOpen.current) {
|
||||||
setCoords(null);
|
setCoords(null);
|
||||||
|
|
||||||
|
if (setIsActive) {
|
||||||
|
setIsActive(false);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -50,6 +66,11 @@ export const addTooltipSupport = ({
|
|||||||
ref_over = u.over;
|
ref_over = u.over;
|
||||||
ref_parent?.addEventListener('click', onUPlotClick);
|
ref_parent?.addEventListener('click', onUPlotClick);
|
||||||
ref_over.addEventListener('mouseleave', onMouseLeave);
|
ref_over.addEventListener('mouseleave', onMouseLeave);
|
||||||
|
ref_over.addEventListener('mouseenter', onMouseEnter);
|
||||||
|
|
||||||
|
if (sync && sync() === DashboardCursorSync.Crosshair) {
|
||||||
|
u.root.classList.add('shared-crosshair');
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
const clearPopupIfOpened = () => {
|
const clearPopupIfOpened = () => {
|
||||||
@ -64,6 +85,7 @@ export const addTooltipSupport = ({
|
|||||||
config.addHook('destroy', () => {
|
config.addHook('destroy', () => {
|
||||||
ref_parent?.removeEventListener('click', onUPlotClick);
|
ref_parent?.removeEventListener('click', onUPlotClick);
|
||||||
ref_over?.removeEventListener('mouseleave', onMouseLeave);
|
ref_over?.removeEventListener('mouseleave', onMouseLeave);
|
||||||
|
ref_over?.removeEventListener('mouseenter', onMouseEnter);
|
||||||
clearPopupIfOpened();
|
clearPopupIfOpened();
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -84,7 +106,7 @@ export const addTooltipSupport = ({
|
|||||||
setFocusedSeriesIdx,
|
setFocusedSeriesIdx,
|
||||||
setFocusedPointIdx,
|
setFocusedPointIdx,
|
||||||
(clear) => {
|
(clear) => {
|
||||||
if (clear) {
|
if (clear && isActive) {
|
||||||
setCoords(null);
|
setCoords(null);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -104,7 +126,7 @@ export const addTooltipSupport = ({
|
|||||||
}
|
}
|
||||||
|
|
||||||
config.addHook('setLegend', (u) => {
|
config.addHook('setLegend', (u) => {
|
||||||
if (!isToolTipOpen.current && !tooltipInterpolator) {
|
if (!isToolTipOpen.current) {
|
||||||
setFocusedPointIdx(u.legend.idx!);
|
setFocusedPointIdx(u.legend.idx!);
|
||||||
}
|
}
|
||||||
if (u.cursor.idxs != null) {
|
if (u.cursor.idxs != null) {
|
||||||
|
@ -82,6 +82,7 @@ export const BarChartPanel: React.FunctionComponent<Props> = ({
|
|||||||
const [coords, setCoords] = useState<{ viewport: CartesianCoords2D; canvas: CartesianCoords2D } | null>(null);
|
const [coords, setCoords] = useState<{ viewport: CartesianCoords2D; canvas: CartesianCoords2D } | null>(null);
|
||||||
const [focusedSeriesIdx, setFocusedSeriesIdx] = useState<number | null>(null);
|
const [focusedSeriesIdx, setFocusedSeriesIdx] = useState<number | null>(null);
|
||||||
const [focusedPointIdx, setFocusedPointIdx] = useState<number | null>(null);
|
const [focusedPointIdx, setFocusedPointIdx] = useState<number | null>(null);
|
||||||
|
const [isActive, setIsActive] = useState<boolean>(false);
|
||||||
const [shouldDisplayCloseButton, setShouldDisplayCloseButton] = useState<boolean>(false);
|
const [shouldDisplayCloseButton, setShouldDisplayCloseButton] = useState<boolean>(false);
|
||||||
|
|
||||||
const onCloseToolTip = () => {
|
const onCloseToolTip = () => {
|
||||||
@ -298,6 +299,8 @@ export const BarChartPanel: React.FunctionComponent<Props> = ({
|
|||||||
setCoords,
|
setCoords,
|
||||||
setHover,
|
setHover,
|
||||||
isToolTipOpen,
|
isToolTipOpen,
|
||||||
|
isActive,
|
||||||
|
setIsActive,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -307,7 +310,7 @@ export const BarChartPanel: React.FunctionComponent<Props> = ({
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<Portal>
|
<Portal>
|
||||||
{hover && coords && (
|
{hover && coords && focusedSeriesIdx && (
|
||||||
<VizTooltipContainer
|
<VizTooltipContainer
|
||||||
position={{ x: coords.viewport.x, y: coords.viewport.y }}
|
position={{ x: coords.viewport.x, y: coords.viewport.y }}
|
||||||
offset={{ x: TOOLTIP_OFFSET, y: TOOLTIP_OFFSET }}
|
offset={{ x: TOOLTIP_OFFSET, y: TOOLTIP_OFFSET }}
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import React, { useCallback, useMemo, useRef, useState } from 'react';
|
import React, { useCallback, useMemo, useRef, useState } from 'react';
|
||||||
|
|
||||||
import { CartesianCoords2D, DataFrame, FieldType, PanelProps } from '@grafana/data';
|
import { CartesianCoords2D, DashboardCursorSync, DataFrame, FieldType, PanelProps } from '@grafana/data';
|
||||||
import {
|
import {
|
||||||
Portal,
|
Portal,
|
||||||
TooltipDisplayMode,
|
TooltipDisplayMode,
|
||||||
@ -50,8 +50,9 @@ export const StateTimelinePanel: React.FC<TimelinePanelProps> = ({
|
|||||||
const [coords, setCoords] = useState<{ viewport: CartesianCoords2D; canvas: CartesianCoords2D } | null>(null);
|
const [coords, setCoords] = useState<{ viewport: CartesianCoords2D; canvas: CartesianCoords2D } | null>(null);
|
||||||
const [focusedSeriesIdx, setFocusedSeriesIdx] = useState<number | null>(null);
|
const [focusedSeriesIdx, setFocusedSeriesIdx] = useState<number | null>(null);
|
||||||
const [focusedPointIdx, setFocusedPointIdx] = useState<number | null>(null);
|
const [focusedPointIdx, setFocusedPointIdx] = useState<number | null>(null);
|
||||||
|
const [isActive, setIsActive] = useState<boolean>(false);
|
||||||
const [shouldDisplayCloseButton, setShouldDisplayCloseButton] = useState<boolean>(false);
|
const [shouldDisplayCloseButton, setShouldDisplayCloseButton] = useState<boolean>(false);
|
||||||
const { canAddAnnotations } = usePanelContext();
|
const { sync, canAddAnnotations } = usePanelContext();
|
||||||
|
|
||||||
const onCloseToolTip = () => {
|
const onCloseToolTip = () => {
|
||||||
isToolTipOpen.current = false;
|
isToolTipOpen.current = false;
|
||||||
@ -178,6 +179,9 @@ export const StateTimelinePanel: React.FC<TimelinePanelProps> = ({
|
|||||||
setCoords,
|
setCoords,
|
||||||
setHover,
|
setHover,
|
||||||
isToolTipOpen,
|
isToolTipOpen,
|
||||||
|
isActive,
|
||||||
|
setIsActive,
|
||||||
|
sync,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -198,9 +202,13 @@ export const StateTimelinePanel: React.FC<TimelinePanelProps> = ({
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (focusedPointIdx === null || (!isActive && sync && sync() === DashboardCursorSync.Crosshair)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Portal>
|
<Portal>
|
||||||
{hover && coords && (
|
{hover && coords && focusedSeriesIdx && (
|
||||||
<VizTooltipContainer
|
<VizTooltipContainer
|
||||||
position={{ x: coords.viewport.x, y: coords.viewport.y }}
|
position={{ x: coords.viewport.x, y: coords.viewport.y }}
|
||||||
offset={{ x: TOOLTIP_OFFSET, y: TOOLTIP_OFFSET }}
|
offset={{ x: TOOLTIP_OFFSET, y: TOOLTIP_OFFSET }}
|
||||||
|
@ -1,10 +1,11 @@
|
|||||||
import React, { useCallback, useMemo, useRef, useState } from 'react';
|
import React, { useCallback, useMemo, useRef, useState } from 'react';
|
||||||
|
|
||||||
import { CartesianCoords2D, DataFrame, FieldType, PanelProps } from '@grafana/data';
|
import { CartesianCoords2D, DashboardCursorSync, DataFrame, FieldType, PanelProps } from '@grafana/data';
|
||||||
import {
|
import {
|
||||||
Portal,
|
Portal,
|
||||||
TooltipDisplayMode,
|
TooltipDisplayMode,
|
||||||
UPlotConfigBuilder,
|
UPlotConfigBuilder,
|
||||||
|
usePanelContext,
|
||||||
useTheme2,
|
useTheme2,
|
||||||
VizTooltipContainer,
|
VizTooltipContainer,
|
||||||
ZoomPlugin,
|
ZoomPlugin,
|
||||||
@ -46,7 +47,9 @@ export const StatusHistoryPanel: React.FC<TimelinePanelProps> = ({
|
|||||||
const [coords, setCoords] = useState<{ viewport: CartesianCoords2D; canvas: CartesianCoords2D } | null>(null);
|
const [coords, setCoords] = useState<{ viewport: CartesianCoords2D; canvas: CartesianCoords2D } | null>(null);
|
||||||
const [focusedSeriesIdx, setFocusedSeriesIdx] = useState<number | null>(null);
|
const [focusedSeriesIdx, setFocusedSeriesIdx] = useState<number | null>(null);
|
||||||
const [focusedPointIdx, setFocusedPointIdx] = useState<number | null>(null);
|
const [focusedPointIdx, setFocusedPointIdx] = useState<number | null>(null);
|
||||||
|
const [isActive, setIsActive] = useState<boolean>(false);
|
||||||
const [shouldDisplayCloseButton, setShouldDisplayCloseButton] = useState<boolean>(false);
|
const [shouldDisplayCloseButton, setShouldDisplayCloseButton] = useState<boolean>(false);
|
||||||
|
const { sync } = usePanelContext();
|
||||||
|
|
||||||
const onCloseToolTip = () => {
|
const onCloseToolTip = () => {
|
||||||
isToolTipOpen.current = false;
|
isToolTipOpen.current = false;
|
||||||
@ -179,6 +182,8 @@ export const StatusHistoryPanel: React.FC<TimelinePanelProps> = ({
|
|||||||
setCoords,
|
setCoords,
|
||||||
setHover,
|
setHover,
|
||||||
isToolTipOpen,
|
isToolTipOpen,
|
||||||
|
isActive,
|
||||||
|
setIsActive,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -186,11 +191,15 @@ export const StatusHistoryPanel: React.FC<TimelinePanelProps> = ({
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (focusedPointIdx === null || (!isActive && sync && sync() === DashboardCursorSync.Crosshair)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<ZoomPlugin config={config} onZoom={onChangeTimeRange} />
|
<ZoomPlugin config={config} onZoom={onChangeTimeRange} />
|
||||||
<Portal>
|
<Portal>
|
||||||
{hover && coords && (
|
{hover && coords && focusedSeriesIdx && (
|
||||||
<VizTooltipContainer
|
<VizTooltipContainer
|
||||||
position={{ x: coords.viewport.x, y: coords.viewport.y }}
|
position={{ x: coords.viewport.x, y: coords.viewport.y }}
|
||||||
offset={{ x: TOOLTIP_OFFSET, y: TOOLTIP_OFFSET }}
|
offset={{ x: TOOLTIP_OFFSET, y: TOOLTIP_OFFSET }}
|
||||||
|
Loading…
Reference in New Issue
Block a user