UNPKG

@grafana/ui

Version:
364 lines (361 loc) • 15.3 kB
import { jsx } from 'react/jsx-runtime'; import { css } from '@emotion/css'; import { useRef, useState, useLayoutEffect } from 'react'; import { useMountedState } from 'react-use'; import { DashboardCursorSync, getDisplayProcessor, FALLBACK_COLOR, getFieldDisplayName, formattedValueToString, FieldType, arrayUtils } from '@grafana/data'; import { TooltipDisplayMode, SortOrder } from '@grafana/schema'; import '../../../components/FormField/FormField.mjs'; import '../../../components/Forms/Legacy/Input/Input.mjs'; import 'react-select'; import '../../../components/Icon/Icon.mjs'; import '../../../components/Forms/Legacy/Select/Select.mjs'; import '../../../components/Forms/Legacy/Switch/Switch.mjs'; import '../../../components/SecretFormField/SecretFormField.mjs'; import '../../../components/IconButton/IconButton.mjs'; import '../../../components/ConfirmButton/ConfirmButton.mjs'; import '../../../components/Button/Button.mjs'; import '../../../components/Button/ButtonGroup.mjs'; import '../../../components/Tooltip/Tooltip.mjs'; import '@floating-ui/react'; import { useTheme2, useStyles2 } from '../../../themes/ThemeContext.mjs'; import 'micro-memoize'; import '@emotion/react'; import 'tinycolor2'; import '../../../utils/skeleton.mjs'; import { Portal } from '../../../components/Portal/Portal.mjs'; import '../../../components/Toggletip/Toggletip.mjs'; import 'react-custom-scrollbars-2'; import '../../../components/Tabs/Tab.mjs'; import '../../../components/Tabs/TabsBar.mjs'; import '../../../components/Layout/Box/Box.mjs'; import '../../../components/ScrollContainer/ScrollContainer.mjs'; import '../../../utils/i18n.mjs'; import '../../../components/Cascader/Cascader.mjs'; import '../../../components/Alert/Alert.mjs'; import '../../../components/ButtonCascader/ButtonCascader.mjs'; import 'react-inlinesvg'; import '../../../utils/keyframes.mjs'; import '../../../components/ColorPicker/ColorPicker.mjs'; import '../../../components/ColorPicker/ColorPickerInput.mjs'; import '../../../components/ColorPicker/SeriesColorPickerPopover.mjs'; import '../../../components/Layout/Stack/Stack.mjs'; import '../../../components/Text/Text.mjs'; import '../../../components/EmptyState/GrotCTA/GrotCTA.mjs'; import '../../../components/EmptyState/GrotNotFound/GrotNotFound.mjs'; import '../../../components/StatsPicker/StatsPicker.mjs'; import '../../../components/RefreshPicker/RefreshPicker.mjs'; import '../../../components/DateTimePickers/TimeRangePicker.mjs'; import '../../../components/DateTimePickers/TimeRangeContext.mjs'; import '../../../components/DateTimePickers/TimeRangePicker/TimeRangeLabel.mjs'; import 'rc-picker'; import 'rc-picker/lib/generate/moment'; import 'rc-picker/lib/locale/en_US'; import 'rc-picker/assets/index.css'; import 'lodash'; import 'react-select/async'; import 'react-select/async-creatable'; import 'react-select/creatable'; import '../../../components/Select/IndicatorsContainer.mjs'; import '../../../components/Select/InputControl.mjs'; import '../../../components/Select/getSelectStyles.mjs'; import '../../../components/Input/Input.mjs'; import '../../../components/Select/SelectMenu.mjs'; import 'react-transition-group'; import '../../../components/Select/ValueContainer.mjs'; import '@grafana/e2e-selectors'; import '@tanstack/react-virtual'; import 'downshift'; import '../../../components/Input/AutoSizeInput.mjs'; import '../../../components/Forms/Checkbox.mjs'; import '../../../components/Combobox/filter.mjs'; import '../../../utils/dom.mjs'; import '../../../utils/colors.mjs'; import 'slate'; import '../../../utils/logger.mjs'; import '../../../components/DateTimePickers/DatePicker/DatePicker.mjs'; import '../../../components/DateTimePickers/DateTimePicker/DateTimePicker.mjs'; import '../../../components/List/AbstractList.mjs'; import 'react-table'; import '../../../components/InteractiveTable/Expander/index.mjs'; import '../../../components/AutoSaveField/AutoSaveField.mjs'; import '../../../components/Tags/Tag.mjs'; import '../../../components/Tags/TagList.mjs'; import '../../../components/Modal/Modal.mjs'; import 'react-hook-form'; import '../../../components/Forms/Field.mjs'; import '../../../components/QueryField/QueryField.mjs'; import '../../../components/Monaco/CodeEditor.mjs'; import '../../../components/ErrorBoundary/ErrorWithStack.mjs'; import '../../../components/Modal/ModalsContext.mjs'; import '../../../components/PageLayout/PageToolbar.mjs'; import 'rxjs'; import 'rxjs/operators'; import '../../../components/Table/TableRT/Table.mjs'; import '@react-aria/dialog'; import '@react-aria/focus'; import '@react-aria/overlays'; import 'rc-drawer'; import 'rc-drawer/assets/index.css'; import '../../../components/TableInputCSV/TableInputCSV.mjs'; import '../../../components/Tabs/VerticalTab.mjs'; import '../../../components/BigValue/BigValue.mjs'; import '../../../components/Sparkline/Sparkline.mjs'; import '../../../components/Gauge/Gauge.mjs'; import '../../../components/BarGauge/BarGauge.mjs'; import '../../../components/VizTooltip/VizTooltip.mjs'; import { VizTooltipContainer } from '../../../components/VizTooltip/VizTooltipContainer.mjs'; import { SeriesTable } from '../../../components/VizTooltip/SeriesTable.mjs'; import '../../../components/VizRepeater/VizRepeater.mjs'; import '../../../components/PanelChrome/index.mjs'; import '../../../components/VizLayout/VizLayout.mjs'; import '../../../components/VizLegend/VizLegend.mjs'; import '../../../components/VizLegend/VizLegendListItem.mjs'; import '../../../components/Collapse/Collapse.mjs'; import '../../../components/ClickOutsideWrapper/ClickOutsideWrapper.mjs'; import '../../../components/ContextMenu/ContextMenu.mjs'; import '../../../components/Menu/Menu.mjs'; import '../../../components/Menu/MenuGroup.mjs'; import '../../../components/Menu/MenuItem.mjs'; import '../../../components/DataLinks/DataLinkEditor.mjs'; import '@hello-pangea/dnd'; import '../../../components/Badge/Badge.mjs'; import '../../../components/DataLinks/DataLinkInput.mjs'; import '../../../components/VizLegend/SeriesIcon.mjs'; import '../../../components/InfoBox/InfoBox.mjs'; import '../../../components/InfoBox/FeatureInfoBox.mjs'; import '../../../components/JSONFormatter/JSONFormatter.mjs'; import '../../../components/ErrorBoundary/ErrorBoundary.mjs'; import '../../../components/Forms/InlineField.mjs'; import '../../../components/Forms/RadioButtonGroup/RadioButtonGroup.mjs'; import '../../../components/Switch/Switch.mjs'; import '../../../components/DataSourceSettings/CustomHeadersSettings.mjs'; import '../../../components/TextArea/TextArea.mjs'; import 'react-use/lib/useClickAway'; import '../../../components/Slider/Slider.mjs'; import '../../../components/Slider/RangeSlider.mjs'; import '../../../components/ToolbarButton/ToolbarButton.mjs'; import '../../../components/ToolbarButton/ToolbarButtonRow.mjs'; import '../../../components/MatchersUI/fieldMatchersUI.mjs'; import '../../../components/Link/Link.mjs'; import '../../../components/Link/TextLink.mjs'; import '../../../components/Layout/Grid/Grid.mjs'; import '../../../components/Forms/InlineSegmentGroup.mjs'; import '../../../components/Combobox/ValuePill.mjs'; import '../../../components/FilterInput/FilterInput.mjs'; import 'uuid'; import 'react-dropzone'; import '../../../components/DateTimePickers/TimeRangePicker/TimePickerContent.mjs'; import '../../../components/DateTimePickers/RelativeTimeRangePicker/RelativeTimeRangePicker.mjs'; import '../../../components/Card/Card.mjs'; import '../../../components/FormattedValueDisplay/FormattedValueDisplay.mjs'; import '../../../components/Dropdown/ButtonSelect.mjs'; import '../../../components/Dropdown/Dropdown.mjs'; import '../../../components/PluginSignatureBadge/PluginSignatureBadge.mjs'; import 'classnames'; import '../../../components/Divider/Divider.mjs'; import '../../../components/uPlot/config.mjs'; import 'uplot'; import { findMidPointYPosition } from '../../../components/uPlot/utils.mjs'; import 'uplot/dist/uPlot.min.css'; import '../../../components/uPlot/PlotLegend.mjs'; import 'react-dom'; import '../../../components/BrowserLabel/Label.mjs'; import '../../Graph/Graph.mjs'; import '../../GraphNG/GraphNG.mjs'; import '../../TimeSeries/TimeSeries.mjs'; import '../../GraphNG/hooks.mjs'; import '../../../components/ElementSelectionContext/ElementSelectionContext.mjs'; const TOOLTIP_OFFSET = 10; const TooltipPlugin = ({ mode = TooltipDisplayMode.Single, sortOrder = SortOrder.None, sync, timeZone, config, renderTooltip, ...otherProps }) => { var _a, _b, _c, _d, _e; const plotInstance = useRef(); const theme = useTheme2(); const [focusedSeriesIdx, setFocusedSeriesIdx] = useState(null); const [focusedPointIdx, setFocusedPointIdx] = useState(null); const [focusedPointIdxs, setFocusedPointIdxs] = useState([]); const [coords, setCoords] = useState(null); const [isActive, setIsActive] = useState(false); const isMounted = useMountedState(); let parentWithFocus = null; const style = useStyles2(getStyles); useLayoutEffect(() => { let bbox = void 0; const plotEnter = () => { var _a2; if (!isMounted()) { return; } setIsActive(true); (_a2 = plotInstance.current) == null ? void 0 : _a2.root.classList.add("plot-active"); }; const plotLeave = () => { var _a2; if (!isMounted()) { return; } setCoords(null); setIsActive(false); (_a2 = plotInstance.current) == null ? void 0 : _a2.root.classList.remove("plot-active"); }; config.addHook("syncRect", (u, rect) => bbox = rect); config.addHook("init", (u) => { plotInstance.current = u; u.over.addEventListener("mouseenter", plotEnter); u.over.addEventListener("mouseleave", plotLeave); parentWithFocus = u.root.closest("[tabindex]"); if (parentWithFocus) { parentWithFocus.addEventListener("focus", plotEnter); parentWithFocus.addEventListener("blur", plotLeave); } if (sync && sync() === DashboardCursorSync.Crosshair) { u.root.classList.add("shared-crosshair"); } }); config.addHook("setLegend", (u) => { if (!isMounted()) { return; } setFocusedPointIdx(u.legend.idx); setFocusedPointIdxs(u.legend.idxs.slice()); }); config.addHook("setCursor", (u) => { if (!bbox || !isMounted()) { return; } const { x, y } = positionTooltip(u, bbox); if (x !== void 0 && y !== void 0) { setCoords({ x, y }); } else { setCoords(null); } }); config.addHook("setSeries", (_, idx) => { if (!isMounted()) { return; } setFocusedSeriesIdx(idx); }); return () => { setCoords(null); if (plotInstance.current) { plotInstance.current.over.removeEventListener("mouseleave", plotLeave); plotInstance.current.over.removeEventListener("mouseenter", plotEnter); if (parentWithFocus) { parentWithFocus.removeEventListener("focus", plotEnter); parentWithFocus.removeEventListener("blur", plotLeave); } } }; }, [config, setCoords, setIsActive, setFocusedPointIdx, setFocusedPointIdxs]); if (focusedPointIdx === null || !isActive && sync && sync() === DashboardCursorSync.Crosshair) { return null; } let xField = otherProps.data.fields[0]; if (!xField) { return null; } const xFieldFmt = xField.display || getDisplayProcessor({ field: xField, timeZone, theme }); let tooltip = null; let xVal = xFieldFmt(xField.values[focusedPointIdx]).text; if (!renderTooltip) { if (mode === TooltipDisplayMode.Single && focusedSeriesIdx !== null) { const field = otherProps.data.fields[focusedSeriesIdx]; if (!field) { return null; } const dataIdx = (_a = focusedPointIdxs == null ? void 0 : focusedPointIdxs[focusedSeriesIdx]) != null ? _a : focusedPointIdx; xVal = xFieldFmt(xField.values[dataIdx]).text; const fieldFmt = field.display || getDisplayProcessor({ field, timeZone, theme }); const display = fieldFmt(field.values[dataIdx]); tooltip = /* @__PURE__ */ jsx( SeriesTable, { series: [ { color: display.color || FALLBACK_COLOR, label: getFieldDisplayName(field, otherProps.data, otherProps.frames), value: display ? formattedValueToString(display) : null } ], timestamp: xVal } ); } if (mode === TooltipDisplayMode.Multi) { let series = []; const frame = otherProps.data; const fields = frame.fields; const sortIdx = []; for (let i = 0; i < fields.length; i++) { const field = frame.fields[i]; if (!field || field === xField || field.type === FieldType.time || field.type !== FieldType.number || ((_c = (_b = field.config.custom) == null ? void 0 : _b.hideFrom) == null ? void 0 : _c.tooltip) || ((_e = (_d = field.config.custom) == null ? void 0 : _d.hideFrom) == null ? void 0 : _e.viz)) { continue; } const v = otherProps.data.fields[i].values[focusedPointIdxs[i]]; const display = field.display(v); sortIdx.push(v); series.push({ color: display.color || FALLBACK_COLOR, label: getFieldDisplayName(field, frame, otherProps.frames), value: display ? formattedValueToString(display) : null, isActive: focusedSeriesIdx === i }); } if (sortOrder !== SortOrder.None) { const sortRef = [...series]; const sortFn = arrayUtils.sortValues(sortOrder); series.sort((a, b) => { const aIdx = sortRef.indexOf(a); const bIdx = sortRef.indexOf(b); return sortFn(sortIdx[aIdx], sortIdx[bIdx]); }); } tooltip = /* @__PURE__ */ jsx(SeriesTable, { series, timestamp: xVal }); } } else { tooltip = renderTooltip(otherProps.data, focusedSeriesIdx, focusedPointIdx); } return /* @__PURE__ */ jsx(Portal, { className: isActive ? style.tooltipWrapper : void 0, children: tooltip && coords && /* @__PURE__ */ jsx(VizTooltipContainer, { position: { x: coords.x, y: coords.y }, offset: { x: TOOLTIP_OFFSET, y: TOOLTIP_OFFSET }, children: tooltip }) }); }; function isCursorOutsideCanvas({ left, top }, canvas) { if (left === void 0 || top === void 0) { return false; } return left < 0 || left > canvas.width || top < 0 || top > canvas.height; } function positionTooltip(u, bbox) { let x, y; const cL = u.cursor.left || 0; const cT = u.cursor.top || 0; if (isCursorOutsideCanvas(u.cursor, bbox)) { const idx = u.posToIdx(cL); if (cT < 0 || cT > bbox.height) { let pos = findMidPointYPosition(u, idx); if (pos) { y = bbox.top + pos; if (cL >= 0 && cL <= bbox.width) { x = bbox.left + u.valToPos(u.data[0][u.posToIdx(cL)], u.series[0].scale); } } } } else { x = bbox.left + cL; y = bbox.top + cT; } return { x, y }; } const getStyles = (theme) => ({ tooltipWrapper: css({ "z-index": theme.zIndex.portal + 1 + " !important" }) }); export { TooltipPlugin, positionTooltip }; //# sourceMappingURL=TooltipPlugin.mjs.map