more work on dashboard tags / search (#86)

pull/131/head
Torkel Ödegaard 12 years ago
parent 123f90d24d
commit e9b1c92911
  1. 51
      src/app/controllers/search.js
  2. 1
      src/app/panels/graphite/editor.html
  3. 32
      src/app/partials/search.html
  4. 2
      src/css/bootstrap.dark.min.css
  5. 2
      src/css/bootstrap.light.min.css
  6. 18
      src/css/less/grafana.less
  7. 7
      src/css/less/overrides.less

@ -12,10 +12,9 @@ function (angular, _, config, $) {
module.controller('SearchCtrl', function($scope, $rootScope, dashboard, $element, $location) { module.controller('SearchCtrl', function($scope, $rootScope, dashboard, $element, $location) {
$scope.init = function() { $scope.init = function() {
$scope.elasticsearch = $scope.elasticsearch || {};
$scope.giveSearchFocus = 0; $scope.giveSearchFocus = 0;
$scope.selectedIndex = -1; $scope.selectedIndex = -1;
$scope.query = { query: 'title:' };
$rootScope.$on('open-search', $scope.openSearch); $rootScope.$on('open-search', $scope.openSearch);
}; };
@ -42,11 +41,20 @@ function (angular, _, config, $) {
$scope.elasticsearch_dashboards = function(query) { $scope.elasticsearch_dashboards = function(query) {
var request = $scope.ejs.Request().indices(config.grafana_index).types('dashboard'); var request = $scope.ejs.Request().indices(config.grafana_index).types('dashboard');
// if elasticsearch has disabled _all field we need
// need to specifiy field here
var q = 'title:' + (query + '*' || '*');
return request.query($scope.ejs.QueryStringQuery(q)).size(50).doSearch() if (query.length === 0) {
query = 'title:';
}
if (query[query.length - 1] !== '*') {
query += '*';
}
return request
.query($scope.ejs.QueryStringQuery(query))
.sort('_uid')
.facet($scope.ejs.TermsFacet("tags").field("tags").order('term').size(50))
.size(50).doSearch()
.then(function(results) { .then(function(results) {
if(_.isUndefined(results.hits)) { if(_.isUndefined(results.hits)) {
@ -54,18 +62,36 @@ function (angular, _, config, $) {
return; return;
} }
var hits = _.sortBy(results.hits.hits, '_id'); $scope.search_results = { dashboards: results.hits.hits };
$scope.search_results = { dashboards: hits }; $scope.tags = results.facets.tags.terms;
}); });
}; };
$scope.elasticsearch_dblist = function(queryStr) { $scope.filterByTag = function(tag, evt) {
$scope.query.query = "tags:" + tag + " AND title:";
$scope.search();
$scope.tagsOnly = false;
$scope.giveSearchFocus = $scope.giveSearchFocus + 1;
evt.stopPropagation();
evt.preventDefault();
};
$scope.showTags = function(evt) {
evt.stopPropagation();
$scope.tagsOnly = !$scope.tagsOnly;
$scope.query.query = $scope.tagsOnly ? "tags!" : "";
$scope.giveSearchFocus = $scope.giveSearchFocus + 1;
$scope.selectedIndex = -1;
};
$scope.search = function() {
$scope.showImport = false; $scope.showImport = false;
$scope.selectedIndex = -1; $scope.selectedIndex = -1;
queryStr = queryStr.toLowerCase(); var queryStr = $scope.query.query.toLowerCase();
if (queryStr.indexOf('m:') !== 0) { if (queryStr.indexOf('m:') !== 0) {
queryStr = queryStr.replace(' and ', ' AND ');
$scope.elasticsearch_dashboards(queryStr); $scope.elasticsearch_dashboards(queryStr);
return; return;
} }
@ -103,7 +129,8 @@ function (angular, _, config, $) {
} }
$scope.giveSearchFocus = $scope.giveSearchFocus + 1; $scope.giveSearchFocus = $scope.giveSearchFocus + 1;
$scope.elasticsearch_dblist(""); $scope.query.query = 'title:';
$scope.search();
}; };
$scope.addMetricToCurrentDashboard = function (metricId) { $scope.addMetricToCurrentDashboard = function (metricId) {
@ -133,8 +160,6 @@ function (angular, _, config, $) {
}); });
module.directive('xngFocus', function() { module.directive('xngFocus', function() {
return function(scope, element, attrs) { return function(scope, element, attrs) {
$(element).click(function(e) { $(element).click(function(e) {

@ -55,6 +55,7 @@
class="grafana-target-text-input" class="grafana-target-text-input"
ng-model="target.target" ng-model="target.target"
focus-me="showTextEditor" focus-me="showTextEditor"
spellcheck='false'
ng-model-onblur ng-change="targetTextChanged()" ng-model-onblur ng-change="targetTextChanged()"
ng-show="showTextEditor" /> ng-show="showTextEditor" />

@ -28,17 +28,35 @@
<i class="icon-th-large"></i> <i class="icon-th-large"></i>
New New
</button> </button>
<span> <span class="position: relative;">
<input type="text" <input type="text"
placeholder="search dashboards, metrics, or graphs" placeholder="search dashboards, metrics, or graphs"
xng-focus="giveSearchFocus" xng-focus="giveSearchFocus"
ng-keydown="keyDown($event)" ng-keydown="keyDown($event)"
ng-model="elasticsearch.query" ng-model="query.query" spellcheck='false'
ng-change="elasticsearch_dblist(elasticsearch.query)" /> ng-change="search()" />
<a class="search-tagview-switch" href="javascript:void(0);"
ng-class="{'active': tagsOnly}"
ng-click="showTags($event)">Tags</a>
</span> </span>
</div> </div>
<h6 ng-hide="search_results.dashboards.length || search_results.metrics.length">No dashboards or metrics matching your query found</h6> <h6 ng-hide="search_results.dashboards.length || search_results.metrics.length">No dashboards or metrics matching your query found</h6>
<table class="table table-condensed table-striped">
<table class="table table-condensed table-striped" ng-if="tagsOnly">
<tr ng-repeat="tag in tags" ng-class="{'selected-tag': $index === selectedIndex }">
<td>
<a ng-click="filterByTag(tag.term, $event)" class="label label-tag">
{{tag.term}}
</a>
</td>
<td style="width:100%;">
{{tag.count}}
</td>
</tr>
</table>
<table class="table table-condensed table-striped" ng-if="!tagsOnly">
<tr bindonce ng-repeat="row in search_results.metrics" <tr bindonce ng-repeat="row in search_results.metrics"
class="grafana-search-metric-result" class="grafana-search-metric-result"
ng-class="{'selected': $index === selectedIndex }"> ng-class="{'selected': $index === selectedIndex }">
@ -60,8 +78,10 @@
<td style="width:100%"> <td style="width:100%">
<a href="#/dashboard/elasticsearch/{{row._id}}" bo-text="row._id"></a> <a href="#/dashboard/elasticsearch/{{row._id}}" bo-text="row._id"></a>
</td> </td>
<td style="white-space: nowrap"> <td style="white-space: nowrap; text-align: right;">
<span ng-repeat="tag in row._source.tags" style="margin-right: 5px;" class="label label-tag">{{tag}}</span> <a ng-click="filterByTag(tag, $event)" ng-repeat="tag in row._source.tags" style="margin-right: 5px;" class="label label-tag">
{{tag}}
</a>
</td> </td>
<td><a><i class="icon-share" ng-click="share = dashboard.share_link(row._id,'elasticsearch',row._id)" bs-modal="'app/partials/dashLoaderShare.html'"></i></a></td> <td><a><i class="icon-share" ng-click="share = dashboard.share_link(row._id,'elasticsearch',row._id)" bs-modal="'app/partials/dashLoaderShare.html'"></i></a></td>
</tr> </tr>

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

@ -12,6 +12,8 @@
} }
} }
// Search
.grafana-search-panel { .grafana-search-panel {
padding: 6px 10px; padding: 6px 10px;
@ -37,6 +39,20 @@
color: white; color: white;
} }
} }
.selected-tag .label-tag {
background-color: @blue;
}
}
.search-tagview-switch {
position: absolute;
top: 15px;
right: 180px;
color: darken(@linkColor, 30%);
&.active {
color: @linkColor;
}
} }
.row-button { .row-button {
@ -417,3 +433,5 @@ input[type=text].func-param {
.sp-palette-container, .sp-picker-container { .sp-palette-container, .sp-picker-container {
border: none; border: none;
} }

@ -555,7 +555,12 @@ div.flot-text {
// Labels & Badges // Labels & Badges
.label-tag, .label-tag:hover { .label-tag {
background-color: @purple; background-color: @purple;
color: @linkColor; color: @linkColor;
}
.label-tag:hover {
background-color: darken(@purple, 10%);
color: lighten(@linkColor, 5%);
} }
Loading…
Cancel
Save