Timeseries: add UI to control the span nulls threshold (#32222)

This commit is contained in:
Ryan McKinley 2021-03-24 21:32:03 -07:00 committed by GitHub
parent d33a77a67f
commit ea186947d2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 87 additions and 12 deletions

View File

@ -155,18 +155,28 @@ Dot spacing set to 0, 30:
Choose how null values (gaps in the data) are displayed on the graph.
#### Gaps
#### Connect null values
If there is a gap in the series, the line in the graph will be broken and show the gap.
If there are null values in the series, the line can be connected or show gaps
![Null values gaps example](/img/docs/time-series-panel/line-graph-null-gaps-7-4.png)
#### Connected
#### Never
If there is a gap in the series, the line will skip the gap and connect to the next non-null value.
When values are missing in the data, they will be rendered as gaps in the line
#### Always
If there is a gap in the data, the line will be shown connected to the next non-null value
![Null values connected example](/img/docs/time-series-panel/line-graph-null-connected-7-4.png)
#### Threshold
The threshold settings allows specifying a maximum time between points that should be connected.
### Show points
Choose when the points should be shown on the graph.

View File

@ -0,0 +1,65 @@
import React from 'react';
import { FieldOverrideEditorProps, rangeUtil, SelectableValue } from '@grafana/data';
import { HorizontalGroup, Input, RadioButtonGroup } from '@grafana/ui';
const GAPS_OPTIONS: Array<SelectableValue<boolean | number>> = [
{
label: 'Never',
value: false,
},
{
label: 'Always',
value: true,
},
{
label: 'Threshold',
value: 3600000, // 1h
},
];
export const SpanNullsEditor: React.FC<FieldOverrideEditorProps<boolean | number, any>> = ({ value, onChange }) => {
const isThreshold = typeof value === 'number';
const formattedTime = isThreshold ? rangeUtil.secondsToHms((value as number) / 1000) : undefined;
GAPS_OPTIONS[2].value = isThreshold ? (value as number) : 3600000; // 1h
const checkAndUpdate = (txt: string) => {
let val: boolean | number = false;
if (txt) {
try {
val = rangeUtil.intervalToSeconds(txt) * 1000;
} catch (err) {
console.warn('ERROR', err);
}
}
onChange(val);
};
const handleEnterKey = (e: React.KeyboardEvent<HTMLInputElement>) => {
if (e.key !== 'Enter') {
return;
}
checkAndUpdate((e.target as any).value);
};
const handleBlur = (e: React.FocusEvent<HTMLInputElement>) => {
checkAndUpdate(e.target.value);
};
return (
<HorizontalGroup>
<RadioButtonGroup value={value} options={GAPS_OPTIONS} onChange={onChange} />
{isThreshold && (
<Input
autoFocus={true}
placeholder="never"
width={10}
defaultValue={formattedTime}
onKeyDown={handleEnterKey}
onBlur={handleBlur}
prefix={<div>&lt;</div>}
spellCheck={false}
/>
)}
</HorizontalGroup>
);
};

View File

@ -30,6 +30,7 @@ import { ScaleDistributionEditor } from './ScaleDistributionEditor';
import { LineStyleEditor } from './LineStyleEditor';
import { FillBellowToEditor } from './FillBelowToEditor';
import { OptionsWithLegend } from './types';
import { SpanNullsEditor } from './SpanNullsEditor';
export const defaultGraphConfig: GraphFieldConfig = {
drawStyle: DrawStyle.Line,
@ -133,17 +134,16 @@ export function getGraphFieldConfig(cfg: GraphFieldConfig): SetFieldConfigOption
process: identityOverrideProcessor,
shouldApply: (f) => f.type === FieldType.number,
})
.addRadio({
.addCustomEditor<void, boolean>({
id: 'spanNulls',
path: 'spanNulls',
name: 'Null values',
name: 'Connect null values',
defaultValue: false,
settings: {
options: [
{ label: 'Gaps', value: false },
{ label: 'Connected', value: true },
],
},
editor: SpanNullsEditor,
override: SpanNullsEditor,
showIf: (c) => c.drawStyle === DrawStyle.Line,
shouldApply: (f) => f.type !== FieldType.time,
process: identityOverrideProcessor,
})
.addRadio({
path: 'showPoints',