1
0
Fork 0

fixed ui behaviour when replacing a foxx app (#9877)

* release version 3.4.8

* [3.4] fix agency lockup when removing 404-ed callbacks (#9839)

* fixed ui behaviour when replacing a foxx app

* Bug fix/curb aardvark foxx cthulhu (#9867)

* Revert "fixed ui behaviour when replacing a foxx app"

This reverts commit 6092465e05d11c10e83e3424945d8bf9e8f3ddaa.

* Cleanup on aisle 3

* Typo

* Fixed param order

* Cleanup flags

* Actually use the queryParams

* currently not supported via grunt env

* changelog

* removed not needed view

* fixed wrong used function
This commit is contained in:
Heiko 2019-09-20 15:21:56 +02:00 committed by KVS85
parent 8f9ebce0e0
commit c989fcfc8a
12 changed files with 110 additions and 570 deletions

View File

@ -1,6 +1,8 @@
v3.4.9 (XXXX-XX-XX)
v3.4.9 (XXX-XX-XX)
-------------------
* Made the mechanism in the Web UI of replacing and upgrading a foxx app more clear.
* Fixed a bug in the edge cache's internal memory accounting, which led
to the edge cache underreporting its current memory usage.

View File

@ -68,11 +68,15 @@ foxxRouter.use(installer)
`)
.queryParam('upgrade', joi.boolean().default(false), dd`
Flag to upgrade the service installed at the mount point.
Triggers setup.
`)
.queryParam('replace', joi.boolean().default(false), dd`
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) {
@ -83,6 +87,8 @@ installer.use(function (req, res, next) {
const options = {};
const appInfo = req.body;
options.legacy = req.queryParams.legacy;
options.setup = req.queryParams.setup;
options.teardown = req.queryParams.teardown;
let service;
try {
if (upgrade) {

View File

@ -1150,18 +1150,25 @@
});
},
getFoxxFlag: function () {
var flag;
getFoxxFlags: function () {
var flags = {};
if ($('#new-app-replace').prop('checked')) {
flag = true;
} else {
if ($('#new-app-teardown').prop('checked')) {
flag = false;
}
var $replace = $('#new-app-flag-replace')[0];
if ($replace) {
flags.replace = Boolean($replace.checked);
}
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) {
@ -1191,12 +1198,24 @@
)
);
if (window.App.replaceApp) {
tableContent.push(
window.modalView.createCheckboxEntry(
'new-app-flag-teardown',
'Run teardown?',
true,
"Should the existing service's teardown script be executed before replacing the service?",
false
)
);
}
tableContent.push(
window.modalView.createCheckboxEntry(
'new-app-teardown',
'new-app-flag-setup',
'Run setup?',
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
)
);
@ -1204,7 +1223,7 @@
if (window.App.replaceApp) {
tableContent.push(
window.modalView.createCheckboxEntry(
'new-app-replace',
'new-app-flag-replace',
'Discard configuration and dependency files?',
true,
"Should this service's existing configuration and settings be removed completely before replacing the service?",

View File

@ -28,19 +28,25 @@
this.sortOptions.desc = val;
},
// Install Foxx from github repo
// info is expected to contain: "url" and "version"
installFromGithub: function (info, mount, callback, isLegacy, flag) {
var url = arangoHelper.databaseUrl('/_admin/aardvark/foxxes/git?mount=' + encodeURIComponent(mount));
if (isLegacy) {
install: function (mode, info, mount, options, callback) {
var url = arangoHelper.databaseUrl('/_admin/aardvark/foxxes/' + mode + '?mount=' + encodeURIComponent(mount));
if (options.legacy) {
url += '&legacy=true';
}
if (flag !== undefined) {
if (flag) {
url += '&replace=true';
} else {
url += '&upgrade=true';
}
if (options.setup === true) {
url += '&setup=true';
} else if (options.setup === false) {
url += '&setup=false';
}
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({
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);
}
});
}
});
}());

View File

@ -225,9 +225,6 @@
// foxxes
this.foxxList = new window.FoxxCollection();
window.foxxInstallView = new window.FoxxInstallView({
collection: this.foxxList
});
// foxx repository
this.foxxRepo = new window.FoxxRepository();

View File

@ -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;
}());

View File

@ -201,21 +201,23 @@
installFoxxFromStore: function (e) {
if (window.modalView.modalTestAll()) {
var mount, flag;
var mount, info, options;
if (this._upgrade) {
mount = window.App.replaceAppData.mount;
flag = arangoHelper.getFoxxFlag();
} else {
mount = window.arangoHelper.escapeHtml($('#new-app-mount').val());
if (mount.charAt(0) !== '/') {
mount = '/' + mount;
}
}
if (flag !== undefined) {
this.collection.installFromStore({name: this.toInstall, version: this.version}, mount, this.installCallback.bind(this), flag);
} else {
this.collection.installFromStore({name: this.toInstall, version: this.version}, mount, this.installCallback.bind(this));
}
info = {
name: this.toInstall,
version: this.version
};
options = arangoHelper.getFoxxFlags();
this.collection.install('store', info, mount, options, this.installCallback.bind(this));
window.modalView.hide();
if (this._upgrade) {

View File

@ -73,35 +73,36 @@
installFoxxFromGithub: function () {
if (window.modalView.modalTestAll()) {
var url, version, mount, flag, isLegacy;
var mount, info, options, url, version;
if (this._upgrade) {
mount = window.App.replaceAppData.mount;
flag = arangoHelper.getFoxxFlag();
} else {
mount = window.arangoHelper.escapeHtml($('#new-app-mount').val());
if (mount.charAt(0) !== '/') {
mount = '/' + mount;
}
}
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, 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));
}
},

View File

@ -56,17 +56,17 @@
generateNewFoxxApp: function () {
if (window.modalView.modalTestAll()) {
var mount, flag;
var mount, info, options;
if (this._upgrade) {
mount = window.App.replaceAppData.mount;
flag = arangoHelper.getFoxxFlag();
} else {
mount = window.arangoHelper.escapeHtml($('#new-app-mount').val());
if (mount.charAt(0) !== '/') {
mount = '/' + mount;
}
}
var info = {
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);
@ -79,7 +79,9 @@
license: window.arangoHelper.escapeHtml($('#new-app-license').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();
},

View File

@ -71,18 +71,23 @@
this._uploadData = window.foxxData.data;
}
if (window.foxxData.data && window.modalView.modalTestAll()) {
var mount, flag, isLegacy;
var mount, info, options;
if (this._upgrade) {
mount = window.App.replaceAppData.mount;
flag = arangoHelper.getFoxxFlag();
} else {
mount = window.arangoHelper.escapeHtml($('#new-app-mount').val());
if (mount.charAt(0) !== '/') {
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();
},

View File

@ -65,11 +65,9 @@
installFoxxFromUrl: function () {
if (window.modalView.modalTestAll()) {
var url, mount, flag;
var mount, info, options, url;
if (this._upgrade) {
mount = window.App.replaceAppData.mount;
flag = arangoHelper.getFoxxFlag();
} else {
mount = window.arangoHelper.escapeHtml($('#new-app-mount').val());
if (mount.charAt(0) !== '/') {
@ -77,13 +75,14 @@
}
}
url = window.arangoHelper.escapeHtml($('#repository').val());
var info = {
url: url,
version: 'master'
info = {
url: url
};
// 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));
}
},

View File

@ -34,21 +34,24 @@
installFoxxFromStore: function (e) {
if (window.modalView.modalTestAll()) {
var mount, flag;
var mount, info, options;
if (this._upgrade) {
mount = this.mount;
flag = $('#new-app-teardown').prop('checked');
} else {
mount = window.arangoHelper.escapeHtml($('#new-app-mount').val());
if (mount.charAt(0) !== '/') {
mount = '/' + mount;
}
}
if (flag !== undefined) {
this.collection.installFromStore({name: this.model.get('name'), version: this.model.get('latestVersion')}, mount, this.installCallback.bind(this), flag);
} else {
this.collection.installFromStore({name: this.model.get('name'), version: this.model.get('latestVersion')}, mount, this.installCallback.bind(this));
}
info = {
name: this.model.get('name'),
version: this.model.get('latestVersion')
};
options = arangoHelper.getFoxxFlags();
this.collection.install('store', info, mount, options, this.installCallback.bind(this));
window.modalView.hide();
arangoHelper.arangoNotification('Services', 'Installing ' + this.model.get('name') + '.');
}