diff --git a/CHANGELOG.md b/CHANGELOG.md
index 6ee7904..a8cba2f 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,6 +1,18 @@
# Changelog
-## 1.x.0
+## 1.14.0
+
+Threshold Support for Text Data
+-------------------------------
+This adds the ability to configure thresholds using regex patterns for text data.
+New config terms in siteConfig and panelConfig:
+- siteConfig:thresholdPatterns
+- panelConfig:cells.cell-name.labelColor.thresholdPatterns
+- panelConfig:cells.cell-name.labelColor.thresholdPatternsRef
+- panelConfig:cells.cell-name.strokeColor.thresholdPatterns
+- panelConfig:cells.cell-name.strokeColor.thresholdPatternsRef
+- panelConfig:cells.cell-name.fillColor.thresholdPatterns
+- panelConfig:cells.cell-name.fillColor.thresholdPatternsRef
Link in the Same Tab
--------------------
diff --git a/provisioning/dashboardData/stringData.yaml b/provisioning/dashboardData/stringData.yaml
index 0d0a5f0..4f68222 100644
--- a/provisioning/dashboardData/stringData.yaml
+++ b/provisioning/dashboardData/stringData.yaml
@@ -28,7 +28,7 @@ cells:
url: "https://github.com/andymchugh/andrewbmchugh-flow-panel/blob/main/src/README.md"
inbox_depth:
tags: ['depth']
- dataRef: "test-data-large-sin"
+ dataRef: "test-data-large-cos"
label:
dataRef: "test-data-string"
valueMappings:
@@ -79,6 +79,7 @@ cells:
separator: "cr"
units: "none"
labelColor:
- thresholds:
- - {color: "#888888", level: 0}
- - {color: "light-blue", level: 100}
+ thresholdPatterns:
+ - {color: "#888888", pattern: '\*1[0-9][0-9]\*'} # 100-199
+ - {color: "light-blue", pattern: '\*2[0-9][0-9]\*'} # 200-299
+ - {color: "green", pattern: '.*'} # base
diff --git a/provisioning/dashboardData/stringDataSparse.yaml b/provisioning/dashboardData/stringDataSparse.yaml
index 425a09a..472dbb4 100644
--- a/provisioning/dashboardData/stringDataSparse.yaml
+++ b/provisioning/dashboardData/stringDataSparse.yaml
@@ -80,6 +80,7 @@ cells:
separator: "cr"
units: "none"
labelColor:
+ dataRef: "test-data-large-cos"
thresholds:
- {color: "#888888", level: 0}
- {color: "light-blue", level: 100}
diff --git a/provisioning/dashboardData/stringDataThresholdPatterns.yaml b/provisioning/dashboardData/stringDataThresholdPatterns.yaml
new file mode 100644
index 0000000..accb3ba
--- /dev/null
+++ b/provisioning/dashboardData/stringDataThresholdPatterns.yaml
@@ -0,0 +1,80 @@
+---
+
+#------------------------------------------------------------------------------
+# YAML Aliases to simplify maintenance
+
+anchorLinks:
+ - link: &grafana-home
+ url: "https://grafana.com/"
+ params: "time"
+
+#------------------------------------------------------------------------------
+# Panel Config
+
+test:
+ testDataExtendedZero: true
+ testDataStringData: true
+
+cellIdPreamble: "cell-"
+gradientMode: "hue"
+tagConfig:
+ condensed: false
+cells:
+ drawio:
+ link:
+ url: "https://app.diagrams.net/?p=svgdata"
+ docs:
+ link:
+ url: "https://github.com/andymchugh/andrewbmchugh-flow-panel/blob/main/src/README.md"
+ inbox_depth:
+ tags: ['depth']
+ dataRef: "test-data-string"
+ label:
+ valueMappings:
+ - {value: "*0*", text: "*mapped to 0*"}
+ - {value: "*29*", text: "*mapped to 29*"}
+ - {valueMin: 300, valueMax: 600, text: "will never get here as data not a number"}
+ separator: "cr"
+ units: "none"
+ labelColor:
+ thresholdPatternsRef: "example"
+ link: *grafana-home
+ db_transactions:
+ dataRef: "test-data-large-cos"
+ label:
+ separator: "cr"
+ units: "ops"
+ fillColor:
+ thresholds:
+ - {color: "semi-dark-green", level: 0}
+ - {color: "orange", level: 400}
+ - {color: "red", level: 800}
+ link: *grafana-home
+ inbox_transactions:
+ tags: ['db']
+ dataRef: "test-data-large-cos"
+ inbox_workers:
+ tags: ['worker']
+ dataRef: "test-data-small-sin"
+ workers_reads:
+ dataRef: "test-data-small-sin"
+ start_rate:
+ dataRef: "test-data-small-sin"
+ label:
+ separator: "colon"
+ units: "pps"
+ labelColor:
+ thresholds:
+ - {color: "green", level: 0}
+ - {color: "orange", level: 100}
+ link: *grafana-home
+ active_workers:
+ dataRef: "test-data-string"
+ label:
+ separator: "cr"
+ units: "none"
+ labelColor:
+ thresholdPatterns:
+ - {color: "#888888", pattern: '\*1[0-9][0-9]\*'} # 100-199
+ - {color: "light-blue", pattern: '\*2[0-9][0-9]\*'} # 200-299
+ - {color: "green", pattern: '.*'} # base
diff --git a/provisioning/dashboardData/stringDataThresholdPatternsSite.yaml b/provisioning/dashboardData/stringDataThresholdPatternsSite.yaml
new file mode 100644
index 0000000..d060581
--- /dev/null
+++ b/provisioning/dashboardData/stringDataThresholdPatternsSite.yaml
@@ -0,0 +1,10 @@
+---
+
+#------------------------------------------------------------------------------
+# Site Config
+
+thresholdPatterns:
+ example:
+ - {color: "#888888", pattern: '\*1[0-9][0-9]\*'} # 100-199
+ - {color: "light-blue", pattern: '\*2[0-9][0-9]\*'} # 200-299
+ - {color: "green", pattern: '.*'} # base
diff --git a/provisioning/dashboards/stringData.json b/provisioning/dashboards/stringData.json
index 723f279..1214270 100644
--- a/provisioning/dashboards/stringData.json
+++ b/provisioning/dashboards/stringData.json
@@ -40,7 +40,7 @@
"showLineNumbers": false,
"showMiniMap": false
},
- "content": "# String Data \n\nThis shows labels being driven off of string timeseries in all the potential ways:\n- 'Inbox Depth' cell-label has dateRef override for string data so color drive\n also possible.\n- 'Active Workers' cell level dataRef is string data so color drive not possible\neven though defined\n- Value mappings: 'Inbox Depth' has a zero mapping and a 29 mapping defined.\nIt also has a range mapping that can't work because source data is a string.\n- Sparse data: The string data has a different timestamp cadence to the number\ndata and so comes and goes at a different frequency. This results in a a complete\nintermix of no-data / color-data with no label-data / label-data with no color-data / all-data",
+ "content": "# String Data \n\nThis shows labels being driven off of string timeseries:\n- 'Inbox Depth' cell-label uses a siteConfig thresholdPatternsRef to drive colors in the 100->300 range.\n- 'Active Workers' does the same with panelConfig thresholdPatterns.\n- Value mappings: 'Inbox Depth' has a zero mapping and a 29 mapping defined.\nIt also has a range mapping that can't work because source data is a string.\n- Sparse data: The string data has a different timestamp cadence to the number\ndata and so comes and goes at a different frequency. This results in a a complete\nintermix of no-data / color-data with no label-data / label-data with no color-data / all-data. In these examples\nnumber thresholds are used rather than pattern thresholds.",
"mode": "markdown"
},
"pluginVersion": "10.0.0",
@@ -69,8 +69,8 @@
},
"highlighterEnabled": true,
"panZoomEnabled": true,
- "panelConfig": "---\n\n#------------------------------------------------------------------------------\n# YAML Aliases to simplify maintenance\n\nanchorLinks:\n - link: &grafana-home\n url: \"https://grafana.com/\"\n params: \"time\"\n\n#------------------------------------------------------------------------------\n# Panel Config\n\ntest:\n testDataExtendedZero: true\n testDataStringData: true\n\ncellIdPreamble: \"cell-\"\ngradientMode: \"hue\"\ntagConfig:\n condensed: false\ncells: \n drawio:\n link:\n url: \"https://app.diagrams.net/?p=svgdata\"\n docs:\n link:\n url: \"https://github.com/andymchugh/andrewbmchugh-flow-panel/blob/main/src/README.md\"\n inbox_depth:\n tags: ['depth']\n dataRef: \"test-data-large-sin\"\n label:\n dataRef: \"test-data-string\"\n valueMappings:\n - {value: \"*0*\", text: \"*mapped to 0*\"}\n - {value: \"*29*\", text: \"*mapped to 29*\"}\n - {valueMin: 300, valueMax: 600, text: \"will never get here as data not a number\"}\n separator: \"cr\"\n units: \"none\"\n labelColor:\n gradientMode: \"hue\"\n thresholds:\n - {color: \"green\", level: 0}\n - {color: \"orange\", level: 500}\n - {color: \"red\", level: 1000}\n link: *grafana-home\n db_transactions:\n dataRef: \"test-data-large-cos\"\n label:\n separator: \"cr\"\n units: \"ops\"\n fillColor:\n thresholds:\n - {color: \"semi-dark-green\", level: 0}\n - {color: \"orange\", level: 400}\n - {color: \"red\", level: 800}\n link: *grafana-home\n inbox_transactions:\n tags: ['db']\n dataRef: \"test-data-large-cos\"\n inbox_workers:\n tags: ['worker']\n dataRef: \"test-data-small-sin\"\n workers_reads:\n dataRef: \"test-data-small-sin\"\n start_rate:\n dataRef: \"test-data-small-sin\"\n label:\n separator: \"colon\"\n units: \"pps\"\n labelColor:\n thresholds:\n - {color: \"green\", level: 0}\n - {color: \"orange\", level: 100}\n link: *grafana-home\n active_workers:\n dataRef: \"test-data-string\"\n label:\n separator: \"cr\"\n units: \"none\"\n labelColor:\n thresholds:\n - {color: \"#888888\", level: 0}\n - {color: \"light-blue\", level: 100}",
- "siteConfig": "",
+ "panelConfig": "---\n\n#------------------------------------------------------------------------------\n# YAML Aliases to simplify maintenance\n\nanchorLinks:\n - link: &grafana-home\n url: \"https://grafana.com/\"\n params: \"time\"\n\n#------------------------------------------------------------------------------\n# Panel Config\n\ntest:\n testDataExtendedZero: true\n testDataStringData: true\n\ncellIdPreamble: \"cell-\"\ngradientMode: \"hue\"\ntagConfig:\n condensed: false\ncells: \n drawio:\n link:\n url: \"https://app.diagrams.net/?p=svgdata\"\n docs:\n link:\n url: \"https://github.com/andymchugh/andrewbmchugh-flow-panel/blob/main/src/README.md\"\n inbox_depth:\n tags: ['depth']\n dataRef: \"test-data-string\"\n label:\n valueMappings:\n - {value: \"*0*\", text: \"*mapped to 0*\"}\n - {value: \"*29*\", text: \"*mapped to 29*\"}\n - {valueMin: 300, valueMax: 600, text: \"will never get here as data not a number\"}\n separator: \"cr\"\n units: \"none\"\n labelColor:\n thresholdPatternsRef: \"example\"\n link: *grafana-home\n db_transactions:\n dataRef: \"test-data-large-cos\"\n label:\n separator: \"cr\"\n units: \"ops\"\n fillColor:\n thresholds:\n - {color: \"semi-dark-green\", level: 0}\n - {color: \"orange\", level: 400}\n - {color: \"red\", level: 800}\n link: *grafana-home\n inbox_transactions:\n tags: ['db']\n dataRef: \"test-data-large-cos\"\n inbox_workers:\n tags: ['worker']\n dataRef: \"test-data-small-sin\"\n workers_reads:\n dataRef: \"test-data-small-sin\"\n start_rate:\n dataRef: \"test-data-small-sin\"\n label:\n separator: \"colon\"\n units: \"pps\"\n labelColor:\n thresholds:\n - {color: \"green\", level: 0}\n - {color: \"orange\", level: 100}\n link: *grafana-home\n active_workers:\n dataRef: \"test-data-string\"\n label:\n separator: \"cr\"\n units: \"none\"\n labelColor:\n thresholdPatterns:\n - {color: \"#888888\", pattern: '\\*1[0-9][0-9]\\*'} # 100-199\n - {color: \"light-blue\", pattern: '\\*2[0-9][0-9]\\*'} # 200-299\n - {color: \"green\", pattern: '.*'} # base",
+ "siteConfig": "---\n\n#------------------------------------------------------------------------------\n# Site Config\n\nthresholdPatterns:\n example:\n - {color: \"#888888\", pattern: '\\*1[0-9][0-9]\\*'} # 100-199\n - {color: \"light-blue\", pattern: '\\*2[0-9][0-9]\\*'} # 200-299\n - {color: \"green\", pattern: '.*'} # base",
"svg": "\n\n\n",
"testDataEnabled": true,
"timeSliderEnabled": true
@@ -101,7 +101,7 @@
},
"highlighterEnabled": true,
"panZoomEnabled": true,
- "panelConfig": "---\n\n#------------------------------------------------------------------------------\n# YAML Aliases to simplify maintenance\n\nanchorLinks:\n - link: &grafana-home\n url: \"https://grafana.com/\"\n params: \"time\"\n\n#------------------------------------------------------------------------------\n# Panel Config\n\ntest:\n testDataExtendedZero: true\n testDataStringData: true\n testDataSparse: true\n\ncellIdPreamble: \"cell-\"\ngradientMode: \"hue\"\ntagConfig:\n condensed: false\ncells: \n drawio:\n link:\n url: \"https://app.diagrams.net/?p=svgdata\"\n docs:\n link:\n url: \"https://github.com/andymchugh/andrewbmchugh-flow-panel/blob/main/src/README.md\"\n inbox_depth:\n tags: ['depth']\n dataRef: \"test-data-large-sin\"\n label:\n dataRef: \"test-data-string\"\n valueMappings:\n - {value: \"*0*\", text: \"*mapped to 0*\"}\n - {value: \"*29*\", text: \"*mapped to 29*\"}\n - {valueMin: 300, valueMax: 600, text: \"will never get here as data not a number\"}\n separator: \"cr\"\n units: \"none\"\n labelColor:\n gradientMode: \"hue\"\n thresholds:\n - {color: \"green\", level: 0}\n - {color: \"orange\", level: 500}\n - {color: \"red\", level: 1000}\n link: *grafana-home\n db_transactions:\n dataRef: \"test-data-large-cos\"\n label:\n separator: \"cr\"\n units: \"ops\"\n fillColor:\n thresholds:\n - {color: \"semi-dark-green\", level: 0}\n - {color: \"orange\", level: 400}\n - {color: \"red\", level: 800}\n link: *grafana-home\n inbox_transactions:\n tags: ['db']\n dataRef: \"test-data-large-cos\"\n inbox_workers:\n tags: ['worker']\n dataRef: \"test-data-small-sin\"\n workers_reads:\n dataRef: \"test-data-small-sin\"\n start_rate:\n dataRef: \"test-data-small-sin\"\n label:\n separator: \"colon\"\n units: \"pps\"\n labelColor:\n thresholds:\n - {color: \"green\", level: 0}\n - {color: \"orange\", level: 100}\n link: *grafana-home\n active_workers:\n dataRef: \"test-data-string\"\n label:\n separator: \"cr\"\n units: \"none\"\n labelColor:\n thresholds:\n - {color: \"#888888\", level: 0}\n - {color: \"light-blue\", level: 100}",
+ "panelConfig": "---\n\n#------------------------------------------------------------------------------\n# YAML Aliases to simplify maintenance\n\nanchorLinks:\n - link: &grafana-home\n url: \"https://grafana.com/\"\n params: \"time\"\n\n#------------------------------------------------------------------------------\n# Panel Config\n\ntest:\n testDataExtendedZero: true\n testDataStringData: true\n testDataSparse: true\n\ncellIdPreamble: \"cell-\"\ngradientMode: \"hue\"\ntagConfig:\n condensed: false\ncells: \n drawio:\n link:\n url: \"https://app.diagrams.net/?p=svgdata\"\n docs:\n link:\n url: \"https://github.com/andymchugh/andrewbmchugh-flow-panel/blob/main/src/README.md\"\n inbox_depth:\n tags: ['depth']\n dataRef: \"test-data-large-sin\"\n label:\n dataRef: \"test-data-string\"\n valueMappings:\n - {value: \"*0*\", text: \"*mapped to 0*\"}\n - {value: \"*29*\", text: \"*mapped to 29*\"}\n - {valueMin: 300, valueMax: 600, text: \"will never get here as data not a number\"}\n separator: \"cr\"\n units: \"none\"\n labelColor:\n gradientMode: \"hue\"\n thresholds:\n - {color: \"green\", level: 0}\n - {color: \"orange\", level: 500}\n - {color: \"red\", level: 1000}\n link: *grafana-home\n db_transactions:\n dataRef: \"test-data-large-cos\"\n label:\n separator: \"cr\"\n units: \"ops\"\n fillColor:\n thresholds:\n - {color: \"semi-dark-green\", level: 0}\n - {color: \"orange\", level: 400}\n - {color: \"red\", level: 800}\n link: *grafana-home\n inbox_transactions:\n tags: ['db']\n dataRef: \"test-data-large-cos\"\n inbox_workers:\n tags: ['worker']\n dataRef: \"test-data-small-sin\"\n workers_reads:\n dataRef: \"test-data-small-sin\"\n start_rate:\n dataRef: \"test-data-small-sin\"\n label:\n separator: \"colon\"\n units: \"pps\"\n labelColor:\n thresholds:\n - {color: \"green\", level: 0}\n - {color: \"orange\", level: 100}\n link: *grafana-home\n active_workers:\n dataRef: \"test-data-string\"\n label:\n separator: \"cr\"\n units: \"none\"\n labelColor:\n dataRef: \"test-data-large-cos\"\n thresholds:\n - {color: \"#888888\", level: 0}\n - {color: \"light-blue\", level: 100}",
"siteConfig": "",
"svg": "\n\n\n",
"testDataEnabled": true,
diff --git a/src/components/Config.tsx b/src/components/Config.tsx
index b2c6a05..8d1440f 100644
--- a/src/components/Config.tsx
+++ b/src/components/Config.tsx
@@ -14,12 +14,20 @@ export type VariableThresholdScalars = {
cellIdPatternScope: string[];
};
-export type Threshold = {
+export type ThresholdNumber = {
color: string;
level: number;
order: number;
};
+export type ThresholdPattern = {
+ color: string;
+ pattern: string;
+ regexp: RegExp;
+ order: number;
+};
+
+
export type Link = {
url: string;
params: LinkUrlParams;
@@ -63,7 +71,9 @@ export type PanelConfigCellColor = {
datapoint: DatapointMode | undefined;
gradientMode: ColorGradientMode | undefined;
thresholdsRef: string | undefined;
- thresholds: Threshold[] | undefined;
+ thresholds: ThresholdNumber[] |undefined;
+ thresholdPatternsRef: string | undefined;
+ thresholdPatterns: ThresholdPattern[] | undefined;
};
export type PanelConfigCellColorCompound = {
@@ -140,7 +150,8 @@ export type SiteConfig = {
linkVariables: Map;
links: Map;
colors: Map;
- thresholds: Map;
+ thresholds: Map;
+ thresholdPatterns: Map;
valueMappings: Map;
};
@@ -213,14 +224,15 @@ export function siteConfigFactory(config: any) {
links: new Map(Object.entries(config.links || {})),
colors: new Map(Object.entries(config.colors || {})),
variableThresholdScalars: new Map(Object.entries(config.variableThresholdScalars || {})),
- thresholds: new Map(Object.entries(config.thresholds || {})),
+ thresholds: new Map(Object.entries(config.thresholds || {})),
+ thresholdPatterns: new Map(Object.entries(config.thresholdPatterns || {})),
valueMappings: new Map(Object.entries(config.valueMappings || {})),
} as SiteConfig;
}
function siteConfigDereference(siteConfig: SiteConfig) {
siteConfig.thresholds.forEach((thresholds) => {
- thresholds.forEach(function(threshold: Threshold) {
+ thresholds.forEach(function(threshold: ThresholdNumber | ThresholdPattern) {
threshold.color = siteConfig.colors.get(threshold.color) || threshold.color;
});
});
@@ -230,14 +242,24 @@ function panelConfigDereference(siteConfig: SiteConfig, panelConfig: PanelConfig
function colorDeref(cell: PanelConfigCell, color: PanelConfigCellColor | undefined) {
if (color) {
color.gradientMode = color.gradientMode || panelConfig.gradientMode;
+ if (!color.thresholds && color.thresholdsRef) {
+ color.thresholds = siteConfig.thresholds.get(color.thresholdsRef);
+ }
if (color.thresholds) {
color.thresholds.forEach(function(threshold, index) {
threshold.color = siteConfig.colors.get(threshold.color) || threshold.color;
threshold.order = typeof threshold.order === 'number' ? threshold.order : index;
});
}
- if (!color.thresholds && color.thresholdsRef) {
- color.thresholds = siteConfig.thresholds.get(color.thresholdsRef);
+ if (!color.thresholdPatterns && color.thresholdPatternsRef) {
+ color.thresholdPatterns = siteConfig.thresholdPatterns.get(color.thresholdPatternsRef);
+ }
+ if (color.thresholdPatterns) {
+ color.thresholdPatterns.forEach(function(threshold, index) {
+ threshold.color = siteConfig.colors.get(threshold.color) || threshold.color;
+ threshold.order = typeof threshold.order === 'number' ? threshold.order : index;
+ threshold.regexp = typeof threshold.pattern === 'object' ? threshold.regexp : new RegExp(threshold.pattern);
+ });
}
if (typeof color.datapoint === 'undefined') {
color.datapoint = cell.datapoint || panelConfig.datapoint;
diff --git a/src/components/SvgUpdater.tsx b/src/components/SvgUpdater.tsx
index ae0c21c..cecee41 100644
--- a/src/components/SvgUpdater.tsx
+++ b/src/components/SvgUpdater.tsx
@@ -367,7 +367,7 @@ function getThresholdColor(sdb: SvgDriveBase,
configCellColor: PanelConfigCellColor | undefined) {
const datapoint = configCellColor?.datapoint;
const colorSeed = thresholdSeed(sdb, datapoint, configCellColor, cellValueSeed);
- const thresholdColor = configCellColor && (typeof colorSeed === 'number') ? getColor(configCellColor, colorSeed, sdb.highlight, sdb.highlightFactors) : null;
+ const thresholdColor = configCellColor && (colorSeed !== null) ? getColor(configCellColor, colorSeed, sdb.highlight, sdb.highlightFactors) : null;
return thresholdColor;
}
diff --git a/src/components/Utils.tsx b/src/components/Utils.tsx
index d60aa69..bf425ed 100644
--- a/src/components/Utils.tsx
+++ b/src/components/Utils.tsx
@@ -1,6 +1,6 @@
import { GrafanaTheme2, colorManipulator } from '@grafana/data';
import { SvgAttribs, SvgCell, SvgElementAttribs } from 'components/SvgUpdater'
-import { Background, HighlightFactors, Link, PanelConfigCellColor, Threshold, VariableThresholdScalars } from 'components/Config';
+import { Background, ColorGradientMode, HighlightFactors, Link, PanelConfigCellColor, ThresholdNumber, ThresholdPattern, VariableThresholdScalars } from 'components/Config';
import { HighlightState } from './Highlighter';
@@ -126,7 +126,7 @@ function rgbToString(rgb: number[], highlight: HighlightState, highlightFactors:
}
export function primeColorCache(theme: GrafanaTheme2, svgAttribs: SvgAttribs, background: Background) {
- function initCache(thresholds: Threshold[] | undefined) {
+ function initCache(thresholds: ThresholdNumber[] | ThresholdPattern[] | undefined) {
if (thresholds) {
thresholds.forEach(function(threshold) {
colorStringToRgb(theme, threshold.color);
@@ -135,8 +135,12 @@ export function primeColorCache(theme: GrafanaTheme2, svgAttribs: SvgAttribs, ba
}
svgAttribs.cells.forEach((cellData) => {
- initCache(cellData.cellProps.fillColor && cellData.cellProps.fillColor.thresholds);
- initCache(cellData.cellProps.labelColor && cellData.cellProps.labelColor.thresholds);
+ initCache(cellData.cellProps.strokeColor?.thresholds);
+ initCache(cellData.cellProps.strokeColor?.thresholdPatterns);
+ initCache(cellData.cellProps.fillColor?.thresholds);
+ initCache(cellData.cellProps.fillColor?.thresholdPatterns);
+ initCache(cellData.cellProps.labelColor?.thresholds);
+ initCache(cellData.cellProps.labelColor?.thresholdPatterns);
});
if (background.darkThemeColor) {
@@ -261,37 +265,56 @@ export function variableThresholdScaleValue(variableValues: Map,
return value / scalar;
}
-export function getColor(cellColorData: PanelConfigCellColor, value: number, highlight: HighlightState, highlightFactors: HighlightFactors) {
- if (cellColorData.thresholds && cellColorData.thresholds.length > 0) {
- const thresholds = cellColorData.thresholds;
- let threshold = thresholds[0];
- for (let i = 1; i < thresholds.length; i++) {
- threshold = thresholds[i];
- if (value < threshold.level) {
- const thresholdLwr = thresholds[i - 1];
- if (cellColorData.gradientMode === 'hue') {
- const scalar = (value - thresholdLwr.level) / (threshold.level - thresholdLwr.level);
- const scalarBounded = isFinite(scalar) ? Math.min(1, Math.max(0, scalar)) : 1;
-
- return {
- color: colorGradient(thresholdLwr.color, threshold.color, scalarBounded, highlight, highlightFactors),
- order: thresholdLwr.order + scalarBounded,
- };
- }
- else {
- // The only other mode is 'none'
- return {
- color: colorLookup(thresholdLwr.color, highlight, highlightFactors),
- order: thresholdLwr.order,
- }
- }
+export function getColorFromPattern(thresholds: ThresholdPattern[], value: string, highlight: HighlightState, highlightFactors: HighlightFactors) {
+ for (let i = 0; i < thresholds.length; i++) {
+ const threshold = thresholds[i];
+ if (value.match(threshold.regexp)) {
+ return {
+ color: colorLookup(threshold.color, highlight, highlightFactors),
+ order: threshold.order,
}
}
- return {
- color: colorLookup(threshold.color, highlight, highlightFactors),
- order: threshold.order,
+ }
+ return null;
+}
+
+export function getColorFromNumber(gradientMode: ColorGradientMode | undefined, thresholds: ThresholdNumber[], value: number, highlight: HighlightState, highlightFactors: HighlightFactors) {
+ let threshold = thresholds[0];
+ for (let i = 1; i < thresholds.length; i++) {
+ threshold = thresholds[i];
+ if (value < threshold.level) {
+ const thresholdLwr = thresholds[i - 1];
+ if (gradientMode === 'hue') {
+ const scalar = (value - thresholdLwr.level) / (threshold.level - thresholdLwr.level);
+ const scalarBounded = isFinite(scalar) ? Math.min(1, Math.max(0, scalar)) : 1;
+
+ return {
+ color: colorGradient(thresholdLwr.color, threshold.color, scalarBounded, highlight, highlightFactors),
+ order: thresholdLwr.order + scalarBounded,
+ };
+ }
+ else {
+ // The only other mode is 'none'
+ return {
+ color: colorLookup(thresholdLwr.color, highlight, highlightFactors),
+ order: thresholdLwr.order,
+ }
+ }
}
}
+ return {
+ color: colorLookup(threshold.color, highlight, highlightFactors),
+ order: threshold.order,
+ }
+}
+
+export function getColor(cellColorData: PanelConfigCellColor, value: number | string, highlight: HighlightState, highlightFactors: HighlightFactors) {
+ if (cellColorData.thresholdPatterns && cellColorData.thresholdPatterns.length > 0) {
+ return getColorFromPattern(cellColorData.thresholdPatterns, value.toString(), highlight, highlightFactors);
+ }
+ else if ((typeof value === 'number') && cellColorData.thresholds && (cellColorData.thresholds.length > 0)) {
+ return getColorFromNumber(cellColorData.gradientMode, cellColorData.thresholds, value, highlight, highlightFactors);
+ }
return null;
}
diff --git a/yaml_defs/panelConfig.yaml b/yaml_defs/panelConfig.yaml
index 330db01..47a3f3f 100644
--- a/yaml_defs/panelConfig.yaml
+++ b/yaml_defs/panelConfig.yaml
@@ -267,6 +267,29 @@ cells:
# checked.
thresholdsRef: "depth"
+ # Version 1.14.0 onwards: ThresholdPatterns are the same concept as thresholds but are used with
+ # text data. They have the same fields apart from 'level' being substituted for 'pattern'.
+ # Whereas thresholds start with a base value and then progress through the numerical levels,
+ # thresholdPatterns define a regex that must be explicitely matched for the color to be applied.
+ # As a match has to occur there is no 'gradient' possible. If no match occurs, no color is
+ # applied, so if a default color is wanted it should be in the last 'catch-all' pattern. Pattern
+ # match breaks out on first match so patterns should be defined in most-specific->least specific
+ # order.
+ # If both 'thresholds' and 'thresholdPatterns' are defined, 'thresholdPatterns' take precedence
+ # and the 'thresholds' definitions are ignored.
+ thresholdPatterns:
+ queuecount:
+ - {color: "green", pattern: '.*INFO.*', order: null}
+ - {color: "amber", pattern: '.*WARNING.*', order: null}
+ - {color: "red", pattern: '.*ERROR.*', order: null}
+ - {color: "gray", pattern: '.*', order: null}
+
+ # Version 1.14.0 onwards: This defines an ID to a thresholdPatterns set defined in the siteConfig.
+ # If you want to share a thresholdPatterns set just within the panelConfig you should instead use a
+ # yaml anchor/alias. The above 'thresholdPatterns' field takes precedence. Only if undefined will
+ # thresholdPatternsRef be checked.
+ thresholdPatternsRef: "depth"
+
# Version 1.14.0 onwards: This defines an array of 'labelColor' alongside an
# aggregation function on how the color should be chosen from the array. If 'labelColor'
# is also defined it is prepended to this array and color is just driven from this array.
@@ -298,6 +321,16 @@ cells:
# See labelColor
thresholdsRef: "depth"
+ # Version 1.14.0 onwards: See labelColor
+ thresholdPatterns:
+ - {color: "green", pattern: '.*INFO.*'}
+ - {color: "amber", pattern: '.*WARNING.*'}
+ - {color: "red", pattern: '.*ERROR.*'}
+ - {color: "gray", pattern: '.*'}
+
+ # Version 1.14.0 onwards: See labelColor
+ thresholdPatternsRef: "depth"
+
# Version 1.14.0 onwards: This defines an array of 'strokeColor' alongside an
# aggregation function on how the color should be chosen from the array. If 'strokeColor'
# is also defined it is prepended to this array and color is just driven from this array.
@@ -329,6 +362,16 @@ cells:
# See labelColor
thresholdsRef: "depth"
+ # Version 1.14.0 onwards: See labelColor
+ thresholdPatterns:
+ - {color: "green", pattern: '.*INFO.*'}
+ - {color: "amber", pattern: '.*WARNING.*'}
+ - {color: "red", pattern: '.*ERROR.*'}
+ - {color: "gray", pattern: '.*'}
+
+ # Version 1.14.0 onwards: See labelColor
+ thresholdPatternsRef: "depth"
+
# Version 1.14.0 onwards: This defines an array of 'fillColor' alongside an
# aggregation function on how the color should be chosen from the array. If 'fillColor'
# is also defined it is prepended to this array and color is just driven from this array.
diff --git a/yaml_defs/siteConfig.yaml b/yaml_defs/siteConfig.yaml
index 08a1d98..cce59d2 100644
--- a/yaml_defs/siteConfig.yaml
+++ b/yaml_defs/siteConfig.yaml
@@ -58,7 +58,7 @@ colors:
green: "#00AA00"
# These are refenced from panelConfig via the 'thresholdsRef' field.
-# i.e. in panelConfig you see: thresholdsRef: "queueCount".
+# i.e. in panelConfig you see: thresholdsRef: "queuecount".
# The fields inside are explained in the panelConfig documentation.
thresholds:
queuecount:
@@ -70,6 +70,21 @@ thresholds:
- {color: "amber", level: 300}
- {color: "red", level: 1500}
+# Version 1.14.0 onwards: These are refenced from panelConfig via the 'thresholdPatternsRef'
+# field. i.e. in panelConfig you see: thresholdPatternsRef: "queuecount".
+# The fields inside are explained in the panelConfig documentation.
+thresholdPatterns:
+ queuecount:
+ - {color: "green", pattern: '.*INFO.*'}
+ - {color: "amber", pattern: '.*WARNING.*'}
+ - {color: "red", pattern: '.*ERROR.*'}
+ - {color: "gray", pattern: '.*'}
+ queuedepth:
+ - {color: "green", level: 200}
+ - {color: "amber", level: 300}
+ - {color: "red", level: 1500}
+ - {color: "gray", pattern: '.*'}
+
# Version 1.11.0 onwards: These are refenced from panelConfig via the 'valueMappingsRef' field.
# i.e. in panelConfig you see: valueMappingsRef: "dbTrans".
# The fields inside are explained in the panelConfig documentation.