mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
feat(import): things are starting to work
This commit is contained in:
parent
0d3e06e68a
commit
ca8df67947
9
.flooignore
Normal file
9
.flooignore
Normal file
@ -0,0 +1,9 @@
|
||||
#*
|
||||
*.o
|
||||
*.pyc
|
||||
*.pyo
|
||||
*~
|
||||
extern/
|
||||
node_modules/
|
||||
tmp
|
||||
vendor/
|
@ -10,4 +10,4 @@
|
||||
"disallowSpacesInsideArrayBrackets": true,
|
||||
"disallowSpacesInsideParentheses": true,
|
||||
"validateIndentation": 2
|
||||
}
|
||||
}
|
||||
|
76
public/app/core/components/dash_importer/dash_importer.html
Normal file
76
public/app/core/components/dash_importer/dash_importer.html
Normal file
@ -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 & Open</span>
|
||||
<span ng-show="!model.nameExists">Save & Open</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- <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 class="gf-form-button-row text-right">
|
||||
<a class="btn-text" ng-click="dismiss();">Cancel</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
77
public/app/core/components/dash_importer/dash_importer.ts
Normal file
77
public/app/core/components/dash_importer/dash_importer.ts
Normal file
@ -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
|
||||
});
|
||||
}
|
||||
}
|
@ -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,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() {
|
||||
|
@ -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-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>
|
||||
|
||||
</div>
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -34,6 +34,7 @@ export class UtilSrv {
|
||||
|
||||
Promise.resolve(modal).then(function(modalEl) {
|
||||
modalEl.modal('show');
|
||||
options.scope.model.dismiss = options.scope.dismiss;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user