mirror of https://gitee.com/bigwinds/arangodb
Merge branch 'devel' of github.com:arangodb/arangodb into devel
This commit is contained in:
commit
b35674dffa
|
@ -1,10 +1,9 @@
|
||||||
devel
|
devel
|
||||||
-----
|
-----
|
||||||
|
|
||||||
* Bugfix: In an AQL cluster query, when gathering unsorted data in combination
|
* Made the mechanism in the Web UI of replacing and upgrading a foxx app more clear.
|
||||||
with a LIMIT with non-zero offset, if this offset exactly matches the number
|
|
||||||
of documents in the first shards consumed, the rest of the documents was not
|
* Fixed search not working in document view while in code mode
|
||||||
returned.
|
|
||||||
|
|
||||||
* Show shards of all collections (including system collections) in the web UI's shard
|
* Show shards of all collections (including system collections) in the web UI's shard
|
||||||
distribution view.
|
distribution view.
|
||||||
|
|
|
@ -68,11 +68,15 @@ foxxRouter.use(installer)
|
||||||
`)
|
`)
|
||||||
.queryParam('upgrade', joi.boolean().default(false), dd`
|
.queryParam('upgrade', joi.boolean().default(false), dd`
|
||||||
Flag to upgrade the service installed at the mount point.
|
Flag to upgrade the service installed at the mount point.
|
||||||
Triggers setup.
|
|
||||||
`)
|
`)
|
||||||
.queryParam('replace', joi.boolean().default(false), dd`
|
.queryParam('replace', joi.boolean().default(false), dd`
|
||||||
Flag to replace the service installed at the mount point.
|
Flag to replace the service installed at the mount point.
|
||||||
Triggers teardown and setup.
|
`)
|
||||||
|
.queryParam('setup', joi.boolean().default(true), dd`
|
||||||
|
Flag to run setup after install.
|
||||||
|
`)
|
||||||
|
.queryParam('teardown', joi.boolean().default(false), dd`
|
||||||
|
Flag to run teardown before replace/upgrade.
|
||||||
`);
|
`);
|
||||||
|
|
||||||
installer.use(function (req, res, next) {
|
installer.use(function (req, res, next) {
|
||||||
|
@ -83,6 +87,8 @@ installer.use(function (req, res, next) {
|
||||||
const options = {};
|
const options = {};
|
||||||
const appInfo = req.body;
|
const appInfo = req.body;
|
||||||
options.legacy = req.queryParams.legacy;
|
options.legacy = req.queryParams.legacy;
|
||||||
|
options.setup = req.queryParams.setup;
|
||||||
|
options.teardown = req.queryParams.teardown;
|
||||||
let service;
|
let service;
|
||||||
try {
|
try {
|
||||||
if (upgrade) {
|
if (upgrade) {
|
||||||
|
|
|
@ -1159,18 +1159,25 @@
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
getFoxxFlag: function () {
|
getFoxxFlags: function () {
|
||||||
var flag;
|
var flags = {};
|
||||||
|
|
||||||
if ($('#new-app-replace').prop('checked')) {
|
var $replace = $('#new-app-flag-replace')[0];
|
||||||
flag = true;
|
if ($replace) {
|
||||||
} else {
|
flags.replace = Boolean($replace.checked);
|
||||||
if ($('#new-app-teardown').prop('checked')) {
|
|
||||||
flag = false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return flag;
|
var $teardown = $('#new-app-flag-teardown')[0];
|
||||||
|
if ($teardown) {
|
||||||
|
flags.teardown = Boolean($teardown.checked);
|
||||||
|
}
|
||||||
|
|
||||||
|
var $setup = $('#new-app-flag-setup')[0];
|
||||||
|
if ($setup) {
|
||||||
|
flags.setup = Boolean($setup.checked);
|
||||||
|
}
|
||||||
|
|
||||||
|
return flags;
|
||||||
},
|
},
|
||||||
|
|
||||||
createMountPointModal: function (callback, mode, mountpoint) {
|
createMountPointModal: function (callback, mode, mountpoint) {
|
||||||
|
@ -1200,12 +1207,24 @@
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
if (window.App.replaceApp) {
|
||||||
|
tableContent.push(
|
||||||
|
window.modalView.createCheckboxEntry(
|
||||||
|
'new-app-flag-teardown',
|
||||||
|
'Run teardown?',
|
||||||
|
false,
|
||||||
|
"Should the existing service's teardown script be executed before replacing the service?",
|
||||||
|
false
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
tableContent.push(
|
tableContent.push(
|
||||||
window.modalView.createCheckboxEntry(
|
window.modalView.createCheckboxEntry(
|
||||||
'new-app-teardown',
|
'new-app-flag-setup',
|
||||||
'Run setup?',
|
'Run setup?',
|
||||||
true,
|
true,
|
||||||
"Should this app's setup script be executed after installing the app?",
|
"Should this service's setup script be executed after installing the service?",
|
||||||
true
|
true
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
@ -1213,9 +1232,9 @@
|
||||||
if (window.App.replaceApp) {
|
if (window.App.replaceApp) {
|
||||||
tableContent.push(
|
tableContent.push(
|
||||||
window.modalView.createCheckboxEntry(
|
window.modalView.createCheckboxEntry(
|
||||||
'new-app-replace',
|
'new-app-flag-replace',
|
||||||
'Discard configuration and dependency files?',
|
'Discard configuration and dependency files?',
|
||||||
true,
|
false,
|
||||||
"Should this service's existing configuration and settings be removed completely before replacing the service?",
|
"Should this service's existing configuration and settings be removed completely before replacing the service?",
|
||||||
false
|
false
|
||||||
)
|
)
|
||||||
|
|
|
@ -28,19 +28,25 @@
|
||||||
this.sortOptions.desc = val;
|
this.sortOptions.desc = val;
|
||||||
},
|
},
|
||||||
|
|
||||||
// Install Foxx from github repo
|
install: function (mode, info, mount, options, callback) {
|
||||||
// info is expected to contain: "url" and "version"
|
var url = arangoHelper.databaseUrl('/_admin/aardvark/foxxes/' + mode + '?mount=' + encodeURIComponent(mount));
|
||||||
installFromGithub: function (info, mount, callback, isLegacy, flag) {
|
if (options.legacy) {
|
||||||
var url = arangoHelper.databaseUrl('/_admin/aardvark/foxxes/git?mount=' + encodeURIComponent(mount));
|
|
||||||
if (isLegacy) {
|
|
||||||
url += '&legacy=true';
|
url += '&legacy=true';
|
||||||
}
|
}
|
||||||
if (flag !== undefined) {
|
if (options.setup === true) {
|
||||||
if (flag) {
|
url += '&setup=true';
|
||||||
url += '&replace=true';
|
} else if (options.setup === false) {
|
||||||
} else {
|
url += '&setup=false';
|
||||||
url += '&upgrade=true';
|
}
|
||||||
}
|
if (options.teardown === true) {
|
||||||
|
url += '&teardown=true';
|
||||||
|
} else if (options.teardown === false) {
|
||||||
|
url += '&teardown=false';
|
||||||
|
}
|
||||||
|
if (options.replace === true) {
|
||||||
|
url += '&replace=true';
|
||||||
|
} else if (options.replace === false) {
|
||||||
|
url += '&upgrade=true';
|
||||||
}
|
}
|
||||||
$.ajax({
|
$.ajax({
|
||||||
cache: false,
|
cache: false,
|
||||||
|
@ -58,115 +64,5 @@
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
// Install Foxx from public url
|
|
||||||
// info is expected to contain: "url" and "version"
|
|
||||||
installFromUrl: function (info, mount, callback, isLegacy, flag) {
|
|
||||||
var url = arangoHelper.databaseUrl('/_admin/aardvark/foxxes/url?mount=' + encodeURIComponent(mount));
|
|
||||||
if (isLegacy) {
|
|
||||||
url += '&legacy=true';
|
|
||||||
}
|
|
||||||
if (flag !== undefined) {
|
|
||||||
if (flag) {
|
|
||||||
url += '&replace=true';
|
|
||||||
} else {
|
|
||||||
url += '&upgrade=true';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
$.ajax({
|
|
||||||
cache: false,
|
|
||||||
type: 'PUT',
|
|
||||||
url: url,
|
|
||||||
data: JSON.stringify(info),
|
|
||||||
contentType: 'application/json',
|
|
||||||
processData: false,
|
|
||||||
success: function (data) {
|
|
||||||
callback(data);
|
|
||||||
},
|
|
||||||
error: function (err) {
|
|
||||||
callback(err);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
},
|
|
||||||
|
|
||||||
// Install Foxx from arango store
|
|
||||||
// info is expected to contain: "name" and "version"
|
|
||||||
installFromStore: function (info, mount, callback, flag) {
|
|
||||||
var url = arangoHelper.databaseUrl('/_admin/aardvark/foxxes/store?mount=' + encodeURIComponent(mount));
|
|
||||||
if (flag !== undefined) {
|
|
||||||
if (flag) {
|
|
||||||
url += '&replace=true';
|
|
||||||
} else {
|
|
||||||
url += '&upgrade=true';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
$.ajax({
|
|
||||||
cache: false,
|
|
||||||
type: 'PUT',
|
|
||||||
url: url,
|
|
||||||
data: JSON.stringify(info),
|
|
||||||
contentType: 'application/json',
|
|
||||||
processData: false,
|
|
||||||
success: function (data) {
|
|
||||||
callback(data);
|
|
||||||
},
|
|
||||||
error: function (err) {
|
|
||||||
callback(err);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
},
|
|
||||||
|
|
||||||
installFromZip: function (fileName, mount, callback, isLegacy, flag) {
|
|
||||||
var url = arangoHelper.databaseUrl('/_admin/aardvark/foxxes/zip?mount=' + encodeURIComponent(mount));
|
|
||||||
if (isLegacy) {
|
|
||||||
url += '&legacy=true';
|
|
||||||
}
|
|
||||||
if (flag !== undefined) {
|
|
||||||
if (flag) {
|
|
||||||
url += '&replace=true';
|
|
||||||
} else {
|
|
||||||
url += '&upgrade=true';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
$.ajax({
|
|
||||||
cache: false,
|
|
||||||
type: 'PUT',
|
|
||||||
url: url,
|
|
||||||
data: JSON.stringify({zipFile: fileName}),
|
|
||||||
contentType: 'application/json',
|
|
||||||
processData: false,
|
|
||||||
success: function (data) {
|
|
||||||
callback(data);
|
|
||||||
},
|
|
||||||
error: function (err) {
|
|
||||||
callback(err);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
},
|
|
||||||
|
|
||||||
generate: function (info, mount, callback, flag) {
|
|
||||||
var url = arangoHelper.databaseUrl('/_admin/aardvark/foxxes/generate?mount=' + encodeURIComponent(mount));
|
|
||||||
if (flag !== undefined) {
|
|
||||||
if (flag) {
|
|
||||||
url += '&replace=true';
|
|
||||||
} else {
|
|
||||||
url += '&upgrade=true';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
$.ajax({
|
|
||||||
cache: false,
|
|
||||||
type: 'PUT',
|
|
||||||
url: url,
|
|
||||||
data: JSON.stringify(info),
|
|
||||||
contentType: 'application/json',
|
|
||||||
processData: false,
|
|
||||||
success: function (data) {
|
|
||||||
callback(data);
|
|
||||||
},
|
|
||||||
error: function (err) {
|
|
||||||
callback(err);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
});
|
});
|
||||||
}());
|
}());
|
||||||
|
|
|
@ -225,9 +225,6 @@
|
||||||
|
|
||||||
// foxxes
|
// foxxes
|
||||||
this.foxxList = new window.FoxxCollection();
|
this.foxxList = new window.FoxxCollection();
|
||||||
window.foxxInstallView = new window.FoxxInstallView({
|
|
||||||
collection: this.foxxList
|
|
||||||
});
|
|
||||||
|
|
||||||
// foxx repository
|
// foxx repository
|
||||||
this.foxxRepo = new window.FoxxRepository();
|
this.foxxRepo = new window.FoxxRepository();
|
||||||
|
|
|
@ -1,392 +0,0 @@
|
||||||
/* jshint browser: true */
|
|
||||||
/* global $, Joi, _, arangoHelper, templateEngine, window */
|
|
||||||
(function () {
|
|
||||||
'use strict';
|
|
||||||
|
|
||||||
// mop: copy paste from common/bootstrap/errors.js
|
|
||||||
var errors = {
|
|
||||||
'ERROR_SERVICE_DOWNLOAD_FAILED': { 'code': 1752, 'message': 'service download failed' }
|
|
||||||
};
|
|
||||||
|
|
||||||
var appStoreTemplate = templateEngine.createTemplate('applicationListView.ejs');
|
|
||||||
|
|
||||||
var FoxxInstallView = function (opts) {
|
|
||||||
this.collection = opts.collection;
|
|
||||||
};
|
|
||||||
|
|
||||||
var installCallback = function (result) {
|
|
||||||
var self = this;
|
|
||||||
|
|
||||||
if (result.error === false) {
|
|
||||||
this.collection.fetch({
|
|
||||||
success: function () {
|
|
||||||
window.modalView.hide();
|
|
||||||
self.reload();
|
|
||||||
arangoHelper.arangoNotification('Services', 'Service ' + result.name + ' installed.');
|
|
||||||
}
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
var res = result;
|
|
||||||
if (result.hasOwnProperty('responseJSON')) {
|
|
||||||
res = result.responseJSON;
|
|
||||||
}
|
|
||||||
switch (res.errorNum) {
|
|
||||||
case errors.ERROR_SERVICE_DOWNLOAD_FAILED.code:
|
|
||||||
arangoHelper.arangoError('Services', 'Unable to download application from the given repository.');
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
arangoHelper.arangoError('Services', res.errorNum + '. ' + res.errorMessage);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
var setMountpointValidators = function () {
|
|
||||||
window.modalView.modalBindValidation({
|
|
||||||
id: 'new-app-mount',
|
|
||||||
validateInput: function () {
|
|
||||||
return [
|
|
||||||
{
|
|
||||||
rule: Joi.string().regex(/(\/|^)APP(\/|$)/i, {invert: true}),
|
|
||||||
msg: 'May not contain /APP'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
rule: Joi.string().regex(/^(\/[a-zA-Z0-9_\-%]+)+$/),
|
|
||||||
msg: 'Can only contain [a-zA-Z0-9_-%]'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
rule: Joi.string().regex(/^\/([^_]|_open\/)/),
|
|
||||||
msg: 'Mountpoints with _ are reserved for internal use'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
rule: Joi.string().regex(/[^/]$/),
|
|
||||||
msg: 'May not end with /'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
rule: Joi.string().regex(/^\//),
|
|
||||||
msg: 'Has to start with /'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
rule: Joi.string().required().min(2),
|
|
||||||
msg: 'Has to be non-empty'
|
|
||||||
}
|
|
||||||
];
|
|
||||||
}
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
var setGithubValidators = function () {
|
|
||||||
window.modalView.modalBindValidation({
|
|
||||||
id: 'repository',
|
|
||||||
validateInput: function () {
|
|
||||||
return [
|
|
||||||
{
|
|
||||||
rule: Joi.string().required().regex(/^[a-zA-Z0-9_-]+\/[a-zA-Z0-9_-]+$/),
|
|
||||||
msg: 'No valid Github account and repository.'
|
|
||||||
}
|
|
||||||
];
|
|
||||||
}
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
var setNewAppValidators = function () {
|
|
||||||
window.modalView.modalBindValidation({
|
|
||||||
id: 'new-app-author',
|
|
||||||
validateInput: function () {
|
|
||||||
return [
|
|
||||||
{
|
|
||||||
rule: Joi.string().required().min(1),
|
|
||||||
msg: 'Has to be non empty.'
|
|
||||||
}
|
|
||||||
];
|
|
||||||
}
|
|
||||||
});
|
|
||||||
window.modalView.modalBindValidation({
|
|
||||||
id: 'new-app-name',
|
|
||||||
validateInput: function () {
|
|
||||||
return [
|
|
||||||
{
|
|
||||||
rule: Joi.string().required().regex(/^[a-zA-Z\-_][a-zA-Z0-9\-_]*$/),
|
|
||||||
msg: "Can only contain a to z, A to Z, 0-9, '-' and '_'. Cannot start with a number."
|
|
||||||
}
|
|
||||||
];
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
window.modalView.modalBindValidation({
|
|
||||||
id: 'new-app-description',
|
|
||||||
validateInput: function () {
|
|
||||||
return [
|
|
||||||
{
|
|
||||||
rule: Joi.string().required().min(1),
|
|
||||||
msg: 'Has to be non empty.'
|
|
||||||
}
|
|
||||||
];
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
window.modalView.modalBindValidation({
|
|
||||||
id: 'new-app-license',
|
|
||||||
validateInput: function () {
|
|
||||||
return [
|
|
||||||
{
|
|
||||||
rule: Joi.string().required().regex(/^[a-zA-Z0-9 .,;-]+$/),
|
|
||||||
msg: "Can only contain a to z, A to Z, 0-9, '-', '.', ',' and ';'."
|
|
||||||
}
|
|
||||||
];
|
|
||||||
}
|
|
||||||
});
|
|
||||||
window.modalView.modalTestAll();
|
|
||||||
};
|
|
||||||
|
|
||||||
var switchTab = function (openTab) {
|
|
||||||
window.modalView.clearValidators();
|
|
||||||
var button = $('#modalButton1');
|
|
||||||
if (!this._upgrade) {
|
|
||||||
setMountpointValidators();
|
|
||||||
}
|
|
||||||
switch (openTab) {
|
|
||||||
case 'newApp':
|
|
||||||
button.html('Generate');
|
|
||||||
button.prop('disabled', false);
|
|
||||||
setNewAppValidators();
|
|
||||||
break;
|
|
||||||
case 'appstore':
|
|
||||||
button.html('Install');
|
|
||||||
button.prop('disabled', true);
|
|
||||||
break;
|
|
||||||
case 'github':
|
|
||||||
setGithubValidators();
|
|
||||||
button.html('Install');
|
|
||||||
button.prop('disabled', false);
|
|
||||||
break;
|
|
||||||
case 'zip':
|
|
||||||
button.html('Install');
|
|
||||||
button.prop('disabled', false);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!button.prop('disabled') && !window.modalView.modalTestAll()) {
|
|
||||||
// trigger the validation so the "ok" button has the correct state
|
|
||||||
button.prop('disabled', true);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
var switchModalButton = function (event) {
|
|
||||||
var openTab = $(event.currentTarget).attr('href').substr(1);
|
|
||||||
switchTab.call(this, openTab);
|
|
||||||
};
|
|
||||||
|
|
||||||
var installFoxxFromStore = function (e) {
|
|
||||||
switchTab.call(this, 'appstore');
|
|
||||||
if (window.modalView.modalTestAll()) {
|
|
||||||
var mount, flag;
|
|
||||||
if (this._upgrade) {
|
|
||||||
mount = this.mount;
|
|
||||||
flag = $('#new-app-teardown').prop('checked');
|
|
||||||
} else {
|
|
||||||
mount = window.arangoHelper.escapeHtml($('#new-app-mount').val());
|
|
||||||
}
|
|
||||||
var toInstall = $(e.currentTarget).attr('appId');
|
|
||||||
var version = $(e.currentTarget).attr('appVersion');
|
|
||||||
if (flag !== undefined) {
|
|
||||||
this.collection.installFromStore({name: toInstall, version: version}, mount, installCallback.bind(this), flag);
|
|
||||||
} else {
|
|
||||||
this.collection.installFromStore({name: toInstall, version: version}, mount, installCallback.bind(this));
|
|
||||||
}
|
|
||||||
window.modalView.hide();
|
|
||||||
arangoHelper.arangoNotification('Services', 'Installing ' + toInstall + '.');
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
var installFoxxFromZip = function (files, data) {
|
|
||||||
if (data === undefined) {
|
|
||||||
data = this._uploadData;
|
|
||||||
} else {
|
|
||||||
this._uploadData = data;
|
|
||||||
}
|
|
||||||
if (data && window.modalView.modalTestAll()) {
|
|
||||||
var mount, flag, isLegacy;
|
|
||||||
if (this._upgrade) {
|
|
||||||
mount = this.mount;
|
|
||||||
flag = Boolean($('#new-app-teardown').prop('checked'));
|
|
||||||
} else {
|
|
||||||
mount = window.arangoHelper.escapeHtml($('#new-app-mount').val());
|
|
||||||
}
|
|
||||||
isLegacy = Boolean($('#zip-app-islegacy').prop('checked'));
|
|
||||||
this.collection.installFromZip(data.filename, mount, installCallback.bind(this), isLegacy, flag);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
var installFoxxFromGithub = function () {
|
|
||||||
if (window.modalView.modalTestAll()) {
|
|
||||||
var url, version, mount, flag, isLegacy;
|
|
||||||
if (this._upgrade) {
|
|
||||||
mount = this.mount;
|
|
||||||
flag = $('#new-app-teardown').prop('checked');
|
|
||||||
} else {
|
|
||||||
mount = window.arangoHelper.escapeHtml($('#new-app-mount').val());
|
|
||||||
}
|
|
||||||
url = window.arangoHelper.escapeHtml($('#repository').val());
|
|
||||||
version = window.arangoHelper.escapeHtml($('#tag').val());
|
|
||||||
|
|
||||||
if (version === '') {
|
|
||||||
version = 'master';
|
|
||||||
}
|
|
||||||
var info = {
|
|
||||||
url: window.arangoHelper.escapeHtml($('#repository').val()),
|
|
||||||
version: window.arangoHelper.escapeHtml($('#tag').val())
|
|
||||||
};
|
|
||||||
|
|
||||||
try {
|
|
||||||
Joi.assert(url, Joi.string().regex(/^[a-zA-Z0-9_-]+\/[a-zA-Z0-9_-]+$/));
|
|
||||||
} catch (e) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
// send server req through collection
|
|
||||||
isLegacy = Boolean($('#github-app-islegacy').prop('checked'));
|
|
||||||
this.collection.installFromGithub(info, mount, installCallback.bind(this), isLegacy, flag);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
var generateNewFoxxApp = function () {
|
|
||||||
if (window.modalView.modalTestAll()) {
|
|
||||||
var mount, flag;
|
|
||||||
if (this._upgrade) {
|
|
||||||
mount = this.mount;
|
|
||||||
flag = $('#new-app-teardown').prop('checked');
|
|
||||||
} else {
|
|
||||||
mount = window.arangoHelper.escapeHtml($('#new-app-mount').val());
|
|
||||||
}
|
|
||||||
var info = {
|
|
||||||
name: window.arangoHelper.escapeHtml($('#new-app-name').val()),
|
|
||||||
documentCollections: _.map($('#new-app-document-collections').select2('data'), function (d) {
|
|
||||||
return window.arangoHelper.escapeHtml(d.text);
|
|
||||||
}),
|
|
||||||
edgeCollections: _.map($('#new-app-edge-collections').select2('data'), function (d) {
|
|
||||||
return window.arangoHelper.escapeHtml(d.text);
|
|
||||||
}),
|
|
||||||
// authenticated: window.arangoHelper.escapeHtml($("#new-app-name").val()),
|
|
||||||
author: window.arangoHelper.escapeHtml($('#new-app-author').val()),
|
|
||||||
license: window.arangoHelper.escapeHtml($('#new-app-license').val()),
|
|
||||||
description: window.arangoHelper.escapeHtml($('#new-app-description').val())
|
|
||||||
};
|
|
||||||
this.collection.generate(info, mount, installCallback.bind(this), flag);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
var addAppAction = function () {
|
|
||||||
var openTab = $('.modal-body .tab-pane.active').attr('id');
|
|
||||||
switch (openTab) {
|
|
||||||
case 'newApp':
|
|
||||||
generateNewFoxxApp.apply(this);
|
|
||||||
break;
|
|
||||||
case 'github':
|
|
||||||
installFoxxFromGithub.apply(this);
|
|
||||||
break;
|
|
||||||
case 'zip':
|
|
||||||
installFoxxFromZip.apply(this);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
var render = function (scope, upgrade) {
|
|
||||||
var buttons = [];
|
|
||||||
var modalEvents = {
|
|
||||||
'click #infoTab a': switchModalButton.bind(scope),
|
|
||||||
'click .install-app': installFoxxFromStore.bind(scope)
|
|
||||||
};
|
|
||||||
buttons.push(
|
|
||||||
window.modalView.createSuccessButton('Generate', addAppAction.bind(scope))
|
|
||||||
);
|
|
||||||
window.modalView.show(
|
|
||||||
'modalApplicationMount.ejs',
|
|
||||||
'Install Service',
|
|
||||||
buttons,
|
|
||||||
upgrade,
|
|
||||||
undefined,
|
|
||||||
undefined,
|
|
||||||
modalEvents
|
|
||||||
);
|
|
||||||
$('#new-app-document-collections').select2({
|
|
||||||
tags: [],
|
|
||||||
showSearchBox: false,
|
|
||||||
minimumResultsForSearch: -1,
|
|
||||||
width: '336px'
|
|
||||||
});
|
|
||||||
$('#new-app-edge-collections').select2({
|
|
||||||
tags: [],
|
|
||||||
showSearchBox: false,
|
|
||||||
minimumResultsForSearch: -1,
|
|
||||||
width: '336px'
|
|
||||||
});
|
|
||||||
|
|
||||||
var checkButton = function () {
|
|
||||||
var button = $('#modalButton1');
|
|
||||||
if (!button.prop('disabled') && !window.modalView.modalTestAll()) {
|
|
||||||
button.prop('disabled', true);
|
|
||||||
} else {
|
|
||||||
button.prop('disabled', false);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
$('.select2-search-field input').focusout(function () {
|
|
||||||
checkButton();
|
|
||||||
window.setTimeout(function () {
|
|
||||||
if ($('.select2-drop').is(':visible')) {
|
|
||||||
if (!$('#select2-search-field input').is(':focus')) {
|
|
||||||
$('#s2id_new-app-document-collections').select2('close');
|
|
||||||
$('#s2id_new-app-edge-collections').select2('close');
|
|
||||||
checkButton();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}, 200);
|
|
||||||
});
|
|
||||||
$('.select2-search-field input').focusin(function () {
|
|
||||||
if ($('.select2-drop').is(':visible')) {
|
|
||||||
var button = $('#modalButton1');
|
|
||||||
button.prop('disabled', true);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
$('#upload-foxx-zip').uploadFile({
|
|
||||||
url: arangoHelper.databaseUrl('/_api/upload?multipart=true'),
|
|
||||||
allowedTypes: 'zip,js',
|
|
||||||
multiple: false,
|
|
||||||
onSuccess: installFoxxFromZip.bind(scope)
|
|
||||||
});
|
|
||||||
$.get('foxxes/fishbowl', function (list) {
|
|
||||||
var table = $('#appstore-content');
|
|
||||||
table.html('');
|
|
||||||
_.each(_.sortBy(list, 'name'), function (app) {
|
|
||||||
table.append(appStoreTemplate.render(app));
|
|
||||||
});
|
|
||||||
}).fail(function () {
|
|
||||||
var table = $('#appstore-content');
|
|
||||||
table.append('<tr><td>Store is not available. ArangoDB is not able to connect to github.com</td></tr>');
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
FoxxInstallView.prototype.install = function (callback) {
|
|
||||||
this.reload = callback;
|
|
||||||
this._upgrade = false;
|
|
||||||
this._uploadData = undefined;
|
|
||||||
delete this.mount;
|
|
||||||
render(this, false);
|
|
||||||
window.modalView.clearValidators();
|
|
||||||
setMountpointValidators();
|
|
||||||
setNewAppValidators();
|
|
||||||
};
|
|
||||||
|
|
||||||
FoxxInstallView.prototype.upgrade = function (mount, callback) {
|
|
||||||
this.reload = callback;
|
|
||||||
this._upgrade = true;
|
|
||||||
this._uploadData = undefined;
|
|
||||||
this.mount = mount;
|
|
||||||
render(this, true);
|
|
||||||
window.modalView.clearValidators();
|
|
||||||
setNewAppValidators();
|
|
||||||
};
|
|
||||||
|
|
||||||
window.FoxxInstallView = FoxxInstallView;
|
|
||||||
}());
|
|
|
@ -201,21 +201,23 @@
|
||||||
|
|
||||||
installFoxxFromStore: function (e) {
|
installFoxxFromStore: function (e) {
|
||||||
if (window.modalView.modalTestAll()) {
|
if (window.modalView.modalTestAll()) {
|
||||||
var mount, flag;
|
var mount, info, options;
|
||||||
if (this._upgrade) {
|
if (this._upgrade) {
|
||||||
mount = window.App.replaceAppData.mount;
|
mount = window.App.replaceAppData.mount;
|
||||||
flag = arangoHelper.getFoxxFlag();
|
|
||||||
} else {
|
} else {
|
||||||
mount = window.arangoHelper.escapeHtml($('#new-app-mount').val());
|
mount = window.arangoHelper.escapeHtml($('#new-app-mount').val());
|
||||||
if (mount.charAt(0) !== '/') {
|
if (mount.charAt(0) !== '/') {
|
||||||
mount = '/' + mount;
|
mount = '/' + mount;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (flag !== undefined) {
|
|
||||||
this.collection.installFromStore({name: this.toInstall, version: this.version}, mount, this.installCallback.bind(this), flag);
|
info = {
|
||||||
} else {
|
name: this.toInstall,
|
||||||
this.collection.installFromStore({name: this.toInstall, version: this.version}, mount, this.installCallback.bind(this));
|
version: this.version
|
||||||
}
|
};
|
||||||
|
|
||||||
|
options = arangoHelper.getFoxxFlags();
|
||||||
|
this.collection.install('store', info, mount, options, this.installCallback.bind(this));
|
||||||
window.modalView.hide();
|
window.modalView.hide();
|
||||||
|
|
||||||
if (this._upgrade) {
|
if (this._upgrade) {
|
||||||
|
|
|
@ -73,35 +73,36 @@
|
||||||
|
|
||||||
installFoxxFromGithub: function () {
|
installFoxxFromGithub: function () {
|
||||||
if (window.modalView.modalTestAll()) {
|
if (window.modalView.modalTestAll()) {
|
||||||
var url, version, mount, flag, isLegacy;
|
var mount, info, options, url, version;
|
||||||
if (this._upgrade) {
|
if (this._upgrade) {
|
||||||
mount = window.App.replaceAppData.mount;
|
mount = window.App.replaceAppData.mount;
|
||||||
flag = arangoHelper.getFoxxFlag();
|
|
||||||
} else {
|
} else {
|
||||||
mount = window.arangoHelper.escapeHtml($('#new-app-mount').val());
|
mount = window.arangoHelper.escapeHtml($('#new-app-mount').val());
|
||||||
if (mount.charAt(0) !== '/') {
|
if (mount.charAt(0) !== '/') {
|
||||||
mount = '/' + mount;
|
mount = '/' + mount;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
url = window.arangoHelper.escapeHtml($('#repository').val());
|
url = window.arangoHelper.escapeHtml($('#repository').val());
|
||||||
version = window.arangoHelper.escapeHtml($('#tag').val());
|
version = window.arangoHelper.escapeHtml($('#tag').val());
|
||||||
|
|
||||||
if (version === '') {
|
if (version === '') {
|
||||||
version = 'master';
|
version = 'master';
|
||||||
}
|
}
|
||||||
var info = {
|
|
||||||
url: window.arangoHelper.escapeHtml($('#repository').val()),
|
|
||||||
version: window.arangoHelper.escapeHtml($('#tag').val())
|
|
||||||
};
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
Joi.assert(url, Joi.string().regex(/^[a-zA-Z0-9_-]+\/[a-zA-Z0-9_-]+$/));
|
Joi.assert(url, Joi.string().regex(/^[a-zA-Z0-9_-]+\/[a-zA-Z0-9_-]+$/));
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// send server req through collection
|
// send server req through collection
|
||||||
isLegacy = Boolean($('#github-app-islegacy').prop('checked'));
|
|
||||||
this.collection.installFromGithub(info, mount, this.installCallback.bind(this), isLegacy, flag);
|
info = {
|
||||||
|
url: url,
|
||||||
|
version: version
|
||||||
|
};
|
||||||
|
|
||||||
|
options = arangoHelper.getFoxxFlags();
|
||||||
|
options.legacy = Boolean($('#github-app-islegacy')[0].checked);
|
||||||
|
this.collection.install('git', info, mount, options, this.installCallback.bind(this));
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
|
@ -56,17 +56,17 @@
|
||||||
|
|
||||||
generateNewFoxxApp: function () {
|
generateNewFoxxApp: function () {
|
||||||
if (window.modalView.modalTestAll()) {
|
if (window.modalView.modalTestAll()) {
|
||||||
var mount, flag;
|
var mount, info, options;
|
||||||
if (this._upgrade) {
|
if (this._upgrade) {
|
||||||
mount = window.App.replaceAppData.mount;
|
mount = window.App.replaceAppData.mount;
|
||||||
flag = arangoHelper.getFoxxFlag();
|
|
||||||
} else {
|
} else {
|
||||||
mount = window.arangoHelper.escapeHtml($('#new-app-mount').val());
|
mount = window.arangoHelper.escapeHtml($('#new-app-mount').val());
|
||||||
if (mount.charAt(0) !== '/') {
|
if (mount.charAt(0) !== '/') {
|
||||||
mount = '/' + mount;
|
mount = '/' + mount;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
var info = {
|
|
||||||
|
info = {
|
||||||
name: window.arangoHelper.escapeHtml($('#new-app-name').val()),
|
name: window.arangoHelper.escapeHtml($('#new-app-name').val()),
|
||||||
documentCollections: _.map($('#new-app-document-collections').select2('data'), function (d) {
|
documentCollections: _.map($('#new-app-document-collections').select2('data'), function (d) {
|
||||||
return window.arangoHelper.escapeHtml(d.text);
|
return window.arangoHelper.escapeHtml(d.text);
|
||||||
|
@ -79,7 +79,9 @@
|
||||||
license: window.arangoHelper.escapeHtml($('#new-app-license').val()),
|
license: window.arangoHelper.escapeHtml($('#new-app-license').val()),
|
||||||
description: window.arangoHelper.escapeHtml($('#new-app-description').val())
|
description: window.arangoHelper.escapeHtml($('#new-app-description').val())
|
||||||
};
|
};
|
||||||
this.collection.generate(info, mount, this.installCallback.bind(this), flag);
|
|
||||||
|
options = arangoHelper.getFoxxFlags();
|
||||||
|
this.collection.install('generate', info, mount, options, this.installCallback.bind(this));
|
||||||
}
|
}
|
||||||
window.modalView.hide();
|
window.modalView.hide();
|
||||||
},
|
},
|
||||||
|
|
|
@ -71,18 +71,23 @@
|
||||||
this._uploadData = window.foxxData.data;
|
this._uploadData = window.foxxData.data;
|
||||||
}
|
}
|
||||||
if (window.foxxData.data && window.modalView.modalTestAll()) {
|
if (window.foxxData.data && window.modalView.modalTestAll()) {
|
||||||
var mount, flag, isLegacy;
|
var mount, info, options;
|
||||||
if (this._upgrade) {
|
if (this._upgrade) {
|
||||||
mount = window.App.replaceAppData.mount;
|
mount = window.App.replaceAppData.mount;
|
||||||
flag = arangoHelper.getFoxxFlag();
|
|
||||||
} else {
|
} else {
|
||||||
mount = window.arangoHelper.escapeHtml($('#new-app-mount').val());
|
mount = window.arangoHelper.escapeHtml($('#new-app-mount').val());
|
||||||
if (mount.charAt(0) !== '/') {
|
if (mount.charAt(0) !== '/') {
|
||||||
mount = '/' + mount;
|
mount = '/' + mount;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
isLegacy = Boolean($('#zip-app-islegacy').prop('checked'));
|
|
||||||
this.collection.installFromZip(window.foxxData.data.filename, mount, this.installCallback.bind(this), isLegacy, flag);
|
info = {
|
||||||
|
zipFile: window.foxxData.data.filename
|
||||||
|
};
|
||||||
|
|
||||||
|
options = arangoHelper.getFoxxFlags();
|
||||||
|
options.legacy = Boolean($('#zip-app-islegacy')[0].checked);
|
||||||
|
this.collection.install('zip', info, mount, options, this.installCallback.bind(this));
|
||||||
}
|
}
|
||||||
window.modalView.hide();
|
window.modalView.hide();
|
||||||
},
|
},
|
||||||
|
|
|
@ -65,11 +65,9 @@
|
||||||
|
|
||||||
installFoxxFromUrl: function () {
|
installFoxxFromUrl: function () {
|
||||||
if (window.modalView.modalTestAll()) {
|
if (window.modalView.modalTestAll()) {
|
||||||
var url, mount, flag;
|
var mount, info, options, url;
|
||||||
|
|
||||||
if (this._upgrade) {
|
if (this._upgrade) {
|
||||||
mount = window.App.replaceAppData.mount;
|
mount = window.App.replaceAppData.mount;
|
||||||
flag = arangoHelper.getFoxxFlag();
|
|
||||||
} else {
|
} else {
|
||||||
mount = window.arangoHelper.escapeHtml($('#new-app-mount').val());
|
mount = window.arangoHelper.escapeHtml($('#new-app-mount').val());
|
||||||
if (mount.charAt(0) !== '/') {
|
if (mount.charAt(0) !== '/') {
|
||||||
|
@ -77,13 +75,14 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
url = window.arangoHelper.escapeHtml($('#repository').val());
|
url = window.arangoHelper.escapeHtml($('#repository').val());
|
||||||
var info = {
|
|
||||||
url: url,
|
info = {
|
||||||
version: 'master'
|
url: url
|
||||||
};
|
};
|
||||||
|
|
||||||
// send server req through collection
|
// send server req through collection
|
||||||
this.collection.installFromUrl(info, mount, this.installCallback.bind(this), null, flag);
|
options = arangoHelper.getFoxxFlags();
|
||||||
|
this.collection.install('url', info, mount, options, this.installCallback.bind(this));
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
|
@ -34,21 +34,24 @@
|
||||||
|
|
||||||
installFoxxFromStore: function (e) {
|
installFoxxFromStore: function (e) {
|
||||||
if (window.modalView.modalTestAll()) {
|
if (window.modalView.modalTestAll()) {
|
||||||
var mount, flag;
|
var mount, info, options;
|
||||||
if (this._upgrade) {
|
if (this._upgrade) {
|
||||||
mount = this.mount;
|
mount = this.mount;
|
||||||
flag = $('#new-app-teardown').prop('checked');
|
|
||||||
} else {
|
} else {
|
||||||
mount = window.arangoHelper.escapeHtml($('#new-app-mount').val());
|
mount = window.arangoHelper.escapeHtml($('#new-app-mount').val());
|
||||||
if (mount.charAt(0) !== '/') {
|
if (mount.charAt(0) !== '/') {
|
||||||
mount = '/' + mount;
|
mount = '/' + mount;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (flag !== undefined) {
|
|
||||||
this.collection.installFromStore({name: this.model.get('name'), version: this.model.get('latestVersion')}, mount, this.installCallback.bind(this), flag);
|
info = {
|
||||||
} else {
|
name: this.model.get('name'),
|
||||||
this.collection.installFromStore({name: this.model.get('name'), version: this.model.get('latestVersion')}, mount, this.installCallback.bind(this));
|
version: this.model.get('latestVersion')
|
||||||
}
|
};
|
||||||
|
|
||||||
|
options = arangoHelper.getFoxxFlags();
|
||||||
|
this.collection.install('store', info, mount, options, this.installCallback.bind(this));
|
||||||
|
|
||||||
window.modalView.hide();
|
window.modalView.hide();
|
||||||
arangoHelper.arangoNotification('Services', 'Installing ' + this.model.get('name') + '.');
|
arangoHelper.arangoNotification('Services', 'Installing ' + this.model.get('name') + '.');
|
||||||
}
|
}
|
||||||
|
|
|
@ -68,6 +68,7 @@
|
||||||
"/img": "frontend/compressed-img",
|
"/img": "frontend/compressed-img",
|
||||||
"/data": "frontend/data",
|
"/data": "frontend/data",
|
||||||
"/js/arango/aqltemplates.json": "frontend/aqltemplates.json",
|
"/js/arango/aqltemplates.json": "frontend/aqltemplates.json",
|
||||||
|
"/ext-searchbox.js": "frontend/src/ext-searchbox.js",
|
||||||
"/worker-json.js": {
|
"/worker-json.js": {
|
||||||
"path": "frontend/src/worker-json.js",
|
"path": "frontend/src/worker-json.js",
|
||||||
"gzip": true
|
"gzip": true
|
||||||
|
|
|
@ -0,0 +1,78 @@
|
||||||
|
/*jshint globalstrict:true, strict:true, esnext: true */
|
||||||
|
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/// DISCLAIMER
|
||||||
|
///
|
||||||
|
/// Copyright 2019 ArangoDB 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 ArangoDB GmbH, Cologne, Germany
|
||||||
|
///
|
||||||
|
/// @author Tobias Gödderz
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
const _ = require('lodash');
|
||||||
|
const internal = require("internal");
|
||||||
|
const jsunity = require("jsunity");
|
||||||
|
const {assertEqual} = jsunity.jsUnity.assertions;
|
||||||
|
|
||||||
|
const db = internal.db;
|
||||||
|
|
||||||
|
|
||||||
|
function aqlSkippingClusterTestsuite () {
|
||||||
|
const colName = 'UnitTestsAhuacatlSkipCluster';
|
||||||
|
const numberOfShards = 16;
|
||||||
|
let col;
|
||||||
|
|
||||||
|
return {
|
||||||
|
setUpAll: function () {
|
||||||
|
col = db._create(colName, {numberOfShards});
|
||||||
|
},
|
||||||
|
tearDownAll: function () {
|
||||||
|
col.drop();
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Regression test for PR https://github.com/arangodb/arangodb/pull/10190.
|
||||||
|
* This bug was never in a released version.
|
||||||
|
* In an AQL cluster query, when gathering unsorted data in combination with a LIMIT with non-zero offset,
|
||||||
|
* if this offset exactly matches the number of documents in the first shards consumed, the rest of the documents
|
||||||
|
* was not returned.
|
||||||
|
* The test is undeterministic, but has a high chance to detect this problem.
|
||||||
|
* This can only trigger when we skip a shard with the exact number of documents left in it,
|
||||||
|
* AND the shard returning DONE with that skip.
|
||||||
|
* Because of this, this problem didn't occur in 3.5, as the UnsortingGather dependencies were always RemoteNodes,
|
||||||
|
* and the RemoteNodes always reported HASMORE when at least one document was skipped.
|
||||||
|
* If we just used EnumerateCollection, the RocksDB iterator would also report HASMORE with the last document.
|
||||||
|
* Thus we use a FILTER here, which overfetches - the test relies on this and will not work without it, but I see
|
||||||
|
* no other way without writing a plan manually.
|
||||||
|
*/
|
||||||
|
testSkipExactDocsInShard: function () {
|
||||||
|
const query = 'FOR doc IN @@col FILTER doc._key != "" LIMIT 1, null RETURN doc';
|
||||||
|
const bind = {'@col': colName};
|
||||||
|
for (let i = 0; i < 2*numberOfShards; ++i) {
|
||||||
|
col.insert({});
|
||||||
|
const res = db._query(query, bind);
|
||||||
|
const n = res.toArray().length;
|
||||||
|
assertEqual(i, n);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
jsunity.run(aqlSkippingClusterTestsuite);
|
||||||
|
|
||||||
|
return jsunity.done();
|
Loading…
Reference in New Issue