define([ 'angular', 'jquery', 'kbn', 'underscore', 'config', 'moment', 'modernizr', 'filesaver' ], function (angular, $, kbn, _, config, moment, Modernizr) { 'use strict'; var module = angular.module('kibana.services'); module.service('dashboard', function( $routeParams, $http, $rootScope, $injector, $location, $timeout, ejsResource, timer, alertSrv, $q ) { // A hash of defaults to use when loading a dashboard var _dash = { title: "", tags: [], style: "dark", timezone: 'browser', editable: true, failover: false, panel_hints: true, rows: [], pulldowns: [ { type: 'templating' }, { type: 'annotations' } ], nav: [ { type: 'timepicker' } ], services: {}, loader: { save_gist: false, save_elasticsearch: true, save_local: true, save_default: true, save_temp: true, save_temp_ttl_enable: true, save_temp_ttl: '30d', load_gist: false, load_elasticsearch: true, load_elasticsearch_size: 20, load_local: false, hide: false }, refresh: false }; // An elasticJS client to use var ejs = ejsResource(config.elasticsearch, config.elasticsearchBasicAuth); var gist_pattern = /(^\d{5,}$)|(^[a-z0-9]{10,}$)|(gist.github.com(\/*.*)\/[a-z0-9]{5,}\/*$)/; // Store a reference to this var self = this; this.current = _.clone(_dash); this.last = {}; this.availablePanels = []; $rootScope.$on('$routeChangeSuccess',function(){ // Clear the current dashboard to prevent reloading self.current = {}; self.original = null; self.indices = []; route(); }); var route = function() { // Is there a dashboard type and id in the URL? if(!(_.isUndefined($routeParams.kbnType)) && !(_.isUndefined($routeParams.kbnId))) { var _type = $routeParams.kbnType; var _id = $routeParams.kbnId; switch(_type) { case ('elasticsearch'): self.elasticsearch_load('dashboard',_id); break; case ('temp'): self.elasticsearch_load('temp',_id); break; case ('file'): self.file_load(_id); break; case('script'): self.script_load(_id); break; case('local'): self.local_load(); break; default: $location.path(config.default_route); } // No dashboard in the URL } else { // Check if browser supports localstorage, and if there's an old dashboard. If there is, // inform the user that they should save their dashboard to Elasticsearch and then set that // as their default if (Modernizr.localstorage) { if(!(_.isUndefined(window.localStorage['dashboard'])) && window.localStorage['dashboard'] !== '') { $location.path(config.default_route); alertSrv.set('Saving to browser storage has been replaced',' with saving to Elasticsearch.'+ ' Click here to load your old dashboard anyway.'); } else if(!(_.isUndefined(window.localStorage.grafanaDashboardDefault))) { $location.path(window.localStorage.grafanaDashboardDefault); } else { $location.path(config.default_route); } // No? Ok, grab the default route, its all we have now } else { $location.path(config.default_route); } } }; this.refresh = function() { $rootScope.$broadcast('refresh'); }; var dash_defaults = function(dashboard) { _.defaults(dashboard, _dash); _.defaults(dashboard.loader,_dash.loader); var filtering = _.findWhere(dashboard.pulldowns, {type: 'filtering'}); if (!filtering) { dashboard.pulldowns.push({ type: 'filtering', enable: false }); } var annotations = _.findWhere(dashboard.pulldowns, {type: 'annotations'}); if (!annotations) { dashboard.pulldowns.push({ type: 'annotations', enable: false }); } return dashboard; }; this.dash_load = function(dashboard) { // Cancel all timers timer.cancel_all(); // reset fullscreen flag $rootScope.fullscreen = false; // Make sure the dashboard being loaded has everything required dashboard = dash_defaults(dashboard); window.document.title = 'Grafana - ' + dashboard.title; // Set the current dashboard self.current = angular.copy(dashboard); if(dashboard.refresh) { self.set_interval(dashboard.refresh); } // Set the available panels for the "Add Panel" drop down self.availablePanels = _.difference(config.panel_names, _.pluck(_.union(self.current.nav,self.current.pulldowns),'type')); // Take out any that we're not allowed to add from the gui. self.availablePanels = _.difference(self.availablePanels,config.hidden_panels); $rootScope.$emit('dashboard-loaded'); $timeout(function() { self.original = angular.copy(self.current); }, 1000); return true; }; this.gist_id = function(string) { if(self.is_gist(string)) { return string.match(gist_pattern)[0].replace(/.*\//, ''); } }; this.is_gist = function(string) { if(!_.isUndefined(string) && string !== '' && !_.isNull(string.match(gist_pattern))) { return string.match(gist_pattern).length > 0 ? true : false; } else { return false; } }; this.to_file = function() { var blob = new Blob([angular.toJson(self.current,true)], {type: "application/json;charset=utf-8"}); // from filesaver.js window.saveAs(blob, self.current.title+"-"+new Date().getTime()); return true; }; this.set_default = function(route) { if (Modernizr.localstorage) { // Purge any old dashboards if(!_.isUndefined(window.localStorage['dashboard'])) { delete window.localStorage['dashboard']; } window.localStorage.grafanaDashboardDefault = route; return true; } else { return false; } }; this.purge_default = function() { if (Modernizr.localstorage) { // Purge any old dashboards if(!_.isUndefined(window.localStorage['dashboard'])) { delete window.localStorage['dashboard']; } delete window.localStorage.grafanaDashboardDefault; return true; } else { return false; } }; // TOFIX: Pretty sure this breaks when you're on a saved dashboard already this.share_link = function(title,type,id) { return { location : window.location.href.replace(window.location.hash,""), type : type, id : id, link : window.location.href.replace(window.location.hash,"")+"#dashboard/"+type+"/"+id, title : title }; }; var renderTemplate = function(json,params) { var _r; _.templateSettings = {interpolate : /\{\{(.+?)\}\}/g}; var template = _.template(json); var rendered = template({ARGS:params}); try { _r = angular.fromJson(rendered); } catch(e) { _r = false; } return _r; }; this.local_load = function() { var dashboard = JSON.parse(window.localStorage['dashboard']); dashboard.rows.unshift({ height: "30", title: "Deprecation Notice", panels: [ { title: 'WARNING: Legacy dashboard', type: 'text', span: 12, mode: 'html', content: 'This dashboard has been loaded from the browsers local cache. If you use '+ 'another brower or computer you will not be able to access it! '+ '\n\n