mirror of https://github.com/grafana/grafana
Search: Allowed actions (#52529)
parent
ce04a01ae9
commit
bcfa4fabf6
@ -0,0 +1,257 @@ |
||||
package searchV2 |
||||
|
||||
import ( |
||||
"context" |
||||
"encoding/json" |
||||
"errors" |
||||
"sort" |
||||
|
||||
"github.com/grafana/grafana-plugin-sdk-go/backend" |
||||
"github.com/grafana/grafana-plugin-sdk-go/data" |
||||
"github.com/grafana/grafana/pkg/models" |
||||
"github.com/grafana/grafana/pkg/services/accesscontrol" |
||||
"github.com/grafana/grafana/pkg/services/dashboards" |
||||
"github.com/grafana/grafana/pkg/services/datasources" |
||||
) |
||||
|
||||
func (s *StandardSearchService) addAllowedActionsField(ctx context.Context, orgId int64, user *models.SignedInUser, response *backend.DataResponse) error { |
||||
references, err := getEntityReferences(response) |
||||
if err != nil { |
||||
return err |
||||
} |
||||
|
||||
allAllowedActions, err := s.createAllowedActions(ctx, orgId, user, references) |
||||
if err != nil { |
||||
return err |
||||
} |
||||
|
||||
if len(response.Frames) == 0 { |
||||
return errors.New("empty response") |
||||
} |
||||
|
||||
frame := response.Frames[0] |
||||
|
||||
allowedActionsField := data.NewFieldFromFieldType(data.FieldTypeJSON, len(allAllowedActions)) |
||||
allowedActionsField.Name = "allowed_actions" |
||||
frame.Fields = append(frame.Fields, allowedActionsField) |
||||
|
||||
for i, actions := range allAllowedActions { |
||||
js, _ := json.Marshal(actions) |
||||
jsb := json.RawMessage(js) |
||||
allowedActionsField.Set(i, jsb) |
||||
} |
||||
|
||||
return nil |
||||
} |
||||
|
||||
type allowedActions struct { |
||||
EntityKind entityKind `json:"kind"` |
||||
UID string `json:"uid"` |
||||
Actions []string `json:"actions"` |
||||
} |
||||
|
||||
func (s *StandardSearchService) createAllowedActions(ctx context.Context, orgId int64, user *models.SignedInUser, references []entityReferences) ([][]allowedActions, error) { |
||||
uidsPerKind := make(map[entityKind][]string) |
||||
for _, refs := range references { |
||||
if _, ok := uidsPerKind[refs.entityKind]; !ok { |
||||
uidsPerKind[refs.entityKind] = []string{} |
||||
} |
||||
|
||||
uidsPerKind[refs.entityKind] = append(uidsPerKind[refs.entityKind], refs.uid) |
||||
|
||||
if len(refs.dsUids) > 0 { |
||||
if _, ok := uidsPerKind[entityKindDatasource]; !ok { |
||||
uidsPerKind[entityKindDatasource] = []string{} |
||||
} |
||||
|
||||
uidsPerKind[entityKindDatasource] = append(uidsPerKind[entityKindDatasource], refs.dsUids...) |
||||
} |
||||
} |
||||
|
||||
allowedActionsByUid := make(map[entityKind]map[string][]string) |
||||
|
||||
for entKind, uids := range uidsPerKind { |
||||
if entKind == entityKindPanel { |
||||
emptyAllowedActions := make(map[string][]string) |
||||
for _, uid := range uids { |
||||
emptyAllowedActions[uid] = []string{} |
||||
} |
||||
allowedActionsByUid[entityKindPanel] = emptyAllowedActions |
||||
} |
||||
|
||||
var prefix string |
||||
switch entKind { |
||||
case entityKindFolder: |
||||
prefix = dashboards.ScopeFoldersPrefix |
||||
case entityKindDatasource: |
||||
prefix = datasources.ScopePrefix |
||||
case entityKindDashboard: |
||||
prefix = dashboards.ScopeDashboardsPrefix |
||||
default: |
||||
continue |
||||
} |
||||
|
||||
allowedActionsByUid[entKind] = s.getAllowedActionsByUid(ctx, user, orgId, prefix, uids) |
||||
} |
||||
|
||||
dsActionsByUid, ok := allowedActionsByUid[entityKindDatasource] |
||||
if !ok { |
||||
dsActionsByUid = make(map[string][]string) |
||||
} |
||||
|
||||
var out [][]allowedActions |
||||
for _, ref := range references { |
||||
var actions []allowedActions |
||||
|
||||
selfActions := make([]string, 0) |
||||
if selfKindActions, ok := allowedActionsByUid[ref.entityKind]; ok { |
||||
if self, ok := selfKindActions[ref.uid]; ok && len(self) > 0 { |
||||
selfActions = self |
||||
} |
||||
} |
||||
|
||||
actions = append(actions, allowedActions{ |
||||
EntityKind: ref.entityKind, |
||||
UID: ref.uid, |
||||
Actions: selfActions, |
||||
}) |
||||
|
||||
for _, dsUid := range ref.dsUids { |
||||
dsActions := make([]string, 0) |
||||
if dsAct, ok := dsActionsByUid[dsUid]; ok { |
||||
dsActions = dsAct |
||||
} |
||||
|
||||
actions = append(actions, allowedActions{ |
||||
EntityKind: entityKindDatasource, |
||||
UID: dsUid, |
||||
Actions: dsActions, |
||||
}) |
||||
} |
||||
|
||||
out = append(out, actions) |
||||
} |
||||
|
||||
return out, nil |
||||
} |
||||
|
||||
func (s *StandardSearchService) getAllowedActionsByUid(ctx context.Context, user *models.SignedInUser, |
||||
orgID int64, prefix string, resourceIDs []string) map[string][]string { |
||||
if s.ac.IsDisabled() { |
||||
return map[string][]string{} |
||||
} |
||||
|
||||
if user.Permissions == nil { |
||||
return map[string][]string{} |
||||
} |
||||
|
||||
permissions, ok := user.Permissions[orgID] |
||||
if !ok { |
||||
return map[string][]string{} |
||||
} |
||||
|
||||
uidsAsMap := make(map[string]bool) |
||||
for _, uid := range resourceIDs { |
||||
uidsAsMap[uid] = true |
||||
} |
||||
|
||||
out := make(map[string][]string) |
||||
resp := accesscontrol.GetResourcesMetadata(ctx, permissions, prefix, uidsAsMap) |
||||
for uid, meta := range resp { |
||||
var actions []string |
||||
for action := range meta { |
||||
actions = append(actions, action) |
||||
} |
||||
sort.Strings(actions) |
||||
out[uid] = actions |
||||
} |
||||
return out |
||||
} |
||||
|
||||
type entityReferences struct { |
||||
entityKind entityKind |
||||
uid string |
||||
dsUids []string |
||||
} |
||||
|
||||
func getEntityReferences(resp *backend.DataResponse) ([]entityReferences, error) { |
||||
if resp == nil { |
||||
return nil, errors.New("nil response") |
||||
} |
||||
|
||||
if resp.Error != nil { |
||||
return nil, resp.Error |
||||
} |
||||
|
||||
if len(resp.Frames) == 0 { |
||||
return nil, errors.New("empty response") |
||||
} |
||||
|
||||
frame := resp.Frames[0] |
||||
|
||||
kindField, idx := frame.FieldByName("kind") |
||||
if idx == -1 { |
||||
return nil, errors.New("no kind field") |
||||
} |
||||
|
||||
dsUidField, idx := frame.FieldByName("ds_uid") |
||||
if idx == -1 { |
||||
return nil, errors.New("no ds_uid field") |
||||
} |
||||
uidField, idx := frame.FieldByName("uid") |
||||
if idx == -1 { |
||||
return nil, errors.New("no dash_uid field") |
||||
} |
||||
|
||||
if dsUidField.Len() != uidField.Len() { |
||||
return nil, errors.New("mismatched lengths") |
||||
} |
||||
|
||||
var out []entityReferences |
||||
for i := 0; i < dsUidField.Len(); i++ { |
||||
kind, ok := kindField.At(i).(string) |
||||
if !ok || kind == "" { |
||||
return nil, errors.New("invalid value in kind field") |
||||
} |
||||
|
||||
uid, ok := uidField.At(i).(string) |
||||
if !ok || uid == "" { |
||||
return nil, errors.New("invalid value in uid field") |
||||
} |
||||
|
||||
if entityKind(kind) != entityKindDashboard { |
||||
out = append(out, entityReferences{ |
||||
entityKind: entityKind(kind), |
||||
uid: uid, |
||||
}) |
||||
continue |
||||
} |
||||
|
||||
uidField, ok := uidField.At(i).(string) |
||||
if !ok || uidField == "" { |
||||
return nil, errors.New("invalid value in dash_uid field") |
||||
} |
||||
|
||||
rawDsUids, ok := dsUidField.At(i).(*json.RawMessage) |
||||
if !ok { |
||||
return nil, errors.New("invalid value in ds_uid field") |
||||
} |
||||
|
||||
var uids []string |
||||
if rawDsUids != nil { |
||||
jsonValue, err := rawDsUids.MarshalJSON() |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
|
||||
err = json.Unmarshal(jsonValue, &uids) |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
} |
||||
|
||||
out = append(out, entityReferences{entityKind: entityKindDashboard, uid: uid, dsUids: uids}) |
||||
} |
||||
|
||||
return out, nil |
||||
} |
@ -0,0 +1,119 @@ |
||||
package searchV2 |
||||
|
||||
import ( |
||||
"context" |
||||
_ "embed" |
||||
"fmt" |
||||
"testing" |
||||
|
||||
"github.com/grafana/grafana-plugin-sdk-go/backend" |
||||
"github.com/grafana/grafana-plugin-sdk-go/data" |
||||
"github.com/grafana/grafana-plugin-sdk-go/experimental" |
||||
"github.com/grafana/grafana/pkg/models" |
||||
ac "github.com/grafana/grafana/pkg/services/accesscontrol" |
||||
accesscontrolmock "github.com/grafana/grafana/pkg/services/accesscontrol/mock" |
||||
"github.com/grafana/grafana/pkg/services/dashboards" |
||||
"github.com/grafana/grafana/pkg/services/datasources" |
||||
"github.com/stretchr/testify/require" |
||||
) |
||||
|
||||
var ( |
||||
//go:embed testdata/search_response_frame.json
|
||||
exampleListFrameJSON string |
||||
|
||||
orgId = int64(1) |
||||
permissionsWithScopeAll = map[string][]string{ |
||||
datasources.ActionIDRead: {datasources.ScopeAll}, |
||||
datasources.ActionDelete: {datasources.ScopeAll}, |
||||
ac.ActionDatasourcesExplore: {datasources.ScopeAll}, |
||||
datasources.ActionQuery: {datasources.ScopeAll}, |
||||
datasources.ActionRead: {datasources.ScopeAll}, |
||||
datasources.ActionWrite: {datasources.ScopeAll}, |
||||
datasources.ActionPermissionsRead: {datasources.ScopeAll}, |
||||
datasources.ActionPermissionsWrite: {datasources.ScopeAll}, |
||||
|
||||
dashboards.ActionFoldersCreate: {dashboards.ScopeFoldersAll}, |
||||
dashboards.ActionFoldersRead: {dashboards.ScopeFoldersAll}, |
||||
dashboards.ActionFoldersWrite: {dashboards.ScopeFoldersAll}, |
||||
dashboards.ActionFoldersDelete: {dashboards.ScopeFoldersAll}, |
||||
dashboards.ActionFoldersPermissionsRead: {dashboards.ScopeFoldersAll}, |
||||
dashboards.ActionFoldersPermissionsWrite: {dashboards.ScopeFoldersAll}, |
||||
|
||||
dashboards.ActionDashboardsCreate: {dashboards.ScopeDashboardsAll}, |
||||
dashboards.ActionDashboardsRead: {dashboards.ScopeDashboardsAll}, |
||||
dashboards.ActionDashboardsWrite: {dashboards.ScopeDashboardsAll}, |
||||
dashboards.ActionDashboardsDelete: {dashboards.ScopeDashboardsAll}, |
||||
dashboards.ActionDashboardsPermissionsRead: {dashboards.ScopeDashboardsAll}, |
||||
dashboards.ActionDashboardsPermissionsWrite: {dashboards.ScopeDashboardsAll}, |
||||
} |
||||
permissionsWithUidScopes = map[string][]string{ |
||||
datasources.ActionIDRead: {}, |
||||
datasources.ActionDelete: {}, |
||||
ac.ActionDatasourcesExplore: {}, |
||||
datasources.ActionQuery: {}, |
||||
datasources.ActionRead: { |
||||
datasources.ScopeProvider.GetResourceScopeUID("datasource-2"), |
||||
datasources.ScopeProvider.GetResourceScopeUID("datasource-3"), |
||||
}, |
||||
datasources.ActionWrite: {}, |
||||
datasources.ActionPermissionsRead: {}, |
||||
datasources.ActionPermissionsWrite: {}, |
||||
|
||||
dashboards.ActionFoldersCreate: {}, |
||||
dashboards.ActionFoldersRead: { |
||||
dashboards.ScopeFoldersProvider.GetResourceScopeUID("ujaM1h6nz"), |
||||
}, |
||||
dashboards.ActionFoldersWrite: {}, |
||||
dashboards.ActionFoldersDelete: {}, |
||||
dashboards.ActionFoldersPermissionsRead: {}, |
||||
dashboards.ActionFoldersPermissionsWrite: {}, |
||||
|
||||
dashboards.ActionDashboardsCreate: {}, |
||||
dashboards.ActionDashboardsRead: {}, |
||||
dashboards.ActionDashboardsWrite: { |
||||
dashboards.ScopeDashboardsProvider.GetResourceScopeUID("7MeksYbmk"), |
||||
}, |
||||
dashboards.ActionDashboardsDelete: {}, |
||||
dashboards.ActionDashboardsPermissionsRead: {}, |
||||
dashboards.ActionDashboardsPermissionsWrite: {}, |
||||
} |
||||
) |
||||
|
||||
func service(t *testing.T) *StandardSearchService { |
||||
service, ok := ProvideService(nil, nil, nil, accesscontrolmock.New()).(*StandardSearchService) |
||||
require.True(t, ok) |
||||
return service |
||||
} |
||||
|
||||
func TestAllowedActionsForPermissionsWithScopeAll(t *testing.T) { |
||||
tests := []struct { |
||||
name string |
||||
permissions map[string][]string |
||||
}{ |
||||
{ |
||||
name: "scope_all", |
||||
permissions: permissionsWithScopeAll, |
||||
}, |
||||
{ |
||||
name: "scope_uids", |
||||
permissions: permissionsWithUidScopes, |
||||
}, |
||||
} |
||||
|
||||
for _, tt := range tests { |
||||
frame := &data.Frame{} |
||||
err := frame.UnmarshalJSON([]byte(exampleListFrameJSON)) |
||||
require.NoError(t, err) |
||||
|
||||
err = service(t).addAllowedActionsField(context.Background(), orgId, &models.SignedInUser{ |
||||
Permissions: map[int64]map[string][]string{ |
||||
orgId: tt.permissions, |
||||
}, |
||||
}, &backend.DataResponse{ |
||||
Frames: []*data.Frame{frame}, |
||||
}) |
||||
require.NoError(t, err) |
||||
|
||||
experimental.CheckGoldenJSONFrame(t, "testdata", fmt.Sprintf("allowed_actions_%s.golden", tt.name), frame, true) |
||||
} |
||||
} |
@ -0,0 +1,321 @@ |
||||
// 🌟 This was machine generated. Do not edit. 🌟 |
||||
// |
||||
// Frame[0] { |
||||
// "type": "search-results", |
||||
// "custom": { |
||||
// "count": 106, |
||||
// "locationInfo": { |
||||
// "yboVMzb7z": { |
||||
// "kind": "folder", |
||||
// "name": "gdev dashboards", |
||||
// "url": "/dashboards/f/yboVMzb7z/gdev-dashboards" |
||||
// } |
||||
// }, |
||||
// "sortBy": "name_sort" |
||||
// } |
||||
// } |
||||
// Name: Query results |
||||
// Dimensions: 9 Fields by 4 Rows |
||||
// +----------------+----------------+-------------------------+------------------+--------------------------------------+--------------------------+---------------------------+----------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ |
||||
// | Name: kind | Name: uid | Name: name | Name: panel_type | Name: url | Name: tags | Name: ds_uid | Name: location | Name: allowed_actions | |
||||
// | Labels: | Labels: | Labels: | Labels: | Labels: | Labels: | Labels: | Labels: | Labels: | |
||||
// | Type: []string | Type: []string | Type: []string | Type: []string | Type: []string | Type: []*json.RawMessage | Type: []*json.RawMessage | Type: []string | Type: []json.RawMessage | |
||||
// +----------------+----------------+-------------------------+------------------+--------------------------------------+--------------------------+---------------------------+----------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ |
||||
// | folder | ujaM1h6nz | abc2 | | /dashboards/f/ujaM1h6nz/abc2 | null | null | | [{"kind":"folder","uid":"ujaM1h6nz","actions":["folders.permissions:read","folders.permissions:write","folders:create","folders:delete","folders:read","folders:write"]}] | |
||||
// | dashboard | 7MeksYbmk | Alerting with TestData | | /d/7MeksYbmk/alerting-with-testdata | [ | [ | yboVMzb7z | [{"kind":"dashboard","uid":"7MeksYbmk","actions":["dashboards.permissions:read","dashboards.permissions:write","dashboards:create","dashboards:delete","dashboards:read","dashboards:write"]},{"kind":"datasource","uid":"datasource-1","actions":["datasources.id:read","datasources.permissions:read","datasources.permissions:write","datasources:delete","datasources:explore","datasources:query","datasources:read","datasources:write"]}] | |
||||
// | | | | | | "gdev", | "datasource-1" | | | |
||||
// | | | | | | "alerting" | ] | | | |
||||
// | | | | | | ] | | | | |
||||
// | dashboard | vmie2cmWz | Bar Gauge Demo | | /d/vmie2cmWz/bar-gauge-demo | [ | [ | yboVMzb7z | [{"kind":"dashboard","uid":"vmie2cmWz","actions":["dashboards.permissions:read","dashboards.permissions:write","dashboards:create","dashboards:delete","dashboards:read","dashboards:write"]},{"kind":"datasource","uid":"datasource-2","actions":["datasources.id:read","datasources.permissions:read","datasources.permissions:write","datasources:delete","datasources:explore","datasources:query","datasources:read","datasources:write"]},{"kind":"datasource","uid":"datasource-3","actions":["datasources.id:read","datasources.permissions:read","datasources.permissions:write","datasources:delete","datasources:explore","datasources:query","datasources:read","datasources:write"]},{"kind":"datasource","uid":"datasource-4","actions":["datasources.id:read","datasources.permissions:read","datasources.permissions:write","datasources:delete","datasources:explore","datasources:query","datasources:read","datasources:write"]}] | |
||||
// | | | | | | "gdev", | "datasource-2", | | | |
||||
// | | | | | | "demo" | "datasource-3", | | | |
||||
// | | | | | | ] | "datasource-4" | | | |
||||
// | | | | | | | ] | | | |
||||
// | dashboard | xMsQdBfWz | Bar Gauge Demo Unfilled | | /d/xMsQdBfWz/bar-gauge-demo-unfilled | [ | [] | yboVMzb7z | [{"kind":"dashboard","uid":"xMsQdBfWz","actions":["dashboards.permissions:read","dashboards.permissions:write","dashboards:create","dashboards:delete","dashboards:read","dashboards:write"]}] | |
||||
// | | | | | | "gdev", | | | | |
||||
// | | | | | | "demo" | | | | |
||||
// | | | | | | ] | | | | |
||||
// +----------------+----------------+-------------------------+------------------+--------------------------------------+--------------------------+---------------------------+----------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ |
||||
// |
||||
// |
||||
// 🌟 This was machine generated. Do not edit. 🌟 |
||||
{ |
||||
"frames": [ |
||||
{ |
||||
"schema": { |
||||
"name": "Query results", |
||||
"refId": "Search", |
||||
"meta": { |
||||
"type": "search-results", |
||||
"custom": { |
||||
"count": 106, |
||||
"locationInfo": { |
||||
"yboVMzb7z": { |
||||
"kind": "folder", |
||||
"name": "gdev dashboards", |
||||
"url": "/dashboards/f/yboVMzb7z/gdev-dashboards" |
||||
} |
||||
}, |
||||
"sortBy": "name_sort" |
||||
} |
||||
}, |
||||
"fields": [ |
||||
{ |
||||
"name": "kind", |
||||
"type": "string", |
||||
"typeInfo": { |
||||
"frame": "string" |
||||
} |
||||
}, |
||||
{ |
||||
"name": "uid", |
||||
"type": "string", |
||||
"typeInfo": { |
||||
"frame": "string" |
||||
} |
||||
}, |
||||
{ |
||||
"name": "name", |
||||
"type": "string", |
||||
"typeInfo": { |
||||
"frame": "string" |
||||
} |
||||
}, |
||||
{ |
||||
"name": "panel_type", |
||||
"type": "string", |
||||
"typeInfo": { |
||||
"frame": "string" |
||||
} |
||||
}, |
||||
{ |
||||
"name": "url", |
||||
"type": "string", |
||||
"typeInfo": { |
||||
"frame": "string" |
||||
}, |
||||
"config": { |
||||
"links": [ |
||||
{ |
||||
"title": "link", |
||||
"url": "${__value.text}" |
||||
} |
||||
] |
||||
} |
||||
}, |
||||
{ |
||||
"name": "tags", |
||||
"type": "other", |
||||
"typeInfo": { |
||||
"frame": "json.RawMessage", |
||||
"nullable": true |
||||
} |
||||
}, |
||||
{ |
||||
"name": "ds_uid", |
||||
"type": "other", |
||||
"typeInfo": { |
||||
"frame": "json.RawMessage", |
||||
"nullable": true |
||||
} |
||||
}, |
||||
{ |
||||
"name": "location", |
||||
"type": "string", |
||||
"typeInfo": { |
||||
"frame": "string" |
||||
} |
||||
}, |
||||
{ |
||||
"name": "allowed_actions", |
||||
"type": "other", |
||||
"typeInfo": { |
||||
"frame": "json.RawMessage" |
||||
} |
||||
} |
||||
] |
||||
}, |
||||
"data": { |
||||
"values": [ |
||||
[ |
||||
"folder", |
||||
"dashboard", |
||||
"dashboard", |
||||
"dashboard" |
||||
], |
||||
[ |
||||
"ujaM1h6nz", |
||||
"7MeksYbmk", |
||||
"vmie2cmWz", |
||||
"xMsQdBfWz" |
||||
], |
||||
[ |
||||
"abc2", |
||||
"Alerting with TestData", |
||||
"Bar Gauge Demo", |
||||
"Bar Gauge Demo Unfilled" |
||||
], |
||||
[ |
||||
"", |
||||
"", |
||||
"", |
||||
"" |
||||
], |
||||
[ |
||||
"/dashboards/f/ujaM1h6nz/abc2", |
||||
"/d/7MeksYbmk/alerting-with-testdata", |
||||
"/d/vmie2cmWz/bar-gauge-demo", |
||||
"/d/xMsQdBfWz/bar-gauge-demo-unfilled" |
||||
], |
||||
[ |
||||
null, |
||||
[ |
||||
"gdev", |
||||
"alerting" |
||||
], |
||||
[ |
||||
"gdev", |
||||
"demo" |
||||
], |
||||
[ |
||||
"gdev", |
||||
"demo" |
||||
] |
||||
], |
||||
[ |
||||
null, |
||||
[ |
||||
"datasource-1" |
||||
], |
||||
[ |
||||
"datasource-2", |
||||
"datasource-3", |
||||
"datasource-4" |
||||
], |
||||
[] |
||||
], |
||||
[ |
||||
"", |
||||
"yboVMzb7z", |
||||
"yboVMzb7z", |
||||
"yboVMzb7z" |
||||
], |
||||
[ |
||||
[ |
||||
{ |
||||
"kind": "folder", |
||||
"uid": "ujaM1h6nz", |
||||
"actions": [ |
||||
"folders.permissions:read", |
||||
"folders.permissions:write", |
||||
"folders:create", |
||||
"folders:delete", |
||||
"folders:read", |
||||
"folders:write" |
||||
] |
||||
} |
||||
], |
||||
[ |
||||
{ |
||||
"kind": "dashboard", |
||||
"uid": "7MeksYbmk", |
||||
"actions": [ |
||||
"dashboards.permissions:read", |
||||
"dashboards.permissions:write", |
||||
"dashboards:create", |
||||
"dashboards:delete", |
||||
"dashboards:read", |
||||
"dashboards:write" |
||||
] |
||||
}, |
||||
{ |
||||
"kind": "datasource", |
||||
"uid": "datasource-1", |
||||
"actions": [ |
||||
"datasources.id:read", |
||||
"datasources.permissions:read", |
||||
"datasources.permissions:write", |
||||
"datasources:delete", |
||||
"datasources:explore", |
||||
"datasources:query", |
||||
"datasources:read", |
||||
"datasources:write" |
||||
] |
||||
} |
||||
], |
||||
[ |
||||
{ |
||||
"kind": "dashboard", |
||||
"uid": "vmie2cmWz", |
||||
"actions": [ |
||||
"dashboards.permissions:read", |
||||
"dashboards.permissions:write", |
||||
"dashboards:create", |
||||
"dashboards:delete", |
||||
"dashboards:read", |
||||
"dashboards:write" |
||||
] |
||||
}, |
||||
{ |
||||
"kind": "datasource", |
||||
"uid": "datasource-2", |
||||
"actions": [ |
||||
"datasources.id:read", |
||||
"datasources.permissions:read", |
||||
"datasources.permissions:write", |
||||
"datasources:delete", |
||||
"datasources:explore", |
||||
"datasources:query", |
||||
"datasources:read", |
||||
"datasources:write" |
||||
] |
||||
}, |
||||
{ |
||||
"kind": "datasource", |
||||
"uid": "datasource-3", |
||||
"actions": [ |
||||
"datasources.id:read", |
||||
"datasources.permissions:read", |
||||
"datasources.permissions:write", |
||||
"datasources:delete", |
||||
"datasources:explore", |
||||
"datasources:query", |
||||
"datasources:read", |
||||
"datasources:write" |
||||
] |
||||
}, |
||||
{ |
||||
"kind": "datasource", |
||||
"uid": "datasource-4", |
||||
"actions": [ |
||||
"datasources.id:read", |
||||
"datasources.permissions:read", |
||||
"datasources.permissions:write", |
||||
"datasources:delete", |
||||
"datasources:explore", |
||||
"datasources:query", |
||||
"datasources:read", |
||||
"datasources:write" |
||||
] |
||||
} |
||||
], |
||||
[ |
||||
{ |
||||
"kind": "dashboard", |
||||
"uid": "xMsQdBfWz", |
||||
"actions": [ |
||||
"dashboards.permissions:read", |
||||
"dashboards.permissions:write", |
||||
"dashboards:create", |
||||
"dashboards:delete", |
||||
"dashboards:read", |
||||
"dashboards:write" |
||||
] |
||||
} |
||||
] |
||||
] |
||||
] |
||||
} |
||||
} |
||||
] |
||||
} |
@ -0,0 +1,265 @@ |
||||
// 🌟 This was machine generated. Do not edit. 🌟 |
||||
// |
||||
// Frame[0] { |
||||
// "type": "search-results", |
||||
// "custom": { |
||||
// "count": 106, |
||||
// "locationInfo": { |
||||
// "yboVMzb7z": { |
||||
// "kind": "folder", |
||||
// "name": "gdev dashboards", |
||||
// "url": "/dashboards/f/yboVMzb7z/gdev-dashboards" |
||||
// } |
||||
// }, |
||||
// "sortBy": "name_sort" |
||||
// } |
||||
// } |
||||
// Name: Query results |
||||
// Dimensions: 9 Fields by 4 Rows |
||||
// +----------------+----------------+-------------------------+------------------+--------------------------------------+--------------------------+---------------------------+----------------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ |
||||
// | Name: kind | Name: uid | Name: name | Name: panel_type | Name: url | Name: tags | Name: ds_uid | Name: location | Name: allowed_actions | |
||||
// | Labels: | Labels: | Labels: | Labels: | Labels: | Labels: | Labels: | Labels: | Labels: | |
||||
// | Type: []string | Type: []string | Type: []string | Type: []string | Type: []string | Type: []*json.RawMessage | Type: []*json.RawMessage | Type: []string | Type: []json.RawMessage | |
||||
// +----------------+----------------+-------------------------+------------------+--------------------------------------+--------------------------+---------------------------+----------------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ |
||||
// | folder | ujaM1h6nz | abc2 | | /dashboards/f/ujaM1h6nz/abc2 | null | null | | [{"kind":"folder","uid":"ujaM1h6nz","actions":["folders:read"]}] | |
||||
// | dashboard | 7MeksYbmk | Alerting with TestData | | /d/7MeksYbmk/alerting-with-testdata | [ | [ | yboVMzb7z | [{"kind":"dashboard","uid":"7MeksYbmk","actions":["dashboards:write"]},{"kind":"datasource","uid":"datasource-1","actions":[]}] | |
||||
// | | | | | | "gdev", | "datasource-1" | | | |
||||
// | | | | | | "alerting" | ] | | | |
||||
// | | | | | | ] | | | | |
||||
// | dashboard | vmie2cmWz | Bar Gauge Demo | | /d/vmie2cmWz/bar-gauge-demo | [ | [ | yboVMzb7z | [{"kind":"dashboard","uid":"vmie2cmWz","actions":[]},{"kind":"datasource","uid":"datasource-2","actions":["datasources:read"]},{"kind":"datasource","uid":"datasource-3","actions":["datasources:read"]},{"kind":"datasource","uid":"datasource-4","actions":[]}] | |
||||
// | | | | | | "gdev", | "datasource-2", | | | |
||||
// | | | | | | "demo" | "datasource-3", | | | |
||||
// | | | | | | ] | "datasource-4" | | | |
||||
// | | | | | | | ] | | | |
||||
// | dashboard | xMsQdBfWz | Bar Gauge Demo Unfilled | | /d/xMsQdBfWz/bar-gauge-demo-unfilled | [ | [] | yboVMzb7z | [{"kind":"dashboard","uid":"xMsQdBfWz","actions":[]}] | |
||||
// | | | | | | "gdev", | | | | |
||||
// | | | | | | "demo" | | | | |
||||
// | | | | | | ] | | | | |
||||
// +----------------+----------------+-------------------------+------------------+--------------------------------------+--------------------------+---------------------------+----------------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ |
||||
// |
||||
// |
||||
// 🌟 This was machine generated. Do not edit. 🌟 |
||||
{ |
||||
"frames": [ |
||||
{ |
||||
"schema": { |
||||
"name": "Query results", |
||||
"refId": "Search", |
||||
"meta": { |
||||
"type": "search-results", |
||||
"custom": { |
||||
"count": 106, |
||||
"locationInfo": { |
||||
"yboVMzb7z": { |
||||
"kind": "folder", |
||||
"name": "gdev dashboards", |
||||
"url": "/dashboards/f/yboVMzb7z/gdev-dashboards" |
||||
} |
||||
}, |
||||
"sortBy": "name_sort" |
||||
} |
||||
}, |
||||
"fields": [ |
||||
{ |
||||
"name": "kind", |
||||
"type": "string", |
||||
"typeInfo": { |
||||
"frame": "string" |
||||
} |
||||
}, |
||||
{ |
||||
"name": "uid", |
||||
"type": "string", |
||||
"typeInfo": { |
||||
"frame": "string" |
||||
} |
||||
}, |
||||
{ |
||||
"name": "name", |
||||
"type": "string", |
||||
"typeInfo": { |
||||
"frame": "string" |
||||
} |
||||
}, |
||||
{ |
||||
"name": "panel_type", |
||||
"type": "string", |
||||
"typeInfo": { |
||||
"frame": "string" |
||||
} |
||||
}, |
||||
{ |
||||
"name": "url", |
||||
"type": "string", |
||||
"typeInfo": { |
||||
"frame": "string" |
||||
}, |
||||
"config": { |
||||
"links": [ |
||||
{ |
||||
"title": "link", |
||||
"url": "${__value.text}" |
||||
} |
||||
] |
||||
} |
||||
}, |
||||
{ |
||||
"name": "tags", |
||||
"type": "other", |
||||
"typeInfo": { |
||||
"frame": "json.RawMessage", |
||||
"nullable": true |
||||
} |
||||
}, |
||||
{ |
||||
"name": "ds_uid", |
||||
"type": "other", |
||||
"typeInfo": { |
||||
"frame": "json.RawMessage", |
||||
"nullable": true |
||||
} |
||||
}, |
||||
{ |
||||
"name": "location", |
||||
"type": "string", |
||||
"typeInfo": { |
||||
"frame": "string" |
||||
} |
||||
}, |
||||
{ |
||||
"name": "allowed_actions", |
||||
"type": "other", |
||||
"typeInfo": { |
||||
"frame": "json.RawMessage" |
||||
} |
||||
} |
||||
] |
||||
}, |
||||
"data": { |
||||
"values": [ |
||||
[ |
||||
"folder", |
||||
"dashboard", |
||||
"dashboard", |
||||
"dashboard" |
||||
], |
||||
[ |
||||
"ujaM1h6nz", |
||||
"7MeksYbmk", |
||||
"vmie2cmWz", |
||||
"xMsQdBfWz" |
||||
], |
||||
[ |
||||
"abc2", |
||||
"Alerting with TestData", |
||||
"Bar Gauge Demo", |
||||
"Bar Gauge Demo Unfilled" |
||||
], |
||||
[ |
||||
"", |
||||
"", |
||||
"", |
||||
"" |
||||
], |
||||
[ |
||||
"/dashboards/f/ujaM1h6nz/abc2", |
||||
"/d/7MeksYbmk/alerting-with-testdata", |
||||
"/d/vmie2cmWz/bar-gauge-demo", |
||||
"/d/xMsQdBfWz/bar-gauge-demo-unfilled" |
||||
], |
||||
[ |
||||
null, |
||||
[ |
||||
"gdev", |
||||
"alerting" |
||||
], |
||||
[ |
||||
"gdev", |
||||
"demo" |
||||
], |
||||
[ |
||||
"gdev", |
||||
"demo" |
||||
] |
||||
], |
||||
[ |
||||
null, |
||||
[ |
||||
"datasource-1" |
||||
], |
||||
[ |
||||
"datasource-2", |
||||
"datasource-3", |
||||
"datasource-4" |
||||
], |
||||
[] |
||||
], |
||||
[ |
||||
"", |
||||
"yboVMzb7z", |
||||
"yboVMzb7z", |
||||
"yboVMzb7z" |
||||
], |
||||
[ |
||||
[ |
||||
{ |
||||
"kind": "folder", |
||||
"uid": "ujaM1h6nz", |
||||
"actions": [ |
||||
"folders:read" |
||||
] |
||||
} |
||||
], |
||||
[ |
||||
{ |
||||
"kind": "dashboard", |
||||
"uid": "7MeksYbmk", |
||||
"actions": [ |
||||
"dashboards:write" |
||||
] |
||||
}, |
||||
{ |
||||
"kind": "datasource", |
||||
"uid": "datasource-1", |
||||
"actions": [] |
||||
} |
||||
], |
||||
[ |
||||
{ |
||||
"kind": "dashboard", |
||||
"uid": "vmie2cmWz", |
||||
"actions": [] |
||||
}, |
||||
{ |
||||
"kind": "datasource", |
||||
"uid": "datasource-2", |
||||
"actions": [ |
||||
"datasources:read" |
||||
] |
||||
}, |
||||
{ |
||||
"kind": "datasource", |
||||
"uid": "datasource-3", |
||||
"actions": [ |
||||
"datasources:read" |
||||
] |
||||
}, |
||||
{ |
||||
"kind": "datasource", |
||||
"uid": "datasource-4", |
||||
"actions": [] |
||||
} |
||||
], |
||||
[ |
||||
{ |
||||
"kind": "dashboard", |
||||
"uid": "xMsQdBfWz", |
||||
"actions": [] |
||||
} |
||||
] |
||||
] |
||||
] |
||||
} |
||||
} |
||||
] |
||||
} |
@ -0,0 +1,155 @@ |
||||
{ |
||||
"schema": { |
||||
"name": "Query results", |
||||
"refId": "Search", |
||||
"meta": { |
||||
"type": "search-results", |
||||
"custom": { |
||||
"count": 106, |
||||
"locationInfo": { |
||||
"yboVMzb7z": { |
||||
"name": "gdev dashboards", |
||||
"kind": "folder", |
||||
"url": "/dashboards/f/yboVMzb7z/gdev-dashboards" |
||||
} |
||||
}, |
||||
"sortBy": "name_sort" |
||||
} |
||||
}, |
||||
"fields": [ |
||||
{ |
||||
"name": "kind", |
||||
"type": "string", |
||||
"typeInfo": { |
||||
"frame": "string" |
||||
} |
||||
}, |
||||
{ |
||||
"name": "uid", |
||||
"type": "string", |
||||
"typeInfo": { |
||||
"frame": "string" |
||||
} |
||||
}, |
||||
{ |
||||
"name": "name", |
||||
"type": "string", |
||||
"typeInfo": { |
||||
"frame": "string" |
||||
} |
||||
}, |
||||
{ |
||||
"name": "panel_type", |
||||
"type": "string", |
||||
"typeInfo": { |
||||
"frame": "string" |
||||
} |
||||
}, |
||||
{ |
||||
"name": "url", |
||||
"type": "string", |
||||
"typeInfo": { |
||||
"frame": "string" |
||||
}, |
||||
"config": { |
||||
"links": [ |
||||
{ |
||||
"title": "link", |
||||
"url": "${__value.text}" |
||||
} |
||||
] |
||||
} |
||||
}, |
||||
{ |
||||
"name": "tags", |
||||
"type": "other", |
||||
"typeInfo": { |
||||
"frame": "json.RawMessage", |
||||
"nullable": true |
||||
} |
||||
}, |
||||
{ |
||||
"name": "ds_uid", |
||||
"type": "other", |
||||
"typeInfo": { |
||||
"frame": "json.RawMessage", |
||||
"nullable": true |
||||
} |
||||
}, |
||||
{ |
||||
"name": "location", |
||||
"type": "string", |
||||
"typeInfo": { |
||||
"frame": "string" |
||||
} |
||||
} |
||||
] |
||||
}, |
||||
"data": { |
||||
"values": [ |
||||
[ |
||||
"folder", |
||||
"dashboard", |
||||
"dashboard", |
||||
"dashboard" |
||||
], |
||||
[ |
||||
"ujaM1h6nz", |
||||
"7MeksYbmk", |
||||
"vmie2cmWz", |
||||
"xMsQdBfWz" |
||||
], |
||||
[ |
||||
"abc2", |
||||
"Alerting with TestData", |
||||
"Bar Gauge Demo", |
||||
"Bar Gauge Demo Unfilled" |
||||
], |
||||
[ |
||||
"", |
||||
"", |
||||
"", |
||||
"" |
||||
], |
||||
[ |
||||
"/dashboards/f/ujaM1h6nz/abc2", |
||||
"/d/7MeksYbmk/alerting-with-testdata", |
||||
"/d/vmie2cmWz/bar-gauge-demo", |
||||
"/d/xMsQdBfWz/bar-gauge-demo-unfilled" |
||||
], |
||||
[ |
||||
null, |
||||
[ |
||||
"gdev", |
||||
"alerting" |
||||
], |
||||
[ |
||||
"gdev", |
||||
"demo" |
||||
], |
||||
[ |
||||
"gdev", |
||||
"demo" |
||||
] |
||||
], |
||||
[ |
||||
null, |
||||
[ |
||||
"datasource-1" |
||||
], |
||||
[ |
||||
"datasource-2", |
||||
"datasource-3", |
||||
"datasource-4" |
||||
], |
||||
[] |
||||
], |
||||
[ |
||||
"", |
||||
"yboVMzb7z", |
||||
"yboVMzb7z", |
||||
"yboVMzb7z" |
||||
] |
||||
] |
||||
} |
||||
} |
Loading…
Reference in new issue