Files
grafana/public/app/plugins/panel/timeseries/TimeSeriesPanel.tsx

171 lines
5.9 KiB
TypeScript

import React, { useMemo } from 'react';
import { PanelProps, DataFrameType } from '@grafana/data';
import { PanelDataErrorView } from '@grafana/runtime';
import { TooltipDisplayMode } from '@grafana/schema';
import { KeyboardPlugin, TimeSeries, TooltipPlugin, usePanelContext, ZoomPlugin } from '@grafana/ui';
import { config } from 'app/core/config';
import { Options } from './panelcfg.gen';
import { AnnotationEditorPlugin } from './plugins/AnnotationEditorPlugin';
import { AnnotationsPlugin } from './plugins/AnnotationsPlugin';
import { ContextMenuPlugin } from './plugins/ContextMenuPlugin';
import { ExemplarsPlugin, getVisibleLabels } from './plugins/ExemplarsPlugin';
import { OutsideRangePlugin } from './plugins/OutsideRangePlugin';
import { ThresholdControlsPlugin } from './plugins/ThresholdControlsPlugin';
import { getPrepareTimeseriesSuggestion } from './suggestions';
import { getTimezones, prepareGraphableFields, regenerateLinksSupplier } from './utils';
interface TimeSeriesPanelProps extends PanelProps<Options> {}
export const TimeSeriesPanel = ({
data,
timeRange,
timeZone,
width,
height,
options,
fieldConfig,
onChangeTimeRange,
replaceVariables,
id,
}: TimeSeriesPanelProps) => {
const { sync, canAddAnnotations, onThresholdsChange, canEditThresholds, showThresholds, dataLinkPostProcessor } =
usePanelContext();
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]);
if (!frames || suggestions) {
return (
<PanelDataErrorView
panelId={id}
message={suggestions?.message}
fieldConfig={fieldConfig}
data={data}
needsTimeField={true}
needsNumberField={true}
suggestions={suggestions?.suggestions}
/>
);
}
const enableAnnotationCreation = Boolean(canAddAnnotations && canAddAnnotations());
return (
<TimeSeries
frames={frames}
structureRev={data.structureRev}
timeRange={timeRange}
timeZone={timezones}
width={width}
height={height}
legend={options.legend}
options={options}
>
{(config, alignedDataFrame) => {
if (alignedDataFrame.fields.some((f) => Boolean(f.config.links?.length))) {
alignedDataFrame = regenerateLinksSupplier(
alignedDataFrame,
frames,
replaceVariables,
timeZone,
dataLinkPostProcessor
);
}
return (
<>
<KeyboardPlugin config={config} />
<ZoomPlugin config={config} onZoom={onChangeTimeRange} withZoomY={true} />
{options.tooltip.mode === TooltipDisplayMode.None || (
<TooltipPlugin
frames={frames}
data={alignedDataFrame}
config={config}
mode={options.tooltip.mode}
sortOrder={options.tooltip.sort}
sync={sync}
timeZone={timeZone}
/>
)}
{/* Renders annotation markers*/}
{data.annotations && (
<AnnotationsPlugin annotations={data.annotations} config={config} timeZone={timeZone} />
)}
{/* Enables annotations creation*/}
{enableAnnotationCreation ? (
<AnnotationEditorPlugin data={alignedDataFrame} timeZone={timeZone} config={config}>
{({ startAnnotating }) => {
return (
<ContextMenuPlugin
data={alignedDataFrame}
config={config}
timeZone={timeZone}
replaceVariables={replaceVariables}
defaultItems={[
{
items: [
{
label: 'Add annotation',
ariaLabel: 'Add annotation',
icon: 'comment-alt',
onClick: (e, p) => {
if (!p) {
return;
}
startAnnotating({ coords: p.coords });
},
},
],
},
]}
/>
);
}}
</AnnotationEditorPlugin>
) : (
<ContextMenuPlugin
data={alignedDataFrame}
frames={frames}
config={config}
timeZone={timeZone}
replaceVariables={replaceVariables}
defaultItems={[]}
/>
)}
{data.annotations && (
<ExemplarsPlugin
visibleSeries={getVisibleLabels(config, frames)}
config={config}
exemplars={data.annotations}
timeZone={timeZone}
/>
)}
{((canEditThresholds && onThresholdsChange) || showThresholds) && (
<ThresholdControlsPlugin
config={config}
fieldConfig={fieldConfig}
onThresholdsChange={canEditThresholds ? onThresholdsChange : undefined}
/>
)}
<OutsideRangePlugin config={config} onChangeTimeRange={onChangeTimeRange} />
</>
);
}}
</TimeSeries>
);
};