Преглед на файлове

New global option in config.js to specify admin password (useful to hinder some users from accidentally making changes), Closes #606

Torkel Ödegaard преди 11 години
родител
ревизия
a1772d26b5

+ 7 - 6
CHANGELOG.md

@@ -1,23 +1,24 @@
 # 1.7.0 (unreleased)
 
 **New features or improvements**
-- [Issue #511](https://github.com/grafana/grafana/issues/511). Allow [[..]] filter notation in all text panels (markdown/html/text)
-- [Issue #136](https://github.com/grafana/grafana/issues/136). New legend display option "Align as table"
-- [Issue #556](https://github.com/grafana/grafana/issues/556). New legend display option "Right side", will show legend to the right of the graph
+- [Issue #511](https://github.com/grafana/grafana/issues/511). Text panel: Allow [[..]] filter notation in all text panels (markdown/html/text)
+- [Issue #136](https://github.com/grafana/grafana/issues/136). Chart: New legend display option "Align as table"
+- [Issue #556](https://github.com/grafana/grafana/issues/556). Chart: New legend display option "Right side", will show legend to the right of the graph
+- [Issue #604](https://github.com/grafana/grafana/issues/604). Chart: New axis format, 'bps' (SI unit in steps of 1000) useful for network gear metics
 - [Issue #525](https://github.com/grafana/grafana/issues/525). InfluxDB: Enhanced series aliasing (legend names) with pattern replacements
 - [Issue #581](https://github.com/grafana/grafana/issues/581). InfluxDB: Add continuous query in series results (series typeahead).
 - [Issue #584](https://github.com/grafana/grafana/issues/584). InfluxDB: Support for alias & alias patterns when using raw query mode
 - [Issue #394](https://github.com/grafana/grafana/issues/394). InfluxDB: Annotation support
 - [Issue #610](https://github.com/grafana/grafana/issues/610). InfluxDB: Support for InfluxdB v0.8 list series response schemea (series typeahead)
-- [Issue #604](https://github.com/grafana/grafana/issues/604). Chart: New axis format, 'bps' (SI unit in steps of 1000) useful for network gear metics
 - [Issue #266](https://github.com/grafana/grafana/issues/266). Graphite: New option cacheTimeout to override graphite default memcache timeout
+- [Issue #606](https://github.com/grafana/grafana/issues/606). General: New global option in config.js to specify admin password (useful to hinder users from accidentally make changes)
 
 **Changes**
 - [Issue #536](https://github.com/grafana/grafana/issues/536). Graphite: Use unix epoch for Graphite from/to for absolute time ranges
 
 **Fixes**
-- [Issue #545](https://github.com/grafana/grafana/issues/545). Fix formatting negative values
-- [Issue #460](https://github.com/grafana/grafana/issues/460). fix for max legend value when max value is zero
+- [Issue #545](https://github.com/grafana/grafana/issues/545). Chart: Fix formatting negative values (axis formats, legend values)
+- [Issue #460](https://github.com/grafana/grafana/issues/460). Chart: fix for max legend value when max value is zero
 
 # 1.6.1 (2014-06-24)
 

+ 2 - 1
src/app/components/settings.js

@@ -26,7 +26,8 @@ function (_, crypto) {
       grafana_index                 : 'grafana-dash',
       elasticsearch_all_disabled    : false,
       playlist_timespan             : "1m",
-      unsaved_changes_warning       : true
+      unsaved_changes_warning       : true,
+      admin: {}
     };
 
     // This initializes a new hash on purpose, to avoid adding parameters to

+ 0 - 2
src/app/controllers/dashLoader.js

@@ -12,8 +12,6 @@ function (angular, _, moment) {
   module.controller('dashLoader', function($scope, $rootScope, $http, alertSrv, $location, playlistSrv, elastic) {
 
     $scope.init = function() {
-      $scope.gist_pattern = /(^\d{5,}$)|(^[a-z0-9]{10,}$)|(gist.github.com(\/*.*)\/[a-z0-9]{5,}\/*$)/;
-      $scope.gist = $scope.gist || {};
       $scope.elasticsearch = $scope.elasticsearch || {};
 
       $scope.onAppEvent('save-dashboard', function() {

+ 1 - 10
src/app/partials/dashLoader.html

@@ -49,15 +49,6 @@
     </li>
     <li ng-show="showDropdown('share')"><a bs-tooltip="'Share'" data-placement="bottom" ng-click="saveForSharing()" config-modal="app/partials/dashLoaderShare.html">Share temp copy</i></a></li>
 
-    <li ng-show="dashboard.loader.save_gist" style="margin:10px">
-      <h6>Gist</h6>
-      <form class="input-append">
-        <input class='input-medium' placeholder='Title' type="text" ng-model="gist.title"/>
-        <button class="btn" ng-click="save_gist()"><i class="icon-github-alt"></i></button>
-      </form><br>
-      <small ng-show="gist.last">Last gist: <a target="_blank" href="{{gist.last}}">{{gist.last}}</a></small>
-    </li>
-
   </ul>
 </li>
 
@@ -73,4 +64,4 @@
   <a class='small' ng-click='stopPlaylist(2)'>
     Stop playlist
   </a>
-</li>
+</li>

+ 2 - 8
src/app/partials/dasheditor.html

@@ -72,19 +72,13 @@
     <div class="editor-row">
       <div class="section">
         <h5>Save to</h5>
-        <div class="editor-option">
-          <label class="small">Gist <tip>Requires your domain to be OAUTH registered with Github<tip></label><input type="checkbox" ng-model="dashboard.loader.save_gist" ng-checked="dashboard.loader.save_gist">
-        </div>
         <div class="editor-option">
           <label class="small">Elasticsearch</label><input type="checkbox" ng-model="dashboard.loader.save_elasticsearch" ng-checked="dashboard.loader.save_elasticsearch">
         </div>
       </div>
       <div class="section">
         <h5>Load from</h5>
-        <div class="editor-option">
-          <label class="small">Gist</label><input type="checkbox" ng-model="dashboard.loader.load_gist" ng-checked="dashboard.loader.load_gist">
-        </div>
-        <div class="editor-option">
+				<div class="editor-option">
           <label class="small">Elasticsearch</label><input type="checkbox" ng-model="dashboard.loader.load_elasticsearch" ng-checked="dashboard.loader.load_elasticsearch">
         </div>
       </div>
@@ -143,4 +137,4 @@
 
   <button ng-click="add_row(dashboard,row); reset_row();" class="btn btn-success" ng-show="editor.index == 1">Create Row</button>
   <button type="button" class="btn btn-info" ng-click="editor.index=0;dismiss();reset_panel();dashboard.emit_refresh()">Close</button>
-</div>
+</div>

+ 1 - 2
src/app/partials/search.html

@@ -77,7 +77,7 @@
           <tr bindonce
               ng-repeat="row in results.dashboards"
               ng-class="{'selected': $index === selectedIndex }">
-            <td><a confirm-click="deleteDashboard(row._id)" confirmation="Are you sure you want to delete the {{row._id}} dashboard"><i class="icon-remove"></i></a></td>
+            <td><a ng-click="deleteDashboard(row._id)"><i class="icon-remove"></i></a></td>
             <td style="width:100%">
               <a href="#/dashboard/elasticsearch/{{row._id}}" bo-text="row._id"></a>
             </td>
@@ -92,7 +92,6 @@
       </div>
     </li>
 
-    <!-- ng-show="dashboard.loader.load_gist || dashboard.loader.load_local" -->
     <li ng-if="showImport" style="margin: 20px;">
       <div class="editor-row">
         <div class="section">

+ 21 - 1
src/app/services/elasticsearch/es-client.js

@@ -7,7 +7,7 @@ function(angular, config) {
 
   var module = angular.module('grafana.services');
 
-  module.service('elastic', function($http) {
+  module.service('elastic', function($http, $q) {
 
     this._request = function(method, url, data) {
       var options = {
@@ -40,6 +40,8 @@ function(angular, config) {
     };
 
     this.deleteDashboard = function(id) {
+      if (!this.isAdmin()) { return $q.reject("Invalid admin password"); }
+
       return this._request('DELETE', '/dashboard/' + id)
         .then(function(result) {
           return result.data._id;
@@ -72,7 +74,25 @@ function(angular, config) {
         });
     };
 
+    this.passwordCache = function(pwd) {
+      if (!window.sessionStorage) { return null; }
+      if (!pwd) { return window.sessionStorage["grafanaAdminPassword"]; }
+      window.sessionStorage["grafanaAdminPassword"] = pwd;
+    };
+
+    this.isAdmin = function() {
+      if (!config.admin || !config.admin.password) { return true; }
+      if (this.passwordCache() === config.admin.password) { return true; }
+
+      var password = window.prompt("Admin password", "");
+      this.passwordCache(password);
+
+      return password === config.admin.password;
+    };
+
     this.saveDashboard = function(dashboard, title) {
+      if (!this.isAdmin()) { return $q.reject("Invalid admin password"); }
+
       var dashboardClone = angular.copy(dashboard);
       title = dashboardClone.title = title ? title : dashboard.title;
 

+ 6 - 0
src/config.sample.js

@@ -42,6 +42,12 @@ function (Settings) {
     // Example: "1m", "1h"
     playlist_timespan: "1m",
 
+    // If you want to specify password before saving, please specify it bellow
+    // The purpose of this password is not security, but to stop some users from accidentally changing dashboards
+    admin: {
+      password: ''
+    },
+
     // Add your own custom pannels
     plugins: {
       panels: []