Ver código fonte

feat(import): things are starting to work

Torkel Ödegaard 9 anos atrás
pai
commit
ca8df67947

+ 3 - 0
.floo

@@ -0,0 +1,3 @@
+{
+    "url": "https://floobits.com/raintank/grafana"
+}

+ 9 - 0
.flooignore

@@ -0,0 +1,9 @@
+#*
+*.o
+*.pyc
+*.pyo
+*~
+extern/
+node_modules/
+tmp
+vendor/

+ 1 - 1
.jscs.json

@@ -10,4 +10,4 @@
     "disallowSpacesInsideArrayBrackets": true,
     "disallowSpacesInsideParentheses": true,
     "validateIndentation": 2
-}
+}

+ 76 - 0
public/app/core/components/dash_importer/dash_importer.html

@@ -0,0 +1,76 @@
+<div class="modal-body">
+	<div class="modal-header">
+		<h2 class="modal-header-title">
+			<i class="fa fa-upload"></i>
+			<span class="p-l-1">Import Dashboard</span>
+		</h2>
+
+		<a class="modal-header-close" ng-click="dismiss();">
+			<i class="fa fa-remove"></i>
+		</a>
+	</div>
+
+	<div class="modal-content" ng-cloak>
+    <div ng-if="model.step === 0">
+			<form class="gf-form-group">
+        <dash-upload on-upload="model.onUpload(dash)"></dash-upload>
+			</form>
+
+			<h5 class="section-heading">Or paste JSON:</h5>
+
+			<div class="gf-form-group">
+				<div class="gf-form">
+					<textarea rows="7" data-share-panel-url="" class="gf-form-input" ng-model="model.jsonText"></textarea>
+				</div>
+				<button type="button" class="btn btn-secondary" ng-click="model.loadJsonText()">
+					<i class="fa fa-paste"></i>
+					Load
+				</button>
+        <span ng-if="model.parseError" class="text-error p-l-1">
+          <i class="fa fa-warning"></i>
+          {{model.parseError}}
+        </span>
+			</div>
+		</div>
+
+    <div ng-if="model.step === 2">
+      <div class="gf-form-group">
+        <h3 class="section-heading p-b-1" ng-if="model.nameExists">
+          <i class="fa fa-warning"></i> Dashboard with same title already exists
+        </h3>
+        <h3 class="section-heading p-b-1" ng-if="!model.nameExists">
+          <i class="fa fa-check"></i> Dashboard title available
+        </h3>
+        <div class="gf-form-inline">
+          <div class="gf-form gf-form--grow">
+            <label class="gf-form-label">New title</label>
+            <input type="text" class="gf-form-input" ng-model="model.dash.title" give-focus="true" ng-change="model.titleChanged()" ng-class="{'validation-error': model.nameExists}">
+            <button type="button" class="btn btn-success gf-form-btn width-10" ng-click="model.saveDashboard()">
+              <i class="fa fa-save"></i>
+              <span ng-show="model.nameExists">Overwrite &amp; Open</span>
+              <span ng-show="!model.nameExists">Save &amp; Open</span>
+            </button>
+          </div>
+        </div>
+      </div>
+    </div>
+
+  <!-- <table class="filter&#45;table"> -->
+  <!-- 	<tbody> -->
+  <!-- 		<tr ng&#45;repeat="step in model.steps"> -->
+  <!-- 			<td>{{step.name}}</td> -->
+  <!-- 			<td>{{step.status}}</td> -->
+  <!-- 			<td width="1%"> -->
+  <!-- 				<i class="fa fa&#45;check" style="color: #39A039"></i> -->
+  <!-- 			</td> -->
+  <!-- 		</tr> -->
+  <!-- 	</tbody> -->
+  <!-- </table> -->
+
+  <div class="gf-form-button-row text-right">
+    <a class="btn-text" ng-click="dismiss();">Cancel</a>
+  </div>
+</div>
+
+</div>
+

+ 77 - 0
public/app/core/components/dash_importer/dash_importer.ts

