Browse Source

Merge branch 'master' into 10190_fix_select_icon_and_firefox

Johannes Schill 8 years ago
parent
commit
143c0022b8

+ 3 - 3
public/app/core/components/navbar/navbar.ts

@@ -1,15 +1,15 @@
 import coreModule from '../../core_module';
 import {NavModel}  from '../../nav_model_srv';
+import appEvents from 'app/core/app_events';
 
 export class NavbarCtrl {
   model: NavModel;
 
   /** @ngInject */
-  constructor(private $rootScope) {
-  }
+  constructor() {}
 
   showSearch() {
-    this.$rootScope.appEvent('show-dash-search');
+    appEvents.emit('show-dash-search');
   }
 
   navItemClicked(navItem, evt) {

+ 2 - 2
public/app/core/components/search/search.html

@@ -57,11 +57,11 @@
       <div class="search-filter-box">
         <a href="dashboard/new" class="search-filter-box-link">
           <i class="gicon gicon-dashboard-new"></i>
-          Dashboard
+          New dashboard
         </a>
         <a href="dashboards/folder/new" class="search-filter-box-link">
           <i class="gicon gicon-folder-new"></i>
-          Folder
+          New folder
         </a>
         <a class="search-filter-box-link" target="_blank" href="https://grafana.com/dashboards?utm_source=grafana_search">
           <img src="public/img/icn-dashboard-tiny.svg" width="20" /> Find  dashboards on Grafana.com

+ 5 - 3
public/app/core/components/search/search.ts

@@ -1,6 +1,7 @@
 import _ from 'lodash';
 import coreModule from '../../core_module';
 import { SearchSrv } from 'app/core/services/search_srv';
+import appEvents from 'app/core/app_events';
 
 export class SearchCtrl {
   isOpen: boolean;
@@ -16,9 +17,9 @@ export class SearchCtrl {
   initialFolderFilterTitle: string;
 
   /** @ngInject */
-  constructor($scope, private $location, private $timeout, private searchSrv: SearchSrv, $rootScope) {
-    $rootScope.onAppEvent('show-dash-search', this.openSearch.bind(this), $scope);
-    $rootScope.onAppEvent('hide-dash-search', this.closeSearch.bind(this), $scope);
+  constructor($scope, private $location, private $timeout, private searchSrv: SearchSrv) {
+    appEvents.on('show-dash-search', this.openSearch.bind(this), $scope);
+    appEvents.on('hide-dash-search', this.closeSearch.bind(this), $scope);
 
     this.initialFolderFilterTitle = "All";
   }
@@ -74,6 +75,7 @@ export class SearchCtrl {
           if (selectedDash) {
             this.$location.search({});
             this.$location.path(selectedDash.url);
+            this.closeSearch();
           }
         } else {
           const selectedFolder = this.results[currentItem.folderIndex];

+ 1 - 1
public/app/core/components/search/search_results.html

@@ -32,7 +32,7 @@
       <span class="search-item__icon">
         <i class="gicon mini gicon-dashboard-list"></i>
       </span>
-      <span class="search-item__body">
+      <span class="search-item__body" ng-click="ctrl.onItemClick(item)">
         <div class="search-item__body-title">{{::item.title}}</div>
       </span>
       <span class="search-item__tags">

+ 7 - 0
public/app/core/components/search/search_results.ts

@@ -1,5 +1,6 @@
 import _ from 'lodash';
 import coreModule from '../../core_module';
+import appEvents from 'app/core/app_events';
 
 export class SearchResultsCtrl {
   results: any;
@@ -61,6 +62,12 @@ export class SearchResultsCtrl {
     }
   }
 
+  onItemClick(item) {
+    if (this.$location.path().indexOf(item.url) > -1) {
+      appEvents.emit('hide-dash-search');
+    }
+  }
+
   selectTag(tag, evt) {
     if (this.onTagSelected) {
       this.onTagSelected({$tag: tag});

+ 3 - 3
public/app/core/services/keybindingSrv.ts

@@ -36,15 +36,15 @@ export class KeybindingSrv {
   }
 
   openSearchStarred() {
-    this.$rootScope.appEvent('show-dash-search', {starred: true});
+    appEvents.emit('show-dash-search', {starred: true});
   }
 
   openSearchTags() {
-    this.$rootScope.appEvent('show-dash-search', {tagsMode: true});
+    appEvents.emit('show-dash-search', {tagsMode: true});
   }
 
   openSearch() {
-    this.$rootScope.appEvent('show-dash-search');
+    appEvents.emit('show-dash-search');
   }
 
   openAlerting() {

+ 1 - 1
public/app/core/specs/search.jest.ts

@@ -6,7 +6,7 @@ describe('SearchCtrl', () => {
     search: (options: any) => {},
     getDashboardTags: () => {}
   };
-  let ctrl = new SearchCtrl({}, {}, {}, <SearchSrv>searchSrvStub, { onAppEvent: () => { } });
+  let ctrl = new SearchCtrl({$on: () => {}}, {}, {}, <SearchSrv>searchSrvStub);
 
   describe('Given an empty result', () => {
     beforeEach(() => {

+ 43 - 0
public/app/core/specs/search_results.jest.ts

@@ -1,4 +1,12 @@
 import { SearchResultsCtrl } from '../components/search/search_results';
+import { beforeEach, afterEach } from 'test/lib/common';
+import appEvents from 'app/core/app_events';
+
+jest.mock('app/core/app_events', () => {
+  return {
+    emit: jest.fn<any>()
+  };
+});
 
 describe('SearchResultsCtrl', () => {
   let ctrl;
@@ -94,4 +102,39 @@ describe('SearchResultsCtrl', () => {
       expect(folderExpanded).toBeFalsy();
     });
   });
+
+  describe('when clicking on a link in search result', () => {
+    const dashPath = 'dashboard/path';
+    const $location = { path: () =>  dashPath};
+    const appEventsMock = appEvents as any;
+
+    describe('with the same url as current path', () => {
+      beforeEach(() => {
+        ctrl = new SearchResultsCtrl($location);
+        const item = { url: dashPath};
+        ctrl.onItemClick(item);
+      });
+
+      it('should close the search', () => {
+        expect(appEventsMock.emit.mock.calls.length).toBe(1);
+        expect(appEventsMock.emit.mock.calls[0][0]).toBe('hide-dash-search');
+      });
+    });
+
+    describe('with a different url than current path', () => {
+      beforeEach(() => {
+        ctrl = new SearchResultsCtrl($location);
+        const item = { url: 'another/path'};
+        ctrl.onItemClick(item);
+      });
+
+      it('should do nothing', () => {
+        expect(appEventsMock.emit.mock.calls.length).toBe(0);
+      });
+    });
+
+    afterEach(() => {
+      appEventsMock.emit.mockClear();
+    });
+  });
 });

+ 2 - 2
public/app/features/dashboard/dashnav/dashnav.html

@@ -33,9 +33,9 @@
 			<i class="fa fa-save"></i>
 		</button>
 
-		<button class="btn navbar-button navbar-button--snapshot-origin" ng-if="::ctrl.dashboard.snapshot.originalUrl" ng-href="{{ctrl.dashboard.snapshot.originalUrl}}" bs-tooltip="'Open original dashboard'" data-placement="bottom">
+		<a class="btn navbar-button navbar-button--snapshot-origin" ng-if="::ctrl.dashboard.snapshot.originalUrl" href="{{ctrl.dashboard.snapshot.originalUrl}}" bs-tooltip="'Open original dashboard'" data-placement="bottom">
 			<i class="fa fa-link"></i>
-		</button>
+		</a>
 
 		<button class="btn navbar-button navbar-button--settings" ng-click="ctrl.toggleSettings()" bs-tooltip="'Settings'" data-placement="bottom" ng-show="ctrl.dashboard.meta.showSettings">
 			<i class="fa fa-cog"></i>

+ 1 - 2
public/app/features/dashboard/dashnav/dashnav.ts

@@ -11,7 +11,6 @@ export class DashNavCtrl {
   /** @ngInject */
   constructor(
     private $scope,
-    private $rootScope,
     private dashboardSrv,
     private $location,
     public playlistSrv) {
@@ -75,7 +74,7 @@ export class DashNavCtrl {
     }
 
     showSearch() {
-      this.$rootScope.appEvent('show-dash-search');
+      appEvents.emit('show-dash-search');
     }
 
     addPanel() {

+ 2 - 2
public/app/features/org/teams_ctrl.ts

@@ -1,7 +1,7 @@
 ///<reference path="../../headers/common.d.ts" />
 
-import coreModule from "app/core/core_module";
-import { appEvents } from "app/core/core";
+import coreModule from 'app/core/core_module';
+import appEvents from 'app/core/app_events';
 
 export class TeamsCtrl {
   teams: any;

+ 115 - 66
public/app/features/panel/panel_ctrl.ts

@@ -1,15 +1,15 @@
-import config from 'app/core/config';
-import _ from 'lodash';
-import $ from 'jquery';
-import {appEvents, profiler} from 'app/core/core';
-import { PanelModel } from 'app/features/dashboard/panel_model';
-import Remarkable from 'remarkable';
-import {GRID_CELL_HEIGHT, GRID_CELL_VMARGIN} from 'app/core/constants';
+import config from "app/core/config";
+import _ from "lodash";
+import $ from "jquery";
+import { appEvents, profiler } from "app/core/core";
+import { PanelModel } from "app/features/dashboard/panel_model";
+import Remarkable from "remarkable";
+import { GRID_CELL_HEIGHT, GRID_CELL_VMARGIN } from "app/core/constants";
 
 const TITLE_HEIGHT = 27;
 const PANEL_BORDER = 2;
 
-import {Emitter} from 'app/core/core';
+import { Emitter } from "app/core/core";
 
 export class PanelCtrl {
   panel: any;
@@ -35,7 +35,7 @@ export class PanelCtrl {
   constructor($scope, $injector) {
     this.$injector = $injector;
     this.$scope = $scope;
-    this.$timeout = $injector.get('$timeout');
+    this.$timeout = $injector.get("$timeout");
     this.editorTabIndex = 0;
     this.events = this.panel.events;
     this.timing = {};
@@ -50,18 +50,18 @@ export class PanelCtrl {
     $scope.$on("component-did-mount", () => this.panelDidMount());
 
     $scope.$on("$destroy", () => {
-      this.events.emit('panel-teardown');
+      this.events.emit("panel-teardown");
       this.events.removeAllListeners();
     });
   }
 
   init() {
-    this.events.emit('panel-initialized');
-    this.publishAppEvent('panel-initialized', {scope: this.$scope});
+    this.events.emit("panel-initialized");
+    this.publishAppEvent("panel-initialized", { scope: this.$scope });
   }
 
   panelDidMount() {
-    this.events.emit('component-did-mount');
+    this.events.emit("component-did-mount");
   }
 
   renderingCompleted() {
@@ -69,7 +69,7 @@ export class PanelCtrl {
   }
 
   refresh() {
-    this.events.emit('refresh', null);
+    this.events.emit("refresh", null);
   }
 
   publishAppEvent(evtName, evt) {
@@ -77,8 +77,10 @@ export class PanelCtrl {
   }
 
   changeView(fullscreen, edit) {
-    this.publishAppEvent('panel-change-view', {
-      fullscreen: fullscreen, edit: edit, panelId: this.panel.id
+    this.publishAppEvent("panel-change-view", {
+      fullscreen: fullscreen,
+      edit: edit,
+      panelId: this.panel.id
     });
   }
 
@@ -96,11 +98,11 @@ export class PanelCtrl {
 
   initEditMode() {
     this.editorTabs = [];
-    this.addEditorTab('General', 'public/app/partials/panelgeneral.html');
+    this.addEditorTab("General", "public/app/partials/panelgeneral.html");
     this.editModeInitiated = true;
-    this.events.emit('init-edit-mode', null);
+    this.events.emit("init-edit-mode", null);
 
-    var urlTab = (this.$injector.get('$routeParams').tab || '').toLowerCase();
+    var urlTab = (this.$injector.get("$routeParams").tab || "").toLowerCase();
     if (urlTab) {
       this.editorTabs.forEach((tab, i) => {
         if (tab.title.toLowerCase() === urlTab) {
@@ -112,17 +114,17 @@ export class PanelCtrl {
 
   changeTab(newIndex) {
     this.editorTabIndex = newIndex;
-    var route = this.$injector.get('$route');
+    var route = this.$injector.get("$route");
     route.current.params.tab = this.editorTabs[newIndex].title.toLowerCase();
     route.updateParams();
   }
 
   addEditorTab(title, directiveFn, index?) {
-    var editorTab = {title, directiveFn};
+    var editorTab = { title, directiveFn };
 
     if (_.isString(directiveFn)) {
       editorTab.directiveFn = function() {
-        return {templateUrl: directiveFn};
+        return { templateUrl: directiveFn };
       };
     }
     if (index) {
@@ -134,20 +136,47 @@ export class PanelCtrl {
 
   getMenu() {
     let menu = [];
-    menu.push({text: 'View', click: 'ctrl.viewPanel();', icon: "fa fa-fw fa-eye", shortcut: "v"});
+    menu.push({
+      text: "View",
+      click: "ctrl.viewPanel();",
+      icon: "fa fa-fw fa-eye",
+      shortcut: "v"
+    });
 
     if (this.dashboard.meta.canEdit) {
-      menu.push({text: 'Edit', click: 'ctrl.editPanel();', role: 'Editor', icon: "fa fa-fw fa-edit", shortcut: "e"});
+      menu.push({
+        text: "Edit",
+        click: "ctrl.editPanel();",
+        role: "Editor",
+        icon: "fa fa-fw fa-edit",
+        shortcut: "e"
+      });
     }
 
-    menu.push({text: 'Share', click: 'ctrl.sharePanel();', icon: "fa fa-fw fa-share", shortcut: "p s"});
+    menu.push({
+      text: "Share",
+      click: "ctrl.sharePanel();",
+      icon: "fa fa-fw fa-share",
+      shortcut: "p s"
+    });
 
     let extendedMenu = this.getExtendedMenu();
-    menu.push({text: 'More ...', click: 'ctrl.removePanel();', icon: "fa fa-fw fa-cube", submenu: extendedMenu});
+    menu.push({
+      text: "More ...",
+      click: "",
+      icon: "fa fa-fw fa-cube",
+      submenu: extendedMenu
+    });
 
     if (this.dashboard.meta.canEdit) {
-      menu.push({divider: true, role: 'Editor'});
-      menu.push({text: 'Remove', click: 'ctrl.removePanel();', role: 'Editor', icon: "fa fa-fw fa-trash", shortcut: "p r"});
+      menu.push({ divider: true, role: "Editor" });
+      menu.push({
+        text: "Remove",
+        click: "ctrl.removePanel();",
+        role: "Editor",
+        icon: "fa fa-fw fa-trash",
+        shortcut: "p r"
+      });
     }
 
     return menu;
@@ -156,10 +185,17 @@ export class PanelCtrl {
   getExtendedMenu() {
     let menu = [];
     if (!this.fullscreen && this.dashboard.meta.canEdit) {
-      menu.push({ text: 'Duplicate', click: 'ctrl.duplicate()', role: 'Editor' });
+      menu.push({
+        text: "Duplicate",
+        click: "ctrl.duplicate()",
+        role: "Editor"
+      });
     }
-    menu.push({text: 'Panel JSON', click: 'ctrl.editPanelJson(); dismiss();' });
-    this.events.emit('init-panel-actions', menu);
+    menu.push({
+      text: "Panel JSON",
+      click: "ctrl.editPanelJson(); dismiss();"
+    });
+    this.events.emit("init-panel-actions", menu);
     return menu;
   }
 
@@ -169,12 +205,14 @@ export class PanelCtrl {
 
   calculatePanelHeight() {
     if (this.fullscreen) {
-       var docHeight = $(window).height();
-       var editHeight = Math.floor(docHeight * 0.4);
-       var fullscreenHeight = Math.floor(docHeight * 0.8);
-       this.containerHeight = this.editMode ? editHeight : fullscreenHeight;
+      var docHeight = $(window).height();
+      var editHeight = Math.floor(docHeight * 0.4);
+      var fullscreenHeight = Math.floor(docHeight * 0.8);
+      this.containerHeight = this.editMode ? editHeight : fullscreenHeight;
     } else {
-      this.containerHeight = this.panel.gridPos.h * GRID_CELL_HEIGHT + ((this.panel.gridPos.h-1) * GRID_CELL_VMARGIN);
+      this.containerHeight =
+        this.panel.gridPos.h * GRID_CELL_HEIGHT +
+        (this.panel.gridPos.h - 1) * GRID_CELL_VMARGIN;
     }
 
     if (this.panel.soloMode) {
@@ -186,13 +224,13 @@ export class PanelCtrl {
 
   render(payload?) {
     this.timing.renderStart = new Date().getTime();
-    this.events.emit('render', payload);
+    this.events.emit("render", payload);
   }
 
   duplicate() {
     this.dashboard.duplicatePanel(this.panel);
     this.$timeout(() => {
-      this.$scope.$root.$broadcast('render');
+      this.$scope.$root.$broadcast("render");
     });
   }
 
@@ -202,17 +240,18 @@ export class PanelCtrl {
       var text2, confirmText;
 
       if (this.panel.alert) {
-        text2 = "Panel includes an alert rule, removing panel will also remove alert rule";
+        text2 =
+          "Panel includes an alert rule, removing panel will also remove alert rule";
         confirmText = "YES";
       }
 
-      appEvents.emit('confirm-modal', {
-        title: 'Remove Panel',
-        text: 'Are you sure you want to remove this panel?',
+      appEvents.emit("confirm-modal", {
+        title: "Remove Panel",
+        text: "Are you sure you want to remove this panel?",
         text2: text2,
-        icon: 'fa-trash',
+        icon: "fa-trash",
         confirmText: confirmText,
-        yesText: 'Remove',
+        yesText: "Remove",
         onConfirm: () => {
           this.removePanel(false);
         }
@@ -228,27 +267,27 @@ export class PanelCtrl {
     editScope.object = this.panel.getSaveModel();
     editScope.updateHandler = this.replacePanel.bind(this);
 
-    this.publishAppEvent('show-modal', {
-      src: 'public/app/partials/edit_json.html',
+    this.publishAppEvent("show-modal", {
+      src: "public/app/partials/edit_json.html",
       scope: editScope
     });
   }
 
   replacePanel(newPanel, oldPanel) {
     let dashboard = this.dashboard;
-    let index = _.findIndex(dashboard.panels, (panel) => {
+    let index = _.findIndex(dashboard.panels, panel => {
       return panel.id === oldPanel.id;
     });
 
     let deletedPanel = dashboard.panels.splice(index, 1);
-    this.dashboard.events.emit('panel-removed', deletedPanel);
+    this.dashboard.events.emit("panel-removed", deletedPanel);
 
     newPanel = new PanelModel(newPanel);
     newPanel.id = oldPanel.id;
 
     dashboard.panels.splice(index, 0, newPanel);
     dashboard.sortPanelsByGridPos();
-    dashboard.events.emit('panel-added', newPanel);
+    dashboard.events.emit("panel-added", newPanel);
   }
 
   sharePanel() {
@@ -256,60 +295,70 @@ export class PanelCtrl {
     shareScope.panel = this.panel;
     shareScope.dashboard = this.dashboard;
 
-    this.publishAppEvent('show-modal', {
-      src: 'public/app/features/dashboard/partials/shareModal.html',
+    this.publishAppEvent("show-modal", {
+      src: "public/app/features/dashboard/partials/shareModal.html",
       scope: shareScope
     });
   }
 
   getInfoMode() {
     if (this.error) {
-      return 'error';
+      return "error";
     }
     if (!!this.panel.description) {
-      return 'info';
+      return "info";
     }
     if (this.panel.links && this.panel.links.length) {
-      return 'links';
+      return "links";
     }
-    return '';
+    return "";
   }
 
   getInfoContent(options) {
     var markdown = this.panel.description;
 
-    if (options.mode === 'tooltip') {
+    if (options.mode === "tooltip") {
       markdown = this.error || this.panel.description;
     }
 
-    var linkSrv = this.$injector.get('linkSrv');
-    var templateSrv = this.$injector.get('templateSrv');
-    var interpolatedMarkdown = templateSrv.replace(markdown, this.panel.scopedVars);
+    var linkSrv = this.$injector.get("linkSrv");
+    var templateSrv = this.$injector.get("templateSrv");
+    var interpolatedMarkdown = templateSrv.replace(
+      markdown,
+      this.panel.scopedVars
+    );
     var html = '<div class="markdown-html">';
 
     html += new Remarkable().render(interpolatedMarkdown);
 
     if (this.panel.links && this.panel.links.length > 0) {
-      html += '<ul>';
+      html += "<ul>";
       for (let link of this.panel.links) {
         var info = linkSrv.getPanelLinkAnchorInfo(link, this.panel.scopedVars);
-        html += '<li><a class="panel-menu-link" href="' + info.href + '" target="' + info.target + '">' + info.title + '</a></li>';
+        html +=
+          '<li><a class="panel-menu-link" href="' +
+          info.href +
+          '" target="' +
+          info.target +
+          '">' +
+          info.title +
+          "</a></li>";
       }
-      html += '</ul>';
+      html += "</ul>";
     }
 
-    return html + '</div>';
+    return html + "</div>";
   }
 
   openInspector() {
     var modalScope = this.$scope.$new();
     modalScope.panel = this.panel;
     modalScope.dashboard = this.dashboard;
-    modalScope.panelInfoHtml = this.getInfoContent({mode: 'inspector'});
+    modalScope.panelInfoHtml = this.getInfoContent({ mode: "inspector" });
 
     modalScope.inspector = $.extend(true, {}, this.inspector);
-    this.publishAppEvent('show-modal', {
-      src: 'public/app/features/dashboard/partials/inspector.html',
+    this.publishAppEvent("show-modal", {
+      src: "public/app/features/dashboard/partials/inspector.html",
       scope: modalScope
     });
   }