mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
Search: Allowed actions (#52529)
This commit is contained in:
parent
ce04a01ae9
commit
bcfa4fabf6
257
pkg/services/searchV2/allowed_actions.go
Normal file
257
pkg/services/searchV2/allowed_actions.go
Normal file
@ -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
|
||||||
|
}
|
119
pkg/services/searchV2/allowed_actions_test.go
Normal file
119
pkg/services/searchV2/allowed_actions_test.go
Normal file
@ -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)
|
||||||
|
}
|
||||||
|
}
|
@ -18,9 +18,10 @@ type PermissionFilter struct {
|
|||||||
type entityKind string
|
type entityKind string
|
||||||
|
|
||||||
const (
|
const (
|
||||||
entityKindPanel entityKind = "panel"
|
entityKindPanel entityKind = "panel"
|
||||||
entityKindDashboard entityKind = "dashboard"
|
entityKindDashboard entityKind = "dashboard"
|
||||||
entityKindFolder entityKind = "folder"
|
entityKindFolder entityKind = "folder"
|
||||||
|
entityKindDatasource entityKind = "datasource"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (r entityKind) IsValid() bool {
|
func (r entityKind) IsValid() bool {
|
||||||
|
@ -175,5 +175,13 @@ func (s *StandardSearchService) DoDashboardQuery(ctx context.Context, user *back
|
|||||||
return rsp
|
return rsp
|
||||||
}
|
}
|
||||||
|
|
||||||
return doSearchQuery(ctx, s.logger, index, filter, q, s.extender.GetQueryExtender(q), s.cfg.AppSubURL)
|
response := doSearchQuery(ctx, s.logger, index, filter, q, s.extender.GetQueryExtender(q), s.cfg.AppSubURL)
|
||||||
|
|
||||||
|
if q.WithAllowedActions {
|
||||||
|
if err := s.addAllowedActionsField(ctx, orgID, signedInUser, response); err != nil {
|
||||||
|
s.logger.Error("error when adding the allowedActions field", "err", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return response
|
||||||
}
|
}
|
||||||
|
321
pkg/services/searchV2/testdata/allowed_actions_scope_all.golden.jsonc
vendored
Normal file
321
pkg/services/searchV2/testdata/allowed_actions_scope_all.golden.jsonc
vendored
Normal file
@ -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"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
]
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
265
pkg/services/searchV2/testdata/allowed_actions_scope_uids.golden.jsonc
vendored
Normal file
265
pkg/services/searchV2/testdata/allowed_actions_scope_uids.golden.jsonc
vendored
Normal file
@ -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": []
|
||||||
|
}
|
||||||
|
]
|
||||||
|
]
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
155
pkg/services/searchV2/testdata/search_response_frame.json
vendored
Normal file
155
pkg/services/searchV2/testdata/search_response_frame.json
vendored
Normal file
@ -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"
|
||||||
|
]
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
@ -14,21 +14,21 @@ type FacetField struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type DashboardQuery struct {
|
type DashboardQuery struct {
|
||||||
Query string `json:"query"`
|
Query string `json:"query"`
|
||||||
Location string `json:"location,omitempty"` // parent folder ID
|
Location string `json:"location,omitempty"` // parent folder ID
|
||||||
Sort string `json:"sort,omitempty"` // field ASC/DESC
|
Sort string `json:"sort,omitempty"` // field ASC/DESC
|
||||||
Datasource string `json:"ds_uid,omitempty"` // "datasource" collides with the JSON value at the same leel :()
|
Datasource string `json:"ds_uid,omitempty"` // "datasource" collides with the JSON value at the same leel :()
|
||||||
Tags []string `json:"tags,omitempty"`
|
Tags []string `json:"tags,omitempty"`
|
||||||
Kind []string `json:"kind,omitempty"`
|
Kind []string `json:"kind,omitempty"`
|
||||||
PanelType string `json:"panel_type,omitempty"`
|
PanelType string `json:"panel_type,omitempty"`
|
||||||
UIDs []string `json:"uid,omitempty"`
|
UIDs []string `json:"uid,omitempty"`
|
||||||
Explain bool `json:"explain,omitempty"` // adds details on why document matched
|
Explain bool `json:"explain,omitempty"` // adds details on why document matched
|
||||||
Facet []FacetField `json:"facet,omitempty"`
|
WithAllowedActions bool `json:"withAllowedActions,omitempty"` // adds allowed actions per entity
|
||||||
SkipLocation bool `json:"skipLocation,omitempty"`
|
Facet []FacetField `json:"facet,omitempty"`
|
||||||
AccessInfo bool `json:"accessInfo,omitempty"` // adds field for access control
|
SkipLocation bool `json:"skipLocation,omitempty"`
|
||||||
HasPreview string `json:"hasPreview,omitempty"` // the light|dark theme
|
HasPreview string `json:"hasPreview,omitempty"` // the light|dark theme
|
||||||
Limit int `json:"limit,omitempty"` // explicit page size
|
Limit int `json:"limit,omitempty"` // explicit page size
|
||||||
From int `json:"from,omitempty"` // for paging
|
From int `json:"from,omitempty"` // for paging
|
||||||
}
|
}
|
||||||
|
|
||||||
type SearchService interface {
|
type SearchService interface {
|
||||||
|
@ -14,6 +14,7 @@ export interface Props {
|
|||||||
const tabs = [
|
const tabs = [
|
||||||
{ label: 'Score', value: 'score' },
|
{ label: 'Score', value: 'score' },
|
||||||
{ label: 'Fields', value: 'fields' },
|
{ label: 'Fields', value: 'fields' },
|
||||||
|
{ label: 'Allowed actions', value: 'allowed_actions' },
|
||||||
];
|
];
|
||||||
|
|
||||||
export function ExplainScorePopup({ name, explain, frame, row }: Props) {
|
export function ExplainScorePopup({ name, explain, frame, row }: Props) {
|
||||||
@ -51,6 +52,21 @@ export function ExplainScorePopup({ name, explain, frame, row }: Props) {
|
|||||||
<DataHoverView data={frame} rowIndex={row} />
|
<DataHoverView data={frame} rowIndex={row} />
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
{activeTab === tabs[2].value && (
|
||||||
|
<CodeEditor
|
||||||
|
width="100%"
|
||||||
|
height="70vh"
|
||||||
|
language="json"
|
||||||
|
showLineNumbers={false}
|
||||||
|
showMiniMap={false}
|
||||||
|
value={(() => {
|
||||||
|
const allowedActions = frame.fields.find((f) => f.name === 'allowed_actions')?.values?.get(row);
|
||||||
|
const dsUids = frame.fields.find((f) => f.name === 'ds_uid')?.values?.get(row);
|
||||||
|
return JSON.stringify({ dsUids: dsUids ?? [], allowedActions: allowedActions ?? [] }, null, 2);
|
||||||
|
})()}
|
||||||
|
readOnly={false}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
</TabContent>
|
</TabContent>
|
||||||
</Modal>
|
</Modal>
|
||||||
);
|
);
|
||||||
|
@ -65,6 +65,7 @@ export const SearchView = ({
|
|||||||
location: folderDTO?.uid, // This will scope all results to the prefix
|
location: folderDTO?.uid, // This will scope all results to the prefix
|
||||||
sort: query.sort?.value,
|
sort: query.sort?.value,
|
||||||
explain: query.explain,
|
explain: query.explain,
|
||||||
|
withAllowedActions: query.explain, // allowedActions are currently not used for anything on the UI and added only in `explain` mode
|
||||||
};
|
};
|
||||||
|
|
||||||
// Only dashboards have additional properties
|
// Only dashboards have additional properties
|
||||||
|
@ -18,6 +18,7 @@ export interface SearchQuery {
|
|||||||
id?: number[];
|
id?: number[];
|
||||||
facet?: FacetField[];
|
facet?: FacetField[];
|
||||||
explain?: boolean;
|
explain?: boolean;
|
||||||
|
withAllowedActions?: boolean;
|
||||||
accessInfo?: boolean;
|
accessInfo?: boolean;
|
||||||
hasPreview?: string; // theme
|
hasPreview?: string; // theme
|
||||||
limit?: number;
|
limit?: number;
|
||||||
|
Loading…
Reference in New Issue
Block a user