108 lines
2.9 KiB
TypeScript
108 lines
2.9 KiB
TypeScript
import { dropRight, last } from 'lodash';
|
|
|
|
import { DataFrame, Labels, roundDecimals } from '@grafana/data';
|
|
import { CombinedRuleNamespace } from 'app/types/unified-alerting';
|
|
|
|
import { isCloudRulesSource } from '../../utils/datasource';
|
|
|
|
/**
|
|
* ⚠️ `frame.fields` could be an empty array ⚠️
|
|
*
|
|
* TypeScript will NOT complain about it when accessing items via index signatures.
|
|
* Make sure to check for empty array or use optional chaining!
|
|
*
|
|
* see https://github.com/Microsoft/TypeScript/issues/13778
|
|
*/
|
|
|
|
const getSeriesName = (frame: DataFrame): string | undefined => {
|
|
const firstField = frame.fields[0];
|
|
|
|
const displayNameFromDS = firstField?.config?.displayNameFromDS;
|
|
return displayNameFromDS ?? frame.name ?? firstField?.labels?.__name__;
|
|
};
|
|
|
|
const getSeriesValue = (frame: DataFrame) => {
|
|
const value = frame.fields[0]?.values[0];
|
|
|
|
if (Number.isFinite(value)) {
|
|
return roundDecimals(value, 5);
|
|
}
|
|
|
|
return value;
|
|
};
|
|
|
|
const getSeriesLabels = (frame: DataFrame): Record<string, string> => {
|
|
const firstField = frame.fields[0];
|
|
return firstField?.labels ?? {};
|
|
};
|
|
|
|
const formatLabels = (labels: Labels): string => {
|
|
return Object.entries(labels)
|
|
.map(([key, value]) => key + '=' + value)
|
|
.join(', ');
|
|
};
|
|
|
|
interface DecodedNamespace {
|
|
name: string;
|
|
parents: string[];
|
|
}
|
|
|
|
/**
|
|
* After https://github.com/grafana/grafana/pull/74600,
|
|
* Grafana folder names will be returned from the API as a combination of the folder name and parent UID in a format of JSON array,
|
|
* where first element is parent UID and the second element is Title.
|
|
*
|
|
* Here we parse this to return the name of the last folder and the array of parent folders
|
|
*/
|
|
const decodeGrafanaNamespace = (namespace: CombinedRuleNamespace): DecodedNamespace => {
|
|
const namespaceName = namespace.name;
|
|
|
|
if (isCloudRulesSource(namespace.rulesSource)) {
|
|
return {
|
|
name: namespaceName,
|
|
parents: [],
|
|
};
|
|
}
|
|
|
|
// try to parse the folder as a nested folder, if it fails fall back to returning the folder name as-is.
|
|
try {
|
|
const folderParts: string[] = JSON.parse(namespaceName);
|
|
if (!Array.isArray(folderParts)) {
|
|
throw new Error('not a nested Grafana folder');
|
|
}
|
|
|
|
const name = last(folderParts) ?? namespaceName;
|
|
const parents = dropRight(folderParts, 1);
|
|
|
|
return {
|
|
name,
|
|
parents,
|
|
};
|
|
} catch {
|
|
return {
|
|
name: namespace.name,
|
|
parents: [],
|
|
};
|
|
}
|
|
};
|
|
|
|
const encodeGrafanaNamespace = (name: string, parents: string[] | undefined = []) => {
|
|
return JSON.stringify(parents.concat(name));
|
|
};
|
|
|
|
const isEmptySeries = (series: DataFrame[]): boolean => {
|
|
const isEmpty = series.every((serie) => serie.fields.every((field) => field.values.every((value) => value == null)));
|
|
|
|
return isEmpty;
|
|
};
|
|
|
|
export {
|
|
decodeGrafanaNamespace,
|
|
encodeGrafanaNamespace,
|
|
formatLabels,
|
|
getSeriesLabels,
|
|
getSeriesName,
|
|
getSeriesValue,
|
|
isEmptySeries,
|
|
};
|