mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
Peakq: support multi-value template variables (#82036)
This commit is contained in:
parent
e77ec26897
commit
3464b6e581
@ -75,24 +75,35 @@ type VariableReplacement struct {
|
|||||||
Position *Position `json:"position,omitempty"`
|
Position *Position `json:"position,omitempty"`
|
||||||
|
|
||||||
// How values should be interpolated
|
// How values should be interpolated
|
||||||
// See: https://grafana.com/docs/grafana/latest/dashboards/variables/variable-syntax/#advanced-variable-format-options
|
Format VariableFormat `json:"format,omitempty"`
|
||||||
// NOTE: the format parameter is not yet supported!
|
|
||||||
Format string `json:"format,omitempty"`
|
|
||||||
|
|
||||||
// Keep track of the values from previous iterations
|
|
||||||
History []ReplacementHistory `json:"history,omitempty"`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type ReplacementHistory struct {
|
// Define how to format values in the template.
|
||||||
// Who/what made the change
|
// See: https://grafana.com/docs/grafana/latest/dashboards/variables/variable-syntax/#advanced-variable-format-options
|
||||||
Source string `json:"source,omitempty"`
|
// +enum
|
||||||
|
type VariableFormat string
|
||||||
|
|
||||||
// Value before replacement
|
// Defines values for ItemType.
|
||||||
Previous string `json:"previous"`
|
const (
|
||||||
|
// Formats variables with multiple values as a comma-separated string.
|
||||||
|
FormatCSV VariableFormat = "csv"
|
||||||
|
|
||||||
// The value(s) that replaced the section
|
// Formats variables with multiple values as a comma-separated string.
|
||||||
Replacement []string `json:"replacement"`
|
FormatJSON VariableFormat = "json"
|
||||||
}
|
|
||||||
|
// Formats single- and multi-valued variables into a comma-separated string
|
||||||
|
FormatDoubleQuote VariableFormat = "doublequote"
|
||||||
|
|
||||||
|
// Formats single- and multi-valued variables into a comma-separated string
|
||||||
|
FormatSingleQuote VariableFormat = "singlequote"
|
||||||
|
|
||||||
|
// Formats variables with multiple values into a pipe-separated string.
|
||||||
|
FormatPipe VariableFormat = "pipe"
|
||||||
|
|
||||||
|
// Formats variables with multiple values into comma-separated string.
|
||||||
|
// This is the default behavior when no format is specified
|
||||||
|
FormatRaw VariableFormat = "raw"
|
||||||
|
)
|
||||||
|
|
||||||
// Position is where to do replacement in the targets
|
// Position is where to do replacement in the targets
|
||||||
// during render.
|
// during render.
|
||||||
|
@ -149,27 +149,6 @@ func (in *RenderedQuery) DeepCopyObject() runtime.Object {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
|
||||||
func (in *ReplacementHistory) DeepCopyInto(out *ReplacementHistory) {
|
|
||||||
*out = *in
|
|
||||||
if in.Replacement != nil {
|
|
||||||
in, out := &in.Replacement, &out.Replacement
|
|
||||||
*out = make([]string, len(*in))
|
|
||||||
copy(*out, *in)
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ReplacementHistory.
|
|
||||||
func (in *ReplacementHistory) DeepCopy() *ReplacementHistory {
|
|
||||||
if in == nil {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
out := new(ReplacementHistory)
|
|
||||||
in.DeepCopyInto(out)
|
|
||||||
return out
|
|
||||||
}
|
|
||||||
|
|
||||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||||
func (in *Target) DeepCopyInto(out *Target) {
|
func (in *Target) DeepCopyInto(out *Target) {
|
||||||
*out = *in
|
*out = *in
|
||||||
@ -234,13 +213,6 @@ func (in *VariableReplacement) DeepCopyInto(out *VariableReplacement) {
|
|||||||
*out = new(Position)
|
*out = new(Position)
|
||||||
**out = **in
|
**out = **in
|
||||||
}
|
}
|
||||||
if in.History != nil {
|
|
||||||
in, out := &in.History, &out.History
|
|
||||||
*out = make([]ReplacementHistory, len(*in))
|
|
||||||
for i := range *in {
|
|
||||||
(*in)[i].DeepCopyInto(&(*out)[i])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -21,7 +21,6 @@ func GetOpenAPIDefinitions(ref common.ReferenceCallback) map[string]common.OpenA
|
|||||||
"github.com/grafana/grafana/pkg/apis/peakq/v0alpha1.QueryTemplateList": schema_pkg_apis_peakq_v0alpha1_QueryTemplateList(ref),
|
"github.com/grafana/grafana/pkg/apis/peakq/v0alpha1.QueryTemplateList": schema_pkg_apis_peakq_v0alpha1_QueryTemplateList(ref),
|
||||||
"github.com/grafana/grafana/pkg/apis/peakq/v0alpha1.QueryTemplateSpec": schema_pkg_apis_peakq_v0alpha1_QueryTemplateSpec(ref),
|
"github.com/grafana/grafana/pkg/apis/peakq/v0alpha1.QueryTemplateSpec": schema_pkg_apis_peakq_v0alpha1_QueryTemplateSpec(ref),
|
||||||
"github.com/grafana/grafana/pkg/apis/peakq/v0alpha1.RenderedQuery": schema_pkg_apis_peakq_v0alpha1_RenderedQuery(ref),
|
"github.com/grafana/grafana/pkg/apis/peakq/v0alpha1.RenderedQuery": schema_pkg_apis_peakq_v0alpha1_RenderedQuery(ref),
|
||||||
"github.com/grafana/grafana/pkg/apis/peakq/v0alpha1.ReplacementHistory": schema_pkg_apis_peakq_v0alpha1_ReplacementHistory(ref),
|
|
||||||
"github.com/grafana/grafana/pkg/apis/peakq/v0alpha1.Target": schema_pkg_apis_peakq_v0alpha1_Target(ref),
|
"github.com/grafana/grafana/pkg/apis/peakq/v0alpha1.Target": schema_pkg_apis_peakq_v0alpha1_Target(ref),
|
||||||
"github.com/grafana/grafana/pkg/apis/peakq/v0alpha1.TemplateVariable": schema_pkg_apis_peakq_v0alpha1_TemplateVariable(ref),
|
"github.com/grafana/grafana/pkg/apis/peakq/v0alpha1.TemplateVariable": schema_pkg_apis_peakq_v0alpha1_TemplateVariable(ref),
|
||||||
"github.com/grafana/grafana/pkg/apis/peakq/v0alpha1.VariableReplacement": schema_pkg_apis_peakq_v0alpha1_VariableReplacement(ref),
|
"github.com/grafana/grafana/pkg/apis/peakq/v0alpha1.VariableReplacement": schema_pkg_apis_peakq_v0alpha1_VariableReplacement(ref),
|
||||||
@ -255,49 +254,6 @@ func schema_pkg_apis_peakq_v0alpha1_RenderedQuery(ref common.ReferenceCallback)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func schema_pkg_apis_peakq_v0alpha1_ReplacementHistory(ref common.ReferenceCallback) common.OpenAPIDefinition {
|
|
||||||
return common.OpenAPIDefinition{
|
|
||||||
Schema: spec.Schema{
|
|
||||||
SchemaProps: spec.SchemaProps{
|
|
||||||
Type: []string{"object"},
|
|
||||||
Properties: map[string]spec.Schema{
|
|
||||||
"source": {
|
|
||||||
SchemaProps: spec.SchemaProps{
|
|
||||||
Description: "Who/what made the change",
|
|
||||||
Type: []string{"string"},
|
|
||||||
Format: "",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
"previous": {
|
|
||||||
SchemaProps: spec.SchemaProps{
|
|
||||||
Description: "Value before replacement",
|
|
||||||
Default: "",
|
|
||||||
Type: []string{"string"},
|
|
||||||
Format: "",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
"replacement": {
|
|
||||||
SchemaProps: spec.SchemaProps{
|
|
||||||
Description: "The value(s) that replaced the section",
|
|
||||||
Type: []string{"array"},
|
|
||||||
Items: &spec.SchemaOrArray{
|
|
||||||
Schema: &spec.Schema{
|
|
||||||
SchemaProps: spec.SchemaProps{
|
|
||||||
Default: "",
|
|
||||||
Type: []string{"string"},
|
|
||||||
Format: "",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
Required: []string{"previous", "replacement"},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func schema_pkg_apis_peakq_v0alpha1_Target(ref common.ReferenceCallback) common.OpenAPIDefinition {
|
func schema_pkg_apis_peakq_v0alpha1_Target(ref common.ReferenceCallback) common.OpenAPIDefinition {
|
||||||
return common.OpenAPIDefinition{
|
return common.OpenAPIDefinition{
|
||||||
Schema: spec.Schema{
|
Schema: spec.Schema{
|
||||||
@ -421,23 +377,10 @@ func schema_pkg_apis_peakq_v0alpha1_VariableReplacement(ref common.ReferenceCall
|
|||||||
},
|
},
|
||||||
"format": {
|
"format": {
|
||||||
SchemaProps: spec.SchemaProps{
|
SchemaProps: spec.SchemaProps{
|
||||||
Description: "How values should be interpolated See: https://grafana.com/docs/grafana/latest/dashboards/variables/variable-syntax/#advanced-variable-format-options NOTE: the format parameter is not yet supported!",
|
Description: "How values should be interpolated See: NOTE: the format parameter is not yet supported!\n\nPossible enum values:\n - `\"csv\"` Formats variables with multiple values as a comma-separated string.\n - `\"doublequote\"` Formats single- and multi-valued variables into a comma-separated string\n - `\"json\"` Formats variables with multiple values as a comma-separated string.\n - `\"pipe\"` Formats variables with multiple values into a pipe-separated string.\n - `\"raw\"` Formats variables with multiple values into comma-separated string. This is the default behavior when no format is specified\n - `\"singlequote\"` Formats single- and multi-valued variables into a comma-separated string",
|
||||||
Type: []string{"string"},
|
Type: []string{"string"},
|
||||||
Format: "",
|
Format: "",
|
||||||
},
|
Enum: []interface{}{"csv", "doublequote", "json", "pipe", "raw", "singlequote"},
|
||||||
},
|
|
||||||
"history": {
|
|
||||||
SchemaProps: spec.SchemaProps{
|
|
||||||
Description: "Keep track of the values from previous iterations",
|
|
||||||
Type: []string{"array"},
|
|
||||||
Items: &spec.SchemaOrArray{
|
|
||||||
Schema: &spec.Schema{
|
|
||||||
SchemaProps: spec.SchemaProps{
|
|
||||||
Default: map[string]interface{}{},
|
|
||||||
Ref: ref("github.com/grafana/grafana/pkg/apis/peakq/v0alpha1.ReplacementHistory"),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -445,6 +388,6 @@ func schema_pkg_apis_peakq_v0alpha1_VariableReplacement(ref common.ReferenceCall
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
Dependencies: []string{
|
Dependencies: []string{
|
||||||
"github.com/grafana/grafana/pkg/apis/peakq/v0alpha1.Position", "github.com/grafana/grafana/pkg/apis/peakq/v0alpha1.ReplacementHistory"},
|
"github.com/grafana/grafana/pkg/apis/peakq/v0alpha1.Position"},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,2 @@
|
|||||||
API rule violation: list_type_missing,github.com/grafana/grafana/pkg/apis/peakq/v0alpha1,ReplacementHistory,Replacement
|
|
||||||
API rule violation: list_type_missing,github.com/grafana/grafana/pkg/apis/peakq/v0alpha1,VariableReplacement,History
|
|
||||||
API rule violation: names_match,github.com/grafana/grafana/pkg/apis/peakq/v0alpha1,QueryTemplateSpec,Variables
|
API rule violation: names_match,github.com/grafana/grafana/pkg/apis/peakq/v0alpha1,QueryTemplateSpec,Variables
|
||||||
API rule violation: names_match,github.com/grafana/grafana/pkg/apis/peakq/v0alpha1,TemplateVariable,DefaultValues
|
API rule violation: names_match,github.com/grafana/grafana/pkg/apis/peakq/v0alpha1,TemplateVariable,DefaultValues
|
||||||
|
70
pkg/registry/apis/peakq/format.go
Normal file
70
pkg/registry/apis/peakq/format.go
Normal file
@ -0,0 +1,70 @@
|
|||||||
|
package peakq
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"encoding/csv"
|
||||||
|
"encoding/json"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
peakq "github.com/grafana/grafana/pkg/apis/peakq/v0alpha1"
|
||||||
|
)
|
||||||
|
|
||||||
|
func formatVariables(fmt peakq.VariableFormat, input []string) string {
|
||||||
|
if len(input) < 1 {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
// MultiValued formats
|
||||||
|
// nolint: exhaustive
|
||||||
|
switch fmt {
|
||||||
|
case peakq.FormatJSON:
|
||||||
|
v, _ := json.Marshal(input)
|
||||||
|
return string(v)
|
||||||
|
|
||||||
|
case peakq.FormatDoubleQuote:
|
||||||
|
sb := bytes.NewBufferString("")
|
||||||
|
for idx, val := range input {
|
||||||
|
if idx > 0 {
|
||||||
|
_, _ = sb.WriteRune(',')
|
||||||
|
}
|
||||||
|
_, _ = sb.WriteRune('"')
|
||||||
|
_, _ = sb.WriteString(strings.ReplaceAll(val, `"`, `\"`))
|
||||||
|
_, _ = sb.WriteRune('"')
|
||||||
|
}
|
||||||
|
return sb.String()
|
||||||
|
|
||||||
|
case peakq.FormatSingleQuote:
|
||||||
|
sb := bytes.NewBufferString("")
|
||||||
|
for idx, val := range input {
|
||||||
|
if idx > 0 {
|
||||||
|
_, _ = sb.WriteRune(',')
|
||||||
|
}
|
||||||
|
_, _ = sb.WriteRune('\'')
|
||||||
|
_, _ = sb.WriteString(strings.ReplaceAll(val, `'`, `\'`))
|
||||||
|
_, _ = sb.WriteRune('\'')
|
||||||
|
}
|
||||||
|
return sb.String()
|
||||||
|
|
||||||
|
case peakq.FormatCSV:
|
||||||
|
sb := bytes.NewBufferString("")
|
||||||
|
w := csv.NewWriter(sb)
|
||||||
|
_ = w.Write(input)
|
||||||
|
w.Flush()
|
||||||
|
v := sb.Bytes()
|
||||||
|
return string(v[:len(v)-1])
|
||||||
|
}
|
||||||
|
|
||||||
|
// Single valued formats
|
||||||
|
if len(input) == 1 {
|
||||||
|
return input[0]
|
||||||
|
}
|
||||||
|
|
||||||
|
// nolint: exhaustive
|
||||||
|
switch fmt {
|
||||||
|
case peakq.FormatPipe:
|
||||||
|
return strings.Join(input, "|")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Raw output (joined with a comma)
|
||||||
|
return strings.Join(input, ",")
|
||||||
|
}
|
83
pkg/registry/apis/peakq/format_test.go
Normal file
83
pkg/registry/apis/peakq/format_test.go
Normal file
@ -0,0 +1,83 @@
|
|||||||
|
package peakq
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
|
||||||
|
peakq "github.com/grafana/grafana/pkg/apis/peakq/v0alpha1"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestFormat(t *testing.T) {
|
||||||
|
// Invalid input
|
||||||
|
require.Equal(t, "", formatVariables(peakq.FormatCSV, nil))
|
||||||
|
require.Equal(t, "", formatVariables(peakq.FormatCSV, []string{}))
|
||||||
|
|
||||||
|
type check struct {
|
||||||
|
name string
|
||||||
|
input []string
|
||||||
|
output map[peakq.VariableFormat]string
|
||||||
|
}
|
||||||
|
|
||||||
|
tests := []check{
|
||||||
|
{
|
||||||
|
name: "three simple variables",
|
||||||
|
input: []string{"a", "b", "c"},
|
||||||
|
output: map[peakq.VariableFormat]string{
|
||||||
|
peakq.FormatCSV: "a,b,c",
|
||||||
|
peakq.FormatJSON: `["a","b","c"]`,
|
||||||
|
peakq.FormatDoubleQuote: `"a","b","c"`,
|
||||||
|
peakq.FormatSingleQuote: `'a','b','c'`,
|
||||||
|
peakq.FormatPipe: `a|b|c`,
|
||||||
|
peakq.FormatRaw: "a,b,c",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "single value",
|
||||||
|
input: []string{"a"},
|
||||||
|
output: map[peakq.VariableFormat]string{
|
||||||
|
peakq.FormatCSV: "a",
|
||||||
|
peakq.FormatJSON: `["a"]`,
|
||||||
|
peakq.FormatDoubleQuote: `"a"`,
|
||||||
|
peakq.FormatSingleQuote: `'a'`,
|
||||||
|
peakq.FormatPipe: "a",
|
||||||
|
peakq.FormatRaw: "a",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "value with quote",
|
||||||
|
input: []string{`hello "world"`},
|
||||||
|
output: map[peakq.VariableFormat]string{
|
||||||
|
peakq.FormatCSV: `"hello ""world"""`, // note the double quotes
|
||||||
|
peakq.FormatJSON: `["hello \"world\""]`,
|
||||||
|
peakq.FormatDoubleQuote: `"hello \"world\""`,
|
||||||
|
peakq.FormatSingleQuote: `'hello "world"'`,
|
||||||
|
peakq.FormatPipe: `hello "world"`,
|
||||||
|
peakq.FormatRaw: `hello "world"`,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for _, test := range tests {
|
||||||
|
// Make sure all keys are set in tests
|
||||||
|
all := map[peakq.VariableFormat]bool{
|
||||||
|
peakq.FormatRaw: true,
|
||||||
|
peakq.FormatCSV: true,
|
||||||
|
peakq.FormatJSON: true,
|
||||||
|
peakq.FormatDoubleQuote: true,
|
||||||
|
peakq.FormatSingleQuote: true,
|
||||||
|
peakq.FormatPipe: true,
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check the default (no format) matches CSV
|
||||||
|
require.Equal(t, test.output[peakq.FormatRaw],
|
||||||
|
formatVariables("", test.input),
|
||||||
|
"test %s default values are not raw", test.name)
|
||||||
|
|
||||||
|
// Check each input value
|
||||||
|
for format, v := range test.output {
|
||||||
|
require.Equal(t, v, formatVariables(format, test.input), "Test: %s (format:%s)", test.name, format)
|
||||||
|
delete(all, format)
|
||||||
|
}
|
||||||
|
require.Empty(t, all, "test %s is missing cases for: %v", test.name, all)
|
||||||
|
}
|
||||||
|
}
|
@ -9,13 +9,13 @@ import (
|
|||||||
"sort"
|
"sort"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
"github.com/spyzhov/ajson"
|
||||||
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
"k8s.io/apimachinery/pkg/runtime"
|
"k8s.io/apimachinery/pkg/runtime"
|
||||||
"k8s.io/apiserver/pkg/registry/rest"
|
"k8s.io/apiserver/pkg/registry/rest"
|
||||||
|
|
||||||
"github.com/grafana/grafana/pkg/apis/common/v0alpha1"
|
common "github.com/grafana/grafana/pkg/apis/common/v0alpha1"
|
||||||
peakq "github.com/grafana/grafana/pkg/apis/peakq/v0alpha1"
|
peakq "github.com/grafana/grafana/pkg/apis/peakq/v0alpha1"
|
||||||
"github.com/spyzhov/ajson"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type renderREST struct {
|
type renderREST struct {
|
||||||
@ -107,6 +107,7 @@ func makeVarMapFromParams(v url.Values) (map[string][]string, error) {
|
|||||||
type replacement struct {
|
type replacement struct {
|
||||||
*peakq.Position
|
*peakq.Position
|
||||||
*peakq.TemplateVariable
|
*peakq.TemplateVariable
|
||||||
|
format peakq.VariableFormat
|
||||||
}
|
}
|
||||||
|
|
||||||
func getReplacementMap(qt peakq.QueryTemplateSpec) map[int]map[string][]replacement {
|
func getReplacementMap(qt peakq.QueryTemplateSpec) map[int]map[string][]replacement {
|
||||||
@ -127,6 +128,7 @@ func getReplacementMap(qt peakq.QueryTemplateSpec) map[int]map[string][]replacem
|
|||||||
replacement{
|
replacement{
|
||||||
Position: vReps[rI].Position,
|
Position: vReps[rI].Position,
|
||||||
TemplateVariable: varMap[k],
|
TemplateVariable: varMap[k],
|
||||||
|
format: rep.Format,
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@ -178,13 +180,10 @@ func Render(qt peakq.QueryTemplateSpec, selectedValues map[string][]string) (*pe
|
|||||||
s = s[1 : len(s)-1]
|
s = s[1 : len(s)-1]
|
||||||
var offSet int64
|
var offSet int64
|
||||||
for _, r := range reps {
|
for _, r := range reps {
|
||||||
|
value := []rune(formatVariables(r.format, selectedValues[r.Key]))
|
||||||
if r.Position == nil {
|
if r.Position == nil {
|
||||||
return nil, fmt.Errorf("nil position not support yet, will be full replacement")
|
return nil, fmt.Errorf("nil position not support yet, will be full replacement")
|
||||||
}
|
}
|
||||||
if len(selectedValues[r.Key]) != 1 {
|
|
||||||
return nil, fmt.Errorf("selected value missing, or more then one provided")
|
|
||||||
}
|
|
||||||
value := []rune(selectedValues[r.Key][0])
|
|
||||||
s = append(s[:r.Start+offSet], append(value, s[r.End+offSet:]...)...)
|
s = append(s[:r.Start+offSet], append(value, s[r.End+offSet:]...)...)
|
||||||
offSet += int64(len(value)) - (r.End - r.Start)
|
offSet += int64(len(value)) - (r.End - r.Start)
|
||||||
}
|
}
|
||||||
@ -199,7 +198,7 @@ func Render(qt peakq.QueryTemplateSpec, selectedValues map[string][]string) (*pe
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
u := v0alpha1.Unstructured{}
|
u := common.Unstructured{}
|
||||||
err = u.UnmarshalJSON(raw)
|
err = u.UnmarshalJSON(raw)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
Loading…
Reference in New Issue
Block a user