mirror of https://github.com/grafana/grafana
parent
15f46b8534
commit
44ea0ff71d
@ -0,0 +1,163 @@ |
||||
import _ from 'lodash'; |
||||
import config from 'app/core/config'; |
||||
|
||||
export class DashboardImportCtrl { |
||||
navModel: any; |
||||
step: number; |
||||
jsonText: string; |
||||
parseError: string; |
||||
nameExists: boolean; |
||||
dash: any; |
||||
inputs: any[]; |
||||
inputsValid: boolean; |
||||
gnetUrl: string; |
||||
gnetError: string; |
||||
gnetInfo: any; |
||||
|
||||
/** @ngInject */ |
||||
constructor(private backendSrv, navModelSrv, private $location, private $scope, $routeParams) { |
||||
this.navModel = navModelSrv.getNav('dashboards', 'import', 0); |
||||
|
||||
this.step = 1; |
||||
this.nameExists = false; |
||||
|
||||
// check gnetId in url
|
||||
if ($routeParams.gnetId) { |
||||
this.gnetUrl = $routeParams.gnetId ; |
||||
this.checkGnetDashboard(); |
||||
} |
||||
} |
||||
|
||||
onUpload(dash) { |
||||
this.dash = dash; |
||||
this.dash.id = null; |
||||
this.step = 2; |
||||
this.inputs = []; |
||||
|
||||
if (this.dash.__inputs) { |
||||
for (let input of this.dash.__inputs) { |
||||
var inputModel = { |
||||
name: input.name, |
||||
label: input.label, |
||||
info: input.description, |
||||
value: input.value, |
||||
type: input.type, |
||||
pluginId: input.pluginId, |
||||
options: [] |
||||
}; |
||||
|
||||
if (input.type === 'datasource') { |
||||
this.setDatasourceOptions(input, inputModel); |
||||
} else if (!inputModel.info) { |
||||
inputModel.info = 'Specify a string constant'; |
||||
} |
||||
|
||||
this.inputs.push(inputModel); |
||||
} |
||||
} |
||||
|
||||
this.inputsValid = this.inputs.length === 0; |
||||
this.titleChanged(); |
||||
} |
||||
|
||||
setDatasourceOptions(input, inputModel) { |
||||
var sources = _.filter(config.datasources, val => { |
||||
return val.type === input.pluginId; |
||||
}); |
||||
|
||||
if (sources.length === 0) { |
||||
inputModel.info = "No data sources of type " + input.pluginName + " found"; |
||||
} else if (!inputModel.info) { |
||||
inputModel.info = "Select a " + input.pluginName + " data source"; |
||||
} |
||||
|
||||
inputModel.options = sources.map(val => { |
||||
return {text: val.name, value: val.name}; |
||||
}); |
||||
} |
||||
|
||||
inputValueChanged() { |
||||
this.inputsValid = true; |
||||
for (let input of this.inputs) { |
||||
if (!input.value) { |
||||
this.inputsValid = false; |
||||
} |
||||
} |
||||
} |
||||
|
||||
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() { |
||||
var inputs = this.inputs.map(input => { |
||||
return { |
||||
name: input.name, |
||||
type: input.type, |
||||
pluginId: input.pluginId, |
||||
value: input.value |
||||
}; |
||||
}); |
||||
|
||||
return this.backendSrv.post('api/dashboards/import', { |
||||
dashboard: this.dash, |
||||
overwrite: true, |
||||
inputs: inputs |
||||
}).then(res => { |
||||
this.$location.url('dashboard/' + res.importedUri); |
||||
this.$scope.dismiss(); |
||||
}); |
||||
} |
||||
|
||||
loadJsonText() { |
||||
try { |
||||
this.parseError = ''; |
||||
var dash = JSON.parse(this.jsonText); |
||||
this.onUpload(dash); |
||||
} catch (err) { |
||||
console.log(err); |
||||
this.parseError = err.message; |
||||
return; |
||||
} |
||||
} |
||||
|
||||
checkGnetDashboard() { |
||||
this.gnetError = ''; |
||||
|
||||
var match = /(^\d+$)|dashboards\/(\d+)/.exec(this.gnetUrl); |
||||
var dashboardId; |
||||
|
||||
if (match && match[1]) { |
||||
dashboardId = match[1]; |
||||
} else if (match && match[2]) { |
||||
dashboardId = match[2]; |
||||
} else { |
||||
this.gnetError = 'Could not find dashboard'; |
||||
} |
||||
|
||||
return this.backendSrv.get('api/gnet/dashboards/' + dashboardId).then(res => { |
||||
this.gnetInfo = res; |
||||
// store reference to grafana.com
|
||||
res.json.gnetId = res.id; |
||||
this.onUpload(res.json); |
||||
}).catch(err => { |
||||
err.isHandled = true; |
||||
this.gnetError = err.data.message || err; |
||||
}); |
||||
} |
||||
|
||||
back() { |
||||
this.gnetUrl = ''; |
||||
this.step = 1; |
||||
this.gnetError = ''; |
||||
this.gnetInfo = ''; |
||||
} |
||||
} |
@ -0,0 +1,125 @@ |
||||
<page-header model="ctrl.navModel"></page-header> |
||||
|
||||
<div class="page-container page-body" ng-cloak> |
||||
<div ng-if="ctrl.step === 1"> |
||||
|
||||
<form class="gf-form-group"> |
||||
<dash-upload on-upload="ctrl.onUpload(dash)"></dash-upload> |
||||
</form> |
||||
|
||||
<h5 class="section-heading">Grafana.com Dashboard</h5> |
||||
|
||||
<div class="gf-form-group"> |
||||
<div class="gf-form gf-form--grow"> |
||||
<input type="text" class="gf-form-input max-width-30" ng-model="ctrl.gnetUrl" placeholder="Paste Grafana.com dashboard url or id" ng-blur="ctrl.checkGnetDashboard()"></textarea> |
||||
</div> |
||||
<div class="gf-form" ng-if="ctrl.gnetError"> |
||||
<label class="gf-form-label text-warning"> |
||||
<i class="fa fa-warning"></i> |
||||
{{ctrl.gnetError}} |
||||
</label> |
||||
</div> |
||||
</div> |
||||
|
||||
<h5 class="section-heading">Or paste JSON</h5> |
||||
|
||||
<div class="gf-form-group"> |
||||
<div class="gf-form"> |
||||
<textarea rows="10" data-share-panel-url="" class="gf-form-input" ng-model="ctrl.jsonText"></textarea> |
||||
</div> |
||||
<button type="button" class="btn btn-secondary" ng-click="ctrl.loadJsonText()"> |
||||
<i class="fa fa-paste"></i> |
||||
Load |
||||
</button> |
||||
<span ng-if="ctrl.parseError" class="text-error p-l-1"> |
||||
<i class="fa fa-warning"></i> |
||||
{{ctrl.parseError}} |
||||
</span> |
||||
</div> |
||||
</div> |
||||
|
||||
<div ng-if="ctrl.step === 2"> |
||||
<div class="gf-form-group" ng-if="ctrl.dash.gnetId"> |
||||
<h3 class="section-heading"> |
||||
Importing Dashboard from |
||||
<a href="https://grafana.com/dashboards/{{ctrl.dash.gnetId}}" class="external-link" target="_blank">Grafana.com</a> |
||||
</h3> |
||||
|
||||
<div class="gf-form"> |
||||
<label class="gf-form-label width-15">Published by</label> |
||||
<label class="gf-form-label width-15">{{ctrl.gnetInfo.orgName}}</label> |
||||
</div> |
||||
<div class="gf-form"> |
||||
<label class="gf-form-label width-15">Updated on</label> |
||||
<label class="gf-form-label width-15">{{ctrl.gnetInfo.updatedAt | date : 'yyyy-MM-dd HH:mm:ss'}}</label> |
||||
</div> |
||||
</div> |
||||
|
||||
<h3 class="section-heading"> |
||||
Options |
||||
</h3> |
||||
|
||||
<div class="gf-form-group"> |
||||
<div class="gf-form-inline"> |
||||
<div class="gf-form gf-form--grow"> |
||||
<label class="gf-form-label width-15">Name</label> |
||||
<input type="text" class="gf-form-input" ng-model="ctrl.dash.title" give-focus="true" ng-change="ctrl.titleChanged()" ng-class="{'validation-error': ctrl.nameExists || !ctrl.dash.title}"> |
||||
<label class="gf-form-label text-success" ng-if="!ctrl.nameExists && ctrl.dash.title"> |
||||
<i class="fa fa-check"></i> |
||||
</label> |
||||
</div> |
||||
</div> |
||||
|
||||
<div class="gf-form-inline" ng-if="ctrl.nameExists"> |
||||
<div class="gf-form offset-width-15 gf-form--grow"> |
||||
<label class="gf-form-label text-warning gf-form-label--grow"> |
||||
<i class="fa fa-warning"></i> |
||||
A Dashboard with the same name already exists |
||||
</label> |
||||
</div> |
||||
</div> |
||||
|
||||
<div class="gf-form-inline" ng-if="!ctrl.dash.title"> |
||||
<div class="gf-form offset-width-15 gf-form--grow"> |
||||
<label class="gf-form-label text-warning gf-form-label--grow"> |
||||
<i class="fa fa-warning"></i> |
||||
A Dashboard should have a name |
||||
</label> |
||||
</div> |
||||
</div> |
||||
|
||||
<div ng-repeat="input in ctrl.inputs"> |
||||
<div class="gf-form"> |
||||
<label class="gf-form-label width-15"> |
||||
{{input.label}} |
||||
<info-popover mode="right-normal"> |
||||
{{input.info}} |
||||
</info-popover> |
||||
</label> |
||||
<!-- Data source input --> |
||||
<div class="gf-form-select-wrapper" style="width: 100%" ng-if="input.type === 'datasource'"> |
||||
<select class="gf-form-input" ng-model="input.value" ng-options="v.value as v.text for v in input.options" ng-change="ctrl.inputValueChanged()"> |
||||
<option value="" ng-hide="input.value">{{input.info}}</option> |
||||
</select> |
||||
</div> |
||||
<!-- Constant input --> |
||||
<input ng-if="input.type === 'constant'" type="text" class="gf-form-input" ng-model="input.value" placeholder="{{input.default}}" ng-change="ctrl.inputValueChanged()"> |
||||
<label class="gf-form-label text-success" ng-show="input.value"> |
||||
<i class="fa fa-check"></i> |
||||
</label> |
||||
</div> |
||||
</div> |
||||
</div> |
||||
|
||||
<div class="gf-form-button-row"> |
||||
<button type="button" class="btn gf-form-btn btn-success width-12" ng-click="ctrl.saveDashboard()" ng-hide="ctrl.nameExists" ng-disabled="!ctrl.inputsValid"> |
||||
<i class="fa fa-save"></i> Import |
||||
</button> |
||||
<button type="button" class="btn gf-form-btn btn-danger width-12" ng-click="ctrl.saveDashboard()" ng-show="ctrl.nameExists" ng-disabled="!ctrl.inputsValid"> |
||||
<i class="fa fa-save"></i> Import (Overwrite) |
||||
</button> |
||||
<a class="btn btn-link" ng-click="ctrl.back()">Cancel</a> |
||||
</div> |
||||
|
||||
</div> |
||||
</div> |
Loading…
Reference in new issue