diff --git a/public/app/features/dashboard/dashboard_ctrl.ts b/public/app/features/dashboard/dashboard_ctrl.ts index f7acac4e1b7..7bb50f58bf1 100644 --- a/public/app/features/dashboard/dashboard_ctrl.ts +++ b/public/app/features/dashboard/dashboard_ctrl.ts @@ -136,10 +136,6 @@ export class DashboardCtrl { $scope.timezoneChanged = function() { $rootScope.$broadcast("refresh"); }; - - $scope.formatDate = function(date) { - return moment(date).format('MMM Do YYYY, h:mm:ss a'); - }; } init(dashboard) { diff --git a/public/app/features/dashboard/dashnav/dashnav.ts b/public/app/features/dashboard/dashnav/dashnav.ts index 2d5b66cb13c..afad15afe87 100644 --- a/public/app/features/dashboard/dashnav/dashnav.ts +++ b/public/app/features/dashboard/dashnav/dashnav.ts @@ -4,6 +4,8 @@ import _ from 'lodash'; import moment from 'moment'; import angular from 'angular'; +import {DashboardExporter} from '../exporter'; + export class DashNavCtrl { /** @ngInject */ @@ -170,9 +172,8 @@ export class DashNavCtrl { $scope.exportDashboard = function() { var clone = $scope.dashboard.getSaveModelClone(); - var blob = new Blob([angular.toJson(clone, true)], { type: "application/json;charset=utf-8" }); - var wnd: any = window; - wnd.saveAs(blob, $scope.dashboard.title + '-' + new Date().getTime()); + var exporter = new DashboardExporter(); + exporter.export(clone); }; $scope.snapshot = function() { diff --git a/public/app/features/dashboard/dynamic_dashboard_srv.ts b/public/app/features/dashboard/dynamic_dashboard_srv.ts index 340bca69b40..a5fb73d099a 100644 --- a/public/app/features/dashboard/dynamic_dashboard_srv.ts +++ b/public/app/features/dashboard/dynamic_dashboard_srv.ts @@ -8,30 +8,36 @@ export class DynamicDashboardSrv { iteration: number; dashboard: any; + constructor() { + this.iteration = new Date().getTime(); + } + init(dashboard) { if (dashboard.snapshot) { return; } - - this.iteration = new Date().getTime(); - this.process(dashboard); + this.process(dashboard, {}); } update(dashboard) { if (dashboard.snapshot) { return; } this.iteration = this.iteration + 1; - this.process(dashboard); + this.process(dashboard, {}); } - process(dashboard) { + process(dashboard, options) { if (dashboard.templating.list.length === 0) { return; } this.dashboard = dashboard; + var cleanUpOnly = options.cleanUpOnly; + var i, j, row, panel; for (i = 0; i < this.dashboard.rows.length; i++) { row = this.dashboard.rows[i]; // handle row repeats if (row.repeat) { - this.repeatRow(row, i); + if (!cleanUpOnly) { + this.repeatRow(row, i); + } } else if (row.repeatRowId && row.repeatIteration !== this.iteration) { // clean up old left overs this.dashboard.rows.splice(i, 1); @@ -43,7 +49,9 @@ export class DynamicDashboardSrv { for (j = 0; j < row.panels.length; j++) { panel = row.panels[j]; if (panel.repeat) { - this.repeatPanel(panel, row); + if (!cleanUpOnly) { + this.repeatPanel(panel, row); + } } else if (panel.repeatPanelId && panel.repeatIteration !== this.iteration) { // clean up old left overs row.panels = _.without(row.panels, panel); diff --git a/public/app/features/dashboard/exporter.ts b/public/app/features/dashboard/exporter.ts new file mode 100644 index 00000000000..0a9ac2ff2ca --- /dev/null +++ b/public/app/features/dashboard/exporter.ts @@ -0,0 +1,28 @@ +/// + +import config from 'app/core/config'; +import angular from 'angular'; +import _ from 'lodash'; + +import {DynamicDashboardSrv} from './dynamic_dashboard_srv'; + +export class DashboardExporter { + + makeExportable(dashboard) { + var dynSrv = new DynamicDashboardSrv(); + dynSrv.process(dashboard, {cleanUpOnly: true}); + + return dashboard; + } + + export(dashboard) { + var clean = this.makeExportable(dashboard); + var blob = new Blob([angular.toJson(clean, true)], { type: "application/json;charset=utf-8" }); + var wnd: any = window; + wnd.saveAs(blob, clean.title + '-' + new Date().getTime()); + } + +} + + + diff --git a/public/app/features/dashboard/partials/settings.html b/public/app/features/dashboard/partials/settings.html index 2a2287613ae..d641e21cfdb 100644 --- a/public/app/features/dashboard/partials/settings.html +++ b/public/app/features/dashboard/partials/settings.html @@ -104,7 +104,7 @@
Last updated at: - {{formatDate(dashboardMeta.updated)}} + {{dashboard.formatDate(dashboardMeta.updated)}}
Last updated by: @@ -112,7 +112,7 @@
Created at: - {{formatDate(dashboardMeta.created)}}  + {{dashboard.formatDate(dashboardMeta.created)}} 
Created by: diff --git a/public/test/specs/dynamic_dashboard_srv_specs.ts b/public/app/features/dashboard/specs/dynamic_dashboard_srv_specs.ts similarity index 98% rename from public/test/specs/dynamic_dashboard_srv_specs.ts rename to public/app/features/dashboard/specs/dynamic_dashboard_srv_specs.ts index 6f233fcb9ff..ee2fac16ba1 100644 --- a/public/test/specs/dynamic_dashboard_srv_specs.ts +++ b/public/app/features/dashboard/specs/dynamic_dashboard_srv_specs.ts @@ -1,7 +1,7 @@ import {describe, beforeEach, it, sinon, expect, angularMocks} from 'test/lib/common'; import 'app/features/dashboard/dashboardSrv'; -import {DynamicDashboardSrv} from '../../app/features/dashboard/dynamic_dashboard_srv'; +import {DynamicDashboardSrv} from '../dynamic_dashboard_srv'; function dynamicDashScenario(desc, func) { diff --git a/public/app/features/dashboard/specs/exporter_specs.ts b/public/app/features/dashboard/specs/exporter_specs.ts new file mode 100644 index 00000000000..7831905fda8 --- /dev/null +++ b/public/app/features/dashboard/specs/exporter_specs.ts @@ -0,0 +1,45 @@ +import {describe, beforeEach, it, sinon, expect, angularMocks} from 'test/lib/common'; + +import {DashboardExporter} from '../exporter'; + +describe('given dashboard with repeated panels', function() { + var dash, exported; + + beforeEach(() => { + dash = { + rows: [], + templating: { list: [] } + }; + dash.templating.list.push({ + name: 'apps', + current: {}, + options: [] + }); + + dash.rows.push({ + repeat: 'test', + panels: [ + {id: 2, repeat: 'apps'}, + {id: 2, repeat: null, repeatPanelId: 2}, + ] + }); + dash.rows.push({ + repeat: null, + repeatRowId: 1 + }); + + var exporter = new DashboardExporter(); + exported = exporter.makeExportable(dash); + }); + + + it('exported dashboard should not contain repeated panels', function() { + expect(exported.rows[0].panels.length).to.be(1); + }); + + it('exported dashboard should not contain repeated rows', function() { + expect(exported.rows.length).to.be(1); + }); + +}); +