mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
@@ -238,7 +238,6 @@ func (hs *HttpServer) registerRoutes() {
|
|||||||
r.Post("/db", bind(m.SaveDashboardCommand{}), wrap(PostDashboard))
|
r.Post("/db", bind(m.SaveDashboardCommand{}), wrap(PostDashboard))
|
||||||
|
|
||||||
r.Post("/calculate-diff", bind(dtos.CalculateDiffOptions{}), wrap(CalculateDashboardDiff))
|
r.Post("/calculate-diff", bind(dtos.CalculateDiffOptions{}), wrap(CalculateDashboardDiff))
|
||||||
r.Get("/file/:file", GetDashboardFromJsonFile)
|
|
||||||
r.Get("/home", wrap(GetHomeDashboard))
|
r.Get("/home", wrap(GetHomeDashboard))
|
||||||
r.Get("/tags", GetDashboardTags)
|
r.Get("/tags", GetDashboardTags)
|
||||||
r.Post("/import", bind(dtos.ImportDashboardCommand{}), wrap(ImportDashboard))
|
r.Post("/import", bind(dtos.ImportDashboardCommand{}), wrap(ImportDashboard))
|
||||||
|
|||||||
@@ -17,7 +17,6 @@ import (
|
|||||||
"github.com/grafana/grafana/pkg/plugins"
|
"github.com/grafana/grafana/pkg/plugins"
|
||||||
"github.com/grafana/grafana/pkg/services/alerting"
|
"github.com/grafana/grafana/pkg/services/alerting"
|
||||||
"github.com/grafana/grafana/pkg/services/guardian"
|
"github.com/grafana/grafana/pkg/services/guardian"
|
||||||
"github.com/grafana/grafana/pkg/services/search"
|
|
||||||
"github.com/grafana/grafana/pkg/setting"
|
"github.com/grafana/grafana/pkg/setting"
|
||||||
"github.com/grafana/grafana/pkg/util"
|
"github.com/grafana/grafana/pkg/util"
|
||||||
)
|
)
|
||||||
@@ -290,22 +289,6 @@ func addGettingStartedPanelToHomeDashboard(dash *simplejson.Json) {
|
|||||||
row.Set("panels", panels)
|
row.Set("panels", panels)
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetDashboardFromJsonFile(c *middleware.Context) {
|
|
||||||
file := c.Params(":file")
|
|
||||||
|
|
||||||
dashboard := search.GetDashboardFromJsonIndex(file)
|
|
||||||
if dashboard == nil {
|
|
||||||
c.JsonApiErr(404, "Dashboard not found", nil)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
dash := dtos.DashboardFullWithMeta{Dashboard: dashboard.Data}
|
|
||||||
dash.Meta.Type = m.DashTypeJson
|
|
||||||
dash.Meta.CanEdit = c.SignedInUser.HasRole(m.ROLE_READ_ONLY_EDITOR)
|
|
||||||
|
|
||||||
c.JSON(200, &dash)
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetDashboardVersions returns all dashboard versions as JSON
|
// GetDashboardVersions returns all dashboard versions as JSON
|
||||||
func GetDashboardVersions(c *middleware.Context) Response {
|
func GetDashboardVersions(c *middleware.Context) Response {
|
||||||
dashId := c.ParamsInt64(":dashboardId")
|
dashId := c.ParamsInt64(":dashboardId")
|
||||||
|
|||||||
@@ -16,16 +16,11 @@ func Search(c *middleware.Context) {
|
|||||||
limit := c.QueryInt("limit")
|
limit := c.QueryInt("limit")
|
||||||
dashboardType := c.Query("type")
|
dashboardType := c.Query("type")
|
||||||
folderId := c.QueryInt64("folderId")
|
folderId := c.QueryInt64("folderId")
|
||||||
mode := c.Query("mode")
|
|
||||||
|
|
||||||
if limit == 0 {
|
if limit == 0 {
|
||||||
limit = 1000
|
limit = 1000
|
||||||
}
|
}
|
||||||
|
|
||||||
if mode == "" {
|
|
||||||
mode = "list"
|
|
||||||
}
|
|
||||||
|
|
||||||
dbids := make([]int64, 0)
|
dbids := make([]int64, 0)
|
||||||
for _, id := range c.QueryStrings("dashboardIds") {
|
for _, id := range c.QueryStrings("dashboardIds") {
|
||||||
dashboardId, err := strconv.ParseInt(id, 10, 64)
|
dashboardId, err := strconv.ParseInt(id, 10, 64)
|
||||||
@@ -44,7 +39,6 @@ func Search(c *middleware.Context) {
|
|||||||
DashboardIds: dbids,
|
DashboardIds: dbids,
|
||||||
Type: dashboardType,
|
Type: dashboardType,
|
||||||
FolderId: folderId,
|
FolderId: folderId,
|
||||||
Mode: mode,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
err := bus.Dispatch(&searchQuery)
|
err := bus.Dispatch(&searchQuery)
|
||||||
|
|||||||
@@ -1,43 +1,17 @@
|
|||||||
package search
|
package search
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"log"
|
|
||||||
"path/filepath"
|
|
||||||
"sort"
|
"sort"
|
||||||
|
|
||||||
"github.com/grafana/grafana/pkg/bus"
|
"github.com/grafana/grafana/pkg/bus"
|
||||||
m "github.com/grafana/grafana/pkg/models"
|
m "github.com/grafana/grafana/pkg/models"
|
||||||
"github.com/grafana/grafana/pkg/setting"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
var jsonDashIndex *JsonDashIndex
|
|
||||||
|
|
||||||
func Init() {
|
func Init() {
|
||||||
bus.AddHandler("search", searchHandler)
|
bus.AddHandler("search", searchHandler)
|
||||||
|
|
||||||
jsonIndexCfg, _ := setting.Cfg.GetSection("dashboards.json")
|
|
||||||
|
|
||||||
if jsonIndexCfg == nil {
|
|
||||||
log.Fatal("Config section missing: dashboards.json")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
jsonIndexEnabled := jsonIndexCfg.Key("enabled").MustBool(false)
|
|
||||||
|
|
||||||
if jsonIndexEnabled {
|
|
||||||
jsonFilesPath := jsonIndexCfg.Key("path").String()
|
|
||||||
if !filepath.IsAbs(jsonFilesPath) {
|
|
||||||
jsonFilesPath = filepath.Join(setting.HomePath, jsonFilesPath)
|
|
||||||
}
|
|
||||||
|
|
||||||
jsonDashIndex = NewJsonDashIndex(jsonFilesPath)
|
|
||||||
go jsonDashIndex.updateLoop()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func searchHandler(query *Query) error {
|
func searchHandler(query *Query) error {
|
||||||
hits := make(HitList, 0)
|
|
||||||
|
|
||||||
dashQuery := FindPersistedDashboardsQuery{
|
dashQuery := FindPersistedDashboardsQuery{
|
||||||
Title: query.Title,
|
Title: query.Title,
|
||||||
SignedInUser: query.SignedInUser,
|
SignedInUser: query.SignedInUser,
|
||||||
@@ -45,35 +19,17 @@ func searchHandler(query *Query) error {
|
|||||||
DashboardIds: query.DashboardIds,
|
DashboardIds: query.DashboardIds,
|
||||||
Type: query.Type,
|
Type: query.Type,
|
||||||
FolderId: query.FolderId,
|
FolderId: query.FolderId,
|
||||||
Mode: query.Mode,
|
Tags: query.Tags,
|
||||||
|
Limit: query.Limit,
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := bus.Dispatch(&dashQuery); err != nil {
|
if err := bus.Dispatch(&dashQuery); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
hits := make(HitList, 0)
|
||||||
hits = append(hits, dashQuery.Result...)
|
hits = append(hits, dashQuery.Result...)
|
||||||
|
|
||||||
if jsonDashIndex != nil {
|
|
||||||
jsonHits, err := jsonDashIndex.Search(query)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
hits = append(hits, jsonHits...)
|
|
||||||
}
|
|
||||||
|
|
||||||
// filter out results with tag filter
|
|
||||||
if len(query.Tags) > 0 {
|
|
||||||
filtered := HitList{}
|
|
||||||
for _, hit := range hits {
|
|
||||||
if hasRequiredTags(query.Tags, hit.Tags) {
|
|
||||||
filtered = append(filtered, hit)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
hits = filtered
|
|
||||||
}
|
|
||||||
|
|
||||||
// sort main result array
|
// sort main result array
|
||||||
sort.Sort(hits)
|
sort.Sort(hits)
|
||||||
|
|
||||||
@@ -95,25 +51,6 @@ func searchHandler(query *Query) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func stringInSlice(a string, list []string) bool {
|
|
||||||
for _, b := range list {
|
|
||||||
if b == a {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
func hasRequiredTags(queryTags, hitTags []string) bool {
|
|
||||||
for _, queryTag := range queryTags {
|
|
||||||
if !stringInSlice(queryTag, hitTags) {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
func setIsStarredFlagOnSearchResults(userId int64, hits []*Hit) error {
|
func setIsStarredFlagOnSearchResults(userId int64, hits []*Hit) error {
|
||||||
query := m.GetUserStarsQuery{UserId: userId}
|
query := m.GetUserStarsQuery{UserId: userId}
|
||||||
if err := bus.Dispatch(&query); err != nil {
|
if err := bus.Dispatch(&query); err != nil {
|
||||||
@@ -128,10 +65,3 @@ func setIsStarredFlagOnSearchResults(userId int64, hits []*Hit) error {
|
|||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetDashboardFromJsonIndex(filename string) *m.Dashboard {
|
|
||||||
if jsonDashIndex == nil {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
return jsonDashIndex.GetDashboard(filename)
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -11,9 +11,7 @@ import (
|
|||||||
func TestSearch(t *testing.T) {
|
func TestSearch(t *testing.T) {
|
||||||
|
|
||||||
Convey("Given search query", t, func() {
|
Convey("Given search query", t, func() {
|
||||||
jsonDashIndex = NewJsonDashIndex("../../../public/dashboards/")
|
|
||||||
query := Query{Limit: 2000, SignedInUser: &m.SignedInUser{IsGrafanaAdmin: true}}
|
query := Query{Limit: 2000, SignedInUser: &m.SignedInUser{IsGrafanaAdmin: true}}
|
||||||
|
|
||||||
bus.AddHandler("test", func(query *FindPersistedDashboardsQuery) error {
|
bus.AddHandler("test", func(query *FindPersistedDashboardsQuery) error {
|
||||||
query.Result = HitList{
|
query.Result = HitList{
|
||||||
&Hit{Id: 16, Title: "CCAA", Type: "dash-db", Tags: []string{"BB", "AA"}},
|
&Hit{Id: 16, Title: "CCAA", Type: "dash-db", Tags: []string{"BB", "AA"}},
|
||||||
@@ -54,17 +52,5 @@ func TestSearch(t *testing.T) {
|
|||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
Convey("That filters by tag", func() {
|
|
||||||
query.Tags = []string{"BB", "AA"}
|
|
||||||
err := searchHandler(&query)
|
|
||||||
So(err, ShouldBeNil)
|
|
||||||
|
|
||||||
Convey("should return correct results", func() {
|
|
||||||
So(len(query.Result), ShouldEqual, 3)
|
|
||||||
So(query.Result[0].Title, ShouldEqual, "BBAA")
|
|
||||||
So(query.Result[2].Title, ShouldEqual, "CCAA")
|
|
||||||
})
|
|
||||||
|
|
||||||
})
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,137 +0,0 @@
|
|||||||
package search
|
|
||||||
|
|
||||||
import (
|
|
||||||
"os"
|
|
||||||
"path/filepath"
|
|
||||||
"strings"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/grafana/grafana/pkg/components/simplejson"
|
|
||||||
"github.com/grafana/grafana/pkg/log"
|
|
||||||
m "github.com/grafana/grafana/pkg/models"
|
|
||||||
)
|
|
||||||
|
|
||||||
type JsonDashIndex struct {
|
|
||||||
path string
|
|
||||||
items []*JsonDashIndexItem
|
|
||||||
}
|
|
||||||
|
|
||||||
type JsonDashIndexItem struct {
|
|
||||||
TitleLower string
|
|
||||||
TagsCsv string
|
|
||||||
Path string
|
|
||||||
Dashboard *m.Dashboard
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewJsonDashIndex(path string) *JsonDashIndex {
|
|
||||||
log.Info("Creating json dashboard index for path: %v", path)
|
|
||||||
|
|
||||||
index := JsonDashIndex{}
|
|
||||||
index.path = path
|
|
||||||
index.updateIndex()
|
|
||||||
return &index
|
|
||||||
}
|
|
||||||
|
|
||||||
func (index *JsonDashIndex) updateLoop() {
|
|
||||||
ticker := time.NewTicker(time.Minute)
|
|
||||||
for {
|
|
||||||
select {
|
|
||||||
case <-ticker.C:
|
|
||||||
if err := index.updateIndex(); err != nil {
|
|
||||||
log.Error(3, "Failed to update dashboard json index %v", err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (index *JsonDashIndex) Search(query *Query) ([]*Hit, error) {
|
|
||||||
results := make([]*Hit, 0)
|
|
||||||
|
|
||||||
if query.IsStarred {
|
|
||||||
return results, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
queryStr := strings.ToLower(query.Title)
|
|
||||||
|
|
||||||
for _, item := range index.items {
|
|
||||||
if len(results) > query.Limit {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
|
|
||||||
// add results with matchig title filter
|
|
||||||
if strings.Contains(item.TitleLower, queryStr) {
|
|
||||||
results = append(results, &Hit{
|
|
||||||
Type: DashHitJson,
|
|
||||||
Title: item.Dashboard.Title,
|
|
||||||
Tags: item.Dashboard.GetTags(),
|
|
||||||
Uri: "file/" + item.Path,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return results, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (index *JsonDashIndex) GetDashboard(path string) *m.Dashboard {
|
|
||||||
for _, item := range index.items {
|
|
||||||
if item.Path == path {
|
|
||||||
return item.Dashboard
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (index *JsonDashIndex) updateIndex() error {
|
|
||||||
var items = make([]*JsonDashIndexItem, 0)
|
|
||||||
|
|
||||||
visitor := func(path string, f os.FileInfo, err error) error {
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if f.IsDir() {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
if strings.HasSuffix(f.Name(), ".json") {
|
|
||||||
dash, err := loadDashboardFromFile(path)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
items = append(items, dash)
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := filepath.Walk(index.path, visitor); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
index.items = items
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func loadDashboardFromFile(filename string) (*JsonDashIndexItem, error) {
|
|
||||||
reader, err := os.Open(filename)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
defer reader.Close()
|
|
||||||
|
|
||||||
data, err := simplejson.NewFromReader(reader)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
stat, _ := os.Stat(filename)
|
|
||||||
|
|
||||||
item := &JsonDashIndexItem{}
|
|
||||||
item.Dashboard = m.NewDashboardFromJson(data)
|
|
||||||
item.TitleLower = strings.ToLower(item.Dashboard.Title)
|
|
||||||
item.TagsCsv = strings.Join(item.Dashboard.GetTags(), ",")
|
|
||||||
item.Path = stat.Name()
|
|
||||||
|
|
||||||
return item, nil
|
|
||||||
}
|
|
||||||
@@ -1,42 +0,0 @@
|
|||||||
package search
|
|
||||||
|
|
||||||
import (
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
. "github.com/smartystreets/goconvey/convey"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestJsonDashIndex(t *testing.T) {
|
|
||||||
|
|
||||||
Convey("Given the json dash index", t, func() {
|
|
||||||
index := NewJsonDashIndex("../../../public/dashboards/")
|
|
||||||
|
|
||||||
Convey("Should be able to update index", func() {
|
|
||||||
err := index.updateIndex()
|
|
||||||
So(err, ShouldBeNil)
|
|
||||||
})
|
|
||||||
|
|
||||||
Convey("Should be able to search index", func() {
|
|
||||||
res, err := index.Search(&Query{Title: "", Limit: 20})
|
|
||||||
So(err, ShouldBeNil)
|
|
||||||
|
|
||||||
So(len(res), ShouldEqual, 3)
|
|
||||||
})
|
|
||||||
|
|
||||||
Convey("Should be able to search index by title", func() {
|
|
||||||
res, err := index.Search(&Query{Title: "home", Limit: 20})
|
|
||||||
So(err, ShouldBeNil)
|
|
||||||
|
|
||||||
So(len(res), ShouldEqual, 1)
|
|
||||||
So(res[0].Title, ShouldEqual, "Home")
|
|
||||||
})
|
|
||||||
|
|
||||||
Convey("Should not return when starred is filtered", func() {
|
|
||||||
res, err := index.Search(&Query{Title: "", IsStarred: true})
|
|
||||||
So(err, ShouldBeNil)
|
|
||||||
|
|
||||||
So(len(res), ShouldEqual, 0)
|
|
||||||
})
|
|
||||||
|
|
||||||
})
|
|
||||||
}
|
|
||||||
@@ -6,11 +6,9 @@ import "github.com/grafana/grafana/pkg/models"
|
|||||||
type HitType string
|
type HitType string
|
||||||
|
|
||||||
const (
|
const (
|
||||||
DashHitDB HitType = "dash-db"
|
DashHitDB HitType = "dash-db"
|
||||||
DashHitHome HitType = "dash-home"
|
DashHitHome HitType = "dash-home"
|
||||||
DashHitJson HitType = "dash-json"
|
DashHitFolder HitType = "dash-folder"
|
||||||
DashHitScripted HitType = "dash-scripted"
|
|
||||||
DashHitFolder HitType = "dash-folder"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type Hit struct {
|
type Hit struct {
|
||||||
@@ -51,7 +49,6 @@ type Query struct {
|
|||||||
Type string
|
Type string
|
||||||
DashboardIds []int64
|
DashboardIds []int64
|
||||||
FolderId int64
|
FolderId int64
|
||||||
Mode string
|
|
||||||
|
|
||||||
Result HitList
|
Result HitList
|
||||||
}
|
}
|
||||||
@@ -64,7 +61,8 @@ type FindPersistedDashboardsQuery struct {
|
|||||||
DashboardIds []int64
|
DashboardIds []int64
|
||||||
Type string
|
Type string
|
||||||
FolderId int64
|
FolderId int64
|
||||||
Mode string
|
Tags []string
|
||||||
|
Limit int
|
||||||
|
|
||||||
Result HitList
|
Result HitList
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ package sqlstore
|
|||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/grafana/grafana/pkg/bus"
|
"github.com/grafana/grafana/pkg/bus"
|
||||||
@@ -159,22 +160,49 @@ type DashboardSearchProjection struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func findDashboards(query *search.FindPersistedDashboardsQuery) ([]DashboardSearchProjection, error) {
|
func findDashboards(query *search.FindPersistedDashboardsQuery) ([]DashboardSearchProjection, error) {
|
||||||
|
limit := query.Limit
|
||||||
|
if limit == 0 {
|
||||||
|
limit = 1000
|
||||||
|
}
|
||||||
|
|
||||||
var sql bytes.Buffer
|
var sql bytes.Buffer
|
||||||
params := make([]interface{}, 0)
|
params := make([]interface{}, 0)
|
||||||
|
|
||||||
sql.WriteString(`SELECT
|
sql.WriteString(`
|
||||||
dashboard.id,
|
SELECT
|
||||||
dashboard.title,
|
dashboard.id,
|
||||||
dashboard.slug,
|
dashboard.title,
|
||||||
dashboard_tag.term,
|
dashboard.slug,
|
||||||
dashboard.is_folder,
|
dashboard_tag.term,
|
||||||
dashboard.folder_id,
|
dashboard.is_folder,
|
||||||
f.slug as folder_slug,
|
dashboard.folder_id,
|
||||||
f.title as folder_title
|
folder.slug as folder_slug,
|
||||||
FROM dashboard
|
folder.title as folder_title
|
||||||
LEFT OUTER JOIN dashboard f on f.id = dashboard.folder_id
|
FROM (
|
||||||
LEFT OUTER JOIN dashboard_tag on dashboard_tag.dashboard_id = dashboard.id`)
|
SELECT
|
||||||
|
dashboard.id FROM dashboard
|
||||||
|
LEFT OUTER JOIN dashboard_tag ON dashboard_tag.dashboard_id = dashboard.id
|
||||||
|
`)
|
||||||
|
|
||||||
|
// add tags filter
|
||||||
|
if len(query.Tags) > 0 {
|
||||||
|
sql.WriteString(` WHERE dashboard_tag.term IN (?` + strings.Repeat(",?", len(query.Tags)-1) + `)`)
|
||||||
|
for _, tag := range query.Tags {
|
||||||
|
params = append(params, tag)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// this ends the inner select (tag filtered part)
|
||||||
|
sql.WriteString(`
|
||||||
|
GROUP BY dashboard.id HAVING COUNT(dashboard.id) >= ?
|
||||||
|
ORDER BY dashboard.title ASC LIMIT ?) as ids`)
|
||||||
|
params = append(params, len(query.Tags))
|
||||||
|
params = append(params, limit)
|
||||||
|
|
||||||
|
sql.WriteString(`
|
||||||
|
INNER JOIN dashboard on ids.id = dashboard.id
|
||||||
|
LEFT OUTER JOIN dashboard folder on folder.id = dashboard.folder_id
|
||||||
|
LEFT OUTER JOIN dashboard_tag on dashboard.id = dashboard_tag.dashboard_id`)
|
||||||
if query.IsStarred {
|
if query.IsStarred {
|
||||||
sql.WriteString(" INNER JOIN star on star.dashboard_id = dashboard.id")
|
sql.WriteString(" INNER JOIN star on star.dashboard_id = dashboard.id")
|
||||||
}
|
}
|
||||||
@@ -188,16 +216,10 @@ func findDashboards(query *search.FindPersistedDashboardsQuery) ([]DashboardSear
|
|||||||
}
|
}
|
||||||
|
|
||||||
if len(query.DashboardIds) > 0 {
|
if len(query.DashboardIds) > 0 {
|
||||||
sql.WriteString(" AND (")
|
sql.WriteString(` AND dashboard.id IN (?` + strings.Repeat(",?", len(query.DashboardIds)-1) + `)`)
|
||||||
for i, dashboardId := range query.DashboardIds {
|
for _, dashboardId := range query.DashboardIds {
|
||||||
if i != 0 {
|
|
||||||
sql.WriteString(" OR")
|
|
||||||
}
|
|
||||||
|
|
||||||
sql.WriteString(" dashboard.id = ?")
|
|
||||||
params = append(params, dashboardId)
|
params = append(params, dashboardId)
|
||||||
}
|
}
|
||||||
sql.WriteString(")")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if query.SignedInUser.OrgRole != m.ROLE_ADMIN {
|
if query.SignedInUser.OrgRole != m.ROLE_ADMIN {
|
||||||
|
|||||||
Reference in New Issue
Block a user