ObjectStore: add a kind registry (#56507)

This commit is contained in:
Ryan McKinley
2022-10-08 09:05:46 -07:00
committed by GitHub
parent ac91df0ea2
commit b24be6c0fc
72 changed files with 1883 additions and 402 deletions

View File

@@ -0,0 +1,450 @@
package dashboard
import (
"io"
"strconv"
"strings"
jsoniter "github.com/json-iterator/go"
)
func logf(format string, a ...interface{}) {
//fmt.Printf(format, a...)
}
type templateVariable struct {
current struct {
value interface{}
}
name string
query interface{}
variableType string
}
type datasourceVariableLookup struct {
variableNameToRefs map[string][]DataSourceRef
dsLookup DatasourceLookup
}
func (d *datasourceVariableLookup) getDsRefsByTemplateVariableValue(value string, datasourceType string) []DataSourceRef {
switch value {
case "default":
// can be the default DS, or a DS with UID="default"
candidateDs := d.dsLookup.ByRef(&DataSourceRef{UID: value})
if candidateDs == nil {
// get the actual default DS
candidateDs = d.dsLookup.ByRef(nil)
}
if candidateDs != nil {
return []DataSourceRef{*candidateDs}
}
return []DataSourceRef{}
case "$__all":
// TODO: filter datasources by template variable's regex
return d.dsLookup.ByType(datasourceType)
case "":
return []DataSourceRef{}
case "No data sources found":
return []DataSourceRef{}
default:
// some variables use `ds.name` rather `ds.uid`
if ref := d.dsLookup.ByRef(&DataSourceRef{
UID: value,
}); ref != nil {
return []DataSourceRef{*ref}
}
// discard variable
return []DataSourceRef{}
}
}
func (d *datasourceVariableLookup) add(templateVariable templateVariable) {
var refs []DataSourceRef
datasourceType, isDataSourceTypeValid := templateVariable.query.(string)
if !isDataSourceTypeValid {
d.variableNameToRefs[templateVariable.name] = refs
return
}
if values, multiValueVariable := templateVariable.current.value.([]interface{}); multiValueVariable {
for _, value := range values {
if valueAsString, ok := value.(string); ok {
refs = append(refs, d.getDsRefsByTemplateVariableValue(valueAsString, datasourceType)...)
}
}
}
if value, stringValue := templateVariable.current.value.(string); stringValue {
refs = append(refs, d.getDsRefsByTemplateVariableValue(value, datasourceType)...)
}
d.variableNameToRefs[templateVariable.name] = unique(refs)
}
func unique(refs []DataSourceRef) []DataSourceRef {
var uniqueRefs []DataSourceRef
uidPresence := make(map[string]bool)
for _, ref := range refs {
if !uidPresence[ref.UID] {
uidPresence[ref.UID] = true
uniqueRefs = append(uniqueRefs, ref)
}
}
return uniqueRefs
}
func (d *datasourceVariableLookup) getDatasourceRefs(name string) []DataSourceRef {
refs, ok := d.variableNameToRefs[name]
if ok {
return refs
}
return []DataSourceRef{}
}
func newDatasourceVariableLookup(dsLookup DatasourceLookup) *datasourceVariableLookup {
return &datasourceVariableLookup{
variableNameToRefs: make(map[string][]DataSourceRef),
dsLookup: dsLookup,
}
}
// nolint:gocyclo
// ReadDashboard will take a byte stream and return dashboard info
func readDashboard(stream io.Reader, lookup DatasourceLookup) (*dashboardInfo, error) {
dash := &dashboardInfo{}
iter := jsoniter.Parse(jsoniter.ConfigDefault, stream, 1024)
datasourceVariablesLookup := newDatasourceVariableLookup(lookup)
for l1Field := iter.ReadObject(); l1Field != ""; l1Field = iter.ReadObject() {
// Skip null values so we don't need special int handling
if iter.WhatIsNext() == jsoniter.NilValue {
iter.Skip()
continue
}
switch l1Field {
case "id":
dash.ID = iter.ReadInt64()
case "uid":
iter.ReadString()
case "title":
dash.Title = iter.ReadString()
case "description":
dash.Description = iter.ReadString()
case "schemaVersion":
switch iter.WhatIsNext() {
case jsoniter.NumberValue:
dash.SchemaVersion = iter.ReadInt64()
case jsoniter.StringValue:
val := iter.ReadString()
if v, err := strconv.ParseInt(val, 10, 64); err == nil {
dash.SchemaVersion = v
}
default:
iter.Skip()
}
case "timezone":
dash.TimeZone = iter.ReadString()
case "editable":
dash.ReadOnly = !iter.ReadBool()
case "refresh":
nxt := iter.WhatIsNext()
if nxt == jsoniter.StringValue {
dash.Refresh = iter.ReadString()
} else {
iter.Skip()
}
case "tags":
for iter.ReadArray() {
dash.Tags = append(dash.Tags, iter.ReadString())
}
case "links":
for iter.ReadArray() {
iter.Skip()
dash.LinkCount++
}
case "time":
obj, ok := iter.Read().(map[string]interface{})
if ok {
if timeFrom, ok := obj["from"].(string); ok {
dash.TimeFrom = timeFrom
}
if timeTo, ok := obj["to"].(string); ok {
dash.TimeTo = timeTo
}
}
case "panels":
for iter.ReadArray() {
dash.Panels = append(dash.Panels, readpanelInfo(iter, lookup))
}
case "rows":
for iter.ReadArray() {
v := iter.Read()
logf("[DASHBOARD.ROW???] id=%s // %v\n", dash.ID, v)
}
case "annotations":
for sub := iter.ReadObject(); sub != ""; sub = iter.ReadObject() {
if sub == "list" {
for iter.ReadArray() {
v := iter.Read()
logf("[dash.anno] %v\n", v)
}
} else {
iter.Skip()
}
}
case "templating":
for sub := iter.ReadObject(); sub != ""; sub = iter.ReadObject() {
if sub == "list" {
for iter.ReadArray() {
templateVariable := templateVariable{}
for k := iter.ReadObject(); k != ""; k = iter.ReadObject() {
switch k {
case "name":
name := iter.ReadString()
dash.TemplateVars = append(dash.TemplateVars, name)
templateVariable.name = name
case "type":
templateVariable.variableType = iter.ReadString()
case "query":
templateVariable.query = iter.Read()
case "current":
for c := iter.ReadObject(); c != ""; c = iter.ReadObject() {
if c == "value" {
templateVariable.current.value = iter.Read()
} else {
iter.Skip()
}
}
default:
iter.Skip()
}
}
if templateVariable.variableType == "datasource" {
datasourceVariablesLookup.add(templateVariable)
}
}
} else {
iter.Skip()
}
}
// Ignore these properties
case "timepicker":
fallthrough
case "version":
fallthrough
case "iteration":
iter.Skip()
default:
v := iter.Read()
logf("[DASHBOARD] support key: %s / %v\n", l1Field, v)
}
}
replaceDatasourceVariables(dash, datasourceVariablesLookup)
fillDefaultDatasources(dash, lookup)
filterOutSpecialDatasources(dash)
targets := newTargetInfo(lookup)
for _, panel := range dash.Panels {
targets.addPanel(panel)
}
dash.Datasource = targets.GetDatasourceInfo()
return dash, iter.Error
}
func panelRequiresDatasource(panel panelInfo) bool {
return panel.Type != "row"
}
func fillDefaultDatasources(dash *dashboardInfo, lookup DatasourceLookup) {
for i, panel := range dash.Panels {
if len(panel.Datasource) != 0 || !panelRequiresDatasource(panel) {
continue
}
defaultDs := lookup.ByRef(nil)
if defaultDs != nil {
dash.Panels[i].Datasource = []DataSourceRef{*defaultDs}
}
}
}
func filterOutSpecialDatasources(dash *dashboardInfo) {
for i, panel := range dash.Panels {
var dsRefs []DataSourceRef
// partition into actual datasource references and variables
for _, ds := range panel.Datasource {
switch ds.UID {
case "-- Mixed --":
// The actual datasources used as targets will remain
continue
case "-- Dashboard --":
// The `Dashboard` datasource refers to the results of the query used in another panel
continue
default:
dsRefs = append(dsRefs, ds)
}
}
dash.Panels[i].Datasource = dsRefs
}
}
func replaceDatasourceVariables(dash *dashboardInfo, datasourceVariablesLookup *datasourceVariableLookup) {
for i, panel := range dash.Panels {
var dsVariableRefs []DataSourceRef
var dsRefs []DataSourceRef
// partition into actual datasource references and variables
for i := range panel.Datasource {
uid := panel.Datasource[i].UID
if isVariableRef(uid) {
dsVariableRefs = append(dsVariableRefs, panel.Datasource[i])
} else {
dsRefs = append(dsRefs, panel.Datasource[i])
}
}
variables := findDatasourceRefsForVariables(dsVariableRefs, datasourceVariablesLookup)
dash.Panels[i].Datasource = append(dsRefs, variables...)
}
}
func isSpecialDatasource(uid string) bool {
return uid == "-- Mixed --" || uid == "-- Dashboard --"
}
func isVariableRef(uid string) bool {
return strings.HasPrefix(uid, "$")
}
func getDataSourceVariableName(dsVariableRef DataSourceRef) string {
if strings.HasPrefix(dsVariableRef.UID, "${") {
return strings.TrimPrefix(strings.TrimSuffix(dsVariableRef.UID, "}"), "${")
}
return strings.TrimPrefix(dsVariableRef.UID, "$")
}
func findDatasourceRefsForVariables(dsVariableRefs []DataSourceRef, datasourceVariablesLookup *datasourceVariableLookup) []DataSourceRef {
var referencedDs []DataSourceRef
for _, dsVariableRef := range dsVariableRefs {
variableName := getDataSourceVariableName(dsVariableRef)
refs := datasourceVariablesLookup.getDatasourceRefs(variableName)
referencedDs = append(referencedDs, refs...)
}
return referencedDs
}
// will always return strings for now
func readpanelInfo(iter *jsoniter.Iterator, lookup DatasourceLookup) panelInfo {
panel := panelInfo{}
targets := newTargetInfo(lookup)
for l1Field := iter.ReadObject(); l1Field != ""; l1Field = iter.ReadObject() {
if iter.WhatIsNext() == jsoniter.NilValue {
if l1Field == "datasource" {
targets.addDatasource(iter)
continue
}
// Skip null values so we don't need special int handling
iter.Skip()
continue
}
switch l1Field {
case "id":
panel.ID = iter.ReadInt64()
case "type":
panel.Type = iter.ReadString()
case "title":
panel.Title = iter.ReadString()
case "description":
panel.Description = iter.ReadString()
case "pluginVersion":
panel.PluginVersion = iter.ReadString() // since 7x (the saved version for the plugin model)
case "datasource":
targets.addDatasource(iter)
case "targets":
switch iter.WhatIsNext() {
case jsoniter.ArrayValue:
for iter.ReadArray() {
targets.addTarget(iter)
}
case jsoniter.ObjectValue:
for f := iter.ReadObject(); f != ""; f = iter.ReadObject() {
targets.addTarget(iter)
}
default:
iter.Skip()
}
case "transformations":
for iter.ReadArray() {
for sub := iter.ReadObject(); sub != ""; sub = iter.ReadObject() {
if sub == "id" {
panel.Transformer = append(panel.Transformer, iter.ReadString())
} else {
iter.Skip()
}
}
}
// Rows have nested panels
case "panels":
for iter.ReadArray() {
panel.Collapsed = append(panel.Collapsed, readpanelInfo(iter, lookup))
}
case "options":
fallthrough
case "gridPos":
fallthrough
case "fieldConfig":
iter.Skip()
default:
v := iter.Read()
logf("[PANEL] support key: %s / %v\n", l1Field, v)
}
}
panel.Datasource = targets.GetDatasourceInfo()
return panel
}

View File

@@ -0,0 +1,126 @@
package dashboard
import (
"encoding/json"
"os"
"path/filepath"
"sort"
"strings"
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func dsLookupForTests() DatasourceLookup {
return CreateDatasourceLookup([]*DatasourceQueryResult{
{
UID: "P8045C56BDA891CB2",
Type: "cloudwatch",
Name: "cloudwatch-name",
IsDefault: false,
},
{
UID: "PD8C576611E62080A",
Type: "testdata",
Name: "gdev-testdata",
IsDefault: false,
},
{
UID: "dgd92lq7k",
Type: "frser-sqlite-datasource",
Name: "frser-sqlite-datasource-name",
IsDefault: false,
},
{
UID: "sqlite-1",
Type: "sqlite-datasource",
Name: "SQLite Grafana",
IsDefault: false,
},
{
UID: "sqlite-2",
Type: "sqlite-datasource",
Name: "SQLite Grafana2",
IsDefault: false,
},
{
UID: "default.uid",
Type: "default.type",
Name: "default.name",
IsDefault: true,
},
})
}
func TestReadDashboard(t *testing.T) {
inputs := []string{
"check-string-datasource-id",
"all-panels",
"panel-graph/graph-shared-tooltips",
"datasource-variable",
"default-datasource-variable",
"empty-datasource-variable",
"repeated-datasource-variables",
"string-datasource-variable",
"datasource-variable-no-curly-braces",
"all-selected-multi-datasource-variable",
"all-selected-single-datasource-variable",
"repeated-datasource-variables-with-default",
"mixed-datasource-with-variable",
"special-datasource-types",
"panels-without-datasources",
}
devdash := "../../../../../devenv/dev-dashboards/"
for _, input := range inputs {
// nolint:gosec
// We can ignore the gosec G304 warning because this is a test with hardcoded input values
f, err := os.Open(filepath.Join(devdash, input) + ".json")
if err == nil {
input = "devdash-" + filepath.Base(input)
}
if err != nil {
// nolint:gosec
// We can ignore the gosec G304 warning because this is a test with hardcoded input values
f, err = os.Open(filepath.Join("testdata", input) + ".json")
}
require.NoError(t, err)
dash, err := readDashboard(f, dsLookupForTests())
sortDatasources(dash)
require.NoError(t, err)
out, err := json.MarshalIndent(dash, "", " ")
require.NoError(t, err)
update := false
savedPath := filepath.Join("testdata/", input+"-info.json")
//nolint:gosec
saved, err := os.ReadFile(savedPath)
if err != nil {
update = true
assert.NoError(t, err)
} else if !assert.JSONEq(t, string(saved), string(out)) {
update = true
}
if update {
_ = os.WriteFile(savedPath, out, 0600)
}
}
}
// assure consistent ordering of datasources to prevent random failures of `assert.JSONEq`
func sortDatasources(dash *dashboardInfo) {
sort.Slice(dash.Datasource, func(i, j int) bool {
return strings.Compare(dash.Datasource[i].UID, dash.Datasource[j].UID) > 0
})
for panelId := range dash.Panels {
sort.Slice(dash.Panels[panelId].Datasource, func(i, j int) bool {
return strings.Compare(dash.Panels[panelId].Datasource[i].UID, dash.Panels[panelId].Datasource[j].UID) > 0
})
}
}

View File

@@ -0,0 +1,136 @@
package dashboard
import (
"context"
"github.com/grafana/grafana/pkg/services/sqlstore"
)
type DataSourceRef struct {
UID string `json:"uid,omitempty"`
Type string `json:"type,omitempty"`
}
type DatasourceLookup interface {
// ByRef will return the default DS given empty reference (nil ref, or empty ref.uid and ref.type)
ByRef(ref *DataSourceRef) *DataSourceRef
ByType(dsType string) []DataSourceRef
}
type DatasourceQueryResult struct {
UID string `xorm:"uid"`
Type string `xorm:"type"`
Name string `xorm:"name"`
IsDefault bool `xorm:"is_default"`
}
func CreateDatasourceLookup(rows []*DatasourceQueryResult) DatasourceLookup {
byUID := make(map[string]*DataSourceRef, 50)
byName := make(map[string]*DataSourceRef, 50)
byType := make(map[string][]DataSourceRef, 50)
var defaultDS *DataSourceRef
for _, row := range rows {
ref := &DataSourceRef{
UID: row.UID,
Type: row.Type,
}
byUID[row.UID] = ref
byName[row.Name] = ref
if row.IsDefault {
defaultDS = ref
}
if _, ok := byType[row.Type]; !ok {
byType[row.Type] = make([]DataSourceRef, 0)
}
byType[row.Type] = append(byType[row.Type], *ref)
}
grafanaDs := &DataSourceRef{
UID: "grafana",
Type: "datasource",
}
if defaultDS == nil {
// fallback replicated from /pkg/api/frontendsettings.go
// https://github.com/grafana/grafana/blob/7ef21662f9ad74b80d832b9f2aa9db2fb4192741/pkg/api/frontendsettings.go#L51-L56
defaultDS = grafanaDs
}
if _, ok := byUID[grafanaDs.UID]; !ok {
byUID[grafanaDs.UID] = grafanaDs
}
grafanaDsName := "-- Grafana --"
if _, ok := byName[grafanaDsName]; !ok {
byName[grafanaDsName] = grafanaDs
}
return &DsLookup{
byName: byName,
byUID: byUID,
byType: byType,
defaultDS: defaultDS,
}
}
type DsLookup struct {
byName map[string]*DataSourceRef
byUID map[string]*DataSourceRef
byType map[string][]DataSourceRef
defaultDS *DataSourceRef
}
func (d *DsLookup) ByRef(ref *DataSourceRef) *DataSourceRef {
if ref == nil {
return d.defaultDS
}
key := ""
if ref.UID != "" {
ds, ok := d.byUID[ref.UID]
if ok {
return ds
}
key = ref.UID
}
if key == "" {
return d.defaultDS
}
ds, ok := d.byUID[key]
if ok {
return ds
}
return d.byName[key]
}
func (d *DsLookup) ByType(dsType string) []DataSourceRef {
ds, ok := d.byType[dsType]
if !ok {
return make([]DataSourceRef, 0)
}
return ds
}
func LoadDatasourceLookup(ctx context.Context, orgID int64, sql *sqlstore.SQLStore) (DatasourceLookup, error) {
rows := make([]*DatasourceQueryResult, 0)
if err := sql.WithDbSession(ctx, func(sess *sqlstore.DBSession) error {
sess.Table("data_source").
Where("org_id = ?", orgID).
Cols("uid", "name", "type", "is_default")
err := sess.Find(&rows)
if err != nil {
return err
}
return nil
}); err != nil {
return nil, err
}
return CreateDatasourceLookup(rows), nil
}

View File

@@ -0,0 +1,53 @@
package dashboard
import (
"fmt"
"sort"
"github.com/grafana/grafana/pkg/models"
)
// A reference accumulator can combine
type ReferenceAccumulator interface {
// Add references as we find them
Add(kind string, subtype string, uid string)
// Returns the set of distinct references in a sorted order
Get() []*models.ObjectExternalReference
}
func NewReferenceAccumulator() ReferenceAccumulator {
return &referenceAccumulator{
refs: make(map[string]*models.ObjectExternalReference),
}
}
type referenceAccumulator struct {
refs map[string]*models.ObjectExternalReference
}
func (x *referenceAccumulator) Add(kind string, sub string, uid string) {
key := fmt.Sprintf("%s/%s/%s", kind, sub, uid)
_, ok := x.refs[key]
if !ok {
x.refs[key] = &models.ObjectExternalReference{
Kind: kind,
Type: sub,
UID: uid,
}
}
}
func (x *referenceAccumulator) Get() []*models.ObjectExternalReference {
keys := make([]string, 0, len(x.refs))
for k := range x.refs {
keys = append(keys, k)
}
sort.Strings(keys)
refs := make([]*models.ObjectExternalReference, len(keys))
for i, key := range keys {
refs[i] = x.refs[key]
}
return refs
}

View File

@@ -0,0 +1,99 @@
package dashboard
import (
"bytes"
"context"
"fmt"
"strconv"
"github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/services/sqlstore"
"github.com/grafana/grafana/pkg/services/store"
)
func GetObjectKindInfo() models.ObjectKindInfo {
return models.ObjectKindInfo{
ID: models.StandardKindDashboard,
Name: "Dashboard",
Description: "Define a grafana dashboard layout",
}
}
func NewDashboardSummary(sql *sqlstore.SQLStore) models.ObjectSummaryBuilder {
return func(ctx context.Context, uid string, body []byte) (*models.ObjectSummary, []byte, error) {
// This just gets the orgID (that will soon/eventually be encoded in a GRN and passed instead of a UID)
user := store.UserFromContext(ctx)
if user == nil {
return nil, nil, fmt.Errorf("can not find user in context")
}
// Totally inefficient to look this up every time, but for the current use case that is OK
// The lookup is currently structured to support searchV2, but I think should become a real fallback
// that is only executed when we find a legacy dashboard ref
lookup, err := LoadDatasourceLookup(ctx, user.OrgID, sql)
if err != nil {
return nil, nil, err
}
builder := NewStaticDashboardSummaryBuilder(lookup)
return builder(ctx, uid, body)
}
}
func NewStaticDashboardSummaryBuilder(lookup DatasourceLookup) models.ObjectSummaryBuilder {
return func(ctx context.Context, uid string, body []byte) (*models.ObjectSummary, []byte, error) {
summary := &models.ObjectSummary{
Labels: make(map[string]string),
Fields: make(map[string]interface{}),
}
stream := bytes.NewBuffer(body)
dash, err := readDashboard(stream, lookup)
if err != nil {
summary.Error = &models.ObjectErrorInfo{
Message: err.Error(),
}
return summary, body, err
}
dashboardRefs := NewReferenceAccumulator()
url := fmt.Sprintf("/d/%s/%s", uid, models.SlugifyTitle(dash.Title))
summary.Name = dash.Title
summary.Description = dash.Description
summary.URL = url
for _, v := range dash.Tags {
summary.Labels[v] = ""
}
if len(dash.TemplateVars) > 0 {
summary.Fields["hasTemplateVars"] = true
}
summary.Fields["schemaVersion"] = dash.SchemaVersion
for _, panel := range dash.Panels {
panelRefs := NewReferenceAccumulator()
p := &models.ObjectSummary{
UID: uid + "#" + strconv.FormatInt(panel.ID, 10),
Kind: "panel",
}
p.Name = panel.Title
p.Description = panel.Description
p.URL = fmt.Sprintf("%s?viewPanel=%d", url, panel.ID)
p.Fields = make(map[string]interface{}, 0)
panelRefs.Add("panel", panel.Type, "")
for _, v := range panel.Datasource {
dashboardRefs.Add(models.StandardKindDataSource, v.Type, v.UID)
panelRefs.Add(models.StandardKindDataSource, v.Type, v.UID)
}
for _, v := range panel.Transformer {
panelRefs.Add(models.StandardKindTransform, v, "")
}
dashboardRefs.Add(models.StandardKindPanel, panel.Type, "")
p.References = panelRefs.Get()
summary.Nested = append(summary.Nested, p)
}
summary.References = dashboardRefs.Get()
return summary, body, nil
}
}

View File

@@ -0,0 +1,67 @@
package dashboard
import (
"bytes"
"context"
"encoding/json"
"os"
"path/filepath"
"strings"
"testing"
"github.com/stretchr/testify/require"
)
func TestReadSummaries(t *testing.T) {
devdash := "../../../../../devenv/dev-dashboards/panel-graph/"
ctx := context.Background()
reader := NewStaticDashboardSummaryBuilder(dsLookupForTests())
failed := make([]string, 0, 10)
err := filepath.Walk(devdash,
func(path string, info os.FileInfo, err error) error {
if err != nil {
return err
}
if !info.IsDir() && strings.HasSuffix(path, ".json") {
// Ignore gosec warning G304 since it's a test
// nolint:gosec
body, err := os.ReadFile(path)
if err != nil {
return err
}
uid := path[len(devdash):]
summary, _, err := reader(ctx, uid, body)
if err != nil {
return err
}
out, err := json.MarshalIndent(summary, "", " ")
if err != nil {
return err
}
gpath := "testdata/gdev-walk-" + strings.ReplaceAll(uid, "/", "-")
// Ignore gosec warning G304 since it's a test
// nolint:gosec
golden, _ := os.ReadFile(gpath)
if !bytes.Equal(out, golden) {
failed = append(failed, uid)
err = os.WriteFile(gpath, out, 0600)
if err != nil {
return err
}
}
}
return nil
})
require.NoError(t, err)
// accumulated in the walk test
require.Equal(t, []string{}, failed)
}

View File

@@ -0,0 +1,91 @@
package dashboard
import (
jsoniter "github.com/json-iterator/go"
)
type targetInfo struct {
lookup DatasourceLookup
uids map[string]*DataSourceRef
}
func newTargetInfo(lookup DatasourceLookup) targetInfo {
return targetInfo{
lookup: lookup,
uids: make(map[string]*DataSourceRef),
}
}
func (s *targetInfo) GetDatasourceInfo() []DataSourceRef {
keys := make([]DataSourceRef, len(s.uids))
i := 0
for _, v := range s.uids {
keys[i] = *v
i++
}
return keys
}
// the node will either be string (name|uid) OR ref
func (s *targetInfo) addDatasource(iter *jsoniter.Iterator) {
switch iter.WhatIsNext() {
case jsoniter.StringValue:
key := iter.ReadString()
dsRef := &DataSourceRef{UID: key}
if !isVariableRef(dsRef.UID) && !isSpecialDatasource(dsRef.UID) {
ds := s.lookup.ByRef(dsRef)
s.addRef(ds)
} else {
s.addRef(dsRef)
}
case jsoniter.NilValue:
s.addRef(s.lookup.ByRef(nil))
iter.Skip()
case jsoniter.ObjectValue:
ref := &DataSourceRef{}
iter.ReadVal(ref)
if !isVariableRef(ref.UID) && !isSpecialDatasource(ref.UID) {
s.addRef(s.lookup.ByRef(ref))
} else {
s.addRef(ref)
}
default:
v := iter.Read()
logf("[Panel.datasource.unknown] %v\n", v)
}
}
func (s *targetInfo) addRef(ref *DataSourceRef) {
if ref != nil && ref.UID != "" {
s.uids[ref.UID] = ref
}
}
func (s *targetInfo) addTarget(iter *jsoniter.Iterator) {
for l1Field := iter.ReadObject(); l1Field != ""; l1Field = iter.ReadObject() {
switch l1Field {
case "datasource":
s.addDatasource(iter)
case "refId":
iter.Skip()
default:
v := iter.Read()
logf("[Panel.TARGET] %s=%v\n", l1Field, v)
}
}
}
func (s *targetInfo) addPanel(panel panelInfo) {
for idx, v := range panel.Datasource {
if v.UID != "" {
s.uids[v.UID] = &panel.Datasource[idx]
}
}
}

View File

@@ -0,0 +1,61 @@
{
"id": 209,
"title": "ds-variables",
"tags": null,
"templateVars": [
"sqllite"
],
"datasource": [
{
"uid": "sqlite-2",
"type": "sqlite-datasource"
},
{
"uid": "sqlite-1",
"type": "sqlite-datasource"
}
],
"panels": [
{
"id": 7,
"title": "Panel Title",
"type": "timeseries",
"datasource": [
{
"uid": "sqlite-2",
"type": "sqlite-datasource"
},
{
"uid": "sqlite-1",
"type": "sqlite-datasource"
}
]
},
{
"id": 3,
"title": "Row title",
"type": "row"
},
{
"id": 1,
"title": "usersss!",
"type": "table",
"pluginVersion": "9.1.0-pre",
"datasource": [
{
"uid": "sqlite-2",
"type": "sqlite-datasource"
},
{
"uid": "sqlite-1",
"type": "sqlite-datasource"
}
]
}
],
"schemaVersion": 36,
"linkCount": 0,
"timeFrom": "now-6h",
"timeTo": "now",
"timezone": ""
}

View File

@@ -0,0 +1,230 @@
{
"annotations": {
"list": [
]
},
"editable": true,
"fiscalYearStartMonth": 0,
"graphTooltip": 0,
"id": 209,
"iteration": 1656533909544,
"links": [],
"liveNow": false,
"panels": [
{
"datasource": {
"type": "sqlite-datasource",
"uid": "${sqllite}"
},
"fieldConfig": {
"defaults": {
"color": {
"mode": "palette-classic"
},
"custom": {
"axisLabel": "",
"axisPlacement": "auto",
"barAlignment": 0,
"drawStyle": "line",
"fillOpacity": 0,
"gradientMode": "none",
"hideFrom": {
"legend": false,
"tooltip": false,
"viz": false
},
"lineInterpolation": "linear",
"lineWidth": 1,
"pointSize": 5,
"scaleDistribution": {
"type": "linear"
},
"showPoints": "auto",
"spanNulls": false,
"stacking": {
"group": "A",
"mode": "none"
},
"thresholdsStyle": {
"mode": "off"
}
},
"mappings": [],
"thresholds": {
"mode": "absolute",
"steps": [
{
"color": "green",
"value": null
},
{
"color": "red",
"value": 80
}
]
}
},
"overrides": []
},
"gridPos": {
"h": 8,
"w": 12,
"x": 0,
"y": 0
},
"id": 7,
"options": {
"legend": {
"calcs": [],
"displayMode": "list",
"placement": "bottom"
},
"tooltip": {
"mode": "single",
"sort": "none"
}
},
"repeat": "sqllite",
"repeatDirection": "h",
"targets": [
{
"datasource": {
"type": "sqlite-datasource",
"uid": "${sqllite}"
},
"queryText": "\n SELECT CAST(strftime('%s', 'now', '-1 minute') as INTEGER) as time, 4 as value\n WHERE time >= 1234 and time < 134567\n ",
"queryType": "table",
"rawQueryText": "SELECT CAST(strftime('%s', 'now', '-1 minute') as INTEGER) as time, 4 as value \nWHERE time >= $__from / 1000 and time < $__to / 1000",
"refId": "A",
"timeColumns": [
"time",
"ts"
]
}
],
"title": "Panel Title",
"type": "timeseries"
},
{
"collapsed": false,
"gridPos": {
"h": 1,
"w": 24,
"x": 0,
"y": 8
},
"id": 3,
"panels": [],
"repeat": "sqllite",
"repeatDirection": "h",
"title": "Row title",
"type": "row"
},
{
"datasource": {
"type": "sqlite-datasource",
"uid": "${sqllite}"
},
"fieldConfig": {
"defaults": {
"custom": {
"align": "auto",
"displayMode": "auto",
"inspect": false
},
"mappings": [],
"thresholds": {
"mode": "absolute",
"steps": [
{
"color": "green",
"value": null
},
{
"color": "red",
"value": 80
}
]
}
},
"overrides": []
},
"gridPos": {
"h": 8,
"w": 12,
"x": 8,
"y": 9
},
"id": 1,
"options": {
"footer": {
"fields": "",
"reducer": [
"sum"
],
"show": false
},
"showHeader": true
},
"pluginVersion": "9.1.0-pre",
"targets": [
{
"datasource": {
"type": "sqlite-datasource",
"uid": "${sqllite}"
},
"queryText": "select * from user",
"queryType": "table",
"rawQueryText": "select * from user",
"refId": "A",
"timeColumns": [
"time",
"ts"
]
}
],
"title": "usersss!",
"type": "table"
}
],
"schemaVersion": 36,
"style": "dark",
"tags": [],
"templating": {
"list": [
{
"allValue": "",
"current": {
"selected": true,
"text": [
"All"
],
"value": [
"$__all"
]
},
"hide": 0,
"includeAll": true,
"multi": true,
"name": "sqllite",
"options": [],
"query": "sqlite-datasource",
"queryValue": "",
"refresh": 1,
"regex": "",
"skipUrlSync": false,
"type": "datasource"
}
]
},
"time": {
"from": "now-6h",
"to": "now"
},
"timepicker": {},
"timezone": "",
"title": "ds-variables",
"uid": "7BzWolqnk",
"version": 36,
"weekStart": ""
}

View File

@@ -0,0 +1,41 @@
{
"id": 208,
"title": "new-dashboard-var-ds-test",
"tags": null,
"templateVars": [
"dsVariable"
],
"datasource": [
{
"uid": "sqlite-2",
"type": "sqlite-datasource"
},
{
"uid": "sqlite-1",
"type": "sqlite-datasource"
}
],
"panels": [
{
"id": 2,
"title": "Panel Title",
"type": "table",
"pluginVersion": "9.1.0-pre",
"datasource": [
{
"uid": "sqlite-2",
"type": "sqlite-datasource"
},
{
"uid": "sqlite-1",
"type": "sqlite-datasource"
}
]
}
],
"schemaVersion": 36,
"linkCount": 0,
"timeFrom": "now-6h",
"timeTo": "now",
"timezone": ""
}

View File

@@ -0,0 +1,133 @@
{
"annotations": {
"list": [
{
"builtIn": 1,
"datasource": {
"type": "grafana",
"uid": "-- Grafana --"
},
"enable": true,
"hide": true,
"iconColor": "rgba(0, 211, 255, 1)",
"name": "Annotations & Alerts",
"target": {
"limit": 100,
"matchAny": false,
"tags": [],
"type": "dashboard"
},
"type": "dashboard"
}
]
},
"editable": true,
"fiscalYearStartMonth": 0,
"graphTooltip": 0,
"id": 208,
"iteration": 1657048248371,
"links": [],
"liveNow": false,
"panels": [
{
"datasource": {
"type": "sqlite-datasource",
"uid": "${dsVariable}"
},
"fieldConfig": {
"defaults": {
"color": {
"mode": "thresholds"
},
"custom": {
"align": "auto",
"displayMode": "auto",
"inspect": false
},
"mappings": [],
"thresholds": {
"mode": "absolute",
"steps": [
{
"color": "green",
"value": null
},
{
"color": "red",
"value": 80
}
]
}
},
"overrides": []
},
"gridPos": {
"h": 16,
"w": 12,
"x": 0,
"y": 0
},
"id": 2,
"options": {
"footer": {
"fields": "",
"reducer": [
"sum"
],
"show": false
},
"showHeader": true
},
"pluginVersion": "9.1.0-pre",
"repeat": "dsVariable",
"repeatDirection": "h",
"targets": [
{
"datasource": {
"type": "sqlite-datasource",
"uid": "${dsVariable}"
},
"refId": "A"
}
],
"title": "Panel Title",
"type": "table"
}
],
"refresh": "",
"schemaVersion": 36,
"style": "dark",
"tags": [],
"templating": {
"list": [
{
"current": {
"selected": true,
"text": "All",
"value": "$__all"
},
"hide": 0,
"includeAll": true,
"multi": false,
"name": "dsVariable",
"options": [],
"query": "sqlite-datasource",
"queryValue": "",
"refresh": 1,
"regex": "",
"skipUrlSync": false,
"type": "datasource"
}
]
},
"time": {
"from": "now-6h",
"to": "now"
},
"timepicker": {},
"timezone": "",
"title": "new-dashboard-var-ds-test",
"uid": "2HLX_B3nk",
"version": 21,
"weekStart": ""
}

View File

@@ -0,0 +1,30 @@
{
"id": 250,
"title": "fast streaming",
"tags": null,
"datasource": [
{
"uid": "grafana",
"type": "datasource"
}
],
"panels": [
{
"id": 3,
"title": "Panel Title",
"type": "timeseries",
"pluginVersion": "7.5.0-pre",
"datasource": [
{
"uid": "grafana",
"type": "datasource"
}
]
}
],
"schemaVersion": 27,
"linkCount": 0,
"timeFrom": "now-30s",
"timeTo": "now",
"timezone": ""
}

View File

@@ -0,0 +1,67 @@
{
"annotations": {
"list": [
{
"builtIn": 1,
"datasource": "-- Grafana --",
"enable": true,
"hide": true,
"iconColor": "rgba(0, 211, 255, 1)",
"name": "Annotations \u0026 Alerts",
"type": "dashboard"
}
]
},
"editable": true,
"gnetId": null,
"graphTooltip": 0,
"id": 250,
"links": [],
"panels": [
{
"datasource": "-- Grafana --",
"fieldConfig": {},
"gridPos": {},
"id": 3,
"options": {
"graph": {},
"legend": {
"calcs": [],
"displayMode": "list",
"placement": "bottom"
},
"tooltipOptions": {
"mode": "single"
}
},
"pluginVersion": "7.5.0-pre",
"targets": [
{
"channel": "stream/telegraf/cpu",
"filter": {
"fields": []
},
"queryType": "measurements",
"refId": "A"
}
],
"title": "Panel Title",
"type": "timeseries"
}
],
"schemaVersion": 27,
"style": "dark",
"tags": [],
"templating": {
"list": []
},
"time": {
"from": "now-30s",
"to": "now"
},
"timepicker": {},
"timezone": "",
"title": "fast streaming",
"uid": "K2X7hzwGk",
"version": 8
}

View File

@@ -0,0 +1,33 @@
{
"id": 209,
"title": "ds-variables",
"tags": null,
"templateVars": [
"sqllite"
],
"datasource": [
{
"uid": "sqlite-1",
"type": "sqlite-datasource"
}
],
"panels": [
{
"id": 1,
"title": "usersss!",
"type": "table",
"pluginVersion": "9.1.0-pre",
"datasource": [
{
"uid": "sqlite-1",
"type": "sqlite-datasource"
}
]
}
],
"schemaVersion": 36,
"linkCount": 0,
"timeFrom": "now-6h",
"timeTo": "now",
"timezone": ""
}

View File

@@ -0,0 +1,33 @@
{
"id": 209,
"title": "ds-variables",
"tags": null,
"templateVars": [
"sqllite"
],
"datasource": [
{
"uid": "sqlite-1",
"type": "sqlite-datasource"
}
],
"panels": [
{
"id": 1,
"title": "usersss!",
"type": "table",
"pluginVersion": "9.1.0-pre",
"datasource": [
{
"uid": "sqlite-1",
"type": "sqlite-datasource"
}
]
}
],
"schemaVersion": 36,
"linkCount": 0,
"timeFrom": "now-6h",
"timeTo": "now",
"timezone": ""
}

View File

@@ -0,0 +1,134 @@
{
"annotations": {
"list": [
{
"builtIn": 1,
"datasource": {
"type": "grafana",
"uid": "-- Grafana --"
},
"enable": true,
"hide": true,
"iconColor": "rgba(0, 211, 255, 1)",
"name": "Annotations & Alerts",
"target": {
"limit": 100,
"matchAny": false,
"tags": [],
"type": "dashboard"
},
"type": "dashboard"
}
]
},
"editable": true,
"fiscalYearStartMonth": 0,
"graphTooltip": 0,
"id": 209,
"iteration": 1656508852566,
"links": [],
"liveNow": false,
"panels": [
{
"datasource": {
"type": "sqlite-datasource",
"uid": "$sqllite"
},
"fieldConfig": {
"defaults": {
"custom": {
"align": "auto",
"displayMode": "auto",
"inspect": false
},
"mappings": [],
"thresholds": {
"mode": "absolute",
"steps": [
{
"color": "green",
"value": null
},
{
"color": "red",
"value": 80
}
]
}
},
"overrides": []
},
"gridPos": {
"h": 8,
"w": 12,
"x": 0,
"y": 0
},
"id": 1,
"options": {
"footer": {
"fields": "",
"reducer": [
"sum"
],
"show": false
},
"showHeader": true
},
"pluginVersion": "9.1.0-pre",
"targets": [
{
"datasource": {
"type": "sqlite-datasource",
"uid": "$sqllite"
},
"queryText": "select * from user",
"queryType": "table",
"rawQueryText": "select * from user",
"refId": "A",
"timeColumns": [
"time",
"ts"
]
}
],
"title": "usersss!",
"type": "table"
}
],
"schemaVersion": 36,
"style": "dark",
"tags": [],
"templating": {
"list": [
{
"current": {
"selected": false,
"text": "SQLite Grafana",
"value": "SQLite Grafana"
},
"hide": 0,
"includeAll": false,
"multi": false,
"name": "sqllite",
"options": [],
"query": "sqlite-datasource",
"queryValue": "",
"refresh": 1,
"regex": "",
"skipUrlSync": false,
"type": "datasource"
}
]
},
"time": {
"from": "now-6h",
"to": "now"
},
"timepicker": {},
"timezone": "",
"title": "ds-variables",
"uid": "7BzWolqnk",
"version": 13,
"weekStart": ""
}

View File

@@ -0,0 +1,134 @@
{
"annotations": {
"list": [
{
"builtIn": 1,
"datasource": {
"type": "grafana",
"uid": "-- Grafana --"
},
"enable": true,
"hide": true,
"iconColor": "rgba(0, 211, 255, 1)",
"name": "Annotations & Alerts",
"target": {
"limit": 100,
"matchAny": false,
"tags": [],
"type": "dashboard"
},
"type": "dashboard"
}
]
},
"editable": true,
"fiscalYearStartMonth": 0,
"graphTooltip": 0,
"id": 209,
"iteration": 1656508852566,
"links": [],
"liveNow": false,
"panels": [
{
"datasource": {
"type": "sqlite-datasource",
"uid": "${sqllite}"
},
"fieldConfig": {
"defaults": {
"custom": {
"align": "auto",
"displayMode": "auto",
"inspect": false
},
"mappings": [],
"thresholds": {
"mode": "absolute",
"steps": [
{
"color": "green",
"value": null
},
{
"color": "red",
"value": 80
}
]
}
},
"overrides": []
},
"gridPos": {
"h": 8,
"w": 12,
"x": 0,
"y": 0
},
"id": 1,
"options": {
"footer": {
"fields": "",
"reducer": [
"sum"
],
"show": false
},
"showHeader": true
},
"pluginVersion": "9.1.0-pre",
"targets": [
{
"datasource": {
"type": "sqlite-datasource",
"uid": "${sqllite}"
},
"queryText": "select * from user",
"queryType": "table",
"rawQueryText": "select * from user",
"refId": "A",
"timeColumns": [
"time",
"ts"
]
}
],
"title": "usersss!",
"type": "table"
}
],
"schemaVersion": 36,
"style": "dark",
"tags": [],
"templating": {
"list": [
{
"current": {
"selected": false,
"text": "SQLite Grafana",
"value": "SQLite Grafana"
},
"hide": 0,
"includeAll": false,
"multi": false,
"name": "sqllite",
"options": [],
"query": "sqlite-datasource",
"queryValue": "",
"refresh": 1,
"regex": "",
"skipUrlSync": false,
"type": "datasource"
}
]
},
"time": {
"from": "now-6h",
"to": "now"
},
"timepicker": {},
"timezone": "",
"title": "ds-variables",
"uid": "7BzWolqnk",
"version": 13,
"weekStart": ""
}

View File

@@ -0,0 +1,33 @@
{
"id": 208,
"title": "new-dashboard-var-ds-test",
"tags": null,
"templateVars": [
"dsVariable"
],
"datasource": [
{
"uid": "default.uid",
"type": "default.type"
}
],
"panels": [
{
"id": 2,
"title": "Panel Title",
"type": "table",
"pluginVersion": "9.1.0-pre",
"datasource": [
{
"uid": "default.uid",
"type": "default.type"
}
]
}
],
"schemaVersion": 36,
"linkCount": 0,
"timeFrom": "now-6h",
"timeTo": "now",
"timezone": ""
}

View File

@@ -0,0 +1,133 @@
{
"annotations": {
"list": [
{
"builtIn": 1,
"datasource": {
"type": "grafana",
"uid": "-- Grafana --"
},
"enable": true,
"hide": true,
"iconColor": "rgba(0, 211, 255, 1)",
"name": "Annotations & Alerts",
"target": {
"limit": 100,
"matchAny": false,
"tags": [],
"type": "dashboard"
},
"type": "dashboard"
}
]
},
"editable": true,
"fiscalYearStartMonth": 0,
"graphTooltip": 0,
"id": 208,
"iteration": 1657048248373,
"links": [],
"liveNow": false,
"panels": [
{
"datasource": {
"type": "testdata",
"uid": "${dsVariable}"
},
"fieldConfig": {
"defaults": {
"color": {
"mode": "thresholds"
},
"custom": {
"align": "auto",
"displayMode": "auto",
"inspect": false
},
"mappings": [],
"thresholds": {
"mode": "absolute",
"steps": [
{
"color": "green",
"value": null
},
{
"color": "red",
"value": 80
}
]
}
},
"overrides": []
},
"gridPos": {
"h": 16,
"w": 24,
"x": 0,
"y": 0
},
"id": 2,
"options": {
"footer": {
"fields": "",
"reducer": [
"sum"
],
"show": false
},
"showHeader": true
},
"pluginVersion": "9.1.0-pre",
"repeat": "dsVariable",
"repeatDirection": "h",
"targets": [
{
"datasource": {
"type": "testdata",
"uid": "${dsVariable}"
},
"refId": "A"
}
],
"title": "Panel Title",
"type": "table"
}
],
"refresh": "",
"schemaVersion": 36,
"style": "dark",
"tags": [],
"templating": {
"list": [
{
"current": {
"selected": true,
"text": "default",
"value": "default"
},
"hide": 0,
"includeAll": false,
"multi": false,
"name": "dsVariable",
"options": [],
"query": "testdata",
"queryValue": "",
"refresh": 1,
"regex": "",
"skipUrlSync": false,
"type": "datasource"
}
]
},
"time": {
"from": "now-6h",
"to": "now"
},
"timepicker": {},
"timezone": "",
"title": "new-dashboard-var-ds-test",
"uid": "2HLX_B3nk",
"version": 22,
"weekStart": ""
}

View File

@@ -0,0 +1,236 @@
{
"title": "Panel tests - All panels",
"tags": [
"gdev",
"panel-tests",
"all-panels"
],
"templateVars": [
"query0",
"query1",
"text"
],
"datasource": [
{
"uid": "default.uid",
"type": "default.type"
}
],
"panels": [
{
"id": 34,
"title": "",
"type": "text",
"pluginVersion": "8.1.0-pre",
"datasource": [
{
"uid": "default.uid",
"type": "default.type"
}
]
},
{
"id": 35,
"title": "",
"type": "text",
"pluginVersion": "8.1.0-pre",
"datasource": [
{
"uid": "default.uid",
"type": "default.type"
}
]
},
{
"id": 32,
"title": "Row title",
"type": "row"
},
{
"id": 41,
"title": "State timeline",
"type": "state-timeline",
"datasource": [
{
"uid": "default.uid",
"type": "default.type"
}
]
},
{
"id": 62,
"title": "Size, color mapped to different fields + share view",
"type": "geomap",
"datasource": [
{
"uid": "default.uid",
"type": "default.type"
}
]
},
{
"id": 4,
"title": "Histogram",
"type": "histogram",
"datasource": [
{
"uid": "default.uid",
"type": "default.type"
}
]
},
{
"id": 28,
"title": "Logs",
"type": "logs",
"datasource": [
{
"uid": "default.uid",
"type": "default.type"
}
]
},
{
"id": 8,
"title": "Dashboard list",
"type": "dashlist",
"pluginVersion": "8.1.0-pre",
"datasource": [
{
"uid": "default.uid",
"type": "default.type"
}
]
},
{
"id": 6,
"title": "Alert list",
"type": "alertlist",
"datasource": [
{
"uid": "default.uid",
"type": "default.type"
}
]
},
{
"id": 26,
"title": "Heatmap",
"type": "heatmap",
"datasource": [
{
"uid": "default.uid",
"type": "default.type"
}
]
},
{
"id": 20,
"title": "Bar gauge",
"type": "bargauge",
"pluginVersion": "8.1.0-pre",
"datasource": [
{
"uid": "default.uid",
"type": "default.type"
}
]
},
{
"id": 24,
"title": "Pie chart",
"type": "piechart",
"datasource": [
{
"uid": "default.uid",
"type": "default.type"
}
]
},
{
"id": 18,
"title": "Gauge",
"type": "gauge",
"pluginVersion": "8.1.0-pre",
"datasource": [
{
"uid": "default.uid",
"type": "default.type"
}
]
},
{
"id": 22,
"title": "Tabel",
"type": "table",
"pluginVersion": "8.1.0-pre",
"datasource": [
{
"uid": "default.uid",
"type": "default.type"
}
]
},
{
"id": 10,
"title": "Annotation list",
"type": "annolist",
"datasource": [
{
"uid": "default.uid",
"type": "default.type"
}
]
},
{
"id": 16,
"title": "Stat",
"type": "stat",
"pluginVersion": "8.1.0-pre",
"datasource": [
{
"uid": "default.uid",
"type": "default.type"
}
]
},
{
"id": 2,
"title": "Graph NG",
"type": "timeseries",
"datasource": [
{
"uid": "default.uid",
"type": "default.type"
}
]
},
{
"id": 14,
"title": "Bar chart",
"type": "barchart",
"datasource": [
{
"uid": "default.uid",
"type": "default.type"
}
]
},
{
"id": 12,
"title": "News panel",
"type": "news",
"datasource": [
{
"uid": "default.uid",
"type": "default.type"
}
]
}
],
"schemaVersion": 33,
"linkCount": 2,
"timeFrom": "now-6h",
"timeTo": "now",
"timezone": ""
}

View File

@@ -0,0 +1,121 @@
{
"title": "Panel Tests - shared tooltips",
"tags": [
"gdev",
"panel-tests",
"graph-ng"
],
"datasource": [
{
"uid": "default.uid",
"type": "default.type"
}
],
"panels": [
{
"id": 4,
"title": "two units",
"type": "timeseries",
"pluginVersion": "7.5.0-pre",
"datasource": [
{
"uid": "default.uid",
"type": "default.type"
}
]
},
{
"id": 13,
"title": "Speed vs Temperature (XY)",
"type": "xychart",
"pluginVersion": "7.5.0-pre",
"datasource": [
{
"uid": "default.uid",
"type": "default.type"
}
],
"transformer": [
"seriesToColumns",
"organize"
]
},
{
"id": 2,
"title": "Cursor info",
"type": "debug",
"pluginVersion": "7.5.0-pre",
"datasource": [
{
"uid": "default.uid",
"type": "default.type"
}
]
},
{
"id": 5,
"title": "Only temperature",
"type": "timeseries",
"pluginVersion": "7.5.0-pre",
"datasource": [
{
"uid": "default.uid",
"type": "default.type"
}
]
},
{
"id": 9,
"title": "Only Speed",
"type": "timeseries",
"pluginVersion": "7.5.0-pre",
"datasource": [
{
"uid": "default.uid",
"type": "default.type"
}
]
},
{
"id": 11,
"title": "Panel Title",
"type": "timeseries",
"pluginVersion": "7.5.0-pre",
"datasource": [
{
"uid": "default.uid",
"type": "default.type"
}
]
},
{
"id": 8,
"title": "flot panel (temperature)",
"type": "graph",
"pluginVersion": "7.5.0-pre",
"datasource": [
{
"uid": "default.uid",
"type": "default.type"
}
]
},
{
"id": 10,
"title": "flot panel (no units)",
"type": "graph",
"pluginVersion": "7.5.0-pre",
"datasource": [
{
"uid": "default.uid",
"type": "default.type"
}
]
}
],
"schemaVersion": 28,
"linkCount": 0,
"timeFrom": "2020-09-14T16:13:20.000Z",
"timeTo": "2020-09-15T20:00:00.000Z",
"timezone": ""
}

View File

@@ -0,0 +1,33 @@
{
"id": 209,
"title": "ds-variables",
"tags": null,
"templateVars": [
"sqllite"
],
"datasource": [
{
"uid": "default.uid",
"type": "default.type"
}
],
"panels": [
{
"id": 1,
"title": "usersss!",
"type": "table",
"pluginVersion": "9.1.0-pre",
"datasource": [
{
"uid": "default.uid",
"type": "default.type"
}
]
}
],
"schemaVersion": 36,
"linkCount": 0,
"timeFrom": "now-6h",
"timeTo": "now",
"timezone": ""
}

View File

@@ -0,0 +1,134 @@
{
"annotations": {
"list": [
{
"builtIn": 1,
"datasource": {
"type": "grafana",
"uid": "-- Grafana --"
},
"enable": true,
"hide": true,
"iconColor": "rgba(0, 211, 255, 1)",
"name": "Annotations & Alerts",
"target": {
"limit": 100,
"matchAny": false,
"tags": [],
"type": "dashboard"
},
"type": "dashboard"
}
]
},
"editable": true,
"fiscalYearStartMonth": 0,
"graphTooltip": 0,
"id": 209,
"iteration": 1656513278471,
"links": [],
"liveNow": false,
"panels": [
{
"datasource": {
"type": "sqlite-datasource",
"uid": "${sqllite}"
},
"fieldConfig": {
"defaults": {
"custom": {
"align": "auto",
"displayMode": "auto",
"inspect": false
},
"mappings": [],
"thresholds": {
"mode": "absolute",
"steps": [
{
"color": "green",
"value": null
},
{
"color": "red",
"value": 80
}
]
}
},
"overrides": []
},
"gridPos": {
"h": 8,
"w": 12,
"x": 0,
"y": 0
},
"id": 1,
"options": {
"footer": {
"fields": "",
"reducer": [
"sum"
],
"show": false
},
"showHeader": true
},
"pluginVersion": "9.1.0-pre",
"targets": [
{
"datasource": {
"type": "sqlite-datasource",
"uid": "${sqllite}"
},
"queryText": "select * from user",
"queryType": "table",
"rawQueryText": "select * from user",
"refId": "A",
"timeColumns": [
"time",
"ts"
]
}
],
"title": "usersss!",
"type": "table"
}
],
"schemaVersion": 36,
"style": "dark",
"tags": [],
"templating": {
"list": [
{
"current": {
"selected": false,
"text": "No data sources found",
"value": ""
},
"hide": 0,
"includeAll": false,
"multi": false,
"name": "sqllite",
"options": [],
"query": "sqlite-datasource",
"queryValue": "",
"refresh": 1,
"regex": "asdgasd",
"skipUrlSync": false,
"type": "datasource"
}
]
},
"time": {
"from": "now-6h",
"to": "now"
},
"timepicker": {},
"timezone": "",
"title": "ds-variables",
"uid": "7BzWolqnk",
"version": 14,
"weekStart": ""
}

View File

@@ -0,0 +1,93 @@
{
"name": "Panel Tests - Graph - Gradient Area Fills",
"labels": {
"gdev": "",
"graph": "",
"panel-tests": ""
},
"URL": "/d/graph-gradient-area-fills.json/panel-tests-graph-gradient-area-fills",
"fields": {
"schemaVersion": 18
},
"nested": [
{
"uid": "graph-gradient-area-fills.json#2",
"kind": "panel",
"name": "Req/s",
"URL": "/d/graph-gradient-area-fills.json/panel-tests-graph-gradient-area-fills?viewPanel=2",
"references": [
{
"kind": "ds",
"type": "default.type",
"UID": "default.uid"
},
{
"kind": "panel",
"type": "graph"
}
]
},
{
"uid": "graph-gradient-area-fills.json#11",
"kind": "panel",
"name": "Req/s",
"URL": "/d/graph-gradient-area-fills.json/panel-tests-graph-gradient-area-fills?viewPanel=11",
"references": [
{
"kind": "ds",
"type": "default.type",
"UID": "default.uid"
},
{
"kind": "panel",
"type": "graph"
}
]
},
{
"uid": "graph-gradient-area-fills.json#7",
"kind": "panel",
"name": "Memory",
"URL": "/d/graph-gradient-area-fills.json/panel-tests-graph-gradient-area-fills?viewPanel=7",
"references": [
{
"kind": "ds",
"type": "default.type",
"UID": "default.uid"
},
{
"kind": "panel",
"type": "graph"
}
]
},
{
"uid": "graph-gradient-area-fills.json#10",
"kind": "panel",
"name": "Req/s",
"URL": "/d/graph-gradient-area-fills.json/panel-tests-graph-gradient-area-fills?viewPanel=10",
"references": [
{
"kind": "ds",
"type": "default.type",
"UID": "default.uid"
},
{
"kind": "panel",
"type": "graph"
}
]
}
],
"references": [
{
"kind": "ds",
"type": "default.type",
"UID": "default.uid"
},
{
"kind": "panel",
"type": "graph"
}
]
}

View File

@@ -0,0 +1,181 @@
{
"name": "Panel Tests - shared tooltips",
"labels": {
"gdev": "",
"graph-ng": "",
"panel-tests": ""
},
"URL": "/d/graph-shared-tooltips.json/panel-tests-shared-tooltips",
"fields": {
"schemaVersion": 28
},
"nested": [
{
"uid": "graph-shared-tooltips.json#4",
"kind": "panel",
"name": "two units",
"URL": "/d/graph-shared-tooltips.json/panel-tests-shared-tooltips?viewPanel=4",
"references": [
{
"kind": "ds",
"type": "default.type",
"UID": "default.uid"
},
{
"kind": "panel",
"type": "timeseries"
}
]
},
{
"uid": "graph-shared-tooltips.json#13",
"kind": "panel",
"name": "Speed vs Temperature (XY)",
"URL": "/d/graph-shared-tooltips.json/panel-tests-shared-tooltips?viewPanel=13",
"references": [
{
"kind": "ds",
"type": "default.type",
"UID": "default.uid"
},
{
"kind": "panel",
"type": "xychart"
},
{
"kind": "transform",
"type": "organize"
},
{
"kind": "transform",
"type": "seriesToColumns"
}
]
},
{
"uid": "graph-shared-tooltips.json#2",
"kind": "panel",
"name": "Cursor info",
"URL": "/d/graph-shared-tooltips.json/panel-tests-shared-tooltips?viewPanel=2",
"references": [
{
"kind": "ds",
"type": "default.type",
"UID": "default.uid"
},
{
"kind": "panel",
"type": "debug"
}
]
},
{
"uid": "graph-shared-tooltips.json#5",
"kind": "panel",
"name": "Only temperature",
"URL": "/d/graph-shared-tooltips.json/panel-tests-shared-tooltips?viewPanel=5",
"references": [
{
"kind": "ds",
"type": "default.type",
"UID": "default.uid"
},
{
"kind": "panel",
"type": "timeseries"
}
]
},
{
"uid": "graph-shared-tooltips.json#9",
"kind": "panel",
"name": "Only Speed",
"URL": "/d/graph-shared-tooltips.json/panel-tests-shared-tooltips?viewPanel=9",
"references": [
{
"kind": "ds",
"type": "default.type",
"UID": "default.uid"
},
{
"kind": "panel",
"type": "timeseries"
}
]
},
{
"uid": "graph-shared-tooltips.json#11",
"kind": "panel",
"name": "Panel Title",
"URL": "/d/graph-shared-tooltips.json/panel-tests-shared-tooltips?viewPanel=11",
"references": [
{
"kind": "ds",
"type": "default.type",
"UID": "default.uid"
},
{
"kind": "panel",
"type": "timeseries"
}
]
},
{
"uid": "graph-shared-tooltips.json#8",
"kind": "panel",
"name": "flot panel (temperature)",
"URL": "/d/graph-shared-tooltips.json/panel-tests-shared-tooltips?viewPanel=8",
"references": [
{
"kind": "ds",
"type": "default.type",
"UID": "default.uid"
},
{
"kind": "panel",
"type": "graph"
}
]
},
{
"uid": "graph-shared-tooltips.json#10",
"kind": "panel",
"name": "flot panel (no units)",
"URL": "/d/graph-shared-tooltips.json/panel-tests-shared-tooltips?viewPanel=10",
"references": [
{
"kind": "ds",
"type": "default.type",
"UID": "default.uid"
},
{
"kind": "panel",
"type": "graph"
}
]
}
],
"references": [
{
"kind": "ds",
"type": "default.type",
"UID": "default.uid"
},
{
"kind": "panel",
"type": "debug"
},
{
"kind": "panel",
"type": "graph"
},
{
"kind": "panel",
"type": "timeseries"
},
{
"kind": "panel",
"type": "xychart"
}
]
}

View File

@@ -0,0 +1,110 @@
{
"name": "Panel Tests - Graph Time Regions",
"labels": {
"gdev": "",
"graph": "",
"panel-tests": ""
},
"URL": "/d/graph-time-regions.json/panel-tests-graph-time-regions",
"fields": {
"schemaVersion": 18
},
"nested": [
{
"uid": "graph-time-regions.json#2",
"kind": "panel",
"name": "Business Hours",
"URL": "/d/graph-time-regions.json/panel-tests-graph-time-regions?viewPanel=2",
"references": [
{
"kind": "ds",
"type": "testdata",
"UID": "PD8C576611E62080A"
},
{
"kind": "panel",
"type": "graph"
}
]
},
{
"uid": "graph-time-regions.json#4",
"kind": "panel",
"name": "Sunday's 20-23",
"URL": "/d/graph-time-regions.json/panel-tests-graph-time-regions?viewPanel=4",
"references": [
{
"kind": "ds",
"type": "testdata",
"UID": "PD8C576611E62080A"
},
{
"kind": "panel",
"type": "graph"
}
]
},
{
"uid": "graph-time-regions.json#3",
"kind": "panel",
"name": "Each day of week",
"URL": "/d/graph-time-regions.json/panel-tests-graph-time-regions?viewPanel=3",
"references": [
{
"kind": "ds",
"type": "testdata",
"UID": "PD8C576611E62080A"
},
{
"kind": "panel",
"type": "graph"
}
]
},
{
"uid": "graph-time-regions.json#5",
"kind": "panel",
"name": "05:00",
"URL": "/d/graph-time-regions.json/panel-tests-graph-time-regions?viewPanel=5",
"references": [
{
"kind": "ds",
"type": "testdata",
"UID": "PD8C576611E62080A"
},
{
"kind": "panel",
"type": "graph"
}
]
},
{
"uid": "graph-time-regions.json#7",
"kind": "panel",
"name": "From 22:00 to 00:30 (crossing midnight)",
"URL": "/d/graph-time-regions.json/panel-tests-graph-time-regions?viewPanel=7",
"references": [
{
"kind": "ds",
"type": "testdata",
"UID": "PD8C576611E62080A"
},
{
"kind": "panel",
"type": "graph"
}
]
}
],
"references": [
{
"kind": "ds",
"type": "testdata",
"UID": "PD8C576611E62080A"
},
{
"kind": "panel",
"type": "graph"
}
]
}

View File

@@ -0,0 +1,385 @@
{
"name": "Panel Tests - Graph",
"labels": {
"gdev": "",
"graph": "",
"panel-tests": ""
},
"URL": "/d/graph_tests.json/panel-tests-graph",
"fields": {
"schemaVersion": 16
},
"nested": [
{
"uid": "graph_tests.json#1",
"kind": "panel",
"name": "No Data Points Warning",
"URL": "/d/graph_tests.json/panel-tests-graph?viewPanel=1",
"references": [
{
"kind": "ds",
"type": "testdata",
"UID": "PD8C576611E62080A"
},
{
"kind": "panel",
"type": "graph"
}
]
},
{
"uid": "graph_tests.json#2",
"kind": "panel",
"name": "Datapoints Outside Range Warning",
"URL": "/d/graph_tests.json/panel-tests-graph?viewPanel=2",
"references": [
{
"kind": "ds",
"type": "testdata",
"UID": "PD8C576611E62080A"
},
{
"kind": "panel",
"type": "graph"
}
]
},
{
"uid": "graph_tests.json#3",
"kind": "panel",
"name": "Random walk series",
"URL": "/d/graph_tests.json/panel-tests-graph?viewPanel=3",
"references": [
{
"kind": "ds",
"type": "testdata",
"UID": "PD8C576611E62080A"
},
{
"kind": "panel",
"type": "graph"
}
]
},
{
"uid": "graph_tests.json#4",
"kind": "panel",
"name": "Millisecond res x-axis and tooltip",
"URL": "/d/graph_tests.json/panel-tests-graph?viewPanel=4",
"references": [
{
"kind": "ds",
"type": "testdata",
"UID": "PD8C576611E62080A"
},
{
"kind": "panel",
"type": "graph"
}
]
},
{
"uid": "graph_tests.json#6",
"kind": "panel",
"URL": "/d/graph_tests.json/panel-tests-graph?viewPanel=6",
"references": [
{
"kind": "ds",
"type": "default.type",
"UID": "default.uid"
},
{
"kind": "panel",
"type": "text"
}
]
},
{
"uid": "graph_tests.json#5",
"kind": "panel",
"name": "2 yaxis and axis labels",
"URL": "/d/graph_tests.json/panel-tests-graph?viewPanel=5",
"references": [
{
"kind": "ds",
"type": "testdata",
"UID": "PD8C576611E62080A"
},
{
"kind": "panel",
"type": "graph"
}
]
},
{
"uid": "graph_tests.json#7",
"kind": "panel",
"URL": "/d/graph_tests.json/panel-tests-graph?viewPanel=7",
"references": [
{
"kind": "ds",
"type": "default.type",
"UID": "default.uid"
},
{
"kind": "panel",
"type": "text"
}
]
},
{
"uid": "graph_tests.json#8",
"kind": "panel",
"name": "null value connected",
"URL": "/d/graph_tests.json/panel-tests-graph?viewPanel=8",
"references": [
{
"kind": "ds",
"type": "testdata",
"UID": "PD8C576611E62080A"
},
{
"kind": "panel",
"type": "graph"
}
]
},
{
"uid": "graph_tests.json#10",
"kind": "panel",
"name": "null value null as zero",
"URL": "/d/graph_tests.json/panel-tests-graph?viewPanel=10",
"references": [
{
"kind": "ds",
"type": "testdata",
"UID": "PD8C576611E62080A"
},
{
"kind": "panel",
"type": "graph"
}
]
},
{
"uid": "graph_tests.json#13",
"kind": "panel",
"URL": "/d/graph_tests.json/panel-tests-graph?viewPanel=13",
"references": [
{
"kind": "ds",
"type": "default.type",
"UID": "default.uid"
},
{
"kind": "panel",
"type": "text"
}
]
},
{
"uid": "graph_tests.json#9",
"kind": "panel",
"name": "Stacking value ontop of nulls",
"URL": "/d/graph_tests.json/panel-tests-graph?viewPanel=9",
"references": [
{
"kind": "ds",
"type": "testdata",
"UID": "PD8C576611E62080A"
},
{
"kind": "panel",
"type": "graph"
}
]
},
{
"uid": "graph_tests.json#14",
"kind": "panel",
"URL": "/d/graph_tests.json/panel-tests-graph?viewPanel=14",
"references": [
{
"kind": "ds",
"type": "default.type",
"UID": "default.uid"
},
{
"kind": "panel",
"type": "text"
}
]
},
{
"uid": "graph_tests.json#12",
"kind": "panel",
"name": "Stacking all series null segment",
"URL": "/d/graph_tests.json/panel-tests-graph?viewPanel=12",
"references": [
{
"kind": "ds",
"type": "testdata",
"UID": "PD8C576611E62080A"
},
{
"kind": "panel",
"type": "graph"
}
]
},
{
"uid": "graph_tests.json#15",
"kind": "panel",
"URL": "/d/graph_tests.json/panel-tests-graph?viewPanel=15",
"references": [
{
"kind": "ds",
"type": "default.type",
"UID": "default.uid"
},
{
"kind": "panel",
"type": "text"
}
]
},
{
"uid": "graph_tests.json#21",
"kind": "panel",
"name": "Null between points",
"URL": "/d/graph_tests.json/panel-tests-graph?viewPanel=21",
"references": [
{
"kind": "ds",
"type": "testdata",
"UID": "PD8C576611E62080A"
},
{
"kind": "panel",
"type": "graph"
}
]
},
{
"uid": "graph_tests.json#22",
"kind": "panel",
"URL": "/d/graph_tests.json/panel-tests-graph?viewPanel=22",
"references": [
{
"kind": "ds",
"type": "default.type",
"UID": "default.uid"
},
{
"kind": "panel",
"type": "text"
}
]
},
{
"uid": "graph_tests.json#20",
"kind": "panel",
"name": "Legend Table Single Series Should Take Minimum Height",
"URL": "/d/graph_tests.json/panel-tests-graph?viewPanel=20",
"references": [
{
"kind": "ds",
"type": "testdata",
"UID": "PD8C576611E62080A"
},
{
"kind": "panel",
"type": "graph"
}
]
},
{
"uid": "graph_tests.json#16",
"kind": "panel",
"name": "Legend Table No Scroll Visible",
"URL": "/d/graph_tests.json/panel-tests-graph?viewPanel=16",
"references": [
{
"kind": "ds",
"type": "testdata",
"UID": "PD8C576611E62080A"
},
{
"kind": "panel",
"type": "graph"
}
]
},
{
"uid": "graph_tests.json#17",
"kind": "panel",
"name": "Legend Table Should Scroll",
"URL": "/d/graph_tests.json/panel-tests-graph?viewPanel=17",
"references": [
{
"kind": "ds",
"type": "testdata",
"UID": "PD8C576611E62080A"
},
{
"kind": "panel",
"type": "graph"
}
]
},
{
"uid": "graph_tests.json#18",
"kind": "panel",
"name": "Legend Table No Scroll Visible",
"URL": "/d/graph_tests.json/panel-tests-graph?viewPanel=18",
"references": [
{
"kind": "ds",
"type": "testdata",
"UID": "PD8C576611E62080A"
},
{
"kind": "panel",
"type": "graph"
}
]
},
{
"uid": "graph_tests.json#19",
"kind": "panel",
"name": "Legend Table No Scroll Visible",
"URL": "/d/graph_tests.json/panel-tests-graph?viewPanel=19",
"references": [
{
"kind": "ds",
"type": "testdata",
"UID": "PD8C576611E62080A"
},
{
"kind": "panel",
"type": "graph"
}
]
}
],
"references": [
{
"kind": "ds",
"type": "default.type",
"UID": "default.uid"
},
{
"kind": "ds",
"type": "testdata",
"UID": "PD8C576611E62080A"
},
{
"kind": "panel",
"type": "graph"
},
{
"kind": "panel",
"type": "text"
}
]
}

View File

@@ -0,0 +1,177 @@
{
"name": "Panel Tests - Graph - Y axis ticks",
"labels": {
"gdev": "",
"panel-tests": ""
},
"URL": "/d/graph_y_axis.json/panel-tests-graph-y-axis-ticks",
"fields": {
"schemaVersion": 19
},
"nested": [
{
"uid": "graph_y_axis.json#7",
"kind": "panel",
"name": "Data from 0 - 10K (unit short)",
"URL": "/d/graph_y_axis.json/panel-tests-graph-y-axis-ticks?viewPanel=7",
"references": [
{
"kind": "ds",
"type": "default.type",
"UID": "default.uid"
},
{
"kind": "panel",
"type": "graph"
}
]
},
{
"uid": "graph_y_axis.json#5",
"kind": "panel",
"name": "Data from 0 - 10K (unit bytes metric)",
"URL": "/d/graph_y_axis.json/panel-tests-graph-y-axis-ticks?viewPanel=5",
"references": [
{
"kind": "ds",
"type": "default.type",
"UID": "default.uid"
},
{
"kind": "panel",
"type": "graph"
}
]
},
{
"uid": "graph_y_axis.json#4",
"kind": "panel",
"name": "Data from 0 - 10K (unit bytes IEC)",
"URL": "/d/graph_y_axis.json/panel-tests-graph-y-axis-ticks?viewPanel=4",
"references": [
{
"kind": "ds",
"type": "default.type",
"UID": "default.uid"
},
{
"kind": "panel",
"type": "graph"
}
]
},
{
"uid": "graph_y_axis.json#2",
"kind": "panel",
"name": "Data from 0 - 10K (unit short)",
"URL": "/d/graph_y_axis.json/panel-tests-graph-y-axis-ticks?viewPanel=2",
"references": [
{
"kind": "ds",
"type": "default.type",
"UID": "default.uid"
},
{
"kind": "panel",
"type": "graph"
}
]
},
{
"uid": "graph_y_axis.json#3",
"kind": "panel",
"name": "Data from 0.0002 - 0.001 (unit short)",
"URL": "/d/graph_y_axis.json/panel-tests-graph-y-axis-ticks?viewPanel=3",
"references": [
{
"kind": "ds",
"type": "default.type",
"UID": "default.uid"
},
{
"kind": "panel",
"type": "graph"
}
]
},
{
"uid": "graph_y_axis.json#6",
"kind": "panel",
"name": "Data from 12000 - 30000 (unit ms)",
"URL": "/d/graph_y_axis.json/panel-tests-graph-y-axis-ticks?viewPanel=6",
"references": [
{
"kind": "ds",
"type": "default.type",
"UID": "default.uid"
},
{
"kind": "panel",
"type": "graph"
}
]
},
{
"uid": "graph_y_axis.json#9",
"kind": "panel",
"name": "Data from 0 - 1B (unit short)",
"URL": "/d/graph_y_axis.json/panel-tests-graph-y-axis-ticks?viewPanel=9",
"references": [
{
"kind": "ds",
"type": "default.type",
"UID": "default.uid"
},
{
"kind": "panel",
"type": "graph"
}
]
},
{
"uid": "graph_y_axis.json#10",
"kind": "panel",
"name": "Data from 0 - 1B (unit bytes)",
"URL": "/d/graph_y_axis.json/panel-tests-graph-y-axis-ticks?viewPanel=10",
"references": [
{
"kind": "ds",
"type": "default.type",
"UID": "default.uid"
},
{
"kind": "panel",
"type": "graph"
}
]
},
{
"uid": "graph_y_axis.json#8",
"kind": "panel",
"name": "Data from 12000 - 30000 (unit ms)",
"URL": "/d/graph_y_axis.json/panel-tests-graph-y-axis-ticks?viewPanel=8",
"references": [
{
"kind": "ds",
"type": "default.type",
"UID": "default.uid"
},
{
"kind": "panel",
"type": "graph"
}
]
}
],
"references": [
{
"kind": "ds",
"type": "default.type",
"UID": "default.uid"
},
{
"kind": "panel",
"type": "graph"
}
]
}

View File

@@ -0,0 +1,49 @@
{
"id": 220,
"title": "new-dashboard-mixed",
"tags": null,
"templateVars": [
"dsVariable"
],
"datasource": [
{
"uid": "default.uid",
"type": "default.type"
},
{
"uid": "PD8C576611E62080A",
"type": "testdata"
},
{
"uid": "P8045C56BDA891CB2",
"type": "cloudwatch"
}
],
"panels": [
{
"id": 2,
"title": "Panel Title",
"type": "table",
"pluginVersion": "9.1.0-pre",
"datasource": [
{
"uid": "default.uid",
"type": "default.type"
},
{
"uid": "PD8C576611E62080A",
"type": "testdata"
},
{
"uid": "P8045C56BDA891CB2",
"type": "cloudwatch"
}
]
}
],
"schemaVersion": 36,
"linkCount": 0,
"timeFrom": "now-6h",
"timeTo": "now",
"timezone": ""
}

View File

@@ -0,0 +1,139 @@
{
"editable": true,
"fiscalYearStartMonth": 0,
"graphTooltip": 0,
"id": 220,
"iteration": 1658225888559,
"links": [],
"liveNow": false,
"panels": [
{
"datasource": {
"type": "datasource",
"uid": "-- Mixed --"
},
"fieldConfig": {
"defaults": {
"color": {
"mode": "thresholds"
},
"custom": {
"align": "auto",
"displayMode": "auto",
"inspect": false
},
"mappings": [],
"thresholds": {
"mode": "absolute",
"steps": [
{
"color": "green",
"value": null
},
{
"color": "red",
"value": 80
}
]
}
},
"overrides": []
},
"gridPos": {
"h": 16,
"w": 12,
"x": 0,
"y": 0
},
"id": 2,
"options": {
"footer": {
"fields": "",
"reducer": [
"sum"
],
"show": false
},
"showHeader": true
},
"pluginVersion": "9.1.0-pre",
"repeat": "dsVariable",
"repeatDirection": "h",
"targets": [
{
"datasource": {
"type": "testdata",
"uid": "${dsVariable}"
},
"refId": "A"
},
{
"datasource": {
"type": "cloudwatch",
"uid": "P8045C56BDA891CB2"
},
"dimensions": {},
"expression": "",
"hide": false,
"id": "",
"label": "",
"matchExact": true,
"metricEditorMode": 0,
"metricName": "",
"metricQueryType": 0,
"namespace": "",
"period": "",
"queryMode": "Metrics",
"refId": "B",
"region": "default",
"sqlExpression": "",
"statistic": "Average"
}
],
"title": "Panel Title",
"type": "table"
}
],
"refresh": "",
"schemaVersion": 36,
"style": "dark",
"tags": [],
"templating": {
"list": [
{
"current": {
"selected": true,
"text": [
"gdev-testdata",
"default"
],
"value": [
"gdev-testdata",
"default"
]
},
"hide": 0,
"includeAll": false,
"multi": false,
"name": "dsVariable",
"options": [],
"query": "testdata",
"queryValue": "",
"refresh": 1,
"regex": "",
"skipUrlSync": false,
"type": "datasource"
}
]
},
"time": {
"from": "now-6h",
"to": "now"
},
"timepicker": {},
"timezone": "",
"title": "new-dashboard-mixed",
"uid": "NV5PypgVz",
"version": 2,
"weekStart": ""
}

View File

@@ -0,0 +1,54 @@
{
"title": "Datasource tests - Shared Queries",
"tags": [
"gdev",
"datasource-test"
],
"datasource": [
{
"uid": "default.uid",
"type": "default.type"
}
],
"panels": [
{
"id": 2,
"title": "Raw Data Graph",
"type": "graph",
"datasource": [
{
"uid": "default.uid",
"type": "default.type"
}
]
},
{
"id": 4,
"title": "Last non-null",
"type": "gauge",
"pluginVersion": "6.4.0-pre"
},
{
"id": 6,
"title": "min",
"type": "gauge",
"pluginVersion": "6.4.0-pre"
},
{
"id": 5,
"title": "Max",
"type": "bargauge",
"pluginVersion": "6.4.0-pre"
},
{
"id": 8,
"title": "Panel Title",
"type": "table"
}
],
"schemaVersion": 19,
"linkCount": 0,
"timeFrom": "now-6h",
"timeTo": "now",
"timezone": ""
}

View File

@@ -0,0 +1,346 @@
{
"annotations": {
"list": [
{
"builtIn": 1,
"datasource": "-- Grafana --",
"enable": true,
"hide": true,
"iconColor": "rgba(0, 211, 255, 1)",
"name": "Annotations \u0026 Alerts",
"type": "dashboard"
}
]
},
"editable": true,
"gnetId": null,
"graphTooltip": 0,
"links": [],
"panels": [
{
"aliasColors": {},
"bars": false,
"dashLength": 10,
"dashes": false,
"fill": 0,
"fillGradient": 6,
"gridPos": {
"h": 15,
"w": 12,
"x": 0,
"y": 0
},
"id": 2,
"legend": {
"avg": false,
"current": false,
"max": false,
"min": false,
"show": true,
"total": false,
"values": false
},
"lines": true,
"linewidth": 1,
"nullPointMode": "null",
"options": {
"dataLinks": []
},
"percentage": false,
"pointradius": 2,
"points": true,
"renderer": "flot",
"seriesOverrides": [],
"spaceLength": 10,
"stack": false,
"steppedLine": false,
"targets": [
{
"refId": "A",
"scenarioId": "csv_metric_values",
"stringInput": "1,20,90,30,5,0,100"
},
{
"refId": "B",
"scenarioId": "csv_metric_values",
"stringInput": "1,20,90,30,5,-100,200"
},
{
"refId": "C",
"scenarioId": "csv_metric_values",
"stringInput": "2.5,3.5,4.5,10.5,20.5,21.5,19.5"
}
],
"thresholds": [],
"timeFrom": null,
"timeRegions": [],
"timeShift": null,
"title": "Raw Data Graph",
"tooltip": {
"shared": true,
"sort": 0,
"value_type": "individual"
},
"type": "graph",
"xaxis": {
"buckets": null,
"mode": "time",
"name": null,
"show": true,
"values": []
},
"yaxes": [
{
"format": "short",
"label": null,
"logBase": 1,
"max": null,
"min": null,
"show": true
},
{
"format": "short",
"label": null,
"logBase": 1,
"max": null,
"min": null,
"show": true
}
],
"yaxis": {
"align": false,
"alignLevel": null
}
},
{
"datasource": "-- Dashboard --",
"gridPos": {
"h": 5,
"w": 12,
"x": 12,
"y": 0
},
"id": 4,
"options": {
"fieldOptions": {
"calcs": [
"lastNotNull"
],
"defaults": {
"mappings": [],
"max": 100,
"min": 0,
"thresholds": [
{
"color": "green",
"value": null
},
{
"color": "red",
"value": 80
}
]
},
"override": {},
"values": false
},
"orientation": "auto",
"showThresholdLabels": false,
"showThresholdMarkers": true
},
"pluginVersion": "6.4.0-pre",
"targets": [
{
"panelId": 2,
"refId": "A"
}
],
"timeFrom": null,
"timeShift": null,
"title": "Last non-null",
"type": "gauge"
},
{
"datasource": "-- Dashboard --",
"gridPos": {
"h": 5,
"w": 12,
"x": 12,
"y": 5
},
"id": 6,
"options": {
"fieldOptions": {
"calcs": [
"min"
],
"defaults": {
"mappings": [],
"max": 100,
"min": 0,
"thresholds": [
{
"color": "green",
"value": null
},
{
"color": "red",
"value": 80
}
]
},
"override": {},
"values": false
},
"orientation": "auto",
"showThresholdLabels": false,
"showThresholdMarkers": true
},
"pluginVersion": "6.4.0-pre",
"targets": [
{
"panelId": 2,
"refId": "A"
}
],
"timeFrom": null,
"timeShift": null,
"title": "min",
"type": "gauge"
},
{
"datasource": "-- Dashboard --",
"gridPos": {
"h": 5,
"w": 12,
"x": 12,
"y": 10
},
"id": 5,
"options": {
"displayMode": "basic",
"fieldOptions": {
"calcs": [
"max"
],
"defaults": {
"mappings": [],
"max": 200,
"min": 0,
"thresholds": [
{
"color": "green",
"value": null
},
{
"color": "blue",
"value": 40
},
{
"color": "red",
"value": 120
}
]
},
"override": {},
"values": false
},
"orientation": "vertical"
},
"pluginVersion": "6.4.0-pre",
"targets": [
{
"panelId": 2,
"refId": "A"
}
],
"timeFrom": null,
"timeShift": null,
"title": "Max",
"type": "bargauge"
},
{
"columns": [],
"datasource": "-- Dashboard --",
"fontSize": "100%",
"gridPos": {
"h": 10,
"w": 24,
"x": 0,
"y": 15
},
"id": 8,
"options": {},
"pageSize": null,
"showHeader": true,
"sort": {
"col": 0,
"desc": true
},
"styles": [
{
"alias": "Time",
"dateFormat": "YYYY-MM-DD HH:mm:ss",
"pattern": "Time",
"type": "date"
},
{
"alias": "",
"colorMode": null,
"colors": [
"rgba(245, 54, 54, 0.9)",
"rgba(237, 129, 40, 0.89)",
"rgba(50, 172, 45, 0.97)"
],
"decimals": 2,
"pattern": "/.*/",
"thresholds": [],
"type": "number",
"unit": "short"
}
],
"targets": [
{
"panelId": 2,
"refId": "A"
}
],
"timeFrom": null,
"timeShift": null,
"title": "Panel Title",
"transform": "timeseries_to_columns",
"type": "table"
}
],
"schemaVersion": 19,
"style": "dark",
"tags": [
"gdev",
"datasource-test"
],
"templating": {
"list": []
},
"time": {
"from": "now-6h",
"to": "now"
},
"timepicker": {
"refresh_intervals": [
"5s",
"10s",
"30s",
"1m",
"5m",
"15m",
"30m",
"1h",
"2h",
"1d"
]
},
"timezone": "",
"title": "Datasource tests - Shared Queries",
"uid": "ZqZnVvFZz",
"version": 1
}

View File

@@ -0,0 +1,41 @@
{
"id": 209,
"title": "ds-variables",
"tags": null,
"templateVars": [
"sqllite"
],
"datasource": [
{
"uid": "sqlite-2",
"type": "sqlite-datasource"
},
{
"uid": "sqlite-1",
"type": "sqlite-datasource"
}
],
"panels": [
{
"id": 1,
"title": "usersss!",
"type": "table",
"pluginVersion": "9.1.0-pre",
"datasource": [
{
"uid": "sqlite-2",
"type": "sqlite-datasource"
},
{
"uid": "sqlite-1",
"type": "sqlite-datasource"
}
]
}
],
"schemaVersion": 36,
"linkCount": 0,
"timeFrom": "now-6h",
"timeTo": "now",
"timezone": ""
}

View File

@@ -0,0 +1,41 @@
{
"id": 208,
"title": "new-dashboard-var-ds-test",
"tags": null,
"templateVars": [
"dsVariable"
],
"datasource": [
{
"uid": "default.uid",
"type": "default.type"
},
{
"uid": "PD8C576611E62080A",
"type": "testdata"
}
],
"panels": [
{
"id": 2,
"title": "Panel Title",
"type": "table",
"pluginVersion": "9.1.0-pre",
"datasource": [
{
"uid": "default.uid",
"type": "default.type"
},
{
"uid": "PD8C576611E62080A",
"type": "testdata"
}
]
}
],
"schemaVersion": 36,
"linkCount": 0,
"timeFrom": "now-6h",
"timeTo": "now",
"timezone": ""
}

View File

@@ -0,0 +1,139 @@
{
"annotations": {
"list": [
{
"builtIn": 1,
"datasource": {
"type": "grafana",
"uid": "-- Grafana --"
},
"enable": true,
"hide": true,
"iconColor": "rgba(0, 211, 255, 1)",
"name": "Annotations & Alerts",
"target": {
"limit": 100,
"matchAny": false,
"tags": [],
"type": "dashboard"
},
"type": "dashboard"
}
]
},
"editable": true,
"fiscalYearStartMonth": 0,
"graphTooltip": 0,
"id": 208,
"iteration": 1657048248365,
"links": [],
"liveNow": false,
"panels": [
{
"datasource": {
"type": "testdata",
"uid": "${dsVariable}"
},
"fieldConfig": {
"defaults": {
"color": {
"mode": "thresholds"
},
"custom": {
"align": "auto",
"displayMode": "auto",
"inspect": false
},
"mappings": [],
"thresholds": {
"mode": "absolute",
"steps": [
{
"color": "green",
"value": null
},
{
"color": "red",
"value": 80
}
]
}
},
"overrides": []
},
"gridPos": {
"h": 16,
"w": 12,
"x": 0,
"y": 0
},
"id": 2,
"options": {
"footer": {
"fields": "",
"reducer": [
"sum"
],
"show": false
},
"showHeader": true
},
"pluginVersion": "9.1.0-pre",
"repeat": "dsVariable",
"repeatDirection": "h",
"targets": [
{
"datasource": {
"type": "testdata",
"uid": "${dsVariable}"
},
"refId": "A"
}
],
"title": "Panel Title",
"type": "table"
}
],
"refresh": "",
"schemaVersion": 36,
"style": "dark",
"tags": [],
"templating": {
"list": [
{
"current": {
"selected": true,
"text": [
"gdev-testdata",
"default"
],
"value": [
"gdev-testdata",
"default"
]
},
"hide": 0,
"includeAll": false,
"multi": true,
"name": "dsVariable",
"options": [],
"query": "testdata",
"queryValue": "",
"refresh": 1,
"regex": "",
"skipUrlSync": false,
"type": "datasource"
}
]
},
"time": {
"from": "now-6h",
"to": "now"
},
"timepicker": {},
"timezone": "",
"title": "new-dashboard-var-ds-test",
"uid": "2HLX_B3nk",
"version": 19,
"weekStart": ""
}

View File

@@ -0,0 +1,143 @@
{
"annotations": {
"list": [
{
"builtIn": 1,
"datasource": {
"type": "grafana",
"uid": "-- Grafana --"
},
"enable": true,
"hide": true,
"iconColor": "rgba(0, 211, 255, 1)",
"name": "Annotations & Alerts",
"target": {
"limit": 100,
"matchAny": false,
"tags": [],
"type": "dashboard"
},
"type": "dashboard"
}
]
},
"editable": true,
"fiscalYearStartMonth": 0,
"graphTooltip": 0,
"id": 209,
"iteration": 1656507534777,
"links": [],
"liveNow": false,
"panels": [
{
"datasource": {
"type": "sqlite-datasource",
"uid": "${sqllite}"
},
"fieldConfig": {
"defaults": {
"custom": {
"align": "auto",
"displayMode": "auto",
"inspect": false
},
"mappings": [],
"thresholds": {
"mode": "absolute",
"steps": [
{
"color": "green",
"value": null
},
{
"color": "red",
"value": 80
}
]
}
},
"overrides": []
},
"gridPos": {
"h": 8,
"w": 12,
"x": 0,
"y": 0
},
"id": 1,
"options": {
"footer": {
"fields": "",
"reducer": [
"sum"
],
"show": false
},
"showHeader": true
},
"pluginVersion": "9.1.0-pre",
"repeat": "sqllite",
"repeatDirection": "h",
"targets": [
{
"datasource": {
"type": "sqlite-datasource",
"uid": "${sqllite}"
},
"key": "Q-7ab4ab1a-3c70-41f4-9a45-19919e1c2193-0",
"queryText": "select * from user",
"queryType": "table",
"rawQueryText": "select * from user",
"refId": "A",
"timeColumns": [
"time",
"ts"
]
}
],
"title": "usersss!",
"type": "table"
}
],
"schemaVersion": 36,
"style": "dark",
"tags": [],
"templating": {
"list": [
{
"current": {
"selected": false,
"text": [
"SQLite Grafana",
"SQLite Grafana2"
],
"value": [
"SQLite Grafana",
"SQLite Grafana2"
]
},
"hide": 0,
"includeAll": false,
"multi": true,
"name": "sqllite",
"options": [],
"query": "sqlite-datasource",
"queryValue": "",
"refresh": 1,
"regex": "",
"skipUrlSync": false,
"type": "datasource"
}
]
},
"time": {
"from": "now-6h",
"to": "now"
},
"timepicker": {},
"timezone": "",
"title": "ds-variables",
"uid": "7BzWolqnk",
"version": 8,
"weekStart": ""
}

View File

@@ -0,0 +1,77 @@
{
"id": 221,
"title": "special ds",
"tags": null,
"datasource": [
{
"uid": "grafana",
"type": "datasource"
},
{
"uid": "dgd92lq7k",
"type": "frser-sqlite-datasource"
},
{
"uid": "PD8C576611E62080A",
"type": "testdata"
}
],
"panels": [
{
"id": 10,
"title": "mixed ds with grafana ds",
"type": "timeseries",
"datasource": [
{
"uid": "grafana",
"type": "datasource"
},
{
"uid": "dgd92lq7k",
"type": "frser-sqlite-datasource"
}
]
},
{
"id": 8,
"title": "Row title",
"type": "row"
},
{
"id": 4,
"title": "dashboard ds",
"type": "timeseries"
},
{
"id": 6,
"title": "grafana ds",
"type": "timeseries",
"datasource": [
{
"uid": "grafana",
"type": "datasource"
}
]
},
{
"id": 2,
"title": "mixed ds",
"type": "timeseries",
"datasource": [
{
"uid": "dgd92lq7k",
"type": "frser-sqlite-datasource"
},
{
"uid": "PD8C576611E62080A",
"type": "testdata"
}
]
}
],
"schemaVersion": 36,
"linkCount": 0,
"timeFrom": "now-6h",
"timeTo": "now",
"timezone": ""
}

View File

@@ -0,0 +1,310 @@
{
"editable": true,
"fiscalYearStartMonth": 0,
"graphTooltip": 0,
"id": 221,
"links": [],
"liveNow": false,
"panels": [
{
"datasource": {
"type": "datasource",
"uid": "-- Mixed --"
},
"gridPos": {
"h": 8,
"w": 12,
"x": 0,
"y": 0
},
"id": 10,
"options": {
"legend": {
"calcs": [],
"displayMode": "list",
"placement": "bottom"
},
"tooltip": {
"mode": "single",
"sort": "none"
}
},
"targets": [
{
"datasource": {
"type": "datasource",
"uid": "grafana"
},
"refId": "A"
},
{
"datasource": {
"type": "frser-sqlite-datasource",
"uid": "dgd92lq7k"
},
"hide": false,
"queryText": "\n SELECT CAST(strftime('%s', 'now', '-1 minute') as INTEGER) as time, 4 as value\n WHERE time >= 1234 and time < 134567\n ",
"queryType": "table",
"rawQueryText": "SELECT CAST(strftime('%s', 'now', '-1 minute') as INTEGER) as time, 4 as value \nWHERE time >= $__from / 1000 and time < $__to / 1000",
"refId": "B",
"timeColumns": [
"time",
"ts"
]
}
],
"title": "mixed ds with grafana ds",
"type": "timeseries"
},
{
"gridPos": {
"h": 1,
"w": 24,
"x": 0,
"y": 8
},
"id": 8,
"title": "Row title",
"type": "row"
},
{
"datasource": {
"type": "datasource",
"uid": "-- Dashboard --"
},
"fieldConfig": {
"defaults": {
"color": {
"mode": "palette-classic"
},
"custom": {
"axisColorMode": "text",
"axisLabel": "",
"axisPlacement": "auto",
"barAlignment": 0,
"drawStyle": "line",
"fillOpacity": 0,
"gradientMode": "none",
"hideFrom": {
"legend": false,
"tooltip": false,
"viz": false
},
"lineInterpolation": "linear",
"lineWidth": 1,
"pointSize": 5,
"scaleDistribution": {
"type": "linear"
},
"showPoints": "auto",
"spanNulls": false,
"stacking": {
"group": "A",
"mode": "none"
},
"thresholdsStyle": {
"mode": "off"
}
},
"mappings": [],
"thresholds": {
"mode": "absolute",
"steps": [
{
"color": "green",
"value": null
},
{
"color": "red",
"value": 80
}
]
}
},
"overrides": []
},
"gridPos": {
"h": 8,
"w": 12,
"x": 0,
"y": 9
},
"id": 4,
"options": {
"legend": {
"calcs": [],
"displayMode": "list",
"placement": "bottom"
},
"tooltip": {
"mode": "single",
"sort": "none"
}
},
"targets": [
{
"datasource": {
"type": "datasource",
"uid": "-- Dashboard --"
},
"panelId": 2,
"refId": "A"
}
],
"title": "dashboard ds",
"type": "timeseries"
},
{
"datasource": {
"type": "grafana",
"uid": "grafana"
},
"fieldConfig": {
"defaults": {
"color": {
"mode": "palette-classic"
},
"custom": {
"axisColorMode": "text",
"axisLabel": "",
"axisPlacement": "auto",
"barAlignment": 0,
"drawStyle": "line",
"fillOpacity": 0,
"gradientMode": "none",
"hideFrom": {
"legend": false,
"tooltip": false,
"viz": false
},
"lineInterpolation": "linear",
"lineWidth": 1,
"pointSize": 5,
"scaleDistribution": {
"type": "linear"
},
"showPoints": "auto",
"spanNulls": false,
"stacking": {
"group": "A",
"mode": "none"
},
"thresholdsStyle": {
"mode": "off"
}
},
"mappings": [],
"thresholds": {
"mode": "absolute",
"steps": [
{
"color": "green",
"value": null
},
{
"color": "red",
"value": 80
}
]
}
},
"overrides": []
},
"gridPos": {
"h": 8,
"w": 12,
"x": 12,
"y": 9
},
"id": 6,
"options": {
"legend": {
"calcs": [],
"displayMode": "list",
"placement": "bottom"
},
"tooltip": {
"mode": "single",
"sort": "none"
}
},
"targets": [
{
"datasource": {
"type": "datasource",
"uid": "grafana"
},
"refId": "A"
}
],
"title": "grafana ds",
"type": "timeseries"
},
{
"datasource": {
"type": "datasource",
"uid": "-- Mixed --"
},
"gridPos": {
"h": 9,
"w": 12,
"x": 0,
"y": 17
},
"id": 2,
"options": {
"legend": {
"calcs": [],
"displayMode": "list",
"placement": "bottom"
},
"tooltip": {
"mode": "single",
"sort": "none"
}
},
"targets": [
{
"datasource": {
"type": "testdata",
"uid": "PD8C576611E62080A"
},
"refId": "A"
},
{
"datasource": {
"type": "frser-sqlite-datasource",
"uid": "dgd92lq7k"
},
"hide": false,
"queryText": "\n SELECT CAST(strftime('%s', 'now', '-1 minute') as INTEGER) as time, 4 as value\n WHERE time >= 1234 and time < 134567\n ",
"queryType": "table",
"rawQueryText": "SELECT CAST(strftime('%s', 'now', '-1 minute') as INTEGER) as time, 4 as value \nWHERE time >= $__from / 1000 and time < $__to / 1000",
"refId": "B",
"timeColumns": [
"time",
"ts"
]
}
],
"title": "mixed ds",
"type": "timeseries"
}
],
"schemaVersion": 36,
"style": "dark",
"tags": [],
"templating": {
"list": []
},
"time": {
"from": "now-6h",
"to": "now"
},
"timepicker": {},
"timezone": "",
"title": "special ds",
"uid": "mocpwtR4k",
"version": 1,
"weekStart": ""
}

View File

@@ -0,0 +1,33 @@
{
"id": 209,
"title": "ds-variables",
"tags": null,
"templateVars": [
"sqllite"
],
"datasource": [
{
"uid": "sqlite-1",
"type": "sqlite-datasource"
}
],
"panels": [
{
"id": 1,
"title": "usersss!",
"type": "table",
"pluginVersion": "9.1.0-pre",
"datasource": [
{
"uid": "sqlite-1",
"type": "sqlite-datasource"
}
]
}
],
"schemaVersion": 36,
"linkCount": 0,
"timeFrom": "now-6h",
"timeTo": "now",
"timezone": ""
}

View File

@@ -0,0 +1,109 @@
{
"editable": true,
"fiscalYearStartMonth": 0,
"graphTooltip": 0,
"id": 209,
"iteration": 1656508852566,
"links": [],
"liveNow": false,
"panels": [
{
"datasource": "${sqllite}",
"fieldConfig": {
"defaults": {
"custom": {
"align": "auto",
"displayMode": "auto",
"inspect": false
},
"mappings": [],
"thresholds": {
"mode": "absolute",
"steps": [
{
"color": "green",
"value": null
},
{
"color": "red",
"value": 80
}
]
}
},
"overrides": []
},
"gridPos": {
"h": 8,
"w": 12,
"x": 0,
"y": 0
},
"id": 1,
"options": {
"footer": {
"fields": "",
"reducer": [
"sum"
],
"show": false
},
"showHeader": true
},
"pluginVersion": "9.1.0-pre",
"targets": [
{
"datasource": {
"type": "sqlite-datasource",
"uid": "${sqllite}"
},
"queryText": "select * from user",
"queryType": "table",
"rawQueryText": "select * from user",
"refId": "A",
"timeColumns": [
"time",
"ts"
]
}
],
"title": "usersss!",
"type": "table"
}
],
"schemaVersion": 36,
"style": "dark",
"tags": [],
"templating": {
"list": [
{
"current": {
"selected": false,
"text": "SQLite Grafana",
"value": "SQLite Grafana"
},
"hide": 0,
"includeAll": false,
"multi": false,
"name": "sqllite",
"options": [],
"query": "sqlite-datasource",
"queryValue": "",
"refresh": 1,
"regex": "",
"skipUrlSync": false,
"type": "datasource"
}
]
},
"time": {
"from": "now-6h",
"to": "now"
},
"timepicker": {},
"timezone": "",
"title": "ds-variables",
"uid": "7BzWolqnk",
"version": 13,
"weekStart": ""
}

View File

@@ -0,0 +1,32 @@
package dashboard
type panelInfo struct {
ID int64 `json:"id"`
Title string `json:"title"`
Description string `json:"description,omitempty"`
Type string `json:"type,omitempty"` // PluginID
PluginVersion string `json:"pluginVersion,omitempty"`
Datasource []DataSourceRef `json:"datasource,omitempty"` // UIDs
Transformer []string `json:"transformer,omitempty"` // ids of the transformation steps
// Rows define panels as sub objects
Collapsed []panelInfo `json:"collapsed,omitempty"`
}
type dashboardInfo struct {
UID string `json:"uid,omitempty"`
ID int64 `json:"id,omitempty"` // internal ID
Title string `json:"title"`
Description string `json:"description,omitempty"`
Tags []string `json:"tags"`
TemplateVars []string `json:"templateVars,omitempty"` // the keys used
Datasource []DataSourceRef `json:"datasource,omitempty"` // UIDs
Panels []panelInfo `json:"panels"` // nesed documents
SchemaVersion int64 `json:"schemaVersion"`
LinkCount int64 `json:"linkCount"`
TimeFrom string `json:"timeFrom"`
TimeTo string `json:"timeTo"`
TimeZone string `json:"timezone"`
Refresh string `json:"refresh,omitempty"`
ReadOnly bool `json:"readOnly,omitempty"` // editable = false
}

View File

@@ -0,0 +1,4 @@
// Package dummy provides a dummy kind useful for testing
//
// The dummy kind returns a complicated summary that can exercise most of the storage options
package dummy

View File

@@ -0,0 +1,61 @@
package dummy
import (
"context"
"fmt"
"time"
"github.com/grafana/grafana/pkg/models"
)
func GetObjectKindInfo(kind string) models.ObjectKindInfo {
return models.ObjectKindInfo{
ID: kind,
Name: kind,
Description: "Dummy kind used for testing.",
IsRaw: true,
}
}
func GetObjectSummaryBuilder(kind string) models.ObjectSummaryBuilder {
return func(ctx context.Context, uid string, body []byte) (*models.ObjectSummary, []byte, error) {
summary := &models.ObjectSummary{
Name: fmt.Sprintf("Dummy: %s", kind),
Kind: kind,
Description: fmt.Sprintf("Wrote at %s", time.Now().Local().String()),
Labels: map[string]string{
"hello": "world",
"tag1": "",
"tag2": "",
},
Fields: map[string]interface{}{
"field1": "a string",
"field2": 1.224,
"field4": true,
},
Error: nil, // ignore for now
Nested: nil, // ignore for now
References: []*models.ObjectExternalReference{
{
Kind: "ds",
Type: "influx",
UID: "xyz",
},
{
Kind: "panel",
Type: "heatmap",
},
{
Kind: "panel",
Type: "timeseries",
},
},
}
if summary.UID != "" && uid != summary.UID {
return summary, nil, fmt.Errorf("internal UID mismatch")
}
return summary, body, nil
}
}

View File

@@ -0,0 +1,67 @@
package playlist
import (
"context"
"encoding/json"
"fmt"
"github.com/grafana/grafana/pkg/coremodel/playlist"
"github.com/grafana/grafana/pkg/models"
)
func GetObjectKindInfo() models.ObjectKindInfo {
return models.ObjectKindInfo{
ID: models.StandardKindPlaylist,
Name: "Playlist",
Description: "Cycle though a collection of dashboards automatically",
}
}
func GetObjectSummaryBuilder() models.ObjectSummaryBuilder {
return summaryBuilder
}
func summaryBuilder(ctx context.Context, uid string, body []byte) (*models.ObjectSummary, []byte, error) {
obj := &playlist.Model{}
err := json.Unmarshal(body, obj)
if err != nil {
return nil, nil, err // unable to read object
}
// TODO: fix model so this is not possible
if obj.Items == nil {
temp := make([]playlist.PlaylistItem, 0)
obj.Items = &temp
}
summary := &models.ObjectSummary{
UID: obj.Uid,
Name: obj.Name,
Description: fmt.Sprintf("%d items, refreshed every %s", len(*obj.Items), obj.Interval),
}
for _, item := range *obj.Items {
switch item.Type {
case playlist.PlaylistItemTypeDashboardByUid:
summary.References = append(summary.References, &models.ObjectExternalReference{
Kind: "dashboard",
UID: item.Value,
})
case playlist.PlaylistItemTypeDashboardByTag:
if summary.Labels == nil {
summary.Labels = make(map[string]string, 0)
}
summary.Labels[item.Value] = ""
case playlist.PlaylistItemTypeDashboardById:
// obviously insufficient long term... but good to have an example :)
summary.Error = &models.ObjectErrorInfo{
Message: "Playlist uses deprecated internal id system",
}
}
}
out, err := json.Marshal(obj)
return summary, out, err
}

View File

@@ -0,0 +1,39 @@
package playlist
import (
"context"
"encoding/json"
"testing"
"github.com/grafana/grafana/pkg/coremodel/playlist"
"github.com/stretchr/testify/require"
)
func TestPlaylistSummary(t *testing.T) {
builder := GetObjectSummaryBuilder()
// Do not parse invalid input
_, _, err := builder(context.Background(), "abc", []byte("{invalid json"))
require.Error(t, err)
playlist := playlist.Model{
Interval: "30s",
Name: "test",
Items: &[]playlist.PlaylistItem{
{Type: playlist.PlaylistItemTypeDashboardByUid, Value: "D1"},
{Type: playlist.PlaylistItemTypeDashboardByTag, Value: "tagA"},
{Type: playlist.PlaylistItemTypeDashboardByUid, Value: "D3"},
},
}
out, err := json.Marshal(playlist)
require.NoError(t, err)
require.NotNil(t, out)
// Do not parse invalid input
summary, body, err := builder(context.Background(), "abc", out)
require.NoError(t, err)
require.Equal(t, "test", summary.Name)
require.Equal(t, 2, len(summary.References))
require.Equal(t, map[string]string{"tagA": ""}, summary.Labels)
require.True(t, json.Valid(body))
}

View File

@@ -0,0 +1,55 @@
package png
import (
"bytes"
"context"
"image/png"
"strings"
"github.com/grafana/grafana/pkg/models"
)
func GetObjectKindInfo() models.ObjectKindInfo {
return models.ObjectKindInfo{
ID: models.StandardKindPNG,
Name: "PNG",
Description: "PNG Image file",
IsRaw: true,
FileExtension: "png",
MimeType: "image/png",
}
}
// SVG sanitizer based on the rendering service
func GetObjectSummaryBuilder() models.ObjectSummaryBuilder {
return func(ctx context.Context, uid string, body []byte) (*models.ObjectSummary, []byte, error) {
img, err := png.Decode(bytes.NewReader(body))
if err != nil {
return nil, nil, err
}
size := img.Bounds().Size()
summary := &models.ObjectSummary{
Kind: models.StandardKindSVG,
Name: guessNameFromUID(uid),
UID: uid,
Fields: map[string]interface{}{
"width": int64(size.X),
"height": int64(size.Y),
},
}
return summary, body, nil
}
}
func guessNameFromUID(uid string) string {
sidx := strings.LastIndex(uid, "/") + 1
didx := strings.LastIndex(uid, ".")
if didx > sidx && didx != sidx {
return uid[sidx:didx]
}
if sidx > 0 {
return uid[sidx:]
}
return uid
}

View File

@@ -0,0 +1,33 @@
package png
import (
"context"
"encoding/base64"
"encoding/json"
"testing"
"github.com/stretchr/testify/require"
)
func TestPNGSummary(t *testing.T) {
const gopher = `iVBORw0KGgoAAAANSUhEUgAAAEsAAAA8CAAAAAALAhhPAAAFfUlEQVRYw62XeWwUVRzHf2+OPbo9d7tsWyiyaZti6eWGAhISoIGKECEKCAiJJkYTiUgTMYSIosYYBBIUIxoSPIINEBDi2VhwkQrVsj1ESgu9doHWdrul7ba73WNm3vOPtsseM9MdwvvrzTs+8/t95ze/33sI5BqiabU6m9En8oNjduLnAEDLUsQXFF8tQ5oxK3vmnNmDSMtrncks9Hhtt/qeWZapHb1ha3UqYSWVl2ZmpWgaXMXGohQAvmeop3bjTRtv6SgaK/Pb9/bFzUrYslbFAmHPp+3WhAYdr+7GN/YnpN46Opv55VDsJkoEpMrY/vO2BIYQ6LLvm0ThY3MzDzzeSJeeWNyTkgnIE5ePKsvKlcg/0T9QMzXalwXMlj54z4c0rh/mzEfr+FgWEz2w6uk8dkzFAgcARAgNp1ZYef8bH2AgvuStbc2/i6CiWGj98y2tw2l4FAXKkQBIf+exyRnteY83LfEwDQAYCoK+P6bxkZm/0966LxcAAILHB56kgD95PPxltuYcMtFTWw/FKkY/6Opf3GGd9ZF+Qp6mzJxzuRSractOmJrH1u8XTvWFHINNkLQLMR+XHXvfPPHw967raE1xxwtA36IMRfkAAG29/7mLuQcb2WOnsJReZGfpiHsSBX81cvMKywYZHhX5hFPtOqPGWZCXnhWGAu6lX91ElKXSalcLXu3UaOXVay57ZSe5f6Gpx7J2MXAsi7EqSp09b/MirKSyJfnfEEgeDjl8FgDAfvewP03zZ+AJ0m9aFRM8eEHBDRKjfcreDXnZdQuAxXpT2NRJ7xl3UkLBhuVGU16gZiGOgZmrSbRdqkILuL/yYoSXHHkl9KXgqNu3PB8oRg0geC5vFmLjad6mUyTKLmF3OtraWDIfACyXqmephaDABawfpi6tqqBZytfQMqOz6S09iWXhktrRaB8Xz4Yi/8gyABDm5NVe6qq/3VzPrcjELWrebVuyY2T7ar4zQyybUCtsQ5Es1FGaZVrRVQwAgHGW2ZCRZshI5bGQi7HesyE972pOSeMM0dSktlzxRdrlqb3Osa6CCS8IJoQQQgBAbTAa5l5epO34rJszibJI8rxLfGzcp1dRosutGeb2VDNgqYrwTiPNsLxXiPi3dz7LiS1WBRBDBOnqEjyy3aQb+/bLiJzz9dIkscVBBLxMfSEac7kO4Fpkngi0ruNBeSOal+u8jgOuqPz12nryMLCniEjtOOOmpt+KEIqsEdocJjYXwrh9OZqWJQyPCTo67LNS/TdxLAv6R5ZNK9npEjbYdT33gRo4o5oTqR34R+OmaSzDBWsAIPhuRcgyoteNi9gF0KzNYWVItPf2TLoXEg+7isNC7uJkgo1iQWOfRSP9NR11RtbZZ3OMG/VhL6jvx+J1m87+RCfJChAtEBQkSBX2PnSiihc/Twh3j0h7qdYQAoRVsRGmq7HU2QRbaxVGa1D6nIOqaIWRjyRZpHMQKWKpZM5feA+lzC4ZFultV8S6T0mzQGhQohi5I8iw+CsqBSxhFMuwyLgSwbghGb0AiIKkSDmGZVmJSiKihsiyOAUs70UkywooYP0bii9GdH4sfr1UNysd3fUyLLMQN+rsmo3grHl9VNJHbbwxoa47Vw5gupIqrZcjPh9R4Nye3nRDk199V+aetmvVtDRE8/+cbgAAgMIWGb3UA0MGLE9SCbWX670TDy1y98c3D27eppUjsZ6fql3jcd5rUe7+ZIlLNQny3Rd+E5Tct3WVhTM5RBCEdiEK0b6B+/ca2gYU393nFj/n1AygRQxPIUA043M42u85+z2SnssKrPl8Mx76NL3E6eXc3be7OD+H4WHbJkKI8AU8irbITQjZ+0hQcPEgId/Fn/pl9crKH02+5o2b9T/eMx7pKoskYgAAAABJRU5ErkJggg==`
img, err := base64.StdEncoding.DecodeString(gopher)
require.NoError(t, err)
summary, out, err := GetObjectSummaryBuilder()(context.Background(), "hello.png", img)
require.NoError(t, err)
require.Equal(t, img, out) // same image
asjson, err := json.MarshalIndent(summary, "", " ")
//fmt.Printf(string(asjson))
require.NoError(t, err)
require.JSONEq(t, `{
"uid": "hello.png",
"kind": "svg",
"name": "hello",
"fields": {
"height": 60,
"width": 75
}
}`, string(asjson))
}

View File

@@ -0,0 +1,144 @@
package kind
import (
"fmt"
"sort"
"sync"
"github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/services/rendering"
"github.com/grafana/grafana/pkg/services/sqlstore"
"github.com/grafana/grafana/pkg/services/store/kind/dashboard"
"github.com/grafana/grafana/pkg/services/store/kind/dummy"
"github.com/grafana/grafana/pkg/services/store/kind/playlist"
"github.com/grafana/grafana/pkg/services/store/kind/png"
"github.com/grafana/grafana/pkg/services/store/kind/svg"
"github.com/grafana/grafana/pkg/setting"
)
type KindRegistry interface {
Register(info models.ObjectKindInfo, builder models.ObjectSummaryBuilder) error
GetSummaryBuilder(kind string) models.ObjectSummaryBuilder
GetInfo(kind string) (models.ObjectKindInfo, error)
GetKinds() []models.ObjectKindInfo
}
func NewKindRegistry() KindRegistry {
kinds := make(map[string]*kindValues)
kinds[models.StandardKindPlaylist] = &kindValues{
info: playlist.GetObjectKindInfo(),
builder: playlist.GetObjectSummaryBuilder(),
}
kinds[models.StandardKindPNG] = &kindValues{
info: png.GetObjectKindInfo(),
builder: png.GetObjectSummaryBuilder(),
}
// FIXME -- these are registered because existing tests use them
for _, k := range []string{"dummy", "kind1", "kind2", "kind3"} {
kinds[k] = &kindValues{
info: dummy.GetObjectKindInfo(k),
builder: dummy.GetObjectSummaryBuilder(k),
}
}
// create a registry
reg := &registry{
mutex: sync.RWMutex{},
kinds: kinds,
}
reg.updateInfoArray()
return reg
}
// TODO? This could be a zero dependency service that others are responsible for configuring
func ProvideService(cfg *setting.Cfg, renderer rendering.Service, sql *sqlstore.SQLStore) KindRegistry {
reg := NewKindRegistry()
// Register Dashboard support
//-----------------------
_ = reg.Register(dashboard.GetObjectKindInfo(), dashboard.NewDashboardSummary(sql))
// Register SVG support
//-----------------------
info := svg.GetObjectKindInfo()
allowUnsanitizedSvgUpload := cfg != nil && cfg.Storage.AllowUnsanitizedSvgUpload
support := svg.GetObjectSummaryBuilder(allowUnsanitizedSvgUpload, renderer)
_ = reg.Register(info, support)
return reg
}
type kindValues struct {
info models.ObjectKindInfo
builder models.ObjectSummaryBuilder
}
type registry struct {
mutex sync.RWMutex
kinds map[string]*kindValues
info []models.ObjectKindInfo
}
func (r *registry) updateInfoArray() {
info := make([]models.ObjectKindInfo, 0, len(r.kinds))
for _, v := range r.kinds {
info = append(info, v.info)
}
sort.Slice(info, func(i, j int) bool {
return info[i].ID < info[j].ID
})
r.info = info
}
func (r *registry) Register(info models.ObjectKindInfo, builder models.ObjectSummaryBuilder) error {
if info.ID == "" || builder == nil {
return fmt.Errorf("invalid kind")
}
r.mutex.Lock()
defer r.mutex.Unlock()
if r.kinds[info.ID] != nil {
return fmt.Errorf("already exits")
}
r.kinds[info.ID] = &kindValues{
info: info,
builder: builder,
}
r.updateInfoArray()
return nil
}
// GetSummaryBuilder returns a builder or nil if not found
func (r *registry) GetSummaryBuilder(kind string) models.ObjectSummaryBuilder {
r.mutex.RLock()
defer r.mutex.RUnlock()
v, ok := r.kinds[kind]
if ok {
return v.builder
}
return nil
}
// GetInfo returns the registered info
func (r *registry) GetInfo(kind string) (models.ObjectKindInfo, error) {
r.mutex.RLock()
defer r.mutex.RUnlock()
v, ok := r.kinds[kind]
if ok {
return v.info, nil
}
return models.ObjectKindInfo{}, fmt.Errorf("not found")
}
// GetSummaryBuilder returns a builder or nil if not found
func (r *registry) GetKinds() []models.ObjectKindInfo {
r.mutex.RLock()
defer r.mutex.RUnlock()
return r.info // returns a copy of the array
}

View File

@@ -0,0 +1,42 @@
package kind
import (
"testing"
"github.com/stretchr/testify/require"
"github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/services/store/kind/dummy"
)
func TestKindRegistry(t *testing.T) {
registry := NewKindRegistry()
err := registry.Register(dummy.GetObjectKindInfo("test"), dummy.GetObjectSummaryBuilder("test"))
require.NoError(t, err)
ids := []string{}
for _, k := range registry.GetKinds() {
ids = append(ids, k.ID)
}
require.Equal(t, []string{
"dummy",
"kind1",
"kind2",
"kind3",
"playlist",
"png",
"test",
}, ids)
// Check playlist exists
info, err := registry.GetInfo(models.StandardKindPlaylist)
require.NoError(t, err)
require.Equal(t, "Playlist", info.Name)
require.False(t, info.IsRaw)
// Check that we registered a test item
info, err = registry.GetInfo("test")
require.NoError(t, err)
require.Equal(t, "test", info.Name)
require.True(t, info.IsRaw)
}

View File

@@ -0,0 +1,66 @@
package svg
import (
"context"
"fmt"
"strings"
"github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/services/rendering"
)
func GetObjectKindInfo() models.ObjectKindInfo {
return models.ObjectKindInfo{
ID: models.StandardKindSVG,
Name: "SVG",
Description: "Scalable Vector Graphics",
IsRaw: true,
FileExtension: "svg",
MimeType: "image/svg+xml",
}
}
// SVG sanitizer based on the rendering service
func GetObjectSummaryBuilder(allowUnsanitizedSvgUpload bool, renderer rendering.Service) models.ObjectSummaryBuilder {
return func(ctx context.Context, uid string, body []byte) (*models.ObjectSummary, []byte, error) {
if !IsSVG(body) {
return nil, nil, fmt.Errorf("invalid svg")
}
// When a renderer exists, we can return a sanitized version
var sanitized []byte
if renderer != nil {
rsp, err := renderer.SanitizeSVG(ctx, &rendering.SanitizeSVGRequest{
Content: body,
})
if err != nil && !allowUnsanitizedSvgUpload {
return nil, nil, err
}
sanitized = rsp.Sanitized
}
if sanitized == nil {
if !allowUnsanitizedSvgUpload {
return nil, nil, fmt.Errorf("unable to sanitize svg")
}
sanitized = body
}
return &models.ObjectSummary{
Kind: models.StandardKindSVG,
Name: guessNameFromUID(uid),
UID: uid,
}, sanitized, nil
}
}
func guessNameFromUID(uid string) string {
sidx := strings.LastIndex(uid, "/") + 1
didx := strings.LastIndex(uid, ".")
if didx > sidx && didx != sidx {
return uid[sidx:didx]
}
if sidx > 0 {
return uid[sidx:]
}
return uid
}

View File

@@ -0,0 +1,56 @@
// The MIT License
//
//Copyright (c) 2016 Tomas Aparicio
//
//Permission is hereby granted, free of charge, to any person
//obtaining a copy of this software and associated documentation
//files (the "Software"), to deal in the Software without
//restriction, including without limitation the rights to use,
//copy, modify, merge, publish, distribute, sublicense, and/or sell
//copies of the Software, and to permit persons to whom the
//Software is furnished to do so, subject to the following
//conditions:
//
//The above copyright notice and this permission notice shall be
//included in all copies or substantial portions of the Software.
//
//THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
//EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
//OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
//NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
//HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
//WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
//FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
//OTHER DEALINGS IN THE SOFTWARE.
package svg
import (
"regexp"
"unicode/utf8"
)
var (
// nolint:gosimple
htmlCommentRegex = regexp.MustCompile("(?i)<!--([\\s\\S]*?)-->")
svgRegex = regexp.MustCompile(`(?i)^\s*(?:<\?xml[^>]*>\s*)?(?:<!doctype svg[^>]*>\s*)?<svg[^>]*>[^*]*<\/svg>\s*$`)
)
// isBinary checks if the given buffer is a binary file.
func isBinary(buf []byte) bool {
if len(buf) < 24 {
return false
}
for i := 0; i < 24; i++ {
charCode, _ := utf8.DecodeRuneInString(string(buf[i]))
if charCode == 65533 || charCode <= 8 {
return true
}
}
return false
}
// Is returns true if the given buffer is a valid SVG image.
func IsSVG(buf []byte) bool {
return !isBinary(buf) && svgRegex.Match(htmlCommentRegex.ReplaceAll(buf, []byte{}))
}