diff --git a/pdb-ui/src/main/resources/resources/js/ui.js b/pdb-ui/src/main/resources/resources/js/ui.js
index 460246f..69e9c75 100644
--- a/pdb-ui/src/main/resources/resources/js/ui.js
+++ b/pdb-ui/src/main/resources/resources/js/ui.js
@@ -1,835 +1,835 @@
-'use strict';
-
-function ffHasParentWithId(el, id) {
- if (el.id == id){
- return true;
- }
- else if (el.parentNode) {
- return ffHasParentWithId(el.parentNode, id);
- }
-
- return false;
-};
-
-window.onload=function(){
-
-Vue.config.keyCodes.arrowUp = 38;
-Vue.config.keyCodes.arrowDown = 40;
-
-Vue.component('search-bar-query', {
- props: ['searchBar'],
- autocompleteTimeout: null,
- requestNumber: 1,
- created: function() {
- this.requestNumber= 1;
- document.addEventListener("click", function(event){
- const isSearchInput = event.path
- ? event.path.map((e) => e.id == "search-input-wrapper")
- .reduce((accumulator, currentValue) => accumulator || currentValue)
- : ffHasParentWithId(event.explicitOriginalTarget, "search-input-wrapper");
- if(!isSearchInput){
- data.searchBar.proposals = [];
- }
- });
- },
- data: function() {
- return {
- highlightedProposal: -1,
- };
- },
- methods: {
- onChange: function (event) {
- if (event.key == 'ArrowDown' || event.key == 'ArrowUp' || event.key == 'Enter' || event.key == 'Escape'){
- return;
- }
-
- this.autocomplete(this, event);
- },
- autocomplete: function(vm, event) {
-
- if(this.autocompleteTimeout) {
- window.clearTimeout(this.autocompleteTimeout);
- if (event) {
- event.preventDefault();
- }
- }
-
- vm.showProposals = false;
-
- var expectedRequestNumber = ++vm.requestNumber;
- vm.autocompleteTimeout = window.setTimeout(function() {
- var caretIndex = document.getElementById('search-input').selectionStart + 1;
- var request='autocomplete?caretIndex=' + caretIndex + '&query='+encodeURIComponent(data.searchBar.query);
-
- var successCallback = function(result) {
- if (expectedRequestNumber == vm.requestNumber) {
- vm.highlightedProposal = -1;
- vm.showProposals = true;
-
- var index = 0;
- var proposals = result.proposals;
- proposals.forEach(function(p) {
- p.id = "proposal_"+index
- p.index = index++;
- p.highlighted=false;
- });
- data.searchBar.proposals = proposals;
- } else {
- console.log("ignoring stale response "+ expectedRequestNumber +" != "+ vm.requestNumber);
- }
- };
-
- var errorCallback = function(e) {
- console.log("FAILED: " + JSON.parse(e.responseText).message);
- vm.proposals=[];
- };
-
- getJson(request, {}, successCallback, errorCallback);
- },
- 300);
- },
- selectOrSubmit: function(event) {
- const vm = this;
- if (this.highlightedProposal >= 0){
- event.preventDefault();
- var proposal = data.searchBar.proposals[this.highlightedProposal];
- data.searchBar.query = proposal.newQuery;
- data.searchBar.proposals = [];
-
- Vue.nextTick(function () {
- var el = document.getElementById('search-input');
- el.select();
- el.selectionStart=proposal.newCaretPosition;
- el.selectionEnd=proposal.newCaretPosition;
-
- vm.autocomplete(vm);
- });
- }
- },
- selectUpDown: function(event) {
- if (event.key == 'ArrowDown'){
- this.highlightedProposal = (this.highlightedProposal+1) % data.searchBar.proposals.length;
- } else if (event.key == 'ArrowUp') {
- this.highlightedProposal = (this.highlightedProposal-1) % data.searchBar.proposals.length;
- this.highlightedProposal = this.highlightedProposal < 0 ? -1 : this.highlightedProposal;
- }
- },
-
- noop: function(event){},
- },
- template: `
-
`
-});
-
-Vue.component('proposal-item', {
- props: ['proposalItem', 'highlightedProposal'],
- computed: {
- isHighlighted: function() {
- return this.highlightedProposal == this.proposalItem.index;
- }
- },
- methods: {
- selectProposal: function(event) {
- var proposal = data.searchBar.proposals[this.proposalItem.index];
- data.searchBar.query = proposal.newQuery;
- data.searchBar.proposals = [];
-
- Vue.nextTick(function () {
- var el = document.getElementById('search-input');
- el.select();
- el.selectionStart=proposal.newCaretPosition;
- el.selectionEnd=proposal.newCaretPosition;
- });
- },
- },
- template: `
- {{ proposalItem.value }}
`
-});
-
-
-Vue.component('result-view', {
- props: ['searchBar', 'resultView'],
- methods: {
- prev_image: function()
- {
- var splitBy = data.searchBar.splitBy;
- if (splitBy['values'].length > 0)
- {
- splitBy['index'] = (splitBy['index']+ splitBy['values'].length-1) % splitBy['values'].length;
- plotCurrent();
- }
- },
- next_image: function()
- {
- var splitBy = data.searchBar.splitBy;
- if (splitBy['values'].length > 0)
- {
- splitBy['index'] = (splitBy['index']+1) % splitBy['values'].length;
- plotCurrent();
- }
- }
- },
- computed: {
- showPrevNext: function() {
- return data.searchBar.splitBy.values.length > 0 && !data.resultView.loadingGameActive;
- }
- },
- template: `
-
-
-
-
-
{{ resultView.errorMessage }}
-
`
-});
-
-Vue.component('navigation-bar', {
- props: [],
- methods: {
-
- refresh: function()
- {
- plotCurrent();
- },
- zoomIn: function()
- {
- this.shiftDate(0.25);
- this.zoom(0.5);
- plotCurrent();
- },
- zoomOut: function()
- {
- this.shiftDate(-0.5);
- this.zoom(2);
- plotCurrent();
- },
- dateLeftShift: function()
- {
- this.shiftDate(-1);
- plotCurrent();
- },
- dateHalfLeftShift: function()
- {
- this.shiftDate(-0.5);
- plotCurrent();
- },
- dateHalfRightShift: function()
- {
- this.shiftDate(0.5);
- plotCurrent();
- },
- dateRightShift: function()
- {
- this.shiftDate(1);
- plotCurrent();
- },
- zoom: function(factor)
- {
- if (!$('#search-date-range').is(":invalid")) {
-
- var dateRange = data.searchBar.dateRange;
- var tokens = dateRange.split(/ +/,2);
-
- if(tokens.length == 2)
- {
- var value = parseInt(tokens[0]);
- var period = tokens[1];
-
- var newValue = value*factor;
- while (newValue != Math.round(newValue)){
-
- switch (period) {
- case "second":
- case "seconds":
- if (value == 1) {
- // we reached the smallest range
- }
- else if (value % 2 == 1){
- value = value -1;
- }
- break;
- case "minute":
- case "minutes":
- value = value * 60;
- period = "seconds";
- break;
- case "hour":
- case "hours":
- value = value * 60;
- period = "minutes";
- break;
- case "day":
- case "days":
- value = value * 24;
- period = "hours";
- break;
- case "week":
- case "weeks":
- value = value * 7;
- period = "days";
- break;
- case "month":
- case "months":
- value = value * 30;
- period = "days";
- break;
- default:
- console.log("unhandled value: "+ period);
- break;
- }
-
- newValue = value*factor
- }
-
-
- data.searchBar.dateRange = newValue + " " + period;
- }
- }
- },
- shiftDate: function(directionalFactor)
- {
- var dateBefore = Date.parse(data.searchBar.dateFrom);
- var newDate = this.shiftByInterval(dateBefore, directionalFactor);
- data.searchBar.dateFrom = newDate.toString("yyyy-MM-dd HH:mm:ss");
- },
- shiftByInterval: function(date, directionalFactor)
- {
- if (!$('#search-date-range').is(":invalid")) {
-
- var dateRange = data.searchBar.dateRange;
- var tokens = dateRange.split(/ +/,2);
-
- if(tokens.length == 2)
- {
- var value = parseInt(tokens[0]);
- var period = tokens[1];
- var config = {};
-
- value = directionalFactor * value;
-
- switch (period) {
- case "second":
- case "seconds":
- config = { seconds: value };
- break;
- case "minute":
- case "minutes":
- config = { minutes: value };
- break;
- case "hour":
- case "hours":
- config = { minutes: 60*value };
- break;
- case "day":
- case "days":
- config = { days: value };
- break;
- case "week":
- case "weeks":
- config = { days: 7*value };
- break;
- case "month":
- case "months":
- config = { days: 30*value };
- break;
-
- default:
- break;
- }
-
- var newDate = date.add(config);
- return newDate;
- }
- }
- return date;
- }
- },
- template: `
- `
-});
-
-Vue.component('group-by-item', {
- props: ['groupBy'],
- template: `
- `
-});
-
-Vue.component('search-bar', {
- props: ['searchBar'],
- methods: {
- plot: function (event) {
- var vm = this;
- if (this.searchBar.splitByKeys.selected){
- this.splitQueries(function (fieldValues) {
- data.searchBar.splitBy['values'] = fieldValues;
- vm.enableSplitBy(fieldValues);
- plotCurrent();
- });
-
- }else{
- this.disableSplitBy();
- plotCurrent();
- }
- },
- dashboard: function (event) {
- alert('dashboard');
- },
- enableSplitBy: function(fieldValues) {
- data.searchBar.splitBy['field'] = data.searchBar.splitByKeys.selected;
- data.searchBar.splitBy['values'] = fieldValues;
- data.searchBar.splitBy['index'] = 0;
- data.searchBar.splitBy['query'] = data.searchBar.query;
- },
- disableSplitBy: function() {
- data.searchBar.splitBy['field'] = '';
- data.searchBar.splitBy['values'] = [];
- data.searchBar.splitBy['index'] = 0;
- data.searchBar.splitBy['query'] = '';
- },
- splitQueries: function(successCallback)
- {
- var request = {};
- request['query'] = data.searchBar.query;
-
- var error = function(e) {
- data.resultView.errorMessage = "FAILED: " + JSON.parse(e.responseText).message;
- };
-
- var url = "/fields/"+encodeURIComponent(data.searchBar.splitByKeys.selected)+"/values";
- getJson(url, request, successCallback, error);
- },
- },
- computed: {
- permalink: function() {
- var groupBy = [];
- data.searchBar.groupByKeys.forEach(function(e){ if (e.selected) {groupBy.push(e.selected);}});
-
- var params = {
- 'query': data.searchBar.query,
- 'groupBy': groupBy,
- 'splitByKeys.selected': data.searchBar.splitByKeys.selected,
- 'limitBy.selected': data.searchBar.limitBy.selected,
- 'limitBy.number': data.searchBar.limitBy.number,
- 'dateFrom': data.searchBar.dateFrom,
- 'dateRange': data.searchBar.dateRange,
- 'axisScale': data.searchBar.axisScale,
- 'plotType': data.searchBar.plotType,
- 'aggregate': data.searchBar.aggregate,
- 'keyOutside': data.searchBar.keyOutside,
- };
-
- var link = window.location.origin+ window.location.pathname + "?" + jQuery.param( params );
- return link;
- }
- },
- template: `
- `
-});
-
-var rootView = new Vue({
- el: '#app',
- data: data,
- created: function() {
- var self = this;
- var request = {};
-
- var success = function(response){
-
- var options = [{ text: '', value: '' }];
-
- response.forEach( (item, index) => { options.push({text: item, value: item}); } );
-
- const groupByDefaults = GetURLParameterArray('groupBy');
-
- for (var i = 0; i < 3; i++){
- self.searchBar.groupByKeys.push({
- 'id': 'groupByKeys'+i,
- 'selected': groupByDefaults[i] ? groupByDefaults[i] : '',
- 'options': options
- });
- }
- self.searchBar.splitByKeys.options = options
- };
- var error = function(e) {
- data.resultView.errorMessage = "FAILED: " + JSON.parse(e.responseText).message;
- };
-
- getJson("fields", request, success, error);
- }
-});
-
-initInvaders('result-image');
-
-} // end window.on-load
-
-var data = {
-
- searchBar: {
- query: GetURLParameter('query', 'pod=vapfinra01 and method = ViewService.findFieldViewGroup'),
- proposals: [],
- groupByKeys: [],
- splitByKeys: {
- 'selected': GetURLParameter('splitByKeys.selected','method'),
- 'options': []
- },
- limitBy: {
- 'selected': GetURLParameter('limitBy.selected','NO_LIMIT'),
- 'number': GetURLParameter('limitBy.number',10)
- },
- dateFrom: GetURLParameter('dateFrom', Date.now().add({ days: -7 }).toString("yyyy-MM-dd HH:mm:ss")), // '2018-01-05 09:03:00'
- dateRange: GetURLParameter('dateRange','1 week'),
- axisScale: GetURLParameter('axisScale','LOG10'),
- plotType: GetURLParameter('plotType','SCATTER'),
- aggregate: GetURLParameter('aggregate','NONE'),
- keyOutside: GetURLParameterBoolean('keyOutside', 'false'),
-
- splitBy: {
- field: '',
- query: '',
- values: [],
- index: 0
- },
- imagelink: ""
- },
- resultView: {
- imageUrl: '',
- errorMessage: '',
- loadingGameActive: false
- },
-};
-
-
-function showLoadingIcon()
-{
- data.resultView.imageUrl = '';
- data.resultView.errorMessage = '';
- data.resultView.loadingGameActive = true;
-
- startInvaders();
-}
-
-function hideLoadingIcon()
-{
- data.resultView.loadingGameActive = false;
- pauseInvaders();
-}
-
-function plotCurrent()
-{
- showLoadingIcon();
-
- if (data.searchBar.splitBy['field']) {
- var query = createQuery();
- sendPlotRequest(query);
- }else{
- sendPlotRequest(data.searchBar.query);
- }
-}
-
-function createQuery()
-{
- var splitBy = data.searchBar.splitBy;
- var query = splitBy['query'];
- if (query.length > 0) {
- query = "("+query+") and "+splitBy['field']+ " = " +splitBy['values'][splitBy['index']];
- } else {
- query = splitBy['field']+ " = " +splitBy['values'][splitBy['index']];
- }
- return query;
-}
-
-
-function groupBy()
-{
- var result = [];
- data.searchBar.groupByKeys.forEach(function(item) {
- if (item.selected) {
- result.push(item.selected);
- }
- });
- return result;
-}
-
-function sendPlotRequest(query){
-
- var request = {};
- request['query'] = query;
- request['height'] = $('#result-image').height();
- request['width'] = $('#result-image').width();
- request['groupBy'] = groupBy();
- request['limitBy'] = data.searchBar.limitBy.selected;
- request['limit'] = parseInt(data.searchBar.limitBy.number);
- request['dateFrom'] = data.searchBar.dateFrom;
- request['dateRange'] = data.searchBar.dateRange;
- request['axisScale'] = data.searchBar.axisScale;
- request['plotType'] = data.searchBar.plotType;
- request['aggregate'] = data.searchBar.aggregate;
- request['keyOutside'] = data.searchBar.keyOutside;
-
-
- var success = function(response){
- data.resultView.imageUrl = response.imageUrl;
- data.resultView.errorMessage = '';
- hideLoadingIcon();
- updateImageLink(query);
- };
- var error = function(e) {
- data.resultView.imageUrl = '';
- if (e.status == 404){
- data.resultView.errorMessage = "No data points found for query: " + query;
- }
- else if (e.status == 503){
- data.resultView.errorMessage = "Too many parallel requests.";
- }
- else{
- data.resultView.errorMessage = "FAILED: " + JSON.parse(e.responseText).message;
- }
- hideLoadingIcon();
- };
-
- data.searchBar.imagelink = '';
- postJson("plots", request, success, error);
-}
-
-function updateImageLink(query) {
-
- var groupBy = [];
- data.searchBar.groupByKeys.forEach(function(e){ if (e.selected) {groupBy.push(e.selected);}});
-
- var params = {
- 'query': query,
- 'groupBy': groupBy,
- 'splitByKeys.selected': data.searchBar.splitByKeys.selected,
- 'limitBy.selected': data.searchBar.limitBy.selected,
- 'limitBy.number': data.searchBar.limitBy.number,
- 'dateFrom': data.searchBar.dateFrom,
- 'dateRange': data.searchBar.dateRange,
- 'axisScale': data.searchBar.axisScale,
- 'plotType': data.searchBar.plotType,
- 'aggregate': data.searchBar.aggregate,
- 'keyOutside': data.searchBar.keyOutside,
- 'width': $('#result-image').width(),
- 'height': $('#result-image').height()
- };
-
- data.searchBar.imagelink = window.location.origin+ window.location.pathname + "plots?" + jQuery.param(params);
-}
-
-function postJson(url, requestData, successCallback, errorCallback) {
-
- $.ajax({
- type: "POST",
- url: url,
- data: JSON.stringify(requestData),
- contentType: 'application/json'
- })
- .done(successCallback)
- .fail(errorCallback);
-}
-
-function getJson(url, requestData, successCallback, errorCallback) {
-
- $.ajax({
- type: "GET",
- url: url,
- data: requestData,
- contentType: 'application/json'
- })
- .done(successCallback)
- .fail(errorCallback);
-}
-
-function GetURLParameter(paramName, defaultValue)
-{
- var pageURL = window.location.search.substring(1);
- var URLVariables = pageURL.split('&');
- for (var i = 0; i < URLVariables.length; i++)
- {
- var keyValue = URLVariables[i].split('=');
- if (keyValue[0] == paramName)
- {
- return decodeURIComponent(keyValue[1]);
- }
- }
- return defaultValue;
-}
-
-function GetURLParameterArray(paramName)
-{
- var result = [];
- var pageURL = window.location.search.substring(1);
- var URLVariables = pageURL.split('&');
- for (var i = 0; i < URLVariables.length; i++)
- {
- var keyValue = URLVariables[i].split('=');
- if (decodeURIComponent(keyValue[0]) == paramName+"[]")
- {
- result.push(decodeURIComponent(keyValue[1]));
- }
- }
- return result;
-}
-
-function GetURLParameterBoolean(paramName, defaultValue){
- return GetURLParameter(paramName, defaultValue) == 'true';
-}
-
+'use strict';
+
+function ffHasParentWithId(el, id) {
+ if (el.id == id){
+ return true;
+ }
+ else if (el.parentNode) {
+ return ffHasParentWithId(el.parentNode, id);
+ }
+
+ return false;
+};
+
+window.onload=function(){
+
+Vue.config.keyCodes.arrowUp = 38;
+Vue.config.keyCodes.arrowDown = 40;
+
+Vue.component('search-bar-query', {
+ props: ['searchBar'],
+ autocompleteTimeout: null,
+ requestNumber: 1,
+ created: function() {
+ this.requestNumber= 1;
+ document.addEventListener("click", function(event){
+ const isSearchInput = event.path
+ ? event.path.map((e) => e.id == "search-input-wrapper")
+ .reduce((accumulator, currentValue) => accumulator || currentValue)
+ : ffHasParentWithId(event.explicitOriginalTarget, "search-input-wrapper");
+ if(!isSearchInput){
+ data.searchBar.proposals = [];
+ }
+ });
+ },
+ data: function() {
+ return {
+ highlightedProposal: -1,
+ };
+ },
+ methods: {
+ onChange: function (event) {
+ if (event.key == 'ArrowDown' || event.key == 'ArrowUp' || event.key == 'Enter' || event.key == 'Escape'){
+ return;
+ }
+
+ this.autocomplete(this, event);
+ },
+ autocomplete: function(vm, event) {
+
+ if(this.autocompleteTimeout) {
+ window.clearTimeout(this.autocompleteTimeout);
+ if (event) {
+ event.preventDefault();
+ }
+ }
+
+ vm.showProposals = false;
+
+ var expectedRequestNumber = ++vm.requestNumber;
+ vm.autocompleteTimeout = window.setTimeout(function() {
+ var caretIndex = document.getElementById('search-input').selectionStart + 1;
+ var request='autocomplete?caretIndex=' + caretIndex + '&query='+encodeURIComponent(data.searchBar.query);
+
+ var successCallback = function(result) {
+ if (expectedRequestNumber == vm.requestNumber) {
+ vm.highlightedProposal = -1;
+ vm.showProposals = true;
+
+ var index = 0;
+ var proposals = result.proposals;
+ proposals.forEach(function(p) {
+ p.id = "proposal_"+index
+ p.index = index++;
+ p.highlighted=false;
+ });
+ data.searchBar.proposals = proposals;
+ } else {
+ console.log("ignoring stale response "+ expectedRequestNumber +" != "+ vm.requestNumber);
+ }
+ };
+
+ var errorCallback = function(e) {
+ console.log("FAILED: " + JSON.parse(e.responseText).message);
+ vm.proposals=[];
+ };
+
+ getJson(request, {}, successCallback, errorCallback);
+ },
+ 300);
+ },
+ selectOrSubmit: function(event) {
+ const vm = this;
+ if (this.highlightedProposal >= 0){
+ event.preventDefault();
+ var proposal = data.searchBar.proposals[this.highlightedProposal];
+ data.searchBar.query = proposal.newQuery;
+ data.searchBar.proposals = [];
+
+ Vue.nextTick(function () {
+ var el = document.getElementById('search-input');
+ el.select();
+ el.selectionStart=proposal.newCaretPosition;
+ el.selectionEnd=proposal.newCaretPosition;
+
+ vm.autocomplete(vm);
+ });
+ }
+ },
+ selectUpDown: function(event) {
+ if (event.key == 'ArrowDown'){
+ this.highlightedProposal = (this.highlightedProposal+1) % data.searchBar.proposals.length;
+ } else if (event.key == 'ArrowUp') {
+ this.highlightedProposal = (this.highlightedProposal-1) % data.searchBar.proposals.length;
+ this.highlightedProposal = this.highlightedProposal < 0 ? -1 : this.highlightedProposal;
+ }
+ },
+
+ noop: function(event){},
+ },
+ template: `
+ `
+});
+
+Vue.component('proposal-item', {
+ props: ['proposalItem', 'highlightedProposal'],
+ computed: {
+ isHighlighted: function() {
+ return this.highlightedProposal == this.proposalItem.index;
+ }
+ },
+ methods: {
+ selectProposal: function(event) {
+ var proposal = data.searchBar.proposals[this.proposalItem.index];
+ data.searchBar.query = proposal.newQuery;
+ data.searchBar.proposals = [];
+
+ Vue.nextTick(function () {
+ var el = document.getElementById('search-input');
+ el.select();
+ el.selectionStart=proposal.newCaretPosition;
+ el.selectionEnd=proposal.newCaretPosition;
+ });
+ },
+ },
+ template: `
+ {{ proposalItem.value }}
`
+});
+
+
+Vue.component('result-view', {
+ props: ['searchBar', 'resultView'],
+ methods: {
+ prev_image: function()
+ {
+ var splitBy = data.searchBar.splitBy;
+ if (splitBy['values'].length > 0)
+ {
+ splitBy['index'] = (splitBy['index']+ splitBy['values'].length-1) % splitBy['values'].length;
+ plotCurrent();
+ }
+ },
+ next_image: function()
+ {
+ var splitBy = data.searchBar.splitBy;
+ if (splitBy['values'].length > 0)
+ {
+ splitBy['index'] = (splitBy['index']+1) % splitBy['values'].length;
+ plotCurrent();
+ }
+ }
+ },
+ computed: {
+ showPrevNext: function() {
+ return data.searchBar.splitBy.values.length > 0 && !data.resultView.loadingGameActive;
+ }
+ },
+ template: `
+
+
+
+
+
{{ resultView.errorMessage }}
+
`
+});
+
+Vue.component('navigation-bar', {
+ props: [],
+ methods: {
+
+ refresh: function()
+ {
+ plotCurrent();
+ },
+ zoomIn: function()
+ {
+ this.shiftDate(0.25);
+ this.zoom(0.5);
+ plotCurrent();
+ },
+ zoomOut: function()
+ {
+ this.shiftDate(-0.5);
+ this.zoom(2);
+ plotCurrent();
+ },
+ dateLeftShift: function()
+ {
+ this.shiftDate(-1);
+ plotCurrent();
+ },
+ dateHalfLeftShift: function()
+ {
+ this.shiftDate(-0.5);
+ plotCurrent();
+ },
+ dateHalfRightShift: function()
+ {
+ this.shiftDate(0.5);
+ plotCurrent();
+ },
+ dateRightShift: function()
+ {
+ this.shiftDate(1);
+ plotCurrent();
+ },
+ zoom: function(factor)
+ {
+ if (!$('#search-date-range').is(":invalid")) {
+
+ var dateRange = data.searchBar.dateRange;
+ var tokens = dateRange.split(/ +/,2);
+
+ if(tokens.length == 2)
+ {
+ var value = parseInt(tokens[0]);
+ var period = tokens[1];
+
+ var newValue = value*factor;
+ while (newValue != Math.round(newValue)){
+
+ switch (period) {
+ case "second":
+ case "seconds":
+ if (value == 1) {
+ // we reached the smallest range
+ }
+ else if (value % 2 == 1){
+ value = value -1;
+ }
+ break;
+ case "minute":
+ case "minutes":
+ value = value * 60;
+ period = "seconds";
+ break;
+ case "hour":
+ case "hours":
+ value = value * 60;
+ period = "minutes";
+ break;
+ case "day":
+ case "days":
+ value = value * 24;
+ period = "hours";
+ break;
+ case "week":
+ case "weeks":
+ value = value * 7;
+ period = "days";
+ break;
+ case "month":
+ case "months":
+ value = value * 30;
+ period = "days";
+ break;
+ default:
+ console.log("unhandled value: "+ period);
+ break;
+ }
+
+ newValue = value*factor
+ }
+
+
+ data.searchBar.dateRange = newValue + " " + period;
+ }
+ }
+ },
+ shiftDate: function(directionalFactor)
+ {
+ var dateBefore = Date.parse(data.searchBar.dateFrom);
+ var newDate = this.shiftByInterval(dateBefore, directionalFactor);
+ data.searchBar.dateFrom = newDate.toString("yyyy-MM-dd HH:mm:ss");
+ },
+ shiftByInterval: function(date, directionalFactor)
+ {
+ if (!$('#search-date-range').is(":invalid")) {
+
+ var dateRange = data.searchBar.dateRange;
+ var tokens = dateRange.split(/ +/,2);
+
+ if(tokens.length == 2)
+ {
+ var value = parseInt(tokens[0]);
+ var period = tokens[1];
+ var config = {};
+
+ value = directionalFactor * value;
+
+ switch (period) {
+ case "second":
+ case "seconds":
+ config = { seconds: value };
+ break;
+ case "minute":
+ case "minutes":
+ config = { minutes: value };
+ break;
+ case "hour":
+ case "hours":
+ config = { minutes: 60*value };
+ break;
+ case "day":
+ case "days":
+ config = { days: value };
+ break;
+ case "week":
+ case "weeks":
+ config = { days: 7*value };
+ break;
+ case "month":
+ case "months":
+ config = { days: 30*value };
+ break;
+
+ default:
+ break;
+ }
+
+ var newDate = date.add(config);
+ return newDate;
+ }
+ }
+ return date;
+ }
+ },
+ template: `
+ `
+});
+
+Vue.component('group-by-item', {
+ props: ['groupBy'],
+ template: `
+ `
+});
+
+Vue.component('search-bar', {
+ props: ['searchBar'],
+ methods: {
+ plot: function (event) {
+ var vm = this;
+ if (this.searchBar.splitByKeys.selected){
+ this.splitQueries(function (fieldValues) {
+ data.searchBar.splitBy['values'] = fieldValues;
+ vm.enableSplitBy(fieldValues);
+ plotCurrent();
+ });
+
+ }else{
+ this.disableSplitBy();
+ plotCurrent();
+ }
+ },
+ dashboard: function (event) {
+ alert('dashboard');
+ },
+ enableSplitBy: function(fieldValues) {
+ data.searchBar.splitBy['field'] = data.searchBar.splitByKeys.selected;
+ data.searchBar.splitBy['values'] = fieldValues;
+ data.searchBar.splitBy['index'] = 0;
+ data.searchBar.splitBy['query'] = data.searchBar.query;
+ },
+ disableSplitBy: function() {
+ data.searchBar.splitBy['field'] = '';
+ data.searchBar.splitBy['values'] = [];
+ data.searchBar.splitBy['index'] = 0;
+ data.searchBar.splitBy['query'] = '';
+ },
+ splitQueries: function(successCallback)
+ {
+ var request = {};
+ request['query'] = data.searchBar.query;
+
+ var error = function(e) {
+ data.resultView.errorMessage = "FAILED: " + JSON.parse(e.responseText).message;
+ };
+
+ var url = "/fields/"+encodeURIComponent(data.searchBar.splitByKeys.selected)+"/values";
+ getJson(url, request, successCallback, error);
+ },
+ },
+ computed: {
+ permalink: function() {
+ var groupBy = [];
+ data.searchBar.groupByKeys.forEach(function(e){ if (e.selected) {groupBy.push(e.selected);}});
+
+ var params = {
+ 'query': data.searchBar.query,
+ 'groupBy': groupBy,
+ 'splitByKeys.selected': data.searchBar.splitByKeys.selected,
+ 'limitBy.selected': data.searchBar.limitBy.selected,
+ 'limitBy.number': data.searchBar.limitBy.number,
+ 'dateFrom': data.searchBar.dateFrom,
+ 'dateRange': data.searchBar.dateRange,
+ 'axisScale': data.searchBar.axisScale,
+ 'plotType': data.searchBar.plotType,
+ 'aggregate': data.searchBar.aggregate,
+ 'keyOutside': data.searchBar.keyOutside,
+ };
+
+ var link = window.location.origin+ window.location.pathname + "?" + jQuery.param( params );
+ return link;
+ }
+ },
+ template: `
+ `
+});
+
+var rootView = new Vue({
+ el: '#app',
+ data: data,
+ created: function() {
+ var self = this;
+ var request = {};
+
+ var success = function(response){
+
+ var options = [{ text: '', value: '' }];
+
+ response.forEach( (item, index) => { options.push({text: item, value: item}); } );
+
+ const groupByDefaults = GetURLParameterArray('groupBy');
+
+ for (var i = 0; i < 3; i++){
+ self.searchBar.groupByKeys.push({
+ 'id': 'groupByKeys'+i,
+ 'selected': groupByDefaults[i] ? groupByDefaults[i] : '',
+ 'options': options
+ });
+ }
+ self.searchBar.splitByKeys.options = options
+ };
+ var error = function(e) {
+ data.resultView.errorMessage = "FAILED: " + JSON.parse(e.responseText).message;
+ };
+
+ getJson("fields", request, success, error);
+ }
+});
+
+initInvaders('result-image');
+
+} // end window.on-load
+
+var data = {
+
+ searchBar: {
+ query: GetURLParameter('query', 'pod=vapfinra01 and method = ViewService.findFieldViewGroup'),
+ proposals: [],
+ groupByKeys: [],
+ splitByKeys: {
+ 'selected': GetURLParameter('splitByKeys.selected','method'),
+ 'options': []
+ },
+ limitBy: {
+ 'selected': GetURLParameter('limitBy.selected','NO_LIMIT'),
+ 'number': GetURLParameter('limitBy.number',10)
+ },
+ dateFrom: GetURLParameter('dateFrom', Date.now().add({ days: -7 }).toString("yyyy-MM-dd HH:mm:ss")), // '2018-01-05 09:03:00'
+ dateRange: GetURLParameter('dateRange','1 week'),
+ axisScale: GetURLParameter('axisScale','LOG10'),
+ plotType: GetURLParameter('plotType','SCATTER'),
+ aggregate: GetURLParameter('aggregate','NONE'),
+ keyOutside: GetURLParameterBoolean('keyOutside', 'false'),
+
+ splitBy: {
+ field: '',
+ query: '',
+ values: [],
+ index: 0
+ },
+ imagelink: ""
+ },
+ resultView: {
+ imageUrl: '',
+ errorMessage: '',
+ loadingGameActive: false
+ },
+};
+
+
+function showLoadingIcon()
+{
+ data.resultView.imageUrl = '';
+ data.resultView.errorMessage = '';
+ data.resultView.loadingGameActive = true;
+
+ startInvaders();
+}
+
+function hideLoadingIcon()
+{
+ data.resultView.loadingGameActive = false;
+ pauseInvaders();
+}
+
+function plotCurrent()
+{
+ showLoadingIcon();
+
+ if (data.searchBar.splitBy['field']) {
+ var query = createQuery();
+ sendPlotRequest(query);
+ }else{
+ sendPlotRequest(data.searchBar.query);
+ }
+}
+
+function createQuery()
+{
+ var splitBy = data.searchBar.splitBy;
+ var query = splitBy['query'];
+ if (query.length > 0) {
+ query = "("+query+") and "+splitBy['field']+ " = " +splitBy['values'][splitBy['index']];
+ } else {
+ query = splitBy['field']+ " = " +splitBy['values'][splitBy['index']];
+ }
+ return query;
+}
+
+
+function groupBy()
+{
+ var result = [];
+ data.searchBar.groupByKeys.forEach(function(item) {
+ if (item.selected) {
+ result.push(item.selected);
+ }
+ });
+ return result;
+}
+
+function sendPlotRequest(query){
+
+ var request = {};
+ request['query'] = query;
+ request['height'] = Math.floor($('#result-image').height());
+ request['width'] = Math.floor($('#result-image').width());
+ request['groupBy'] = groupBy();
+ request['limitBy'] = data.searchBar.limitBy.selected;
+ request['limit'] = parseInt(data.searchBar.limitBy.number);
+ request['dateFrom'] = data.searchBar.dateFrom;
+ request['dateRange'] = data.searchBar.dateRange;
+ request['axisScale'] = data.searchBar.axisScale;
+ request['plotType'] = data.searchBar.plotType;
+ request['aggregate'] = data.searchBar.aggregate;
+ request['keyOutside'] = data.searchBar.keyOutside;
+
+
+ var success = function(response){
+ data.resultView.imageUrl = response.imageUrl;
+ data.resultView.errorMessage = '';
+ hideLoadingIcon();
+ updateImageLink(query);
+ };
+ var error = function(e) {
+ data.resultView.imageUrl = '';
+ if (e.status == 404){
+ data.resultView.errorMessage = "No data points found for query: " + query;
+ }
+ else if (e.status == 503){
+ data.resultView.errorMessage = "Too many parallel requests.";
+ }
+ else{
+ data.resultView.errorMessage = "FAILED: " + JSON.parse(e.responseText).message;
+ }
+ hideLoadingIcon();
+ };
+
+ data.searchBar.imagelink = '';
+ postJson("plots", request, success, error);
+}
+
+function updateImageLink(query) {
+
+ var groupBy = [];
+ data.searchBar.groupByKeys.forEach(function(e){ if (e.selected) {groupBy.push(e.selected);}});
+
+ var params = {
+ 'query': query,
+ 'groupBy': groupBy,
+ 'splitByKeys.selected': data.searchBar.splitByKeys.selected,
+ 'limitBy.selected': data.searchBar.limitBy.selected,
+ 'limitBy.number': data.searchBar.limitBy.number,
+ 'dateFrom': data.searchBar.dateFrom,
+ 'dateRange': data.searchBar.dateRange,
+ 'axisScale': data.searchBar.axisScale,
+ 'plotType': data.searchBar.plotType,
+ 'aggregate': data.searchBar.aggregate,
+ 'keyOutside': data.searchBar.keyOutside,
+ 'width': Math.floor($('#result-image').width()),
+ 'height': Math.floor($('#result-image').height())
+ };
+
+ data.searchBar.imagelink = window.location.origin+ window.location.pathname + "plots?" + jQuery.param(params);
+}
+
+function postJson(url, requestData, successCallback, errorCallback) {
+
+ $.ajax({
+ type: "POST",
+ url: url,
+ data: JSON.stringify(requestData),
+ contentType: 'application/json'
+ })
+ .done(successCallback)
+ .fail(errorCallback);
+}
+
+function getJson(url, requestData, successCallback, errorCallback) {
+
+ $.ajax({
+ type: "GET",
+ url: url,
+ data: requestData,
+ contentType: 'application/json'
+ })
+ .done(successCallback)
+ .fail(errorCallback);
+}
+
+function GetURLParameter(paramName, defaultValue)
+{
+ var pageURL = window.location.search.substring(1);
+ var URLVariables = pageURL.split('&');
+ for (var i = 0; i < URLVariables.length; i++)
+ {
+ var keyValue = URLVariables[i].split('=');
+ if (keyValue[0] == paramName)
+ {
+ return decodeURIComponent(keyValue[1]);
+ }
+ }
+ return defaultValue;
+}
+
+function GetURLParameterArray(paramName)
+{
+ var result = [];
+ var pageURL = window.location.search.substring(1);
+ var URLVariables = pageURL.split('&');
+ for (var i = 0; i < URLVariables.length; i++)
+ {
+ var keyValue = URLVariables[i].split('=');
+ if (decodeURIComponent(keyValue[0]) == paramName+"[]")
+ {
+ result.push(decodeURIComponent(keyValue[1]));
+ }
+ }
+ return result;
+}
+
+function GetURLParameterBoolean(paramName, defaultValue){
+ return GetURLParameter(paramName, defaultValue) == 'true';
+}
+