浏览代码

Major refactorings around searching, moved to seperate package, trying to move stuff out of models package, extend search support searching different types of entities and different types of dashboards, #960

Torkel Ödegaard 10 年之前
父节点
当前提交
448a8b8d1c

+ 1 - 2
conf/defaults.ini

@@ -216,7 +216,6 @@ exchange = grafana_events
 #################################### Dashboard JSON files ##########################
 [dashboards.json]
 enabled = false
-path = dashboards
-orgs = *
+path = /var/lib/grafana/dashboards
 
 

+ 8 - 0
conf/sample.ini

@@ -211,3 +211,11 @@
 ;enabled = false
 ;rabbitmq_url = amqp://localhost/
 ;exchange = grafana_events
+
+;#################################### Dashboard JSON files ##########################
+[dashboards.json]
+;enabled = false
+;path = /var/lib/grafana/dashboards
+
+
+

+ 1 - 1
main.go

@@ -14,8 +14,8 @@ import (
 	"github.com/grafana/grafana/pkg/log"
 	"github.com/grafana/grafana/pkg/metrics"
 	"github.com/grafana/grafana/pkg/plugins"
+	"github.com/grafana/grafana/pkg/search"
 	"github.com/grafana/grafana/pkg/services/eventpublisher"
-	"github.com/grafana/grafana/pkg/services/search"
 	"github.com/grafana/grafana/pkg/services/sqlstore"
 	"github.com/grafana/grafana/pkg/setting"
 	"github.com/grafana/grafana/pkg/social"

+ 1 - 1
pkg/api/dashboard.go

@@ -10,7 +10,7 @@ import (
 	"github.com/grafana/grafana/pkg/metrics"
 	"github.com/grafana/grafana/pkg/middleware"
 	m "github.com/grafana/grafana/pkg/models"
-	"github.com/grafana/grafana/pkg/services/search"
+	"github.com/grafana/grafana/pkg/search"
 	"github.com/grafana/grafana/pkg/setting"
 	"github.com/grafana/grafana/pkg/util"
 )

+ 1 - 1
pkg/api/search.go

@@ -3,7 +3,7 @@ package api
 import (
 	"github.com/grafana/grafana/pkg/bus"
 	"github.com/grafana/grafana/pkg/middleware"
-	"github.com/grafana/grafana/pkg/services/search"
+	"github.com/grafana/grafana/pkg/search"
 )
 
 func Search(c *middleware.Context) {

+ 10 - 0
pkg/models/dashboards.go

@@ -126,3 +126,13 @@ type GetDashboardQuery struct {
 
 	Result *Dashboard
 }
+
+type DashboardTagCloudItem struct {
+	Term  string `json:"term"`
+	Count int    `json:"count"`
+}
+
+type GetDashboardTagsQuery struct {
+	OrgId  int64
+	Result []*DashboardTagCloudItem
+}

+ 1 - 28
pkg/models/search.go

@@ -1,12 +1,6 @@
 package models
 
-type SearchResult struct {
-	Dashboards []*DashboardSearchHit    `json:"dashboards"`
-	Tags       []*DashboardTagCloudItem `json:"tags"`
-	TagsOnly   bool                     `json:"tagsOnly"`
-}
-
-type DashboardSearchHit struct {
+type SearchHit struct {
 	Id        int64    `json:"id"`
 	Title     string   `json:"title"`
 	Uri       string   `json:"uri"`
@@ -14,24 +8,3 @@ type DashboardSearchHit struct {
 	Tags      []string `json:"tags"`
 	IsStarred bool     `json:"isStarred"`
 }
-
-type DashboardTagCloudItem struct {
-	Term  string `json:"term"`
-	Count int    `json:"count"`
-}
-
-type SearchDashboardsQuery struct {
-	Title     string
-	Tag       string
-	OrgId     int64
-	UserId    int64
-	Limit     int
-	IsStarred bool
-
-	Result []*DashboardSearchHit
-}
-
-type GetDashboardTagsQuery struct {
-	OrgId  int64
-	Result []*DashboardTagCloudItem
-}

+ 7 - 16
pkg/services/search/search.go → pkg/search/handlers.go

@@ -2,23 +2,13 @@ package search
 
 import (
 	"path/filepath"
+	"sort"
 
 	"github.com/grafana/grafana/pkg/bus"
 	m "github.com/grafana/grafana/pkg/models"
 	"github.com/grafana/grafana/pkg/setting"
 )
 
-type Query struct {
-	Title     string
-	Tag       string
-	OrgId     int64
-	UserId    int64
-	Limit     int
-	IsStarred bool
-
-	Result []*m.DashboardSearchHit
-}
-
 var jsonDashIndex *JsonDashIndex
 
 func Init() {
@@ -33,15 +23,14 @@ func Init() {
 			jsonFilesPath = filepath.Join(setting.HomePath, jsonFilesPath)
 		}
 
-		orgIds := jsonIndexCfg.Key("org_ids").String()
-		jsonDashIndex = NewJsonDashIndex(jsonFilesPath, orgIds)
+		jsonDashIndex = NewJsonDashIndex(jsonFilesPath)
 	}
 }
 
 func searchHandler(query *Query) error {
-	hits := make([]*m.DashboardSearchHit, 0)
+	hits := make(HitList, 0)
 
-	dashQuery := m.SearchDashboardsQuery{
+	dashQuery := FindPersistedDashboardsQuery{
 		Title:     query.Title,
 		Tag:       query.Tag,
 		UserId:    query.UserId,
@@ -65,6 +54,8 @@ func searchHandler(query *Query) error {
 		hits = append(hits, jsonHits...)
 	}
 
+	sort.Sort(hits)
+
 	if err := setIsStarredFlagOnSearchResults(query.UserId, hits); err != nil {
 		return err
 	}
@@ -73,7 +64,7 @@ func searchHandler(query *Query) error {
 	return nil
 }
 
-func setIsStarredFlagOnSearchResults(userId int64, hits []*m.DashboardSearchHit) error {
+func setIsStarredFlagOnSearchResults(userId int64, hits []*Hit) error {
 	query := m.GetUserStarsQuery{UserId: userId}
 	if err := bus.Dispatch(&query); err != nil {
 		return err

+ 7 - 8
pkg/services/search/json_index.go → pkg/search/json_index.go

@@ -11,9 +11,8 @@ import (
 )
 
 type JsonDashIndex struct {
-	path    string
-	orgsIds []int64
-	items   []*JsonDashIndexItem
+	path  string
+	items []*JsonDashIndexItem
 }
 
 type JsonDashIndexItem struct {
@@ -23,7 +22,7 @@ type JsonDashIndexItem struct {
 	Dashboard  *m.Dashboard
 }
 
-func NewJsonDashIndex(path string, orgIds string) *JsonDashIndex {
+func NewJsonDashIndex(path string) *JsonDashIndex {
 	log.Info("Creating json dashboard index for path: ", path)
 
 	index := JsonDashIndex{}
@@ -32,8 +31,8 @@ func NewJsonDashIndex(path string, orgIds string) *JsonDashIndex {
 	return &index
 }
 
-func (index *JsonDashIndex) Search(query *Query) ([]*m.DashboardSearchHit, error) {
-	results := make([]*m.DashboardSearchHit, 0)
+func (index *JsonDashIndex) Search(query *Query) ([]*Hit, error) {
+	results := make([]*Hit, 0)
 
 	for _, item := range index.items {
 		if len(results) > query.Limit {
@@ -49,8 +48,8 @@ func (index *JsonDashIndex) Search(query *Query) ([]*m.DashboardSearchHit, error
 
 		// add results with matchig title filter
 		if strings.Contains(item.TitleLower, query.Title) {
-			results = append(results, &m.DashboardSearchHit{
-				Type:  m.DashTypeJson,
+			results = append(results, &Hit{
+				Type:  DashHitJson,
 				Title: item.Dashboard.Title,
 				Tags:  item.Dashboard.GetTags(),
 				Uri:   "file/" + item.Path,

+ 1 - 1
pkg/services/search/json_index_test.go → pkg/search/json_index_test.go

@@ -9,7 +9,7 @@ import (
 func TestJsonDashIndex(t *testing.T) {
 
 	Convey("Given the json dash index", t, func() {
-		index := NewJsonDashIndex("../../../public/dashboards/", "*")
+		index := NewJsonDashIndex("../../public/dashboards/", "*")
 
 		Convey("Should be able to update index", func() {
 			err := index.updateIndex()

+ 47 - 0
pkg/search/models.go

@@ -0,0 +1,47 @@
+package search
+
+type HitType string
+
+const (
+	DashHitDB       HitType = "dash-db"
+	DashHitHome     HitType = "dash-home"
+	DashHitJson     HitType = "dash-json"
+	DashHitScripted HitType = "dash-scripted"
+)
+
+type Hit struct {
+	Id        int64    `json:"id"`
+	Title     string   `json:"title"`
+	Uri       string   `json:"uri"`
+	Type      HitType  `json:"type"`
+	Tags      []string `json:"tags"`
+	IsStarred bool     `json:"isStarred"`
+}
+
+type HitList []*Hit
+
+func (s HitList) Len() int           { return len(s) }
+func (s HitList) Swap(i, j int)      { s[i], s[j] = s[j], s[i] }
+func (s HitList) Less(i, j int) bool { return s[i].Title < s[j].Title }
+
+type Query struct {
+	Title     string
+	Tag       string
+	OrgId     int64
+	UserId    int64
+	Limit     int
+	IsStarred bool
+
+	Result HitList
+}
+
+type FindPersistedDashboardsQuery struct {
+	Title     string
+	Tag       string
+	OrgId     int64
+	UserId    int64
+	Limit     int
+	IsStarred bool
+
+	Result HitList
+}

+ 6 - 5
pkg/services/sqlstore/dashboard.go

@@ -8,6 +8,7 @@ import (
 	"github.com/grafana/grafana/pkg/bus"
 	"github.com/grafana/grafana/pkg/metrics"
 	m "github.com/grafana/grafana/pkg/models"
+	"github.com/grafana/grafana/pkg/search"
 )
 
 func init() {
@@ -119,7 +120,7 @@ type DashboardSearchProjection struct {
 	Term  string
 }
 
-func SearchDashboards(query *m.SearchDashboardsQuery) error {
+func SearchDashboards(query *search.FindPersistedDashboardsQuery) error {
 	var sql bytes.Buffer
 	params := make([]interface{}, 0)
 
@@ -166,17 +167,17 @@ func SearchDashboards(query *m.SearchDashboardsQuery) error {
 		return err
 	}
 
-	query.Result = make([]*m.DashboardSearchHit, 0)
-	hits := make(map[int64]*m.DashboardSearchHit)
+	query.Result = make([]*search.Hit, 0)
+	hits := make(map[int64]*search.Hit)
 
 	for _, item := range res {
 		hit, exists := hits[item.Id]
 		if !exists {
-			hit = &m.DashboardSearchHit{
+			hit = &search.Hit{
 				Id:    item.Id,
 				Title: item.Title,
 				Uri:   "db/" + item.Slug,
-				Type:  m.DashTypeDB,
+				Type:  search.DashHitDB,
 				Tags:  []string{},
 			}
 			query.Result = append(query.Result, hit)

+ 5 - 4
pkg/services/sqlstore/dashboard_test.go

@@ -6,6 +6,7 @@ import (
 	. "github.com/smartystreets/goconvey/convey"
 
 	m "github.com/grafana/grafana/pkg/models"
+	"github.com/grafana/grafana/pkg/search"
 )
 
 func insertTestDashboard(title string, orgId int64, tags ...interface{}) *m.Dashboard {
@@ -85,7 +86,7 @@ func TestDashboardDataAccess(t *testing.T) {
 			})
 
 			Convey("Should be able to search for dashboard", func() {
-				query := m.SearchDashboardsQuery{
+				query := search.FindPersistedDashboardsQuery{
 					Title: "test",
 					OrgId: 1,
 				}
@@ -99,8 +100,8 @@ func TestDashboardDataAccess(t *testing.T) {
 			})
 
 			Convey("Should be able to search for dashboards using tags", func() {
-				query1 := m.SearchDashboardsQuery{Tag: "webapp", OrgId: 1}
-				query2 := m.SearchDashboardsQuery{Tag: "tagdoesnotexist", OrgId: 1}
+				query1 := search.FindPersistedDashboardsQuery{Tag: "webapp", OrgId: 1}
+				query2 := search.FindPersistedDashboardsQuery{Tag: "tagdoesnotexist", OrgId: 1}
 
 				err := SearchDashboards(&query1)
 				err = SearchDashboards(&query2)
@@ -146,7 +147,7 @@ func TestDashboardDataAccess(t *testing.T) {
 				})
 
 				Convey("Should be able to search for starred dashboards", func() {
-					query := m.SearchDashboardsQuery{OrgId: 1, UserId: 10, IsStarred: true}
+					query := search.FindPersistedDashboardsQuery{OrgId: 1, UserId: 10, IsStarred: true}
 					err := SearchDashboards(&query)
 
 					So(err, ShouldBeNil)

+ 9 - 28
public/app/controllers/search.js

@@ -40,15 +40,15 @@ function (angular, _, config) {
         $scope.moveSelection(-1);
       }
       if (evt.keyCode === 13) {
-        if ($scope.query.tagcloud) {
-          var tag = $scope.results.tags[$scope.selectedIndex];
+        if ($scope.tagMode) {
+          var tag = $scope.results[$scope.selectedIndex];
           if (tag) {
             $scope.filterByTag(tag.term);
           }
           return;
         }
 
-        var selectedDash = $scope.results.dashboards[$scope.selectedIndex];
+        var selectedDash = $scope.results[$scope.selectedIndex];
         if (selectedDash) {
           $location.search({});
           $location.path(selectedDash.url);
@@ -57,7 +57,9 @@ function (angular, _, config) {
     };
 
     $scope.moveSelection = function(direction) {
-      $scope.selectedIndex = Math.max(Math.min($scope.selectedIndex + direction, $scope.resultCount - 1), 0);
+      var max = ($scope.results || []).length;
+      var newIndex = $scope.selectedIndex + direction;
+      $scope.selectedIndex = ((newIndex %= max) < 0) ? newIndex + max : newIndex;
     };
 
     $scope.searchDashboards = function() {
@@ -68,14 +70,13 @@ function (angular, _, config) {
       return backendSrv.search($scope.query).then(function(results) {
         if (localSearchId < $scope.currentSearchId) { return; }
 
-        $scope.resultCount = results.length;
         $scope.results = _.map(results, function(dash) {
           dash.url = 'dashboard/' + dash.uri;
           return dash;
         });
 
         if ($scope.queryHasNoFilters()) {
-          $scope.results.unshift({ title: 'Home', url: config.appSubUrl + '/', isHome: true });
+          $scope.results.unshift({ title: 'Home', url: config.appSubUrl + '/', type: 'dash-home' });
         }
       });
     };
@@ -97,10 +98,10 @@ function (angular, _, config) {
     };
 
     $scope.getTags = function() {
-      $scope.tagsMode = true;
       return backendSrv.get('/api/dashboards/tags').then(function(results) {
-        $scope.resultCount = results.length;
+        $scope.tagsMode = true;
         $scope.results = results;
+        $scope.giveSearchFocus = $scope.giveSearchFocus + 1;
       });
     };
 
@@ -116,26 +117,6 @@ function (angular, _, config) {
       $scope.searchDashboards();
     };
 
-    $scope.addMetricToCurrentDashboard = function (metricId) {
-      $scope.dashboard.rows.push({
-        title: '',
-        height: '250px',
-        editable: true,
-        panels: [
-      {
-        type: 'graphite',
-        title: 'test',
-        span: 12,
-        targets: [{ target: metricId }]
-      }
-      ]
-      });
-    };
-
-    $scope.toggleImport = function () {
-      $scope.showImport = !$scope.showImport;
-    };
-
     $scope.newDashboard = function() {
       $location.url('dashboard/new');
     };

+ 2 - 2
public/app/features/dashlinks/module.js

@@ -133,12 +133,12 @@ function (angular, _) {
 
     $scope.searchDashboards = function(link) {
       return backendSrv.search({tag: link.tag}).then(function(results) {
-        return _.reduce(results.dashboards, function(memo, dash) {
+        return _.reduce(results, function(memo, dash) {
           // do not add current dashboard
           if (dash.id !== currentDashId) {
             memo.push({
               title: dash.title,
-              url: 'dashboard/db/'+ dash.slug,
+              url: 'dashboard/' + dash.uri,
               icon: 'fa fa-th-large',
               keepTime: link.keepTime,
               includeVars: link.includeVars

+ 1 - 1
public/app/panels/dashlist/module.html

@@ -1,7 +1,7 @@
 <grafana-panel>
 	<div class="dashlist">
 	<div class="dashlist-item" ng-repeat="dash in dashList">
-		<a class="dashlist-link" href="dashboard/{{dash.uri}}">
+		<a class="dashlist-link dashlist-link-{{dash.type}}" href="dashboard/{{dash.uri}}">
 			<span class="dashlist-title">
 				{{dash.title}}
 			</span>

+ 1 - 1
public/app/panels/dashlist/module.js

@@ -62,7 +62,7 @@ function (angular, app, _, config, PanelMeta) {
       }
 
       return backendSrv.search(params).then(function(result) {
-        $scope.dashList = result.dashboards;
+        $scope.dashList = result;
       });
     };
 

+ 25 - 27
public/app/partials/search.html

@@ -24,41 +24,39 @@
 		</div>
 	</div>
 
-	<div ng-if="!showImport">
-		<div class="search-results-container" ng-if="tagsMode">
-			<div class="row">
-				<div class="span6 offset1">
-					<div ng-repeat="tag in results" class="pointer" style="width: 180px; float: left;"
-						ng-class="{'selected': $index === selectedIndex }"
-						ng-click="filterByTag(tag.term, $event)">
-						<a class="search-result-tag label label-tag" tag-color-from-name tag="tag.term">
-							<i class="fa fa-tag"></i>
-							<span>{{tag.term}} &nbsp;({{tag.count}})</span>
-						</a>
-					</div>
+	<div class="search-results-container" ng-if="tagsMode">
+		<div class="row">
+			<div class="span6 offset1">
+				<div ng-repeat="tag in results" class="pointer" style="width: 180px; float: left;"
+					ng-class="{'selected': $index === selectedIndex }"
+					ng-click="filterByTag(tag.term, $event)">
+					<a class="search-result-tag label label-tag" tag-color-from-name tag="tag.term">
+						<i class="fa fa-tag"></i>
+						<span>{{tag.term}} &nbsp;({{tag.count}})</span>
+					</a>
 				</div>
 			</div>
 		</div>
+	</div>
 
-		<div class="search-results-container" ng-if="!tagsMode">
-			<h6 ng-hide="results.length">No dashboards matching your query were found.</h6>
+	<div class="search-results-container" ng-if="!tagsMode">
+		<h6 ng-hide="results.length">No dashboards matching your query were found.</h6>
 
-			<a class="search-result-item pointer search-result-item-{{row.type}}" bindonce ng-repeat="row in results"
-				ng-class="{'selected': $index == selectedIndex}" ng-href="{{row.url}}">
+		<a class="search-item pointer search-item-{{row.type}}" bindonce ng-repeat="row in results"
+			ng-class="{'selected': $index == selectedIndex}" ng-href="{{row.url}}">
 
-				<span class="search-result-tags">
-					<span ng-click="filterByTag(tag, $event)" ng-repeat="tag in row.tags" tag-color-from-name tag="tag"  class="label label-tag">
-						{{tag}}
-					</span>
-					<i class="fa" ng-class="{'fa-star': row.isStarred, 'fa-star-o': !row.isStarred}"></i>
+			<span class="search-result-tags">
+				<span ng-click="filterByTag(tag, $event)" ng-repeat="tag in row.tags" tag-color-from-name tag="tag"  class="label label-tag">
+					{{tag}}
 				</span>
+				<i class="fa" ng-class="{'fa-star': row.isStarred, 'fa-star-o': !row.isStarred}"></i>
+			</span>
 
-				<span class="search-result-link">
-					<i class="search-result-icon"></i>
-					<span bo-text="row.title"></span>
-				</span>
-			</a>
-		</div>
+			<span class="search-result-link">
+				<i class="fa search-result-icon"></i>
+				<span bo-text="row.title"></span>
+			</span>
+		</a>
 	</div>
 
 	<div class="search-button-row">

+ 9 - 2
public/css/less/search.less

@@ -41,7 +41,7 @@
   display: block;
   line-height: 28px;
 
-  .search-result-item:hover, .search-result-item.selected {
+  .search-item:hover, .search-item.selected {
     background-color: @grafanaListHighlight;
   }
 
@@ -67,12 +67,19 @@
     }
   }
 
-  .search-result-item {
+  .search-item {
     display: block;
     padding: 3px 10px;
     white-space: nowrap;
     background-color: @grafanaListBackground;
     margin-bottom: 4px;
+    .search-result-icon:before {
+      content: "\f009";
+    }
+
+    &.search-item-dash-home .search-result-icon:before {
+      content: "\f015";
+    }
   }
 
   .search-result-tags {