StateTimeline: Fix tooltip showing erroneously in shared crosshair dashboards (#55809)

* StateTimeline: Fix shared crosshair

* Fix for StatusHistory also
This commit is contained in:
Victor Marin 2022-10-07 08:56:15 +03:00 committed by GitHub
parent 21d9cf0db4
commit b622a87aee
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 51 additions and 9 deletions

View File

@ -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) {

View File

@ -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 }}

View File

@ -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 }}

View File

@ -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 }}