@@ -0,0 +1,77 @@
+///<reference path="../../../headers/common.d.ts" />
+
+import kbn from 'app/core/utils/kbn';
+import coreModule from 'app/core/core_module';
+
+import appEvents from 'app/core/app_events';
+import {WizardFlow} from 'app/core/core';
+
+var wnd: any = window;
+
+export class DashImporter {
+  step: number;
+  jsonText: string;
+  parseError: string;
+  nameExists: boolean;
+  dash: any;
+  dismiss: any;
+
+  constructor(private backendSrv, private $location) {
+  }
+
+  onUpload(dash) {
+    this.dash = dash;
+    this.dash.id = null;
+
+    this.backendSrv.saveDashboard(this.dash, {overwrite: false}).then(res => {
+
+    }).catch(err => {
+      if (err.data.status === 'name-exists') {
+        err.isHandled = true;
+        this.step = 2;
+        this.nameExists = true;
+      }
+      console.log(err);
+    });
+  }
+
+  titleChanged() {
+    this.backendSrv.search({query: this.dash.title}).then(res => {
+      this.nameExists = false;
+      for (let hit of res) {
+        if (this.dash.title === hit.title) {
+          this.nameExists = true;
+          break;
+        }
+      }
+    });
+  }
+
+  saveDashboard() {
+    return this.backendSrv.saveDashboard(this.dash, {overwrite: true}).then(res => {
+      this.$location.url('dashboard/db/' + res.slug);
+      this.dismiss();
+    });
+  }
+
+  loadJsonText() {
+    try {
+      this.parseError = '';
+      var dash = JSON.parse(this.jsonText);
+      this.onUpload(dash);
+    } catch (err) {
+      console.log(err);
+      this.parseError = err.message;
+      return;
+    }
+  }
+
+  run() {
+    this.step = 0;
+
+    appEvents.emit('show-modal', {
+      src: 'public/app/core/components/dash_importer/dash_importer.html',
+      model: this
+    });
+  }
+}

+ 5 - 8
public/app/core/components/search/search.html

@@ -67,14 +67,11 @@
 			Create New
 		</button>
 
-    <form class="pull-left p-r-1">
-			<input type="file" id="dashupload" dash-upload name="dashupload" class="hide"/>
-			<label class="btn btn-inverse" for="dashupload">
-        <i class="fa fa-upload"></i>
-        Upload Dashboard
-      </label>
-		</form>
+		<button class="btn btn-inverse pull-left" ng-click="ctrl.import()" ng-show="ctrl.contextSrv.isEditor">
+			<i class="fa fa-upload"></i>
+			Import
+		</button>
 
-		<div class="clearfix"></div>
+ 		<div class="clearfix"></div>
 	</div>
 </div>

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

@@ -5,6 +5,7 @@ import config from 'app/core/config';
 import _ from 'lodash';
 import $ from 'jquery';
 import coreModule from '../../core_module';
