From ca8df67947f7ed4cb37c61a433c8c424d1ee8426 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Torkel=20=C3=96degaard?= Date: Fri, 13 May 2016 11:26:02 +0200 Subject: [PATCH] feat(import): things are starting to work --- .floo | 3 + .flooignore | 9 +++ .jscs.json | 2 +- .../dash_importer/dash_importer.html | 76 ++++++++++++++++++ .../components/dash_importer/dash_importer.ts | 77 +++++++++++++++++++ public/app/core/components/search/search.html | 13 ++-- public/app/core/components/search/search.ts | 5 ++ public/app/core/components/wizard/wizard.html | 24 +++--- public/app/core/components/wizard/wizard.ts | 34 +++++--- public/app/core/services/util_srv.ts | 1 + public/app/features/dashboard/upload.ts | 48 ++++-------- public/sass/_variables.dark.scss | 2 +- public/sass/utils/_validation.scss | 2 + 13 files changed, 230 insertions(+), 66 deletions(-) create mode 100644 .floo create mode 100644 .flooignore create mode 100644 public/app/core/components/dash_importer/dash_importer.html create mode 100644 public/app/core/components/dash_importer/dash_importer.ts diff --git a/.floo b/.floo new file mode 100644 index 00000000000..1201c5e93b9 --- /dev/null +++ b/.floo @@ -0,0 +1,3 @@ +{ + "url": "https://floobits.com/raintank/grafana" +} \ No newline at end of file diff --git a/.flooignore b/.flooignore new file mode 100644 index 00000000000..b300a62c4da --- /dev/null +++ b/.flooignore @@ -0,0 +1,9 @@ +#* +*.o +*.pyc +*.pyo +*~ +extern/ +node_modules/ +tmp +vendor/ \ No newline at end of file diff --git a/.jscs.json b/.jscs.json index dcf694dcc63..8fdad332de5 100644 --- a/.jscs.json +++ b/.jscs.json @@ -10,4 +10,4 @@ "disallowSpacesInsideArrayBrackets": true, "disallowSpacesInsideParentheses": true, "validateIndentation": 2 -} \ No newline at end of file +} diff --git a/public/app/core/components/dash_importer/dash_importer.html b/public/app/core/components/dash_importer/dash_importer.html new file mode 100644 index 00000000000..8b4e649dd50 --- /dev/null +++ b/public/app/core/components/dash_importer/dash_importer.html @@ -0,0 +1,76 @@ + + diff --git a/public/app/core/components/dash_importer/dash_importer.ts b/public/app/core/components/dash_importer/dash_importer.ts new file mode 100644 index 00000000000..2f04640ffc2 --- /dev/null +++ b/public/app/core/components/dash_importer/dash_importer.ts @@ -0,0 +1,77 @@ +/// + +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 + }); + } +} diff --git a/public/app/core/components/search/search.html b/public/app/core/components/search/search.html index 953a769f7ee..ddfe22215a9 100644 --- a/public/app/core/components/search/search.html +++ b/public/app/core/components/search/search.html @@ -67,14 +67,11 @@ Create New -
- - -
+ -
+
diff --git a/public/app/core/components/search/search.ts b/public/app/core/components/search/search.ts index e296acf56e1..30ad9792c31 100644 --- a/public/app/core/components/search/search.ts +++ b/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() { diff --git a/public/app/core/components/wizard/wizard.html b/public/app/core/components/wizard/wizard.html index 4a532e81a0f..9d3f680649a 100644 --- a/public/app/core/components/wizard/wizard.html +++ b/public/app/core/components/wizard/wizard.html @@ -11,19 +11,21 @@ diff --git a/public/app/core/components/wizard/wizard.ts b/public/app/core/components/wizard/wizard.ts index 943998f2e10..2ae38cf9e03 100644 --- a/public/app/core/components/wizard/wizard.ts +++ b/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 class WizardStep { +export interface WizardStep { name: string; - fn: any; + type: string; + process: any; +} + +export class SelectOptionStep { + type: string; + name: string; + 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; } diff --git a/public/app/core/services/util_srv.ts b/public/app/core/services/util_srv.ts index 0f15a65a0dc..595962cd3c6 100644 --- a/public/app/core/services/util_srv.ts +++ b/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; }); } } diff --git a/public/app/features/dashboard/upload.ts b/public/app/features/dashboard/upload.ts index 35095fb6cb9..ddc4005546c 100644 --- a/public/app/features/dashboard/upload.ts +++ b/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 = ` + + +`; /** @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 diff --git a/public/sass/_variables.dark.scss b/public/sass/_variables.dark.scss index fed3d805b82..29e3cce1ee5 100644 --- a/public/sass/_variables.dark.scss +++ b/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; diff --git a/public/sass/utils/_validation.scss b/public/sass/utils/_validation.scss index 1145212707e..c0dd44d59a0 100644 --- a/public/sass/utils/_validation.scss +++ b/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; } +