Compare commits
5 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| f77f87bde5 | |||
| 18e873fb59 | |||
| d99c5c2185 | |||
| 195bc409ef | |||
| 6a855ef6e4 |
@@ -212,6 +212,7 @@ export const VizTooltipRow = ({
|
|||||||
colorIndicator={colorIndicator}
|
colorIndicator={colorIndicator}
|
||||||
position={ColorIndicatorPosition.Trailing}
|
position={ColorIndicatorPosition.Trailing}
|
||||||
lineStyle={lineStyle}
|
lineStyle={lineStyle}
|
||||||
|
isHollow={isHiddenFromViz}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -148,18 +148,26 @@ export const getContentItems = (
|
|||||||
|
|
||||||
_restFields?.forEach((field) => {
|
_restFields?.forEach((field) => {
|
||||||
if (!field.config.custom?.hideFrom?.tooltip) {
|
if (!field.config.custom?.hideFrom?.tooltip) {
|
||||||
const { colorIndicator, colorPlacement } = getIndicatorAndPlacement(field);
|
const valueIdx = dataIdxs[seriesIdx ?? 0];
|
||||||
const display = field.display!(field.values[dataIdxs[0]!]);
|
|
||||||
|
|
||||||
rows.push({
|
if (valueIdx != null) {
|
||||||
label: field.state?.displayName ?? field.name,
|
const value = field.values[valueIdx];
|
||||||
value: formattedValueToString(display),
|
|
||||||
color: FALLBACK_COLOR,
|
if (value != null) {
|
||||||
colorIndicator,
|
const display = field.display!(value);
|
||||||
colorPlacement,
|
const { colorIndicator, colorPlacement } = getIndicatorAndPlacement(field);
|
||||||
lineStyle: field.config.custom?.lineStyle,
|
|
||||||
isHiddenFromViz: true,
|
rows.push({
|
||||||
});
|
label: field.state?.displayName ?? field.name,
|
||||||
|
value: formattedValueToString(display),
|
||||||
|
color: FALLBACK_COLOR,
|
||||||
|
colorIndicator,
|
||||||
|
colorPlacement,
|
||||||
|
lineStyle: field.config.custom?.lineStyle,
|
||||||
|
isHiddenFromViz: true,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -53,14 +53,6 @@ export interface GraphNGProps extends Themeable2 {
|
|||||||
dataLinkPostProcessor?: DataLinkPostProcessor;
|
dataLinkPostProcessor?: DataLinkPostProcessor;
|
||||||
cursorSync?: DashboardCursorSync;
|
cursorSync?: DashboardCursorSync;
|
||||||
|
|
||||||
// Remove fields that are hidden from the visualization before rendering
|
|
||||||
// The fields will still be available for other things like data links
|
|
||||||
// this is a temporary hack that only works when:
|
|
||||||
// 1. renderLegend (above) does not render <PlotLegend>
|
|
||||||
// 2. does not have legend series toggle
|
|
||||||
// 3. passes through all fields required for link/action gen (including those with hideFrom.viz)
|
|
||||||
omitHideFromViz?: boolean;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* needed for propsToDiff to re-init the plot & config
|
* needed for propsToDiff to re-init the plot & config
|
||||||
* this is a generic approach to plot re-init, without having to specify which panel-level options
|
* this is a generic approach to plot re-init, without having to specify which panel-level options
|
||||||
@@ -187,15 +179,6 @@ export class GraphNG extends Component<GraphNGProps, GraphNGState> {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
if (props.omitHideFromViz) {
|
|
||||||
const nonHiddenFields = alignedFrameFinal.fields.filter((field) => field.config.custom?.hideFrom?.viz !== true);
|
|
||||||
alignedFrameFinal = {
|
|
||||||
...alignedFrameFinal,
|
|
||||||
fields: nonHiddenFields,
|
|
||||||
length: nonHiddenFields.length,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
let config = this.state?.config;
|
let config = this.state?.config;
|
||||||
|
|
||||||
if (withConfig) {
|
if (withConfig) {
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ import { UPlotConfigBuilder, VizLayout, VizLegend, VizLegendItem } from '@grafan
|
|||||||
import { GraphNG, GraphNGProps } from '../GraphNG/GraphNG';
|
import { GraphNG, GraphNGProps } from '../GraphNG/GraphNG';
|
||||||
import { getXAxisConfig } from '../TimeSeries/utils';
|
import { getXAxisConfig } from '../TimeSeries/utils';
|
||||||
|
|
||||||
import { preparePlotConfigBuilder, TimelineMode } from './utils';
|
import { getSeriesAndRest, preparePlotConfigBuilder, TimelineMode } from './utils';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @alpha
|
* @alpha
|
||||||
@@ -56,8 +56,10 @@ export const TimelineChart = (props: TimelineProps) => {
|
|||||||
|
|
||||||
const prepConfig = useCallback(
|
const prepConfig = useCallback(
|
||||||
(alignedFrame: DataFrame, allFrames: DataFrame[], getTimeRange: () => TimeRange) => {
|
(alignedFrame: DataFrame, allFrames: DataFrame[], getTimeRange: () => TimeRange) => {
|
||||||
|
const { seriesFrame } = getSeriesAndRest(alignedFrame);
|
||||||
|
|
||||||
return preparePlotConfigBuilder({
|
return preparePlotConfigBuilder({
|
||||||
frame: alignedFrame,
|
frame: seriesFrame,
|
||||||
getTimeRange,
|
getTimeRange,
|
||||||
allFrames: frames,
|
allFrames: frames,
|
||||||
...props,
|
...props,
|
||||||
@@ -66,7 +68,7 @@ export const TimelineChart = (props: TimelineProps) => {
|
|||||||
timeZones: Array.isArray(timeZone) ? timeZone : [timeZone],
|
timeZones: Array.isArray(timeZone) ? timeZone : [timeZone],
|
||||||
|
|
||||||
// When there is only one row, use the full space
|
// When there is only one row, use the full space
|
||||||
rowHeight: alignedFrame.fields.length > 2 ? rowHeight : 1,
|
rowHeight: seriesFrame.fields.length > 2 ? rowHeight : 1,
|
||||||
getValueColor: getValueColor,
|
getValueColor: getValueColor,
|
||||||
|
|
||||||
hoverMulti: tooltip?.mode === TooltipDisplayMode.Multi,
|
hoverMulti: tooltip?.mode === TooltipDisplayMode.Multi,
|
||||||
@@ -105,7 +107,6 @@ export const TimelineChart = (props: TimelineProps) => {
|
|||||||
prepConfig={prepConfig}
|
prepConfig={prepConfig}
|
||||||
propsToDiff={propsToDiff}
|
propsToDiff={propsToDiff}
|
||||||
renderLegend={renderLegend}
|
renderLegend={renderLegend}
|
||||||
omitHideFromViz={true}
|
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ import { preparePlotFrame } from '../GraphNG/utils';
|
|||||||
import {
|
import {
|
||||||
findNextStateIndex,
|
findNextStateIndex,
|
||||||
fmtDuration,
|
fmtDuration,
|
||||||
|
getSeriesAndRest,
|
||||||
getThresholdItems,
|
getThresholdItems,
|
||||||
hasSpecialMappedValue,
|
hasSpecialMappedValue,
|
||||||
makeFramePerSeries,
|
makeFramePerSeries,
|
||||||
@@ -563,3 +564,95 @@ describe('hasSpecialMappedValue', () => {
|
|||||||
expect(hasSpecialMappedValue(field, valueMatch)).toEqual(expected);
|
expect(hasSpecialMappedValue(field, valueMatch)).toEqual(expected);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('getSeriesAndRest', () => {
|
||||||
|
it('should return all fields as series when none are hidden', () => {
|
||||||
|
const frame = toDataFrame({
|
||||||
|
fields: [
|
||||||
|
{ name: 'time', type: FieldType.time, values: [1, 2, 3] },
|
||||||
|
{ name: 'value1', type: FieldType.number, values: [10, 20, 30] },
|
||||||
|
{ name: 'value2', type: FieldType.string, values: ['a', 'b', 'c'] },
|
||||||
|
],
|
||||||
|
});
|
||||||
|
|
||||||
|
const result = getSeriesAndRest(frame);
|
||||||
|
|
||||||
|
expect(result.seriesFrame.fields).toHaveLength(3);
|
||||||
|
expect(result.restFields).toHaveLength(0);
|
||||||
|
expect(result.seriesFrame.fields.map((f) => f.name)).toEqual(['time', 'value1', 'value2']);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should separate hidden fields from visible fields', () => {
|
||||||
|
const frame = toDataFrame({
|
||||||
|
fields: [
|
||||||
|
{ name: 'time', type: FieldType.time, values: [1, 2, 3] },
|
||||||
|
{
|
||||||
|
name: 'visible1',
|
||||||
|
type: FieldType.number,
|
||||||
|
values: [10, 20, 30],
|
||||||
|
config: { custom: { hideFrom: { viz: false, legend: true } } },
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'hidden1',
|
||||||
|
type: FieldType.string,
|
||||||
|
values: ['a', 'b', 'c'],
|
||||||
|
config: { custom: { hideFrom: { viz: true } } },
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'visible2',
|
||||||
|
type: FieldType.number,
|
||||||
|
values: [100, 200, 300],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'hidden2',
|
||||||
|
type: FieldType.string,
|
||||||
|
values: ['x', 'y', 'z'],
|
||||||
|
config: { custom: { hideFrom: { viz: true, tooltip: false } } },
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
|
||||||
|
const result = getSeriesAndRest(frame);
|
||||||
|
|
||||||
|
expect(result.seriesFrame.fields).toHaveLength(3);
|
||||||
|
expect(result.restFields).toHaveLength(2);
|
||||||
|
expect(result.seriesFrame.fields.map((f) => f.name)).toEqual(['time', 'visible1', 'visible2']);
|
||||||
|
expect(result.restFields.map((f) => f.name)).toEqual(['hidden1', 'hidden2']);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should handle all fields being hidden', () => {
|
||||||
|
const frame = toDataFrame({
|
||||||
|
fields: [
|
||||||
|
{
|
||||||
|
name: 'time',
|
||||||
|
type: FieldType.time,
|
||||||
|
values: [1, 2, 3],
|
||||||
|
config: { custom: { hideFrom: { viz: true } } },
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'value1',
|
||||||
|
type: FieldType.number,
|
||||||
|
values: [10, 20, 30],
|
||||||
|
config: { custom: { hideFrom: { viz: true } } },
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
|
||||||
|
const result = getSeriesAndRest(frame);
|
||||||
|
|
||||||
|
expect(result.seriesFrame.fields).toHaveLength(0);
|
||||||
|
expect(result.restFields).toHaveLength(2);
|
||||||
|
expect(result.restFields.map((f) => f.name)).toEqual(['time', 'value1']);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should handle empty frame', () => {
|
||||||
|
const frame = toDataFrame({
|
||||||
|
fields: [],
|
||||||
|
});
|
||||||
|
|
||||||
|
const result = getSeriesAndRest(frame);
|
||||||
|
|
||||||
|
expect(result.seriesFrame.fields).toHaveLength(0);
|
||||||
|
expect(result.restFields).toHaveLength(0);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|||||||
@@ -756,3 +756,26 @@ export function fmtDuration(milliSeconds: number): string {
|
|||||||
: '0'
|
: '0'
|
||||||
).trim();
|
).trim();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function getSeriesAndRest(alignedFrame: DataFrame) {
|
||||||
|
const seriesFields: Field[] = [];
|
||||||
|
const restFields: Field[] = [];
|
||||||
|
|
||||||
|
alignedFrame.fields.forEach((field) => {
|
||||||
|
if (field.config.custom?.hideFrom?.viz) {
|
||||||
|
restFields.push(field);
|
||||||
|
} else {
|
||||||
|
seriesFields.push(field);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const seriesFrame: DataFrame = {
|
||||||
|
...alignedFrame,
|
||||||
|
fields: seriesFields,
|
||||||
|
};
|
||||||
|
|
||||||
|
return {
|
||||||
|
seriesFrame: seriesFrame,
|
||||||
|
restFields: restFields,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ import {
|
|||||||
import { TimeRange2, TooltipHoverMode } from '@grafana/ui/internal';
|
import { TimeRange2, TooltipHoverMode } from '@grafana/ui/internal';
|
||||||
import { TimelineChart } from 'app/core/components/TimelineChart/TimelineChart';
|
import { TimelineChart } from 'app/core/components/TimelineChart/TimelineChart';
|
||||||
import {
|
import {
|
||||||
|
getSeriesAndRest,
|
||||||
prepareTimelineFields,
|
prepareTimelineFields,
|
||||||
prepareTimelineLegendItems,
|
prepareTimelineLegendItems,
|
||||||
TimelineMode,
|
TimelineMode,
|
||||||
@@ -98,10 +99,13 @@ export const StateTimelinePanel = ({
|
|||||||
annotationLanes={options.annotations?.multiLane ? getXAnnotationFrames(data.annotations).length : undefined}
|
annotationLanes={options.annotations?.multiLane ? getXAnnotationFrames(data.annotations).length : undefined}
|
||||||
>
|
>
|
||||||
{(builder, alignedFrame) => {
|
{(builder, alignedFrame) => {
|
||||||
|
// TODO: refactor frame prep not to do this here, should be memod at panel level once GraphNG is dissolved
|
||||||
|
const { seriesFrame, restFields } = getSeriesAndRest(alignedFrame);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
{cursorSync !== DashboardCursorSync.Off && (
|
{cursorSync !== DashboardCursorSync.Off && (
|
||||||
<EventBusPlugin config={builder} eventBus={eventBus} frame={alignedFrame} />
|
<EventBusPlugin config={builder} eventBus={eventBus} frame={seriesFrame} />
|
||||||
)}
|
)}
|
||||||
<XAxisInteractionAreaPlugin config={builder} queryZoom={onChangeTimeRange} />
|
<XAxisInteractionAreaPlugin config={builder} queryZoom={onChangeTimeRange} />
|
||||||
{options.tooltip.mode !== TooltipDisplayMode.None && (
|
{options.tooltip.mode !== TooltipDisplayMode.None && (
|
||||||
@@ -114,7 +118,7 @@ export const StateTimelinePanel = ({
|
|||||||
syncMode={cursorSync}
|
syncMode={cursorSync}
|
||||||
syncScope={eventsScope}
|
syncScope={eventsScope}
|
||||||
getDataLinks={(seriesIdx, dataIdx) =>
|
getDataLinks={(seriesIdx, dataIdx) =>
|
||||||
alignedFrame.fields[seriesIdx].getLinks?.({ valueRowIndex: dataIdx }) ?? []
|
seriesFrame.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) {
|
||||||
@@ -132,7 +136,7 @@ export const StateTimelinePanel = ({
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<StateTimelineTooltip
|
<StateTimelineTooltip
|
||||||
series={alignedFrame}
|
series={seriesFrame}
|
||||||
dataIdxs={dataIdxs}
|
dataIdxs={dataIdxs}
|
||||||
seriesIdx={seriesIdx}
|
seriesIdx={seriesIdx}
|
||||||
mode={viaSync ? TooltipDisplayMode.Multi : options.tooltip.mode}
|
mode={viaSync ? TooltipDisplayMode.Multi : options.tooltip.mode}
|
||||||
@@ -145,13 +149,14 @@ export const StateTimelinePanel = ({
|
|||||||
replaceVariables={replaceVariables}
|
replaceVariables={replaceVariables}
|
||||||
dataLinks={dataLinks}
|
dataLinks={dataLinks}
|
||||||
canExecuteActions={userCanExecuteActions}
|
canExecuteActions={userCanExecuteActions}
|
||||||
|
_rest={restFields}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
}}
|
}}
|
||||||
maxWidth={options.tooltip.maxWidth}
|
maxWidth={options.tooltip.maxWidth}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
{alignedFrame.fields[0].config.custom?.axisPlacement !== AxisPlacement.Hidden && (
|
{seriesFrame.fields[0].config.custom?.axisPlacement !== AxisPlacement.Hidden && (
|
||||||
<AnnotationsPlugin2
|
<AnnotationsPlugin2
|
||||||
replaceVariables={replaceVariables}
|
replaceVariables={replaceVariables}
|
||||||
multiLane={options.annotations?.multiLane}
|
multiLane={options.annotations?.multiLane}
|
||||||
|
|||||||
@@ -35,6 +35,7 @@ export const StateTimelineTooltip = ({
|
|||||||
maxHeight,
|
maxHeight,
|
||||||
replaceVariables,
|
replaceVariables,
|
||||||
dataLinks,
|
dataLinks,
|
||||||
|
_rest,
|
||||||
}: StateTimelineTooltipProps) => {
|
}: StateTimelineTooltipProps) => {
|
||||||
const pluginContext = usePluginContext();
|
const pluginContext = usePluginContext();
|
||||||
const xField = series.fields[0];
|
const xField = series.fields[0];
|
||||||
@@ -45,7 +46,17 @@ export const StateTimelineTooltip = ({
|
|||||||
|
|
||||||
mode = isPinned ? TooltipDisplayMode.Single : mode;
|
mode = isPinned ? TooltipDisplayMode.Single : mode;
|
||||||
|
|
||||||
const contentItems = getContentItems(series.fields, xField, dataIdxs, seriesIdx, mode, sortOrder);
|
const contentItems = getContentItems(
|
||||||
|
series.fields,
|
||||||
|
xField,
|
||||||
|
dataIdxs,
|
||||||
|
seriesIdx,
|
||||||
|
mode,
|
||||||
|
sortOrder,
|
||||||
|
undefined,
|
||||||
|
undefined,
|
||||||
|
_rest
|
||||||
|
);
|
||||||
let endTime = null;
|
let endTime = null;
|
||||||
|
|
||||||
// append duration in single mode
|
// append duration in single mode
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ import {
|
|||||||
import { TimeRange2, TooltipHoverMode } from '@grafana/ui/internal';
|
import { TimeRange2, TooltipHoverMode } from '@grafana/ui/internal';
|
||||||
import { TimelineChart } from 'app/core/components/TimelineChart/TimelineChart';
|
import { TimelineChart } from 'app/core/components/TimelineChart/TimelineChart';
|
||||||
import {
|
import {
|
||||||
|
getSeriesAndRest,
|
||||||
prepareTimelineFields,
|
prepareTimelineFields,
|
||||||
prepareTimelineLegendItems,
|
prepareTimelineLegendItems,
|
||||||
TimelineMode,
|
TimelineMode,
|
||||||
@@ -113,10 +114,13 @@ export const StatusHistoryPanel = ({
|
|||||||
annotationLanes={options.annotations?.multiLane ? getXAnnotationFrames(data.annotations).length : undefined}
|
annotationLanes={options.annotations?.multiLane ? getXAnnotationFrames(data.annotations).length : undefined}
|
||||||
>
|
>
|
||||||
{(builder, alignedFrame) => {
|
{(builder, alignedFrame) => {
|
||||||
|
// TODO: refactor frame prep not to do this here, should be memod at panel level once GraphNG is dissolved
|
||||||
|
const { seriesFrame, restFields } = getSeriesAndRest(alignedFrame);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
{cursorSync !== DashboardCursorSync.Off && (
|
{cursorSync !== DashboardCursorSync.Off && (
|
||||||
<EventBusPlugin config={builder} eventBus={eventBus} frame={alignedFrame} />
|
<EventBusPlugin config={builder} eventBus={eventBus} frame={seriesFrame} />
|
||||||
)}
|
)}
|
||||||
<XAxisInteractionAreaPlugin config={builder} queryZoom={onChangeTimeRange} />
|
<XAxisInteractionAreaPlugin config={builder} queryZoom={onChangeTimeRange} />
|
||||||
{options.tooltip.mode !== TooltipDisplayMode.None && (
|
{options.tooltip.mode !== TooltipDisplayMode.None && (
|
||||||
@@ -129,7 +133,7 @@ export const StatusHistoryPanel = ({
|
|||||||
syncMode={cursorSync}
|
syncMode={cursorSync}
|
||||||
syncScope={eventsScope}
|
syncScope={eventsScope}
|
||||||
getDataLinks={(seriesIdx, dataIdx) =>
|
getDataLinks={(seriesIdx, dataIdx) =>
|
||||||
alignedFrame.fields[seriesIdx].getLinks?.({ valueRowIndex: dataIdx }) ?? []
|
seriesFrame.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) {
|
||||||
@@ -147,7 +151,7 @@ export const StatusHistoryPanel = ({
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<StateTimelineTooltip
|
<StateTimelineTooltip
|
||||||
series={alignedFrame}
|
series={seriesFrame}
|
||||||
dataIdxs={dataIdxs}
|
dataIdxs={dataIdxs}
|
||||||
seriesIdx={seriesIdx}
|
seriesIdx={seriesIdx}
|
||||||
mode={viaSync ? TooltipDisplayMode.Multi : options.tooltip.mode}
|
mode={viaSync ? TooltipDisplayMode.Multi : options.tooltip.mode}
|
||||||
@@ -160,13 +164,14 @@ export const StatusHistoryPanel = ({
|
|||||||
replaceVariables={replaceVariables}
|
replaceVariables={replaceVariables}
|
||||||
dataLinks={dataLinks}
|
dataLinks={dataLinks}
|
||||||
canExecuteActions={userCanExecuteActions}
|
canExecuteActions={userCanExecuteActions}
|
||||||
|
_rest={restFields}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
}}
|
}}
|
||||||
maxWidth={options.tooltip.maxWidth}
|
maxWidth={options.tooltip.maxWidth}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
{alignedFrame.fields[0].config.custom?.axisPlacement !== AxisPlacement.Hidden && (
|
{seriesFrame.fields[0].config.custom?.axisPlacement !== AxisPlacement.Hidden && (
|
||||||
<AnnotationsPlugin2
|
<AnnotationsPlugin2
|
||||||
replaceVariables={replaceVariables}
|
replaceVariables={replaceVariables}
|
||||||
multiLane={options.annotations?.multiLane}
|
multiLane={options.annotations?.multiLane}
|
||||||
|
|||||||
Reference in New Issue
Block a user