diff --git a/CHANGELOG b/CHANGELOG index 2d2a1329bf..a20a50d1af 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,10 +1,9 @@ devel ----- -* Bugfix: 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. +* Made the mechanism in the Web UI of replacing and upgrading a foxx app more clear. + +* Fixed search not working in document view while in code mode * Show shards of all collections (including system collections) in the web UI's shard distribution view. diff --git a/js/apps/system/_admin/aardvark/APP/foxxes.js b/js/apps/system/_admin/aardvark/APP/foxxes.js index 09371149ed..14fefed275 100644 --- a/js/apps/system/_admin/aardvark/APP/foxxes.js +++ b/js/apps/system/_admin/aardvark/APP/foxxes.js @@ -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) { diff --git a/js/apps/system/_admin/aardvark/APP/frontend/js/arango/arango.js b/js/apps/system/_admin/aardvark/APP/frontend/js/arango/arango.js index 765155a987..137bf2bb7b 100644 --- a/js/apps/system/_admin/aardvark/APP/frontend/js/arango/arango.js +++ b/js/apps/system/_admin/aardvark/APP/frontend/js/arango/arango.js @@ -1159,18 +1159,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) { @@ -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( 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 ) ); @@ -1213,9 +1232,9 @@ if (window.App.replaceApp) { tableContent.push( window.modalView.createCheckboxEntry( - 'new-app-replace', + 'new-app-flag-replace', 'Discard configuration and dependency files?', - true, + false, "Should this service's existing configuration and settings be removed completely before replacing the service?", false ) diff --git a/js/apps/system/_admin/aardvark/APP/frontend/js/collections/foxxCollection.js b/js/apps/system/_admin/aardvark/APP/frontend/js/collections/foxxCollection.js index 1ba5ea61f8..bd8fde5fba 100644 --- a/js/apps/system/_admin/aardvark/APP/frontend/js/collections/foxxCollection.js +++ b/js/apps/system/_admin/aardvark/APP/frontend/js/collections/foxxCollection.js @@ -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); - } - }); - } - }); }()); diff --git a/js/apps/system/_admin/aardvark/APP/frontend/js/routers/router.js b/js/apps/system/_admin/aardvark/APP/frontend/js/routers/router.js index 2b7a4c685d..9b3a477506 100644 --- a/js/apps/system/_admin/aardvark/APP/frontend/js/routers/router.js +++ b/js/apps/system/_admin/aardvark/APP/frontend/js/routers/router.js @@ -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(); diff --git a/js/apps/system/_admin/aardvark/APP/frontend/js/views/foxxInstallView.js b/js/apps/system/_admin/aardvark/APP/frontend/js/views/foxxInstallView.js deleted file mode 100644 index 26f9b01f98..0000000000 --- a/js/apps/system/_admin/aardvark/APP/frontend/js/views/foxxInstallView.js +++ /dev/null @@ -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('Store is not available. ArangoDB is not able to connect to github.com'); - }); - }; - - 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; -}()); diff --git a/js/apps/system/_admin/aardvark/APP/frontend/js/views/foxxRepoView.js b/js/apps/system/_admin/aardvark/APP/frontend/js/views/foxxRepoView.js index 22099f41ae..74fc347679 100644 --- a/js/apps/system/_admin/aardvark/APP/frontend/js/views/foxxRepoView.js +++ b/js/apps/system/_admin/aardvark/APP/frontend/js/views/foxxRepoView.js @@ -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) { diff --git a/js/apps/system/_admin/aardvark/APP/frontend/js/views/installGitHubServiceView.js b/js/apps/system/_admin/aardvark/APP/frontend/js/views/installGitHubServiceView.js index a80aca1823..4f3d87332b 100644 --- a/js/apps/system/_admin/aardvark/APP/frontend/js/views/installGitHubServiceView.js +++ b/js/apps/system/_admin/aardvark/APP/frontend/js/views/installGitHubServiceView.js @@ -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)); } }, diff --git a/js/apps/system/_admin/aardvark/APP/frontend/js/views/installNewServiceView.js b/js/apps/system/_admin/aardvark/APP/frontend/js/views/installNewServiceView.js index a996395953..5423a4eeb2 100644 --- a/js/apps/system/_admin/aardvark/APP/frontend/js/views/installNewServiceView.js +++ b/js/apps/system/_admin/aardvark/APP/frontend/js/views/installNewServiceView.js @@ -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(); }, diff --git a/js/apps/system/_admin/aardvark/APP/frontend/js/views/installUploadServiceView.js b/js/apps/system/_admin/aardvark/APP/frontend/js/views/installUploadServiceView.js index c429c81d04..806a8b0df8 100644 --- a/js/apps/system/_admin/aardvark/APP/frontend/js/views/installUploadServiceView.js +++ b/js/apps/system/_admin/aardvark/APP/frontend/js/views/installUploadServiceView.js @@ -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(); }, diff --git a/js/apps/system/_admin/aardvark/APP/frontend/js/views/installUrlServiceView.js b/js/apps/system/_admin/aardvark/APP/frontend/js/views/installUrlServiceView.js index 489bb4fb26..ac786f2e00 100644 --- a/js/apps/system/_admin/aardvark/APP/frontend/js/views/installUrlServiceView.js +++ b/js/apps/system/_admin/aardvark/APP/frontend/js/views/installUrlServiceView.js @@ -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)); } }, diff --git a/js/apps/system/_admin/aardvark/APP/frontend/js/views/storeDetailView.js b/js/apps/system/_admin/aardvark/APP/frontend/js/views/storeDetailView.js index a7b489dd8f..465b7bfd7a 100644 --- a/js/apps/system/_admin/aardvark/APP/frontend/js/views/storeDetailView.js +++ b/js/apps/system/_admin/aardvark/APP/frontend/js/views/storeDetailView.js @@ -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') + '.'); } diff --git a/js/apps/system/_admin/aardvark/APP/manifest.json b/js/apps/system/_admin/aardvark/APP/manifest.json index aa7f9f1085..8111fa6a0c 100644 --- a/js/apps/system/_admin/aardvark/APP/manifest.json +++ b/js/apps/system/_admin/aardvark/APP/manifest.json @@ -68,6 +68,7 @@ "/img": "frontend/compressed-img", "/data": "frontend/data", "/js/arango/aqltemplates.json": "frontend/aqltemplates.json", + "/ext-searchbox.js": "frontend/src/ext-searchbox.js", "/worker-json.js": { "path": "frontend/src/worker-json.js", "gzip": true diff --git a/tests/js/server/aql/aql-skipping-cluster.js b/tests/js/server/aql/aql-skipping-cluster.js new file mode 100644 index 0000000000..00d5c44e70 --- /dev/null +++ b/tests/js/server/aql/aql-skipping-cluster.js @@ -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();