From baee09263acdb4988a94f15839a414bd991db46a Mon Sep 17 00:00:00 2001 From: Piotr Gawron <piotr.gawron@uni.lu> Date: Tue, 24 Jul 2018 13:19:48 +0200 Subject: [PATCH] copy to subtree required annotations implemented --- frontend-js/src/main/js/ServerConnector.js | 10 +- .../js/gui/admin/AbstractAnnotatorsDialog.js | 42 ++++++++ .../src/main/js/gui/admin/AddProjectDialog.js | 4 +- .../js/gui/admin/ChooseAnnotatorsDialog.js | 25 +---- .../js/gui/admin/ChooseValidatorsDialog.js | 99 ++++++++++++++++++- .../src/main/js/gui/admin/MapsAdminPanel.js | 3 +- .../src/main/js/map/data/UserPreferences.js | 34 ++++++- .../test/js/map/data/UserPreferences-test.js | 19 ++++ 8 files changed, 198 insertions(+), 38 deletions(-) create mode 100644 frontend-js/src/main/js/gui/admin/AbstractAnnotatorsDialog.js diff --git a/frontend-js/src/main/js/ServerConnector.js b/frontend-js/src/main/js/ServerConnector.js index a4d4f5bb0f..b5f1f91ffc 100644 --- a/frontend-js/src/main/js/ServerConnector.js +++ b/frontend-js/src/main/js/ServerConnector.js @@ -1170,7 +1170,7 @@ ServerConnector.getUser = function (login) { return self.sendGetRequest(self.getUserUrl(queryParams, filterParams)).then(function (content) { var obj = JSON.parse(content); var user = new User(obj); - if (self._usersByLogin[user.getLogin()] !== undefined) { + if (self._usersByLogin[user.getLogin()] instanceof User) { self._usersByLogin[user.getLogin()].update(user); } else { self._usersByLogin[user.getLogin()] = user; @@ -1314,12 +1314,8 @@ ServerConnector.updateUserPreferences = function (params) { }).then(function (content) { var obj = JSON.parse(content); var user = new User(obj); - if (self._usersByLogin[user.getLogin()] !== undefined) { - self._usersByLogin[user.getLogin()].getPreferences().update(user.getPreferences()); - } else { - self._usersByLogin[user.getLogin()] = user; - } - return self._usersByLogin[user.getLogin()]; + params.user.getPreferences().update(user.getPreferences()); + return params.user; }); }; diff --git a/frontend-js/src/main/js/gui/admin/AbstractAnnotatorsDialog.js b/frontend-js/src/main/js/gui/admin/AbstractAnnotatorsDialog.js new file mode 100644 index 0000000000..bd64417285 --- /dev/null +++ b/frontend-js/src/main/js/gui/admin/AbstractAnnotatorsDialog.js @@ -0,0 +1,42 @@ +"use strict"; + +/* exported logger */ + +var AbstractGuiElement = require('../AbstractGuiElement'); + +// noinspection JSUnusedLocalSymbols +var logger = require('../../logger'); + +function AbstractAnnotatorsDialog(params) { + AbstractGuiElement.call(this, params); +} + +AbstractAnnotatorsDialog.prototype = Object.create(AbstractGuiElement.prototype); +AbstractAnnotatorsDialog.prototype.constructor = AbstractAnnotatorsDialog; + +/** + * + * @param {BioEntityType} elementType + * @param {boolean} [includeChildren=false] + * + * @returns {BioEntityType[]} + */ +AbstractAnnotatorsDialog.prototype.getAllChildrenTypesIfNeeded = function (elementType, includeChildren) { + var result = [elementType]; + if (includeChildren) { + var queue = [elementType]; + var elementTypes = this.getConfiguration().getElementTypes(); + while (queue.length > 0) { + var type = queue.shift(); + for (var i = 0; i < elementTypes.length; i++) { + if (type.className === elementTypes[i].parentClass) { + queue.push(elementTypes[i]); + result.push(elementTypes[i]); + } + } + } + } + return result; +}; + +module.exports = AbstractAnnotatorsDialog; diff --git a/frontend-js/src/main/js/gui/admin/AddProjectDialog.js b/frontend-js/src/main/js/gui/admin/AddProjectDialog.js index 72177296be..00bf2533ae 100644 --- a/frontend-js/src/main/js/gui/admin/AddProjectDialog.js +++ b/frontend-js/src/main/js/gui/admin/AddProjectDialog.js @@ -131,7 +131,8 @@ AddProjectDialog.prototype.showAnnotatorsDialog = function () { self._annotatorsDialog = new ChooseAnnotatorsDialog({ element: Functions.createElement({type: "div"}), customMap: null, - configuration: self.getConfiguration() + configuration: self.getConfiguration(), + serverConnector: self.getServerConnector() }); promise = self._annotatorsDialog.init(); } else { @@ -147,6 +148,7 @@ AddProjectDialog.prototype.showValidatorsDialog = function () { if (self._validatorsDialog === undefined) { self._validatorsDialog = new ChooseValidatorsDialog({ element: Functions.createElement({type: "div"}), + configuration: self.getConfiguration(), customMap: null, serverConnector: self.getServerConnector() }); diff --git a/frontend-js/src/main/js/gui/admin/ChooseAnnotatorsDialog.js b/frontend-js/src/main/js/gui/admin/ChooseAnnotatorsDialog.js index e86ed8f788..f7969805f7 100644 --- a/frontend-js/src/main/js/gui/admin/ChooseAnnotatorsDialog.js +++ b/frontend-js/src/main/js/gui/admin/ChooseAnnotatorsDialog.js @@ -2,7 +2,7 @@ /* exported logger */ -var AbstractGuiElement = require('../AbstractGuiElement'); +var AbstractAnnotatorsDialog = require('./AbstractAnnotatorsDialog'); var GuiConnector = require("../../GuiConnector"); var MultiCheckboxList = require("multi-checkbox-list"); var UserPreferences = require("../../map/data/UserPreferences"); @@ -12,12 +12,12 @@ var Functions = require('../../Functions'); var logger = require('../../logger'); function ChooseAnnotatorsDialog(params) { - AbstractGuiElement.call(this, params); + AbstractAnnotatorsDialog.call(this, params); var self = this; self.createGui(); } -ChooseAnnotatorsDialog.prototype = Object.create(AbstractGuiElement.prototype); +ChooseAnnotatorsDialog.prototype = Object.create(AbstractAnnotatorsDialog.prototype); ChooseAnnotatorsDialog.prototype.constructor = ChooseAnnotatorsDialog; ChooseAnnotatorsDialog.prototype.createGui = function () { @@ -81,25 +81,6 @@ ChooseAnnotatorsDialog.prototype.saveAnnotatorsInfo = function (elementTypes, se }).catch(GuiConnector.alert); }; -ChooseAnnotatorsDialog.prototype.getAllChildrenTypesIfNeeded = function (elementType, includeChildren) { - var result = [elementType]; - if (includeChildren) { - var queue = [elementType]; - var elementTypes = this.getConfiguration().getElementTypes(); - while (queue.length > 0) { - var type = queue.shift(); - for (var i = 0; i < elementTypes.length; i++) { - if (type.className === elementTypes[i].parentClass) { - queue.push(elementTypes[i]); - result.push(elementTypes[i]); - } - } - } - } - return result; -}; - - ChooseAnnotatorsDialog.prototype.setElementType = function (elementType) { var self = this; diff --git a/frontend-js/src/main/js/gui/admin/ChooseValidatorsDialog.js b/frontend-js/src/main/js/gui/admin/ChooseValidatorsDialog.js index 2bea97c6de..cc23c46c40 100644 --- a/frontend-js/src/main/js/gui/admin/ChooseValidatorsDialog.js +++ b/frontend-js/src/main/js/gui/admin/ChooseValidatorsDialog.js @@ -2,7 +2,7 @@ /* exported logger */ -var AbstractGuiElement = require('../AbstractGuiElement'); +var AbstractAnnotatorsDialog = require('./AbstractAnnotatorsDialog'); var GuiConnector = require("../../GuiConnector"); var UserPreferences = require("../../map/data/UserPreferences"); var MultiCheckboxList = require("multi-checkbox-list"); @@ -26,12 +26,12 @@ var logger = require('../../logger'); * @extends AbstractGuiElement */ function ChooseValidatorsDialog(params) { - AbstractGuiElement.call(this, params); + AbstractAnnotatorsDialog.call(this, params); var self = this; self.createGui(); } -ChooseValidatorsDialog.prototype = Object.create(AbstractGuiElement.prototype); +ChooseValidatorsDialog.prototype = Object.create(AbstractAnnotatorsDialog.prototype); ChooseValidatorsDialog.prototype.constructor = ChooseValidatorsDialog; /** @@ -90,10 +90,99 @@ ChooseValidatorsDialog.prototype.setElementType = function (elementType) { }); element.appendChild(verifyAnnotationSelect); self.createVerifyAnnotationsDualListBox(user, configuration, elementType, verifyAnnotationSelect); + + element.appendChild(Functions.createElement({type: "br"})); + var includeChildrenCheckbox = Functions.createElement({type: "input", inputType: "checkbox"}); + var copyFromButton = Functions.createElement({ + type: "button", content: "Copy from", onclick: function () { + var typeClassName = copyFromSelect.value; + var requiredAnnotations, validAnnotators; + for (var i = 0; i < configuration.getElementTypes().length; i++) { + var type = configuration.getElementTypes()[i]; + if (typeClassName === type.className) { + requiredAnnotations = user.getPreferences().getElementRequiredAnnotations(typeClassName); + validAnnotators = user.getPreferences().getElementValidAnnotations(typeClassName); + } + } + if (requiredAnnotations === undefined) { + return GuiConnector.alert("Invalid element type: " + copyFromSelect.value); + } else { + var includeChildren = includeChildrenCheckbox.checked; + return self.saveAnnotationsInfo({ + elementTypes: self.getAllChildrenTypesIfNeeded(elementType, includeChildren), + requiredAnnotators: requiredAnnotations, + validAnnotators: validAnnotators + }).then(function () { + return self.setElementType(elementType); + }); + } + } + }); + element.appendChild(copyFromButton); + var copyFromSelect = Functions.createElement({type: "select", style: "margin:5px"}); + element.appendChild(copyFromSelect); + var options = [], i; + for (i = 0; i < configuration.getElementTypes().length; i++) { + var type = configuration.getElementTypes()[i]; + var name = type.className; + if (name.indexOf(".") > 0) { + name = name.substr(name.lastIndexOf(".") + 1); + } + options.push(Functions.createElement({ + type: "option", + value: type.className, + content: name + })); + } + options.sort(function (a, b) { + return a.text === b.text ? 0 : a.text < b.text ? -1 : 1 + }); + for (i = 0; i < options.length; i++) { + copyFromSelect.appendChild(options[i]); + } + element.appendChild(includeChildrenCheckbox); + element.appendChild(Functions.createElement({type: "span", content: "Apply to all in subtree"})); + }); }; +/** + * + * @param {BioEntityType[]} params.elementTypes + * @param {{list:string[], requiredAtLeastOnce:boolean}} params.requiredAnnotators + * @param {string[]} params.validAnnotators + * + * @returns {Promise} + */ +ChooseValidatorsDialog.prototype.saveAnnotationsInfo = function (params) { + var elementTypes = params.elementTypes; + var requiredAnnotators = params.requiredAnnotators; + var validAnnotators = params.validAnnotators; + var self = this; + return self.getServerConnector().getLoggedUser().then(function (user) { + + var data = new UserPreferences(); + + var elementRequiredAnnotators = {}; + var elementValidAnnotators = {}; + for (var i = 0; i < elementTypes.length; i++) { + elementRequiredAnnotators[elementTypes[i].className] = { + "require-at-least-one": requiredAnnotators.requiredAtLeastOnce, + "annotation-list": requiredAnnotators.list.slice() + }; + elementValidAnnotators[elementTypes[i].className] = validAnnotators.slice(); + } + data.setElementRequiredAnnotations(elementRequiredAnnotators); + data.setElementValidAnnotations(elementValidAnnotators); + return self.getServerConnector().updateUserPreferences({ + user: user, + preferences: data + }); + }).catch(GuiConnector.alert); +}; + + /** * * @param {User} user @@ -102,6 +191,7 @@ ChooseValidatorsDialog.prototype.setElementType = function (elementType) { * @param {HTMLElement} validAnnotationSelect */ ChooseValidatorsDialog.prototype.createValidAnnotationsDualListBox = function (user, configuration, elementType, validAnnotationSelect) { + var self = this; var miriamTypes = configuration.getMiriamTypes(); @@ -175,13 +265,14 @@ ChooseValidatorsDialog.prototype.createValidAnnotationsDualListBox = function (u */ ChooseValidatorsDialog.prototype.createVerifyAnnotationsDualListBox = function (user, configuration, elementType, verifyAnnotationSelect) { + var self = this; var requiredAnnotationsData = user.getPreferences().getElementRequiredAnnotations(elementType.className); var verifyCheckboxDiv = Functions.createElement({type: "div"}); var checkbox = Functions.createElement({ - id: "test", type: "input", inputType: "checkbox", + name: "require-at-least-one-checkbox", onclick: function () { var data = new UserPreferences(); diff --git a/frontend-js/src/main/js/gui/admin/MapsAdminPanel.js b/frontend-js/src/main/js/gui/admin/MapsAdminPanel.js index 939f0eb159..f09ccc9854 100644 --- a/frontend-js/src/main/js/gui/admin/MapsAdminPanel.js +++ b/frontend-js/src/main/js/gui/admin/MapsAdminPanel.js @@ -282,7 +282,8 @@ MapsAdminPanel.prototype.onAddClicked = function () { type: "div" }), customMap: null, - configuration: self.getConfiguration() + configuration: self.getConfiguration(), + serverConnector: self.getServerConnector() }); self._addDialog = dialog; dialog.addListener("onProjectAdd", function () { diff --git a/frontend-js/src/main/js/map/data/UserPreferences.js b/frontend-js/src/main/js/map/data/UserPreferences.js index 36ff821d76..a42b804aad 100644 --- a/frontend-js/src/main/js/map/data/UserPreferences.js +++ b/frontend-js/src/main/js/map/data/UserPreferences.js @@ -34,8 +34,8 @@ UserPreferences.prototype.update = function (userPreferences) { updateDict(this._projectUpload, userPreferences.getProjectUpload()); updateDict(this._elementAnnotators, userPreferences.getElementAnnotators); - updateDict(this._elementValidAnnotations, userPreferences.getElementValidAnnotations()); - updateDict(this._elementRequiredAnnotations, userPreferences.getElementRequiredAnnotations()); + updateDict(this._elementValidAnnotations, userPreferences._elementValidAnnotations); + updateDict(this._elementRequiredAnnotations, userPreferences._elementRequiredAnnotations); updateDict(this._annotatorsParameters, userPreferences.getAnnotatorsParameters()); updateDict(this._guiPreferences, userPreferences.getGuiPreferences()); }; @@ -78,6 +78,12 @@ UserPreferences.prototype.getProjectUpload = function () { UserPreferences.prototype.setElementAnnotators = function (elementAnnotators) { this._elementAnnotators = elementAnnotators; }; + +/** + * + * @param {string} className + * @returns {string[]} + */ UserPreferences.prototype.getElementAnnotators = function (className) { var result = this._elementAnnotators[className]; if (result === undefined) { @@ -86,6 +92,11 @@ UserPreferences.prototype.getElementAnnotators = function (className) { } return result; }; + +/** + * + * @param {Object<string, Object>} elementRequiredAnnotations + */ UserPreferences.prototype.setElementRequiredAnnotations = function (elementRequiredAnnotations) { this._elementRequiredAnnotations = {}; for (var key in elementRequiredAnnotations) { @@ -98,16 +109,33 @@ UserPreferences.prototype.setElementRequiredAnnotations = function (elementRequi } } }; + +/** + * + * @param {string} className + * @returns {{list:string[], requiredAtLeastOnce:boolean}} + */ UserPreferences.prototype.getElementRequiredAnnotations = function (className) { var result = this._elementRequiredAnnotations[className]; if (result === undefined) { - result = {list: []}; + result = {list: [], requiredAtLeastOnce: false}; } return result; }; + +/** + * + * @param {Object<string,string[]>}elementValidAnnotations + */ UserPreferences.prototype.setElementValidAnnotations = function (elementValidAnnotations) { this._elementValidAnnotations = elementValidAnnotations; }; + +/** + * + * @param {string} className + * @returns {string[]} + */ UserPreferences.prototype.getElementValidAnnotations = function (className) { var result = this._elementValidAnnotations[className]; if (result === undefined) { diff --git a/frontend-js/src/test/js/map/data/UserPreferences-test.js b/frontend-js/src/test/js/map/data/UserPreferences-test.js index 28b2c51726..44ebb515d4 100644 --- a/frontend-js/src/test/js/map/data/UserPreferences-test.js +++ b/frontend-js/src/test/js/map/data/UserPreferences-test.js @@ -40,4 +40,23 @@ describe('UserPreferences', function () { object.setGuiPreference("test", "val"); assert.ok(object.getGuiPreference("test") === "val"); }); + + describe("update", function () { + it("requiredAtLeastOnce", function () { + return helper.readFile("testFiles/preferences.json").then(function (content) { + var object = new UserPreferences(JSON.parse(content)); + + var modifiedObject = new UserPreferences(JSON.parse(content)); + var newValue = !modifiedObject.getElementRequiredAnnotations("lcsb.mapviewer.model.map.species.Protein").requiredAtLeastOnce; + modifiedObject.getElementRequiredAnnotations("lcsb.mapviewer.model.map.species.Protein").requiredAtLeastOnce = newValue; + + assert.equal(newValue, !object.getElementRequiredAnnotations("lcsb.mapviewer.model.map.species.Protein").requiredAtLeastOnce); + + object.update(modifiedObject); + assert.equal(newValue, object.getElementRequiredAnnotations("lcsb.mapviewer.model.map.species.Protein").requiredAtLeastOnce); + }); + }); + }); + + }); -- GitLab