diff --git a/pkg/api/index.go b/pkg/api/index.go index eb9e70bb404..d2069441b81 100644 --- a/pkg/api/index.go +++ b/pkg/api/index.go @@ -95,7 +95,6 @@ func setIndexViewData(c *middleware.Context) (*dtos.IndexViewData, error) { Children: []*dtos.NavLink{ {Text: "Dashboard", Icon: "gicon gicon-dashboard-new", Url: setting.AppSubUrl + "/dashboard/new"}, {Text: "Folder", Icon: "gicon gicon-folder-new", Url: setting.AppSubUrl + "/dashboard/new/?editview=new-folder"}, - {Text: "Import", Icon: "gicon gicon-dashboard-import", Url: setting.AppSubUrl + "/dashboard/new/?editview=import"}, }, }) } @@ -104,6 +103,7 @@ func setIndexViewData(c *middleware.Context) (*dtos.IndexViewData, error) { {Text: "Home", Url: setting.AppSubUrl + "/", Icon: "fa fa-fw fa-home", HideFromTabs: true}, {Divider: true, HideFromTabs: true}, {Text: "Manage", Id: "dashboards", Url: setting.AppSubUrl + "/dashboards", Icon: "fa fa-fw fa-sitemap"}, + {Text: "Import", Id: "import", Url: setting.AppSubUrl + "/dashboards/import", Icon: "gicon gicon-dashboard-import"}, {Text: "Playlists", Id: "playlists", Url: setting.AppSubUrl + "/playlists", Icon: "fa fa-fw fa-film"}, {Text: "Snapshots", Id: "snapshots", Url: setting.AppSubUrl + "/dashboard/snapshots", Icon: "icon-gf icon-gf-fw icon-gf-snapshot"}, } diff --git a/public/app/core/routes/routes.ts b/public/app/core/routes/routes.ts index 68595da4296..a965cd406d3 100644 --- a/public/app/core/routes/routes.ts +++ b/public/app/core/routes/routes.ts @@ -68,6 +68,11 @@ function setupAngularRoutes($routeProvider, $locationProvider) { controller : 'DashboardListCtrl', controllerAs: 'ctrl', }) + .when('/dashboards/import', { + templateUrl: 'public/app/features/dashboard/partials/dashboardImport.html', + controller : 'DashboardImportCtrl', + controllerAs: 'ctrl', + }) .when('/org', { templateUrl: 'public/app/features/org/partials/orgDetails.html', controller : 'OrgDetailsCtrl', diff --git a/public/app/features/dashboard/all.ts b/public/app/features/dashboard/all.ts index b4f1f4e77f0..f2f2087a24e 100644 --- a/public/app/features/dashboard/all.ts +++ b/public/app/features/dashboard/all.ts @@ -15,7 +15,6 @@ import './unsavedChangesSrv'; import './unsaved_changes_modal'; import './timepicker/timepicker'; import './upload'; -import './import/dash_import'; import './export/export_modal'; import './export_data/export_data_modal'; import './ad_hoc_filters'; @@ -30,5 +29,7 @@ import './move_to_folder_modal/move_to_folder'; import coreModule from 'app/core/core_module'; import {DashboardListCtrl} from './dashboard_list_ctrl'; +import {DashboardImportCtrl} from './dashboard_import_ctrl'; coreModule.controller('DashboardListCtrl', DashboardListCtrl); +coreModule.controller('DashboardImportCtrl', DashboardImportCtrl); diff --git a/public/app/features/dashboard/dashboard_import_ctrl.ts b/public/app/features/dashboard/dashboard_import_ctrl.ts new file mode 100644 index 00000000000..f2b3fb90fc9 --- /dev/null +++ b/public/app/features/dashboard/dashboard_import_ctrl.ts @@ -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 = ''; + } +} diff --git a/public/app/features/dashboard/partials/dashboardImport.html b/public/app/features/dashboard/partials/dashboardImport.html new file mode 100644 index 00000000000..be43078d32a --- /dev/null +++ b/public/app/features/dashboard/partials/dashboardImport.html @@ -0,0 +1,125 @@ + + +
+
+ +
+ +
+ +
Grafana.com Dashboard
+ +
+
+ +
+
+ +
+
+ +
Or paste JSON
+ +
+
+ +
+ + + + {{ctrl.parseError}} + +
+
+ +
+
+

+ Importing Dashboard from + Grafana.com +

+ +
+ + +
+
+ + +
+
+ +

+ Options +

+ +
+
+
+ + + +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ + +
+ +
+ + + +
+
+
+ +
+ + + Cancel +
+ +
+
diff --git a/public/app/features/dashboard/specs/dash_import_ctrl_specs.ts b/public/app/features/dashboard/specs/dashboard_import_ctrl.ts similarity index 93% rename from public/app/features/dashboard/specs/dash_import_ctrl_specs.ts rename to public/app/features/dashboard/specs/dashboard_import_ctrl.ts index c541aca34b2..e78109b01a0 100644 --- a/public/app/features/dashboard/specs/dash_import_ctrl_specs.ts +++ b/public/app/features/dashboard/specs/dashboard_import_ctrl.ts @@ -1,9 +1,9 @@ import {describe, beforeEach, it, sinon, expect, angularMocks} from 'test/lib/common'; -import {DashImportCtrl} from 'app/features/dashboard/import/dash_import'; +import {DashboardImportCtrl} from '../dashboard_import_ctrl'; import config from 'app/core/config'; -describe('DashImportCtrl', function() { +describe('DashboardImportCtrl', function() { var ctx: any = {}; var backendSrv = { search: sinon.stub().returns(Promise.resolve([])), @@ -15,7 +15,7 @@ describe('DashImportCtrl', function() { beforeEach(angularMocks.inject(($rootScope, $controller, $q) => { ctx.$q = $q; ctx.scope = $rootScope.$new(); - ctx.ctrl = $controller(DashImportCtrl, { + ctx.ctrl = $controller(DashboardImportCtrl, { $scope: ctx.scope, backendSrv: backendSrv, });