Commit e74860da authored by Piotr Gawron's avatar Piotr Gawron
Browse files

Merge branch '321-admin-panel-select-valid-annotations-layout-and-function' into 'master'

Resolve "Admin panel: Select valid annotations layout and function"

Closes #321

See merge request minerva/core!358
parents 640e8d56 fc3caf87
Pipeline #5911 passed with stage
in 1 minute and 56 seconds
......@@ -12,6 +12,27 @@ var MiriamType = require('./map/data/MiriamType');
var PrivilegeType = require('./map/data/PrivilegeType');
var ModificationStateType = require('./map/data/ModificationStateType');
/**
* @typedef {Object} BioEntityType
* @property {string} className - string identifying java class
* @property {string} name - common name of element
* @property {string} parentClass - string identifying parent java class
*/
/**
* @typedef {Object} BioEntityTypeTreeNode
* @property {string} text - string description of node
* @property {BioEntityTypeTreeNode[]} children - set if children types
* @property {BioEntityType} data - metadata of the type
*
*/
/**
*
* @param {Object|Configuration} json
* @constructor
*/
function Configuration(json) {
var self = this;
......@@ -66,23 +87,50 @@ function Configuration(json) {
}
}
/**
*
* @param {string} version
*/
Configuration.prototype.setVersion = function (version) {
this._version = version;
};
/**
*
* @returns {string}
*/
Configuration.prototype.getVersion = function () {
return this._version;
};
/**
*
* @param {string} buildDate
*/
Configuration.prototype.setBuildDate = function (buildDate) {
this._buildDate = buildDate;
};
/**
*
* @returns {string}
*/
Configuration.prototype.getBuildDate = function () {
return this._buildDate;
};
/**
*
* @param {string} gitHash
*/
Configuration.prototype.setGitHash = function (gitHash) {
this._gitHash = gitHash;
};
/**
*
* @returns {string}
*/
Configuration.prototype.getGitHash = function () {
return this._gitHash;
};
......@@ -410,6 +458,10 @@ Configuration.prototype.update = function (original) {
}
};
/**
*
* @returns {BioEntityTypeTreeNode}
*/
Configuration.prototype.getElementTypeTree = function () {
var elementTypes = this.getElementTypes();
var reactionTypes = this.getReactionTypes();
......
......@@ -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;
});
};
......
"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;
......@@ -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,7 +148,9 @@ AddProjectDialog.prototype.showValidatorsDialog = function () {
if (self._validatorsDialog === undefined) {
self._validatorsDialog = new ChooseValidatorsDialog({
element: Functions.createElement({type: "div"}),
customMap: null
configuration: self.getConfiguration(),
customMap: null,
serverConnector: self.getServerConnector()
});
promise = self._validatorsDialog.init();
} else {
......
......@@ -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;
......
......@@ -2,26 +2,41 @@
/* exported logger */
var AbstractGuiElement = require('../AbstractGuiElement');
var DualListbox = require('dual-listbox').DualListbox;
var AbstractAnnotatorsDialog = require('./AbstractAnnotatorsDialog');
var GuiConnector = require("../../GuiConnector");
var UserPreferences = require("../../map/data/UserPreferences");
var MultiCheckboxList = require("multi-checkbox-list");
var Functions = require('../../Functions');
// noinspection JSUnusedLocalSymbols
var logger = require('../../logger');
var Promise = require("bluebird");
/**
*
/**
*
* @param {Object} params
* @param {HTMLElement} params.element
* @param {CustomMap} params.customMap
* @param {Configuration} [params.configuration]
* @param {ServerConnector} [params.serverConnector]
*
* @constructor
*
* @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;
/**
*
*/
ChooseValidatorsDialog.prototype.createGui = function () {
var self = this;
var content = Functions.createElement({
......@@ -45,14 +60,19 @@ ChooseValidatorsDialog.prototype.createGui = function () {
self.getElement().appendChild(content);
};
/**
*
* @param {BioEntityType} elementType
* @returns {Promise}
*/
ChooseValidatorsDialog.prototype.setElementType = function (elementType) {
var self = this;
var configuration;
return ServerConnector.getConfiguration().then(function (result) {
return self.getServerConnector().getConfiguration().then(function (result) {
configuration = result;
return ServerConnector.getLoggedUser();
return self.getServerConnector().getLoggedUser();
}).then(function (user) {
var element = $("[name='annotatorListBox']", self.getElement())[0];
Functions.removeChildren(element);
......@@ -70,11 +90,108 @@ 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", name: "copy-from-validator", 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
* @param {Configuration} configuration
* @param {BioEntityType} elementType
* @param {HTMLElement} validAnnotationSelect
*/
ChooseValidatorsDialog.prototype.createValidAnnotationsDualListBox = function (user, configuration, elementType, validAnnotationSelect) {
var self = this;
var miriamTypes = configuration.getMiriamTypes();
......@@ -87,7 +204,6 @@ ChooseValidatorsDialog.prototype.createValidAnnotationsDualListBox = function (u
var miriamType = miriamTypes[i];
var entry = {name: miriamType.getCommonName(), value: miriamType.getName(), selected: false};
var selected = false;
for (var j = 0; j < validAnnotations.length; j++) {
if (miriamType.getName() === validAnnotations[j]) {
entry.selected = true;
......@@ -125,7 +241,10 @@ ChooseValidatorsDialog.prototype.createValidAnnotationsDualListBox = function (u
var elementAnnotators = {};
elementAnnotators[elementType.className] = validAnnotations;
data.setElementValidAnnotations(elementAnnotators);
return ServerConnector.updateUserPreferences({user: user, preferences: data}).then(null, GuiConnector.alert);
return self.getServerConnector().updateUserPreferences({
user: user,
preferences: data
}).catch(GuiConnector.alert);
};
checkboxList.addListener("select", function (element) {
......@@ -137,14 +256,23 @@ ChooseValidatorsDialog.prototype.createValidAnnotationsDualListBox = function (u
};
/**
*
* @param {User} user
* @param {Configuration} configuration
* @param {BioEntityType} elementType
* @param {HTMLElement} verifyAnnotationSelect
*/
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();
......@@ -154,7 +282,7 @@ ChooseValidatorsDialog.prototype.createVerifyAnnotationsDualListBox = function (
"annotation-list": requiredAnnotationsData.list
};
data.setElementRequiredAnnotations(elementRequiredAnnotations);
return ServerConnector.updateUserPreferences({user: user, preferences: data}).then(null, GuiConnector.alert);
return self.getServerConnector().updateUserPreferences({user: user, preferences: data}).catch(GuiConnector.alert);
}
});
checkbox.checked = requiredAnnotationsData.requiredAtLeastOnce;
......@@ -215,7 +343,7 @@ ChooseValidatorsDialog.prototype.createVerifyAnnotationsDualListBox = function (
"annotation-list": requiredAnnotationsData.list
};
data.setElementRequiredAnnotations(elementRequiredAnnotations);
return ServerConnector.updateUserPreferences({user: user, preferences: data}).then(null, GuiConnector.alert);
return self.getServerConnector().updateUserPreferences({user: user, preferences: data}).catch(GuiConnector.alert);
};
checkboxList.addListener("select", function (element) {
......@@ -227,9 +355,13 @@ ChooseValidatorsDialog.prototype.createVerifyAnnotationsDualListBox = function (
};
/**
*
* @returns {Promise}
*/
ChooseValidatorsDialog.prototype.init = function () {
var self = this;
return ServerConnector.getConfiguration().then(function (configuration) {
return self.getServerConnector().getConfiguration().then(function (configuration) {
var treeData = configuration.getElementTypeTree();
......@@ -248,10 +380,16 @@ ChooseValidatorsDialog.prototype.init = function () {
});
};
/**
*
*/
ChooseValidatorsDialog.prototype.destroy = function () {
$(this.getElement()).dialog("destroy");
};
/**
*
*/
ChooseValidatorsDialog.prototype.open = function () {
var self = this;
var div = self.getElement();
......
......@@ -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 () {
......
......@@ -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) {
......
......@@ -3,7 +3,6 @@
require("../../mocha-config");
var AddProjectDialog = require('../../../../main/js/gui/admin/AddProjectDialog');
var ConfigurationType = require('../../../../main/js/ConfigurationType');
var ServerConnector = require('../../ServerConnector-mock');
var ValidationError = require('../../../../main/js/ValidationError');
......@@ -23,13 +22,13 @@ describe('AddProjectDialog', function () {