mirror of
https://github.com/grafana/grafana.git
synced 2025-02-20 11:48:34 -06:00
126 lines
3.0 KiB
TypeScript
126 lines
3.0 KiB
TypeScript
import {
|
|
ArrayVector,
|
|
DataFrame,
|
|
Field,
|
|
FieldType,
|
|
getDisplayProcessor,
|
|
GrafanaTheme2,
|
|
isBooleanUnit,
|
|
TimeRange,
|
|
} from '@grafana/data';
|
|
import { GraphFieldConfig, LineInterpolation } from '@grafana/schema';
|
|
import { applyNullInsertThreshold } from '@grafana/ui/src/components/GraphNG/nullInsertThreshold';
|
|
import { nullToValue } from '@grafana/ui/src/components/GraphNG/nullToValue';
|
|
|
|
/**
|
|
* Returns null if there are no graphable fields
|
|
*/
|
|
export function prepareGraphableFields(
|
|
series: DataFrame[],
|
|
theme: GrafanaTheme2,
|
|
timeRange?: TimeRange
|
|
): DataFrame[] | null {
|
|
if (!series?.length) {
|
|
return null;
|
|
}
|
|
|
|
let copy: Field;
|
|
|
|
const frames: DataFrame[] = [];
|
|
|
|
for (let frame of series) {
|
|
const fields: Field[] = [];
|
|
|
|
let hasTimeField = false;
|
|
let hasValueField = false;
|
|
|
|
let nulledFrame = applyNullInsertThreshold({
|
|
frame,
|
|
refFieldPseudoMin: timeRange?.from.valueOf(),
|
|
refFieldPseudoMax: timeRange?.to.valueOf(),
|
|
});
|
|
|
|
for (const field of nullToValue(nulledFrame).fields) {
|
|
switch (field.type) {
|
|
case FieldType.time:
|
|
hasTimeField = true;
|
|
fields.push(field);
|
|
break;
|
|
case FieldType.number:
|
|
hasValueField = true;
|
|
copy = {
|
|
...field,
|
|
values: new ArrayVector(
|
|
field.values.toArray().map((v) => {
|
|
if (!(Number.isFinite(v) || v == null)) {
|
|
return null;
|
|
}
|
|
return v;
|
|
})
|
|
),
|
|
};
|
|
|
|
fields.push(copy);
|
|
break; // ok
|
|
case FieldType.boolean:
|
|
hasValueField = true;
|
|
const custom: GraphFieldConfig = field.config?.custom ?? {};
|
|
const config = {
|
|
...field.config,
|
|
max: 1,
|
|
min: 0,
|
|
custom,
|
|
};
|
|
|
|
// smooth and linear do not make sense
|
|
if (custom.lineInterpolation !== LineInterpolation.StepBefore) {
|
|
custom.lineInterpolation = LineInterpolation.StepAfter;
|
|
}
|
|
|
|
copy = {
|
|
...field,
|
|
config,
|
|
type: FieldType.number,
|
|
values: new ArrayVector(
|
|
field.values.toArray().map((v) => {
|
|
if (v == null) {
|
|
return v;
|
|
}
|
|
return Boolean(v) ? 1 : 0;
|
|
})
|
|
),
|
|
};
|
|
|
|
if (!isBooleanUnit(config.unit)) {
|
|
config.unit = 'bool';
|
|
copy.display = getDisplayProcessor({ field: copy, theme });
|
|
}
|
|
|
|
fields.push(copy);
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (hasTimeField && hasValueField) {
|
|
frames.push({
|
|
...frame,
|
|
length: nulledFrame.length,
|
|
fields,
|
|
});
|
|
}
|
|
}
|
|
|
|
if (frames.length) {
|
|
return frames;
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
export function getTimezones(timezones: string[] | undefined, defaultTimezone: string): string[] {
|
|
if (!timezones || !timezones.length) {
|
|
return [defaultTimezone];
|
|
}
|
|
return timezones.map((v) => (v?.length ? v : defaultTimezone));
|
|
}
|