diff --git a/pkg/models/object.go b/pkg/models/object.go index 0e2dc3000b8..6a80988a93e 100644 --- a/pkg/models/object.go +++ b/pkg/models/object.go @@ -15,23 +15,36 @@ const ( // Types: influx, prometheus, testdata, ... StandardKindDataSource = "ds" - // StandardKindPanel: currently used in two ways :( in search it defines a panel within a dashboard - // This is also used to refer to a panel plugin with type: heatmap, timeseries, table, ... + // StandardKindPanel: only used for searchV2 right now + // Standalone panel is not an object kind yet -- library panel, or nested in dashboard StandardKindPanel = "panel" - // StandardKindTransform: used to show that a dashboard depends on a set of transformations - // NOTE: this should likey be replaced with kind:system/type:transform/uid:joinByField or something like that - StandardKindTransform = "transform" - // StandardKindSVG SVG file support StandardKindSVG = "svg" // StandardKindPNG PNG file support StandardKindPNG = "png" + // StandardKindGeoJSON represents spatial data + StandardKindGeoJSON = "geojson" + // StandardKindQuery early development on panel query library // the kind may need to change to better encapsulate { targets:[], transforms:[] } StandardKindQuery = "query" + + //---------------------------------------- + // References are referenced from objects + //---------------------------------------- + + // ExternalEntityReferencePlugin: requires a plugin to be installed + ExternalEntityReferencePlugin = "plugin" + + // ExternalEntityReferenceRuntime: frontend runtime requirements + ExternalEntityReferenceRuntime = "runtime" + + // ExternalEntityReferenceRuntime_Transformer is a "type" under runtime + // UIDs include: joinByField, organize, seriesToColumns, etc + ExternalEntityReferenceRuntime_Transformer = "transformer" ) // ObjectKindInfo describes information needed from the object store diff --git a/pkg/services/searchV2/bluge.go b/pkg/services/searchV2/bluge.go index 3a88e8b3a8b..727c38b640a 100644 --- a/pkg/services/searchV2/bluge.go +++ b/pkg/services/searchV2/bluge.go @@ -213,13 +213,13 @@ func getDashboardPanelDocs(dash dashboard, location string) []*bluge.Document { Aggregatable(). SearchTermPositions()) } - case models.StandardKindPanel: - if ref.Type != "" { - doc.AddField(bluge.NewKeywordField(documentFieldPanelType, ref.Type).Aggregatable().StoreValue()) + case models.ExternalEntityReferencePlugin: + if ref.Type == models.StandardKindPanel && ref.UID != "" { + doc.AddField(bluge.NewKeywordField(documentFieldPanelType, ref.UID).Aggregatable().StoreValue()) } - case models.StandardKindTransform: - if ref.Type != "" { - doc.AddField(bluge.NewKeywordField(documentFieldTransformer, ref.Type).Aggregatable()) + case models.ExternalEntityReferenceRuntime: + if ref.Type == models.ExternalEntityReferenceRuntime_Transformer && ref.UID != "" { + doc.AddField(bluge.NewKeywordField(documentFieldTransformer, ref.UID).Aggregatable()) } } } diff --git a/pkg/services/store/kind/dashboard/ds_lookup.go b/pkg/services/store/kind/dashboard/ds_lookup.go index 4b5e961d763..06a5a21c056 100644 --- a/pkg/services/store/kind/dashboard/ds_lookup.go +++ b/pkg/services/store/kind/dashboard/ds_lookup.go @@ -24,6 +24,21 @@ type DatasourceQueryResult struct { IsDefault bool `xorm:"is_default"` } +type directLookup struct{} + +func (d *directLookup) ByRef(ref *DataSourceRef) *DataSourceRef { + if ref == nil { + return &DataSourceRef{} // indicates the default + } + return ref +} + +func (d *directLookup) ByType(dsType string) []DataSourceRef { + return []DataSourceRef{ + {Type: dsType, UID: "*"}, + } +} + func CreateDatasourceLookup(rows []*DatasourceQueryResult) DatasourceLookup { byUID := make(map[string]*DataSourceRef, 50) byName := make(map[string]*DataSourceRef, 50) diff --git a/pkg/services/store/kind/dashboard/summary.go b/pkg/services/store/kind/dashboard/summary.go index 405ca7d7a5b..0f5259ba1ed 100644 --- a/pkg/services/store/kind/dashboard/summary.go +++ b/pkg/services/store/kind/dashboard/summary.go @@ -7,8 +7,7 @@ import ( "strconv" "github.com/grafana/grafana/pkg/models" - "github.com/grafana/grafana/pkg/services/sqlstore" - "github.com/grafana/grafana/pkg/services/store" + "github.com/grafana/grafana/pkg/plugins" ) func GetObjectKindInfo() models.ObjectKindInfo { @@ -19,26 +18,15 @@ func GetObjectKindInfo() models.ObjectKindInfo { } } -func NewDashboardSummary(sql *sqlstore.SQLStore) models.ObjectSummaryBuilder { +// This summary does not resolve old name as UID +func GetObjectSummaryBuilder() models.ObjectSummaryBuilder { + builder := NewStaticDashboardSummaryBuilder(&directLookup{}) 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) } } +// This implementation moves datasources referenced by internal ID or name to UID func NewStaticDashboardSummaryBuilder(lookup DatasourceLookup) models.ObjectSummaryBuilder { return func(ctx context.Context, uid string, body []byte) (*models.ObjectSummary, []byte, error) { summary := &models.ObjectSummary{ @@ -77,18 +65,23 @@ func NewStaticDashboardSummaryBuilder(lookup DatasourceLookup) models.ObjectSumm p.Description = panel.Description p.URL = fmt.Sprintf("%s?viewPanel=%d", url, panel.ID) p.Fields = make(map[string]interface{}, 0) + p.Fields["type"] = panel.Type - panelRefs.Add("panel", panel.Type, "") + if panel.Type != "row" { + panelRefs.Add(models.ExternalEntityReferencePlugin, string(plugins.Panel), panel.Type) + dashboardRefs.Add(models.ExternalEntityReferencePlugin, string(plugins.Panel), panel.Type) + } for _, v := range panel.Datasource { dashboardRefs.Add(models.StandardKindDataSource, v.Type, v.UID) panelRefs.Add(models.StandardKindDataSource, v.Type, v.UID) + if v.Type != "" { + dashboardRefs.Add(models.ExternalEntityReferencePlugin, string(plugins.DataSource), v.Type) + } } - for _, v := range panel.Transformer { - panelRefs.Add(models.StandardKindTransform, v, "") + panelRefs.Add(models.ExternalEntityReferenceRuntime, models.ExternalEntityReferenceRuntime_Transformer, v) + dashboardRefs.Add(models.ExternalEntityReferenceRuntime, models.ExternalEntityReferenceRuntime_Transformer, v) } - - dashboardRefs.Add(models.StandardKindPanel, panel.Type, "") p.References = panelRefs.Get() summary.Nested = append(summary.Nested, p) } diff --git a/pkg/services/store/kind/dashboard/summary_test.go b/pkg/services/store/kind/dashboard/summary_test.go index 8f43ca77c3b..9ec1382165b 100644 --- a/pkg/services/store/kind/dashboard/summary_test.go +++ b/pkg/services/store/kind/dashboard/summary_test.go @@ -16,7 +16,7 @@ func TestReadSummaries(t *testing.T) { devdash := "../../../../../devenv/dev-dashboards/panel-graph/" ctx := context.Background() - reader := NewStaticDashboardSummaryBuilder(dsLookupForTests()) + reader := GetObjectSummaryBuilder() failed := make([]string, 0, 10) err := filepath.Walk(devdash, diff --git a/pkg/services/store/kind/dashboard/testdata/gdev-walk-graph-gradient-area-fills.json b/pkg/services/store/kind/dashboard/testdata/gdev-walk-graph-gradient-area-fills.json index f49b1d3f861..7a498750b87 100644 --- a/pkg/services/store/kind/dashboard/testdata/gdev-walk-graph-gradient-area-fills.json +++ b/pkg/services/store/kind/dashboard/testdata/gdev-walk-graph-gradient-area-fills.json @@ -15,15 +15,17 @@ "kind": "panel", "name": "Req/s", "URL": "/d/graph-gradient-area-fills.json/panel-tests-graph-gradient-area-fills?viewPanel=2", + "fields": { + "type": "graph" + }, "references": [ { - "kind": "ds", - "type": "default.type", - "UID": "default.uid" + "kind": "ds" }, { - "kind": "panel", - "type": "graph" + "kind": "plugin", + "type": "panel", + "UID": "graph" } ] }, @@ -32,15 +34,17 @@ "kind": "panel", "name": "Req/s", "URL": "/d/graph-gradient-area-fills.json/panel-tests-graph-gradient-area-fills?viewPanel=11", + "fields": { + "type": "graph" + }, "references": [ { - "kind": "ds", - "type": "default.type", - "UID": "default.uid" + "kind": "ds" }, { - "kind": "panel", - "type": "graph" + "kind": "plugin", + "type": "panel", + "UID": "graph" } ] }, @@ -49,15 +53,17 @@ "kind": "panel", "name": "Memory", "URL": "/d/graph-gradient-area-fills.json/panel-tests-graph-gradient-area-fills?viewPanel=7", + "fields": { + "type": "graph" + }, "references": [ { - "kind": "ds", - "type": "default.type", - "UID": "default.uid" + "kind": "ds" }, { - "kind": "panel", - "type": "graph" + "kind": "plugin", + "type": "panel", + "UID": "graph" } ] }, @@ -66,28 +72,29 @@ "kind": "panel", "name": "Req/s", "URL": "/d/graph-gradient-area-fills.json/panel-tests-graph-gradient-area-fills?viewPanel=10", + "fields": { + "type": "graph" + }, "references": [ { - "kind": "ds", - "type": "default.type", - "UID": "default.uid" + "kind": "ds" }, { - "kind": "panel", - "type": "graph" + "kind": "plugin", + "type": "panel", + "UID": "graph" } ] } ], "references": [ { - "kind": "ds", - "type": "default.type", - "UID": "default.uid" + "kind": "ds" }, { - "kind": "panel", - "type": "graph" + "kind": "plugin", + "type": "panel", + "UID": "graph" } ] } \ No newline at end of file diff --git a/pkg/services/store/kind/dashboard/testdata/gdev-walk-graph-shared-tooltips.json b/pkg/services/store/kind/dashboard/testdata/gdev-walk-graph-shared-tooltips.json index 7b637a84ab6..76322a60de5 100644 --- a/pkg/services/store/kind/dashboard/testdata/gdev-walk-graph-shared-tooltips.json +++ b/pkg/services/store/kind/dashboard/testdata/gdev-walk-graph-shared-tooltips.json @@ -15,15 +15,17 @@ "kind": "panel", "name": "two units", "URL": "/d/graph-shared-tooltips.json/panel-tests-shared-tooltips?viewPanel=4", + "fields": { + "type": "timeseries" + }, "references": [ { - "kind": "ds", - "type": "default.type", - "UID": "default.uid" + "kind": "ds" }, { - "kind": "panel", - "type": "timeseries" + "kind": "plugin", + "type": "panel", + "UID": "timeseries" } ] }, @@ -32,23 +34,27 @@ "kind": "panel", "name": "Speed vs Temperature (XY)", "URL": "/d/graph-shared-tooltips.json/panel-tests-shared-tooltips?viewPanel=13", + "fields": { + "type": "xychart" + }, "references": [ { - "kind": "ds", - "type": "default.type", - "UID": "default.uid" + "kind": "ds" }, { - "kind": "panel", - "type": "xychart" + "kind": "plugin", + "type": "panel", + "UID": "xychart" }, { - "kind": "transform", - "type": "organize" + "kind": "runtime", + "type": "transformer", + "UID": "organize" }, { - "kind": "transform", - "type": "seriesToColumns" + "kind": "runtime", + "type": "transformer", + "UID": "seriesToColumns" } ] }, @@ -57,15 +63,17 @@ "kind": "panel", "name": "Cursor info", "URL": "/d/graph-shared-tooltips.json/panel-tests-shared-tooltips?viewPanel=2", + "fields": { + "type": "debug" + }, "references": [ { - "kind": "ds", - "type": "default.type", - "UID": "default.uid" + "kind": "ds" }, { - "kind": "panel", - "type": "debug" + "kind": "plugin", + "type": "panel", + "UID": "debug" } ] }, @@ -74,15 +82,17 @@ "kind": "panel", "name": "Only temperature", "URL": "/d/graph-shared-tooltips.json/panel-tests-shared-tooltips?viewPanel=5", + "fields": { + "type": "timeseries" + }, "references": [ { - "kind": "ds", - "type": "default.type", - "UID": "default.uid" + "kind": "ds" }, { - "kind": "panel", - "type": "timeseries" + "kind": "plugin", + "type": "panel", + "UID": "timeseries" } ] }, @@ -91,15 +101,17 @@ "kind": "panel", "name": "Only Speed", "URL": "/d/graph-shared-tooltips.json/panel-tests-shared-tooltips?viewPanel=9", + "fields": { + "type": "timeseries" + }, "references": [ { - "kind": "ds", - "type": "default.type", - "UID": "default.uid" + "kind": "ds" }, { - "kind": "panel", - "type": "timeseries" + "kind": "plugin", + "type": "panel", + "UID": "timeseries" } ] }, @@ -108,15 +120,17 @@ "kind": "panel", "name": "Panel Title", "URL": "/d/graph-shared-tooltips.json/panel-tests-shared-tooltips?viewPanel=11", + "fields": { + "type": "timeseries" + }, "references": [ { - "kind": "ds", - "type": "default.type", - "UID": "default.uid" + "kind": "ds" }, { - "kind": "panel", - "type": "timeseries" + "kind": "plugin", + "type": "panel", + "UID": "timeseries" } ] }, @@ -125,15 +139,17 @@ "kind": "panel", "name": "flot panel (temperature)", "URL": "/d/graph-shared-tooltips.json/panel-tests-shared-tooltips?viewPanel=8", + "fields": { + "type": "graph" + }, "references": [ { - "kind": "ds", - "type": "default.type", - "UID": "default.uid" + "kind": "ds" }, { - "kind": "panel", - "type": "graph" + "kind": "plugin", + "type": "panel", + "UID": "graph" } ] }, @@ -142,40 +158,54 @@ "kind": "panel", "name": "flot panel (no units)", "URL": "/d/graph-shared-tooltips.json/panel-tests-shared-tooltips?viewPanel=10", + "fields": { + "type": "graph" + }, "references": [ { - "kind": "ds", - "type": "default.type", - "UID": "default.uid" + "kind": "ds" }, { - "kind": "panel", - "type": "graph" + "kind": "plugin", + "type": "panel", + "UID": "graph" } ] } ], "references": [ { - "kind": "ds", - "type": "default.type", - "UID": "default.uid" + "kind": "ds" }, { - "kind": "panel", - "type": "debug" + "kind": "plugin", + "type": "panel", + "UID": "debug" }, { - "kind": "panel", - "type": "graph" + "kind": "plugin", + "type": "panel", + "UID": "graph" }, { - "kind": "panel", - "type": "timeseries" + "kind": "plugin", + "type": "panel", + "UID": "timeseries" }, { - "kind": "panel", - "type": "xychart" + "kind": "plugin", + "type": "panel", + "UID": "xychart" + }, + { + "kind": "runtime", + "type": "transformer", + "UID": "organize" + }, + { + "kind": "runtime", + "type": "transformer", + "UID": "seriesToColumns" } ] } \ No newline at end of file diff --git a/pkg/services/store/kind/dashboard/testdata/gdev-walk-graph-time-regions.json b/pkg/services/store/kind/dashboard/testdata/gdev-walk-graph-time-regions.json index a67b14bd80c..1f0eb85e981 100644 --- a/pkg/services/store/kind/dashboard/testdata/gdev-walk-graph-time-regions.json +++ b/pkg/services/store/kind/dashboard/testdata/gdev-walk-graph-time-regions.json @@ -15,15 +15,18 @@ "kind": "panel", "name": "Business Hours", "URL": "/d/graph-time-regions.json/panel-tests-graph-time-regions?viewPanel=2", + "fields": { + "type": "graph" + }, "references": [ { "kind": "ds", - "type": "testdata", - "UID": "PD8C576611E62080A" + "UID": "gdev-testdata" }, { - "kind": "panel", - "type": "graph" + "kind": "plugin", + "type": "panel", + "UID": "graph" } ] }, @@ -32,15 +35,18 @@ "kind": "panel", "name": "Sunday's 20-23", "URL": "/d/graph-time-regions.json/panel-tests-graph-time-regions?viewPanel=4", + "fields": { + "type": "graph" + }, "references": [ { "kind": "ds", - "type": "testdata", - "UID": "PD8C576611E62080A" + "UID": "gdev-testdata" }, { - "kind": "panel", - "type": "graph" + "kind": "plugin", + "type": "panel", + "UID": "graph" } ] }, @@ -49,15 +55,18 @@ "kind": "panel", "name": "Each day of week", "URL": "/d/graph-time-regions.json/panel-tests-graph-time-regions?viewPanel=3", + "fields": { + "type": "graph" + }, "references": [ { "kind": "ds", - "type": "testdata", - "UID": "PD8C576611E62080A" + "UID": "gdev-testdata" }, { - "kind": "panel", - "type": "graph" + "kind": "plugin", + "type": "panel", + "UID": "graph" } ] }, @@ -66,15 +75,18 @@ "kind": "panel", "name": "05:00", "URL": "/d/graph-time-regions.json/panel-tests-graph-time-regions?viewPanel=5", + "fields": { + "type": "graph" + }, "references": [ { "kind": "ds", - "type": "testdata", - "UID": "PD8C576611E62080A" + "UID": "gdev-testdata" }, { - "kind": "panel", - "type": "graph" + "kind": "plugin", + "type": "panel", + "UID": "graph" } ] }, @@ -83,15 +95,18 @@ "kind": "panel", "name": "From 22:00 to 00:30 (crossing midnight)", "URL": "/d/graph-time-regions.json/panel-tests-graph-time-regions?viewPanel=7", + "fields": { + "type": "graph" + }, "references": [ { "kind": "ds", - "type": "testdata", - "UID": "PD8C576611E62080A" + "UID": "gdev-testdata" }, { - "kind": "panel", - "type": "graph" + "kind": "plugin", + "type": "panel", + "UID": "graph" } ] } @@ -99,12 +114,12 @@ "references": [ { "kind": "ds", - "type": "testdata", - "UID": "PD8C576611E62080A" + "UID": "gdev-testdata" }, { - "kind": "panel", - "type": "graph" + "kind": "plugin", + "type": "panel", + "UID": "graph" } ] } \ No newline at end of file diff --git a/pkg/services/store/kind/dashboard/testdata/gdev-walk-graph_tests.json b/pkg/services/store/kind/dashboard/testdata/gdev-walk-graph_tests.json index 2c729edd679..c509113fe4b 100644 --- a/pkg/services/store/kind/dashboard/testdata/gdev-walk-graph_tests.json +++ b/pkg/services/store/kind/dashboard/testdata/gdev-walk-graph_tests.json @@ -15,15 +15,18 @@ "kind": "panel", "name": "No Data Points Warning", "URL": "/d/graph_tests.json/panel-tests-graph?viewPanel=1", + "fields": { + "type": "graph" + }, "references": [ { "kind": "ds", - "type": "testdata", - "UID": "PD8C576611E62080A" + "UID": "gdev-testdata" }, { - "kind": "panel", - "type": "graph" + "kind": "plugin", + "type": "panel", + "UID": "graph" } ] }, @@ -32,15 +35,18 @@ "kind": "panel", "name": "Datapoints Outside Range Warning", "URL": "/d/graph_tests.json/panel-tests-graph?viewPanel=2", + "fields": { + "type": "graph" + }, "references": [ { "kind": "ds", - "type": "testdata", - "UID": "PD8C576611E62080A" + "UID": "gdev-testdata" }, { - "kind": "panel", - "type": "graph" + "kind": "plugin", + "type": "panel", + "UID": "graph" } ] }, @@ -49,15 +55,18 @@ "kind": "panel", "name": "Random walk series", "URL": "/d/graph_tests.json/panel-tests-graph?viewPanel=3", + "fields": { + "type": "graph" + }, "references": [ { "kind": "ds", - "type": "testdata", - "UID": "PD8C576611E62080A" + "UID": "gdev-testdata" }, { - "kind": "panel", - "type": "graph" + "kind": "plugin", + "type": "panel", + "UID": "graph" } ] }, @@ -66,15 +75,18 @@ "kind": "panel", "name": "Millisecond res x-axis and tooltip", "URL": "/d/graph_tests.json/panel-tests-graph?viewPanel=4", + "fields": { + "type": "graph" + }, "references": [ { "kind": "ds", - "type": "testdata", - "UID": "PD8C576611E62080A" + "UID": "gdev-testdata" }, { - "kind": "panel", - "type": "graph" + "kind": "plugin", + "type": "panel", + "UID": "graph" } ] }, @@ -82,15 +94,17 @@ "uid": "graph_tests.json#6", "kind": "panel", "URL": "/d/graph_tests.json/panel-tests-graph?viewPanel=6", + "fields": { + "type": "text" + }, "references": [ { - "kind": "ds", - "type": "default.type", - "UID": "default.uid" + "kind": "ds" }, { - "kind": "panel", - "type": "text" + "kind": "plugin", + "type": "panel", + "UID": "text" } ] }, @@ -99,15 +113,18 @@ "kind": "panel", "name": "2 yaxis and axis labels", "URL": "/d/graph_tests.json/panel-tests-graph?viewPanel=5", + "fields": { + "type": "graph" + }, "references": [ { "kind": "ds", - "type": "testdata", - "UID": "PD8C576611E62080A" + "UID": "gdev-testdata" }, { - "kind": "panel", - "type": "graph" + "kind": "plugin", + "type": "panel", + "UID": "graph" } ] }, @@ -115,15 +132,17 @@ "uid": "graph_tests.json#7", "kind": "panel", "URL": "/d/graph_tests.json/panel-tests-graph?viewPanel=7", + "fields": { + "type": "text" + }, "references": [ { - "kind": "ds", - "type": "default.type", - "UID": "default.uid" + "kind": "ds" }, { - "kind": "panel", - "type": "text" + "kind": "plugin", + "type": "panel", + "UID": "text" } ] }, @@ -132,15 +151,18 @@ "kind": "panel", "name": "null value connected", "URL": "/d/graph_tests.json/panel-tests-graph?viewPanel=8", + "fields": { + "type": "graph" + }, "references": [ { "kind": "ds", - "type": "testdata", - "UID": "PD8C576611E62080A" + "UID": "gdev-testdata" }, { - "kind": "panel", - "type": "graph" + "kind": "plugin", + "type": "panel", + "UID": "graph" } ] }, @@ -149,15 +171,18 @@ "kind": "panel", "name": "null value null as zero", "URL": "/d/graph_tests.json/panel-tests-graph?viewPanel=10", + "fields": { + "type": "graph" + }, "references": [ { "kind": "ds", - "type": "testdata", - "UID": "PD8C576611E62080A" + "UID": "gdev-testdata" }, { - "kind": "panel", - "type": "graph" + "kind": "plugin", + "type": "panel", + "UID": "graph" } ] }, @@ -165,15 +190,17 @@ "uid": "graph_tests.json#13", "kind": "panel", "URL": "/d/graph_tests.json/panel-tests-graph?viewPanel=13", + "fields": { + "type": "text" + }, "references": [ { - "kind": "ds", - "type": "default.type", - "UID": "default.uid" + "kind": "ds" }, { - "kind": "panel", - "type": "text" + "kind": "plugin", + "type": "panel", + "UID": "text" } ] }, @@ -182,15 +209,18 @@ "kind": "panel", "name": "Stacking value ontop of nulls", "URL": "/d/graph_tests.json/panel-tests-graph?viewPanel=9", + "fields": { + "type": "graph" + }, "references": [ { "kind": "ds", - "type": "testdata", - "UID": "PD8C576611E62080A" + "UID": "gdev-testdata" }, { - "kind": "panel", - "type": "graph" + "kind": "plugin", + "type": "panel", + "UID": "graph" } ] }, @@ -198,15 +228,17 @@ "uid": "graph_tests.json#14", "kind": "panel", "URL": "/d/graph_tests.json/panel-tests-graph?viewPanel=14", + "fields": { + "type": "text" + }, "references": [ { - "kind": "ds", - "type": "default.type", - "UID": "default.uid" + "kind": "ds" }, { - "kind": "panel", - "type": "text" + "kind": "plugin", + "type": "panel", + "UID": "text" } ] }, @@ -215,15 +247,18 @@ "kind": "panel", "name": "Stacking all series null segment", "URL": "/d/graph_tests.json/panel-tests-graph?viewPanel=12", + "fields": { + "type": "graph" + }, "references": [ { "kind": "ds", - "type": "testdata", - "UID": "PD8C576611E62080A" + "UID": "gdev-testdata" }, { - "kind": "panel", - "type": "graph" + "kind": "plugin", + "type": "panel", + "UID": "graph" } ] }, @@ -231,15 +266,17 @@ "uid": "graph_tests.json#15", "kind": "panel", "URL": "/d/graph_tests.json/panel-tests-graph?viewPanel=15", + "fields": { + "type": "text" + }, "references": [ { - "kind": "ds", - "type": "default.type", - "UID": "default.uid" + "kind": "ds" }, { - "kind": "panel", - "type": "text" + "kind": "plugin", + "type": "panel", + "UID": "text" } ] }, @@ -248,15 +285,18 @@ "kind": "panel", "name": "Null between points", "URL": "/d/graph_tests.json/panel-tests-graph?viewPanel=21", + "fields": { + "type": "graph" + }, "references": [ { "kind": "ds", - "type": "testdata", - "UID": "PD8C576611E62080A" + "UID": "gdev-testdata" }, { - "kind": "panel", - "type": "graph" + "kind": "plugin", + "type": "panel", + "UID": "graph" } ] }, @@ -264,15 +304,17 @@ "uid": "graph_tests.json#22", "kind": "panel", "URL": "/d/graph_tests.json/panel-tests-graph?viewPanel=22", + "fields": { + "type": "text" + }, "references": [ { - "kind": "ds", - "type": "default.type", - "UID": "default.uid" + "kind": "ds" }, { - "kind": "panel", - "type": "text" + "kind": "plugin", + "type": "panel", + "UID": "text" } ] }, @@ -281,15 +323,18 @@ "kind": "panel", "name": "Legend Table Single Series Should Take Minimum Height", "URL": "/d/graph_tests.json/panel-tests-graph?viewPanel=20", + "fields": { + "type": "graph" + }, "references": [ { "kind": "ds", - "type": "testdata", - "UID": "PD8C576611E62080A" + "UID": "gdev-testdata" }, { - "kind": "panel", - "type": "graph" + "kind": "plugin", + "type": "panel", + "UID": "graph" } ] }, @@ -298,15 +343,18 @@ "kind": "panel", "name": "Legend Table No Scroll Visible", "URL": "/d/graph_tests.json/panel-tests-graph?viewPanel=16", + "fields": { + "type": "graph" + }, "references": [ { "kind": "ds", - "type": "testdata", - "UID": "PD8C576611E62080A" + "UID": "gdev-testdata" }, { - "kind": "panel", - "type": "graph" + "kind": "plugin", + "type": "panel", + "UID": "graph" } ] }, @@ -315,15 +363,18 @@ "kind": "panel", "name": "Legend Table Should Scroll", "URL": "/d/graph_tests.json/panel-tests-graph?viewPanel=17", + "fields": { + "type": "graph" + }, "references": [ { "kind": "ds", - "type": "testdata", - "UID": "PD8C576611E62080A" + "UID": "gdev-testdata" }, { - "kind": "panel", - "type": "graph" + "kind": "plugin", + "type": "panel", + "UID": "graph" } ] }, @@ -332,15 +383,18 @@ "kind": "panel", "name": "Legend Table No Scroll Visible", "URL": "/d/graph_tests.json/panel-tests-graph?viewPanel=18", + "fields": { + "type": "graph" + }, "references": [ { "kind": "ds", - "type": "testdata", - "UID": "PD8C576611E62080A" + "UID": "gdev-testdata" }, { - "kind": "panel", - "type": "graph" + "kind": "plugin", + "type": "panel", + "UID": "graph" } ] }, @@ -349,37 +403,39 @@ "kind": "panel", "name": "Legend Table No Scroll Visible", "URL": "/d/graph_tests.json/panel-tests-graph?viewPanel=19", + "fields": { + "type": "graph" + }, "references": [ { "kind": "ds", - "type": "testdata", - "UID": "PD8C576611E62080A" + "UID": "gdev-testdata" }, { - "kind": "panel", - "type": "graph" + "kind": "plugin", + "type": "panel", + "UID": "graph" } ] } ], "references": [ { - "kind": "ds", - "type": "default.type", - "UID": "default.uid" + "kind": "ds" }, { "kind": "ds", - "type": "testdata", - "UID": "PD8C576611E62080A" + "UID": "gdev-testdata" }, { - "kind": "panel", - "type": "graph" + "kind": "plugin", + "type": "panel", + "UID": "graph" }, { - "kind": "panel", - "type": "text" + "kind": "plugin", + "type": "panel", + "UID": "text" } ] } \ No newline at end of file diff --git a/pkg/services/store/kind/dashboard/testdata/gdev-walk-graph_y_axis.json b/pkg/services/store/kind/dashboard/testdata/gdev-walk-graph_y_axis.json index 1d1bdc17964..d26897eaeef 100644 --- a/pkg/services/store/kind/dashboard/testdata/gdev-walk-graph_y_axis.json +++ b/pkg/services/store/kind/dashboard/testdata/gdev-walk-graph_y_axis.json @@ -14,15 +14,17 @@ "kind": "panel", "name": "Data from 0 - 10K (unit short)", "URL": "/d/graph_y_axis.json/panel-tests-graph-y-axis-ticks?viewPanel=7", + "fields": { + "type": "graph" + }, "references": [ { - "kind": "ds", - "type": "default.type", - "UID": "default.uid" + "kind": "ds" }, { - "kind": "panel", - "type": "graph" + "kind": "plugin", + "type": "panel", + "UID": "graph" } ] }, @@ -31,15 +33,17 @@ "kind": "panel", "name": "Data from 0 - 10K (unit bytes metric)", "URL": "/d/graph_y_axis.json/panel-tests-graph-y-axis-ticks?viewPanel=5", + "fields": { + "type": "graph" + }, "references": [ { - "kind": "ds", - "type": "default.type", - "UID": "default.uid" + "kind": "ds" }, { - "kind": "panel", - "type": "graph" + "kind": "plugin", + "type": "panel", + "UID": "graph" } ] }, @@ -48,15 +52,17 @@ "kind": "panel", "name": "Data from 0 - 10K (unit bytes IEC)", "URL": "/d/graph_y_axis.json/panel-tests-graph-y-axis-ticks?viewPanel=4", + "fields": { + "type": "graph" + }, "references": [ { - "kind": "ds", - "type": "default.type", - "UID": "default.uid" + "kind": "ds" }, { - "kind": "panel", - "type": "graph" + "kind": "plugin", + "type": "panel", + "UID": "graph" } ] }, @@ -65,15 +71,17 @@ "kind": "panel", "name": "Data from 0 - 10K (unit short)", "URL": "/d/graph_y_axis.json/panel-tests-graph-y-axis-ticks?viewPanel=2", + "fields": { + "type": "graph" + }, "references": [ { - "kind": "ds", - "type": "default.type", - "UID": "default.uid" + "kind": "ds" }, { - "kind": "panel", - "type": "graph" + "kind": "plugin", + "type": "panel", + "UID": "graph" } ] }, @@ -82,15 +90,17 @@ "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", + "fields": { + "type": "graph" + }, "references": [ { - "kind": "ds", - "type": "default.type", - "UID": "default.uid" + "kind": "ds" }, { - "kind": "panel", - "type": "graph" + "kind": "plugin", + "type": "panel", + "UID": "graph" } ] }, @@ -99,15 +109,17 @@ "kind": "panel", "name": "Data from 12000 - 30000 (unit ms)", "URL": "/d/graph_y_axis.json/panel-tests-graph-y-axis-ticks?viewPanel=6", + "fields": { + "type": "graph" + }, "references": [ { - "kind": "ds", - "type": "default.type", - "UID": "default.uid" + "kind": "ds" }, { - "kind": "panel", - "type": "graph" + "kind": "plugin", + "type": "panel", + "UID": "graph" } ] }, @@ -116,15 +128,17 @@ "kind": "panel", "name": "Data from 0 - 1B (unit short)", "URL": "/d/graph_y_axis.json/panel-tests-graph-y-axis-ticks?viewPanel=9", + "fields": { + "type": "graph" + }, "references": [ { - "kind": "ds", - "type": "default.type", - "UID": "default.uid" + "kind": "ds" }, { - "kind": "panel", - "type": "graph" + "kind": "plugin", + "type": "panel", + "UID": "graph" } ] }, @@ -133,15 +147,17 @@ "kind": "panel", "name": "Data from 0 - 1B (unit bytes)", "URL": "/d/graph_y_axis.json/panel-tests-graph-y-axis-ticks?viewPanel=10", + "fields": { + "type": "graph" + }, "references": [ { - "kind": "ds", - "type": "default.type", - "UID": "default.uid" + "kind": "ds" }, { - "kind": "panel", - "type": "graph" + "kind": "plugin", + "type": "panel", + "UID": "graph" } ] }, @@ -150,28 +166,29 @@ "kind": "panel", "name": "Data from 12000 - 30000 (unit ms)", "URL": "/d/graph_y_axis.json/panel-tests-graph-y-axis-ticks?viewPanel=8", + "fields": { + "type": "graph" + }, "references": [ { - "kind": "ds", - "type": "default.type", - "UID": "default.uid" + "kind": "ds" }, { - "kind": "panel", - "type": "graph" + "kind": "plugin", + "type": "panel", + "UID": "graph" } ] } ], "references": [ { - "kind": "ds", - "type": "default.type", - "UID": "default.uid" + "kind": "ds" }, { - "kind": "panel", - "type": "graph" + "kind": "plugin", + "type": "panel", + "UID": "graph" } ] } \ No newline at end of file diff --git a/pkg/services/store/kind/geojson/summary.go b/pkg/services/store/kind/geojson/summary.go new file mode 100644 index 00000000000..1c3141be65d --- /dev/null +++ b/pkg/services/store/kind/geojson/summary.go @@ -0,0 +1,71 @@ +package geojson + +import ( + "context" + "encoding/json" + "fmt" + "strings" + + "github.com/grafana/grafana/pkg/models" +) + +func GetObjectKindInfo() models.ObjectKindInfo { + return models.ObjectKindInfo{ + ID: models.StandardKindGeoJSON, + Name: "GeoJSON", + Description: "JSON formatted spatial data", + FileExtension: ".geojson", + MimeType: "application/json", + } +} + +// Very basic geojson validator +func GetObjectSummaryBuilder() models.ObjectSummaryBuilder { + return func(ctx context.Context, uid string, body []byte) (*models.ObjectSummary, []byte, error) { + var geojson map[string]interface{} + err := json.Unmarshal(body, &geojson) + if err != nil { + return nil, nil, err + } + + ftype, ok := geojson["type"].(string) + if !ok { + return nil, nil, fmt.Errorf("missing type") + } + + body, err = json.Marshal(geojson) + if err != nil { + return nil, nil, err + } + + summary := &models.ObjectSummary{ + Kind: models.StandardKindGeoJSON, + Name: guessNameFromUID(uid), + UID: uid, + Fields: map[string]interface{}{ + "type": ftype, + }, + } + + if ftype == "FeatureCollection" { + features, ok := geojson["features"].([]interface{}) + if ok { + summary.Fields["count"] = len(features) + } + } + + 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 +} diff --git a/pkg/services/store/kind/geojson/summary_test.go b/pkg/services/store/kind/geojson/summary_test.go new file mode 100644 index 00000000000..154b525c52f --- /dev/null +++ b/pkg/services/store/kind/geojson/summary_test.go @@ -0,0 +1,54 @@ +package geojson + +import ( + "context" + "encoding/json" + "os" + "testing" + + "github.com/stretchr/testify/require" +) + +func TestGeoJSONSummary(t *testing.T) { + builder := GetObjectSummaryBuilder() + geo := []byte(`{"type":"FeatureCo`) // invalid + _, _, err := builder(context.Background(), "hello", geo) + require.Error(t, err) + + geo = []byte(`{"type":"FeatureCollection","features":[]}`) + summary, out, err := builder(context.Background(), "hello", geo) + require.NoError(t, err) + require.NotEqual(t, geo, out) // wrote json + + asjson, err := json.MarshalIndent(summary, "", " ") + //fmt.Printf(string(asjson)) + require.NoError(t, err) + require.JSONEq(t, `{ + "uid": "hello", + "kind": "geojson", + "name": "hello", + "fields": { + "type": "FeatureCollection", + "count": 0 + } + }`, string(asjson)) + + // Ignore gosec warning G304 since it's a test + // nolint:gosec + airports, err := os.ReadFile("../../../../../public/gazetteer/airports.geojson") + require.NoError(t, err) + summary, _, err = builder(context.Background(), "gaz/airports.geojson", airports) + require.NoError(t, err) + asjson, err = json.MarshalIndent(summary, "", " ") + //fmt.Printf(string(asjson)) + require.NoError(t, err) + require.JSONEq(t, `{ + "uid": "gaz/airports.geojson", + "kind": "geojson", + "name": "airports", + "fields": { + "type": "FeatureCollection", + "count": 888 + } + }`, string(asjson)) +} diff --git a/pkg/services/store/kind/registry.go b/pkg/services/store/kind/registry.go index 66023abbd78..edebae138a4 100644 --- a/pkg/services/store/kind/registry.go +++ b/pkg/services/store/kind/registry.go @@ -7,9 +7,9 @@ import ( "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/geojson" "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" @@ -29,10 +29,18 @@ func NewKindRegistry() KindRegistry { info: playlist.GetObjectKindInfo(), builder: playlist.GetObjectSummaryBuilder(), } + kinds[models.StandardKindDashboard] = &kindValues{ + info: dashboard.GetObjectKindInfo(), + builder: dashboard.GetObjectSummaryBuilder(), + } kinds[models.StandardKindPNG] = &kindValues{ info: png.GetObjectKindInfo(), builder: png.GetObjectSummaryBuilder(), } + kinds[models.StandardKindGeoJSON] = &kindValues{ + info: geojson.GetObjectKindInfo(), + builder: geojson.GetObjectSummaryBuilder(), + } // FIXME -- these are registered because existing tests use them for _, k := range []string{"dummy", "kind1", "kind2", "kind3"} { @@ -52,13 +60,9 @@ func NewKindRegistry() KindRegistry { } // 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 { +func ProvideService(cfg *setting.Cfg, renderer rendering.Service) KindRegistry { reg := NewKindRegistry() - // Register Dashboard support - //----------------------- - _ = reg.Register(dashboard.GetObjectKindInfo(), dashboard.NewDashboardSummary(sql)) - // Register SVG support //----------------------- info := svg.GetObjectKindInfo() diff --git a/pkg/services/store/kind/registry_test.go b/pkg/services/store/kind/registry_test.go index d645dc8d522..f3e9a78bc37 100644 --- a/pkg/services/store/kind/registry_test.go +++ b/pkg/services/store/kind/registry_test.go @@ -19,7 +19,9 @@ func TestKindRegistry(t *testing.T) { ids = append(ids, k.ID) } require.Equal(t, []string{ + "dashboard", "dummy", + "geojson", "kind1", "kind2", "kind3",