Ver código fonte

search: worked on search results

Torkel Ödegaard 8 anos atrás
pai
commit
313735bd75

+ 1 - 0
pkg/services/search/models.go

@@ -15,6 +15,7 @@ type Hit struct {
 	Id          int64    `json:"id"`
 	Title       string   `json:"title"`
 	Uri         string   `json:"uri"`
+	Slug        string   `json:"slug"`
 	Type        HitType  `json:"type"`
 	Tags        []string `json:"tags"`
 	IsStarred   bool     `json:"isStarred"`

+ 1 - 0
pkg/services/sqlstore/dashboard.go

@@ -260,6 +260,7 @@ func makeQueryResult(query *search.FindPersistedDashboardsQuery, res []Dashboard
 				Id:          item.Id,
 				Title:       item.Title,
 				Uri:         "db/" + item.Slug,
+				Slug:        item.Slug,
 				Type:        getHitType(item),
 				FolderId:    item.FolderId,
 				FolderTitle: item.FolderTitle,

+ 14 - 17
public/app/core/components/search/search_results.html

@@ -1,21 +1,21 @@
 <div ng-repeat="section in ctrl.results" class="search-section">
-  <a class="search-section__header pointer" ng-hide="section.hideHeader" ng-class="{'selected': section.selected}" ng-click="ctrl.toggleFolderExpand(section)">
+  <div class="search-section__header pointer" ng-hide="section.hideHeader" ng-class="{'selected': section.selected}" ng-click="ctrl.toggleFolderExpand(section)">
     <div ng-click="ctrl.toggleSelection(section, $event)">
       <gf-form-switch
-        ng-show="ctrl.editable"
-        on-change="ctrl.selectionChanged($event)"
-        checked="section.checked"
-        switch-class="gf-form-switch--transparent gf-form-switch--search-result__section">
+         ng-show="ctrl.editable"
+         on-change="ctrl.selectionChanged($event)"
+         checked="section.checked"
+         switch-class="gf-form-switch--transparent gf-form-switch--search-result__section">
       </gf-form-switch>
     </div>
     <i class="search-section__header__icon" ng-class="section.icon"></i>
     <span class="search-section__header__text">{{::section.title}}</span>
-    <div ng-show="ctrl.editable && section.id > 0" ng-click="ctrl.navigateToFolder(section, $event)">
-        <i class="fa fa-cog search-section__header__toggle"></i>&nbsp;
-    </div>
-		<i class="fa fa-angle-down search-section__header__toggle" ng-show="section.expanded"></i>
+    <a ng-show="section.url" href="{{section.url}}" class="search-section__header__link">
+      <i class="fa fa-cog"></i>
+    </a>
+    <i class="fa fa-angle-down search-section__header__toggle" ng-show="section.expanded"></i>
     <i class="fa fa-angle-right search-section__header__toggle" ng-hide="section.expanded"></i>
-  </a>
+  </div>
 
   <div class="search-section__header" ng-show="section.hideHeader"></div>
 
@@ -23,10 +23,10 @@
     <a ng-repeat="item in section.items" class="search-item" ng-class="{'selected': item.selected}" ng-href="{{::item.url}}">
       <div ng-click="ctrl.toggleSelection(item, $event)">
         <gf-form-switch
-          ng-show="ctrl.editable"
-          on-change="ctrl.selectionChanged()"
-          checked="item.checked"
-          switch-class="gf-form-switch--transparent gf-form-switch--search-result__item">
+           ng-show="ctrl.editable"
+           on-change="ctrl.selectionChanged()"
+           checked="item.checked"
+           switch-class="gf-form-switch--transparent gf-form-switch--search-result__item">
         </gf-form-switch>
       </div>
       <span class="search-item__icon">
@@ -34,9 +34,6 @@
       </span>
       <span class="search-item__body">
         <div class="search-item__body-title">{{::item.title}}</div>
-        <div class="search-item__body-sub-title" ng-show="item.folderTitle && section.hideHeader">
-          {{::item.folderTitle}}
-        </div>
       </span>
       <span class="search-item__tags">
         <span ng-click="ctrl.selectTag(tag, $event)" ng-repeat="tag in item.tags" tag-color-from-name="tag" class="label label-tag">

+ 3 - 3
public/app/core/routes/routes.ts

@@ -78,17 +78,17 @@ function setupAngularRoutes($routeProvider, $locationProvider) {
     controller : 'CreateFolderCtrl',
     controllerAs: 'ctrl',
   })
-  .when('/dashboards/folder/:folderId/:type/:slug/permissions', {
+  .when('/dashboards/folder/:folderId/:slug/permissions', {
     templateUrl: 'public/app/features/dashboard/partials/folder_permissions.html',
     controller : 'FolderPermissionsCtrl',
     controllerAs: 'ctrl',
   })
-  .when('/dashboards/folder/:folderId/:type/:slug/settings', {
+  .when('/dashboards/folder/:folderId/:slug/settings', {
     templateUrl: 'public/app/features/dashboard/partials/folder_settings.html',
     controller : 'FolderSettingsCtrl',
     controllerAs: 'ctrl',
   })
-  .when('/dashboards/folder/:folderId/:type/:slug', {
+  .when('/dashboards/folder/:folderId/:slug', {
     templateUrl: 'public/app/features/dashboard/partials/folder_dashboards.html',
     controller : 'FolderDashboardsCtrl',
     controllerAs: 'ctrl',

+ 65 - 74
public/app/core/services/search_srv.ts

@@ -84,105 +84,96 @@ export class SearchSrv {
     });
   }
 
-  private getDashboardsAndFolders(sections) {
-    const rootFolderId = 0;
-
-    let query = {
-      folderIds: [rootFolderId],
-    };
-
-    return this.backendSrv.search(query).then(results => {
-      for (let hit of results) {
-        if (hit.type === 'dash-folder') {
-          sections[hit.id] = {
-            id: hit.id,
-            title: hit.title,
-            items: [],
-            icon: 'fa fa-folder',
-            score: _.keys(sections).length,
-            uri: hit.uri,
-            toggle: this.toggleFolder.bind(this),
-          };
-        }
-      }
-
-      sections[0] = {
-        id: 0,
-        title: 'Root',
-        items: [],
-        icon: 'fa fa-folder-open',
-        score: _.keys(sections).length,
-        expanded: true,
-      };
-
-      for (let hit of results) {
-        if (hit.type === 'dash-folder') {
-          continue;
-        }
-        let section = sections[hit.folderId || 0];
-        if (section) {
-          section.items.push(this.transformToViewModel(hit));
-        } else {
-          console.log('Error: dashboard returned from browse search but not folder', hit.id, hit.folderId);
-        }
-      }
-    });
+  private transformToViewModel(hit) {
+    hit.url = 'dashboard/db/' + hit.slug;
+    return hit;
   }
 
-  private browse(options) {
+  search(options) {
     let sections: any = {};
-
     let promises = [];
+    let query = _.clone(options);
+    let hasFilters = options.query ||
+      (options.tag && options.tag.length > 0) || options.starred ||
+      (options.folderIds && options.folderIds.length > 0);
 
-    if (!options.skipRecent) {
+    if (!options.skipRecent && !hasFilters) {
       promises.push(this.getRecentDashboards(sections));
     }
 
-    if (!options.skipStarred) {
+    if (!options.skipStarred && !hasFilters) {
       promises.push(this.getStarred(sections));
     }
 
-    promises.push(this.getDashboardsAndFolders(sections));
+    query.folderIds = query.folderIds || [];
+    if (!hasFilters) {
+      query.folderIds = [0];
+    }
+
+    promises.push(this.backendSrv.search(query).then(results => {
+      return this.handleSearchResult(sections, results);
+    }));
 
     return this.$q.all(promises).then(() => {
       return _.sortBy(_.values(sections), 'score');
     });
   }
 
-  private transformToViewModel(hit) {
-    hit.url = 'dashboard/' + hit.uri;
-    return hit;
-  }
-
-  search(options) {
-    if (!options.folderIds && !options.query && (!options.tag || options.tag.length === 0) && !options.starred) {
-      return this.browse(options);
+  private handleSearchResult(sections, results) {
+    if (results.length === 0) {
+      return sections;
     }
 
-    let query = _.clone(options);
-    query.folderIds = options.folderIds || [];
-    query.type = 'dash-db';
-
-    return this.backendSrv.search(query).then(results => {
-      if (results.length === 0) {
-        return results;
+    // create folder index
+    for (let hit of results) {
+      if (hit.type === 'dash-folder') {
+        sections[hit.id] = {
+          id: hit.id,
+          title: hit.title,
+          expanded: false,
+          items: [],
+          toggle: this.toggleFolder.bind(this),
+          url: `dashboards/folder/${hit.id}/${hit.slug}`,
+          icon: 'fa fa-folder',
+          score: _.keys(sections).length,
+        };
       }
+    }
 
-      let section = {
-        hideHeader: true,
-        items: [],
-        expanded: true,
-      };
+    for (let hit of results) {
+      if (hit.type === 'dash-folder') {
+        continue;
+      }
 
-      for (let hit of results) {
-        if (hit.type === 'dash-folder') {
-          continue;
+      let section = sections[hit.folderId || 0];
+      if (!section) {
+        if (hit.folderId) {
+          section = {
+            id: hit.folderId,
+            title: hit.folderTitle,
+            url: `dashboards/folder/${hit.folderId}/${hit.folderSlug}`,
+            items: [],
+            icon: 'fa fa-folder-open',
+            toggle: this.toggleFolder.bind(this),
+            score: _.keys(sections).length,
+          };
+        } else {
+          section = {
+            id: 0,
+            title: 'Root',
+            items: [],
+            icon: 'fa fa-folder-open',
+            toggle: this.toggleFolder.bind(this),
+            score: _.keys(sections).length,
+          };
         }
-        section.items.push(this.transformToViewModel(hit));
+        // add section
+        sections[hit.folderId || 0] = section;
       }
 
-      return [section];
-    });
+      section.expanded = true;
+      section.items.push(this.transformToViewModel(hit));
+    }
   }
 
   private toggleFolder(section) {

+ 2 - 3
public/app/core/specs/search_srv.jest.ts

@@ -214,9 +214,8 @@ describe('SearchSrv', () => {
       expect(backendSrvMock.search.mock.calls[0][0].folderIds).toHaveLength(0);
     });
 
-    it('should place all results in a single section', () => {
-      expect(results).toHaveLength(1);
-      expect(results[0].hideHeader).toBe(true);
+    it('should group results by folder', () => {
+      expect(results).toHaveLength(2);
     });
   });
 

+ 4 - 2
public/app/features/dashboard/folder_dashboards_ctrl.ts

@@ -6,10 +6,12 @@ export class FolderDashboardsCtrl {
 
   /** @ngInject */
   constructor(private backendSrv, navModelSrv, private $routeParams) {
-    if (this.$routeParams.folderId && this.$routeParams.type && this.$routeParams.slug) {
+    if (this.$routeParams.folderId && this.$routeParams.slug) {
       this.folderId = $routeParams.folderId;
 
-      new FolderPageLoader(this.backendSrv, this.$routeParams).load(this, this.folderId, 'manage-folder-dashboards');
+      const loader = new FolderPageLoader(this.backendSrv, this.$routeParams);
+
+      loader.load(this, this.folderId, 'manage-folder-dashboards');
     }
   }
 }

+ 4 - 4
public/app/features/dashboard/folder_page_loader.ts

@@ -9,7 +9,7 @@ export class FolderPageLoader {
         icon: 'fa fa-folder-open',
         id: 'manage-folder',
         subTitle: 'Manage folder dashboards & permissions',
-        url: '/fsdfds',
+        url: '',
         text: '',
         breadcrumbs: [
           { title: 'Dashboards', url: '/dashboards' },
@@ -41,11 +41,11 @@ export class FolderPageLoader {
       }
     };
 
-    return this.backendSrv.getDashboard(this.$routeParams.type, this.$routeParams.slug).then(result => {
+    return this.backendSrv.getDashboard('db', this.$routeParams.slug).then(result => {
       const folderTitle = result.dashboard.title;
       ctrl.navModel.main.text = '';
       ctrl.navModel.main.breadcrumbs = [
-        { title: 'Dashboards', uri: '/dashboards' },
+        { title: 'Dashboards', url: '/dashboards' },
         { title: folderTitle }
       ];
 
@@ -65,6 +65,6 @@ export class FolderPageLoader {
   }
 
   createFolderUrl(folderId: number, type: string, slug: string) {
-    return `/dashboards/folder/${folderId}/${type}/${slug}`;
+    return `/dashboards/folder/${folderId}/${slug}`;
   }
 }

+ 1 - 1
public/app/features/dashboard/folder_permissions_ctrl.ts

@@ -6,7 +6,7 @@ export class FolderPermissionsCtrl {
 
   /** @ngInject */
   constructor(private backendSrv, navModelSrv, private $routeParams) {
-    if (this.$routeParams.folderId && this.$routeParams.type && this.$routeParams.slug) {
+    if (this.$routeParams.folderId && this.$routeParams.slug) {
       this.folderId = $routeParams.folderId;
 
       new FolderPageLoader(this.backendSrv, this.$routeParams).load(this, this.folderId, 'manage-folder-permissions');

+ 1 - 1
public/app/features/dashboard/folder_settings_ctrl.ts

@@ -11,7 +11,7 @@ export class FolderSettingsCtrl {
 
   /** @ngInject */
   constructor(private backendSrv, navModelSrv, private $routeParams, private $location) {
-    if (this.$routeParams.folderId && this.$routeParams.type && this.$routeParams.slug) {
+    if (this.$routeParams.folderId && this.$routeParams.slug) {
       this.folderId = $routeParams.folderId;
 
       this.folderPageLoader = new FolderPageLoader(this.backendSrv, this.$routeParams);

+ 2 - 2
public/app/features/plugins/partials/ds_edit.html

@@ -65,11 +65,11 @@
     </div>
 
     <div class="gf-form-button-row">
-      <button type="submit" class="btn btn-success" ng-disabled="ctrl.current.readOnly"  ng-click="ctrl.saveChanges()">Save</button>
+      <button type="submit" class="btn btn-success" ng-disabled="ctrl.current.readOnly"  ng-click="ctrl.saveChanges()">Save &amp; Test</button>
       <button type="submit" class="btn btn-danger" ng-disabled="ctrl.current.readOnly"  ng-show="!ctrl.isNew" ng-click="ctrl.delete()">
         Delete
       </button>
-      <a class="btn btn-link" href="datasources">Cancel</a>
+      <a class="btn btn-inverse" href="datasources">Back</a>
     </div>
 
     <br />

+ 13 - 6
public/sass/components/_search.scss

@@ -137,6 +137,12 @@
   &:hover, &.selected {
     color: $text-color;
   }
+
+  &:hover {
+    .search-section__header__link {
+      opacity: 1;
+    }
+  }
 }
 
 .search-section__header__icon {
@@ -154,6 +160,13 @@
   line-height: 24px;
 }
 
+.search-section__header__link {
+  padding: 2px 10px 0;
+  color: $text-muted;
+  opacity: 0;
+  transition: opacity 150ms ease-in-out;
+}
+
 .search-item {
   @include list-item();
 
@@ -181,12 +194,6 @@
   color: $list-item-link-color;
 }
 
-.search-item__body-sub-title {
-  color: $text-muted;
-  font-size: $font-size-sm;
-  line-height: 9pt;
-}
-
 .search-item__icon {
   padding: 5px;
   flex: 0 0 auto;