|
|
|
|
@ -1,16 +1,18 @@ |
|
|
|
|
var Prometheus = Prometheus || {}; |
|
|
|
|
var graphs = []; |
|
|
|
|
var graphTemplate; |
|
|
|
|
|
|
|
|
|
var SECOND = 1000; |
|
|
|
|
|
|
|
|
|
Handlebars.registerHelper('pathPrefix', function() { return PATH_PREFIX; }); |
|
|
|
|
|
|
|
|
|
Prometheus.Graph = function(element, options) { |
|
|
|
|
Prometheus.Graph = function(element, options, handleChange, handleRemove) { |
|
|
|
|
this.el = element; |
|
|
|
|
this.graphHTML = null; |
|
|
|
|
this.options = options; |
|
|
|
|
this.changeHandler = null; |
|
|
|
|
this.handleChange = handleChange; |
|
|
|
|
this.handleRemove = function() { |
|
|
|
|
handleRemove(this); |
|
|
|
|
}; |
|
|
|
|
this.rickshawGraph = null; |
|
|
|
|
this.data = []; |
|
|
|
|
|
|
|
|
|
@ -69,7 +71,7 @@ Prometheus.Graph.prototype.initialize = function() { |
|
|
|
|
}; |
|
|
|
|
$(this).on('keyup input', function() { resizeTextarea(this); }); |
|
|
|
|
}); |
|
|
|
|
self.expr.change(storeGraphOptionsInURL); |
|
|
|
|
self.expr.change(self.handleChange); |
|
|
|
|
|
|
|
|
|
self.rangeInput = self.queryForm.find("input[name=range_input]"); |
|
|
|
|
self.stackedBtn = self.queryForm.find(".stacked_btn"); |
|
|
|
|
@ -85,7 +87,7 @@ Prometheus.Graph.prototype.initialize = function() { |
|
|
|
|
self.tabs.on("shown.bs.tab", function(e) { |
|
|
|
|
var target = $(e.target); |
|
|
|
|
self.options.tab = target.parent().index(); |
|
|
|
|
storeGraphOptionsInURL(); |
|
|
|
|
self.handleChange(); |
|
|
|
|
if ($("#" + target.attr("aria-controls")).hasClass("reload")) { |
|
|
|
|
self.submitQuery(); |
|
|
|
|
} |
|
|
|
|
@ -208,10 +210,6 @@ Prometheus.Graph.prototype.populateInsertableMetrics = function() { |
|
|
|
|
}); |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
Prometheus.Graph.prototype.onChange = function(handler) { |
|
|
|
|
this.changeHandler = handler; |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
Prometheus.Graph.prototype.getOptions = function() { |
|
|
|
|
var self = this; |
|
|
|
|
var options = {}; |
|
|
|
|
@ -544,7 +542,7 @@ Prometheus.Graph.prototype.updateGraph = function() { |
|
|
|
|
legend: legend |
|
|
|
|
}); |
|
|
|
|
|
|
|
|
|
self.changeHandler(); |
|
|
|
|
self.handleChange(); |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
Prometheus.Graph.prototype.resizeGraph = function() { |
|
|
|
|
@ -622,41 +620,10 @@ Prometheus.Graph.prototype.handleConsoleResponse = function(data, textStatus) { |
|
|
|
|
Prometheus.Graph.prototype.remove = function() { |
|
|
|
|
var self = this; |
|
|
|
|
$(self.graphHTML).remove(); |
|
|
|
|
graphs = graphs.filter(function(e) {return e !== self}); |
|
|
|
|
storeGraphOptionsInURL(); |
|
|
|
|
self.handleRemove(); |
|
|
|
|
self.handleChange(); |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
function parseGraphOptionsFromURL() { |
|
|
|
|
var hashOptions = window.location.hash.slice(1); |
|
|
|
|
if (!hashOptions) { |
|
|
|
|
return []; |
|
|
|
|
} |
|
|
|
|
var optionsJSON = decodeURIComponent(window.location.hash.slice(1)); |
|
|
|
|
options = JSON.parse(optionsJSON); |
|
|
|
|
return options; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// NOTE: This needs to be kept in sync with rules/helpers.go:GraphLinkForExpression!
|
|
|
|
|
function storeGraphOptionsInURL() { |
|
|
|
|
var allGraphsOptions = []; |
|
|
|
|
for (var i = 0; i < graphs.length; i++) { |
|
|
|
|
allGraphsOptions.push(graphs[i].getOptions()); |
|
|
|
|
} |
|
|
|
|
var optionsJSON = JSON.stringify(allGraphsOptions); |
|
|
|
|
window.location.hash = encodeURIComponent(optionsJSON); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
function addGraph(options) { |
|
|
|
|
var graph = new Prometheus.Graph($("#graph_container"), options); |
|
|
|
|
graphs.push(graph); |
|
|
|
|
graph.onChange(function() { |
|
|
|
|
storeGraphOptionsInURL(); |
|
|
|
|
}); |
|
|
|
|
$(window).resize(function() { |
|
|
|
|
graph.resizeGraph(); |
|
|
|
|
}); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
function escapeHTML(string) { |
|
|
|
|
var entityMap = { |
|
|
|
|
"&": "&", |
|
|
|
|
@ -672,6 +639,135 @@ function escapeHTML(string) { |
|
|
|
|
}); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
Prometheus.Page = function() { |
|
|
|
|
this.graphs = []; |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
Prometheus.Page.prototype.init = function() { |
|
|
|
|
var graphOptions = this.parseURL(); |
|
|
|
|
if (graphOptions.length === 0) { |
|
|
|
|
graphOptions.push({}); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
graphOptions.forEach(this.addGraph, this); |
|
|
|
|
|
|
|
|
|
$("#add_graph").click(this.addGraph.bind(this, {})); |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
Prometheus.Page.prototype.parseURL = function() { |
|
|
|
|
if (window.location.search == "") { |
|
|
|
|
return []; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
var queryParams = window.location.search.substring(1).split('&'); |
|
|
|
|
var queryParamHelper = new Prometheus.Page.QueryParamHelper(); |
|
|
|
|
return queryParamHelper.parseQueryParams(queryParams); |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
Prometheus.Page.prototype.addGraph = function(options) { |
|
|
|
|
var graph = new Prometheus.Graph( |
|
|
|
|
$("#graph_container"), |
|
|
|
|
options, |
|
|
|
|
this.updateURL.bind(this), |
|
|
|
|
this.removeGraph.bind(this) |
|
|
|
|
); |
|
|
|
|
|
|
|
|
|
this.graphs.push(graph); |
|
|
|
|
$(window).resize(function() { |
|
|
|
|
graph.resizeGraph(); |
|
|
|
|
}); |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
// NOTE: This needs to be kept in sync with /util/strutil/strconv.go:GraphLinkForExpression
|
|
|
|
|
Prometheus.Page.prototype.updateURL = function() { |
|
|
|
|
var queryString = this.graphs.map(function(graph, index) { |
|
|
|
|
var graphOptions = graph.getOptions(); |
|
|
|
|
var queryParamHelper = new Prometheus.Page.QueryParamHelper(); |
|
|
|
|
var queryObject = queryParamHelper.generateQueryObject(graphOptions, index); |
|
|
|
|
return $.param(queryObject); |
|
|
|
|
}, this).join("&"); |
|
|
|
|
|
|
|
|
|
history.pushState({}, "", "graph?" + queryString); |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
Prometheus.Page.prototype.removeGraph = function(graph) { |
|
|
|
|
this.graphs = this.graphs.filter(function(g) {return g !== graph}); |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
Prometheus.Page.QueryParamHelper = function() {}; |
|
|
|
|
|
|
|
|
|
Prometheus.Page.QueryParamHelper.prototype.parseQueryParams = function(queryParams) { |
|
|
|
|
var orderedQueryParams = this.filterInvalidParams(queryParams).sort(); |
|
|
|
|
return this.fetchOptionsFromOrderedParams(orderedQueryParams, 0); |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
Prometheus.Page.QueryParamHelper.queryParamFormat = /^g\d+\..+=.+$/; |
|
|
|
|
|
|
|
|
|
Prometheus.Page.QueryParamHelper.prototype.filterInvalidParams = function(paramTuples) { |
|
|
|
|
return paramTuples.filter(function(paramTuple) { |
|
|
|
|
return Prometheus.Page.QueryParamHelper.queryParamFormat.test(paramTuple); |
|
|
|
|
}); |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
Prometheus.Page.QueryParamHelper.prototype.fetchOptionsFromOrderedParams = function(queryParams, graphIndex) { |
|
|
|
|
if (queryParams.length == 0) { |
|
|
|
|
return []; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
var prefixOfThisIndex = this.queryParamPrefix(graphIndex); |
|
|
|
|
var numberOfParamsForThisGraph = queryParams.filter(function(paramTuple) { |
|
|
|
|
return paramTuple.startsWith(prefixOfThisIndex); |
|
|
|
|
}).length; |
|
|
|
|
|
|
|
|
|
if (numberOfParamsForThisGraph == 0) { |
|
|
|
|
return []; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
var paramsForThisGraph = queryParams.splice(0, numberOfParamsForThisGraph); |
|
|
|
|
|
|
|
|
|
paramsForThisGraph = paramsForThisGraph.map(function(paramTuple) { |
|
|
|
|
return paramTuple.substring(prefixOfThisIndex.length); |
|
|
|
|
}); |
|
|
|
|
|
|
|
|
|
var options = this.parseQueryParamsOfOneGraph(paramsForThisGraph); |
|
|
|
|
var optionAccumulator = this.fetchOptionsFromOrderedParams(queryParams, graphIndex + 1); |
|
|
|
|
optionAccumulator.unshift(options); |
|
|
|
|
|
|
|
|
|
return optionAccumulator; |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
Prometheus.Page.QueryParamHelper.prototype.parseQueryParamsOfOneGraph = function(queryParams) { |
|
|
|
|
var options = {}; |
|
|
|
|
queryParams.forEach(function(tuple) { |
|
|
|
|
var optionNameAndValue = tuple.split('='); |
|
|
|
|
var optionName = optionNameAndValue[0]; |
|
|
|
|
var optionValue = decodeURIComponent(optionNameAndValue[1]); |
|
|
|
|
|
|
|
|
|
optionValue = optionValue.replace(/\+/g, " "); // $.param turns spaces into pluses
|
|
|
|
|
|
|
|
|
|
if (optionName == "tab") { |
|
|
|
|
optionValue = parseInt(optionValue); // tab is integer
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
options[optionName] = optionValue; |
|
|
|
|
}); |
|
|
|
|
|
|
|
|
|
return options; |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
Prometheus.Page.QueryParamHelper.prototype.queryParamPrefix = function(index) { |
|
|
|
|
return "g" + index + "."; |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
Prometheus.Page.QueryParamHelper.prototype.generateQueryObject = function(graphOptions, index) { |
|
|
|
|
var prefix = this.queryParamPrefix(index); |
|
|
|
|
var queryObject = {}; |
|
|
|
|
Object.keys(graphOptions).forEach(function(key) { |
|
|
|
|
queryObject[prefix + key] = graphOptions[key]; |
|
|
|
|
}); |
|
|
|
|
return queryObject; |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
function init() { |
|
|
|
|
$.ajaxSetup({ |
|
|
|
|
cache: false |
|
|
|
|
@ -681,14 +777,8 @@ function init() { |
|
|
|
|
url: PATH_PREFIX + "/static/js/graph_template.handlebar", |
|
|
|
|
success: function(data) { |
|
|
|
|
graphTemplate = Handlebars.compile(data); |
|
|
|
|
var options = parseGraphOptionsFromURL(); |
|
|
|
|
if (options.length === 0) { |
|
|
|
|
options.push({}); |
|
|
|
|
} |
|
|
|
|
for (var i = 0; i < options.length; i++) { |
|
|
|
|
addGraph(options[i]); |
|
|
|
|
} |
|
|
|
|
$("#add_graph").click(function() { addGraph({}); }); |
|
|
|
|
var Page = new Prometheus.Page(); |
|
|
|
|
Page.init(); |
|
|
|
|
} |
|
|
|
|
}); |
|
|
|
|
} |
|
|
|
|
|