import { useMemo, useState } from 'react'; import { PanelProps, DataFrameType, DashboardCursorSync } from '@grafana/data'; import { PanelDataErrorView } from '@grafana/runtime'; import { TooltipDisplayMode, VizOrientation } from '@grafana/schema'; import { EventBusPlugin, KeyboardPlugin, TooltipPlugin2, usePanelContext } from '@grafana/ui'; import { TimeRange2, TooltipHoverMode } from '@grafana/ui/src/components/uPlot/plugins/TooltipPlugin2'; import { TimeSeries } from 'app/core/components/TimeSeries/TimeSeries'; import { config } from 'app/core/config'; import { TimeSeriesTooltip } from './TimeSeriesTooltip'; import { Options } from './panelcfg.gen'; import { AnnotationsPlugin2 } from './plugins/AnnotationsPlugin2'; import { ExemplarsPlugin, getVisibleLabels } from './plugins/ExemplarsPlugin'; import { OutsideRangePlugin } from './plugins/OutsideRangePlugin'; import { ThresholdControlsPlugin } from './plugins/ThresholdControlsPlugin'; import { getPrepareTimeseriesSuggestion } from './suggestions'; import { getTimezones, prepareGraphableFields } from './utils'; interface TimeSeriesPanelProps extends PanelProps {} export const TimeSeriesPanel = ({ data, timeRange, timeZone, width, height, options, fieldConfig, onChangeTimeRange, replaceVariables, id, }: TimeSeriesPanelProps) => { const { sync, eventsScope, canAddAnnotations, onThresholdsChange, canEditThresholds, showThresholds, dataLinkPostProcessor, eventBus, } = usePanelContext(); // Vertical orientation is not available for users through config. // It is simplified version of horizontal time series panel and it does not support all plugins. const isVerticallyOriented = options.orientation === VizOrientation.Vertical; const frames = useMemo(() => prepareGraphableFields(data.series, config.theme2, timeRange), [data.series, timeRange]); const timezones = useMemo(() => getTimezones(options.timezone, timeZone), [options.timezone, timeZone]); const suggestions = useMemo(() => { if (frames?.length && frames.every((df) => df.meta?.type === DataFrameType.TimeSeriesLong)) { const s = getPrepareTimeseriesSuggestion(id); return { message: 'Long data must be converted to wide', suggestions: s ? [s] : undefined, }; } return undefined; }, [frames, id]); const enableAnnotationCreation = Boolean(canAddAnnotations && canAddAnnotations()); const [newAnnotationRange, setNewAnnotationRange] = useState(null); const cursorSync = sync?.() ?? DashboardCursorSync.Off; if (!frames || suggestions) { return ( ); } return ( {(uplotConfig, alignedFrame) => { return ( <> {cursorSync !== DashboardCursorSync.Off && ( )} {options.tooltip.mode !== TooltipDisplayMode.None && ( alignedFrame.fields[seriesIdx].getLinks?.({ valueRowIndex: dataIdx }) ?? [] } render={(u, dataIdxs, seriesIdx, isPinned = false, dismiss, timeRange2, viaSync, dataLinks) => { if (enableAnnotationCreation && timeRange2 != null) { setNewAnnotationRange(timeRange2); dismiss(); return; } const annotate = () => { let xVal = u.posToVal(u.cursor.left!, 'x'); setNewAnnotationRange({ from: xVal, to: xVal }); dismiss(); }; return ( // not sure it header time here works for annotations, since it's taken from nearest datapoint index ); }} maxWidth={options.tooltip.maxWidth} /> )} {!isVerticallyOriented && ( <> {data.annotations && ( )} {((canEditThresholds && onThresholdsChange) || showThresholds) && ( )} )} ); }} ); };