2021-01-15 09:20:20 -06:00
|
|
|
import {
|
|
|
|
AbsoluteTimeRange,
|
|
|
|
applyFieldOverrides,
|
|
|
|
createFieldConfigRegistry,
|
|
|
|
DataFrame,
|
|
|
|
dateTime,
|
|
|
|
Field,
|
|
|
|
FieldColorModeId,
|
|
|
|
FieldConfigSource,
|
|
|
|
GrafanaTheme,
|
|
|
|
TimeZone,
|
|
|
|
} from '@grafana/data';
|
|
|
|
import {
|
|
|
|
Collapse,
|
|
|
|
DrawStyle,
|
|
|
|
GraphNG,
|
|
|
|
GraphNGLegendEvent,
|
|
|
|
Icon,
|
|
|
|
LegendDisplayMode,
|
|
|
|
TooltipPlugin,
|
|
|
|
useStyles,
|
2021-04-29 05:44:06 -05:00
|
|
|
useTheme2,
|
2021-01-15 09:20:20 -06:00
|
|
|
ZoomPlugin,
|
2021-04-20 02:45:41 -05:00
|
|
|
TooltipDisplayMode,
|
2021-01-15 09:20:20 -06:00
|
|
|
} from '@grafana/ui';
|
|
|
|
import { defaultGraphConfig, getGraphFieldConfig } from 'app/plugins/panel/timeseries/config';
|
|
|
|
import { hideSeriesConfigFactory } from 'app/plugins/panel/timeseries/overrides/hideSeriesConfigFactory';
|
|
|
|
import { ContextMenuPlugin } from 'app/plugins/panel/timeseries/plugins/ContextMenuPlugin';
|
|
|
|
import { ExemplarsPlugin } from 'app/plugins/panel/timeseries/plugins/ExemplarsPlugin';
|
2021-04-01 07:15:23 -05:00
|
|
|
import { css, cx } from '@emotion/css';
|
2021-01-15 09:20:20 -06:00
|
|
|
import React, { useCallback, useMemo, useState } from 'react';
|
|
|
|
import { splitOpen } from './state/main';
|
|
|
|
import { getFieldLinksForExplore } from './utils/links';
|
|
|
|
|
|
|
|
const MAX_NUMBER_OF_TIME_SERIES = 20;
|
|
|
|
|
|
|
|
interface Props {
|
|
|
|
data: DataFrame[];
|
|
|
|
annotations?: DataFrame[];
|
|
|
|
isLoading: boolean;
|
|
|
|
width: number;
|
|
|
|
absoluteRange: AbsoluteTimeRange;
|
|
|
|
timeZone: TimeZone;
|
|
|
|
onUpdateTimeRange: (absoluteRange: AbsoluteTimeRange) => void;
|
|
|
|
splitOpenFn: typeof splitOpen;
|
|
|
|
}
|
|
|
|
|
|
|
|
export function ExploreGraphNGPanel({
|
|
|
|
width,
|
|
|
|
data,
|
|
|
|
timeZone,
|
|
|
|
absoluteRange,
|
|
|
|
onUpdateTimeRange,
|
|
|
|
isLoading,
|
|
|
|
annotations,
|
|
|
|
splitOpenFn,
|
|
|
|
}: Props) {
|
2021-04-29 05:44:06 -05:00
|
|
|
const theme = useTheme2();
|
2021-01-15 09:20:20 -06:00
|
|
|
const [showAllTimeSeries, setShowAllTimeSeries] = useState(false);
|
2021-04-26 06:30:04 -05:00
|
|
|
const [structureRev, setStructureRev] = useState(1);
|
2021-01-15 09:20:20 -06:00
|
|
|
const [fieldConfig, setFieldConfig] = useState<FieldConfigSource>({
|
|
|
|
defaults: {
|
|
|
|
color: {
|
|
|
|
mode: FieldColorModeId.PaletteClassic,
|
|
|
|
},
|
|
|
|
custom: {
|
|
|
|
drawStyle: DrawStyle.Line,
|
|
|
|
fillOpacity: 0,
|
|
|
|
pointSize: 5,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
overrides: [],
|
|
|
|
});
|
|
|
|
|
|
|
|
const style = useStyles(getStyles);
|
|
|
|
const timeRange = {
|
|
|
|
from: dateTime(absoluteRange.from),
|
|
|
|
to: dateTime(absoluteRange.to),
|
|
|
|
raw: {
|
|
|
|
from: dateTime(absoluteRange.from),
|
|
|
|
to: dateTime(absoluteRange.to),
|
|
|
|
},
|
|
|
|
};
|
|
|
|
|
|
|
|
const dataWithConfig = useMemo(() => {
|
|
|
|
const registry = createFieldConfigRegistry(getGraphFieldConfig(defaultGraphConfig), 'Explore');
|
|
|
|
return applyFieldOverrides({
|
|
|
|
fieldConfig,
|
|
|
|
data,
|
|
|
|
timeZone,
|
2021-01-20 00:59:48 -06:00
|
|
|
replaceVariables: (value) => value, // We don't need proper replace here as it is only used in getLinks and we use getFieldLinks
|
2021-01-15 09:20:20 -06:00
|
|
|
theme,
|
|
|
|
fieldConfigRegistry: registry,
|
|
|
|
});
|
|
|
|
}, [fieldConfig, data, timeZone, theme]);
|
|
|
|
|
|
|
|
const onLegendClick = useCallback(
|
|
|
|
(event: GraphNGLegendEvent) => {
|
2021-04-26 06:30:04 -05:00
|
|
|
setStructureRev((r) => r + 1);
|
2021-01-15 09:20:20 -06:00
|
|
|
setFieldConfig(hideSeriesConfigFactory(event, fieldConfig, data));
|
|
|
|
},
|
|
|
|
[fieldConfig, data]
|
|
|
|
);
|
|
|
|
|
|
|
|
const seriesToShow = showAllTimeSeries ? dataWithConfig : dataWithConfig.slice(0, MAX_NUMBER_OF_TIME_SERIES);
|
|
|
|
|
|
|
|
const getFieldLinks = (field: Field, rowIndex: number) => {
|
|
|
|
return getFieldLinksForExplore({ field, rowIndex, splitOpenFn, range: timeRange });
|
|
|
|
};
|
|
|
|
|
|
|
|
return (
|
|
|
|
<>
|
|
|
|
{dataWithConfig.length > MAX_NUMBER_OF_TIME_SERIES && !showAllTimeSeries && (
|
|
|
|
<div className={cx([style.timeSeriesDisclaimer])}>
|
|
|
|
<Icon className={style.disclaimerIcon} name="exclamation-triangle" />
|
|
|
|
{`Showing only ${MAX_NUMBER_OF_TIME_SERIES} time series. `}
|
|
|
|
<span
|
|
|
|
className={cx([style.showAllTimeSeries])}
|
|
|
|
onClick={() => setShowAllTimeSeries(true)}
|
|
|
|
>{`Show all ${dataWithConfig.length}`}</span>
|
|
|
|
</div>
|
|
|
|
)}
|
|
|
|
|
|
|
|
<Collapse label="Graph" loading={isLoading} isOpen>
|
|
|
|
<GraphNG
|
|
|
|
data={seriesToShow}
|
2021-04-26 06:30:04 -05:00
|
|
|
structureRev={structureRev}
|
2021-01-15 09:20:20 -06:00
|
|
|
width={width}
|
|
|
|
height={400}
|
|
|
|
timeRange={timeRange}
|
|
|
|
onLegendClick={onLegendClick}
|
2021-01-15 10:30:40 -06:00
|
|
|
legend={{ displayMode: LegendDisplayMode.List, placement: 'bottom', calcs: [] }}
|
2021-01-15 09:20:20 -06:00
|
|
|
timeZone={timeZone}
|
|
|
|
>
|
2021-04-26 06:30:04 -05:00
|
|
|
{(config, alignedDataFrame) => {
|
|
|
|
return (
|
|
|
|
<>
|
|
|
|
<ZoomPlugin config={config} onZoom={onUpdateTimeRange} />
|
|
|
|
<TooltipPlugin
|
|
|
|
config={config}
|
|
|
|
data={alignedDataFrame}
|
|
|
|
mode={TooltipDisplayMode.Single}
|
|
|
|
timeZone={timeZone}
|
|
|
|
/>
|
|
|
|
<ContextMenuPlugin config={config} data={alignedDataFrame} timeZone={timeZone} />
|
|
|
|
{annotations && (
|
|
|
|
<ExemplarsPlugin
|
|
|
|
config={config}
|
|
|
|
exemplars={annotations}
|
|
|
|
timeZone={timeZone}
|
|
|
|
getFieldLinks={getFieldLinks}
|
|
|
|
/>
|
|
|
|
)}
|
|
|
|
</>
|
|
|
|
);
|
|
|
|
}}
|
2021-01-15 09:20:20 -06:00
|
|
|
</GraphNG>
|
|
|
|
</Collapse>
|
|
|
|
</>
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
const getStyles = (theme: GrafanaTheme) => ({
|
|
|
|
timeSeriesDisclaimer: css`
|
|
|
|
label: time-series-disclaimer;
|
|
|
|
width: 300px;
|
|
|
|
margin: ${theme.spacing.sm} auto;
|
|
|
|
padding: 10px 0;
|
|
|
|
border-radius: ${theme.border.radius.md};
|
|
|
|
text-align: center;
|
|
|
|
background-color: ${theme.colors.bg1};
|
|
|
|
`,
|
|
|
|
disclaimerIcon: css`
|
|
|
|
label: disclaimer-icon;
|
|
|
|
color: ${theme.palette.yellow};
|
|
|
|
margin-right: ${theme.spacing.xs};
|
|
|
|
`,
|
|
|
|
showAllTimeSeries: css`
|
|
|
|
label: show-all-time-series;
|
|
|
|
cursor: pointer;
|
|
|
|
color: ${theme.colors.linkExternal};
|
|
|
|
`,
|
|
|
|
});
|