+import {DashImporter} from '../dash_importer/dash_importer';
 
 export class SearchCtrl {
   isOpen: boolean;
@@ -151,6 +152,10 @@ export class SearchCtrl {
   newDashboard() {
     this.$location.url('dashboard/new');
   };
+
+  import() {
+    new DashImporter(this.backendSrv, this.$location).run();
+  }
 }
 
 export function searchDirective() {

+ 13 - 11
public/app/core/components/wizard/wizard.html

@@ -11,19 +11,21 @@
 	</div>
 
 	<div class="modal-content">
+    <div ng-if="activeStep">
 
-		<table class="filter-table">
-			<tbody>
-				<tr ng-repeat="step in model.steps">
-					<td>{{step.name}}</td>
-					<td>{{step.status}}</td>
-					<td width="1%">
-						<i class="fa fa-check" style="color: #39A039"></i>
-					</td>
-				</tr>
-			</tbody>
-		</table>
+    </div>
 
+		<!-- <table class="filter&#45;table"> -->
+		<!-- 	<tbody> -->
+		<!-- 		<tr ng&#45;repeat="step in model.steps"> -->
+		<!-- 			<td>{{step.name}}</td> -->
+		<!-- 			<td>{{step.status}}</td> -->
+		<!-- 			<td width="1%"> -->
+		<!-- 				<i class="fa fa&#45;check" style="color: #39A039"></i> -->
+		<!-- 			</td> -->
+		<!-- 		</tr> -->
+		<!-- 	</tbody> -->
+		<!-- </table> -->
 	</div>
 
 </div>

+ 21 - 11
public/app/core/components/wizard/wizard.ts

@@ -8,40 +8,50 @@ import coreModule from 'app/core/core_module';
 import appEvents from 'app/core/app_events';
 
 export class WizardSrv {
-
   /** @ngInject */
   constructor() {
   }
+}
 
+export interface WizardStep {
+  name: string;
+  type: string;
+  process: any;
 }
 
-export class WizardStep {
+export class SelectOptionStep {
+  type: string;
   name: string;
-  fn: any;
+  fulfill: any;
+
+  constructor() {
+    this.type = 'select';
+  }
+
+  process() {
+    return new Promise((fulfill, reject) => {
+
+    });
+  }
 }
 
 export class WizardFlow {
   name: string;
   steps: WizardStep[];
-  reject: any;
-  fulfill: any;
 
   constructor(name) {
     this.name = name;
     this.steps = [];
   }
 
-  addStep(name, stepFn) {
-    this.steps.push({
-      name: name,
-      fn: stepFn
-    });
+  addStep(step) {
+    this.steps.push(step);
   }
 
   next(index) {
     var step = this.steps[0];
 
-    return step.fn().then(() => {
+    return step.process().then(() => {
       if (this.steps.length === index+1) {
         return;
       }

+ 1 - 0
public/app/core/services/util_srv.ts

@@ -34,6 +34,7 @@ export class UtilSrv {
 
     Promise.resolve(modal).then(function(modalEl) {
       modalEl.modal('show');
+      options.scope.model.dismiss = options.scope.dismiss;
     });
   }
 }

+ 15 - 33
public/app/features/dashboard/upload.ts

@@ -3,34 +3,22 @@
 import kbn from 'app/core/utils/kbn';
 import coreModule from 'app/core/core_module';
 
-import {WizardFlow} from 'app/core/core';
-
-var wnd: any = window;
-
-class DashboardImporter {
-
-  prepareForImport(dash) {
-    dash.id = null;
-
-    var wizard = new WizardFlow('Import Dashboard');
-
-    wizard.addStep("Importing dashboard", function() {
-      return new Promise(done => {
-        setTimeout(done, 2000);
-      });
-    });
-
-    return wizard.start().then(() => {
-      return dash;
-    });
-  }
-}
-
+var template = `
+<input type="file" id="dashupload" name="dashupload" class="hide"/>
+<label class="btn btn-secondary" for="dashupload">
+  <i class="fa fa-upload"></i>
+  Upload .json File
+</label>
+`;
 
 /** @ngInject */
 function uploadDashboardDirective(timer, alertSrv, $location) {
   return {
-    restrict: 'A',
+    restrict: 'E',
+    template: template,
+    scope: {
+      onUpload: '&',
+    },
     link: function(scope) {
       function file_selected(evt) {
         var files = evt.target.files; // FileList object
@@ -45,15 +33,7 @@ function uploadDashboardDirective(timer, alertSrv, $location) {
               return;
             }
 
-            var importer = new DashboardImporter();
-            importer.prepareForImport(dash).then(modified => {
-              wnd.grafanaImportDashboard = modified;
-              var title = kbn.slugifyForUrl(dash.title);
-
-              scope.$apply(function() {
-                $location.path('/dashboard-import/' + title);
-              });
-            });
+            scope.onUpload({dash: dash});
           };
         };
 
@@ -63,6 +43,8 @@ function uploadDashboardDirective(timer, alertSrv, $location) {
           reader.readAsText(f);
         }
       }
+
+      var wnd: any = window;
       // Check for the various File API support.
       if (wnd.File && wnd.FileReader && wnd.FileList && wnd.Blob) {
         // Something

+ 1 - 1
public/sass/_variables.dark.scss

@@ -235,7 +235,7 @@ $paginationActiveBackground:          $blue;
 $state-warning-text:      darken(#c09853, 10%);
 $state-warning-bg:        $brand-warning;
 
-$errorText:               #b94a48;
+$errorText:               #E84D4D;
 $errorBackground:         $btn-danger-bg;
 
 $successText:             #468847;

+ 2 - 0
public/sass/utils/_validation.scss

@@ -1,8 +1,10 @@
 input[type=text].ng-dirty.ng-invalid {
 }
 
+input.validation-error,
 input.ng-dirty.ng-invalid {
   box-shadow: inset 0 0px 5px $red;
 }
 
 
+