diff --git a/examples/datasource-http-backend/go.mod b/examples/datasource-http-backend/go.mod index b9ac73c4c..039ad3f18 100644 --- a/examples/datasource-http-backend/go.mod +++ b/examples/datasource-http-backend/go.mod @@ -10,6 +10,7 @@ require ( github.com/stretchr/testify v1.9.0 go.opentelemetry.io/otel v1.29.0 go.opentelemetry.io/otel/trace v1.29.0 + golang.org/x/mod v0.17.0 ) require ( @@ -23,17 +24,21 @@ require ( github.com/cpuguy83/go-md2man/v2 v2.0.4 // indirect github.com/davecgh/go-spew v1.1.1 // indirect github.com/elazarl/goproxy v0.0.0-20230731152917-f99041a5c027 // indirect + github.com/emicklei/go-restful/v3 v3.8.0 // indirect github.com/fatih/color v1.15.0 // indirect github.com/getkin/kin-openapi v0.124.0 // indirect github.com/go-logr/logr v1.4.2 // indirect github.com/go-logr/stdr v1.2.2 // indirect github.com/go-openapi/jsonpointer v0.20.2 // indirect + github.com/go-openapi/jsonreference v0.20.1 // indirect github.com/go-openapi/swag v0.22.8 // indirect github.com/goccy/go-json v0.10.2 // indirect github.com/gogo/protobuf v1.3.2 // indirect github.com/golang/protobuf v1.5.4 // indirect github.com/google/flatbuffers v23.5.26+incompatible // indirect + github.com/google/gnostic-models v0.6.8 // indirect github.com/google/go-cmp v0.6.0 // indirect + github.com/google/gofuzz v1.1.0 // indirect github.com/google/uuid v1.6.0 // indirect github.com/gorilla/mux v1.8.1 // indirect github.com/grafana/otel-profiling-go v0.5.1 // indirect @@ -47,6 +52,7 @@ require ( github.com/invopop/yaml v0.2.0 // indirect github.com/josharian/intern v1.0.0 // indirect github.com/json-iterator/go v1.1.12 // indirect + github.com/jszwedko/go-datemath v0.1.1-0.20230526204004-640a500621d6 // indirect github.com/klauspost/compress v1.17.9 // indirect github.com/klauspost/cpuid/v2 v2.2.5 // indirect github.com/mailru/easyjson v0.7.7 // indirect @@ -84,7 +90,6 @@ require ( go.opentelemetry.io/otel/sdk v1.29.0 // indirect go.opentelemetry.io/proto/otlp v1.3.1 // indirect golang.org/x/exp v0.0.0-20231006140011-7918f672742d // indirect - golang.org/x/mod v0.17.0 // indirect golang.org/x/net v0.28.0 // indirect golang.org/x/sync v0.8.0 // indirect golang.org/x/sys v0.24.0 // indirect @@ -97,4 +102,5 @@ require ( google.golang.org/protobuf v1.34.2 // indirect gopkg.in/fsnotify/fsnotify.v1 v1.4.7 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect + k8s.io/kube-openapi v0.0.0-20240228011516-70dd3763d340 // indirect ) diff --git a/examples/datasource-http-backend/go.sum b/examples/datasource-http-backend/go.sum index 8e3fc94fd..09f5d340f 100644 --- a/examples/datasource-http-backend/go.sum +++ b/examples/datasource-http-backend/go.sum @@ -3,6 +3,8 @@ github.com/BurntSushi/toml v1.3.2 h1:o7IhLm0Msx3BaB+n3Ag7L8EVlByGnpq14C4YWiu/gL8 github.com/BurntSushi/toml v1.3.2/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ= github.com/apache/arrow/go/v15 v15.0.2 h1:60IliRbiyTWCWjERBCkO1W4Qun9svcYoZrSLcyOsMLE= github.com/apache/arrow/go/v15 v15.0.2/go.mod h1:DGXsR3ajT524njufqf95822i+KTh+yea1jass9YXgjA= +github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a h1:idn718Q4B6AGu/h5Sxe66HYVdqdGu2l9Iebqhi/AEoA= +github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY= github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= github.com/bufbuild/protocompile v0.4.0 h1:LbFKd2XowZvQ/kajzguUp2DC9UEIQhIq77fZZlaQsNA= @@ -19,6 +21,7 @@ github.com/chromedp/sysutil v1.0.0/go.mod h1:kgWmDdq8fTzXYcKIBqIYvRRTnYb9aNS9moA github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= github.com/cpuguy83/go-md2man/v2 v2.0.4 h1:wfIWP927BUkWJb2NmU/kNDYIBTh/ziUX91+lVfRxZq4= github.com/cpuguy83/go-md2man/v2 v2.0.4/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= +github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= @@ -27,6 +30,8 @@ github.com/elazarl/goproxy v0.0.0-20230731152917-f99041a5c027/go.mod h1:Ro8st/El github.com/elazarl/goproxy/ext v0.0.0-20190711103511-473e67f1d7d2/go.mod h1:gNh8nYJoAm43RfaxurUnxr+N1PwuFV3ZMl/efxlIlY8= github.com/elazarl/goproxy/ext v0.0.0-20220115173737-adb46da277ac h1:9yrT5tmn9Zc0ytWPASlaPwQfQMQYnRf0RSDe1XvHw0Q= github.com/elazarl/goproxy/ext v0.0.0-20220115173737-adb46da277ac/go.mod h1:gNh8nYJoAm43RfaxurUnxr+N1PwuFV3ZMl/efxlIlY8= +github.com/emicklei/go-restful/v3 v3.8.0 h1:eCZ8ulSerjdAiaNpF7GxXIE7ZCMo1moN1qX+S609eVw= +github.com/emicklei/go-restful/v3 v3.8.0/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc= github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= github.com/fatih/color v1.15.0 h1:kOqh6YHBtK8aywxGerMG2Eq3H6Qgoqeo13Bk2Mv/nBs= github.com/fatih/color v1.15.0/go.mod h1:0h5ZqXfHYED7Bhv2ZJamyIOUej9KtShiJESRwBDUSsw= @@ -42,8 +47,12 @@ github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY= github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= +github.com/go-openapi/jsonpointer v0.19.6/go.mod h1:osyAmYz/mB/C3I+WsTTSgw1ONzaLJoLCyoi6/zppojs= github.com/go-openapi/jsonpointer v0.20.2 h1:mQc3nmndL8ZBzStEo3JYF8wzmeWffDH4VbXz58sAx6Q= github.com/go-openapi/jsonpointer v0.20.2/go.mod h1:bHen+N0u1KEO3YlmqOjTT9Adn1RfD91Ar825/PuiRVs= +github.com/go-openapi/jsonreference v0.20.1 h1:FBLnyygC4/IZZr893oiomc9XaghoveYTrLC1F86HID8= +github.com/go-openapi/jsonreference v0.20.1/go.mod h1:Bl1zwGIM8/wsvqjsOQLJ/SH+En5Ap4rVB5KVcIDZG2k= +github.com/go-openapi/swag v0.22.3/go.mod h1:UzaqsxGiab7freDnrUUra0MwWfN/q7tE4j+VcZ0yl14= github.com/go-openapi/swag v0.22.8 h1:/9RjDSQ0vbFR+NyjGMkFTsA1IA0fmhKSThmfGZjicbw= github.com/go-openapi/swag v0.22.8/go.mod h1:6QT22icPLEqAM/z/TChgb4WAveCHF92+2gF0CNjHpPI= github.com/go-test/deep v1.0.8 h1:TDsG77qcSprGbC6vTN8OuXp5g+J+b5Pcguhf7Zt61VM= @@ -56,9 +65,13 @@ github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= github.com/google/flatbuffers v23.5.26+incompatible h1:M9dgRyhJemaM4Sw8+66GHBu8ioaQmyPLg1b8VwK5WJg= github.com/google/flatbuffers v23.5.26+incompatible/go.mod h1:1AeVuKshWv4vARoZatz6mlQ0JxURH0Kv5+zNeJKJCa8= +github.com/google/gnostic-models v0.6.8 h1:yo/ABAfM5IMRsS1VnXjTBvUb61tFIHozhlYvRgGre9I= +github.com/google/gnostic-models v0.6.8/go.mod h1:5n7qKqH0f5wFt+aWF8CW6pZLLNOfYuF5OpfBSENuI8U= github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/google/gofuzz v1.1.0 h1:Hsa8mG0dQ46ij8Sl2AYJDUv1oA9/d6Vk+3LG99Oe02g= +github.com/google/gofuzz v1.1.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/gopherjs/gopherjs v0.0.0-20181103185306-d547d1d9531e h1:JKmoR8x90Iww1ks85zJ1lfDGgIiMDuIptTOhJq+zKyg= @@ -91,6 +104,8 @@ github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8Hm github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= +github.com/jszwedko/go-datemath v0.1.1-0.20230526204004-640a500621d6 h1:SwcnSwBR7X/5EHJQlXBockkJVIMRVt5yKaesBPMtyZQ= +github.com/jszwedko/go-datemath v0.1.1-0.20230526204004-640a500621d6/go.mod h1:WrYiIuiXUMIvTDAQw97C+9l0CnBmCcvosPjN3XDqS/o= github.com/jtolds/gls v4.2.1+incompatible h1:fSuqC+Gmlu6l/ZYAoZzx2pyucC8Xza35fpRVWLVmUEE= github.com/jtolds/gls v4.2.1+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= @@ -99,8 +114,11 @@ github.com/klauspost/compress v1.17.9 h1:6KIumPrER1LHsvBVuDa0r5xaG0Es51mhhB9BQB2 github.com/klauspost/compress v1.17.9/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw= github.com/klauspost/cpuid/v2 v2.2.5 h1:0E5MSMDEoAulmXNFquVs//DdoomxaoTY1kUhbc/qbZg= github.com/klauspost/cpuid/v2 v2.2.5/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws= +github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc= @@ -172,6 +190,7 @@ github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UV github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= +github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= @@ -294,3 +313,9 @@ gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C gopkg.in/yaml.v3 v3.0.0/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +k8s.io/kube-openapi v0.0.0-20240228011516-70dd3763d340 h1:BZqlfIlq5YbRMFko6/PM7FjZpUb45WallggurYhKGag= +k8s.io/kube-openapi v0.0.0-20240228011516-70dd3763d340/go.mod h1:yD4MZYeKMBwQKVht279WycxKyM84kkAx2DPrTXaeb98= +k8s.io/utils v0.0.0-20230726121419-3b25d923346b h1:sgn3ZU783SCgtaSJjpcVVlRqd6GSnlTLKgpAAttJvpI= +k8s.io/utils v0.0.0-20230726121419-3b25d923346b/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= +sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd h1:EDPBXCAspyGV4jQlpZSudPeMmr1bNJefnuqLsRAsHZo= +sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd/go.mod h1:B8JuhiUyNFVKdsE8h686QcCxMaH6HrOAZj4vswFpcB0= diff --git a/examples/datasource-http-backend/package-lock.json b/examples/datasource-http-backend/package-lock.json index bb6f15824..2d8004be6 100644 --- a/examples/datasource-http-backend/package-lock.json +++ b/examples/datasource-http-backend/package-lock.json @@ -1,12 +1,12 @@ { "name": "datasource-http-backend", - "version": "1.0.0", + "version": "1.1.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "datasource-http-backend", - "version": "1.0.0", + "version": "1.1.0", "license": "Apache-2.0", "dependencies": { "@emotion/css": "11.10.6", diff --git a/examples/datasource-http-backend/package.json b/examples/datasource-http-backend/package.json index faf9ba753..6672dcae1 100644 --- a/examples/datasource-http-backend/package.json +++ b/examples/datasource-http-backend/package.json @@ -1,6 +1,6 @@ { "name": "datasource-http-backend", - "version": "1.0.0", + "version": "1.1.0", "description": "An example plugin for Grafana", "scripts": { "build": "webpack -c ./.config/webpack/webpack.config.ts --env production", diff --git a/examples/datasource-http-backend/pkg/plugin/datasource.go b/examples/datasource-http-backend/pkg/plugin/datasource.go index 4f276ce57..10dc3c5c2 100644 --- a/examples/datasource-http-backend/pkg/plugin/datasource.go +++ b/examples/datasource-http-backend/pkg/plugin/datasource.go @@ -5,6 +5,7 @@ import ( "encoding/json" "errors" "fmt" + "io" "net/http" "strconv" "time" @@ -14,10 +15,12 @@ import ( "github.com/grafana/grafana-plugin-sdk-go/backend/httpclient" "github.com/grafana/grafana-plugin-sdk-go/backend/instancemgmt" "github.com/grafana/grafana-plugin-sdk-go/backend/log" + "github.com/grafana/grafana-plugin-sdk-go/backend/resource/httpadapter" "github.com/grafana/grafana-plugin-sdk-go/backend/tracing" "github.com/grafana/grafana-plugin-sdk-go/data" "go.opentelemetry.io/otel/attribute" "go.opentelemetry.io/otel/trace" + "golang.org/x/mod/semver" ) // Make sure Datasource implements required interfaces. This is important to do @@ -59,10 +62,17 @@ func NewDatasource(ctx context.Context, settings backend.DataSourceInstanceSetti if err != nil { return nil, fmt.Errorf("httpclient new: %w", err) } - return &Datasource{ + + ds := &Datasource{ settings: settings, httpClient: cl, - }, nil + } + + mux := http.NewServeMux() + mux.HandleFunc("/migrate-query", ds.handleMigrateQuery) + ds.resourceHandler = httpadapter.New(mux) + + return ds, nil } // DatasourceOpts contains the default ManageOpts for the datasource. @@ -81,7 +91,8 @@ var DatasourceOpts = datasource.ManageOpts{ type Datasource struct { settings backend.DataSourceInstanceSettings - httpClient *http.Client + httpClient *http.Client + resourceHandler backend.CallResourceHandler } // Dispose here tells plugin SDK that plugin wants to clean up resources when a new instance @@ -147,6 +158,62 @@ func (d *Datasource) QueryData(ctx context.Context, req *backend.QueryDataReques return response, nil } +func (d *Datasource) CallResource(ctx context.Context, req *backend.CallResourceRequest, sender backend.CallResourceResponseSender) error { + return d.resourceHandler.CallResource(ctx, req, sender) +} + +func (d *Datasource) handleMigrateQuery(rw http.ResponseWriter, req *http.Request) { + if req.Method != http.MethodPost { + rw.WriteHeader(http.StatusNotFound) + return + } + + pCtx := backend.PluginConfigFromContext(req.Context()) + defer req.Body.Close() + queryJSON, err := io.ReadAll(req.Body) + if err != nil { + http.Error(rw, fmt.Sprintf("read body: %s", err), http.StatusBadRequest) + return + } + query := &backend.DataQuery{} + err = json.Unmarshal(queryJSON, query) + if err != nil { + http.Error(rw, fmt.Sprintf("unmarshal: %s", err), http.StatusBadRequest) + return + } + query.JSON = queryJSON + input, err := d.migrateQuery(pCtx, *query) + if err != nil { + http.Error(rw, fmt.Sprintf("migrate query: %s", err), http.StatusBadRequest) + return + } + err = json.NewEncoder(rw).Encode(input) + if err != nil { + http.Error(rw, fmt.Sprintf("encode response: %s", err), http.StatusInternalServerError) + return + } + rw.WriteHeader(http.StatusOK) +} + +func (d *Datasource) migrateQuery(pCtx backend.PluginContext, query backend.DataQuery) (*apiQuery, error) { + input := &apiQuery{} + err := json.Unmarshal(query.JSON, input) + if err != nil { + return nil, fmt.Errorf("unmarshal: %w", err) + } + if input.PluginVersion == "" || semver.Compare(input.PluginVersion, "1.1.0") < 0 { + // The query needs migration + deprecatedInput := &apiQueryV1{} + err = json.Unmarshal(query.JSON, deprecatedInput) + if err != nil { + return nil, fmt.Errorf("unmarshal: %w", err) + } + input.Multiply = deprecatedInput.Multiplier + input.PluginVersion = pCtx.PluginVersion + } + return input, nil +} + func (d *Datasource) query(ctx context.Context, pCtx backend.PluginContext, query backend.DataQuery) (backend.DataResponse, error) { // Create spans for this function. // tracing.DefaultTracer() returns the tracer initialized when calling Manage(). @@ -173,13 +240,12 @@ func (d *Datasource) query(ctx context.Context, pCtx backend.PluginContext, quer return backend.DataResponse{}, fmt.Errorf("new request with context: %w", err) } if len(query.JSON) > 0 { - input := &apiQuery{} - err = json.Unmarshal(query.JSON, input) + input, err := d.migrateQuery(pCtx, query) if err != nil { - return backend.DataResponse{}, fmt.Errorf("unmarshal: %w", err) + return backend.DataResponse{}, err } q := req.URL.Query() - q.Add("multiplier", strconv.Itoa(input.Multiplier)) + q.Add("multiplier", strconv.Itoa(input.Multiply)) req.URL.RawQuery = q.Encode() } httpResp, err := d.httpClient.Do(req) diff --git a/examples/datasource-http-backend/pkg/plugin/types.go b/examples/datasource-http-backend/pkg/plugin/types.go index 3834415f2..11bd97fe2 100644 --- a/examples/datasource-http-backend/pkg/plugin/types.go +++ b/examples/datasource-http-backend/pkg/plugin/types.go @@ -1,6 +1,10 @@ package plugin -import "time" +import ( + "time" + + "github.com/grafana/grafana-plugin-sdk-go/experimental/apis/data/v0alpha1" +) // apiMetrics is a struct containing a slice of dataPoint type apiMetrics struct { @@ -14,5 +18,12 @@ type apiDataPoint struct { } type apiQuery struct { + v0alpha1.CommonQueryProperties + + Multiply int `json:"multiply"` + PluginVersion string `json:"pluginVersion"` +} + +type apiQueryV1 struct { Multiplier int `json:"multiplier"` } diff --git a/examples/datasource-http-backend/src/components/QueryEditor.tsx b/examples/datasource-http-backend/src/components/QueryEditor.tsx index 3cf13b0e4..ffe3577cf 100644 --- a/examples/datasource-http-backend/src/components/QueryEditor.tsx +++ b/examples/datasource-http-backend/src/components/QueryEditor.tsx @@ -1,24 +1,37 @@ -import React, { PureComponent } from 'react'; +import React, { useState, useEffect } from 'react'; import { QueryEditorProps } from '@grafana/data'; import { DataSource } from '../datasource'; import { MyDataSourceOptions, MyQuery } from '../types'; -import { HorizontalGroup, Input, Label } from '@grafana/ui'; +import { InlineField, Input, Stack } from '@grafana/ui'; type Props = QueryEditorProps; -export class QueryEditor extends PureComponent { - render() { - return ( - - +export const QueryEditor = (props: Props) => { + const [query, setQuery] = useState(props.query); + useEffect(() => { + props.datasource.migrateQuery(props.query).then((query) => { + setQuery(query); + }); + }, []); // eslint-disable-line react-hooks/exhaustive-deps + + const onChangeMultiplier = (multiply: number) => { + const newQuery = { ...query, multiply, pluginVersion: props.datasource.meta.info.version }; + setQuery(newQuery); + props.onChange(newQuery); + }; + + console.log('query', query); + return ( + + this.props.onChange({ ...this.props.query, multiplier: e.currentTarget.valueAsNumber })} + value={query.multiply} + onChange={(e) => onChangeMultiplier(e.currentTarget.valueAsNumber)} /> - - ); - } -} + + + ); +}; diff --git a/examples/datasource-http-backend/src/datasource.ts b/examples/datasource-http-backend/src/datasource.ts index 19d31d869..ecd5f61c7 100644 --- a/examples/datasource-http-backend/src/datasource.ts +++ b/examples/datasource-http-backend/src/datasource.ts @@ -9,6 +9,10 @@ export class DataSource extends DataSourceWithBackend { - return { multiplier: 1 }; + return { multiply: 1, pluginVersion: this.meta.info.version }; + } + + async migrateQuery(query: any): Promise { + return await this.postResource(`/migrate-query`, query); } } diff --git a/examples/datasource-http-backend/src/types.ts b/examples/datasource-http-backend/src/types.ts index 8c845f552..ce8ba0e1a 100644 --- a/examples/datasource-http-backend/src/types.ts +++ b/examples/datasource-http-backend/src/types.ts @@ -1,7 +1,8 @@ -import { DataQuery, DataSourceJsonData } from '@grafana/data'; +import { DataQuery, DataSourceJsonData } from '@grafana/schema'; export interface MyQuery extends DataQuery { - multiplier: number; + multiply: number; + pluginVersion: string; } /**