diff --git a/public/app/core/utils/file_export.ts b/public/app/core/utils/file_export.ts index ad203f58495..944b6ae8a80 100644 --- a/public/app/core/utils/file_export.ts +++ b/public/app/core/utils/file_export.ts @@ -14,6 +14,41 @@ export function exportSeriesListToCsv(seriesList) { saveSaveBlob(text, 'grafana_data_export.csv'); }; +export function exportSeriesListToCsvColumns(seriesList) { + var text = 'Time;'; + // add header + _.each(seriesList, function(series) { + text += series.alias + ';'; + }); + text = text.substring(0,text.length-1); + text += '\n'; + + // process data + var dataArr = [[]]; + var sIndex = 1; + _.each(seriesList, function(series) { + var cIndex = 0; + dataArr.push([]); + _.each(series.datapoints, function(dp) { + dataArr[0][cIndex] = new Date(dp[1]).toISOString(); + dataArr[sIndex][cIndex] = dp[0]; + cIndex++; + }); + sIndex++; + }); + + // make text + for (var i = 0; i < dataArr[0].length; i++) { + text += dataArr[0][i] + ';'; + for (var j = 1; j < dataArr.length; j++) { + text += dataArr[j][i] + ';'; + } + text = text.substring(0,text.length-1); + text += '\n'; + } + saveSaveBlob(text, 'grafana_data_export.csv'); +}; + export function exportTableDataToCsv(table) { var text = ''; // add header diff --git a/public/app/features/dashboard/all.js b/public/app/features/dashboard/all.js index 073ca2ae1d9..d5cc13b4270 100644 --- a/public/app/features/dashboard/all.js +++ b/public/app/features/dashboard/all.js @@ -16,4 +16,5 @@ define([ './graphiteImportCtrl', './dynamicDashboardSrv', './importCtrl', + './impressionStore', ], function () {}); diff --git a/public/app/features/dashboard/dashboardLoaderSrv.js b/public/app/features/dashboard/dashboardLoaderSrv.js index f578a9d1075..f975c47800f 100644 --- a/public/app/features/dashboard/dashboardLoaderSrv.js +++ b/public/app/features/dashboard/dashboardLoaderSrv.js @@ -5,8 +5,9 @@ define([ 'jquery', 'app/core/utils/kbn', 'app/core/utils/datemath', + './impressionStore', ], -function (angular, moment, _, $, kbn, dateMath) { +function (angular, moment, _, $, kbn, dateMath, impressionStore) { 'use strict'; var module = angular.module('grafana.services'); @@ -24,19 +25,27 @@ function (angular, moment, _, $, kbn, dateMath) { }; this.loadDashboard = function(type, slug) { - if (type === 'script') { - return this._loadScriptedDashboard(slug); - } + var promise; - if (type === 'snapshot') { - return backendSrv.get('/api/snapshots/' + $routeParams.slug).catch(function() { + if (type === 'script') { + promise = this._loadScriptedDashboard(slug); + } else if (type === 'snapshot') { + promise = backendSrv.get('/api/snapshots/' + $routeParams.slug).catch(function() { return {meta:{isSnapshot: true, canSave: false, canEdit: false}, dashboard: {title: 'Snapshot not found'}}; }); + } else { + promise = backendSrv.getDashboard($routeParams.type, $routeParams.slug) + .catch(function() { + return self._dashboardLoadFailed("Not found"); + }); } - return backendSrv.getDashboard($routeParams.type, $routeParams.slug).catch(function() { - return self._dashboardLoadFailed("Not found"); + promise.then(function(result) { + impressionStore.impressions.addDashboardImpression(slug); + return result; }); + + return promise; }; this._loadScriptedDashboard = function(file) { diff --git a/public/app/features/dashboard/impressionStore.ts b/public/app/features/dashboard/impressionStore.ts new file mode 100644 index 00000000000..61be1131cb6 --- /dev/null +++ b/public/app/features/dashboard/impressionStore.ts @@ -0,0 +1,41 @@ +/// + +import store from 'app/core/store'; +import _ from 'lodash'; + +export class ImpressionsStore { + constructor() {} + + addDashboardImpression(slug) { + var impressions = []; + if (store.exists("dashboard_impressions")) { + impressions = JSON.parse(store.get("dashboard_impressions")); + if (!_.isArray(impressions)) { + impressions = []; + } + } + + var exists = impressions.indexOf(slug); + if (exists >= 0) { + impressions.splice(exists, 1); + } + + impressions.unshift(slug); + + if (impressions.length > 20) { + impressions.shift(); + } + store.set("dashboard_impressions", JSON.stringify(impressions)); + } + + getDashboardOpened() { + var k = store.get("dashboard_impressions"); + return JSON.parse(k); + } +} + +var impressions = new ImpressionsStore(); + +export { + impressions +}; diff --git a/public/app/plugins/panel/dashlist/module.html b/public/app/plugins/panel/dashlist/module.html index 455291409d5..79952d0032c 100644 --- a/public/app/plugins/panel/dashlist/module.html +++ b/public/app/plugins/panel/dashlist/module.html @@ -5,7 +5,7 @@ {{dash.title}} - + diff --git a/public/app/plugins/panel/dashlist/module.ts b/public/app/plugins/panel/dashlist/module.ts index a1c72434b38..fd0e905d923 100644 --- a/public/app/plugins/panel/dashlist/module.ts +++ b/public/app/plugins/panel/dashlist/module.ts @@ -3,6 +3,7 @@ import _ from 'lodash'; import config from 'app/core/config'; import {PanelCtrl} from 'app/plugins/sdk'; +import {impressions} from 'app/features/dashboard/impressionStore'; // Set and populate defaults var panelDefaults = { @@ -31,7 +32,7 @@ class DashListCtrl extends PanelCtrl { initEditMode() { super.initEditMode(); - this.modes = ['starred', 'search']; + this.modes = ['starred', 'search', 'last viewed']; this.icon = "fa fa-star"; this.addEditorTab('Options', () => { return {templateUrl: 'public/app/plugins/panel/dashlist/editor.html'}; @@ -41,6 +42,19 @@ class DashListCtrl extends PanelCtrl { refresh() { var params: any = {limit: this.panel.limit}; + if (this.panel.mode === 'last viewed') { + var dashListNames = _.first(impressions.getDashboardOpened(), this.panel.limit).map((dashboard) => { + return { + title: dashboard, + uri: 'db/' + dashboard + }; + }); + + this.dashList = dashListNames; + this.renderingCompleted(); + return; + } + if (this.panel.mode === 'starred') { params.starred = "true"; } else { diff --git a/public/app/plugins/panel/graph/module.ts b/public/app/plugins/panel/graph/module.ts index 1c022d460bb..357da9b6877 100644 --- a/public/app/plugins/panel/graph/module.ts +++ b/public/app/plugins/panel/graph/module.ts @@ -125,7 +125,8 @@ class GraphCtrl extends MetricsPanelCtrl { getExtendedMenu() { var menu = super.getExtendedMenu(); - menu.push({text: 'Export CSV', click: 'ctrl.exportCsv()'}); + menu.push({text: 'Export CSV (series as rows)', click: 'ctrl.exportCsv()'}); + menu.push({text: 'Export CSV (series as columns)', click: 'ctrl.exportCsvColumns()'}); menu.push({text: 'Toggle legend', click: 'ctrl.toggleLegend()'}); return menu; } @@ -295,6 +296,10 @@ class GraphCtrl extends MetricsPanelCtrl { exportCsv() { fileExport.exportSeriesListToCsv(this.seriesList); } + + exportCsvColumns() { + fileExport.exportSeriesListToCsvColumns(this.seriesList); + } } export {GraphCtrl, GraphCtrl as PanelCtrl} diff --git a/public/dashboards/home.json b/public/dashboards/home.json index e05a882ef57..d54e276db5c 100644 --- a/public/dashboards/home.json +++ b/public/dashboards/home.json @@ -47,11 +47,11 @@ { "id": 3, "limit": 10, - "mode": "search", + "mode": "last viewed", "query": "", "span": 6, "tags": [], - "title": "Dashboards", + "title": "Last 10 viewed dashboards", "type": "dashlist" } ],