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('