![JAR search and dependency download from the Maven repository](/logo.png)
app.services.dashboard.js Maven / Gradle / Ivy
The newest version!
define([
'angular',
'jquery',
'kbn',
'lodash',
'config',
'moment',
'modernizr',
'filesaver',
'blob'
],
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, kbnIndex, alertSrv, esVersion, esMinVersion
) {
// A hash of defaults to use when loading a dashboard
var _dash = {
title: "",
style: "dark",
editable: true,
failover: false,
panel_hints: true,
rows: [],
pulldowns: [
{
type: 'query',
},
{
type: 'filtering'
}
],
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
},
index: {
interval: 'none',
pattern: '_all',
default: 'INDEX_MISSING',
warm_fields: true
},
refresh: false
};
// An elasticJS client to use
var ejs = ejsResource(config);
var gist_pattern = /(^\d{5,}$)|(^[a-z0-9]{10,}$)|(gist.github.com(\/*.*)\/[a-z0-9]{5,}\/*$)/;
// Store a reference to this
var self = this;
var filterSrv,querySrv;
this.current = _.clone(_dash);
this.last = {};
this.availablePanels = [];
$rootScope.$on('$routeChangeSuccess',function(){
// Clear the current dashboard to prevent reloading
self.current = {};
self.indices = [];
esVersion.isMinimum().then(function(isMinimum) {
if(_.isUndefined(isMinimum)) {
return;
}
if(isMinimum) {
route();
} else {
alertSrv.set('Upgrade Required',"Your version of Elasticsearch is too old. Kibana requires" +
" Elasticsearch " + esMinVersion + " or above.", "error");
}
});
});
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.kibanaDashboardDefault))) {
$location.path(window.localStorage.kibanaDashboardDefault);
} else {
$location.path(config.default_route);
}
// No? Ok, grab the default route, its all we have now
} else {
$location.path(config.default_route);
}
}
};
// Since the dashboard is responsible for index computation, we can compute and assign the indices
// here before telling the panels to refresh
this.refresh = function() {
if(self.current.index.interval !== 'none') {
if(_.isUndefined(filterSrv)) {
return;
}
if(filterSrv.idsByType('time').length > 0) {
var _range = filterSrv.timeRange('last');
kbnIndex.indices(_range.from,_range.to,
self.current.index.pattern,self.current.index.interval
).then(function (p) {
if(p.length > 0) {
self.indices = p;
} else {
// Option to not failover
if(self.current.failover) {
self.indices = [self.current.index.default];
} else {
// Do not issue refresh if no indices match. This should be removed when panels
// properly understand when no indices are present
alertSrv.set('No results','There were no results because no indices were found that match your'+
' selected time span','info',5000);
return false;
}
}
// Don't resolve queries until indices are updated
querySrv.resolve().then(function(){$rootScope.$broadcast('refresh');});
});
} else {
if(self.current.failover) {
self.indices = [self.current.index.default];
querySrv.resolve().then(function(){$rootScope.$broadcast('refresh');});
} else {
alertSrv.set("No time filter",
'Timestamped indices are configured without a failover. Waiting for time filter.',
'info',5000);
}
}
} else {
self.indices = [self.current.index.default];
querySrv.resolve().then(function(){$rootScope.$broadcast('refresh');});
}
};
var dash_defaults = function(dashboard) {
_.defaults(dashboard,_dash);
_.defaults(dashboard.index,_dash.index);
_.defaults(dashboard.loader,_dash.loader);
return _.cloneDeep(dashboard);
};
this.dash_load = function(dashboard) {
// Cancel all timers
timer.cancel_all();
// Make sure the dashboard being loaded has everything required
dashboard = dash_defaults(dashboard);
// If not using time based indices, use the default index
if(dashboard.index.interval === 'none') {
self.indices = [dashboard.index.default];
}
// Set the current dashboard
self.current = _.clone(dashboard);
// Delay this until we're sure that querySrv and filterSrv are ready
$timeout(function() {
// Ok, now that we've setup the current dashboard, we can inject our services
if(!_.isUndefined(self.current.services.query)) {
querySrv = $injector.get('querySrv');
querySrv.init();
}
if(!_.isUndefined(self.current.services.filter)) {
filterSrv = $injector.get('filterSrv');
filterSrv.init();
}
},0).then(function() {
// Call refresh to calculate the indices and notify the panels that we're ready to roll
self.refresh();
});
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);
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.kibanaDashboardDefault = 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.kibanaDashboardDefault;
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.substr(0, window.location.href.indexOf('#')),
type : type,
id : id,
link : window.location.href.substr(0, window.location.href.indexOf('#'))+"#dashboard/"+type+"/"+encodeURIComponent(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 Good news!
Kibana'+
' now stores saved dashboards in Elasticsearch. Click the '+
'button in the top left to save this dashboard. Then select "Set as Home" from'+
' the "advanced" sub menu to automatically use the stored dashboard as your Kibana '+
'landing page afterwards'+
'
Tip: You may with to remove this row before saving!'
}
]
});
self.dash_load(dashboard);
};
this.file_load = function(file) {
return $http({
url: "app/dashboards/"+file.replace(/\.(?!json)/,"/")+'?' + new Date().getTime(),
method: "GET",
transformResponse: function(response) {
return renderTemplate(response,$routeParams);
}
}).then(function(result) {
if(!result) {
return false;
}
self.dash_load(dash_defaults(result.data));
return true;
},function() {
alertSrv.set('Error',"Could not load dashboards/"+file+". Please make sure it exists" ,'error');
return false;
});
};
this.elasticsearch_load = function(type,id) {
var successcb = function(data) {
var response = renderTemplate(angular.fromJson(data).dashboard, $routeParams);
self.dash_load(response);
};
var errorcb = function(data, status) {
if(status === 0) {
alertSrv.set('Error',"Could not contact Elasticsearch at "+ejs.config.host+
". Please ensure that Elasticsearch is reachable from your system." ,'error');
} else {
alertSrv.set('Error',"Could not find "+id+". If you"+
" are using a proxy, ensure it is configured correctly",'error');
}
return false;
};
ejs.getSource(config.kibana_index, type, id).then(successcb, errorcb);
};
this.script_load = function(file) {
return $http({
url: "app/dashboards/"+file.replace(/\.(?!js)/,"/"),
method: "GET",
transformResponse: function(response) {
/*jshint -W054 */
var _f = new Function('ARGS','kbn','_','moment','window','document','angular','require','define','$','jQuery',response);
return _f($routeParams,kbn,_,moment);
}
}).then(function(result) {
if(!result) {
return false;
}
self.dash_load(dash_defaults(result.data));
return true;
},function() {
alertSrv.set('Error',
"Could not load scripts/"+file+". Please make sure it exists and returns a valid dashboard" ,
'error');
return false;
});
};
this.elasticsearch_save = function(type,title,ttl) {
// Clone object so we can modify it without influencing the existing obejct
var save = _.clone(self.current);
var id;
// Change title on object clone
if (type === 'dashboard') {
id = save.title = _.isUndefined(title) ? self.current.title : title;
}
// Create request with id as title. Rethink this.
var indexSource = {
user: 'guest',
group: 'guest',
title: save.title,
dashboard: angular.toJson(save)
};
return ejs.doIndex(config.kibana_index,type,id, indexSource, type === 'temp' && ttl ? ttl : undefined).then(
// Success
function(result) {
if(type === 'dashboard') {
$location.path('/dashboard/elasticsearch/'+title);
}
return result;
},
// Failure
function() {
return false;
}
);
};
this.elasticsearch_delete = function(id) {
return ejs.doDelete(config.kibana_index,'dashboard',id).then(
// Success
function(result) {
return result;
},
// Failure
function() {
return false;
}
);
};
this.elasticsearch_list = function(query,count) {
var request = ejs.Request();
var ejsQuery = ejs.BoolQuery();
if(query) {
ejsQuery = ejsQuery.must(ejs.QueryStringQuery(query).defaultField('title'));
}
ejsQuery = ejsQuery.must(ejs.MatchQuery('_type', 'dashboard'));
request = request.query(ejsQuery);
return ejs.doSearch(config.kibana_index, request, count).then(
// Success
function(result) {
return result;
},
// Failure
function() {
return false;
}
);
};
this.save_gist = function(title,dashboard) {
var save = _.clone(dashboard || self.current);
save.title = title || self.current.title;
return $http({
url: "https://api.github.com/gists",
method: "POST",
data: {
"description": save.title,
"public": false,
"files": {
"kibana-dashboard.json": {
"content": angular.toJson(save,true)
}
}
}
}).then(function(data) {
return data.data.html_url;
}, function() {
return false;
});
};
this.gist_list = function(id) {
return $http.jsonp("https://api.github.com/gists/"+id+"?callback=JSON_CALLBACK"
).then(function(response) {
var files = [];
_.each(response.data.data.files,function(v) {
try {
var file = JSON.parse(v.content);
files.push(file);
} catch(e) {
return false;
}
});
return files;
}, function() {
return false;
});
};
this.start_scheduled_refresh = function (after_ms) {
timer.cancel(self.refresh_timer);
self.refresh_timer = timer.register($timeout(function () {
self.start_scheduled_refresh(after_ms);
self.refresh();
}, after_ms));
};
this.cancel_scheduled_refresh = function () {
timer.cancel(self.refresh_timer);
};
this.set_interval = function (interval) {
self.current.refresh = interval;
if (interval) {
var _i = kbn.interval_to_ms(interval);
this.start_scheduled_refresh(_i);
} else {
this.cancel_scheduled_refresh();
}
};
});
});
© 2015 - 2025 Weber Informatics LLC | Privacy Policy