mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
Search: Implement basic improved UI (#46758)
This commit is contained in:
@@ -12,7 +12,7 @@ func logf(format string, a ...interface{}) {
|
||||
|
||||
// nolint:gocyclo
|
||||
// ReadDashboard will take a byte stream and return dashboard info
|
||||
func ReadDashboard(stream io.Reader, datasource DatasourceLookup) *DashboardInfo {
|
||||
func ReadDashboard(stream io.Reader, lookup DatasourceLookup) *DashboardInfo {
|
||||
iter := jsoniter.Parse(jsoniter.ConfigDefault, stream, 1024)
|
||||
dash := &DashboardInfo{}
|
||||
|
||||
@@ -73,7 +73,7 @@ func ReadDashboard(stream io.Reader, datasource DatasourceLookup) *DashboardInfo
|
||||
|
||||
case "panels":
|
||||
for iter.ReadArray() {
|
||||
dash.Panels = append(dash.Panels, readPanelInfo(iter))
|
||||
dash.Panels = append(dash.Panels, readPanelInfo(iter, lookup))
|
||||
}
|
||||
|
||||
case "rows":
|
||||
@@ -129,16 +129,29 @@ func ReadDashboard(stream io.Reader, datasource DatasourceLookup) *DashboardInfo
|
||||
logf("All dashbaords should have a UID defined")
|
||||
}
|
||||
|
||||
targets := newTargetInfo(lookup)
|
||||
for _, panel := range dash.Panels {
|
||||
targets.addPanel(panel)
|
||||
}
|
||||
dash.Datasource = targets.GetDatasourceInfo()
|
||||
|
||||
return dash
|
||||
}
|
||||
|
||||
// will always return strings for now
|
||||
func readPanelInfo(iter *jsoniter.Iterator) PanelInfo {
|
||||
func readPanelInfo(iter *jsoniter.Iterator, lookup DatasourceLookup) PanelInfo {
|
||||
panel := PanelInfo{}
|
||||
|
||||
targets := newTargetInfo(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 {
|
||||
if l1Field == "datasource" {
|
||||
targets.addDatasource(iter)
|
||||
continue
|
||||
}
|
||||
|
||||
// Skip null values so we don't need special int handling
|
||||
iter.Skip()
|
||||
continue
|
||||
}
|
||||
@@ -160,13 +173,11 @@ func readPanelInfo(iter *jsoniter.Iterator) PanelInfo {
|
||||
panel.PluginVersion = iter.ReadString() // since 7x (the saved version for the plugin model)
|
||||
|
||||
case "datasource":
|
||||
v := iter.Read()
|
||||
logf(">>Panel.datasource = %v\n", v) // string or object!!!
|
||||
targets.addDatasource(iter)
|
||||
|
||||
case "targets":
|
||||
for iter.ReadArray() {
|
||||
v := iter.Read()
|
||||
logf("[Panel.TARGET] %v\n", v)
|
||||
targets.addTarget(iter)
|
||||
}
|
||||
|
||||
case "transformations":
|
||||
@@ -183,7 +194,7 @@ func readPanelInfo(iter *jsoniter.Iterator) PanelInfo {
|
||||
// Rows have nested panels
|
||||
case "panels":
|
||||
for iter.ReadArray() {
|
||||
panel.Collapsed = append(panel.Collapsed, readPanelInfo(iter))
|
||||
panel.Collapsed = append(panel.Collapsed, readPanelInfo(iter, lookup))
|
||||
}
|
||||
|
||||
case "options":
|
||||
@@ -201,5 +212,7 @@ func readPanelInfo(iter *jsoniter.Iterator) PanelInfo {
|
||||
}
|
||||
}
|
||||
|
||||
panel.Datasource = targets.GetDatasourceInfo()
|
||||
|
||||
return panel
|
||||
}
|
||||
|
||||
@@ -12,19 +12,36 @@ import (
|
||||
|
||||
func TestReadDashboard(t *testing.T) {
|
||||
inputs := []string{
|
||||
"all-panels.json",
|
||||
"panel-graph/graph-shared-tooltips.json",
|
||||
"check-string-datasource-id",
|
||||
"all-panels",
|
||||
"panel-graph/graph-shared-tooltips",
|
||||
}
|
||||
|
||||
// key will allow name or uid
|
||||
ds := func(key string) *DatasourceInfo {
|
||||
return nil // TODO!
|
||||
ds := func(ref *DataSourceRef) *DataSourceRef {
|
||||
if ref == nil || ref.UID == "" {
|
||||
return &DataSourceRef{
|
||||
UID: "default.uid",
|
||||
Type: "default.type",
|
||||
}
|
||||
}
|
||||
return ref
|
||||
}
|
||||
|
||||
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("../../../../devenv/dev-dashboards/" + input)
|
||||
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 := ReadDashboard(f, ds)
|
||||
@@ -32,7 +49,7 @@ func TestReadDashboard(t *testing.T) {
|
||||
require.NoError(t, err)
|
||||
|
||||
update := false
|
||||
savedPath := "testdata/" + filepath.Base(input)
|
||||
savedPath := "testdata/" + input + "-info.json"
|
||||
saved, err := os.ReadFile(savedPath)
|
||||
if err != nil {
|
||||
update = true
|
||||
|
||||
81
pkg/services/searchV2/extract/targets.go
Normal file
81
pkg/services/searchV2/extract/targets.go
Normal file
@@ -0,0 +1,81 @@
|
||||
package extract
|
||||
|
||||
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()
|
||||
ds := s.lookup(&DataSourceRef{UID: key})
|
||||
s.addRef(ds)
|
||||
|
||||
case jsoniter.NilValue:
|
||||
s.addRef(s.lookup(nil))
|
||||
iter.Skip()
|
||||
|
||||
case jsoniter.ObjectValue:
|
||||
ref := &DataSourceRef{}
|
||||
iter.ReadVal(ref)
|
||||
ds := s.lookup(ref)
|
||||
s.addRef(ds)
|
||||
|
||||
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]
|
||||
}
|
||||
}
|
||||
}
|
||||
29
pkg/services/searchV2/extract/testdata/check-string-datasource-id-info.json
vendored
Normal file
29
pkg/services/searchV2/extract/testdata/check-string-datasource-id-info.json
vendored
Normal file
@@ -0,0 +1,29 @@
|
||||
{
|
||||
"id": 250,
|
||||
"uid": "K2X7hzwGk",
|
||||
"title": "fast streaming",
|
||||
"tags": null,
|
||||
"datasource": [
|
||||
{
|
||||
"uid": "-- Grafana --"
|
||||
}
|
||||
],
|
||||
"panels": [
|
||||
{
|
||||
"id": 3,
|
||||
"title": "Panel Title",
|
||||
"type": "timeseries",
|
||||
"pluginVersion": "7.5.0-pre",
|
||||
"datasource": [
|
||||
{
|
||||
"uid": "-- Grafana --"
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"schemaVersion": 27,
|
||||
"linkCount": 0,
|
||||
"timeFrom": "now-30s",
|
||||
"timeTo": "now",
|
||||
"timezone": ""
|
||||
}
|
||||
67
pkg/services/searchV2/extract/testdata/check-string-datasource-id.json
vendored
Normal file
67
pkg/services/searchV2/extract/testdata/check-string-datasource-id.json
vendored
Normal 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
|
||||
}
|
||||
122
pkg/services/searchV2/extract/testdata/devdash-graph-shared-tooltips-info.json
vendored
Normal file
122
pkg/services/searchV2/extract/testdata/devdash-graph-shared-tooltips-info.json
vendored
Normal file
@@ -0,0 +1,122 @@
|
||||
{
|
||||
"uid": "TX2VU59MZ",
|
||||
"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"
|
||||
}
|
||||
],
|
||||
"transformations": [
|
||||
"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": ""
|
||||
}
|
||||
@@ -1,68 +0,0 @@
|
||||
{
|
||||
"uid": "TX2VU59MZ",
|
||||
"title": "Panel Tests - shared tooltips",
|
||||
"tags": [
|
||||
"gdev",
|
||||
"panel-tests",
|
||||
"graph-ng"
|
||||
],
|
||||
"panels": [
|
||||
{
|
||||
"id": 4,
|
||||
"title": "two units",
|
||||
"type": "timeseries",
|
||||
"pluginVersion": "7.5.0-pre"
|
||||
},
|
||||
{
|
||||
"id": 13,
|
||||
"title": "Speed vs Temperature (XY)",
|
||||
"type": "xychart",
|
||||
"pluginVersion": "7.5.0-pre",
|
||||
"transformations": [
|
||||
"seriesToColumns",
|
||||
"organize"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 2,
|
||||
"title": "Cursor info",
|
||||
"type": "debug",
|
||||
"pluginVersion": "7.5.0-pre"
|
||||
},
|
||||
{
|
||||
"id": 5,
|
||||
"title": "Only temperature",
|
||||
"type": "timeseries",
|
||||
"pluginVersion": "7.5.0-pre"
|
||||
},
|
||||
{
|
||||
"id": 9,
|
||||
"title": "Only Speed",
|
||||
"type": "timeseries",
|
||||
"pluginVersion": "7.5.0-pre"
|
||||
},
|
||||
{
|
||||
"id": 11,
|
||||
"title": "Panel Title",
|
||||
"type": "timeseries",
|
||||
"pluginVersion": "7.5.0-pre"
|
||||
},
|
||||
{
|
||||
"id": 8,
|
||||
"title": "flot panel (temperature)",
|
||||
"type": "graph",
|
||||
"pluginVersion": "7.5.0-pre"
|
||||
},
|
||||
{
|
||||
"id": 10,
|
||||
"title": "flot panel (no units)",
|
||||
"type": "graph",
|
||||
"pluginVersion": "7.5.0-pre"
|
||||
}
|
||||
],
|
||||
"schemaVersion": 28,
|
||||
"linkCount": 0,
|
||||
"timeFrom": "2020-09-14T16:13:20.000Z",
|
||||
"timeTo": "2020-09-15T20:00:00.000Z",
|
||||
"timezone": ""
|
||||
}
|
||||
@@ -1,45 +1,40 @@
|
||||
package extract
|
||||
|
||||
type DatasourceLookup = func(key string) *DatasourceInfo
|
||||
// empty everything will return the default
|
||||
type DatasourceLookup = func(ref *DataSourceRef) *DataSourceRef
|
||||
|
||||
type DatasourceInfo struct {
|
||||
UID string `json:"uid"`
|
||||
Name string `json:"name"`
|
||||
Type string `json:"type"` // plugin name
|
||||
Version string `json:"version"`
|
||||
Access string `json:"access,omitempty"` // proxy, direct, or empty
|
||||
type DataSourceRef struct {
|
||||
UID string `json:"uid,omitempty"`
|
||||
Type string `json:"type,omitempty"`
|
||||
}
|
||||
|
||||
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 []string `json:"datasource,omitempty"` // UIDs
|
||||
DatasourceType []string `json:"datasourceType,omitempty"` // PluginIDs
|
||||
Transformations []string `json:"transformations,omitempty"` // ids of the transformation steps
|
||||
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
|
||||
Transformations []string `json:"transformations,omitempty"` // ids of the transformation steps
|
||||
|
||||
// Rows define panels as sub objects
|
||||
Collapsed []PanelInfo `json:"collapsed,omitempty"`
|
||||
}
|
||||
|
||||
type DashboardInfo struct {
|
||||
ID int64 `json:"id,omitempty"`
|
||||
UID string `json:"uid,omitempty"`
|
||||
Path string `json:"path,omitempty"`
|
||||
Title string `json:"title"`
|
||||
Description string `json:"description,omitempty"`
|
||||
Tags []string `json:"tags"` // UIDs
|
||||
Datasource []string `json:"datasource,omitempty"` // UIDs
|
||||
DatasourceType []string `json:"datasourceType,omitempty"` // PluginIDs
|
||||
TemplateVars []string `json:"templateVars,omitempty"` // the keys used
|
||||
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
|
||||
ID int64 `json:"id,omitempty"` // internal ID
|
||||
UID string `json:"uid,omitempty"`
|
||||
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
|
||||
}
|
||||
|
||||
@@ -89,7 +89,7 @@ func (s *StandardSearchService) applyAuthFilter(user *models.SignedInUser, dash
|
||||
// create a list of all viewable dashboards for this user
|
||||
res := make([]dashMeta, 0, len(dash))
|
||||
for _, dash := range dash {
|
||||
if filter(dash.dash.UID) {
|
||||
if filter(dash.dash.UID) || (dash.is_folder && dash.dash.UID == "") { // include the "General" folder
|
||||
res = append(res, dash)
|
||||
}
|
||||
}
|
||||
@@ -106,15 +106,38 @@ type dashDataQueryResult struct {
|
||||
Updated time.Time
|
||||
}
|
||||
|
||||
type dsQueryResult struct {
|
||||
UID string `xorm:"uid"`
|
||||
Type string `xorm:"type"`
|
||||
Name string `xorm:"name"`
|
||||
IsDefault bool `xorm:"is_default"`
|
||||
}
|
||||
|
||||
func loadDashboards(ctx context.Context, orgID int64, sql *sqlstore.SQLStore) ([]dashMeta, error) {
|
||||
meta := make([]dashMeta, 0, 200)
|
||||
|
||||
// Add the root folder ID (does not exist in SQL)
|
||||
meta = append(meta, dashMeta{
|
||||
id: 0,
|
||||
is_folder: true,
|
||||
folder_id: 0,
|
||||
slug: "",
|
||||
created: time.Now(),
|
||||
updated: time.Now(),
|
||||
dash: &extract.DashboardInfo{
|
||||
ID: 0,
|
||||
UID: "",
|
||||
Title: "General",
|
||||
},
|
||||
})
|
||||
|
||||
// key will allow name or uid
|
||||
lookup := func(key string) *extract.DatasourceInfo {
|
||||
return nil // TODO!
|
||||
lookup, err := loadDatasoureLookup(ctx, orgID, sql)
|
||||
if err != nil {
|
||||
return meta, err
|
||||
}
|
||||
|
||||
err := sql.WithDbSession(ctx, func(sess *sqlstore.DBSession) error {
|
||||
err = sql.WithDbSession(ctx, func(sess *sqlstore.DBSession) error {
|
||||
rows := make([]*dashDataQueryResult, 0)
|
||||
|
||||
sess.Table("dashboard").
|
||||
@@ -146,6 +169,64 @@ func loadDashboards(ctx context.Context, orgID int64, sql *sqlstore.SQLStore) ([
|
||||
return meta, err
|
||||
}
|
||||
|
||||
func loadDatasoureLookup(ctx context.Context, orgID int64, sql *sqlstore.SQLStore) (extract.DatasourceLookup, error) {
|
||||
byUID := make(map[string]*extract.DataSourceRef, 50)
|
||||
byName := make(map[string]*extract.DataSourceRef, 50)
|
||||
var defaultDS *extract.DataSourceRef
|
||||
|
||||
err := sql.WithDbSession(ctx, func(sess *sqlstore.DBSession) error {
|
||||
rows := make([]*dsQueryResult, 0)
|
||||
sess.Table("data_source").
|
||||
Where("org_id = ?", orgID).
|
||||
Cols("uid", "name", "type", "is_default")
|
||||
|
||||
err := sess.Find(&rows)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for _, row := range rows {
|
||||
ds := &extract.DataSourceRef{
|
||||
UID: row.UID,
|
||||
Type: row.Type,
|
||||
}
|
||||
byUID[row.UID] = ds
|
||||
byName[row.Name] = ds
|
||||
if row.IsDefault {
|
||||
defaultDS = ds
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Lookup by UID or name
|
||||
return func(ref *extract.DataSourceRef) *extract.DataSourceRef {
|
||||
if ref == nil {
|
||||
return defaultDS
|
||||
}
|
||||
key := ""
|
||||
if ref.UID != "" {
|
||||
ds, ok := byUID[ref.UID]
|
||||
if ok {
|
||||
return ds
|
||||
}
|
||||
key = ref.UID
|
||||
}
|
||||
if key == "" {
|
||||
return defaultDS
|
||||
}
|
||||
ds, ok := byUID[key]
|
||||
if ok {
|
||||
return ds
|
||||
}
|
||||
return byName[key]
|
||||
}, err
|
||||
}
|
||||
|
||||
type simpleCounter struct {
|
||||
values map[string]int64
|
||||
}
|
||||
@@ -173,10 +254,12 @@ func metaToFrame(meta []dashMeta) data.Frames {
|
||||
folderID := data.NewFieldFromFieldType(data.FieldTypeInt64, 0)
|
||||
folderUID := data.NewFieldFromFieldType(data.FieldTypeString, 0)
|
||||
folderName := data.NewFieldFromFieldType(data.FieldTypeString, 0)
|
||||
folderDashCount := data.NewFieldFromFieldType(data.FieldTypeInt64, 0)
|
||||
|
||||
folderID.Name = "ID"
|
||||
folderUID.Name = "UID"
|
||||
folderName.Name = "Name"
|
||||
folderID.Name = "id"
|
||||
folderUID.Name = "uid"
|
||||
folderName.Name = "name"
|
||||
folderDashCount.Name = "DashCount"
|
||||
|
||||
dashID := data.NewFieldFromFieldType(data.FieldTypeInt64, 0)
|
||||
dashUID := data.NewFieldFromFieldType(data.FieldTypeString, 0)
|
||||
@@ -188,22 +271,28 @@ func metaToFrame(meta []dashMeta) data.Frames {
|
||||
dashUpdated := data.NewFieldFromFieldType(data.FieldTypeTime, 0)
|
||||
dashSchemaVersion := data.NewFieldFromFieldType(data.FieldTypeInt64, 0)
|
||||
dashTags := data.NewFieldFromFieldType(data.FieldTypeNullableString, 0)
|
||||
dashPanelCount := data.NewFieldFromFieldType(data.FieldTypeInt64, 0)
|
||||
dashVarCount := data.NewFieldFromFieldType(data.FieldTypeInt64, 0)
|
||||
dashDSList := data.NewFieldFromFieldType(data.FieldTypeNullableString, 0)
|
||||
|
||||
dashID.Name = "ID"
|
||||
dashUID.Name = "UID"
|
||||
dashFolderID.Name = "FolderID"
|
||||
dashName.Name = "Name"
|
||||
dashDescr.Name = "Description"
|
||||
dashTags.Name = "Tags"
|
||||
dashID.Name = "id"
|
||||
dashUID.Name = "uid"
|
||||
dashFolderID.Name = "folderID"
|
||||
dashName.Name = "name"
|
||||
dashDescr.Name = "description"
|
||||
dashTags.Name = "tags"
|
||||
dashSchemaVersion.Name = "SchemaVersion"
|
||||
dashCreated.Name = "Created"
|
||||
dashUpdated.Name = "Updated"
|
||||
dashURL.Name = "URL"
|
||||
dashURL.Name = "url"
|
||||
dashURL.Config = &data.FieldConfig{
|
||||
Links: []data.DataLink{
|
||||
{Title: "link", URL: "${__value.text}"},
|
||||
},
|
||||
}
|
||||
dashPanelCount.Name = "panelCount"
|
||||
dashVarCount.Name = "varCount"
|
||||
dashDSList.Name = "datasource"
|
||||
|
||||
dashTags.Config = &data.FieldConfig{
|
||||
Custom: map[string]interface{}{
|
||||
@@ -218,11 +307,11 @@ func metaToFrame(meta []dashMeta) data.Frames {
|
||||
panelDescr := data.NewFieldFromFieldType(data.FieldTypeString, 0)
|
||||
panelType := data.NewFieldFromFieldType(data.FieldTypeString, 0)
|
||||
|
||||
panelDashID.Name = "DashboardID"
|
||||
panelID.Name = "ID"
|
||||
panelName.Name = "Name"
|
||||
panelDescr.Name = "Description"
|
||||
panelType.Name = "Type"
|
||||
panelDashID.Name = "dashboardID"
|
||||
panelID.Name = "id"
|
||||
panelName.Name = "name"
|
||||
panelDescr.Name = "description"
|
||||
panelType.Name = "type"
|
||||
|
||||
panelTypeCounter := simpleCounter{
|
||||
values: make(map[string]int64, 30),
|
||||
@@ -232,12 +321,14 @@ func metaToFrame(meta []dashMeta) data.Frames {
|
||||
values: make(map[string]int64, 30),
|
||||
}
|
||||
|
||||
var tags *string
|
||||
folderCounter := make(map[int64]int64, 20)
|
||||
|
||||
for _, row := range meta {
|
||||
if row.is_folder {
|
||||
folderID.Append(row.id)
|
||||
folderUID.Append(row.dash.UID)
|
||||
folderName.Append(row.dash.Title)
|
||||
folderDashCount.Append(int64(0)) // filled in later
|
||||
continue
|
||||
}
|
||||
|
||||
@@ -250,22 +341,23 @@ func metaToFrame(meta []dashMeta) data.Frames {
|
||||
dashCreated.Append(row.created)
|
||||
dashUpdated.Append(row.updated)
|
||||
|
||||
// Increment the folder counter
|
||||
fcount, ok := folderCounter[row.folder_id]
|
||||
if !ok {
|
||||
fcount = 0
|
||||
}
|
||||
folderCounter[row.folder_id] = fcount + 1
|
||||
|
||||
url := fmt.Sprintf("/d/%s/%s", row.dash.UID, row.slug)
|
||||
dashURL.Append(url)
|
||||
|
||||
// stats
|
||||
schemaVersionCounter.add(strconv.FormatInt(row.dash.SchemaVersion, 10))
|
||||
|
||||
// Send tags as JSON array
|
||||
tags = nil
|
||||
if len(row.dash.Tags) > 0 {
|
||||
b, err := json.Marshal(row.dash.Tags)
|
||||
if err == nil {
|
||||
s := string(b)
|
||||
tags = &s
|
||||
}
|
||||
}
|
||||
dashTags.Append(tags)
|
||||
dashTags.Append(toJSONString(row.dash.Tags))
|
||||
dashPanelCount.Append(int64(len(row.dash.Panels)))
|
||||
dashVarCount.Append(int64(len(row.dash.TemplateVars)))
|
||||
dashDSList.Append(dsAsJSONString(row.dash.Datasource))
|
||||
|
||||
// Row for each panel
|
||||
for _, panel := range row.dash.Panels {
|
||||
@@ -278,11 +370,47 @@ func metaToFrame(meta []dashMeta) data.Frames {
|
||||
}
|
||||
}
|
||||
|
||||
// Update the folder counts
|
||||
for i := 0; i < folderID.Len(); i++ {
|
||||
id, ok := folderID.At(i).(int64)
|
||||
if ok {
|
||||
folderDashCount.Set(i, folderCounter[id])
|
||||
}
|
||||
}
|
||||
|
||||
return data.Frames{
|
||||
data.NewFrame("folders", folderID, folderUID, folderName),
|
||||
data.NewFrame("dashboards", dashID, dashUID, dashURL, dashFolderID, dashName, dashDescr, dashTags, dashSchemaVersion, dashCreated, dashUpdated),
|
||||
data.NewFrame("folders", folderID, folderUID, folderName, folderDashCount),
|
||||
data.NewFrame("dashboards", dashID, dashUID, dashURL, dashFolderID,
|
||||
dashName, dashDescr, dashTags,
|
||||
dashSchemaVersion,
|
||||
dashPanelCount, dashVarCount, dashDSList,
|
||||
dashCreated, dashUpdated),
|
||||
data.NewFrame("panels", panelDashID, panelID, panelName, panelDescr, panelType),
|
||||
panelTypeCounter.toFrame("panel-type-counts"),
|
||||
schemaVersionCounter.toFrame("schema-version-counts"),
|
||||
}
|
||||
}
|
||||
|
||||
func toJSONString(vals []string) *string {
|
||||
if len(vals) < 1 {
|
||||
return nil
|
||||
}
|
||||
b, err := json.Marshal(vals)
|
||||
if err == nil {
|
||||
s := string(b)
|
||||
return &s
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func dsAsJSONString(vals []extract.DataSourceRef) *string {
|
||||
if len(vals) < 1 {
|
||||
return nil
|
||||
}
|
||||
b, err := json.Marshal(vals)
|
||||
if err == nil {
|
||||
s := string(b)
|
||||
return &s
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user