diff --git a/docs/sources/panels-visualizations/visualizations/canvas/index.md b/docs/sources/panels-visualizations/visualizations/canvas/index.md index 0c0821cc923..76a18031449 100644 --- a/docs/sources/panels-visualizations/visualizations/canvas/index.md +++ b/docs/sources/panels-visualizations/visualizations/canvas/index.md @@ -282,6 +282,8 @@ The options are: - **Enabled** - Show a tooltip when the cursor hovers over an element. - **Disabled** - Tooltips are not shown on hover. +The **Disable for one-click elements** setting allows hiding tooltips on elements that have one-click functionality enabled. This prevents tooltips from interfering with one-click interactions while still allowing tooltips on other elements. + ### Layer options The **Layer** options let you add elements to the canvas and control its appearance: diff --git a/packages/grafana-schema/src/raw/composable/canvas/panelcfg/x/CanvasPanelCfg_types.gen.ts b/packages/grafana-schema/src/raw/composable/canvas/panelcfg/x/CanvasPanelCfg_types.gen.ts index 60cb7a2adcd..04fec030dfa 100644 --- a/packages/grafana-schema/src/raw/composable/canvas/panelcfg/x/CanvasPanelCfg_types.gen.ts +++ b/packages/grafana-schema/src/raw/composable/canvas/panelcfg/x/CanvasPanelCfg_types.gen.ts @@ -114,6 +114,7 @@ export const defaultCanvasElementOptions: Partial = { }; export interface CanvasTooltip { + disableForOneClick?: boolean; mode: ui.TooltipDisplayMode; } diff --git a/public/app/features/canvas/runtime/element.tsx b/public/app/features/canvas/runtime/element.tsx index a64d004967b..b50aa933342 100644 --- a/public/app/features/canvas/runtime/element.tsx +++ b/public/app/features/canvas/runtime/element.tsx @@ -866,7 +866,8 @@ export class ElementState implements LayerElement { handleMouseEnter = (event: React.MouseEvent, isSelected: boolean | undefined) => { const scene = this.getScene(); - const shouldHandleTooltip = !scene?.isEditingEnabled && !scene?.tooltipPayload?.isOpen; + const shouldHandleTooltip = + !scene?.isEditingEnabled && (!scene?.tooltipPayload?.isOpen || scene?.tooltipPayload?.element === this); if (shouldHandleTooltip) { this.handleTooltip(event); } else if (!isSelected) { @@ -933,7 +934,14 @@ export class ElementState implements LayerElement { handleTooltip = (event: React.MouseEvent) => { const scene = this.getScene(); - if (scene?.tooltipCallback && scene.tooltipMode !== TooltipDisplayMode.None) { + if (!scene || !scene.tooltipCallback) { + return; + } + + const shouldDisableForOneClick = scene.tooltipDisableForOneClick && this.oneClickMode !== OneClickMode.Off; + const shouldShowTooltip = scene.tooltipMode !== TooltipDisplayMode.None && !shouldDisableForOneClick; + + if (shouldShowTooltip) { const rect = this.div?.getBoundingClientRect(); scene.tooltipCallback({ anchorPoint: { x: rect?.right ?? event.pageX, y: rect?.top ?? event.pageY }, diff --git a/public/app/features/canvas/runtime/scene.tsx b/public/app/features/canvas/runtime/scene.tsx index 768ebec9f57..ae94ac203ee 100644 --- a/public/app/features/canvas/runtime/scene.tsx +++ b/public/app/features/canvas/runtime/scene.tsx @@ -5,7 +5,7 @@ import { CSSProperties } from 'react'; import { BehaviorSubject, ReplaySubject, Subject, Subscription } from 'rxjs'; import Selecto from 'selecto'; -import { AppEvents, PanelData } from '@grafana/data'; +import { AppEvents, PanelData, OneClickMode } from '@grafana/data'; import { locationService } from '@grafana/runtime'; import { ColorDimensionConfig, @@ -81,6 +81,7 @@ export class Scene { shouldPanZoom?: boolean; zoomToContent?: boolean; tooltipMode?: TooltipDisplayMode; + tooltipDisableForOneClick?: boolean; skipNextSelectionBroadcast = false; ignoreDataUpdate = false; panel: CanvasPanel; @@ -152,6 +153,7 @@ export class Scene { load(options: Options, enableEditing: boolean) { const { root, showAdvancedTypes, panZoom, zoomToContent, tooltip } = options; const tooltipMode = tooltip?.mode ?? TooltipDisplayMode.Single; + const tooltipDisableForOneClick = tooltip?.disableForOneClick ?? false; this.root = new RootElement( root ?? { @@ -167,6 +169,7 @@ export class Scene { this.shouldPanZoom = panZoom; this.zoomToContent = zoomToContent; this.tooltipMode = tooltipMode; + this.tooltipDisableForOneClick = tooltipDisableForOneClick; setTimeout(() => { if (config.featureToggles.canvasPanelPanZoom) { @@ -376,8 +379,12 @@ export class Scene { this.tooltipPayload?.element?.options.actions && this.tooltipPayload.element.options.actions.length > 0; const isTooltipValid = hasDataLinks || hasActions || this.tooltipPayload?.element?.data?.field; - const isTooltipEnabled = this.tooltipMode !== TooltipDisplayMode.None; - const canShowElementTooltip = !this.isEditingEnabled && isTooltipValid && isTooltipEnabled; + const isCanvasTooltipEnabled = this.tooltipMode !== TooltipDisplayMode.None; + + const isTooltipDisabledForOneClick = + this.tooltipDisableForOneClick && this.tooltipPayload?.element?.oneClickMode !== OneClickMode.Off; + const shouldShowElementTooltip = + !this.isEditingEnabled && isTooltipValid && isCanvasTooltipEnabled && !isTooltipDisabledForOneClick; const sceneDiv = ( <> @@ -392,7 +399,7 @@ export class Scene { /> )} - {canShowElementTooltip && ( + {shouldShowElementTooltip && ( diff --git a/public/app/plugins/panel/canvas/CanvasPanel.tsx b/public/app/plugins/panel/canvas/CanvasPanel.tsx index bf19bd867f8..bd1b26bb42a 100644 --- a/public/app/plugins/panel/canvas/CanvasPanel.tsx +++ b/public/app/plugins/panel/canvas/CanvasPanel.tsx @@ -237,13 +237,16 @@ export class CanvasPanel extends Component { const panZoomSwitched = this.props.options.panZoom !== nextProps.options.panZoom; const zoomToContentSwitched = this.props.options.zoomToContent !== nextProps.options.zoomToContent; const tooltipModeSwitched = this.props.options.tooltip?.mode !== nextProps.options.tooltip?.mode; + const tooltipDisableForOneClickSwitched = + this.props.options.tooltip?.disableForOneClick !== nextProps.options.tooltip?.disableForOneClick; if ( this.needsReload || inlineEditingSwitched || shouldShowAdvancedTypesSwitched || panZoomSwitched || zoomToContentSwitched || - tooltipModeSwitched + tooltipModeSwitched || + tooltipDisableForOneClickSwitched ) { if (inlineEditingSwitched) { // Replace scene div to prevent selecto instance leaks diff --git a/public/app/plugins/panel/canvas/module.tsx b/public/app/plugins/panel/canvas/module.tsx index 7d89e793f5a..76ba39a09fb 100644 --- a/public/app/plugins/panel/canvas/module.tsx +++ b/public/app/plugins/panel/canvas/module.tsx @@ -74,6 +74,14 @@ export const addStandardCanvasEditorOptions = (builder: PanelOptionsEditorBuilde ], }, }); + + builder.addBooleanSwitch({ + path: 'tooltip.disableForOneClick', + name: t('canvas.tooltip-options.label-disable-one-click', 'Disable for one-click elements'), + category, + defaultValue: false, + showIf: (options) => options.tooltip?.mode !== TooltipDisplayMode.None, + }); }; export const plugin = new PanelPlugin(CanvasPanel) diff --git a/public/app/plugins/panel/canvas/panelcfg.cue b/public/app/plugins/panel/canvas/panelcfg.cue index 8f1e3d5dc1d..eb4dd2603f0 100644 --- a/public/app/plugins/panel/canvas/panelcfg.cue +++ b/public/app/plugins/panel/canvas/panelcfg.cue @@ -91,6 +91,7 @@ composableKinds: PanelCfg: { } @cuetsy(kind="interface") CanvasTooltip: { mode: ui.TooltipDisplayMode + disableForOneClick?: bool } @cuetsy(kind="interface") Options: { diff --git a/public/app/plugins/panel/canvas/panelcfg.gen.ts b/public/app/plugins/panel/canvas/panelcfg.gen.ts index 207be41d615..aa1ccb5805b 100644 --- a/public/app/plugins/panel/canvas/panelcfg.gen.ts +++ b/public/app/plugins/panel/canvas/panelcfg.gen.ts @@ -112,6 +112,7 @@ export const defaultCanvasElementOptions: Partial = { }; export interface CanvasTooltip { + disableForOneClick?: boolean; mode: ui.TooltipDisplayMode; } diff --git a/public/locales/en-US/grafana.json b/public/locales/en-US/grafana.json index 11e2103b33c..c7744264872 100644 --- a/public/locales/en-US/grafana.json +++ b/public/locales/en-US/grafana.json @@ -4019,6 +4019,7 @@ } }, "tooltip-options": { + "label-disable-one-click": "Disable for one-click elements", "name-tooltip-mode": "Tooltip mode", "tooltip-mode-options": { "label-disabled": "Disabled",