Actions: Fix support in StateTimeline and XYChart (#100543)

Co-authored-by: Leon Sorokin <leeoniya@gmail.com>
This commit is contained in:
Adela Almasan
2025-02-12 13:53:32 -06:00
committed by GitHub
parent d1dee968c3
commit 62e06cfac8
9 changed files with 49 additions and 25 deletions

View File

@ -157,8 +157,8 @@ export const BarChartPanel = (props: PanelProps<Options>) => {
hoverMode={ hoverMode={
options.tooltip.mode === TooltipDisplayMode.Single ? TooltipHoverMode.xOne : TooltipHoverMode.xAll options.tooltip.mode === TooltipDisplayMode.Single ? TooltipHoverMode.xOne : TooltipHoverMode.xAll
} }
getDataLinks={(seriesIdx: number, dataIdx: number) => getDataLinks={(seriesIdx, dataIdx) =>
vizSeries[0].fields[seriesIdx]!.getLinks?.({ valueRowIndex: dataIdx }) ?? [] vizSeries[0].fields[seriesIdx].getLinks?.({ valueRowIndex: dataIdx }) ?? []
} }
render={(u, dataIdxs, seriesIdx, isPinned, dismiss, timeRange2, viaSync, dataLinks) => { render={(u, dataIdxs, seriesIdx, isPinned, dismiss, timeRange2, viaSync, dataLinks) => {
return ( return (

View File

@ -282,8 +282,8 @@ export const CandlestickPanel = ({
clientZoom={true} clientZoom={true}
syncMode={cursorSync} syncMode={cursorSync}
syncScope={eventsScope} syncScope={eventsScope}
getDataLinks={(seriesIdx: number, dataIdx: number) => getDataLinks={(seriesIdx, dataIdx) =>
alignedFrame.fields[seriesIdx]!.getLinks?.({ valueRowIndex: dataIdx }) ?? [] alignedFrame.fields[seriesIdx].getLinks?.({ valueRowIndex: dataIdx }) ?? []
} }
render={(u, dataIdxs, seriesIdx, isPinned = false, dismiss, timeRange2, viaSync, dataLinks) => { render={(u, dataIdxs, seriesIdx, isPinned = false, dismiss, timeRange2, viaSync, dataLinks) => {
if (enableAnnotationCreation && timeRange2 != null) { if (enableAnnotationCreation && timeRange2 != null) {

View File

@ -107,8 +107,8 @@ export const StateTimelinePanel = ({
queryZoom={onChangeTimeRange} queryZoom={onChangeTimeRange}
syncMode={cursorSync} syncMode={cursorSync}
syncScope={eventsScope} syncScope={eventsScope}
getDataLinks={(seriesIdx: number, dataIdx: number) => getDataLinks={(seriesIdx, dataIdx) =>
alignedFrame.fields[seriesIdx]!.getLinks?.({ valueRowIndex: dataIdx }) ?? [] alignedFrame.fields[seriesIdx].getLinks?.({ valueRowIndex: dataIdx }) ?? []
} }
render={(u, dataIdxs, seriesIdx, isPinned, dismiss, timeRange2, viaSync, dataLinks) => { render={(u, dataIdxs, seriesIdx, isPinned, dismiss, timeRange2, viaSync, dataLinks) => {
if (enableAnnotationCreation && timeRange2 != null) { if (enableAnnotationCreation && timeRange2 != null) {

View File

@ -68,12 +68,16 @@ export const StateTimelineTooltip2 = ({
let footer: ReactNode; let footer: ReactNode;
if (isPinned && seriesIdx != null) { if (seriesIdx != null) {
const field = series.fields[seriesIdx]; const field = series.fields[seriesIdx];
const dataIdx = dataIdxs[seriesIdx]!; const hasOneClickLink = dataLinks.some((dataLink) => dataLink.oneClick === true);
const actions = getFieldActions(series, field, replaceVariables!, dataIdx);
footer = <VizTooltipFooter dataLinks={dataLinks} annotate={annotate} actions={actions} />; if (isPinned || hasOneClickLink) {
const dataIdx = dataIdxs[seriesIdx]!;
const actions = getFieldActions(series, field, replaceVariables!, dataIdx);
footer = <VizTooltipFooter dataLinks={dataLinks} actions={actions} annotate={annotate} />;
}
} }
const headerItem: VizTooltipItem = { const headerItem: VizTooltipItem = {

View File

@ -119,8 +119,8 @@ export const StatusHistoryPanel = ({
queryZoom={onChangeTimeRange} queryZoom={onChangeTimeRange}
syncMode={cursorSync} syncMode={cursorSync}
syncScope={eventsScope} syncScope={eventsScope}
getDataLinks={(seriesIdx: number, dataIdx: number) => getDataLinks={(seriesIdx, dataIdx) =>
alignedFrame.fields[seriesIdx]!.getLinks?.({ valueRowIndex: dataIdx }) ?? [] alignedFrame.fields[seriesIdx].getLinks?.({ valueRowIndex: dataIdx }) ?? []
} }
render={(u, dataIdxs, seriesIdx, isPinned, dismiss, timeRange2, viaSync, dataLinks) => { render={(u, dataIdxs, seriesIdx, isPinned, dismiss, timeRange2, viaSync, dataLinks) => {
if (enableAnnotationCreation && timeRange2 != null) { if (enableAnnotationCreation && timeRange2 != null) {

View File

@ -106,8 +106,8 @@ export const TimeSeriesPanel = ({
clientZoom={true} clientZoom={true}
syncMode={cursorSync} syncMode={cursorSync}
syncScope={eventsScope} syncScope={eventsScope}
getDataLinks={(seriesIdx: number, dataIdx: number) => getDataLinks={(seriesIdx, dataIdx) =>
alignedFrame.fields[seriesIdx]!.getLinks?.({ valueRowIndex: dataIdx }) ?? [] alignedFrame.fields[seriesIdx].getLinks?.({ valueRowIndex: dataIdx }) ?? []
} }
render={(u, dataIdxs, seriesIdx, isPinned = false, dismiss, timeRange2, viaSync, dataLinks) => { render={(u, dataIdxs, seriesIdx, isPinned = false, dismiss, timeRange2, viaSync, dataLinks) => {
if (enableAnnotationCreation && timeRange2 != null) { if (enableAnnotationCreation && timeRange2 != null) {

View File

@ -119,8 +119,8 @@ export const TrendPanel = ({
hoverMode={ hoverMode={
options.tooltip.mode === TooltipDisplayMode.Single ? TooltipHoverMode.xOne : TooltipHoverMode.xAll options.tooltip.mode === TooltipDisplayMode.Single ? TooltipHoverMode.xOne : TooltipHoverMode.xAll
} }
getDataLinks={(seriesIdx: number, dataIdx: number) => getDataLinks={(seriesIdx, dataIdx) =>
alignedDataFrame.fields[seriesIdx]!.getLinks?.({ valueRowIndex: dataIdx }) ?? [] alignedDataFrame.fields[seriesIdx].getLinks?.({ valueRowIndex: dataIdx }) ?? []
} }
render={(u, dataIdxs, seriesIdx, isPinned = false, dismiss, timeRange, viaSync, dataLinks) => { render={(u, dataIdxs, seriesIdx, isPinned = false, dismiss, timeRange, viaSync, dataLinks) => {
return ( return (

View File

@ -17,6 +17,8 @@ import {
import { TooltipHoverMode } from '@grafana/ui/src/components/uPlot/plugins/TooltipPlugin2'; import { TooltipHoverMode } from '@grafana/ui/src/components/uPlot/plugins/TooltipPlugin2';
import { getDisplayValuesForCalcs } from '@grafana/ui/src/components/uPlot/utils'; import { getDisplayValuesForCalcs } from '@grafana/ui/src/components/uPlot/utils';
import { getDataLinks } from '../status-history/utils';
import { XYChartTooltip } from './XYChartTooltip'; import { XYChartTooltip } from './XYChartTooltip';
import { Options } from './panelcfg.gen'; import { Options } from './panelcfg.gen';
import { prepConfig } from './scatter'; import { prepConfig } from './scatter';
@ -113,7 +115,11 @@ export const XYChartPanel2 = (props: Props2) => {
<TooltipPlugin2 <TooltipPlugin2
config={builder!} config={builder!}
hoverMode={TooltipHoverMode.xyOne} hoverMode={TooltipHoverMode.xyOne}
render={(u, dataIdxs, seriesIdx, isPinned, dismiss) => { getDataLinks={(seriesIdx, dataIdx) => {
const xySeries = series[seriesIdx - 1];
return getDataLinks(xySeries.y.field, dataIdx);
}}
render={(u, dataIdxs, seriesIdx, isPinned, dismiss, timeRange2, viaSync, dataLinks) => {
return ( return (
<XYChartTooltip <XYChartTooltip
data={props.data.series} data={props.data.series}
@ -123,6 +129,7 @@ export const XYChartPanel2 = (props: Props2) => {
isPinned={isPinned} isPinned={isPinned}
seriesIdx={seriesIdx!} seriesIdx={seriesIdx!}
replaceVariables={props.replaceVariables} replaceVariables={props.replaceVariables}
dataLinks={dataLinks}
/> />
); );
}} }}

View File

@ -1,6 +1,6 @@
import { ReactNode } from 'react'; import { ReactNode } from 'react';
import { DataFrame, InterpolateFunction } from '@grafana/data'; import { DataFrame, InterpolateFunction, LinkModel } from '@grafana/data';
import { alpha } from '@grafana/data/src/themes/colorManipulator'; import { alpha } from '@grafana/data/src/themes/colorManipulator';
import { VizTooltipContent } from '@grafana/ui/src/components/VizTooltip/VizTooltipContent'; import { VizTooltipContent } from '@grafana/ui/src/components/VizTooltip/VizTooltipContent';
import { VizTooltipFooter } from '@grafana/ui/src/components/VizTooltip/VizTooltipFooter'; import { VizTooltipFooter } from '@grafana/ui/src/components/VizTooltip/VizTooltipFooter';
@ -8,7 +8,7 @@ import { VizTooltipHeader } from '@grafana/ui/src/components/VizTooltip/VizToolt
import { VizTooltipWrapper } from '@grafana/ui/src/components/VizTooltip/VizTooltipWrapper'; import { VizTooltipWrapper } from '@grafana/ui/src/components/VizTooltip/VizTooltipWrapper';
import { ColorIndicator, VizTooltipItem } from '@grafana/ui/src/components/VizTooltip/types'; import { ColorIndicator, VizTooltipItem } from '@grafana/ui/src/components/VizTooltip/types';
import { getDataLinks, getFieldActions } from '../status-history/utils'; import { getFieldActions } from '../status-history/utils';
import { XYSeries } from './types2'; import { XYSeries } from './types2';
import { fmt } from './utils'; import { fmt } from './utils';
@ -21,6 +21,7 @@ export interface Props {
data: DataFrame[]; data: DataFrame[];
xySeries: XYSeries[]; xySeries: XYSeries[];
replaceVariables: InterpolateFunction; replaceVariables: InterpolateFunction;
dataLinks: LinkModel[];
} }
function stripSeriesName(fieldName: string, seriesName: string) { function stripSeriesName(fieldName: string, seriesName: string) {
@ -31,7 +32,16 @@ function stripSeriesName(fieldName: string, seriesName: string) {
return fieldName; return fieldName;
} }
export const XYChartTooltip = ({ dataIdxs, seriesIdx, data, xySeries, dismiss, isPinned, replaceVariables }: Props) => { export const XYChartTooltip = ({
dataIdxs,
seriesIdx,
data,
xySeries,
dismiss,
isPinned,
replaceVariables,
dataLinks,
}: Props) => {
const rowIndex = dataIdxs.find((idx) => idx !== null)!; const rowIndex = dataIdxs.find((idx) => idx !== null)!;
const series = xySeries[seriesIdx! - 1]; const series = xySeries[seriesIdx! - 1];
@ -93,12 +103,15 @@ export const XYChartTooltip = ({ dataIdxs, seriesIdx, data, xySeries, dismiss, i
let footer: ReactNode; let footer: ReactNode;
if (isPinned && seriesIdx != null) { if (seriesIdx != null) {
const links = getDataLinks(yField, rowIndex); const hasOneClickLink = dataLinks?.some((dataLink) => dataLink.oneClick === true);
const yFieldFrame = data.find((frame) => frame.fields.includes(yField))!;
const actions = getFieldActions(yFieldFrame, yField, replaceVariables, rowIndex);
footer = <VizTooltipFooter dataLinks={links} actions={actions} />; if (isPinned || hasOneClickLink) {
const yFieldFrame = data.find((frame) => frame.fields.includes(yField))!;
const actions = getFieldActions(yFieldFrame, yField, replaceVariables, rowIndex);
footer = <VizTooltipFooter dataLinks={dataLinks} actions={actions} />;
}
} }
return ( return (