mirror of
https://github.com/grafana/grafana.git
synced 2025-01-23 23:13:52 -06:00
feat(import): import directly from grafana.net id/url now works
This commit is contained in:
parent
22a7eaf2e7
commit
c3708b3096
@ -5,8 +5,10 @@ import (
|
||||
"net"
|
||||
"net/http"
|
||||
"net/http/httputil"
|
||||
"net/url"
|
||||
"time"
|
||||
|
||||
"github.com/Unknwon/log"
|
||||
"github.com/grafana/grafana/pkg/middleware"
|
||||
"github.com/grafana/grafana/pkg/setting"
|
||||
"github.com/grafana/grafana/pkg/util"
|
||||
@ -23,12 +25,15 @@ var gNetProxyTransport = &http.Transport{
|
||||
}
|
||||
|
||||
func ReverseProxyGnetReq(proxyPath string) *httputil.ReverseProxy {
|
||||
director := func(req *http.Request) {
|
||||
req.URL.Scheme = "https"
|
||||
req.URL.Host = "grafana.net"
|
||||
req.Host = "grafana.net"
|
||||
url, _ := url.Parse(setting.GrafanaNetUrl)
|
||||
|
||||
req.URL.Path = util.JoinUrlFragments(setting.GrafanaNetUrl+"/api", proxyPath)
|
||||
director := func(req *http.Request) {
|
||||
req.URL.Scheme = url.Scheme
|
||||
req.URL.Host = url.Host
|
||||
req.Host = url.Host
|
||||
|
||||
req.URL.Path = util.JoinUrlFragments(url.Path+"/api", proxyPath)
|
||||
log.Info("Url: %v", req.URL.Path)
|
||||
|
||||
// clear cookie headers
|
||||
req.Header.Del("Cookie")
|
||||
|
@ -17,7 +17,7 @@ define([
|
||||
'./importCtrl',
|
||||
'./impression_store',
|
||||
'./upload',
|
||||
'./import/import',
|
||||
'./import/dash_import',
|
||||
'./export/export_modal',
|
||||
'./dash_list_ctrl',
|
||||
], function () {});
|
||||
|
@ -15,16 +15,6 @@
|
||||
You can share dashboards on <a class="external-link" href="https://grafana.net">Grafana.net</a>
|
||||
</p>
|
||||
|
||||
<div class="gf-form-group">
|
||||
<div class="gf-form">
|
||||
<label class="gf-form-label width-8">Title</label>
|
||||
<input type="text" class="gf-form-input" ng-model="ctrl.dash.title" ng-change="ctrl.titleChanged()">
|
||||
<label class="gf-form-label text-success" ng-show="ctrl.dash.title">
|
||||
<i class="fa fa-check"></i>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="gf-form-button-row">
|
||||
<button type="button" class="btn gf-form-btn width-10 btn-success" ng-click="ctrl.save()">
|
||||
<i class="fa fa-save"></i> Save to file
|
||||
|
@ -22,7 +22,7 @@
|
||||
|
||||
<div class="gf-form-group">
|
||||
<div class="gf-form">
|
||||
<input type="text" class="gf-form-input" ng-ctrl="ctrl.grafanaNetUrl" placeholder="Paste Grafana.net dashboard url or id" ng-change="ctrl.checkGnetDashboard()"></textarea>
|
||||
<input type="text" class="gf-form-input" ng-model="ctrl.gnetUrl" placeholder="Paste Grafana.net 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">
|
||||
@ -50,6 +50,21 @@
|
||||
</div>
|
||||
|
||||
<div ng-if="ctrl.step === 2">
|
||||
<h3 class="section-heading" ng-if="ctrl.dash.gnetId">
|
||||
Importing Dashboard from
|
||||
<a href="https://grafana.net/dashboards/{{ctrl.dash.gnetId}}" class="external-link" target="_blank">Grafana.net</a>
|
||||
</h3>
|
||||
<div class="gf-form-group">
|
||||
<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>
|
||||
@ -57,7 +72,7 @@
|
||||
<div class="gf-form-group">
|
||||
<div class="gf-form-inline">
|
||||
<div class="gf-form gf-form--grow">
|
||||
<label class="gf-form-label width-15">Title</label>
|
||||
<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}">
|
||||
<label class="gf-form-label text-success" ng-if="!ctrl.nameExists">
|
||||
<i class="fa fa-check"></i>
|
||||
@ -76,32 +91,33 @@
|
||||
|
||||
<div ng-repeat="input in ctrl.inputs">
|
||||
<div class="gf-form">
|
||||
<label class="gf-form-label width-15">{{input.label}}</label>
|
||||
<label class="gf-form-label width-15">
|
||||
{{input.label}}
|
||||
<info-popover mode="right-normal">
|
||||
{{input.info}}
|
||||
</info-popover>
|
||||
</label>
|
||||
<div class="gf-form-select-wrapper" style="width: 100%">
|
||||
<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()"></select>
|
||||
<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>
|
||||
<label class="gf-form-label text-success" ng-show="input.value">
|
||||
<i class="fa fa-check"></i>
|
||||
</label>
|
||||
</div>
|
||||
<div class="gf-form offset-width-15 gf-form--grow">
|
||||
<label class="gf-form-label gf-form-label--grow" ng-show="input.info">
|
||||
<i class="fa fa-info-circle"></i>
|
||||
{{input.info}}
|
||||
</label>
|
||||
<label class="gf-form-label gf-form-label--grow" ng-show="input.error">
|
||||
<i class="fa fa-info-circle"></i>
|
||||
{{input.info}}
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="gf-form-button-row">
|
||||
<button type="button" class="btn gf-form-btn width-10" ng-click="ctrl.saveDashboard()" ng-class="{'btn-danger': ctrl.nameExists, 'btn-success': !ctrl.nameExists}" ng-disabled="!ctrl.inputsValid">
|
||||
<button type="button" class="btn gf-form-btn btn-success width-10" ng-click="ctrl.saveDashboard()" ng-hide="ctrl.nameExists" ng-disabled="!ctrl.inputsValid">
|
||||
<i class="fa fa-save"></i> Save & Open
|
||||
</button>
|
||||
<button type="button" class="btn gf-form-btn btn-danger width-10" ng-click="ctrl.saveDashboard()" ng-show="ctrl.nameExists" ng-disabled="!ctrl.inputsValid">
|
||||
<i class="fa fa-save"></i> Overwrite & Open
|
||||
</button>
|
||||
<a class="btn btn-link" ng-click="dismiss()">Cancel</a>
|
||||
<a class="btn btn-link" ng-click="ctrl.back()">Back</a>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
@ -14,11 +14,20 @@ export class DashImportCtrl {
|
||||
dash: any;
|
||||
inputs: any[];
|
||||
inputsValid: boolean;
|
||||
gnetUrl: string;
|
||||
gnetError: string;
|
||||
gnetInfo: any;
|
||||
|
||||
/** @ngInject */
|
||||
constructor(private backendSrv, private $location, private $scope) {
|
||||
constructor(private backendSrv, private $location, private $scope, private $routeParams) {
|
||||
this.step = 1;
|
||||
this.nameExists = false;
|
||||
|
||||
// check gnetId in url
|
||||
if ($routeParams.gnetId) {
|
||||
this.gnetUrl = $routeParams.gnetId ;
|
||||
this.checkGnetDashboard();
|
||||
}
|
||||
}
|
||||
|
||||
onUpload(dash) {
|
||||
@ -121,6 +130,37 @@ export class DashImportCtrl {
|
||||
}
|
||||
}
|
||||
|
||||
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.net
|
||||
res.json.gnetId = dashboardId;
|
||||
this.onUpload(res.json);
|
||||
}).catch(err => {
|
||||
this.gnetError = err.message || err;
|
||||
});
|
||||
}
|
||||
|
||||
back() {
|
||||
this.gnetUrl = '';
|
||||
this.step = 1;
|
||||
this.gnetError = '';
|
||||
this.gnetInfo = '';
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export function dashImportDirective() {
|
||||
|
@ -22,7 +22,7 @@
|
||||
<div class="gf-form-group section">
|
||||
<h5 class="section-heading">Details</h5>
|
||||
<div class="gf-form">
|
||||
<label class="gf-form-label width-7">Title</label>
|
||||
<label class="gf-form-label width-7">Name</label>
|
||||
<input type="text" class="gf-form-input width-30" ng-model='dashboard.title'></input>
|
||||
</div>
|
||||
<div class="gf-form">
|
||||
|
@ -7,6 +7,7 @@ describe('DashImportCtrl', function() {
|
||||
var ctx: any = {};
|
||||
var backendSrv = {
|
||||
search: sinon.stub().returns(Promise.resolve([])),
|
||||
get: sinon.stub()
|
||||
};
|
||||
|
||||
beforeEach(angularMocks.module('grafana.core'));
|
||||
@ -20,7 +21,7 @@ describe('DashImportCtrl', function() {
|
||||
});
|
||||
}));
|
||||
|
||||
describe('when upload json', function() {
|
||||
describe('when uploading json', function() {
|
||||
beforeEach(function() {
|
||||
config.datasources = {
|
||||
ds: {
|
||||
@ -37,14 +38,47 @@ describe('DashImportCtrl', function() {
|
||||
|
||||
it('should build input model', function() {
|
||||
expect(ctx.ctrl.inputs.length).to.eql(1);
|
||||
expect(ctx.ctrl.inputs[0].label).to.eql(1);
|
||||
expect(ctx.ctrl.inputs[0].name).to.eql('ds');
|
||||
expect(ctx.ctrl.inputs[0].info).to.eql('Select a Test DB data source');
|
||||
});
|
||||
|
||||
it('should set inputValid to false', function() {
|
||||
expect(ctx.ctrl.inputsValid).to.eql(false);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe('when specifing grafana.net url', function() {
|
||||
beforeEach(function() {
|
||||
ctx.ctrl.gnetUrl = 'http://grafana.net/dashboards/123';
|
||||
// setup api mock
|
||||
backendSrv.get = sinon.spy(() => {
|
||||
return Promise.resolve({
|
||||
});
|
||||
});
|
||||
ctx.ctrl.checkGnetDashboard();
|
||||
});
|
||||
|
||||
it('should call gnet api with correct dashboard id', function() {
|
||||
expect(backendSrv.get.getCall(0).args[0]).to.eql('api/gnet/dashboards/123');
|
||||
});
|
||||
});
|
||||
|
||||
describe('when specifing dashbord id', function() {
|
||||
beforeEach(function() {
|
||||
ctx.ctrl.gnetUrl = '2342';
|
||||
// setup api mock
|
||||
backendSrv.get = sinon.spy(() => {
|
||||
return Promise.resolve({
|
||||
});
|
||||
});
|
||||
ctx.ctrl.checkGnetDashboard();
|
||||
});
|
||||
|
||||
it('should call gnet api with correct dashboard id', function() {
|
||||
expect(backendSrv.get.getCall(0).args[0]).to.eql('api/gnet/dashboards/2342');
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
|
||||
|
@ -158,6 +158,10 @@ $gf-form-margin: 0.25rem;
|
||||
color: transparent;
|
||||
text-shadow: 0 0 0 $text-color;
|
||||
}
|
||||
|
||||
&.ng-empty {
|
||||
color: $text-color-weak;
|
||||
}
|
||||
}
|
||||
|
||||
&:after {
|
||||
|
Loading…
Reference in New Issue
Block a user