|
|
|
import { PanelOptions, Threshold, Icon, IconPosition, Condition } from 'types';
|
|
|
|
|
|
|
|
import { formatValue, getLastMetricValue } from '../../utils';
|
|
|
|
|
|
|
|
import _ from 'lodash';
|
|
|
|
|
|
|
|
// Convert Grafana options into Chartwerk Gauge options
|
|
|
|
export class GaugeOptions {
|
|
|
|
private minValue: number | undefined;
|
|
|
|
private maxValue: number | undefined;
|
|
|
|
private thresholds: Array<{ value: number; color: string }> = [];
|
|
|
|
private icons: Array<{ src: string; position: string; size: number }> = [];
|
|
|
|
|
|
|
|
constructor(private grafanaSeriesList: any[], private grafanaOptions: PanelOptions) {
|
|
|
|
this._setMin();
|
|
|
|
this._setMax();
|
|
|
|
this._setThresholds();
|
|
|
|
this._setIcons();
|
|
|
|
}
|
|
|
|
|
|
|
|
private _setMin(): void {
|
|
|
|
if (!this.grafanaOptions.gauge.min) {
|
|
|
|
throw new Error(`Min Config is not selected: [See options: Extremum -> Min]`);
|
|
|
|
}
|
|
|
|
if (!this.grafanaOptions.gauge.min?.useMetric) {
|
|
|
|
this.minValue = this.grafanaOptions.gauge.min.value;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
const aggregatedValue = getLastMetricValue(this.grafanaSeriesList, this.grafanaOptions.gauge.min.metricName, 'Min');
|
|
|
|
this.minValue = aggregatedValue ? aggregatedValue : undefined;
|
|
|
|
}
|
|
|
|
|
|
|
|
private _setMax(): void {
|
|
|
|
if (!this.grafanaOptions.gauge.max) {
|
|
|
|
throw new Error(`Max Config is not selected: [See options: Extremum -> Max]`);
|
|
|
|
}
|
|
|
|
if (!this.grafanaOptions.gauge.max?.useMetric) {
|
|
|
|
this.maxValue = this.grafanaOptions.gauge.max.value;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
const aggregatedValue = getLastMetricValue(this.grafanaSeriesList, this.grafanaOptions.gauge.max.metricName, 'Max');
|
|
|
|
this.maxValue = aggregatedValue ? aggregatedValue : undefined;
|
|
|
|
}
|
|
|
|
|
|
|
|
private _setThresholds(): void {
|
|
|
|
if (_.isEmpty(this.grafanaOptions.gauge.thresholds.thresholds)) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
for (let [idx, threshold] of this.grafanaOptions.gauge.thresholds.thresholds.entries()) {
|
|
|
|
this._setThreshold(threshold, idx);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
private _setThreshold(threshold: Threshold, idx: number): void {
|
|
|
|
const value = threshold.useMetric
|
|
|
|
? getLastMetricValue(this.grafanaSeriesList, threshold.metricName, `Threshold ${idx + 1}`)
|
|
|
|
: threshold.value;
|
|
|
|
if (value === null || value === undefined) {
|
|
|
|
// TODO: may be throw an error
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
this.thresholds.push({
|
|
|
|
value,
|
|
|
|
color: threshold.color,
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
private _setIcons(): void {
|
|
|
|
if (_.isEmpty(this.grafanaOptions.gauge.icons)) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
for (let [idx, icon] of this.grafanaOptions.gauge.icons.entries()) {
|
|
|
|
this._setIcon(icon, idx);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
private _setIcon(icon: Icon, idx: number): void {
|
|
|
|
if (!this._areIconConditionsFulfilled(icon, idx)) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
this.icons.push({
|
|
|
|
src: icon.url,
|
|
|
|
size: icon.size,
|
|
|
|
position: this._getChartwerkIconPosition(icon.position),
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
private _areIconConditionsFulfilled(icon: Icon, iconIdx: number): boolean {
|
|
|
|
if (_.isEmpty(icon.metrics)) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
// check each condition and return false if something goes wrong
|
|
|
|
for (let [conditionIdx, metric] of icon.metrics.entries()) {
|
|
|
|
const value = getLastMetricValue(this.grafanaSeriesList, metric, `Icon ${iconIdx + 1}, Condition ${conditionIdx + 1}`);
|
|
|
|
if (value === null || value === undefined) {
|
|
|
|
// TODO: may be throw an error
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
if (!this._checkIconCondition(value, icon.values[conditionIdx], icon.conditions[conditionIdx])) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
private _checkIconCondition(metricValue: number, inputValue: number, condition: Condition): boolean {
|
|
|
|
if (inputValue === undefined || inputValue === null) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
switch (condition) {
|
|
|
|
case Condition.EQUAL:
|
|
|
|
return metricValue === inputValue;
|
|
|
|
case Condition.GREATER:
|
|
|
|
return metricValue > inputValue;
|
|
|
|
case Condition.GREATER_OR_EQUAL:
|
|
|
|
return metricValue >= inputValue;
|
|
|
|
case Condition.LESS:
|
|
|
|
return metricValue < inputValue;
|
|
|
|
case Condition.LESS_OR_EQUAL:
|
|
|
|
return metricValue <= inputValue;
|
|
|
|
default:
|
|
|
|
throw new Error(`Unknown condition: ${condition}`);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
private _getChartwerkIconPosition(position: IconPosition): string {
|
|
|
|
// TODO: use chartwerk types
|
|
|
|
switch (position) {
|
|
|
|
case IconPosition.MIDDLE:
|
|
|
|
return 'middle';
|
|
|
|
case IconPosition.UPPER_LEFT:
|
|
|
|
return 'left';
|
|
|
|
case IconPosition.UPPER_RIGHT:
|
|
|
|
return 'right';
|
|
|
|
default:
|
|
|
|
throw new Error(`Unknown Icon Position ${position}`);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
getChartwerkOptions(): any {
|
|
|
|
return {
|
|
|
|
maxValue: this.maxValue,
|
|
|
|
minValue: this.minValue,
|
|
|
|
valueFormatter: (val: number) => formatValue(val, this.grafanaOptions.gauge),
|
|
|
|
defaultColor: this.grafanaOptions.gauge.thresholds.defaultColor,
|
|
|
|
valueArcBackgroundColor: this.grafanaOptions.gauge.thresholds.arcBackground,
|
|
|
|
reversed: this.grafanaOptions.gauge.reversed,
|
|
|
|
stops: this.thresholds,
|
|
|
|
valueFontSize: this.grafanaOptions.gauge.valueSize,
|
|
|
|
icons: this.icons,
|
|
|
|
};
|
|
|
|
}
|
|
|
|
}
|