diff --git a/public/app/features/canvas/elements/cloud.tsx b/public/app/features/canvas/elements/cloud.tsx index 64313248f28..10b92de3c8c 100644 --- a/public/app/features/canvas/elements/cloud.tsx +++ b/public/app/features/canvas/elements/cloud.tsx @@ -108,6 +108,7 @@ export const cloudItem: CanvasElementItem = { const data: CanvasElementData = { text: textConfig?.text ? dimensionContext.getText(textConfig.text).value() : '', + field: textConfig?.text?.field, align: textConfig?.align ?? Align.Center, valign: textConfig?.valign ?? VAlign.Middle, size: textConfig?.size, diff --git a/public/app/features/canvas/elements/ellipse.tsx b/public/app/features/canvas/elements/ellipse.tsx index 67e5a68285f..b82c112b1ea 100644 --- a/public/app/features/canvas/elements/ellipse.tsx +++ b/public/app/features/canvas/elements/ellipse.tsx @@ -114,6 +114,7 @@ export const ellipseItem: CanvasElementItem = { const data: TextData = { text: textConfig?.text ? dimensionContext.getText(textConfig.text).value() : '', + field: textConfig?.text?.field, align: textConfig?.align ?? Align.Center, valign: textConfig?.valign ?? VAlign.Middle, size: textConfig?.size, diff --git a/public/app/features/canvas/elements/parallelogram.tsx b/public/app/features/canvas/elements/parallelogram.tsx index 7bccfd0c813..4d4db7dfe29 100644 --- a/public/app/features/canvas/elements/parallelogram.tsx +++ b/public/app/features/canvas/elements/parallelogram.tsx @@ -108,6 +108,7 @@ export const parallelogramItem: CanvasElementItem = { const data: CanvasElementData = { text: textConfig?.text ? dimensionContext.getText(textConfig.text).value() : '', + field: textConfig?.text?.field, align: textConfig?.align ?? Align.Center, valign: textConfig?.valign ?? VAlign.Middle, size: textConfig?.size, diff --git a/public/app/features/canvas/elements/rectangle.tsx b/public/app/features/canvas/elements/rectangle.tsx index e89b7e448e7..0daf949f5b7 100644 --- a/public/app/features/canvas/elements/rectangle.tsx +++ b/public/app/features/canvas/elements/rectangle.tsx @@ -81,6 +81,7 @@ export const rectangleItem: CanvasElementItem = { const data: TextData = { text: textConfig?.text ? dimensionContext.getText(textConfig.text).value() : '', + field: textConfig?.text?.field, align: textConfig?.align ?? Align.Center, valign: textConfig?.valign ?? VAlign.Middle, size: textConfig?.size, diff --git a/public/app/features/canvas/elements/text.tsx b/public/app/features/canvas/elements/text.tsx index b5cabfdc107..988b060cb99 100644 --- a/public/app/features/canvas/elements/text.tsx +++ b/public/app/features/canvas/elements/text.tsx @@ -156,6 +156,7 @@ export const textItem: CanvasElementItem = { const data: TextData = { text: textConfig?.text ? dimensionContext.getText(textConfig.text).value() : '', + field: textConfig?.text?.field, align: textConfig?.align ?? Align.Center, valign: textConfig?.valign ?? VAlign.Middle, size: textConfig?.size, diff --git a/public/app/features/canvas/elements/triangle.tsx b/public/app/features/canvas/elements/triangle.tsx index 84093278df1..b0178142349 100644 --- a/public/app/features/canvas/elements/triangle.tsx +++ b/public/app/features/canvas/elements/triangle.tsx @@ -109,6 +109,7 @@ export const triangleItem: CanvasElementItem = { const data: CanvasElementData = { text: textConfig?.text ? dimensionContext.getText(textConfig.text).value() : '', + field: textConfig?.text?.field, align: textConfig?.align ?? Align.Center, valign: textConfig?.valign ?? VAlign.Middle, size: textConfig?.size, diff --git a/public/app/features/canvas/runtime/scene.tsx b/public/app/features/canvas/runtime/scene.tsx index 764b6d81eda..2e96e69b0c9 100644 --- a/public/app/features/canvas/runtime/scene.tsx +++ b/public/app/features/canvas/runtime/scene.tsx @@ -281,7 +281,7 @@ export class Scene { }; render() { - const isTooltipValid = (this.tooltip?.element?.data?.links?.length ?? 0) > 0; + const isTooltipValid = (this.tooltip?.element?.data?.links?.length ?? 0) > 0 || this.tooltip?.element?.data?.field; const canShowElementTooltip = !this.isEditingEnabled && isTooltipValid; const sceneDiv = ( diff --git a/public/app/features/canvas/types.ts b/public/app/features/canvas/types.ts index 07a144a4798..1dd3f298e7a 100644 --- a/public/app/features/canvas/types.ts +++ b/public/app/features/canvas/types.ts @@ -30,6 +30,7 @@ export interface TextData { align: Align; valign: VAlign; links?: LinkModel[]; + field?: string; } export interface TextConfig { diff --git a/public/app/plugins/panel/canvas/components/CanvasTooltip.tsx b/public/app/plugins/panel/canvas/components/CanvasTooltip.tsx index aba956850fd..0c7db1533ce 100644 --- a/public/app/plugins/panel/canvas/components/CanvasTooltip.tsx +++ b/public/app/plugins/panel/canvas/components/CanvasTooltip.tsx @@ -1,11 +1,15 @@ -import { css } from '@emotion/css'; +import { css, cx } from '@emotion/css'; import { useDialog } from '@react-aria/dialog'; import { useOverlay } from '@react-aria/overlays'; import { createRef } from 'react'; -import { GrafanaTheme2, LinkModel } from '@grafana/data/src'; -import { LinkButton, Portal, Stack, useStyles2, VizTooltipContainer } from '@grafana/ui'; -import { CloseButton } from 'app/core/components/CloseButton/CloseButton'; +import { FieldType, GrafanaTheme2, formattedValueToString, getFieldDisplayName } from '@grafana/data/src'; +import { Portal, useStyles2, VizTooltipContainer } from '@grafana/ui'; +import { VizTooltipContent } from '@grafana/ui/src/components/VizTooltip/VizTooltipContent'; +import { VizTooltipFooter } from '@grafana/ui/src/components/VizTooltip/VizTooltipFooter'; +import { VizTooltipHeader } from '@grafana/ui/src/components/VizTooltip/VizTooltipHeader'; +import { VizTooltipItem } from '@grafana/ui/src/components/VizTooltip/types'; +import { CloseButton } from '@grafana/ui/src/components/uPlot/plugins/CloseButton'; import { Scene } from 'app/features/canvas/runtime/scene'; interface Props { @@ -13,7 +17,7 @@ interface Props { } export const CanvasTooltip = ({ scene }: Props) => { - const style = useStyles2(getStyles); + const styles = useStyles2(getStyles); const onClose = () => { if (scene?.tooltipCallback && scene.tooltip) { @@ -30,40 +34,47 @@ export const CanvasTooltip = ({ scene }: Props) => { return <>; } - const renderDataLinks = () => - element.data?.links && - element.data?.links.length > 0 && ( -
- - {element.data?.links?.map((link: LinkModel, i: number) => ( - - {link.title} - - ))} - -
- ); + // Retrieve timestamp of the last data point if available + const timeField = scene.data?.series[0].fields?.find((field) => field.type === FieldType.time); + const lastTimeValue = timeField?.values[timeField.values.length - 1]; + const shouldDisplayTimeContentItem = + timeField && lastTimeValue && element.data.field && getFieldDisplayName(timeField) !== element.data.field; + + const headerItem: VizTooltipItem | null = { + label: element.getName(), + value: '', + }; + + const contentItems: VizTooltipItem[] = [ + { + label: element.data.field ?? 'Fixed', + value: element.data.text, + }, + ...(shouldDisplayTimeContentItem + ? [ + { + label: 'Time', + value: formattedValueToString(timeField?.display!(lastTimeValue)), + }, + ] + : []), + ]; return ( <> {scene.tooltip?.element && scene.tooltip.anchorPoint && (
{scene.tooltip.isOpen && } -
{renderDataLinks()}
+ + {element.data.text && } +
@@ -77,4 +88,20 @@ const getStyles = (theme: GrafanaTheme2) => ({ marginTop: '20px', background: theme.colors.background.primary, }), + tooltipWrapper: css({ + top: 0, + left: 0, + zIndex: theme.zIndex.portal, + whiteSpace: 'pre', + borderRadius: theme.shape.radius.default, + position: 'fixed', + background: theme.colors.background.primary, + border: `1px solid ${theme.colors.border.weak}`, + boxShadow: theme.shadows.z2, + userSelect: 'text', + padding: 0, + }), + pinned: css({ + boxShadow: theme.shadows.z3, + }), });