From eea10e37ff30c7899b127ba92960e12d20daa58b Mon Sep 17 00:00:00 2001 From: Russell Howe Date: Thu, 29 Sep 2022 14:11:41 +0100 Subject: [PATCH 1/2] Fix docs for the table panel The function to create a table is `tablePanel.new()`, not `table.new()`. --- grafonnet/table_panel.libsonnet | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/grafonnet/table_panel.libsonnet b/grafonnet/table_panel.libsonnet index 4c686b3d..f17ef2e8 100644 --- a/grafonnet/table_panel.libsonnet +++ b/grafonnet/table_panel.libsonnet @@ -1,11 +1,11 @@ { /** - * Creates a [table panel](https://grafana.com/docs/grafana/latest/panels/visualizations/table-panel/) that can be added in a row. + * Creates a [table panel](https://grafana.com/docs/grafana/latest/visualizations/table/) that can be added in a row. * It requires the table panel plugin in grafana, which is built-in. * - * @name table.new + * @name tablePanel.new * - * @param title The title of the graph panel. + * @param title The title of the table panel. * @param description (optional) Description of the panel * @param span (optional) Width of the panel * @param height (optional) Height of the panel From 3f642fa2956ada916668d59e1075beb8dc102971 Mon Sep 17 00:00:00 2001 From: Russell Howe Date: Tue, 25 Oct 2022 20:33:04 +0100 Subject: [PATCH 2/2] Update support for table panels Update this for Grafana 9.x, based on the behaviour of 9.2.1 --- examples/k8s_cluster_summary.jsonnet | 107 ++-- examples/k8s_cluster_summary_compiled.json | 644 +++++++++++++++------ grafonnet/table_panel.libsonnet | 217 +++++-- tests/table_panel/test.jsonnet | 45 +- tests/table_panel/test_compiled.json | 298 +++++++--- 5 files changed, 925 insertions(+), 386 deletions(-) diff --git a/examples/k8s_cluster_summary.jsonnet b/examples/k8s_cluster_summary.jsonnet index 043122f8..9c3333df 100644 --- a/examples/k8s_cluster_summary.jsonnet +++ b/examples/k8s_cluster_summary.jsonnet @@ -75,37 +75,31 @@ grafana.dashboard.new( grafana.tablePanel.new( 'Node Info', datasource='$datasource', - span=12, - styles=[ - - { alias: 'Instance', pattern: 'instance' }, - { alias: 'Instance Type', pattern: 'beta_kubernetes_io_instance_type' }, - { alias: 'Node Pool', pattern: 'cloud_google_com_gke_nodepool' }, - { alias: 'Region', pattern: 'failure_domain_beta_kubernetes_io_region' }, - { alias: 'Zone', pattern: 'failure_domain_beta_kubernetes_io_zone' }, - { - alias: 'Status', - pattern: 'Value', - colorMode: 'cell', - colors: ['rgba(245, 54, 54, 0.9)', 'rgba(237, 129, 40, 0.89)', 'rgba(50, 172, 45, 0.97)'], - thresholds: ['0', '1'], - type: 'string', - unit: 'short', - valueMaps: [{ text: 'OK', value: '1' }, { text: 'Down', value: '0' }], - }, - - // Hide these columns - { pattern: 'Time', type: 'hidden' }, - { pattern: '__name__', type: 'hidden' }, - { pattern: 'beta_kubernetes_io_arch', type: 'hidden' }, - { pattern: 'beta_kubernetes_io_fluentd_ds_ready', type: 'hidden' }, - { pattern: 'beta_kubernetes_io_os', type: 'hidden' }, - { pattern: 'cloud_google_com_gke_os_distribution', type: 'hidden' }, - { pattern: 'job', type: 'hidden' }, - { pattern: 'kubernetes_io_hostname', type: 'hidden' }, - { pattern: 'service', type: 'hidden' }, - ], ) + .addOverridesForField('Value', [ + grafana.tablePanel.overrides.unit('short'), + grafana.tablePanel.overrides.displayName('Status'), + grafana.tablePanel.overrides.cellDisplayMode('color-background'), + grafana.tablePanel.overrides.thresholds([ + { color: 'rgba(245, 54, 54, 0.9)', value: null }, + { color: 'rgba(237, 129, 40, 0.89)', value: 0 }, + { color: 'rgba(50, 172, 45, 0.97)', value: 1 }, + ]), + ]) + .addOverridesForField('instance', [grafana.tablePanel.overrides.displayName('Instance')]) + .addOverridesForField('beta_kubernetes_io_instance_type', [grafana.tablePanel.overrides.displayName('Instance Type')]) + .addOverridesForField('cloud_google_com_gke_nodepool', [grafana.tablePanel.overrides.displayName('Node Pool')]) + .addOverridesForField('failure_domain_beta_kubernetes_io_region', [grafana.tablePanel.overrides.displayName('Region')]) + .addOverridesForField('failure_domain_beta_kubernetes_io_zone', [grafana.tablePanel.overrides.displayName('Zone')]) + .addOverridesForField('Time', [grafana.tablePanel.overrides.hide(true)]) + .addOverridesForField('__name__', [grafana.tablePanel.overrides.hide(true)]) + .addOverridesForField('beta_kubernetes_io_arch', [grafana.tablePanel.overrides.hide(true)]) + .addOverridesForField('beta_kubernetes_io_fluentd_ds_ready', [grafana.tablePanel.overrides.hide(true)]) + .addOverridesForField('beta_kubernetes_io_os', [grafana.tablePanel.overrides.hide(true)]) + .addOverridesForField('cloud_google_com_gke_os_distribution', [grafana.tablePanel.overrides.hide(true)]) + .addOverridesForField('job', [grafana.tablePanel.overrides.hide(true)]) + .addOverridesForField('kubernetes_io_hostname', [grafana.tablePanel.overrides.hide(true)]) + .addOverridesForField('service', [grafana.tablePanel.overrides.hide(true)]) .addTarget( grafana.prometheus.target( 'up{job="kubernetes-nodes"}', @@ -338,11 +332,8 @@ grafana.dashboard.new( grafana.tablePanel.new( 'Deployment Replicas - Up To Date', datasource='$datasource', - span=3, - styles=[ - { pattern: 'Time', type: 'hidden' }, - ], ) + .addOverridesForField('Time', [grafana.tablePanel.overrides.hide(true)]) .addTarget( grafana.prometheus.target( 'kube_deployment_status_replicas', @@ -529,34 +520,28 @@ grafana.dashboard.new( grafana.tablePanel.new( 'Container Failed to Start', datasource='$datasource', - span=12, - styles=[ - - { - alias: 'Status', - pattern: 'Value', - colorMode: 'cell', - colors: ['rgba(50, 172, 45, 0.97)', 'rgba(237, 129, 40, 0.89)', 'rgba(245, 54, 54, 0.9)'], - thresholds: ['0', '1'], - type: 'string', - unit: 'short', - valueMaps: [{ text: 'Error', value: '1' }], - }, - - // Hide these columns - { pattern: 'Time', type: 'hidden' }, - { pattern: '__name__', type: 'hidden' }, - { pattern: 'app', type: 'hidden' }, - { pattern: 'chart', type: 'hidden' }, - { pattern: 'component', type: 'hidden' }, - { pattern: 'heritage', type: 'hidden' }, - { pattern: 'instance', type: 'hidden' }, - { pattern: 'job', type: 'hidden' }, - { pattern: 'kubernetes_name', type: 'hidden' }, - { pattern: 'kubernetes_namespace', type: 'hidden' }, - { pattern: 'release', type: 'hidden' }, - ], ) + .addOverridesForField('Value', [ + grafana.tablePanel.overrides.unit('short'), + grafana.tablePanel.overrides.displayName('Status'), + grafana.tablePanel.overrides.cellDisplayMode('color-background'), + grafana.tablePanel.overrides.thresholds([ + { color: 'rgba(50, 172, 45, 0.97)', value: null }, + { color: 'rgba(237, 129, 40, 0.89)', value: 0 }, + { color: 'rgba(245, 54, 54, 0.9)', value: 1 }, + ]), + ]) + .addOverridesForField('Time', [grafana.tablePanel.overrides.hide(true)]) + .addOverridesForField('__name__', [grafana.tablePanel.overrides.hide(true)]) + .addOverridesForField('app', [grafana.tablePanel.overrides.hide(true)]) + .addOverridesForField('chart', [grafana.tablePanel.overrides.hide(true)]) + .addOverridesForField('component', [grafana.tablePanel.overrides.hide(true)]) + .addOverridesForField('heritage', [grafana.tablePanel.overrides.hide(true)]) + .addOverridesForField('instance', [grafana.tablePanel.overrides.hide(true)]) + .addOverridesForField('job', [grafana.tablePanel.overrides.hide(true)]) + .addOverridesForField('kubernetes_name', [grafana.tablePanel.overrides.hide(true)]) + .addOverridesForField('kubernetes_namespace', [grafana.tablePanel.overrides.hide(true)]) + .addOverridesForField('release', [grafana.tablePanel.overrides.hide(true)]) .addTarget( grafana.prometheus.target( 'kube_pod_container_status_waiting_reason{reason!="ContainerCreating"} > 0', diff --git a/examples/k8s_cluster_summary_compiled.json b/examples/k8s_cluster_summary_compiled.json index a26f7b08..9bbd72e8 100644 --- a/examples/k8s_cluster_summary_compiled.json +++ b/examples/k8s_cluster_summary_compiled.json @@ -249,96 +249,248 @@ "valueName": "avg" }, { - "columns": [ ], "datasource": "$datasource", + "fieldConfig": { + "defaults": { + "color": { + "mode": "threshold" + }, + "custom": { + "align": "auto", + "displayMode": "auto", + "inspect": false + }, + "mappings": [ ], + "thresholds": { + "mode": "absolute", + "steps": [ ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "Value" + }, + "properties": [ + { + "id": "unit", + "value": "short" + }, + { + "id": "displayName", + "value": "Status" + }, + { + "id": "custom.displayMode", + "value": "color-background" + }, + { + "id": "thresholds", + "value": { + "mode": "absolute", + "steps": [ + { + "color": "rgba(245, 54, 54, 0.9)", + "value": null + }, + { + "color": "rgba(237, 129, 40, 0.89)", + "value": 0 + }, + { + "color": "rgba(50, 172, 45, 0.97)", + "value": 1 + } + ] + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "instance" + }, + "properties": [ + { + "id": "displayName", + "value": "Instance" + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "beta_kubernetes_io_instance_type" + }, + "properties": [ + { + "id": "displayName", + "value": "Instance Type" + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "cloud_google_com_gke_nodepool" + }, + "properties": [ + { + "id": "displayName", + "value": "Node Pool" + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "failure_domain_beta_kubernetes_io_region" + }, + "properties": [ + { + "id": "displayName", + "value": "Region" + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "failure_domain_beta_kubernetes_io_zone" + }, + "properties": [ + { + "id": "displayName", + "value": "Zone" + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Time" + }, + "properties": [ + { + "id": "custom.hidden", + "value": true + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "__name__" + }, + "properties": [ + { + "id": "custom.hidden", + "value": true + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "beta_kubernetes_io_arch" + }, + "properties": [ + { + "id": "custom.hidden", + "value": true + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "beta_kubernetes_io_fluentd_ds_ready" + }, + "properties": [ + { + "id": "custom.hidden", + "value": true + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "beta_kubernetes_io_os" + }, + "properties": [ + { + "id": "custom.hidden", + "value": true + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "cloud_google_com_gke_os_distribution" + }, + "properties": [ + { + "id": "custom.hidden", + "value": true + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "job" + }, + "properties": [ + { + "id": "custom.hidden", + "value": true + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "kubernetes_io_hostname" + }, + "properties": [ + { + "id": "custom.hidden", + "value": true + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "service" + }, + "properties": [ + { + "id": "custom.hidden", + "value": true + } + ] + } + ] + }, "gridPos": { }, "id": 5, "links": [ ], - "span": 12, - "styles": [ - { - "alias": "Instance", - "pattern": "instance" - }, - { - "alias": "Instance Type", - "pattern": "beta_kubernetes_io_instance_type" - }, - { - "alias": "Node Pool", - "pattern": "cloud_google_com_gke_nodepool" - }, - { - "alias": "Region", - "pattern": "failure_domain_beta_kubernetes_io_region" - }, - { - "alias": "Zone", - "pattern": "failure_domain_beta_kubernetes_io_zone" - }, - { - "alias": "Status", - "colorMode": "cell", - "colors": [ - "rgba(245, 54, 54, 0.9)", - "rgba(237, 129, 40, 0.89)", - "rgba(50, 172, 45, 0.97)" - ], - "pattern": "Value", - "thresholds": [ - "0", - "1" + "options": { + "footer": { + "fields": "", + "reducer": [ + "sum" ], - "type": "string", - "unit": "short", - "valueMaps": [ - { - "text": "OK", - "value": "1" - }, - { - "text": "Down", - "value": "0" - } - ] - }, - { - "pattern": "Time", - "type": "hidden" - }, - { - "pattern": "__name__", - "type": "hidden" - }, - { - "pattern": "beta_kubernetes_io_arch", - "type": "hidden" - }, - { - "pattern": "beta_kubernetes_io_fluentd_ds_ready", - "type": "hidden" - }, - { - "pattern": "beta_kubernetes_io_os", - "type": "hidden" + "show": false }, - { - "pattern": "cloud_google_com_gke_os_distribution", - "type": "hidden" - }, - { - "pattern": "job", - "type": "hidden" - }, - { - "pattern": "kubernetes_io_hostname", - "type": "hidden" - }, - { - "pattern": "service", - "type": "hidden" - } - ], + "showHeader": true + }, + "pluginVersion": "9.2.1", "targets": [ { "expr": "up{job=\"kubernetes-nodes\"}", @@ -349,8 +501,6 @@ "refId": "A" } ], - "timeFrom": null, - "timeShift": null, "title": "Node Info", "type": "table" } @@ -1297,18 +1447,52 @@ "valueName": "avg" }, { - "columns": [ ], "datasource": "$datasource", + "fieldConfig": { + "defaults": { + "color": { + "mode": "threshold" + }, + "custom": { + "align": "auto", + "displayMode": "auto", + "inspect": false + }, + "mappings": [ ], + "thresholds": { + "mode": "absolute", + "steps": [ ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "Time" + }, + "properties": [ + { + "id": "custom.hidden", + "value": true + } + ] + } + ] + }, "gridPos": { }, "id": 17, "links": [ ], - "span": 3, - "styles": [ - { - "pattern": "Time", - "type": "hidden" - } - ], + "options": { + "footer": { + "fields": "", + "reducer": [ + "sum" + ], + "show": false + }, + "showHeader": true + }, + "pluginVersion": "9.2.1", "targets": [ { "expr": "kube_deployment_status_replicas", @@ -1319,8 +1503,6 @@ "refId": "A" } ], - "timeFrom": null, - "timeShift": null, "title": "Deployment Replicas - Up To Date", "type": "table" } @@ -2209,80 +2391,212 @@ "valueName": "avg" }, { - "columns": [ ], "datasource": "$datasource", + "fieldConfig": { + "defaults": { + "color": { + "mode": "threshold" + }, + "custom": { + "align": "auto", + "displayMode": "auto", + "inspect": false + }, + "mappings": [ ], + "thresholds": { + "mode": "absolute", + "steps": [ ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "Value" + }, + "properties": [ + { + "id": "unit", + "value": "short" + }, + { + "id": "displayName", + "value": "Status" + }, + { + "id": "custom.displayMode", + "value": "color-background" + }, + { + "id": "thresholds", + "value": { + "mode": "absolute", + "steps": [ + { + "color": "rgba(50, 172, 45, 0.97)", + "value": null + }, + { + "color": "rgba(237, 129, 40, 0.89)", + "value": 0 + }, + { + "color": "rgba(245, 54, 54, 0.9)", + "value": 1 + } + ] + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Time" + }, + "properties": [ + { + "id": "custom.hidden", + "value": true + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "__name__" + }, + "properties": [ + { + "id": "custom.hidden", + "value": true + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "app" + }, + "properties": [ + { + "id": "custom.hidden", + "value": true + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "chart" + }, + "properties": [ + { + "id": "custom.hidden", + "value": true + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "component" + }, + "properties": [ + { + "id": "custom.hidden", + "value": true + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "heritage" + }, + "properties": [ + { + "id": "custom.hidden", + "value": true + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "instance" + }, + "properties": [ + { + "id": "custom.hidden", + "value": true + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "job" + }, + "properties": [ + { + "id": "custom.hidden", + "value": true + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "kubernetes_name" + }, + "properties": [ + { + "id": "custom.hidden", + "value": true + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "kubernetes_namespace" + }, + "properties": [ + { + "id": "custom.hidden", + "value": true + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "release" + }, + "properties": [ + { + "id": "custom.hidden", + "value": true + } + ] + } + ] + }, "gridPos": { }, "id": 29, "links": [ ], - "span": 12, - "styles": [ - { - "alias": "Status", - "colorMode": "cell", - "colors": [ - "rgba(50, 172, 45, 0.97)", - "rgba(237, 129, 40, 0.89)", - "rgba(245, 54, 54, 0.9)" - ], - "pattern": "Value", - "thresholds": [ - "0", - "1" + "options": { + "footer": { + "fields": "", + "reducer": [ + "sum" ], - "type": "string", - "unit": "short", - "valueMaps": [ - { - "text": "Error", - "value": "1" - } - ] + "show": false }, - { - "pattern": "Time", - "type": "hidden" - }, - { - "pattern": "__name__", - "type": "hidden" - }, - { - "pattern": "app", - "type": "hidden" - }, - { - "pattern": "chart", - "type": "hidden" - }, - { - "pattern": "component", - "type": "hidden" - }, - { - "pattern": "heritage", - "type": "hidden" - }, - { - "pattern": "instance", - "type": "hidden" - }, - { - "pattern": "job", - "type": "hidden" - }, - { - "pattern": "kubernetes_name", - "type": "hidden" - }, - { - "pattern": "kubernetes_namespace", - "type": "hidden" - }, - { - "pattern": "release", - "type": "hidden" - } - ], + "showHeader": true + }, + "pluginVersion": "9.2.1", "targets": [ { "expr": "kube_pod_container_status_waiting_reason{reason!=\"ContainerCreating\"} > 0", @@ -2293,8 +2607,6 @@ "refId": "A" } ], - "timeFrom": null, - "timeShift": null, "title": "Container Failed to Start", "type": "table" } diff --git a/grafonnet/table_panel.libsonnet b/grafonnet/table_panel.libsonnet index f17ef2e8..e5caee4a 100644 --- a/grafonnet/table_panel.libsonnet +++ b/grafonnet/table_panel.libsonnet @@ -7,79 +7,165 @@ * * @param title The title of the table panel. * @param description (optional) Description of the panel - * @param span (optional) Width of the panel - * @param height (optional) Height of the panel * @param datasource (optional) Datasource - * @param min_span (optional) Min span - * @param styles (optional) Array of styles for the panel - * @param columns (optional) Array of columns for the panel - * @param sort (optional) Sorting instruction for the panel - * @param transform (optional) Allow table manipulation to present data as desired - * @param transparent (default: 'false') Whether to display the panel without a background + * @param unit (optional) The unit to use for values + * @param decimals (optional) The number of decimal places to display + * @param display_name (optional) Override the series name + * @param header (default: `true`) Whether to show the table header + * @param footer (default: `false`) Whether to show the table footer + * @param footer_calculation (default: `'sum'`) The reducer function / calculation to display in the footer + * @param footer_field (optional) The field to display in the footer + * @param pagination (default: `false`) Whether to offer pagination of results + * @param min_column_width (optional) The minimum width for column auto resizing + * @param column_width (optional) The column width + * @param column_align (default: `'auto'`) The column alignment (`'auto'`, `'left'`, `'center'`, or `'right'`) + * @param column_filter (default: `false`) Enable/disable column filters + * @param cell_display_mode (default: `'auto'`) How to display cell values (`'auto'`, `'color-text'`, `'color-background'`, `'color-background-solid'`, `'gradient-gauge'`, `'lcd-gauge'`, `'basic'`. `'json-view'`) + * @param cell_value_inspect (default `'false'`) Enable cell value inspection in a modal window + * @param no_value (optional) What to show when there is no value. + * @param transparent (default: `false`) Whether to display the panel without a background * @param links (optional) Array of links for the panel. + * @param repeat (optional) Name of variable that should be used to repeat this panel. + * @param repeatDirection (default `'h'`) 'h' for horizontal or 'v' for vertical. + * @param repeatMaxPerRow (optional) How many panels to limit each row to when repeating horizontally, + * @param thresholdMode (default `'absolute'`) Whether thresholds are absolute or a percentage. `'absolute'` or `'percentage'` * @return A json that represents a table panel * + * @method addThreshold(color, value=null) Adds a threshold. * @method addTarget(target) Adds a target object * @method addTargets(targets) Adds an array of targets - * @method addColumn(field, style) Adds a column - * @method hideColumn(field) Hides a column + * @method addValueMapping(value, color, displayText=null) Adds a value mapping. + * @method addRangeMapping(from, to, color, displayText=null) Adds a range mapping. + * @method addRegexMapping(pattern, color, displayText=null) Adds a regular expression mapping. + * @method addSpecialMapping(match, color, displayText=null) Adds a special mapping. * @method addLink(link) Adds a link - * @method addTransformation(transformation) Adds a transformation object - * @method addTransformations(transformations) Adds an array of transformations + * @method addOverridesForField(field, overrides) Add a list of overrides for a named field. + * @method addOverridesForFieldsMatchingRegex(regex, overrides) Add a list of overrides for field names matching a given regex. + * @method addOverridesForFieldsOfType(type, overrides) Add a list of overrides for fields of a given type. + * @method addOverridesForQuery(queryId, overrides) Add a list of overrides for fields from a given query. */ new( title, description=null, - span=null, - min_span=null, - height=null, datasource=null, - styles=[], - transform=null, + unit=null, + decimals=null, + display_name=null, + header=true, + footer=false, + footer_calculation='sum', + footer_field=null, + pagination=false, + min_column_width=null, + column_width=null, + column_align='auto', + column_filter=false, + cell_display_mode='auto', + cell_value_inspect=false, + no_value=null, transparent=false, - columns=[], - sort=null, - time_from=null, - time_shift=null, links=[], + repeat=null, + repeatDirection='h', + repeatMaxPerRow=null, + thresholdMode='absolute', ):: { type: 'table', title: title, - [if span != null then 'span']: span, - [if min_span != null then 'minSpan']: min_span, - [if height != null then 'height']: height, + [if description != null then 'description']: description, + [if transparent then 'transparent']: transparent, + fieldConfig: { + defaults: { + custom: { + align: column_align, + displayMode: cell_display_mode, + inspect: cell_value_inspect, + [if min_column_width != null then 'minWidth']: min_column_width, + [if column_width != null then 'width']: column_width, + [if column_filter then 'filterable']: column_filter, + }, + mappings: [], + thresholds: { + mode: thresholdMode, + steps: [], + }, + color: { + mode: 'threshold', + }, + [if unit != null then 'unit']: unit, + [if decimals != null then 'decimals']: decimals, + [if display_name != null then 'displayName']: display_name, + [if no_value != null then 'noValue']: no_value, + }, + overrides: [], + }, datasource: datasource, - targets: [ - ], - styles: styles, - columns: columns, - timeFrom: time_from, - timeShift: time_shift, + options: { + showHeader: header, + footer: { + show: footer, + reducer: [footer_calculation], + fields: if footer_field != null then [footer_field] else '', + [if pagination then 'enablePagination']: true, + }, + }, links: links, - [if sort != null then 'sort']: sort, - [if description != null then 'description']: description, - [if transform != null then 'transform']: transform, - [if transparent == true then 'transparent']: transparent, + [if repeat != null then 'repeat']: repeat, + [if repeat != null then 'repeatDirection']: repeatDirection, + [if repeat != null && repeatDirection == 'h' && repeatMaxPerRow != null then 'maxPerRow']: repeatMaxPerRow, + pluginVersion: '9.2.1', _nextTarget:: 0, + addThreshold(color, value=null):: self { + fieldConfig+: { defaults+: { thresholds+: { steps+: [{ color: color, value: value }] } } }, + }, addTarget(target):: self { local nextTarget = super._nextTarget, _nextTarget: nextTarget + 1, targets+: [target { refId: std.char(std.codepoint('A') + nextTarget) }], }, addTargets(targets):: std.foldl(function(p, t) p.addTarget(t), targets, self), - addColumn(field, style):: self { - local style_ = style { pattern: field }, - local column_ = { text: field, value: field }, - styles+: [style_], - columns+: [column_], - }, - hideColumn(field):: self { - styles+: [{ - alias: field, - pattern: field, - type: 'hidden', - }], + _nextMapping:: 0, + local addMapping = function(type, options) self { + local nextMapping = super._nextMapping, + _nextMapping: nextMapping + 1, + fieldConfig+: { defaults+: { mappings+: [{ type: type, options: options(nextMapping) }] } }, }, + addValueMapping(value, color, displayText=null):: + addMapping(type='value', options=function(index) { + [value]: { + color: color, + index: index, + [if displayText != null then 'text']: displayText, + }, + }), + addRangeMapping(from, to, color, displayText=null):: + addMapping(type='range', options=function(index) { + from: from, + to: to, + result: { + color: color, + index: index, + [if displayText != null then 'text']: displayText, + }, + }), + addRegexMapping(pattern, color, displayText=null):: + addMapping(type='regex', options=function(index) { + pattern: pattern, + result: { + color: color, + index: index, + [if displayText != null then 'text']: displayText, + }, + }), + addSpecialMapping(match, color, displayText=null):: + addMapping(type='special', options=function(index) { + match: match, + result: { + color: color, + index: index, + [if displayText != null then 'text']: displayText, + }, + }), addLink(link):: self { links+: [link], }, @@ -87,5 +173,44 @@ transformations+: [transformation], }, addTransformations(transformations):: std.foldl(function(p, t) p.addTransformation(t), transformations, self), + local addOverrides = function(matcher, overrides) self { + fieldConfig+: { overrides+: [{ matcher: matcher, properties: overrides }] }, + }, + addOverridesForField(field, overrides):: + addOverrides(matcher={ id: 'byName', options: field }, overrides=overrides), + addOverridesForFieldsMatchingRegex(regex, overrides):: + addOverrides(matcher={ id: 'byRegexp', options: regex }, overrides=overrides), + addOverridesForFieldsOfType(type, overrides):: + addOverrides(matcher={ id: 'byType', options: type }, overrides=overrides), + addOverridesForQuery(queryId, overrides):: + addOverrides(matcher={ id: 'byFrameRefID', options: queryId }, overrides=overrides), + }, + /** + * Helpers for use with the addOverrides* methods of the timeseries panel. + * + * Example usage: + * grafana.tablePanel.new(title='my panel') + * .addOverridesForField(field='somefield', overrides=[overrides.cellValueInspect(true)]) + */ + overrides:: { + minColumnWidth(width):: { id: 'custom.minWidth', value: width }, + columnWidth(width=null):: { id: 'custom.width', [if width != null then 'value']: width }, + columnAlignment(align):: { id: 'custom.align', value: align }, + cellDisplayMode(mode):: { id: 'custom.displayMode', value: mode }, + cellValueInspect(inspect):: { id: 'custom.inspect', value: inspect }, + columnFilter(filter):: { id: 'custom.filterable', value: filter }, + hide(hide):: { id: 'custom.hidden', value: hide }, + unit(unit):: { id: 'unit', value: unit }, + min(min):: { id: 'min', value: min }, + max(max):: { id: 'max', value: max }, + decimals(places):: { id: 'decimals', value: places }, + displayName(name):: { id: 'displayName', value: name }, + fixedColor(color):: { id: 'color', value: { mode: 'fixed', fixedColor: color } }, + colorScheme(name, colorBy='last'):: { id: 'color', value: { mode: name, seriesBy: colorBy } }, + noValue(value):: { id: 'noValue', value: value }, + dataLinks(links):: { id: 'links', value: links }, + valueMappings(mappings):: { id: 'mappings', value: mappings }, + thresholds(thresholds, type='absolute'):: { id: 'thresholds', value: { mode: type, steps: thresholds } }, + showThresholds(style):: { id: 'custom.thresholdsStyle', value: { mode: style } }, }, } diff --git a/tests/table_panel/test.jsonnet b/tests/table_panel/test.jsonnet index 7b945343..0de1f6ef 100644 --- a/tests/table_panel/test.jsonnet +++ b/tests/table_panel/test.jsonnet @@ -4,52 +4,26 @@ local transformation = grafana.transformation; { basic: tablePanel.new( - 'test', - span=12 + 'test' ), advanced: tablePanel.new( 'test', - span=12, datasource='$PROMETHEUS', description='description', - columns=[ - { - text: 'Users', - value: 'Users', - }, - ], - styles=[ - { - alias: 'Users', - colorMode: 'row', - colors: ['rgba(245,54,54,0.9)', 'rgba(237,129,40,0.89)', 'rgba(50,172,45,0.97)'], - pattern: 'Users', - thresholds: ['0', '50'], - type: 'number', - unit: 'none', - }, - ], - transform='table', transparent=true, - sort={ - col: 1, - desc: true, - }, - time_from='24h', - time_shift='1h', links=[{ targetBlank: true, title: 'foolink', url: 'https://example.com' }], ), targets: [ - tablePanel.new('with targets', span=12) + tablePanel.new('with targets') .addTarget({ a: 'foo' }) .addTarget({ b: 'foo' }), - tablePanel.new('with batch targets', span=12) + tablePanel.new('with batch targets') .addTargets([{ a: 'foo' }, { b: 'foo' }]), ], transformations: [ - tablePanel.new('with transformations', span=12) + tablePanel.new('with transformations') .addTransformation(transformation.new('seriesToColumns', options={ byField: 'instance', })) @@ -60,7 +34,7 @@ local transformation = grafana.transformation; ], }, })), - tablePanel.new('with batch transformations', span=12) + tablePanel.new('with batch transformations') .addTransformations([ transformation.new('filterFieldsByName', options={ include: { @@ -86,10 +60,7 @@ local transformation = grafana.transformation; }), ]), ], - hideColumns: tablePanel.new( - 'test', - span=12, - ). - hideColumn('Time'). - hideColumn('Space'), + hideColumns: tablePanel.new('test'). + addOverridesForField('Time', tablePanel.overrides.hide(true)). + addOverridesForField('Space', tablePanel.overrides.hide(true)), } diff --git a/tests/table_panel/test_compiled.json b/tests/table_panel/test_compiled.json index efcaa535..77eb2c04 100644 --- a/tests/table_panel/test_compiled.json +++ b/tests/table_panel/test_compiled.json @@ -1,13 +1,25 @@ { "advanced": { - "columns": [ - { - "text": "Users", - "value": "Users" - } - ], "datasource": "$PROMETHEUS", "description": "description", + "fieldConfig": { + "defaults": { + "color": { + "mode": "threshold" + }, + "custom": { + "align": "auto", + "displayMode": "auto", + "inspect": false + }, + "mappings": [ ], + "thresholds": { + "mode": "absolute", + "steps": [ ] + } + }, + "overrides": [ ] + }, "links": [ { "targetBlank": true, @@ -15,79 +27,145 @@ "url": "https://example.com" } ], - "sort": { - "col": 1, - "desc": true - }, - "span": 12, - "styles": [ - { - "alias": "Users", - "colorMode": "row", - "colors": [ - "rgba(245,54,54,0.9)", - "rgba(237,129,40,0.89)", - "rgba(50,172,45,0.97)" + "options": { + "footer": { + "fields": "", + "reducer": [ + "sum" ], - "pattern": "Users", - "thresholds": [ - "0", - "50" - ], - "type": "number", - "unit": "none" - } - ], - "targets": [ ], - "timeFrom": "24h", - "timeShift": "1h", + "show": false + }, + "showHeader": true + }, + "pluginVersion": "9.2.1", "title": "test", - "transform": "table", "transparent": true, "type": "table" }, "basic": { - "columns": [ ], "datasource": null, + "fieldConfig": { + "defaults": { + "color": { + "mode": "threshold" + }, + "custom": { + "align": "auto", + "displayMode": "auto", + "inspect": false + }, + "mappings": [ ], + "thresholds": { + "mode": "absolute", + "steps": [ ] + } + }, + "overrides": [ ] + }, "links": [ ], - "span": 12, - "styles": [ ], - "targets": [ ], - "timeFrom": null, - "timeShift": null, + "options": { + "footer": { + "fields": "", + "reducer": [ + "sum" + ], + "show": false + }, + "showHeader": true + }, + "pluginVersion": "9.2.1", "title": "test", "type": "table" }, "hideColumns": { - "columns": [ ], "datasource": null, + "fieldConfig": { + "defaults": { + "color": { + "mode": "threshold" + }, + "custom": { + "align": "auto", + "displayMode": "auto", + "inspect": false + }, + "mappings": [ ], + "thresholds": { + "mode": "absolute", + "steps": [ ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "Time" + }, + "properties": { + "id": "custom.hidden", + "value": true + } + }, + { + "matcher": { + "id": "byName", + "options": "Space" + }, + "properties": { + "id": "custom.hidden", + "value": true + } + } + ] + }, "links": [ ], - "span": 12, - "styles": [ - { - "alias": "Time", - "pattern": "Time", - "type": "hidden" + "options": { + "footer": { + "fields": "", + "reducer": [ + "sum" + ], + "show": false }, - { - "alias": "Space", - "pattern": "Space", - "type": "hidden" - } - ], - "targets": [ ], - "timeFrom": null, - "timeShift": null, + "showHeader": true + }, + "pluginVersion": "9.2.1", "title": "test", "type": "table" }, "targets": [ { - "columns": [ ], "datasource": null, + "fieldConfig": { + "defaults": { + "color": { + "mode": "threshold" + }, + "custom": { + "align": "auto", + "displayMode": "auto", + "inspect": false + }, + "mappings": [ ], + "thresholds": { + "mode": "absolute", + "steps": [ ] + } + }, + "overrides": [ ] + }, "links": [ ], - "span": 12, - "styles": [ ], + "options": { + "footer": { + "fields": "", + "reducer": [ + "sum" + ], + "show": false + }, + "showHeader": true + }, + "pluginVersion": "9.2.1", "targets": [ { "a": "foo", @@ -98,17 +176,41 @@ "refId": "B" } ], - "timeFrom": null, - "timeShift": null, "title": "with targets", "type": "table" }, { - "columns": [ ], "datasource": null, + "fieldConfig": { + "defaults": { + "color": { + "mode": "threshold" + }, + "custom": { + "align": "auto", + "displayMode": "auto", + "inspect": false + }, + "mappings": [ ], + "thresholds": { + "mode": "absolute", + "steps": [ ] + } + }, + "overrides": [ ] + }, "links": [ ], - "span": 12, - "styles": [ ], + "options": { + "footer": { + "fields": "", + "reducer": [ + "sum" + ], + "show": false + }, + "showHeader": true + }, + "pluginVersion": "9.2.1", "targets": [ { "a": "foo", @@ -119,22 +221,43 @@ "refId": "B" } ], - "timeFrom": null, - "timeShift": null, "title": "with batch targets", "type": "table" } ], "transformations": [ { - "columns": [ ], "datasource": null, + "fieldConfig": { + "defaults": { + "color": { + "mode": "threshold" + }, + "custom": { + "align": "auto", + "displayMode": "auto", + "inspect": false + }, + "mappings": [ ], + "thresholds": { + "mode": "absolute", + "steps": [ ] + } + }, + "overrides": [ ] + }, "links": [ ], - "span": 12, - "styles": [ ], - "targets": [ ], - "timeFrom": null, - "timeShift": null, + "options": { + "footer": { + "fields": "", + "reducer": [ + "sum" + ], + "show": false + }, + "showHeader": true + }, + "pluginVersion": "9.2.1", "title": "with transformations", "transformations": [ { @@ -157,14 +280,37 @@ "type": "table" }, { - "columns": [ ], "datasource": null, + "fieldConfig": { + "defaults": { + "color": { + "mode": "threshold" + }, + "custom": { + "align": "auto", + "displayMode": "auto", + "inspect": false + }, + "mappings": [ ], + "thresholds": { + "mode": "absolute", + "steps": [ ] + } + }, + "overrides": [ ] + }, "links": [ ], - "span": 12, - "styles": [ ], - "targets": [ ], - "timeFrom": null, - "timeShift": null, + "options": { + "footer": { + "fields": "", + "reducer": [ + "sum" + ], + "show": false + }, + "showHeader": true + }, + "pluginVersion": "9.2.1", "title": "with batch transformations", "transformations": [ {