فهرست منبع

Merge branch 'master' into alerting_definitions

bergquist 9 سال پیش
والد
کامیت
bcf10a6483
49فایلهای تغییر یافته به همراه329 افزوده شده و 300 حذف شده
  1. 14 1
      CHANGELOG.md
  2. 0 29
      docs/sources/http_api/data_source.md
  3. 3 3
      docs/sources/installation/debian.md
  4. 4 4
      docs/sources/installation/rpm.md
  5. 3 2
      karma.conf.js
  6. 1 1
      latest.json
  7. 1 1
      package.json
  8. 8 8
      packaging/publish/publish.sh
  9. 3 3
      pkg/api/api.go
  10. 6 5
      pkg/cmd/grafana-cli/main.go
  11. 1 1
      pkg/plugins/update_checker.go
  12. 2 11
      public/app/core/components/colorpicker.ts
  13. 3 0
      public/app/core/components/dashboard_selector.ts
  14. 16 7
      public/app/core/components/info_popover.ts
  15. 6 17
      public/app/core/components/switch.ts
  16. 2 0
      public/app/core/time_series2.ts
  17. 1 1
      public/app/features/dashboard/dashnav/dashnav.html
  18. 7 4
      public/app/features/dashboard/partials/settings.html
  19. 8 14
      public/app/features/dashboard/timepicker/timepicker.html
  20. 1 1
      public/app/features/dashboard/timepicker/timepicker.ts
  21. 0 1
      public/app/features/dashboard/unsavedChangesSrv.js
  22. 3 4
      public/app/features/org/prefs_control.ts
  23. 1 1
      public/app/features/panel/metrics_panel_ctrl.ts
  24. 10 3
      public/app/features/plugins/ds_edit_ctrl.ts
  25. 8 12
      public/app/features/plugins/partials/ds_edit.html
  26. 30 25
      public/app/features/plugins/partials/ds_http_settings.html
  27. 1 1
      public/app/features/plugins/partials/update_instructions.html
  28. 51 50
      public/app/features/templating/partials/editor.html
  29. 1 0
      public/app/features/templating/templateValuesSrv.js
  30. 14 14
      public/app/partials/help_modal.html
  31. 17 12
      public/app/plugins/datasource/cloudwatch/partials/config.html
  32. 1 1
      public/app/plugins/datasource/prometheus/datasource.ts
  33. 0 1
      public/app/plugins/panel/graph/legend.js
  34. 6 5
      public/app/plugins/panel/graph/module.ts
  35. 1 0
      public/app/plugins/panel/graph/series_overrides_ctrl.js
  36. 28 28
      public/app/plugins/panel/pluginlist/module.html
  37. 4 2
      public/app/plugins/panel/pluginlist/module.ts
  38. 1 5
      public/app/plugins/panel/singlestat/module.ts
  39. 1 5
      public/app/plugins/panel/table/module.ts
  40. 7 5
      public/sass/_variables.dark.scss
  41. 5 4
      public/sass/_variables.light.scss
  42. 3 5
      public/sass/base/_code.scss
  43. 1 0
      public/sass/components/_drop.scss
  44. 28 0
      public/sass/components/_gf-form.scss
  45. 2 1
      public/sass/components/_panel_graph.scss
  46. 1 0
      public/sass/components/_panel_text.scss
  47. 12 0
      public/sass/components/_timepicker.scss
  48. 1 0
      public/sass/components/_tooltip.scss
  49. 1 2
      public/sass/pages/_login.scss

+ 14 - 1
CHANGELOG.md

