diff --git a/custom/util/panel.libsonnet b/custom/util/panel.libsonnet index 8d81cdab..89e0bd72 100644 --- a/custom/util/panel.libsonnet +++ b/custom/util/panel.libsonnet @@ -318,4 +318,103 @@ local xtd = import 'github.com/jsonnet-libs/xtd/main.libsonnet'; else p, panels ), + + + '#setRefIDs':: d.func.new( + ||| + `setRefIDs` calculates the `refId` field for each target on a panel. + |||, + args=[ + d.arg('panel', d.T.object), + d.arg('overrideExistingIDs', d.T.bool, default=true), + ] + ), + setRefIDs(panel, overrideExistingIDs=true): + local calculateRefID(n) = + // From: https://github.com/grafana/grafana/blob/bffd87107b786930edd091060143ee013843efac/packages/grafana-data/src/query/refId.ts#L15 + local letters = std.map(std.char, std.range(std.codepoint('A'), std.codepoint('Z'))); + if n < std.length(letters) + then letters[n] + else calculateRefID(std.floor(n / std.length(letters)) - 1) + letters[std.mod(n, std.length(letters))]; + panel + { + targets: + std.mapWithIndex( + function(i, target) + if overrideExistingIDs + || !std.objectHas(target, 'refId') + then target + { + refId: calculateRefID(i), + } + else target, + panel.targets, + ), + }, + + '#setRefIDsOnPanels':: d.func.new( + ||| + `setRefIDsOnPanels` applies `setRefIDs on all `panels`. + |||, + args=[ + d.arg('panels', d.T.array), + ] + ), + setRefIDsOnPanels(panels): + std.map(self.setRefIDs, panels), + + '#dedupeQueryTargets':: d.func.new( + ||| + `dedupeQueryTargets` dedupes the query targets in a set of panels and replaces the duplicates with a ['shared query'](https://grafana.com/docs/grafana/latest/panels-visualizations/query-transform-data/share-query/). Sharing query results across panels reduces the number of queries made to your data source, which can improve the performance of your dashboard. + + This function requires that the query targets have `refId` set, `setRefIDs` and `setRefIDsOnPanels` can help with that. + |||, + args=[ + d.arg('panels', d.T.array), + ] + ), + dedupeQueryTargets(panels): + // Hide ref so it doesn't compare in equality + local targetWithoutRef(target) = + target + { refId:: target.refId }; + + // Find targets that are the same + local findTargets(targets, target) = + std.filter( + function(t) + targetWithoutRef(t) == targetWithoutRef(target), + targets + ); + + // Get a flat array of all targets including their panelId + local targets = std.flattenArrays([ + std.map(function(t) t + { panelId:: panel.id }, panel.targets) + for panel in panels + ]); + + std.map( + function(panel) + // Replace target with 'shared query' target if found in other panels + local replaceTarget(target) = + local found = findTargets(targets, target); + if std.length(found) > 0 + // Do not reference queries from the same panel + && found[0].panelId != panel.id + then { + datasource: { + type: 'datasource', + uid: '-- Dashboard --', + }, + refId: found[0].refId, + panelId: found[0].panelId, + } + else target; + + panel + { + targets: + std.map( + replaceTarget, + panel.targets, + ), + }, + panels + ), } diff --git a/docs/API/util.md b/docs/API/util.md index 286e93c0..af88a40b 100644 --- a/docs/API/util.md +++ b/docs/API/util.md @@ -11,6 +11,7 @@ Helper functions that work well with Grafonnet. * [`fn wrapPanels(panels, panelWidth, panelHeight, startY)`](#fn-gridwrappanels) * [`obj panel`](#obj-panel) * [`fn calculateLowestYforPanel(panel, panels)`](#fn-panelcalculatelowestyforpanel) + * [`fn dedupeQueryTargets(panels)`](#fn-paneldedupequerytargets) * [`fn getPanelIDs(panels)`](#fn-panelgetpanelids) * [`fn getPanelsBeforeNextRow(panels)`](#fn-panelgetpanelsbeforenextrow) * [`fn groupPanelsInRows(panels)`](#fn-panelgrouppanelsinrows) @@ -20,6 +21,8 @@ Helper functions that work well with Grafonnet. * [`fn resolveCollapsedFlagOnRows(panels)`](#fn-panelresolvecollapsedflagonrows) * [`fn sanitizePanel(panel, defaultX=0, defaultY=0, defaultHeight=8, defaultWidth=8)`](#fn-panelsanitizepanel) * [`fn setPanelIDs(panels, overrideExistingIDs=true)`](#fn-panelsetpanelids) + * [`fn setRefIDs(panel, overrideExistingIDs=true)`](#fn-panelsetrefids) + * [`fn setRefIDsOnPanels(panels)`](#fn-panelsetrefidsonpanels) * [`fn sortPanelsByXY(panels)`](#fn-panelsortpanelsbyxy) * [`fn sortPanelsInRow(rowPanel)`](#fn-panelsortpanelsinrow) * [`fn validatePanelIDs(panels)`](#fn-panelvalidatepanelids) @@ -107,6 +110,20 @@ PARAMETERS: `calculateLowestYforPanel` calculates Y for a given `panel` from the `gridPos` of an array of `panels`. This function is used in `normalizeY`. +#### fn panel.dedupeQueryTargets + +```jsonnet +panel.dedupeQueryTargets(panels) +``` + +PARAMETERS: + +* **panels** (`array`) + +`dedupeQueryTargets` dedupes the query targets in a set of panels and replaces the duplicates with a ['shared query'](https://grafana.com/docs/grafana/latest/panels-visualizations/query-transform-data/share-query/). Sharing query results across panels reduces the number of queries made to your data source, which can improve the performance of your dashboard. + +This function requires that the query targets have `refId` set, `setRefIDs` and `setRefIDsOnPanels` can help with that. + #### fn panel.getPanelIDs ```jsonnet @@ -232,6 +249,32 @@ PARAMETERS: `overrideExistingIDs` can be set to not replace existing IDs, consider validating the IDs with `validatePanelIDs()` to ensure there are no duplicate IDs. +#### fn panel.setRefIDs + +```jsonnet +panel.setRefIDs(panel, overrideExistingIDs=true) +``` + +PARAMETERS: + +* **panel** (`object`) +* **overrideExistingIDs** (`bool`) + - default value: `true` + +`setRefIDs` calculates the `refId` field for each target on a panel. + +#### fn panel.setRefIDsOnPanels + +```jsonnet +panel.setRefIDsOnPanels(panels) +``` + +PARAMETERS: + +* **panels** (`array`) + +`setRefIDsOnPanels` applies `setRefIDs on all `panels`. + #### fn panel.sortPanelsByXY ```jsonnet diff --git a/gen/grafonnet-v11.0.0/custom/util/panel.libsonnet b/gen/grafonnet-v11.0.0/custom/util/panel.libsonnet index 8d81cdab..89e0bd72 100644 --- a/gen/grafonnet-v11.0.0/custom/util/panel.libsonnet +++ b/gen/grafonnet-v11.0.0/custom/util/panel.libsonnet @@ -318,4 +318,103 @@ local xtd = import 'github.com/jsonnet-libs/xtd/main.libsonnet'; else p, panels ), + + + '#setRefIDs':: d.func.new( + ||| + `setRefIDs` calculates the `refId` field for each target on a panel. + |||, + args=[ + d.arg('panel', d.T.object), + d.arg('overrideExistingIDs', d.T.bool, default=true), + ] + ), + setRefIDs(panel, overrideExistingIDs=true): + local calculateRefID(n) = + // From: https://github.com/grafana/grafana/blob/bffd87107b786930edd091060143ee013843efac/packages/grafana-data/src/query/refId.ts#L15 + local letters = std.map(std.char, std.range(std.codepoint('A'), std.codepoint('Z'))); + if n < std.length(letters) + then letters[n] + else calculateRefID(std.floor(n / std.length(letters)) - 1) + letters[std.mod(n, std.length(letters))]; + panel + { + targets: + std.mapWithIndex( + function(i, target) + if overrideExistingIDs + || !std.objectHas(target, 'refId') + then target + { + refId: calculateRefID(i), + } + else target, + panel.targets, + ), + }, + + '#setRefIDsOnPanels':: d.func.new( + ||| + `setRefIDsOnPanels` applies `setRefIDs on all `panels`. + |||, + args=[ + d.arg('panels', d.T.array), + ] + ), + setRefIDsOnPanels(panels): + std.map(self.setRefIDs, panels), + + '#dedupeQueryTargets':: d.func.new( + ||| + `dedupeQueryTargets` dedupes the query targets in a set of panels and replaces the duplicates with a ['shared query'](https://grafana.com/docs/grafana/latest/panels-visualizations/query-transform-data/share-query/). Sharing query results across panels reduces the number of queries made to your data source, which can improve the performance of your dashboard. + + This function requires that the query targets have `refId` set, `setRefIDs` and `setRefIDsOnPanels` can help with that. + |||, + args=[ + d.arg('panels', d.T.array), + ] + ), + dedupeQueryTargets(panels): + // Hide ref so it doesn't compare in equality + local targetWithoutRef(target) = + target + { refId:: target.refId }; + + // Find targets that are the same + local findTargets(targets, target) = + std.filter( + function(t) + targetWithoutRef(t) == targetWithoutRef(target), + targets + ); + + // Get a flat array of all targets including their panelId + local targets = std.flattenArrays([ + std.map(function(t) t + { panelId:: panel.id }, panel.targets) + for panel in panels + ]); + + std.map( + function(panel) + // Replace target with 'shared query' target if found in other panels + local replaceTarget(target) = + local found = findTargets(targets, target); + if std.length(found) > 0 + // Do not reference queries from the same panel + && found[0].panelId != panel.id + then { + datasource: { + type: 'datasource', + uid: '-- Dashboard --', + }, + refId: found[0].refId, + panelId: found[0].panelId, + } + else target; + + panel + { + targets: + std.map( + replaceTarget, + panel.targets, + ), + }, + panels + ), } diff --git a/gen/grafonnet-v11.0.0/docs/util.md b/gen/grafonnet-v11.0.0/docs/util.md index 286e93c0..af88a40b 100644 --- a/gen/grafonnet-v11.0.0/docs/util.md +++ b/gen/grafonnet-v11.0.0/docs/util.md @@ -11,6 +11,7 @@ Helper functions that work well with Grafonnet. * [`fn wrapPanels(panels, panelWidth, panelHeight, startY)`](#fn-gridwrappanels) * [`obj panel`](#obj-panel) * [`fn calculateLowestYforPanel(panel, panels)`](#fn-panelcalculatelowestyforpanel) + * [`fn dedupeQueryTargets(panels)`](#fn-paneldedupequerytargets) * [`fn getPanelIDs(panels)`](#fn-panelgetpanelids) * [`fn getPanelsBeforeNextRow(panels)`](#fn-panelgetpanelsbeforenextrow) * [`fn groupPanelsInRows(panels)`](#fn-panelgrouppanelsinrows) @@ -20,6 +21,8 @@ Helper functions that work well with Grafonnet. * [`fn resolveCollapsedFlagOnRows(panels)`](#fn-panelresolvecollapsedflagonrows) * [`fn sanitizePanel(panel, defaultX=0, defaultY=0, defaultHeight=8, defaultWidth=8)`](#fn-panelsanitizepanel) * [`fn setPanelIDs(panels, overrideExistingIDs=true)`](#fn-panelsetpanelids) + * [`fn setRefIDs(panel, overrideExistingIDs=true)`](#fn-panelsetrefids) + * [`fn setRefIDsOnPanels(panels)`](#fn-panelsetrefidsonpanels) * [`fn sortPanelsByXY(panels)`](#fn-panelsortpanelsbyxy) * [`fn sortPanelsInRow(rowPanel)`](#fn-panelsortpanelsinrow) * [`fn validatePanelIDs(panels)`](#fn-panelvalidatepanelids) @@ -107,6 +110,20 @@ PARAMETERS: `calculateLowestYforPanel` calculates Y for a given `panel` from the `gridPos` of an array of `panels`. This function is used in `normalizeY`. +#### fn panel.dedupeQueryTargets + +```jsonnet +panel.dedupeQueryTargets(panels) +``` + +PARAMETERS: + +* **panels** (`array`) + +`dedupeQueryTargets` dedupes the query targets in a set of panels and replaces the duplicates with a ['shared query'](https://grafana.com/docs/grafana/latest/panels-visualizations/query-transform-data/share-query/). Sharing query results across panels reduces the number of queries made to your data source, which can improve the performance of your dashboard. + +This function requires that the query targets have `refId` set, `setRefIDs` and `setRefIDsOnPanels` can help with that. + #### fn panel.getPanelIDs ```jsonnet @@ -232,6 +249,32 @@ PARAMETERS: `overrideExistingIDs` can be set to not replace existing IDs, consider validating the IDs with `validatePanelIDs()` to ensure there are no duplicate IDs. +#### fn panel.setRefIDs + +```jsonnet +panel.setRefIDs(panel, overrideExistingIDs=true) +``` + +PARAMETERS: + +* **panel** (`object`) +* **overrideExistingIDs** (`bool`) + - default value: `true` + +`setRefIDs` calculates the `refId` field for each target on a panel. + +#### fn panel.setRefIDsOnPanels + +```jsonnet +panel.setRefIDsOnPanels(panels) +``` + +PARAMETERS: + +* **panels** (`array`) + +`setRefIDsOnPanels` applies `setRefIDs on all `panels`. + #### fn panel.sortPanelsByXY ```jsonnet