mirror of https://gitee.com/bigwinds/arangodb
Merge branch 'devel' of https://github.com/arangodb/arangodb into agency
This commit is contained in:
commit
f4ffae0433
|
@ -1,4 +1,3 @@
|
|||
js-*.h
|
||||
.deps
|
||||
.dirstamp
|
||||
*.o
|
||||
|
@ -18,11 +17,6 @@ js-*.h
|
|||
*.patch
|
||||
*.lnk
|
||||
|
||||
.idea
|
||||
.setup-mr-directories
|
||||
.setup-js-directories
|
||||
.file-list-js
|
||||
|
||||
testresult.json
|
||||
|
||||
build*/
|
||||
|
@ -60,12 +54,10 @@ Documentation/Books/Users/manual.mobi
|
|||
Documentation/Books/Users/manual.pdf
|
||||
Documentation/Books/Makefile
|
||||
Documentation/Books/Users/node_modules/
|
||||
Documentation/Examples/*.generated
|
||||
Documentation/Books/ppbooks/
|
||||
Documentation/Books/allComments.txt
|
||||
|
||||
UnitTests/HttpInterface/logs/
|
||||
UnitTests/basics_suite
|
||||
UnitTests/geo_suite
|
||||
|
||||
arangod/Aql/grammar.c
|
||||
arangod/Aql/grammar.cpp
|
||||
|
@ -88,12 +80,11 @@ lib/JsonParser/json-parser.c
|
|||
lib/JsonParser/json-parser.cpp
|
||||
lib/V8/v8-json.cpp
|
||||
|
||||
cppcheck.log
|
||||
cppcheck.tmp
|
||||
|
||||
Installation/epm/arangodb.sublist
|
||||
Installation/MacOSX/Bundle/Info.plist
|
||||
|
||||
nbproject/
|
||||
.idea
|
||||
|
||||
test.cpp.txt
|
||||
|
||||
|
@ -112,7 +103,6 @@ js/apps/*
|
|||
js/apps/system/_admin/aardvark/APP/node_modules/*
|
||||
|
||||
3rdParty/etcd/src/
|
||||
Documentation/Books/allComments.txt
|
||||
|
||||
.gdb-history
|
||||
npm-debug.log
|
||||
|
|
|
@ -47,6 +47,7 @@
|
|||
"frontend/js/lib/jquery.textfill.min.js",
|
||||
"frontend/js/lib/jquery.noty.packaged.min.js",
|
||||
"frontend/js/lib/select2.min.js",
|
||||
"frontend/js/lib/typeahead.bundle.min.js",
|
||||
"frontend/js/lib/numeral.min.js",
|
||||
"frontend/js/lib/sigma.min.js",
|
||||
"frontend/js/lib/jsoneditor-min.js",
|
||||
|
|
|
@ -257,6 +257,11 @@
|
|||
window.App.notificationList.add({title:title, content: content, info: info, type: 'error'});
|
||||
},
|
||||
|
||||
hideArangoNotifications: function() {
|
||||
$.noty.clearQueue();
|
||||
$.noty.closeAll();
|
||||
},
|
||||
|
||||
openDocEditor: function (id, type, callback) {
|
||||
var ids = id.split("/"),
|
||||
self = this;
|
||||
|
|
Binary file not shown.
File diff suppressed because one or more lines are too long
Binary file not shown.
File diff suppressed because one or more lines are too long
Binary file not shown.
|
@ -2077,7 +2077,7 @@ textarea,
|
|||
height: 0;
|
||||
visibility: hidden; }
|
||||
|
||||
.script-dropdown-menu .dropdown-item, .addButton, .deleteButton, a.headerButton, a.button-gui, div.toolbox div.gv_action_button, .clusterDownBtn button, div .tile a span.icon, div .bigtile a span.icon, div .tile a svg, div .bigtile a svg, div .tile .iconSet span, div .bigtile .iconSet span, div .bigtile, .contentDiv .icon, .icon-info-sign, .arangoicon, div.headerDropdown.headerDropdown input[type=checkbox].css-checkbox label.css-label, .search-submit-icon, .gv-search-submit-icon, .scenarioImage {
|
||||
.script-dropdown-menu .dropdown-item, .addButton, .deleteButton i, a.headerButton, a.button-gui, div.toolbox div.gv_action_button, .clusterDownBtn button, div .tile a span.icon, div .bigtile a span.icon, div .tile a svg, div .bigtile a svg, div .tile .iconSet span, div .bigtile .iconSet span, div .bigtile, .contentDiv .icon, .icon-info-sign, .arangoicon, div.headerDropdown.headerDropdown input[type=checkbox].css-checkbox label.css-label, .search-submit-icon, .gv-search-submit-icon, .scenarioImage {
|
||||
cursor: pointer; }
|
||||
|
||||
.navbar, footer.footer {
|
||||
|
@ -2095,10 +2095,10 @@ textarea,
|
|||
.button-danger:focus {
|
||||
background-color: #be342e; }
|
||||
|
||||
.deleteButton, a.danger.coordinator, a.danger.dbserver {
|
||||
.deleteButton i, a.danger.coordinator, a.danger.dbserver {
|
||||
color: #da4f49; }
|
||||
.deleteButton:hover,
|
||||
a.danger.coordinator:hover, a.danger.dbserver:hover, .deleteButton:focus, a.danger.coordinator:focus, a.danger.dbserver:focus {
|
||||
.deleteButton i:hover,
|
||||
a.danger.coordinator:hover, a.danger.dbserver:hover, .deleteButton i:focus, a.danger.coordinator:focus, a.danger.dbserver:focus {
|
||||
color: #be342e; }
|
||||
|
||||
a.danger.coordinator, a.danger.dbserver {
|
||||
|
@ -2597,13 +2597,13 @@ button.disabled,
|
|||
cursor: not-allowed; }
|
||||
|
||||
.addButton {
|
||||
font-size: 22px;
|
||||
font-size: 16pt;
|
||||
margin-right: 7px;
|
||||
margin-top: 2px;
|
||||
position: relative; }
|
||||
|
||||
.deleteButton {
|
||||
font-size: 22px;
|
||||
.deleteButton i {
|
||||
font-size: 16pt;
|
||||
padding-right: 3px;
|
||||
position: relative;
|
||||
top: 3px; }
|
||||
|
|
Binary file not shown.
|
@ -10607,6 +10607,11 @@ function GraphViewer(svg, width, height, adapterConfig, config) {
|
|||
window.App.notificationList.add({title:title, content: content, info: info, type: 'error'});
|
||||
},
|
||||
|
||||
hideArangoNotifications: function() {
|
||||
$.noty.clearQueue();
|
||||
$.noty.closeAll();
|
||||
},
|
||||
|
||||
openDocEditor: function (id, type, callback) {
|
||||
var ids = id.split("/"),
|
||||
self = this;
|
||||
|
@ -25884,6 +25889,7 @@ window.ArangoUsers = Backbone.Collection.extend({
|
|||
$('.' + menuItem).addClass('active');
|
||||
}
|
||||
}
|
||||
arangoHelper.hideArangoNotifications();
|
||||
},
|
||||
|
||||
showDropdown: function (e) {
|
||||
|
@ -27625,7 +27631,7 @@ window.ArangoUsers = Backbone.Collection.extend({
|
|||
currentQuery: {},
|
||||
initDone: false,
|
||||
|
||||
bindParamRegExp: /@(@?)(\w+(\d*))/,
|
||||
bindParamRegExp: /@(@?\w+\d*)/,
|
||||
bindParamTableObj: {},
|
||||
|
||||
bindParamTableDesc: {
|
||||
|
@ -27636,7 +27642,7 @@ window.ArangoUsers = Backbone.Collection.extend({
|
|||
|
||||
myQueriesTableDesc: {
|
||||
id: "arangoMyQueriesTable",
|
||||
titles: ["Name", "Actions"],
|
||||
titles: ["Name", "Query", "Actions"],
|
||||
rows: []
|
||||
},
|
||||
|
||||
|
@ -27662,6 +27668,7 @@ window.ArangoUsers = Backbone.Collection.extend({
|
|||
"click #exportQuery": "exportCustomQueries",
|
||||
"click #importQuery": "openImportDialog",
|
||||
"click #removeResults": "removeResults",
|
||||
"click #querySpotlight": "showSpotlight",
|
||||
"click #deleteQuery": "selectAndDeleteQueryFromTable",
|
||||
"click #explQuery": "selectAndExplainQueryFromTable",
|
||||
"keyup #arangoBindParamTable input": "updateBindParams",
|
||||
|
@ -27678,6 +27685,14 @@ window.ArangoUsers = Backbone.Collection.extend({
|
|||
this.aqlEditor.setValue('');
|
||||
},
|
||||
|
||||
openExportDialog: function() {
|
||||
$('#queryImportDialog').modal('show');
|
||||
},
|
||||
|
||||
closeExportDialo: function() {
|
||||
$('#queryImportDialog').modal('hide');
|
||||
},
|
||||
|
||||
initQueryImport: function () {
|
||||
var self = this;
|
||||
self.allowUpload = false;
|
||||
|
@ -27761,7 +27776,7 @@ window.ArangoUsers = Backbone.Collection.extend({
|
|||
}
|
||||
|
||||
var divs = [
|
||||
"aqlEditor", "queryTable", "previewWrapper",
|
||||
"aqlEditor", "queryTable", "previewWrapper", "querySpotlight",
|
||||
"bindParamEditor", "toggleQueries1", "toggleQueries2",
|
||||
"saveCurrentQuery", "querySize", "executeQuery",
|
||||
"explainQuery", "clearQuery", "importQuery", "exportQuery"
|
||||
|
@ -27787,7 +27802,7 @@ window.ArangoUsers = Backbone.Collection.extend({
|
|||
name = $(e.currentTarget).children().first().text();
|
||||
}
|
||||
else if ($(e.currentTarget).is('span')) {
|
||||
name = $(e.currentTarget).parent().parent().prev().text();
|
||||
name = $(e.currentTarget).parent().parent().prev().prev().text();
|
||||
}
|
||||
return name;
|
||||
},
|
||||
|
@ -27914,8 +27929,8 @@ window.ArangoUsers = Backbone.Collection.extend({
|
|||
},
|
||||
|
||||
explainQuery: function() {
|
||||
if (this.aqlEditor.getValue().length === 0) {
|
||||
arangoHelper.arangoError("Query", "Your query is empty");
|
||||
|
||||
if (this.verifyQueryAndParams()) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -27959,6 +27974,7 @@ window.ArangoUsers = Backbone.Collection.extend({
|
|||
if (data.msg.includes('errorMessage')) {
|
||||
self.removeOutputEditor(counter);
|
||||
arangoHelper.arangoError("Explain error", data.msg);
|
||||
window.progressView.hide();
|
||||
}
|
||||
else {
|
||||
outputEditor.setValue(data.msg);
|
||||
|
@ -27969,7 +27985,6 @@ window.ArangoUsers = Backbone.Collection.extend({
|
|||
}
|
||||
},
|
||||
error: function (data) {
|
||||
window.progressView.hide();
|
||||
try {
|
||||
var temp = JSON.parse(data.responseText);
|
||||
arangoHelper.arangoError("Explain error", temp.errorMessage);
|
||||
|
@ -27977,6 +27992,7 @@ window.ArangoUsers = Backbone.Collection.extend({
|
|||
catch (e) {
|
||||
arangoHelper.arangoError("Explain error", "ERROR");
|
||||
}
|
||||
window.progressView.hide();
|
||||
self.handleResult(counter);
|
||||
this.removeOutputEditor(counter);
|
||||
}
|
||||
|
@ -27987,6 +28003,9 @@ window.ArangoUsers = Backbone.Collection.extend({
|
|||
removeOutputEditor: function(counter) {
|
||||
$('#outputEditorWrapper' + counter).hide();
|
||||
$('#outputEditorWrapper' + counter).remove();
|
||||
if ($('.outputEditorWrapper').length === 0) {
|
||||
$('#removeResults').hide();
|
||||
}
|
||||
},
|
||||
|
||||
getCachedQueryAfterRender: function() {
|
||||
|
@ -28081,6 +28100,45 @@ window.ArangoUsers = Backbone.Collection.extend({
|
|||
self.deselect(self.aqlEditor);
|
||||
},
|
||||
|
||||
showSpotlight: function() {
|
||||
var collections = [];
|
||||
window.App.arangoCollectionsStore.each(function(collection) {
|
||||
collections.push(collection.get("name"));
|
||||
});
|
||||
|
||||
var substringMatcher = function(strs) {
|
||||
return function findMatches(q, cb) {
|
||||
var matches, substrRegex;
|
||||
|
||||
matches = [];
|
||||
|
||||
substrRegex = new RegExp(q, 'i');
|
||||
|
||||
_.each(strs, function(str) {
|
||||
if (substrRegex.test(str)) {
|
||||
matches.push(str);
|
||||
}
|
||||
});
|
||||
|
||||
cb(matches);
|
||||
};
|
||||
};
|
||||
|
||||
$('#aql-spotlight .typeahead').typeahead({
|
||||
hint: true,
|
||||
highlight: true,
|
||||
minLength: 1
|
||||
},
|
||||
{
|
||||
name: 'collections',
|
||||
source: substringMatcher(collections)
|
||||
});
|
||||
},
|
||||
|
||||
initSpotlight: function() {
|
||||
|
||||
},
|
||||
|
||||
resize: function() {
|
||||
this.resizeFunction();
|
||||
},
|
||||
|
@ -28101,12 +28159,13 @@ window.ArangoUsers = Backbone.Collection.extend({
|
|||
this.queryPreview.resize();
|
||||
//fix my queries preview table resizing issues TODO
|
||||
$('#arangoMyQueriesTable thead').css('width', $('#queryTable').width());
|
||||
$('#arangoMyQueriesTable thead th').css('width', $('#queryTable').width() / 2);
|
||||
$('#arangoMyQueriesTable thead th').css('width', $('#queryTable').width() / 3);
|
||||
$('#arangoMyQueriesTable tr').css('width', $('#queryTable').width());
|
||||
$('#arangoMyQueriesTable tbody').css('height', $('#queryTable').height() - 18);
|
||||
$('#arangoMyQueriesTable tbody').css('width', $('#queryTable').width());
|
||||
$('#arangoMyQueriesTable tbody tr').css('width', $('#queryTable').width());
|
||||
$('#arangoMyQueriesTable tbody td').css('width', $('#queryTable').width() / 2);
|
||||
$('#arangoMyQueriesTable tbody td').css('width', $('#queryTable').width() / 3);
|
||||
$('#arangoMyQueriesTable tbody td .truncate').css('width', $('#queryTable').width() / 3);
|
||||
}
|
||||
},
|
||||
|
||||
|
@ -28193,6 +28252,13 @@ window.ArangoUsers = Backbone.Collection.extend({
|
|||
});
|
||||
});
|
||||
|
||||
_.each(words, function(word) {
|
||||
word = word.split(",");
|
||||
_.each(word, function(x) {
|
||||
words1.push(x);
|
||||
});
|
||||
});
|
||||
|
||||
_.each(words1, function(word) {
|
||||
// remove newlines and whitespaces
|
||||
words[pos] = word.replace(/(\r\n|\n|\r)/gm,"");
|
||||
|
@ -28203,9 +28269,10 @@ window.ArangoUsers = Backbone.Collection.extend({
|
|||
var newObject = {};
|
||||
_.each(words1, function(word) {
|
||||
//found a valid bind param expression
|
||||
if (self.bindParamRegExp.test(word)) {
|
||||
var match = word.match(self.bindParamRegExp);
|
||||
if (match) {
|
||||
//if property is not available
|
||||
word = word.substr(1, word.length);
|
||||
word = match[1];
|
||||
newObject[word] = '';
|
||||
}
|
||||
});
|
||||
|
@ -28227,7 +28294,13 @@ window.ArangoUsers = Backbone.Collection.extend({
|
|||
this.getCachedQuery();
|
||||
}
|
||||
|
||||
var counter = 0;
|
||||
var counter = 0, self = this;
|
||||
|
||||
var test = Object.keys(this.bindParamTableObj).sort(function(a,b) {
|
||||
return self.bindParamTableObj[a] - self.bindParamTableObj[b];
|
||||
});
|
||||
console.log(test);
|
||||
|
||||
_.each(this.bindParamTableObj, function(val, key) {
|
||||
$('#arangoBindParamTable tbody').append(
|
||||
"<tr>" +
|
||||
|
@ -28314,7 +28387,7 @@ window.ArangoUsers = Backbone.Collection.extend({
|
|||
|
||||
this.aqlEditor.commands.addCommand({
|
||||
name: "explainQuery",
|
||||
bindKey: {win: "Ctrl-Shift-E", mac: "Command-Shift-E", linux: "Ctrl-Shift-E"},
|
||||
bindKey: {win: "Ctrl-Shift-Return", mac: "Command-Shift-Return", linux: "Ctrl-Shift-Return"},
|
||||
exec: function() {
|
||||
self.explainQuery();
|
||||
}
|
||||
|
@ -28330,9 +28403,14 @@ window.ArangoUsers = Backbone.Collection.extend({
|
|||
},
|
||||
|
||||
updateQueryTable: function () {
|
||||
var self = this;
|
||||
this.myQueriesTableDesc.rows = this.customQueries;
|
||||
|
||||
_.each(this.myQueriesTableDesc.rows, function(k) {
|
||||
k.secondRow = '<div class="truncate">' +
|
||||
JSON.stringify(self.collection.findWhere({name: k.name}).get('value')) +
|
||||
'</div>';
|
||||
|
||||
k.thirdRow = '<span class="spanWrapper">' +
|
||||
'<span id="copyQuery" title="Copy query"><i class="fa fa-copy"></i></span>' +
|
||||
'<span id="explQuery" title="Explain query"><i class="fa fa-comments"></i></i></span>' +
|
||||
|
@ -28346,7 +28424,7 @@ window.ArangoUsers = Backbone.Collection.extend({
|
|||
});
|
||||
|
||||
// escape all columns but the third (which contains HTML)
|
||||
this.myQueriesTableDesc.unescaped = [ false, true ];
|
||||
this.myQueriesTableDesc.unescaped = [ false, true, true ];
|
||||
|
||||
this.$(this.myQueriesId).html(this.table.render({content: this.myQueriesTableDesc}));
|
||||
},
|
||||
|
@ -28489,9 +28567,31 @@ window.ArangoUsers = Backbone.Collection.extend({
|
|||
window.modalView.hide();
|
||||
},
|
||||
|
||||
executeQuery: function () {
|
||||
verifyQueryAndParams: function() {
|
||||
var quit = false;
|
||||
|
||||
if (this.aqlEditor.getValue().length === 0) {
|
||||
arangoHelper.arangoError("Query", "Your query is empty");
|
||||
quit = true;
|
||||
}
|
||||
|
||||
var keys = [];
|
||||
_.each(this.bindParamTableObj, function(val, key) {
|
||||
if (val === '') {
|
||||
quit = true;
|
||||
keys.push(key);
|
||||
}
|
||||
});
|
||||
if (keys.length > 0) {
|
||||
arangoHelper.arangoError("Bind Parameter", JSON.stringify(keys) + " not defined.");
|
||||
}
|
||||
|
||||
return quit;
|
||||
},
|
||||
|
||||
executeQuery: function () {
|
||||
|
||||
if (this.verifyQueryAndParams()) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -28572,10 +28672,9 @@ window.ArangoUsers = Backbone.Collection.extend({
|
|||
error: function (data) {
|
||||
try {
|
||||
var temp = JSON.parse(data.responseText);
|
||||
outputEditor.setValue('[' + temp.errorNum + '] ' + temp.errorMessage);
|
||||
arangoHelper.arangoError('[' + temp.errorNum + ']', temp.errorMessage);
|
||||
}
|
||||
catch (e) {
|
||||
outputEditor.setValue('ERROR');
|
||||
arangoHelper.arangoError("Query error", "ERROR");
|
||||
}
|
||||
self.handleResult(counter);
|
||||
|
@ -28700,18 +28799,19 @@ window.ArangoUsers = Backbone.Collection.extend({
|
|||
error.errorMessage.match(/'.*'/g)[0],
|
||||
error.errorMessage.match(/\d+:\d+/g)[0]
|
||||
);
|
||||
arangoHelper.arangoError("Query", error.errorMessage);
|
||||
}
|
||||
else {
|
||||
console.log(resp);
|
||||
self.markPositionError(
|
||||
error.errorMessage.match(/\(\w+\)/g)[0]
|
||||
);
|
||||
}
|
||||
arangoHelper.arangoError("Query", error.errorMessage);
|
||||
self.removeOutputEditor(counter);
|
||||
}
|
||||
}
|
||||
catch (e) {
|
||||
arangoHelper.arangoError("Query", "Something went wrong.");
|
||||
self.removeOutputEditor(counter);
|
||||
console.log(e);
|
||||
}
|
||||
|
||||
window.progressView.hide();
|
||||
|
@ -28722,16 +28822,22 @@ window.ArangoUsers = Backbone.Collection.extend({
|
|||
},
|
||||
|
||||
markPositionError: function(text, pos) {
|
||||
var row = pos.split(":")[0],
|
||||
line = pos.split(":")[1];
|
||||
text = text.substr(1, text.length - 2);
|
||||
var row;
|
||||
|
||||
this.aqlEditor.find(text);
|
||||
if (pos) {
|
||||
row = pos.split(":")[0];
|
||||
text = text.substr(1, text.length - 2);
|
||||
}
|
||||
|
||||
var found = this.aqlEditor.find(text);
|
||||
|
||||
if (!found && pos) {
|
||||
this.aqlEditor.selection.moveCursorToPosition({row: row, column: 0});
|
||||
this.aqlEditor.selection.selectLine();
|
||||
}
|
||||
window.setTimeout(function() {
|
||||
$('.ace_start').first().css('background', 'rgba(255, 129, 129, 0.7)');
|
||||
}, 100);
|
||||
|
||||
},
|
||||
|
||||
refreshAQL: function() {
|
||||
|
@ -30662,8 +30768,8 @@ window.ArangoUsers = Backbone.Collection.extend({
|
|||
"collection/:colid/documents/:pageid": "documents",
|
||||
"collection/:colid/:docid": "document",
|
||||
"shell": "shell",
|
||||
"query": "query",
|
||||
"query2": "query2",
|
||||
"query": "query2",
|
||||
"query2": "query",
|
||||
"queryManagement": "queryManagement",
|
||||
"workMonitor": "workMonitor",
|
||||
"databases": "databases",
|
||||
|
|
Binary file not shown.
File diff suppressed because one or more lines are too long
Binary file not shown.
File diff suppressed because one or more lines are too long
Binary file not shown.
File diff suppressed because one or more lines are too long
Binary file not shown.
|
@ -1,3 +1,3 @@
|
|||
<script src="sharedLibs.js?version=1456340072524"></script>
|
||||
<script src="libs.js?version=1456340072524"></script>
|
||||
<script src="app.js?version=1456340072524"></script>
|
||||
<script src="sharedLibs.js?version=1456501174653"></script>
|
||||
<script src="libs.js?version=1456501174653"></script>
|
||||
<script src="app.js?version=1456501174653"></script>
|
||||
|
|
|
@ -2498,6 +2498,7 @@ if (list.length > 0) {
|
|||
</div>
|
||||
|
||||
<div class="pull-right">
|
||||
<span id="querySpotlight"><i class="fa fa-search"></i></span>
|
||||
<div class="styled-select">
|
||||
<select id="querySize" class="query-size"/>
|
||||
</div>
|
||||
|
@ -2536,6 +2537,12 @@ if (list.length > 0) {
|
|||
<div id="outputEditors" class="outputEditors">
|
||||
</div>
|
||||
|
||||
<div class="aqlSpotlightWrapper">
|
||||
<div id="aql-spotlight">
|
||||
<input class="typeahead" type="text" placeholder="Search for Collections, AQL and more">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="queryImportDialog" class="modal hide fade in" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="false" style="display: none;">
|
||||
<div class="modal-header">
|
||||
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
|
||||
|
@ -2669,7 +2676,7 @@ var cutByResolution = function (str) {
|
|||
</td>
|
||||
<td class="docsThirdCol">
|
||||
<a class="deleteButton">
|
||||
<span class="icon_arangodb_roundminus" data-original-title="Delete document" title="Delete document"></span></a>
|
||||
<span data-original-title="Delete document" title="Delete document"><i class="fa fa-minus-circle"></i></i></span></a>
|
||||
</td>
|
||||
</tr>
|
||||
<%
|
||||
|
@ -2832,4 +2839,4 @@ var cutByResolution = function (str) {
|
|||
</div>
|
||||
|
||||
<div id="workMonitorContent" class="innerContent">
|
||||
</div></script></head><body><nav class="navbar"><div class="resizecontainer"><div class="navlogo"><a class="logo" href="#"><img class="arangodbLogo" src="img/arangodb_logo_small.png"></a></div><div id="progressPlaceholderIcon"></div><div class="statmenu" id="statisticBar"></div><div class="usermenu" id="userBar" style="float:right"></div><div class="notificationmenu" id="notificationBar" style="float:right"></div><div class="navmenu" id="navigationBar"></div></div></nav><div class="centralRow resizecontainer"><div id="content" class="centralContent"></div></div><div id="modalPlaceholder"></div><div id="progressPlaceholder" style="display:none"></div><footer class="footer"><div class="resizecontainer" id="footerBar"></div></footer><div class="arangoFrame" style=""><div class="outerDiv"><div class="innerDiv"></div></div></div><script src="sharedLibs.js?version=1456340072524"></script><script src="libs.js?version=1456340072524"></script><script src="app.js?version=1456340072524"></script></body></html>
|
||||
</div></script></head><body><nav class="navbar"><div class="resizecontainer"><div class="navlogo"><a class="logo" href="#"><img class="arangodbLogo" src="img/arangodb_logo_small.png"></a></div><div id="progressPlaceholderIcon"></div><div class="statmenu" id="statisticBar"></div><div class="usermenu" id="userBar" style="float:right"></div><div class="notificationmenu" id="notificationBar" style="float:right"></div><div class="navmenu" id="navigationBar"></div></div></nav><div class="centralRow resizecontainer"><div id="content" class="centralContent"></div></div><div id="modalPlaceholder"></div><div id="progressPlaceholder" style="display:none"></div><footer class="footer"><div class="resizecontainer" id="footerBar"></div></footer><div class="arangoFrame" style=""><div class="outerDiv"><div class="innerDiv"></div></div></div><script src="sharedLibs.js?version=1456501174653"></script><script src="libs.js?version=1456501174653"></script><script src="app.js?version=1456501174653"></script></body></html>
|
Binary file not shown.
|
@ -2690,6 +2690,7 @@ if (list.length > 0) {
|
|||
</div>
|
||||
|
||||
<div class="pull-right">
|
||||
<span id="querySpotlight"><i class="fa fa-search"></i></span>
|
||||
<div class="styled-select">
|
||||
<select id="querySize" class="query-size"/>
|
||||
</div>
|
||||
|
@ -2728,6 +2729,12 @@ if (list.length > 0) {
|
|||
<div id="outputEditors" class="outputEditors">
|
||||
</div>
|
||||
|
||||
<div class="aqlSpotlightWrapper">
|
||||
<div id="aql-spotlight">
|
||||
<input class="typeahead" type="text" placeholder="Search for Collections, AQL and more">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="queryImportDialog" class="modal hide fade in" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="false" style="display: none;">
|
||||
<div class="modal-header">
|
||||
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
|
||||
|
@ -2880,7 +2887,7 @@ var cutByResolution = function (str) {
|
|||
</td>
|
||||
<td class="docsThirdCol">
|
||||
<a class="deleteButton">
|
||||
<span class="icon_arangodb_roundminus" data-original-title="Delete document" title="Delete document"></span></a>
|
||||
<span data-original-title="Delete document" title="Delete document"><i class="fa fa-minus-circle"></i></i></span></a>
|
||||
</td>
|
||||
</tr>
|
||||
<%
|
||||
|
@ -3109,9 +3116,9 @@ var cutByResolution = function (str) {
|
|||
</div>
|
||||
</div>
|
||||
|
||||
<script src="sharedLibs.js?version=1456340072524"></script>
|
||||
<script src="libs.js?version=1456340072524"></script>
|
||||
<script src="app.js?version=1456340072524"></script>
|
||||
<script src="sharedLibs.js?version=1456501174653"></script>
|
||||
<script src="libs.js?version=1456501174653"></script>
|
||||
<script src="app.js?version=1456501174653"></script>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
|
File diff suppressed because one or more lines are too long
Binary file not shown.
|
@ -2087,7 +2087,7 @@ textarea,
|
|||
height: 0;
|
||||
visibility: hidden; }
|
||||
|
||||
.script-dropdown-menu .dropdown-item, .addButton, .deleteButton, a.headerButton, a.button-gui, div.toolbox div.gv_action_button, .clusterDownBtn button, div .tile a span.icon, div .bigtile a span.icon, div .tile a svg, div .bigtile a svg, div .tile .iconSet span, div .bigtile .iconSet span, div .bigtile, .contentDiv .icon, .icon-info-sign, .arangoicon, div.headerDropdown.headerDropdown input[type=checkbox].css-checkbox label.css-label, .search-submit-icon, .gv-search-submit-icon, .fixedDropdown .notificationItem i, .fullNotification:hover, .contentTables tr.contentRowInactive a, .arango-tab a, .arango-tab li, .pagination-line li a, .link > line, .node, .edit-index-table .icon_arangodb_roundminus {
|
||||
.script-dropdown-menu .dropdown-item, .addButton, .deleteButton i, a.headerButton, a.button-gui, div.toolbox div.gv_action_button, .clusterDownBtn button, div .tile a span.icon, div .bigtile a span.icon, div .tile a svg, div .bigtile a svg, div .tile .iconSet span, div .bigtile .iconSet span, div .bigtile, .contentDiv .icon, .icon-info-sign, .arangoicon, div.headerDropdown.headerDropdown input[type=checkbox].css-checkbox label.css-label, .search-submit-icon, .gv-search-submit-icon, .fixedDropdown .notificationItem i, .fullNotification:hover, .contentTables tr.contentRowInactive a, .arango-tab a, .arango-tab li, .pagination-line li a, .link > line, .node, .edit-index-table .icon_arangodb_roundminus {
|
||||
cursor: pointer; }
|
||||
|
||||
.navbar, footer.footer {
|
||||
|
@ -2106,12 +2106,12 @@ textarea,
|
|||
.button-danger:focus, .ajax-file-upload-red:focus {
|
||||
background-color: #be342e; }
|
||||
|
||||
.deleteButton, .contentTables td span, .edit-index-table .icon_arangodb_roundminus {
|
||||
.deleteButton i, .contentTables td span, .edit-index-table .icon_arangodb_roundminus {
|
||||
color: #da4f49; }
|
||||
.deleteButton:hover,
|
||||
.deleteButton i:hover,
|
||||
.contentTables td span:hover,
|
||||
.edit-index-table .icon_arangodb_roundminus:hover,
|
||||
.deleteButton:focus, .contentTables td span:focus, .edit-index-table .icon_arangodb_roundminus:focus {
|
||||
.deleteButton i:focus, .contentTables td span:focus, .edit-index-table .icon_arangodb_roundminus:focus {
|
||||
color: #be342e; }
|
||||
|
||||
.button-success, .ajax-file-upload {
|
||||
|
@ -2589,13 +2589,13 @@ button.disabled,
|
|||
cursor: not-allowed; }
|
||||
|
||||
.addButton {
|
||||
font-size: 22px;
|
||||
font-size: 16pt;
|
||||
margin-right: 7px;
|
||||
margin-top: 2px;
|
||||
position: relative; }
|
||||
|
||||
.deleteButton {
|
||||
font-size: 22px;
|
||||
.deleteButton i {
|
||||
font-size: 16pt;
|
||||
padding-right: 3px;
|
||||
position: relative;
|
||||
top: 3px; }
|
||||
|
@ -6817,6 +6817,13 @@ toolbar {
|
|||
.inputEditorWrapper .aqlEditorWrapper table tbody {
|
||||
display: block;
|
||||
overflow-y: auto; }
|
||||
.inputEditorWrapper .bindParamEditorWrapper table .truncate,
|
||||
.inputEditorWrapper .aqlEditorWrapper table .truncate {
|
||||
opacity: 0.8;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
width: 30%; }
|
||||
.inputEditorWrapper .bindParamEditorWrapper table tr.noBgColor,
|
||||
.inputEditorWrapper .aqlEditorWrapper table tr.noBgColor {
|
||||
background-color: transparent !important; }
|
||||
|
|
Binary file not shown.
|
@ -257,6 +257,11 @@
|
|||
window.App.notificationList.add({title:title, content: content, info: info, type: 'error'});
|
||||
},
|
||||
|
||||
hideArangoNotifications: function() {
|
||||
$.noty.clearQueue();
|
||||
$.noty.closeAll();
|
||||
},
|
||||
|
||||
openDocEditor: function (id, type, callback) {
|
||||
var ids = id.split("/"),
|
||||
self = this;
|
||||
|
|
File diff suppressed because one or more lines are too long
|
@ -15,8 +15,8 @@
|
|||
"collection/:colid/documents/:pageid": "documents",
|
||||
"collection/:colid/:docid": "document",
|
||||
"shell": "shell",
|
||||
"query": "query",
|
||||
"query2": "query2",
|
||||
"query": "query2",
|
||||
"query2": "query",
|
||||
"queryManagement": "queryManagement",
|
||||
"workMonitor": "workMonitor",
|
||||
"databases": "databases",
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
</div>
|
||||
|
||||
<div class="pull-right">
|
||||
<span id="querySpotlight"><i class="fa fa-search"></i></span>
|
||||
<div class="styled-select">
|
||||
<select id="querySize" class="query-size"/>
|
||||
</div>
|
||||
|
@ -53,6 +54,12 @@
|
|||
<div id="outputEditors" class="outputEditors">
|
||||
</div>
|
||||
|
||||
<div class="aqlSpotlightWrapper">
|
||||
<div id="aql-spotlight">
|
||||
<input class="typeahead" type="text" placeholder="Search for Collections, AQL and more">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="queryImportDialog" class="modal hide fade in" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="false" style="display: none;">
|
||||
<div class="modal-header">
|
||||
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
|
||||
|
|
|
@ -48,7 +48,7 @@ var cutByResolution = function (str) {
|
|||
</td>
|
||||
<td class="docsThirdCol">
|
||||
<a class="deleteButton">
|
||||
<span class="icon_arangodb_roundminus" data-original-title="Delete document" title="Delete document"></span></a>
|
||||
<span data-original-title="Delete document" title="Delete document"><i class="fa fa-minus-circle"></i></i></span></a>
|
||||
</td>
|
||||
</tr>
|
||||
<%
|
||||
|
|
|
@ -143,6 +143,7 @@
|
|||
$('.' + menuItem).addClass('active');
|
||||
}
|
||||
}
|
||||
arangoHelper.hideArangoNotifications();
|
||||
},
|
||||
|
||||
showDropdown: function (e) {
|
||||
|
|
|
@ -24,7 +24,7 @@
|
|||
currentQuery: {},
|
||||
initDone: false,
|
||||
|
||||
bindParamRegExp: /@(@?)(\w+(\d*))/,
|
||||
bindParamRegExp: /@(@?\w+\d*)/,
|
||||
bindParamTableObj: {},
|
||||
|
||||
bindParamTableDesc: {
|
||||
|
@ -35,7 +35,7 @@
|
|||
|
||||
myQueriesTableDesc: {
|
||||
id: "arangoMyQueriesTable",
|
||||
titles: ["Name", "Actions"],
|
||||
titles: ["Name", "Query", "Actions"],
|
||||
rows: []
|
||||
},
|
||||
|
||||
|
@ -61,6 +61,7 @@
|
|||
"click #exportQuery": "exportCustomQueries",
|
||||
"click #importQuery": "openImportDialog",
|
||||
"click #removeResults": "removeResults",
|
||||
"click #querySpotlight": "showSpotlight",
|
||||
"click #deleteQuery": "selectAndDeleteQueryFromTable",
|
||||
"click #explQuery": "selectAndExplainQueryFromTable",
|
||||
"keyup #arangoBindParamTable input": "updateBindParams",
|
||||
|
@ -77,6 +78,14 @@
|
|||
this.aqlEditor.setValue('');
|
||||
},
|
||||
|
||||
openExportDialog: function() {
|
||||
$('#queryImportDialog').modal('show');
|
||||
},
|
||||
|
||||
closeExportDialo: function() {
|
||||
$('#queryImportDialog').modal('hide');
|
||||
},
|
||||
|
||||
initQueryImport: function () {
|
||||
var self = this;
|
||||
self.allowUpload = false;
|
||||
|
@ -160,7 +169,7 @@
|
|||
}
|
||||
|
||||
var divs = [
|
||||
"aqlEditor", "queryTable", "previewWrapper",
|
||||
"aqlEditor", "queryTable", "previewWrapper", "querySpotlight",
|
||||
"bindParamEditor", "toggleQueries1", "toggleQueries2",
|
||||
"saveCurrentQuery", "querySize", "executeQuery",
|
||||
"explainQuery", "clearQuery", "importQuery", "exportQuery"
|
||||
|
@ -186,7 +195,7 @@
|
|||
name = $(e.currentTarget).children().first().text();
|
||||
}
|
||||
else if ($(e.currentTarget).is('span')) {
|
||||
name = $(e.currentTarget).parent().parent().prev().text();
|
||||
name = $(e.currentTarget).parent().parent().prev().prev().text();
|
||||
}
|
||||
return name;
|
||||
},
|
||||
|
@ -313,8 +322,8 @@
|
|||
},
|
||||
|
||||
explainQuery: function() {
|
||||
if (this.aqlEditor.getValue().length === 0) {
|
||||
arangoHelper.arangoError("Query", "Your query is empty");
|
||||
|
||||
if (this.verifyQueryAndParams()) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -358,6 +367,7 @@
|
|||
if (data.msg.includes('errorMessage')) {
|
||||
self.removeOutputEditor(counter);
|
||||
arangoHelper.arangoError("Explain error", data.msg);
|
||||
window.progressView.hide();
|
||||
}
|
||||
else {
|
||||
outputEditor.setValue(data.msg);
|
||||
|
@ -368,7 +378,6 @@
|
|||
}
|
||||
},
|
||||
error: function (data) {
|
||||
window.progressView.hide();
|
||||
try {
|
||||
var temp = JSON.parse(data.responseText);
|
||||
arangoHelper.arangoError("Explain error", temp.errorMessage);
|
||||
|
@ -376,6 +385,7 @@
|
|||
catch (e) {
|
||||
arangoHelper.arangoError("Explain error", "ERROR");
|
||||
}
|
||||
window.progressView.hide();
|
||||
self.handleResult(counter);
|
||||
this.removeOutputEditor(counter);
|
||||
}
|
||||
|
@ -386,6 +396,9 @@
|
|||
removeOutputEditor: function(counter) {
|
||||
$('#outputEditorWrapper' + counter).hide();
|
||||
$('#outputEditorWrapper' + counter).remove();
|
||||
if ($('.outputEditorWrapper').length === 0) {
|
||||
$('#removeResults').hide();
|
||||
}
|
||||
},
|
||||
|
||||
getCachedQueryAfterRender: function() {
|
||||
|
@ -480,6 +493,45 @@
|
|||
self.deselect(self.aqlEditor);
|
||||
},
|
||||
|
||||
showSpotlight: function() {
|
||||
var collections = [];
|
||||
window.App.arangoCollectionsStore.each(function(collection) {
|
||||
collections.push(collection.get("name"));
|
||||
});
|
||||
|
||||
var substringMatcher = function(strs) {
|
||||
return function findMatches(q, cb) {
|
||||
var matches, substrRegex;
|
||||
|
||||
matches = [];
|
||||
|
||||
substrRegex = new RegExp(q, 'i');
|
||||
|
||||
_.each(strs, function(str) {
|
||||
if (substrRegex.test(str)) {
|
||||
matches.push(str);
|
||||
}
|
||||
});
|
||||
|
||||
cb(matches);
|
||||
};
|
||||
};
|
||||
|
||||
$('#aql-spotlight .typeahead').typeahead({
|
||||
hint: true,
|
||||
highlight: true,
|
||||
minLength: 1
|
||||
},
|
||||
{
|
||||
name: 'collections',
|
||||
source: substringMatcher(collections)
|
||||
});
|
||||
},
|
||||
|
||||
initSpotlight: function() {
|
||||
|
||||
},
|
||||
|
||||
resize: function() {
|
||||
this.resizeFunction();
|
||||
},
|
||||
|
@ -500,12 +552,13 @@
|
|||
this.queryPreview.resize();
|
||||
//fix my queries preview table resizing issues TODO
|
||||
$('#arangoMyQueriesTable thead').css('width', $('#queryTable').width());
|
||||
$('#arangoMyQueriesTable thead th').css('width', $('#queryTable').width() / 2);
|
||||
$('#arangoMyQueriesTable thead th').css('width', $('#queryTable').width() / 3);
|
||||
$('#arangoMyQueriesTable tr').css('width', $('#queryTable').width());
|
||||
$('#arangoMyQueriesTable tbody').css('height', $('#queryTable').height() - 18);
|
||||
$('#arangoMyQueriesTable tbody').css('width', $('#queryTable').width());
|
||||
$('#arangoMyQueriesTable tbody tr').css('width', $('#queryTable').width());
|
||||
$('#arangoMyQueriesTable tbody td').css('width', $('#queryTable').width() / 2);
|
||||
$('#arangoMyQueriesTable tbody td').css('width', $('#queryTable').width() / 3);
|
||||
$('#arangoMyQueriesTable tbody td .truncate').css('width', $('#queryTable').width() / 3);
|
||||
}
|
||||
},
|
||||
|
||||
|
@ -592,6 +645,13 @@
|
|||
});
|
||||
});
|
||||
|
||||
_.each(words, function(word) {
|
||||
word = word.split(",");
|
||||
_.each(word, function(x) {
|
||||
words1.push(x);
|
||||
});
|
||||
});
|
||||
|
||||
_.each(words1, function(word) {
|
||||
// remove newlines and whitespaces
|
||||
words[pos] = word.replace(/(\r\n|\n|\r)/gm,"");
|
||||
|
@ -602,9 +662,10 @@
|
|||
var newObject = {};
|
||||
_.each(words1, function(word) {
|
||||
//found a valid bind param expression
|
||||
if (self.bindParamRegExp.test(word)) {
|
||||
var match = word.match(self.bindParamRegExp);
|
||||
if (match) {
|
||||
//if property is not available
|
||||
word = word.substr(1, word.length);
|
||||
word = match[1];
|
||||
newObject[word] = '';
|
||||
}
|
||||
});
|
||||
|
@ -626,7 +687,13 @@
|
|||
this.getCachedQuery();
|
||||
}
|
||||
|
||||
var counter = 0;
|
||||
var counter = 0, self = this;
|
||||
|
||||
var test = Object.keys(this.bindParamTableObj).sort(function(a,b) {
|
||||
return self.bindParamTableObj[a] - self.bindParamTableObj[b];
|
||||
});
|
||||
console.log(test);
|
||||
|
||||
_.each(this.bindParamTableObj, function(val, key) {
|
||||
$('#arangoBindParamTable tbody').append(
|
||||
"<tr>" +
|
||||
|
@ -713,7 +780,7 @@
|
|||
|
||||
this.aqlEditor.commands.addCommand({
|
||||
name: "explainQuery",
|
||||
bindKey: {win: "Ctrl-Shift-E", mac: "Command-Shift-E", linux: "Ctrl-Shift-E"},
|
||||
bindKey: {win: "Ctrl-Shift-Return", mac: "Command-Shift-Return", linux: "Ctrl-Shift-Return"},
|
||||
exec: function() {
|
||||
self.explainQuery();
|
||||
}
|
||||
|
@ -729,9 +796,14 @@
|
|||
},
|
||||
|
||||
updateQueryTable: function () {
|
||||
var self = this;
|
||||
this.myQueriesTableDesc.rows = this.customQueries;
|
||||
|
||||
_.each(this.myQueriesTableDesc.rows, function(k) {
|
||||
k.secondRow = '<div class="truncate">' +
|
||||
JSON.stringify(self.collection.findWhere({name: k.name}).get('value')) +
|
||||
'</div>';
|
||||
|
||||
k.thirdRow = '<span class="spanWrapper">' +
|
||||
'<span id="copyQuery" title="Copy query"><i class="fa fa-copy"></i></span>' +
|
||||
'<span id="explQuery" title="Explain query"><i class="fa fa-comments"></i></i></span>' +
|
||||
|
@ -745,7 +817,7 @@
|
|||
});
|
||||
|
||||
// escape all columns but the third (which contains HTML)
|
||||
this.myQueriesTableDesc.unescaped = [ false, true ];
|
||||
this.myQueriesTableDesc.unescaped = [ false, true, true ];
|
||||
|
||||
this.$(this.myQueriesId).html(this.table.render({content: this.myQueriesTableDesc}));
|
||||
},
|
||||
|
@ -888,9 +960,31 @@
|
|||
window.modalView.hide();
|
||||
},
|
||||
|
||||
executeQuery: function () {
|
||||
verifyQueryAndParams: function() {
|
||||
var quit = false;
|
||||
|
||||
if (this.aqlEditor.getValue().length === 0) {
|
||||
arangoHelper.arangoError("Query", "Your query is empty");
|
||||
quit = true;
|
||||
}
|
||||
|
||||
var keys = [];
|
||||
_.each(this.bindParamTableObj, function(val, key) {
|
||||
if (val === '') {
|
||||
quit = true;
|
||||
keys.push(key);
|
||||
}
|
||||
});
|
||||
if (keys.length > 0) {
|
||||
arangoHelper.arangoError("Bind Parameter", JSON.stringify(keys) + " not defined.");
|
||||
}
|
||||
|
||||
return quit;
|
||||
},
|
||||
|
||||
executeQuery: function () {
|
||||
|
||||
if (this.verifyQueryAndParams()) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -971,10 +1065,9 @@
|
|||
error: function (data) {
|
||||
try {
|
||||
var temp = JSON.parse(data.responseText);
|
||||
outputEditor.setValue('[' + temp.errorNum + '] ' + temp.errorMessage);
|
||||
arangoHelper.arangoError('[' + temp.errorNum + ']', temp.errorMessage);
|
||||
}
|
||||
catch (e) {
|
||||
outputEditor.setValue('ERROR');
|
||||
arangoHelper.arangoError("Query error", "ERROR");
|
||||
}
|
||||
self.handleResult(counter);
|
||||
|
@ -1099,18 +1192,19 @@
|
|||
error.errorMessage.match(/'.*'/g)[0],
|
||||
error.errorMessage.match(/\d+:\d+/g)[0]
|
||||
);
|
||||
arangoHelper.arangoError("Query", error.errorMessage);
|
||||
}
|
||||
else {
|
||||
console.log(resp);
|
||||
self.markPositionError(
|
||||
error.errorMessage.match(/\(\w+\)/g)[0]
|
||||
);
|
||||
}
|
||||
arangoHelper.arangoError("Query", error.errorMessage);
|
||||
self.removeOutputEditor(counter);
|
||||
}
|
||||
}
|
||||
catch (e) {
|
||||
arangoHelper.arangoError("Query", "Something went wrong.");
|
||||
self.removeOutputEditor(counter);
|
||||
console.log(e);
|
||||
}
|
||||
|
||||
window.progressView.hide();
|
||||
|
@ -1121,16 +1215,22 @@
|
|||
},
|
||||
|
||||
markPositionError: function(text, pos) {
|
||||
var row = pos.split(":")[0],
|
||||
line = pos.split(":")[1];
|
||||
text = text.substr(1, text.length - 2);
|
||||
var row;
|
||||
|
||||
this.aqlEditor.find(text);
|
||||
if (pos) {
|
||||
row = pos.split(":")[0];
|
||||
text = text.substr(1, text.length - 2);
|
||||
}
|
||||
|
||||
var found = this.aqlEditor.find(text);
|
||||
|
||||
if (!found && pos) {
|
||||
this.aqlEditor.selection.moveCursorToPosition({row: row, column: 0});
|
||||
this.aqlEditor.selection.selectLine();
|
||||
}
|
||||
window.setTimeout(function() {
|
||||
$('.ace_start').first().css('background', 'rgba(255, 129, 129, 0.7)');
|
||||
}, 100);
|
||||
|
||||
},
|
||||
|
||||
refreshAQL: function() {
|
||||
|
|
|
@ -79,19 +79,22 @@ button.disabled,
|
|||
.addButton {
|
||||
@extend %clickable;
|
||||
@extend %icon-positive;
|
||||
font-size: 22px;
|
||||
font-size: 16pt;
|
||||
margin-right: 7px;
|
||||
margin-top: 2px;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.deleteButton {
|
||||
@extend %clickable;
|
||||
@extend %icon-negative;
|
||||
font-size: 22px;
|
||||
padding-right: 3px;
|
||||
position: relative;
|
||||
top: 3px;
|
||||
|
||||
i {
|
||||
@extend %clickable;
|
||||
@extend %icon-negative;
|
||||
font-size: 16pt;
|
||||
padding-right: 3px;
|
||||
position: relative;
|
||||
top: 3px;
|
||||
}
|
||||
}
|
||||
|
||||
#closeBtnInfoView {
|
||||
|
|
|
@ -58,6 +58,14 @@
|
|||
overflow-y: auto;
|
||||
}
|
||||
|
||||
.truncate {
|
||||
opacity: 0.8;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
width: 30%;
|
||||
}
|
||||
|
||||
tr {
|
||||
&.noBgColor {
|
||||
background-color: rgba(0, 0, 0, 0) !important;
|
||||
|
|
|
@ -27,6 +27,7 @@
|
|||
|
||||
const functionsDocumentation = {
|
||||
"all": "run all tests (marked with [x])",
|
||||
"agency": "run agency tests",
|
||||
"arangob": "arangob tests",
|
||||
"arangosh": "arangosh exit codes tests",
|
||||
"authentication": "authentication tests",
|
||||
|
@ -91,6 +92,8 @@ const optionsDocumentation = [
|
|||
' - `cluster`: if set to true the tests are run with the coordinator',
|
||||
' of a small local cluster',
|
||||
' - `clusterNodes`: number of DB-Servers to use',
|
||||
' - `agency`: if set to true agency tests are done',
|
||||
' - `agencySize`: number of agents in agency',
|
||||
' - `test`: path to single test to execute for "single" test target',
|
||||
' - `cleanup`: if set to true (the default), the cluster data files',
|
||||
' and logs are removed after termination of the test.',
|
||||
|
@ -495,6 +498,68 @@ function checkInstanceAliveSingleServer(instanceInfo, options) {
|
|||
return ret;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief checks if an agency instance is still alive
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
function checkInstanceAliveAgency(instanceInfo, options) {
|
||||
if (instanceInfo.hasOwnProperty('exitStatus')) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (let i = 0; i < options.agencySize; i++) {
|
||||
const res = statusExternal(instanceInfo.pids[i], false);
|
||||
const ret = res.status === "RUNNING";
|
||||
|
||||
if (!ret) {
|
||||
print("ArangoD with PID " + instanceInfo.pids[i].pid + " gone:");
|
||||
print(instanceInfo);
|
||||
|
||||
if (res.hasOwnProperty('signal') &&
|
||||
((res.signal === 11) ||
|
||||
(res.signal === 6) ||
|
||||
// Windows sometimes has random numbers in signal...
|
||||
(require("internal").platform.substr(0, 3) === 'win')
|
||||
)
|
||||
) {
|
||||
const storeArangodPath = "/var/tmp/arangod_" + instanceInfo.pids[i].pid;
|
||||
|
||||
print("Core dump written; copying arangod to " +
|
||||
instanceInfo.tmpDataDir + " for later analysis.");
|
||||
|
||||
let corePath = (options.coreDirectory === "") ?
|
||||
"core" :
|
||||
options.coreDirectory + "/core*" + instanceInfo.pids[i].pid + "*'";
|
||||
|
||||
res.gdbHint = "Run debugger with 'gdb " +
|
||||
storeArangodPath + " " + corePath;
|
||||
|
||||
if (require("internal").platform.substr(0, 3) === 'win') {
|
||||
// Windows: wait for procdump to do its job...
|
||||
statusExternal(instanceInfo.monitor, true);
|
||||
analyzeCoreDumpWindows(instanceInfo);
|
||||
} else {
|
||||
fs.copyFile("bin/arangod", storeArangodPath);
|
||||
analyzeCoreDump(instanceInfo, options, storeArangodPath, instanceInfo.pids[i].pid);
|
||||
}
|
||||
}
|
||||
|
||||
if (instanceInfo.exitStatus === undefined) {
|
||||
instanceInfo.exitStatus = [];
|
||||
}
|
||||
instanceInfo.exitStatus[i] = res;
|
||||
}
|
||||
}
|
||||
|
||||
if (instanceInfo.exitStatus !== undefined) {
|
||||
print("marking crashy");
|
||||
serverCrashed = true;
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
function checkRemoteInstance(pid, wait, options) {
|
||||
const debug = options.debug || false;
|
||||
const p = JSON.stringify(pid);
|
||||
|
@ -556,11 +621,14 @@ function checkInstanceAliveCluster(instanceInfo, options) {
|
|||
}
|
||||
|
||||
function checkInstanceAlive(instanceInfo, options) {
|
||||
if (options.cluster === false) {
|
||||
return checkInstanceAliveSingleServer(instanceInfo, options);
|
||||
if (options.cluster) {
|
||||
return checkInstanceAliveCluster(instanceInfo, options);
|
||||
}
|
||||
if (options.agency) {
|
||||
return checkInstanceAliveAgency(instanceInfo, options);
|
||||
}
|
||||
return checkInstanceAliveSingleServer(instanceInfo, options);
|
||||
|
||||
return checkInstanceAliveCluster(instanceInfo, options);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -972,7 +1040,12 @@ function executeAndWait(cmd, args) {
|
|||
|
||||
function runInArangosh(options, instanceInfo, file, addArgs) {
|
||||
let args = makeArgsArangosh(options);
|
||||
args["server.endpoint"] = instanceInfo.endpoint;
|
||||
if (instanceInfo.endpoint !== undefined) {
|
||||
args["server.endpoint"] = instanceInfo.endpoint;
|
||||
}
|
||||
if (instanceInfo.urls !== undefined) {
|
||||
args["flatCommands"] = instanceInfo.urls;
|
||||
}
|
||||
args["javascript.unit-tests"] = fs.join(TOP_DIR, file);
|
||||
|
||||
if (addArgs !== undefined) {
|
||||
|
@ -1141,6 +1214,87 @@ function shutdownInstance(instanceInfo, options) {
|
|||
killExternal(instanceInfo.dispatcherPid);
|
||||
}
|
||||
|
||||
// agency mode
|
||||
else if (options.agency) {
|
||||
if (instanceInfo.exitStatus === undefined) {
|
||||
instanceInfo.exitStatus = [];
|
||||
}
|
||||
for (let i = 0; i < options.agencySize; i++) {
|
||||
if (instanceInfo.exitStatus[i] === undefined) {
|
||||
download(instanceInfo.urls[i] + "/_admin/shutdown", "",
|
||||
makeAuthorizationHeaders(options));
|
||||
|
||||
print("Waiting for server shut down");
|
||||
|
||||
let count = 0;
|
||||
let bar = "[";
|
||||
|
||||
let timeout = 600;
|
||||
|
||||
if (options.sanitizer) {
|
||||
timeout *= 2;
|
||||
}
|
||||
|
||||
if (instanceInfo.exitStatus === undefined) {
|
||||
instanceInfo.exitStatus = [];
|
||||
}
|
||||
while (true) {
|
||||
instanceInfo.exitStatus[i] = statusExternal(instanceInfo.pids[i], false);
|
||||
|
||||
if (instanceInfo.exitStatus[i].status === "RUNNING") {
|
||||
++count;
|
||||
|
||||
if (options.valgrind) {
|
||||
wait(1);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (count % 10 === 0) {
|
||||
bar = bar + "#";
|
||||
}
|
||||
|
||||
if (count > 600) {
|
||||
print("forcefully terminating " + yaml.safeDump(instanceInfo.pids[i]) +
|
||||
" after " + timeout + "s grace period; marking crashy.");
|
||||
serverCrashed = true;
|
||||
killExternal(instanceInfo.pids[i]);
|
||||
break;
|
||||
} else {
|
||||
wait(1);
|
||||
}
|
||||
} else if (instanceInfo.exitStatus[i].status !== "TERMINATED") {
|
||||
if (instanceInfo.exitStatus[i].hasOwnProperty('signal')) {
|
||||
print("Server shut down with : " +
|
||||
yaml.safeDump(instanceInfo.exitStatus[i]) +
|
||||
" marking build as crashy.");
|
||||
|
||||
serverCrashed = true;
|
||||
break;
|
||||
}
|
||||
if (require("internal").platform.substr(0, 3) === 'win') {
|
||||
// Windows: wait for procdump to do its job...
|
||||
statusExternal(instanceInfo.monitor, true);
|
||||
}
|
||||
} else {
|
||||
print("Server shutdown: Success.");
|
||||
break; // Success.
|
||||
}
|
||||
}
|
||||
|
||||
if (count > 10) {
|
||||
print("long Server shutdown: " + bar + ']');
|
||||
}
|
||||
} else {
|
||||
print("Server already dead, doing nothing.");
|
||||
}
|
||||
|
||||
if (!options.skipLogAnalysis) {
|
||||
instanceInfo.importantLogLines =
|
||||
readImportantLogLines(instanceInfo.tmpDataDir);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// single server
|
||||
else {
|
||||
if (typeof(instanceInfo.exitStatus) === 'undefined') {
|
||||
|
@ -1397,6 +1551,72 @@ function valgrindArgsSingleServer(options, testname, run) {
|
|||
return toArgv(valgrindOpts, true).concat([run]);
|
||||
}
|
||||
|
||||
function startInstanceAgency(instanceInfo, protocol, options,
|
||||
addArgs, testname, appDir, tmpDataDir) {
|
||||
const N = options.agencySize;
|
||||
const ports = [];
|
||||
for (let i = 0; i < N; i++) {
|
||||
ports.push(findFreePort());
|
||||
}
|
||||
instanceInfo.ports = ports;
|
||||
|
||||
const endpoints = ports.map(function(port) {
|
||||
return protocol + "://127.0.0.1:" + port;
|
||||
});
|
||||
instanceInfo.endpoints = endpoints;
|
||||
|
||||
let td = ports.map(function(port) {
|
||||
return fs.join(tmpDataDir, "data" + port);
|
||||
});
|
||||
for (let i = 0; i < N; i++) {
|
||||
fs.makeDirectoryRecursive(td[i]);
|
||||
}
|
||||
|
||||
let argss = [];
|
||||
for (let i = 0; i < N; i++) {
|
||||
let args = makeArgsArangod(options, appDir);
|
||||
args["server.endpoint"] = endpoints[i];
|
||||
args["database.directory"] = td[i];
|
||||
args["log.file"] = fs.join(tmpDataDir, "log" + ports[i]);
|
||||
//args["agency.id"] = String(i);
|
||||
//args["agency.size"] = String(N);
|
||||
|
||||
if (protocol === "ssl") {
|
||||
args["server.keyfile"] = fs.join("UnitTests", "server.pem");
|
||||
}
|
||||
|
||||
args = _.extend(args, options.extraArgs);
|
||||
|
||||
if (addArgs !== undefined) {
|
||||
args = _.extend(args, addArgs);
|
||||
}
|
||||
|
||||
if (i === N-1) {
|
||||
let l = [];
|
||||
for (let j = 0; j < N; j++) {
|
||||
l.push("--agency.endpoint");
|
||||
l.push(endpoints[j]);
|
||||
}
|
||||
//args["flatCommands"] = l;
|
||||
}
|
||||
argss.push(args);
|
||||
}
|
||||
|
||||
instanceInfo.pids = [];
|
||||
for (let i = 0; i < N; i++) {
|
||||
if (options.valgrind) {
|
||||
const valgrindArgs = valgrindArgsSingleServer(options, testname, ARANGOD_BIN);
|
||||
const newargs = valgrindArgs.concat(toArgv(argss[i]));
|
||||
|
||||
instanceInfo.pids[i] = executeExternal(options.valgrind, newargs);
|
||||
} else {
|
||||
instanceInfo.pids[i] = executeExternal(ARANGOD_BIN, toArgv(argss[i]));
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
function startInstanceSingleServer(instanceInfo, protocol, options,
|
||||
addArgs, testname, appDir, tmpDataDir) {
|
||||
const port = findFreePort();
|
||||
|
@ -1458,6 +1678,12 @@ function startInstance(protocol, options, addArgs, testname, tmpDir) {
|
|||
addArgs, testname, appDir, tmpDataDir);
|
||||
}
|
||||
|
||||
// agency testing mode
|
||||
else if (options.agency) {
|
||||
res = startInstanceAgency(instanceInfo, protocol, options,
|
||||
addArgs, testname, appDir, tmpDataDir);
|
||||
}
|
||||
|
||||
// single instance mode
|
||||
else {
|
||||
res = startInstanceSingleServer(instanceInfo, protocol, options,
|
||||
|
@ -1471,8 +1697,15 @@ function startInstance(protocol, options, addArgs, testname, tmpDir) {
|
|||
// wait until the server/coordinator is up:
|
||||
let count = 0;
|
||||
|
||||
const url = endpointToURL(instanceInfo.endpoint);
|
||||
instanceInfo.url = url;
|
||||
let url;
|
||||
if (instanceInfo.endpoint !== undefined) {
|
||||
url = endpointToURL(instanceInfo.endpoint);
|
||||
instanceInfo.url = url;
|
||||
} else {
|
||||
instanceInfo.urls = instanceInfo.endpoints.map(endpointToURL);
|
||||
url = instanceInfo.urls[0];
|
||||
instanceInfo.url = url;
|
||||
}
|
||||
|
||||
while (true) {
|
||||
wait(0.5, false);
|
||||
|
@ -1755,6 +1988,14 @@ function findTests() {
|
|||
return fs.join(makePathUnix("js/common/tests/replication"), x);
|
||||
}).sort();
|
||||
|
||||
testsCases.agency = _.filter(fs.list(makePathUnix("js/client/tests/agency")),
|
||||
function(p) {
|
||||
return p.substr(-3) === ".js";
|
||||
}).map(
|
||||
function(x) {
|
||||
return fs.join(makePathUnix("js/client/tests/agency"), x);
|
||||
}).sort();
|
||||
|
||||
testsCases.server = testsCases.common.concat(testsCases.server_only);
|
||||
testsCases.client = testsCases.common.concat(testsCases.client_only);
|
||||
|
||||
|
@ -3647,6 +3888,86 @@ testFuncs.stress_locks = function(options) {
|
|||
return runStressTest(options, command, "stress_lock");
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief agency tests
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
testFuncs.agency = function(options) {
|
||||
findTests();
|
||||
|
||||
options.agency = true;
|
||||
options.cluster = false;
|
||||
if (options.agencySize === undefined) {
|
||||
options.agencySize = 3;
|
||||
}
|
||||
|
||||
let instanceInfo = startInstance("tcp", options, {}, "agency");
|
||||
|
||||
if (instanceInfo === false) {
|
||||
return {
|
||||
shell_client: {
|
||||
status: false,
|
||||
message: "failed to start agency!"
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
let results = {};
|
||||
let filtered = {};
|
||||
let continueTesting = true;
|
||||
|
||||
for (let i = 0; i < testsCases.agency.length; i++) {
|
||||
const te = testsCases.agency[i];
|
||||
|
||||
if (filterTestcaseByOptions(te, options, filtered)) {
|
||||
if (!continueTesting) {
|
||||
print("Skipping, " + te + " server is gone.");
|
||||
|
||||
results[te] = {
|
||||
status: false,
|
||||
message: instanceInfo.exitStatus
|
||||
};
|
||||
|
||||
instanceInfo.exitStatus = "server is gone.";
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
print("\narangosh: Trying", te, "...");
|
||||
|
||||
const reply = runInArangosh(options, instanceInfo, te);
|
||||
results[te] = reply;
|
||||
|
||||
if (reply.status !== true) {
|
||||
options.cleanup = false;
|
||||
|
||||
if (!options.force) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
continueTesting = checkInstanceAlive(instanceInfo, options);
|
||||
} else {
|
||||
if (options.extremeVerbosity) {
|
||||
print("Skipped " + te + " because of " + filtered.filter);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
print("Shutting down...");
|
||||
shutdownInstance(instanceInfo, options);
|
||||
print("done.");
|
||||
|
||||
if ((!options.skipLogAnalysis) &&
|
||||
instanceInfo.hasOwnProperty('importantLogLines') &&
|
||||
Object.keys(instanceInfo.importantLogLines).length > 0) {
|
||||
print("Found messages in the server logs: \n" +
|
||||
yaml.safeDump(instanceInfo.importantLogLines));
|
||||
}
|
||||
|
||||
return results;
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief pretty prints the result
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
|
|
@ -1,9 +1,12 @@
|
|||
Conventions for testing framework:
|
||||
==================================
|
||||
|
||||
All files in the directory "shell" and ends with ".js" automatically
|
||||
All files in the directory "shell" that end with ".js" automatically
|
||||
take part in client shell tests (target "shell_client").
|
||||
|
||||
All files in the directory "agency" that end with ".js" automatically
|
||||
take part in agency tests (target "agency").
|
||||
|
||||
If the filename contains the string "-cluster", then it is only
|
||||
executed when testing in cluster mode. If the filename contains the
|
||||
string "-noncluster", then it is only executed when testing in single
|
||||
|
|
|
@ -0,0 +1,86 @@
|
|||
/*jshint globalstrict:false, strict:false */
|
||||
/*global assertEqual, assertNotEqual,
|
||||
print, print_plain, COMPARE_STRING, NORMALIZE_STRING,
|
||||
help, start_pager, stop_pager, start_pretty_print, stop_pretty_print, start_color_print, stop_color_print */
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief tests for client-specific functionality
|
||||
///
|
||||
/// @file
|
||||
///
|
||||
/// DISCLAIMER
|
||||
///
|
||||
/// Copyright 2010-2012 triagens GmbH, Cologne, Germany
|
||||
///
|
||||
/// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
/// you may not use this file except in compliance with the License.
|
||||
/// You may obtain a copy of the License at
|
||||
///
|
||||
/// http://www.apache.org/licenses/LICENSE-2.0
|
||||
///
|
||||
/// Unless required by applicable law or agreed to in writing, software
|
||||
/// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
/// See the License for the specific language governing permissions and
|
||||
/// limitations under the License.
|
||||
///
|
||||
/// Copyright holder is triAGENS GmbH, Cologne, Germany
|
||||
///
|
||||
/// @author Max Neunhoeffer
|
||||
/// @author Copyright 2012, triAGENS GmbH, Cologne, Germany
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
var jsunity = require("jsunity");
|
||||
var db = require("@arangodb").db;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief test suite
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
function agencyTestSuite () {
|
||||
'use strict';
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief the agency servers
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
var agencyServers = ARGUMENTS;
|
||||
|
||||
return {
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief set up
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
setUp : function () {
|
||||
},
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief tear down
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
tearDown : function () {
|
||||
},
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief test global help function
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
testWait : function () {
|
||||
require("internal").print("Hallo1", agencyServers);
|
||||
require("internal").wait(5);
|
||||
require("internal").print("Hallo1");
|
||||
}
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief executes the test suite
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
jsunity.run(agencyTestSuite);
|
||||
|
||||
return jsunity.done();
|
||||
|
|
@ -63,6 +63,7 @@ delete global.DEFINE_MODULE;
|
|||
const LOADING = [];
|
||||
|
||||
const GLOBAL_PATHS = [];
|
||||
const ROOT_PATH = fs.normalize(fs.makeAbsolute(internal.startupPath));
|
||||
global.MODULES_PATH.forEach(function (p) {
|
||||
p = fs.normalize(fs.makeAbsolute(p));
|
||||
GLOBAL_PATHS.push(p);
|
||||
|
@ -302,6 +303,10 @@ Module._nodeModulePaths = function(from, root) {
|
|||
var paths = [];
|
||||
var parts = from.split(splitRe);
|
||||
var inRoot = root && from.indexOf(root) === 0;
|
||||
if (!inRoot) {
|
||||
root = ROOT_PATH;
|
||||
inRoot = from.indexOf(root) === 0;
|
||||
}
|
||||
|
||||
for (var tip = parts.length - 1; tip >= 0; tip--) {
|
||||
// don't search in .../node_modules/node_modules
|
||||
|
|
|
@ -24,11 +24,13 @@
|
|||
#define ARANGODB_PROGRAM_OPTIONS_OPTION_H 1
|
||||
|
||||
#include "Basics/Common.h"
|
||||
#include "ProgramOptions2/Parameters.h"
|
||||
|
||||
#include <velocypack/Builder.h>
|
||||
#include <velocypack/velocypack-aliases.h>
|
||||
|
||||
#include <iostream>
|
||||
|
||||
#include "ProgramOptions2/Parameters.h"
|
||||
|
||||
namespace arangodb {
|
||||
namespace options {
|
||||
|
||||
|
@ -57,6 +59,10 @@ struct Option {
|
|||
}
|
||||
}
|
||||
|
||||
void toVPack(VPackBuilder& builder) const {
|
||||
parameter->toVPack(builder);
|
||||
}
|
||||
|
||||
// get display name for the option
|
||||
std::string displayName() const { return "--" + fullName(); }
|
||||
|
||||
|
@ -69,8 +75,9 @@ struct Option {
|
|||
}
|
||||
|
||||
// print help for an option
|
||||
void printHelp(size_t tw, size_t ow) const {
|
||||
if (!hidden) {
|
||||
// the special search string "." will show help for all sections, even if hidden
|
||||
void printHelp(std::string const& search, size_t tw, size_t ow) const {
|
||||
if (search == "." || !hidden) {
|
||||
std::cout << " " << pad(nameWithType(), ow) << " ";
|
||||
|
||||
std::string value = description;
|
||||
|
|
|
@ -25,6 +25,12 @@
|
|||
|
||||
#include "Basics/Common.h"
|
||||
|
||||
#include <velocypack/Builder.h>
|
||||
#include <velocypack/velocypack-aliases.h>
|
||||
|
||||
#include <numeric>
|
||||
#include <type_traits>
|
||||
|
||||
namespace arangodb {
|
||||
namespace options {
|
||||
|
||||
|
@ -33,7 +39,7 @@ template <typename T>
|
|||
typename std::enable_if<std::is_signed<T>::value, T>::type toNumber(
|
||||
std::string const& value) {
|
||||
auto v = static_cast<T>(std::stoll(value));
|
||||
if (v < std::numeric_limits<T>::min() || v > std::numeric_limits<T>::max()) {
|
||||
if (v < (std::numeric_limits<T>::min)() || v > (std::numeric_limits<T>::max)()) {
|
||||
throw std::out_of_range(value);
|
||||
}
|
||||
return static_cast<T>(v);
|
||||
|
@ -44,7 +50,7 @@ template <typename T>
|
|||
typename std::enable_if<std::is_unsigned<T>::value, T>::type toNumber(
|
||||
std::string const& value) {
|
||||
auto v = static_cast<T>(std::stoull(value));
|
||||
if (v < std::numeric_limits<T>::min() || v > std::numeric_limits<T>::max()) {
|
||||
if (v < (std::numeric_limits<T>::min)() || v > (std::numeric_limits<T>::max)()) {
|
||||
throw std::out_of_range(value);
|
||||
}
|
||||
return static_cast<T>(v);
|
||||
|
@ -56,6 +62,20 @@ double toNumber<double>(std::string const& value) {
|
|||
return std::stod(value);
|
||||
}
|
||||
|
||||
// convert a string into another type, specialized version for numbers
|
||||
template <typename T>
|
||||
typename std::enable_if<std::is_arithmetic<T>::value, T>::type fromString(
|
||||
std::string const& value) {
|
||||
return toNumber<T>(value);
|
||||
}
|
||||
|
||||
// convert a string into another type, specialized version for string -> string
|
||||
template <typename T>
|
||||
typename std::enable_if<std::is_same<T, std::string>::value, T>::type fromString(
|
||||
std::string const& value) {
|
||||
return value;
|
||||
}
|
||||
|
||||
// stringify a value, base version for any type
|
||||
template <typename T>
|
||||
inline std::string stringifyValue(T const& value) {
|
||||
|
@ -90,6 +110,8 @@ struct Parameter {
|
|||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
virtual void toVPack(VPackBuilder&) const = 0;
|
||||
};
|
||||
|
||||
// specialized type for boolean values
|
||||
|
@ -119,6 +141,10 @@ struct BooleanParameter : public Parameter {
|
|||
return "";
|
||||
}
|
||||
|
||||
void toVPack(VPackBuilder& builder) const override {
|
||||
builder.add(VPackValue(*ptr));
|
||||
}
|
||||
|
||||
ValueType* ptr;
|
||||
bool required;
|
||||
};
|
||||
|
@ -136,8 +162,8 @@ struct NumericParameter : public Parameter {
|
|||
std::string set(std::string const& value) override {
|
||||
try {
|
||||
ValueType v = toNumber<ValueType>(value);
|
||||
if (v >= std::numeric_limits<T>::min() &&
|
||||
v <= std::numeric_limits<T>::max()) {
|
||||
if (v >= (std::numeric_limits<T>::min)() &&
|
||||
v <= (std::numeric_limits<T>::max)()) {
|
||||
*ptr = v;
|
||||
return "";
|
||||
}
|
||||
|
@ -147,6 +173,10 @@ struct NumericParameter : public Parameter {
|
|||
return "number out of range";
|
||||
}
|
||||
|
||||
void toVPack(VPackBuilder& builder) const override {
|
||||
builder.add(VPackValue(*ptr));
|
||||
}
|
||||
|
||||
ValueType* ptr;
|
||||
};
|
||||
|
||||
|
@ -206,28 +236,28 @@ struct UInt64Parameter : public NumericParameter<uint64_t> {
|
|||
|
||||
template <typename T>
|
||||
struct BoundedParameter : public T {
|
||||
BoundedParameter(typename T::ValueType* ptr, typename T::ValueType min,
|
||||
typename T::ValueType max)
|
||||
: T(ptr), min(min), max(max) {}
|
||||
BoundedParameter(typename T::ValueType* ptr, typename T::ValueType minValue,
|
||||
typename T::ValueType maxValue)
|
||||
: T(ptr), minValue(minValue), maxValue(maxValue) {}
|
||||
|
||||
std::string set(std::string const& value) override {
|
||||
try {
|
||||
typename T::ValueType v = toNumber<typename T::ValueType>(value);
|
||||
if (v >= std::numeric_limits<typename T::ValueType>::min() &&
|
||||
v <= std::numeric_limits<typename T::ValueType>::max() && v >= min &&
|
||||
v <= max) {
|
||||
if (v >= (std::numeric_limits<typename T::ValueType>::min)() &&
|
||||
v <= (std::numeric_limits<typename T::ValueType>::max)() && v >= minValue &&
|
||||
v <= maxValue) {
|
||||
*this->ptr = v;
|
||||
return "";
|
||||
}
|
||||
} catch (...) {
|
||||
return "invalid numeric value";
|
||||
}
|
||||
return "number out of allowed range (" + std::to_string(min) + " - " +
|
||||
std::to_string(max) + ")";
|
||||
return "number out of allowed range (" + std::to_string(minValue) + " - " +
|
||||
std::to_string(maxValue) + ")";
|
||||
}
|
||||
|
||||
typename T::ValueType min;
|
||||
typename T::ValueType max;
|
||||
typename T::ValueType minValue;
|
||||
typename T::ValueType maxValue;
|
||||
};
|
||||
|
||||
// concrete double number value type
|
||||
|
@ -253,9 +283,33 @@ struct StringParameter : public Parameter {
|
|||
return "";
|
||||
}
|
||||
|
||||
void toVPack(VPackBuilder& builder) const override {
|
||||
builder.add(VPackValue(*ptr));
|
||||
}
|
||||
|
||||
ValueType* ptr;
|
||||
};
|
||||
|
||||
// specialized type for discrete values (defined in the unordered_set)
|
||||
// this templated type needs a concrete value type
|
||||
template <typename T>
|
||||
struct DiscreteValuesParameter : public T {
|
||||
DiscreteValuesParameter(typename T::ValueType* ptr,
|
||||
std::unordered_set<typename T::ValueType> const& allowed)
|
||||
: T(ptr), allowed(allowed) {}
|
||||
|
||||
std::string set(std::string const& value) override {
|
||||
auto it = allowed.find(fromString<typename T::ValueType>(value));
|
||||
|
||||
if (it == allowed.end()) {
|
||||
return "invalid value " + value;
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
std::unordered_set<typename T::ValueType> allowed;
|
||||
};
|
||||
|
||||
// specialized type for vectors of values
|
||||
// this templated type needs a concrete value type
|
||||
template <typename T>
|
||||
|
@ -290,6 +344,13 @@ struct VectorParameter : public Parameter {
|
|||
return result;
|
||||
}
|
||||
|
||||
void toVPack(VPackBuilder& builder) const override {
|
||||
builder.openArray();
|
||||
for (size_t i = 0; i < ptr->size(); ++i) {
|
||||
builder.add(VPackValue(ptr->at(i)));
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<typename T::ValueType>* ptr;
|
||||
};
|
||||
|
||||
|
@ -299,6 +360,9 @@ struct ObsoleteParameter : public Parameter {
|
|||
std::string name() const override { return "obsolete"; }
|
||||
std::string valueString() const override { return "-"; }
|
||||
std::string set(std::string const&) override { return ""; }
|
||||
void toVPack(VPackBuilder& builder) const override {
|
||||
builder.add(VPackValue(VPackValueType::Null));
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
|
@ -28,6 +28,11 @@
|
|||
#include "ProgramOptions2/Option.h"
|
||||
#include "ProgramOptions2/Section.h"
|
||||
|
||||
#include <velocypack/Builder.h>
|
||||
#include <velocypack/velocypack-aliases.h>
|
||||
|
||||
#include <functional>
|
||||
|
||||
#define ARANGODB_PROGRAM_OPTIONS_PROGNAME "#progname#"
|
||||
|
||||
namespace arangodb {
|
||||
|
@ -82,7 +87,8 @@ class ProgramOptions {
|
|||
_terminalWidth(terminalWidth),
|
||||
_similarity(similarity),
|
||||
_processingResult(),
|
||||
_sealed(false) {
|
||||
_sealed(false),
|
||||
_overrideOptions(false) {
|
||||
// find progname wildcard in string
|
||||
size_t const pos = _usage.find(ARANGODB_PROGRAM_OPTIONS_PROGNAME);
|
||||
|
||||
|
@ -100,9 +106,19 @@ class ProgramOptions {
|
|||
ProcessingResult& processingResult() { return _processingResult; }
|
||||
|
||||
// seal the options
|
||||
// tryin to add an option or a section after sealing will throw an error
|
||||
// trying to add an option or a section after sealing will throw an error
|
||||
void seal() { _sealed = true; }
|
||||
|
||||
// allow or disallow overriding already set options
|
||||
void allowOverride(bool value) {
|
||||
checkIfSealed();
|
||||
_overrideOptions = value;
|
||||
}
|
||||
|
||||
bool allowOverride() const {
|
||||
return _overrideOptions;
|
||||
}
|
||||
|
||||
// set context for error reporting
|
||||
void setContext(std::string const& value) { _context = value; }
|
||||
|
||||
|
@ -149,20 +165,24 @@ class ProgramOptions {
|
|||
// prints usage information
|
||||
void printUsage() const { std::cout << _usage << std::endl << std::endl; }
|
||||
|
||||
// prints a help for all options
|
||||
void printHelp(std::string const& section) const {
|
||||
// prints a help for all options, or the options of a section
|
||||
// the special search string "*" will show help for all sections
|
||||
// the special search string "." will show help for all sections, even if hidden
|
||||
void printHelp(std::string const& search) const {
|
||||
printUsage();
|
||||
|
||||
size_t const tw = _terminalWidth();
|
||||
size_t const ow = optionsWidth();
|
||||
|
||||
for (auto const& it : _sections) {
|
||||
if (section == "*" || section == it.second.name) {
|
||||
it.second.printHelp(tw, ow);
|
||||
if (search == "*" || search == "." || search == it.second.name) {
|
||||
it.second.printHelp(search, tw, ow);
|
||||
}
|
||||
}
|
||||
|
||||
printSectionsHelp();
|
||||
if (search == "*") {
|
||||
printSectionsHelp();
|
||||
}
|
||||
}
|
||||
|
||||
// prints the names for all section help options
|
||||
|
@ -177,6 +197,28 @@ class ProgramOptions {
|
|||
std::cout << std::endl;
|
||||
}
|
||||
|
||||
// returns a VPack representation of the option values
|
||||
VPackBuilder toVPack(bool onlyTouched, std::unordered_set<std::string> const& exclude) const {
|
||||
VPackBuilder builder;
|
||||
builder.openObject();
|
||||
|
||||
walk([&builder, &exclude](Section const&, Option const& option) {
|
||||
std::string full(option.fullName());
|
||||
if (exclude.find(full) != exclude.end()) {
|
||||
// excluded option
|
||||
return;
|
||||
}
|
||||
|
||||
// add key
|
||||
builder.add(VPackValue(full));
|
||||
// add value
|
||||
option.toVPack(builder);
|
||||
}, onlyTouched);
|
||||
|
||||
builder.close();
|
||||
return builder;
|
||||
}
|
||||
|
||||
// translate a shorthand option
|
||||
std::string translateShorthand(std::string const& name) const {
|
||||
auto it = _shorthands.find(name);
|
||||
|
@ -188,7 +230,7 @@ class ProgramOptions {
|
|||
}
|
||||
|
||||
void walk(std::function<void(Section const&, Option const&)> const& callback,
|
||||
bool onlyTouched) {
|
||||
bool onlyTouched) const {
|
||||
for (auto const& it : _sections) {
|
||||
if (it.second.obsolete) {
|
||||
// obsolete section. ignore it
|
||||
|
@ -229,6 +271,11 @@ class ProgramOptions {
|
|||
|
||||
// sets a value for an option
|
||||
bool setValue(std::string const& name, std::string const& value) {
|
||||
if (!_overrideOptions && _processingResult.touched(name)) {
|
||||
// option already set. don't override it
|
||||
return true;
|
||||
}
|
||||
|
||||
auto parts = Option::splitName(name);
|
||||
auto it = _sections.find(parts.first);
|
||||
|
||||
|
@ -432,6 +479,8 @@ class ProgramOptions {
|
|||
ProcessingResult _processingResult;
|
||||
// whether or not the program options setup is still mutable
|
||||
bool _sealed;
|
||||
// allow or disallow overriding already set options
|
||||
bool _overrideOptions;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
|
@ -61,8 +61,9 @@ struct Section {
|
|||
}
|
||||
|
||||
// print help for a section
|
||||
void printHelp(size_t tw, size_t ow) const {
|
||||
if (hidden || !hasOptions()) {
|
||||
// the special search string "." will show help for all sections, even if hidden
|
||||
void printHelp(std::string const& search, size_t tw, size_t ow) const {
|
||||
if (search != "." && (hidden || !hasOptions())) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -71,7 +72,7 @@ struct Section {
|
|||
|
||||
// propagate print command to options
|
||||
for (auto const& it : options) {
|
||||
it.second.printHelp(tw, ow);
|
||||
it.second.printHelp(search, tw, ow);
|
||||
}
|
||||
|
||||
std::cout << std::endl;
|
||||
|
|
Loading…
Reference in New Issue