@@ -1,4 +1,17 @@
-# 3.0.0-beta3 (unreleased)
+# 3.0.0-beta5 (2016-04-15)
+
+### Bug fixes
+* **grafana-cli**: Fixed issue grafana-cli tool, did not detect the right plugin dir, fixes [#4723](https://github.com/grafana/grafana/issues/4723)
+* **Graph**: Fixed issue with light theme text color issue in tooltip, fixes [#4702](https://github.com/grafana/grafana/issues/4702)
+* **Snapshot**: Fixed issue with empty snapshots, fixes [#4706](https://github.com/grafana/grafana/issues/4706)
+
+# 3.0.0-beta4 (2016-04-13)
+
+### Bug fixes
+* **Home dashboard**: Fixed issue with permission denied error on home dashboard, fixes [#4686](https://github.com/grafana/grafana/issues/4686)
+* **Templating**: Fixed issue templating variables that use regex extraction, fixes [#4672](https://github.com/grafana/grafana/issues/4672)
+
+# 3.0.0-beta3 (2016-04-12)
 
 ### Enhancements
 * **InfluxDB**: Changed multi query encoding to work with InfluxDB 0.11 & 0.12, closes [#4533](https://github.com/grafana/grafana/issues/4533)

+ 0 - 29
docs/sources/http_api/data_source.md

@@ -207,35 +207,6 @@ page_keywords: grafana, admin, http, api, documentation, datasource
 
     {"message":"Data source deleted"}
 
-## Available data source types
-
-`GET /api/datasources/plugins`
-
-**Example Request**:
-
-    GET /api/datasources/plugins HTTP/1.1
-    Accept: application/json
-    Content-Type: application/json
-    Authorization: Bearer eyJrIjoiT0tTcG1pUlY2RnVKZTFVaDFsNFZXdE9ZWmNrMkZYbk
-
-**Example Response**:
-
-    HTTP/1.1 200
-    Content-Type: application/json
-
-    {
-      "grafana":{
-        "metrics":true,"module":"plugins/datasource/grafana/datasource",
-        "name":"Grafana (for testing)",
-        "partials":{
-          "query":"app/plugins/datasource/grafana/partials/query.editor.html"
-        },
-        "pluginType":"datasource",
-        "serviceName":"GrafanaDatasource",
-        "type":"grafana"
-      }
-    }
-
 ## Data source proxy calls
 
 `GET /api/datasources/proxy/:datasourceId/*`

+ 3 - 3
docs/sources/installation/debian.md

@@ -11,7 +11,7 @@ page_keywords: grafana, installation, debian, ubuntu, guide
 Description | Download
 ------------ | -------------
 Stable .deb for Debian-based Linux | [grafana_2.6.0_amd64.deb](https://grafanarel.s3.amazonaws.com/builds/grafana_2.6.0_amd64.deb)
-Beta .deb for Debian-based Linux |   [grafana_3.0.0-beta31460467884_amd64.deb](https://grafanarel.s3.amazonaws.com/builds/grafana_3.0.0-beta31460467884_amd64.deb)
+Beta .deb for Debian-based Linux |   [grafana_3.0.0-beta51460725904_amd64.deb](https://grafanarel.s3.amazonaws.com/builds/grafana_3.0.0-beta51460725904_amd64.deb)
 
 ## Install Stable
 
@@ -21,9 +21,9 @@ Beta .deb for Debian-based Linux |   [grafana_3.0.0-beta31460467884_amd64.deb](h
 
 ## Install 3.0 Beta
 
-    $ wget https://grafanarel.s3.amazonaws.com/builds/grafana_3.0.0-beta31460467884_amd64.deb
+    $ wget https://grafanarel.s3.amazonaws.com/builds/grafana_3.0.0-beta51460725904_amd64.deb
     $ sudo apt-get install -y adduser libfontconfig
-    $ sudo dpkg -i grafana_3.0.0-beta31460467884_amd64.deb
+    $ sudo dpkg -i grafana_3.0.0-beta51460725904_amd64.deb
 
 ## APT Repository
 

+ 4 - 4
docs/sources/installation/rpm.md

@@ -11,7 +11,7 @@ page_keywords: grafana, installation, centos, fedora, opensuse, redhat, guide
 Description | Download
 ------------ | -------------
 Stable .RPM for CentOS / Fedora / OpenSuse / Redhat Linux | [grafana-2.6.0-1.x86_64.rpm](https://grafanarel.s3.amazonaws.com/builds/grafana-2.6.0-1.x86_64.rpm)
-Beta .RPM for CentOS / Fedor / OpenSuse / Redhat Linux | [grafana-3.0.0-beta31460467884.x86_64.rpm](https://grafanarel.s3.amazonaws.com/builds/grafana-3.0.0-beta31460467884§.x86_64.rpm)
+Beta .RPM for CentOS / Fedor / OpenSuse / Redhat Linux | [grafana-3.0.0-beta51460725904.x86_64.rpm](https://grafanarel.s3.amazonaws.com/builds/grafana-3.0.0-beta51460725904§.x86_64.rpm)
 
 ## Install Stable Release from package file
 
@@ -34,18 +34,18 @@ Or install manually using `rpm`.
 
 You can install Grafana using Yum directly.
 
-    $ sudo yum install https://grafanarel.s3.amazonaws.com/builds/grafana-3.0.0-beta31460467884.x86_64.rpm
+    $ sudo yum install https://grafanarel.s3.amazonaws.com/builds/grafana-3.0.0-beta51460725904.x86_64.rpm
 
 Or install manually using `rpm`.
 
 #### On CentOS / Fedora / Redhat:
 
     $ sudo yum install initscripts fontconfig
-    $ sudo rpm -Uvh grafana-3.0.0-beta31460467884.x86_64.rpm
+    $ sudo rpm -Uvh grafana-3.0.0-beta51460725904.x86_64.rpm
 
 #### On OpenSuse:
 
-    $ sudo rpm -i --nodeps grafana-3.0.0-beta31460467884.x86_64.rpm
+    $ sudo rpm -i --nodeps grafana-3.0.0-beta51460725904.x86_64.rpm
 
 
 ## Install via YUM Repository

+ 3 - 2
karma.conf.js

@@ -24,9 +24,10 @@ module.exports = function(config) {
     logLevel: config.LOG_INFO,
     autoWatch: true,
     browsers: ['PhantomJS'],
-    captureTimeout: 2000,
+    captureTimeout: 20000,
     singleRun: true,
-    autoWatchBatchDelay: 1000,
+    autoWatchBatchDelay: 10000,
+    browserNoActivityTimeout: 60000,
 
   });
 

+ 1 - 1
latest.json

@@ -1,4 +1,4 @@
 {
   "stable": "2.6.0",
-	"testing": "3.0.0-beta2"
+	"testing": "3.0.0-beta5"
 }

+ 1 - 1
package.json

@@ -4,7 +4,7 @@
     "company": "Coding Instinct AB"
   },
   "name": "grafana",
-  "version": "3.0.0-beta4",
+  "version": "3.0.0-beta6",
   "repository": {
     "type": "git",
     "url": "http://github.com/grafana/grafana.git"

+ 8 - 8
packaging/publish/publish.sh

@@ -1,22 +1,22 @@
 #! /usr/bin/env bash
 
-deb_ver=3.0.0-beta31460467884
-rpm_ver=3.0.0-beta31460467884
+deb_ver=3.0.0-beta51460725904
+rpm_ver=3.0.0-beta51460725904
 
 #rpm_ver=3.0.0-1
 
-# wget https://grafanarel.s3.amazonaws.com/builds/grafana_${deb_ver}_amd64.deb
+#wget https://grafanarel.s3.amazonaws.com/builds/grafana_${deb_ver}_amd64.deb
 
 #package_cloud push grafana/stable/debian/jessie grafana_${deb_ver}_amd64.deb
 #package_cloud push grafana/stable/debian/wheezy grafana_${deb_ver}_amd64.deb
 
-# package_cloud push grafana/testing/debian/jessie grafana_${deb_ver}_amd64.deb
-package_cloud push grafana/testing/debian/wheezy grafana_${deb_ver}_amd64.deb
+#package_cloud push grafana/testing/debian/jessie grafana_${deb_ver}_amd64.deb
+#package_cloud push grafana/testing/debian/wheezy grafana_${deb_ver}_amd64.deb
 
-wget https://grafanarel.s3.amazonaws.com/builds/grafana-${rpm_ver}.x86_64.rpm
+#wget https://grafanarel.s3.amazonaws.com/builds/grafana-${rpm_ver}.x86_64.rpm
 
-package_cloud push grafana/testing/el/6 grafana-${rpm_ver}.x86_64.rpm
-ackage_cloud push grafana/testing/el/7 grafana-${rpm_ver}.x86_64.rpm
+#package_cloud push grafana/testing/el/6 grafana-${rpm_ver}.x86_64.rpm
+package_cloud push grafana/testing/el/7 grafana-${rpm_ver}.x86_64.rpm
 
 # package_cloud push grafana/stable/el/7 grafana-${version}-1.x86_64.rpm
 # package_cloud push grafana/stable/el/6 grafana-${version}-1.x86_64.rpm

+ 3 - 3
pkg/api/api.go

@@ -191,12 +191,12 @@ func Register(r *macaron.Macaron) {
 
 		r.Get("/datasources/id/:name", wrap(GetDataSourceIdByName), reqSignedIn)
 
-		r.Group("/plugins", func() {
-			r.Get("/", wrap(GetPluginList))
+		r.Get("/plugins", wrap(GetPluginList))
+		r.Get("/plugins/:pluginId/settings", wrap(GetPluginSettingById))
 
+		r.Group("/plugins", func() {
 			r.Get("/:pluginId/readme", wrap(GetPluginReadme))
 			r.Get("/:pluginId/dashboards/", wrap(GetPluginDashboards))
-			r.Get("/:pluginId/settings", wrap(GetPluginSettingById))
 			r.Post("/:pluginId/settings", bind(m.UpdatePluginSettingCmd{}), wrap(UpdatePluginSetting))
 		}, reqOrgAdmin)
 

+ 6 - 5
pkg/cmd/grafana-cli/main.go

@@ -8,6 +8,7 @@ import (
 	"github.com/codegangsta/cli"
 	"github.com/grafana/grafana/pkg/cmd/grafana-cli/commands"
 	"github.com/grafana/grafana/pkg/cmd/grafana-cli/log"
+	"strings"
 )
 
 var version = "master"
@@ -17,7 +18,7 @@ func getGrafanaPluginDir() string {
 	defaultNix := "/var/lib/grafana/plugins"
 
 	if currentOS == "windows" {
-		return "..\\data\\plugins"
+		return "C:\\opt\\grafana\\plugins"
 	}
 
 	pwd, err := os.Getwd()
@@ -28,16 +29,16 @@ func getGrafanaPluginDir() string {
 	}
 
 	if isDevenvironment(pwd) {
-		return "../data/plugins"
+		return "../../../data/plugins"
 	}
 
 	return defaultNix
 }
 
 func isDevenvironment(pwd string) bool {
-	// if ../conf/default.ini exists, grafana is not installed as package
-	_, err := os.Stat("../conf/default.ini")
-	return err != nil
+	// if grafana-cli is executed from the cmd folder we can assume
+	// that its in development environment.
+	return strings.HasSuffix(pwd, "/pkg/cmd/grafana-cli")
 }
 
 func main() {

+ 1 - 1
pkg/plugins/update_checker.go

@@ -111,7 +111,7 @@ func checkForUpdates() {
 
 	if strings.Contains(setting.BuildVersion, "-") {
 		GrafanaLatestVersion = githubLatest.Testing
-		GrafanaHasUpdate = strings.HasPrefix(setting.BuildVersion, githubLatest.Testing)
+		GrafanaHasUpdate = !strings.HasPrefix(setting.BuildVersion, githubLatest.Testing)
 	} else {
 		GrafanaLatestVersion = githubLatest.Stable
 		GrafanaHasUpdate = githubLatest.Stable != setting.BuildVersion

+ 2 - 11
public/app/core/components/colorpicker.ts

@@ -7,10 +7,6 @@ import coreModule from 'app/core/core_module';
 
 var template = `
 <div class="graph-legend-popover">
-  <a class="drop-popopver-close" ng-click="ctrl.close();" href="" ng-hide="ctrl.autoClose">
-    <i class="fa fa-times-circle"></i>
-  </a>
-
   <div ng-show="ctrl.series" class="p-b-1">
     <label>Y Axis:</label>
     <button ng-click="ctrl.toggleAxis(yaxis);" class="btn btn-small"
@@ -31,7 +27,6 @@ var template = `
     ng-style="{color:color}"
     ng-click="ctrl.colorSelected(color);">&nbsp;</i>
   </p>
-
 </div>
 `;
 
@@ -51,21 +46,17 @@ export class ColorPickerCtrl {
   toggleAxis(yaxis) {
     this.$scope.toggleAxis();
 
-    if (!this.$scope.autoClose) {
+    if (this.$scope.autoClose) {
       this.$scope.dismiss();
     }
   }
 
   colorSelected(color) {
     this.$scope.colorSelected(color);
-    if (!this.$scope.autoClose) {
+    if (this.$scope.autoClose) {
       this.$scope.dismiss();
     }
   }
-
-  close() {
-    this.$scope.dismiss();
-  }
 }
 
 export function colorPicker() {

+ 3 - 0
public/app/core/components/dashboard_selector.ts

@@ -7,6 +7,9 @@ import coreModule from 'app/core/core_module';
 
 var template = `
 <select class="gf-form-input" ng-model="ctrl.model" ng-options="f.value as f.text for f in ctrl.options"></select>
+<info-popover mode="right-absolute">
+  Not finding dashboard you want? Star it first, then it should appear in this select box.
+</info-popover>
 `;
 
 export class DashboardSelectorCtrl {

+ 16 - 7
public/app/core/components/info_popover.ts

@@ -8,21 +8,30 @@ import Drop from 'tether-drop';
 export function infoPopover() {
   return {
     restrict: 'E',
+    template: '<i class="fa fa-info-circle"></i>',
     transclude: true,
     link: function(scope, elem, attrs, ctrl, transclude) {
-      var inputElem = elem.prev();
-      if (inputElem.length === 0) {
-        console.log('Failed to find input element for popover');
-        return;
-      }
+      // var inputElem = elem.prev();
+      // if (inputElem.length === 0) {
+      //   console.log('Failed to find input element for popover');
+      //   return;
+      // }
 
       var offset = attrs.offset || '0 -10px';
       var position = attrs.position || 'right middle';
       var classes = 'drop-help drop-hide-out-of-bounds';
+      var openOn = 'hover';
+
+      elem.addClass('gf-form-help-icon');
+
       if (attrs.wide) {
         classes += ' drop-wide';
       }
 
+      if (attrs.mode) {
+        elem.addClass('gf-form-help-icon--' + attrs.mode);
+      }
+
       transclude(function(clone, newScope) {
         var content = document.createElement("div");
         _.each(clone, (node) => {
@@ -30,11 +39,11 @@ export function infoPopover() {
         });
 
         var drop = new Drop({
-          target: inputElem[0],
+          target: elem[0],
           content: content,
           position: position,
           classes: classes,
-          openOn: 'click',
+          openOn: openOn,
           tetherOptions: {
             offset: offset
           }

+ 6 - 17
public/app/core/components/switch.ts

@@ -7,7 +7,12 @@ import coreModule from 'app/core/core_module';
 import Drop from 'tether-drop';
 
 var template = `
-<label for="check-{{ctrl.id}}" class="gf-form-label {{ctrl.labelClass}} pointer">{{ctrl.label}}</label>
+<label for="check-{{ctrl.id}}" class="gf-form-label {{ctrl.labelClass}} pointer">
+  {{ctrl.label}}
+  <info-popover mode="right-normal" ng-if="ctrl.tooltip">
+    {{ctrl.tooltip}}
+  </info-popover>
+</label>
 <div class="gf-form-switch {{ctrl.switchClass}}" ng-if="ctrl.show">
   <input id="check-{{ctrl.id}}" type="checkbox" ng-model="ctrl.checked" ng-change="ctrl.internalOnChange()">
   <label for="check-{{ctrl.id}}" data-on="Yes" data-off="No"></label>
@@ -49,22 +54,6 @@ export function switchDirective() {
       onChange: "&",
     },
     template: template,
-    link: (scope, elem) => {
-      if (scope.ctrl.tooltip) {
-        var drop = new Drop({
-          target: elem[0],
-          content: scope.ctrl.tooltip,
-          position: "right middle",
-          classes: 'drop-help',
-          openOn: 'hover',
-          hoverOpenDelay: 400,
-        });
-
-        scope.$on('$destroy', function() {
-          drop.destroy();
-        });
-      }
-    }
   };
 }
 

+ 2 - 0
public/app/core/time_series2.ts

@@ -42,6 +42,7 @@ export default class TimeSeries {
   fillBelowTo: any;
   transform: any;
   flotpairs: any;
+  unit: any;
 
   constructor(opts) {
     this.datapoints = opts.datapoints;
@@ -52,6 +53,7 @@ export default class TimeSeries {
     this.valueFormater = kbn.valueFormats.none;
     this.stats = {};
     this.legend = true;
+    this.unit = opts.unit;
   }
 
   applySeriesOverrides(overrides) {

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

@@ -36,7 +36,7 @@
 		</ul>
 	</li>
 	<li ng-show="::dashboardMeta.canSave">
-		<a ng-click="saveDashboard()" bs-tooltip="'Save dashboard'" data-placement="bottom"><i class="fa fa-save"></i></a>
+		<a ng-click="saveDashboard()" bs-tooltip="'Save dashboard <br> CTRL+S'" data-placement="bottom"><i class="fa fa-save"></i></a>
 	</li>
 	<li ng-if="::showSettingsMenu" class="dropdown">
 		<a class="pointer" ng-click="hideTooltip($event)" bs-tooltip="'Manage dashboard'" data-placement="bottom" data-toggle="dropdown"><i class="fa fa-cog"></i></a>

+ 7 - 4
public/app/features/dashboard/partials/settings.html

@@ -26,7 +26,10 @@
 				<input type="text" class="gf-form-input width-25" ng-model='dashboard.title'></input>
 			</div>
 			<div class="gf-form">
-				<label class="gf-form-label width-7">Tags<tip>Press enter to a add tag</tip></label>
+				<label class="gf-form-label width-7">
+          Tags
+          <info-popover mode="right-normal">Press enter to a add tag</info-popover>
+        </label>
 				<bootstrap-tagsinput ng-model="dashboard.tags" tagclass="label label-tag" placeholder="add tags">
 				</bootstrap-tagsinput>
 			</div>
@@ -46,19 +49,19 @@
                         label="Editable"
                         tooltip="Uncheck, then save and reload to disable all dashboard editing"
                         checked="dashboard.editable"
-                        label-class="width-10">
+                        label-class="width-11">
         </gf-form-switch>
         <gf-form-switch class="gf-form"
                         label="Hide Controls"
                         tooltip="Hide row controls. Shortcut: CTRL+H"
                         checked="dashboard.hideControls"
-                        label-class="width-10">
+                        label-class="width-11">
         </gf-form-switch>
         <gf-form-switch class="gf-form"
                         label="Shared Crosshair"
                         tooltip="Shared Crosshair line on all graphs. Shortcut: CTRL+O"
                         checked="dashboard.sharedCrosshair"
-                        label-class="width-10">
+                        label-class="width-11">
         </gf-form-switch>
       </div>
     </div>

+ 8 - 14
public/app/features/dashboard/timepicker/timepicker.html

@@ -1,19 +1,13 @@
 <ul class="nav gf-timepicker-nav">
 
-	<li class="dashnav-move-timeframe" style="padding-top: 2px">
-                <a class='small' ng-click='ctrl.move(-1)'>
-                        <i class="fa fa-arrow-left"></i>
-                </a>
-        </li>
-	<li class="dashnav-move-timeframe" style="padding-top: 2px">
-                <a class='small' ng-click='ctrl.move(1)'>
-                        <i class="fa fa-arrow-right"></i>
-                </a>
-        </li>
-	<li class="dashnav-zoom-out" style="padding-top: 2px">
-		<a class='small' ng-click='ctrl.zoom(2)'>
-			Zoom Out
-		</a>
+	<li class="dashnav-move-timeframe gf-timepicker-time-control" bs-tooltip="'Shift time backward <br> (left arrow key)'" data-placement="bottom">
+		<a ng-click='ctrl.move(-1)'><i class="fa fa-chevron-left"></i></a>
+	</li>
+	<li class="dashnav-zoom-out gf-timepicker-time-control" bs-tooltip="'Time range zoom out <br> CTRL+Z'" data-placement="bottom">
+		<a ng-click='ctrl.zoom(2)'>Zoom Out</a></li>
+	</li>
+	<li class="dashnav-move-timeframe gf-timepicker-time-control" bs-tooltip="'Shift time forward <br> (right arrow key)'" data-placement="bottom">
+		<a ng-click='ctrl.move(1)'><i class="fa fa-chevron-right"></i></a>
 	</li>
 
 	<li>

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

@@ -92,7 +92,7 @@ export class TimePickerCtrl {
   move(direction) {
     var range = this.timeSrv.timeRange();
 
-    var timespan = (range.to.valueOf() - range.from.valueOf());
+    var timespan = (range.to.valueOf() - range.from.valueOf()) / 2;
     var to, from;
     if (direction === -1) {
       to = range.to.valueOf() - timespan;

+ 0 - 1
public/app/features/dashboard/unsavedChangesSrv.js

@@ -102,7 +102,6 @@ function(angular, _) {
         value.current = null;
         value.options = null;
       });
-
     };
 
     p.hasChanges = function() {

+ 3 - 4
public/app/features/org/prefs_control.ts

@@ -49,7 +49,7 @@ export class PrefsControlCtrl {
 }
 
 var template = `
-<form name="ctrl.prefsForm" class="gf-form-group">
+<form name="ctrl.prefsForm" class="section gf-form-group">
   <h3 class="page-heading">Preferences</h3>
 
   <div class="gf-form">
@@ -61,9 +61,8 @@ var template = `
 
   <div class="gf-form">
     <span class="gf-form-label width-9">Home Dashboard</span>
-    <dashboard-selector
-        class="gf-form-select-wrapper max-width-20"
-        model="ctrl.prefs.homeDashboardId">
+    <dashboard-selector class="gf-form-select-wrapper max-width-20 gf-form-select-wrapper--has-help-icon"
+                        model="ctrl.prefs.homeDashboardId">
     </dashboard-selector>
   </div>
 

+ 1 - 1
public/app/features/panel/metrics_panel_ctrl.ts

@@ -65,7 +65,7 @@ class MetricsPanelCtrl extends PanelCtrl {
       var data = this.panel.snapshotData;
       // backward compatability
       if (!_.isArray(data)) {
-        data = data;
+        data = data.data;
       }
 
       this.events.emit('data-snapshot-load', data);

+ 10 - 3
public/app/features/plugins/ds_edit_ctrl.ts

@@ -16,6 +16,8 @@ var defaults = {
   jsonData: {}
 };
 
+var datasourceCreated = false;
+
 export class DataSourceEditCtrl {
   isNew: boolean;
   datasources: any[];
@@ -66,6 +68,11 @@ export class DataSourceEditCtrl {
       this.backendSrv.get('/api/datasources/' + id).then(ds => {
         this.isNew = false;
         this.current = ds;
+
+        if (datasourceCreated) {
+          datasourceCreated = false;
+          this.testDatasource();
+        }
         return this.typeChanged();
       });
     }
@@ -123,14 +130,14 @@ export class DataSourceEditCtrl {
       if (this.current.id) {
         return this.backendSrv.put('/api/datasources/' + this.current.id, this.current).then(() => {
           this.updateFrontendSettings().then(() => {
-            if (test) {
-              this.testDatasource();
-            }
+            this.testDatasource();
           });
         });
       } else {
         return this.backendSrv.post('/api/datasources', this.current).then(result => {
           this.updateFrontendSettings();
+
+          datasourceCreated = true;
           this.$location.path('datasources/edit/' + result.id);
         });
       }

+ 8 - 12
public/app/features/plugins/partials/ds_edit.html

@@ -25,24 +25,24 @@
 
   <div ng-if="ctrl.tabIndex === 0" class="tab-content">
 
-    <form name="ctrl.editForm">
+    <form name="ctrl.editForm" ng-if="ctrl.current">
       <div class="gf-form-group">
         <div class="gf-form-inline">
 					<div class="gf-form">
 						<span class="gf-form-label width-7">Name</span>
 						<input class="gf-form-input max-width-21" type="text" ng-model="ctrl.current.name" placeholder="My data source name" required>
+						<info-popover offset="0px -135px" mode="right-absolute">
+							The name is used when you select the data source in panels.
+							The <em>Default</em> data source is preselected in new
+							panels.
+						</info-popover>
 					</div>
-					<info-popover offset="0px -130px">
-						The name is used when you select the data source in panels.
-						The <code>Default</code> data source is preselected in new
-						panels.
-					</info-popover>
 					<gf-form-switch class="gf-form" label="Default" checked="ctrl.current.isDefault" switch-class="max-width-6"></gf-form-switch>
 				</div>
 
 				<div class="gf-form">
 					<span class="gf-form-label width-7">Type</span>
-					<div class="gf-form-select-wrapper max-width-21">
+					<div class="gf-form-select-wrapper max-width-23">
 						<select class="gf-form-input" ng-model="ctrl.current.type" ng-options="v.id as v.name for v in ctrl.types" ng-change="ctrl.typeChanged()"></select>
 					</div>
 				</div>
@@ -55,7 +55,6 @@
 
 			<div ng-if="ctrl.testing" style="margin-top: 25px">
 				<h5 ng-show="!ctrl.testing.done">Testing.... <i class="fa fa-spiner fa-spin"></i></h5>
-				<h5 ng-show="ctrl.testing.done">Test results</h5>
 				<div class="alert-{{ctrl.testing.status}} alert">
 					<div class="alert-title">{{ctrl.testing.title}}</div>
 					<div ng-bind='ctrl.testing.message'></div>
@@ -64,10 +63,7 @@
 
 			<div class="gf-form-button-row">
 				<button type="submit" class="btn btn-success" ng-show="ctrl.isNew" ng-click="ctrl.saveChanges()">Add</button>
-				<button type="submit" class="btn btn-success" ng-show="!ctrl.isNew" ng-click="ctrl.saveChanges()">Save</button>
-				<button type="submit" class="btn btn-secondary" ng-show="!ctrl.isNew" ng-click="ctrl.saveChanges(true)">
-					Test Connection
-				</button>
+				<button type="submit" class="btn btn-success" ng-show="!ctrl.isNew" ng-click="ctrl.saveChanges()">Save &amp; Test</button>
 				<button type="submit" class="btn btn-danger" ng-show="!ctrl.isNew" ng-click="ctrl.delete()">
 					Delete
 				</button>

+ 30 - 25
public/app/features/plugins/partials/ds_http_settings.html

@@ -3,29 +3,34 @@
 <div class="gf-form-group">
 	<h3 class="page-heading">Http settings</h3>
 
-	<div class="gf-form">
-		<span class="gf-form-label width-7">Url</span>
-		<input class="gf-form-input max-width-21" type="text" ng-model='current.url' placeholder="for example: http://localhost:8081" ng-pattern="/^(ftp|http|https):\/\/(\w+:{0,1}\w*@)?(\S+)(:[0-9]+)?(\/|\/([\w#!:.?+=&%@!\-\/]))?$/" required></input>
-
-		<info-popover>
-			<p>Specify a complete HTTP url (for example http://your_server:8080)</p>
-			<span ng-show="current.access === 'direct'">
-				Your access method is <em>Direct</em>, this means the url
-				needs to be accessable from the browser.
-			</span>
-			<span ng-show="current.access === 'proxy'">
-				Your access method is currently <em>Proxy</em>, this means the url
-				needs to be accessable from the grafana backend.
-			</span>
-		</info-popover>
+	<div class="gf-form-inline">
+		<div class="gf-form max-width-30">
+			<span class="gf-form-label width-7">Url</span>
+			<input class="gf-form-input" type="text" ng-model='current.url' placeholder="for example: http://localhost:8081" ng-pattern="/^(ftp|http|https):\/\/(\w+:{0,1}\w*@)?(\S+)(:[0-9]+)?(\/|\/([\w#!:.?+=&%@!\-\/]))?$/" required></input>
+			<info-popover mode="right-absolute">
+				<p>Specify a complete HTTP url (for example http://your_server:8080)</p>
+				<span ng-show="current.access === 'direct'">
+					Your access method is <em>Direct</em>, this means the url
+					needs to be accessable from the browser.
+				</span>
+				<span ng-show="current.access === 'proxy'">
+					Your access method is currently <em>Proxy</em>, this means the url
+					needs to be accessable from the grafana backend.
+				</span>
+			</info-popover>
+		</div>
 	</div>
 
-	<div class="gf-form">
-		<span class="gf-form-label width-7">
-			Access <tip>Direct = url is used directly from browser, Proxy = Grafana backend will proxy the request</tip>
-		</span>
-		<div class="gf-form-select-wrapper">
-			<select class="gf-form-input gf-size-auto" ng-model="current.access" ng-options="f for f in ['direct', 'proxy']"></select>
+	<div class="gf-form-inline">
+		<div class="gf-form max-width-30">
+			<span class="gf-form-label width-7">Access</span>
+			<div class="gf-form-select-wrapper gf-form-select-wrapper--has-help-icon max-width-24">
+				<select class="gf-form-input" ng-model="current.access" ng-options="f for f in ['direct', 'proxy']"></select>
+				<info-popover mode="right-absolute">
+					Direct = url is used directly from browser<br>
+					Proxy = Grafana backend will proxy the request
+				</info-popover>
+			</div>
 		</div>
 	</div>
 
@@ -34,12 +39,12 @@
 			<label class="gf-form-label width-7">Http Auth</label>
 		</div>
 		<gf-form-switch class="gf-form"
-			label="Basic Auth"
-			checked="current.basicAuth" switch-class="max-width-6">
+									label="Basic Auth"
+				 checked="current.basicAuth" switch-class="max-width-6">
 		</gf-form-switch>
 		<gf-form-switch class="gf-form"
-			label="With Credentials"
-			checked="current.withCredentials" switch-class="max-width-6">
+									label="With Credentials"
+				 checked="current.withCredentials" switch-class="max-width-6">
 		</gf-form-switch>
 	</div>
 

+ 1 - 1
public/app/features/plugins/partials/update_instructions.html

@@ -16,6 +16,6 @@
 			<pre><code>grafana-cli plugins update {{plugin.id}}</code></pre>
 			<span class="small">Check out {{plugin.name}} on <a href="http://grafana/net/plugins/{{plugin.id}}">Grafana.net</a> for README and changelog. If you do not have access to the command line, ask your Grafana administator.</span>
 		</div>
-		<p class="pluginlist-none-installed code--line"><img class="pluginlist-inline-logo" src="public/img/grafana_icon.svg"><strong>Pro tip</strong>: To update all plugins at once, type <code class="code--small">grafana-cli plugins update-all</code> on the command line.</div>
+		<p class="pluginlist-none-installed"><img class="pluginlist-inline-logo" src="public/img/grafana_icon.svg"><strong>Pro tip</strong>: To update all plugins at once, type <code class="code--small">grafana-cli plugins update-all</code> on the command line.</div>
 	</div>
 </div>

+ 51 - 50
public/app/features/templating/partials/editor.html

@@ -179,55 +179,56 @@
 
 			<div class="section gf-form-group" >
 				<h5 class="section-heading">Selection Options</h5>
-        <gf-form-switch class="gf-form"
-                        label="Multi-value"
-                        label-class="width-10"
-                        tooltip="Enables multiple values to be selected at the same time"
-                        checked="current.multi"
-                        on-change="runQuery()">
-        </gf-form-switch>
-        <gf-form-switch class="gf-form"
-                        label="Include All option"
-                        label-class="width-10"
-                        checked="current.includeAll"
-                        on-change="runQuery()">
-        </gf-form-switch>
-
-				<div class="gf-form" ng-if="current.includeAll">
-					<span class="gf-form-label width-10">Custom all value</span>
-					<input type="text" class="gf-form-input max-width-15" ng-model='current.allValue' placeholder="blank = auto"></input>
-				</div>
-			</div>
-
-			<div class="gf-form-group" ng-if="current.type === 'query'">
-				<h5>Value groups/tags (Experimental feature)</h5>
-				<div class="gf-form">
-					<editor-checkbox text="Enable" model="current.useTags" change="runQuery()"></editor-checkbox>
-				</div>
-				<div class="gf-form last" ng-if="current.useTags">
-					<span class="gf-form-label width-10">Tags query</span>
-					<input type="text" class="gf-form-input" ng-model='current.tagsQuery' placeholder="metric name or tags query" ng-model-onblur></input>
-				</div>
-				<div class="gf-form" ng-if="current.useTags">
-					<li class="gf-form-label width-10">Tag values query</li>
-					<input type="text" class="gf-form-input" ng-model='current.tagValuesQuery' placeholder="apps.$tag.*" ng-model-onblur></input>
-				</div>
-			</div>
-
-			<div class="gf-form-group">
-				<h5>Preview of values (shows max 20)</h5>
-				<div class="gf-form">
-					<span class="gf-form-label" ng-repeat="option in current.options | limitTo: 20">
-						{{option.text}}
-					</span>
-				</div>
-			</div>
-		</div>
-
-		<div class="gf-form-button-row p-y-0">
-			<button type="button" class="btn btn-success" ng-show="mode === 'edit'" ng-click="update();">Update</button>
-			<button type="button" class="btn btn-success" ng-show="mode === 'new'" ng-click="add();">Add</button>
-		</div>
-	</div>
+        <div class="section">
+          <gf-form-switch class="gf-form"
+                          label="Multi-value"
+                          label-class="width-10"
+                          tooltip="Enables multiple values to be selected at the same time"
+                          checked="current.multi"
+                          on-change="runQuery()">
+          </gf-form-switch>
+          <gf-form-switch class="gf-form"
+                          label="Include All option"
+                          label-class="width-10"
+                          checked="current.includeAll"
+                          on-change="runQuery()">
+          </gf-form-switch>
+        </div>
+        <div class="gf-form" ng-if="current.includeAll">
+          <span class="gf-form-label width-10">Custom all value</span>
+          <input type="text" class="gf-form-input max-width-15" ng-model='current.allValue' placeholder="blank = auto"></input>
+        </div>
+      </div>
+
+      <div class="gf-form-group" ng-if="current.type === 'query'">
+        <h5>Value groups/tags (Experimental feature)</h5>
+        <div class="gf-form">
+          <editor-checkbox text="Enable" model="current.useTags" change="runQuery()"></editor-checkbox>
+        </div>
+        <div class="gf-form last" ng-if="current.useTags">
+          <span class="gf-form-label width-10">Tags query</span>
+          <input type="text" class="gf-form-input" ng-model='current.tagsQuery' placeholder="metric name or tags query" ng-model-onblur></input>
+        </div>
+        <div class="gf-form" ng-if="current.useTags">
+          <li class="gf-form-label width-10">Tag values query</li>
+          <input type="text" class="gf-form-input" ng-model='current.tagValuesQuery' placeholder="apps.$tag.*" ng-model-onblur></input>
+        </div>
+      </div>
+
+      <div class="gf-form-group">
+        <h5>Preview of values (shows max 20)</h5>
+        <div class="gf-form-inline">
+          <div class="gf-form" ng-repeat="option in current.options | limitTo: 20">
+            <span class="gf-form-label">{{option.text}}</span>
+          </div>
+        </div>
+      </div>
+    </div>
+
+    <div class="gf-form-button-row p-y-0">
+      <button type="button" class="btn btn-success" ng-show="mode === 'edit'" ng-click="update();">Update</button>
+      <button type="button" class="btn btn-success" ng-show="mode === 'new'" ng-click="add();">Add</button>
+    </div>
+  </div>
 </div>
 

+ 1 - 0
public/app/features/templating/templateValuesSrv.js

@@ -281,6 +281,7 @@ function (angular, _, kbn) {
           if (!matches) { continue; }
           if (matches.length > 1) {
             value = matches[1];
+            text = value;
           }
         }
 

+ 14 - 14
public/app/partials/help_modal.html

@@ -29,21 +29,21 @@
 				<td>Refresh (Fetches new data and rerenders panels)</td>
 			</tr>
 			<tr>
-                                <td><span class="label label-info">&lt;</span></td>
-                                <td>Shift time backward</td>
-                        </tr>
+				<td><span class="label label-info">left arrow key</span></td>
+				<td>Shift time backward</td>
+			</tr>
 			<tr>
-                                <td><span class="label label-info">&gt;</span></td>
-                                <td>Shift time forward</td>
-                        </tr>
+				<td><span class="label label-info">right arrow key</span></td>
+				<td>Shift time forward</td>
+			</tr>
 			<tr>
 				<td><span class="label label-info">CTRL+S</span></td>
 				<td>Save dashboard</td>
 			</tr>
-      <tr>
-        <td><span class="label label-info">CTRL+E</span></td>
-        <td>Export dashboard</td>
-      </tr>
+			<tr>
+				<td><span class="label label-info">CTRL+E</span></td>
+				<td>Export dashboard</td>
+			</tr>
 			<tr>
 				<td><span class="label label-info">CTRL+H</span></td>
 				<td>Hide row controls</td>
@@ -52,10 +52,10 @@
 				<td><span class="label label-info">CTRL+Z</span></td>
 				<td>Zoom out</td>
 			</tr>
-      <tr>
-        <td><span class="label label-info">CTRL+I</span></td>
-        <td>Quick snapshot</td>
-      </tr>
+			<tr>
+				<td><span class="label label-info">CTRL+I</span></td>
+				<td>Quick snapshot</td>
+			</tr>
 			<tr>
 				<td><span class="label label-info">CTRL+O</span></td>
 				<td>Enable/Disable shared graph crosshair</td>

+ 17 - 12
public/app/plugins/datasource/cloudwatch/partials/config.html

@@ -1,22 +1,27 @@
 <h3 class="page-heading">CloudWatch details</h3>
 
-<div class="gf-form-group">
+<div class="gf-form-group max-width-30">
 	<div class="gf-form">
-		<label class="gf-form-label width-14">
-			Credentials profile name<tip>Credentials profile name, as specified in ~/.aws/credentials, leave blank for default</tip>
-		</label>
-		<input type="text" class="gf-form-input max-width-15" ng-model='ctrl.current.database' placeholder="default"></input>
+		<label class="gf-form-label width-13">Credentials profile name</label>
+		<input type="text" class="gf-form-input max-width-18" ng-model='ctrl.current.database' placeholder="default"></input>
+		<info-popover mode="right-absolute">
+			Credentials profile name, as specified in ~/.aws/credentials, leave blank for default
+		</info-popover>
 	</div>
 	<div class="gf-form">
-		<label class="gf-form-label width-14">
-			Default Region<tip>Specify the region, such as for US West (Oregon) use ` us-west-2 ` as the region.</tip>
-		</label>
-		<div class="gf-form-select-wrapper">
-			<select class="gf-form-input max-width-15" ng-model="ctrl.current.jsonData.defaultRegion" ng-options="region for region in ['ap-northeast-1', 'ap-northeast-2', 'ap-southeast-1', 'ap-southeast-2', 'cn-north-1', 'eu-central-1', 'eu-west-1', 'sa-east-1', 'us-east-1', 'us-west-1', 'us-west-2']"></select>
+		<label class="gf-form-label width-13">Default Region</label>
+		<div class="gf-form-select-wrapper max-width-18 gf-form-select-wrapper--has-help-icon">
+			<select class="gf-form-input" ng-model="ctrl.current.jsonData.defaultRegion" ng-options="region for region in ['ap-northeast-1', 'ap-northeast-2', 'ap-southeast-1', 'ap-southeast-2', 'cn-north-1', 'eu-central-1', 'eu-west-1', 'sa-east-1', 'us-east-1', 'us-west-1', 'us-west-2']"></select>
+			<info-popover mode="right-absolute">
+				Specify the region, such as for US West (Oregon) use ` us-west-2 ` as the region.
+			</info-popover>
 		</div>
 	</div>
 	<div class="gf-form">
-		<label class="gf-form-label width-14">Custom Metrics namespace<tip>Namespaces of Custom Metrics</tip></label>
-		<input type="text" class="gf-form-input max-width-15" ng-model='ctrl.current.jsonData.customMetricsNamespaces' placeholder="Namespace1,Namespace2"></input>
+		<label class="gf-form-label width-13">Custom Metrics namespace</label>
+		<input type="text" class="gf-form-input max-width-18" ng-model='ctrl.current.jsonData.customMetricsNamespaces' placeholder="Namespace1,Namespace2"></input>
+		<info-popover mode="right-absolute">
+			Namespaces of Custom Metrics
+		</info-popover>
 	</div>
 </div>

+ 1 - 1
public/app/plugins/datasource/prometheus/datasource.ts

@@ -157,7 +157,7 @@ export function PrometheusDatasource(instanceSettings, $q, backendSrv, templateS
 
     var interpolated;
     try {
-      interpolated = templateSrv.replace(expr);
+      interpolated = templateSrv.replace(expr, {}, interpolateQueryExpr);
     } catch (err) {
       return $q.reject(err);
     }

+ 0 - 1
public/app/plugins/panel/graph/legend.js

@@ -49,7 +49,6 @@ function (angular, _, $) {
               position: 'bottom center',
               template: '<gf-color-picker></gf-color-picker>',
               model: {
-                autoClose: true,
                 series: series,
                 toggleAxis: function() {
                   ctrl.toggleAxis(series);

+ 6 - 5
public/app/plugins/panel/graph/module.ts

@@ -161,7 +161,7 @@ class GraphCtrl extends MetricsPanelCtrl {
 
   onDataSnapshotLoad(snapshotData) {
     this.annotationsPromise = this.annotationsSrv.getAnnotations(this.dashboard);
-    this.onDataReceived(snapshotData.data);
+    this.onDataReceived(snapshotData);
   }
 
   onDataError(err) {
@@ -202,6 +202,7 @@ class GraphCtrl extends MetricsPanelCtrl {
       datapoints: datapoints,
       alias: alias,
       color: color,
+      unit: seriesData.unit,
     });
 
     if (datapoints && datapoints.length > 0) {
@@ -212,13 +213,9 @@ class GraphCtrl extends MetricsPanelCtrl {
       }
 
       this.datapointsCount += datapoints.length;
-
       this.panel.tooltip.msResolution = this.panel.tooltip.msResolution || series.isMsResolutionNeeded();
     }
 
-    if (seriesData.unit) {
-      this.panel.yaxes[series.yaxis-1].format = seriesData.unit;
-    }
 
     return series;
   }
@@ -228,6 +225,10 @@ class GraphCtrl extends MetricsPanelCtrl {
 
     for (let series of this.seriesList) {
       series.applySeriesOverrides(this.panel.seriesOverrides);
+
+      if (series.unit) {
+        this.panel.yaxes[series.yaxis-1].format = series.unit;
+      }
     }
   }
 

+ 1 - 0
public/app/plugins/panel/graph/series_overrides_ctrl.js

@@ -59,6 +59,7 @@ define([
         openOn: 'click',
         template: '<gf-color-picker></gf-color-picker>',
         model: {
+          autoClose: true,
           colorSelected: $scope.colorSelected,
         },
         onClose: function() {

+ 28 - 28
public/app/plugins/panel/pluginlist/module.html

@@ -1,30 +1,30 @@
 <div class="pluginlist">
-	<div class="pluginlist-section" ng-repeat="category in ctrl.viewModel">
-		<h6 class="pluginlist-section-header">
-			{{category.header}}
-		</h6>
-		<div class="pluginlist-item" ng-repeat="plugin in category.list">
-			<div class="pluginlist-link pluginlist-link-{{plugin.state}} pointer" ng-click="ctrl.gotoPlugin(plugin)">
-				<a href="plugins/{{plugin.id}}/edit">
-						<img ng-src="{{plugin.info.logos.small}}" class="pluginlist-image">
-						<span class="pluginlist-title">{{plugin.name}}</span>
-						<span class="pluginlist-version">v{{plugin.info.version}}</span>
-				</a>
-				<a class="pluginlist-message pluginlist-message--update" ng-show="plugin.hasUpdate" ng-click="ctrl.updateAvailable(plugin, $event)" bs-tooltip="plugin.latestVersion">
-					Update available!
-				</a>
-				<span class="pluginlist-message pluginlist-message--enable" ng-show="!plugin.enabled && !plugin.hasUpdate">
-					Enable now
-				</span>
-				<span class="pluginlist-message pluginlist-message--no-update" ng-show="plugin.enabled && !plugin.hasUpdate">
-					Up to date
-				</span>
-			</div>
-		</div>
-		<div class="pluginlist-item" ng-show="category.list.length === 0">
-			<a class="pluginlist-link pluginlist-link-{{plugin.state}}" href="http://grafana/net/plugins/">
-				<span class="pluginlist-none-installed">No additional panels installed. <span class="pluginlist-emphasis">Browse Grafana.net</span></span>
-			</a>
-		</div>
-	</div>
+  <div class="pluginlist-section" ng-repeat="category in ctrl.viewModel">
+    <h6 class="pluginlist-section-header">
+      {{category.header}}
+    </h6>
+    <div class="pluginlist-item" ng-repeat="plugin in category.list">
+      <a class="pluginlist-link pluginlist-link-{{plugin.state}} pointer" href="plugins/{{plugin.id}}/edit">
+        <span>
+          <img ng-src="{{plugin.info.logos.small}}" class="pluginlist-image">
+          <span class="pluginlist-title">{{plugin.name}}</span>
+          <span class="pluginlist-version">v{{plugin.info.version}}</span>
+        </span>
+        <span class="pluginlist-message pluginlist-message--update" ng-show="plugin.hasUpdate" ng-click="ctrl.updateAvailable(plugin, $event)" bs-tooltip="'New version: ' + plugin.latestVersion">
+          Update available!
+        </span>
+        <span class="pluginlist-message pluginlist-message--enable" ng-show="!plugin.enabled && !plugin.hasUpdate">
+          Enable now
+        </span>
+        <span class="pluginlist-message pluginlist-message--no-update" ng-show="plugin.enabled && !plugin.hasUpdate">
+          Up to date
+        </span>
+      </a>
+    </div>
+    <div class="pluginlist-item" ng-show="category.list.length === 0">
+      <a class="pluginlist-link pluginlist-link-{{plugin.state}}" href="http://grafana.net/plugins/">
+        <span class="pluginlist-none-installed">No additional panels installed. <span class="pluginlist-emphasis">Browse Grafana.net</span></span>
+      </a>
+    </div>
+  </div>
 </div>

+ 4 - 2
public/app/plugins/panel/pluginlist/module.ts

@@ -35,12 +35,14 @@ class PluginListCtrl extends PanelCtrl {
     this.addEditorTab('Options', 'public/app/plugins/panel/pluginlist/editor.html');
   }
 
-  gotoPlugin(plugin) {
-    this.$location.path(`plugins/${plugin.id}/edit`);
+  gotoPlugin(plugin, evt) {
+    if (evt) { evt.stopPropagation(); }
+    this.$location.url(`plugins/${plugin.id}/edit`);
   }
 
   updateAvailable(plugin, $event) {
     $event.stopPropagation();
+    $event.preventDefault();
 
     var modalScope = this.$scope.$new(true);
     modalScope.plugin = plugin;

+ 1 - 5
public/app/plugins/panel/singlestat/module.ts

@@ -56,7 +56,7 @@ class SingleStatCtrl extends MetricsPanelCtrl {
 
     this.events.on('data-received', this.onDataReceived.bind(this));
     this.events.on('data-error', this.onDataError.bind(this));
-    this.events.on('data-snapshot-load', this.onDataSnapshotLoad.bind(this));
+    this.events.on('data-snapshot-load', this.onDataReceived.bind(this));
     this.events.on('init-edit-mode', this.onInitEditMode.bind(this));
   }
 
@@ -71,10 +71,6 @@ class SingleStatCtrl extends MetricsPanelCtrl {
     this.render();
   }
 
-  onDataSnapshotLoad(snapshotData) {
-    this.onDataReceived(snapshotData.data);
-  }
-
   onDataError(err) {
     this.onDataReceived({data: []});
   }

+ 1 - 5
public/app/plugins/panel/table/module.ts

@@ -60,7 +60,7 @@ class TablePanelCtrl extends MetricsPanelCtrl {
 
     this.events.on('data-received', this.onDataReceived.bind(this));
     this.events.on('data-error', this.onDataError.bind(this));
-    this.events.on('data-snapshot-load', this.onDataSnapshotLoad.bind(this));
+    this.events.on('data-snapshot-load', this.onDataReceived.bind(this));
     this.events.on('init-edit-mode', this.onInitEditMode.bind(this));
     this.events.on('init-panel-actions', this.onInitPanelActions.bind(this));
   }
@@ -86,10 +86,6 @@ class TablePanelCtrl extends MetricsPanelCtrl {
     return super.issueQueries(datasource);
   }
 
-  onDataSnapshotLoad(data) {
-    this.onDataReceived(data.data);
-  }
-
   onDataError(err) {
     this.dataRaw = [];
     this.render();

+ 7 - 5
public/sass/_variables.dark.scss

@@ -27,7 +27,7 @@ $white:            #fff;
 // -------------------------
 $blue:                  #33B5E5;
 $blue-dark:             #005f81;
-$green:                 #669900;
+$green:                 #609000;
 $red:                   #CC3900;
 $yellow:                #ECBB13;
 $pink:                  #FF4444;
@@ -102,7 +102,9 @@ $tight-form-func-bg: 		    #333;
 $tight-form-func-highlight-bg:  #444;
 
 $modal-background: $black;
-$code-tag-bg: #444;
+$code-tag-bg:      $dark-5;
+$code-tag-border:  lighten($code-tag-bg, 2%);
+
 
 // Lists
 $grafanaListBackground:  	  $dark-3;
@@ -252,12 +254,12 @@ $popover-help-color:      $text-color;
 
 // Tooltips and popovers
 // -------------------------
-$tooltipColor:            $text-color;
-$tooltipBackground:       $dark-5;
+$tooltipColor:            $popover-help-color;
+$tooltipBackground:       $popover-help-bg;
 $tooltipArrowWidth:       5px;
 $tooltipArrowColor:       $tooltipBackground;
 $tooltipLinkColor:        $link-color;
-$graph-tooltip-bg:        $dark-5;
+$graph-tooltip-bg:        $dark-4;
 
 // images
 $checkboxImageUrl: '../img/checkbox.png';

+ 5 - 4
public/sass/_variables.light.scss

@@ -109,7 +109,8 @@ $tight-form-func-bg:            $gray-5;
 $tight-form-func-highlight-bg:  $gray-6;
 
 $modal-background: $body-bg;
-$code-tag-bg:      $dark-5;
+$code-tag-bg:      $gray-6;
+$code-tag-border:  darken($code-tag-bg, 3%);
 
 // Lists
 $grafanaListBackground:    	   $gray-6;
@@ -277,11 +278,11 @@ $popover-help-color:      $gray-6;
 
 // Tooltips and popovers
 // -------------------------
-$tooltipColor:            $text-color;
-$tooltipBackground:       $gray-5;
+$tooltipColor:            $popover-help-color;
+$tooltipBackground:       $popover-help-bg;
 $tooltipArrowWidth:       5px;
 $tooltipArrowColor:       $tooltipBackground;
-$tooltipLinkColor:        $link-color;
+$tooltipLinkColor:        lighten($popover-help-color, 5%);
 $graph-tooltip-bg:        $gray-5;
 
 // images

+ 3 - 5
public/sass/base/_code.scss

@@ -10,7 +10,7 @@ pre {
   font-size: $font-size-base - 2;
   background-color: $code-tag-bg;
   color: $text-color;
-  border: 1px solid darken($code-tag-bg, 15%);
+  border: 1px solid $code-tag-border;
   padding: 10px;
   border-radius: 4px;
 }
@@ -21,6 +21,8 @@ code {
   background-color: $code-tag-bg;
   border: 1px solid darken($code-tag-bg, 15%);
   white-space: nowrap;
+  padding: 2px 5px;
+  margin: 0 2px;
 }
 
 code.code--small {
@@ -29,10 +31,6 @@ code.code--small {
   margin: 0 2px;
 }
 
-p.code--line {
-  line-height: 1.8;
-}
-
 // Blocks of code
 pre {
   display: block;

+ 1 - 0
public/sass/components/_drop.scss

@@ -7,6 +7,7 @@ $attachmentOffset: 0%;
 $easing: cubic-bezier(0, 0, 0.265, 1.00);
 
 .drop-element {
+  z-index: 10000;
   position: absolute;
   display: none;
   opacity: 0;

+ 28 - 0
public/sass/components/_gf-form.scss

@@ -6,6 +6,7 @@ $gf-form-margin: 0.25rem;
   flex-direction: row;
   align-items: center;
   text-align: left;
+  position: relative;
 
   .cr1 {
     margin-left: 8px;
@@ -138,6 +139,12 @@ $gf-form-margin: 0.25rem;
     content: '\f0d7';
     pointer-events: none;
   }
+
+  &--has-help-icon {
+    &:after {
+      right: $input-padding-x*3;
+    }
+  }
 }
 
 .gf-form--v-stretch {
@@ -182,3 +189,24 @@ $gf-form-margin: 0.25rem;
     pointer-events: none;
   }
 }
+
+.gf-form-help-icon {
+  flex-grow: 0;
+  padding-left: $spacer;
+  color: $text-color-weak;
+
+  &--right-absolute {
+    position: absolute;
+    right: $spacer;
+    top: 8px;
+  }
+
+  &--right-normal {
+    float: right;
+  }
+}
+
+select.gf-form-input ~ .gf-form-help-icon {
+  right: 10px;
+}
+

+ 2 - 1
public/sass/components/_panel_graph.scss

@@ -236,6 +236,7 @@
   white-space: nowrap;
   font-size: $font-size-sm;
   background-color: $graph-tooltip-bg;
+  color: $text-color;
 
   .graph-tooltip-time {
     text-align: center;
@@ -248,7 +249,7 @@
     display: table-row;
 
     &--highlight {
-      color: $link-color;
+      color: $text-color-emphasis;
       font-weight: bold;
     }
   }

+ 1 - 0
public/sass/components/_panel_text.scss

@@ -3,4 +3,5 @@
   ul {
     margin: 0 0 $spacer $spacer * 1.5;
   }
+  li {line-height: 2;}
 }

+ 12 - 0
public/sass/components/_timepicker.scss

@@ -115,3 +115,15 @@
   @extend .fa;
   @extend .fa-chevron-left;
 }
+
+.gf-timepicker-time-control {
+  font-size: $font-size-sm;
+  a {
+    padding: 18px 7px 13px !important;
+  }
+}
+
+.dashnav-move-timeframe  {
+  position: relative;
+  top: 1px;
+}

+ 1 - 0
public/sass/components/_tooltip.scss

@@ -26,6 +26,7 @@
   text-align: center;
   text-decoration: none;
   background-color: $tooltipBackground;
+  border-radius: 2px;
 }
 
 // Arrows

+ 1 - 2
public/sass/pages/_login.scss

@@ -134,7 +134,7 @@
     border-bottom: 1px solid $gray-1;
 
     .login-divider-text {
-      background-color: $dark-3;
+      background-color: $panel-bg;
       color: $gray-2;
       padding: 0 10px;
     }
@@ -192,4 +192,3 @@
     }
   }
 }
-