diff --git a/build.properties.d/00_default.properties b/build.properties.d/00_default.properties index 0304440ef627ee453f646bc8eec4809dc1553024..9b8f8095befc01f3f9fba610ee61efbaa8c24fc5 100644 --- a/build.properties.d/00_default.properties +++ b/build.properties.d/00_default.properties @@ -62,6 +62,7 @@ BUILD_MODULE_EXT_RESOLVE_REFERENCES=ENABLED BUILD_EXT_REFERENCES_CUSTOM_RESOLVER=caosdb_default_person_reference BUILD_MODULE_EXT_EDITMODE_WYSIWYG_TEXT=DISABLED +BUILD_MODULE_EXT_PROPERTY_DISPLAY=DISABLED ############################################################################## # Navbar properties @@ -203,4 +204,5 @@ MODULE_DEPENDENCIES=( ckeditor.js ext_editmode_wysiwyg_text.js reference_resolver/caosdb_default_person.js + ext_prop_display.js ) diff --git a/conf/core/json/ext_prop_display.json b/conf/core/json/ext_prop_display.json new file mode 100644 index 0000000000000000000000000000000000000000..0967ef424bce6791893e9a57bb952f80fd536e93 --- /dev/null +++ b/conf/core/json/ext_prop_display.json @@ -0,0 +1 @@ +{} diff --git a/src/core/css/webcaosdb.css b/src/core/css/webcaosdb.css index 1c8f50be049d308efcac25e41d705b08d96d21e6..248f3444962a839193016a42dc4e9f730ba7d448 100644 --- a/src/core/css/webcaosdb.css +++ b/src/core/css/webcaosdb.css @@ -381,6 +381,14 @@ h5 { margin-right: 0px; } +body[data-hidden-properties="true"] .caosdb-v-hidden-property { + display: None; +} + +body[data-hidden-properties="true"] .caosdb-v-entity-being-edited .caosdb-v-hidden-property { + display: unset; +} + .caosdb-v-edit-drag { padding: 5px; } diff --git a/src/core/js/edit_mode.js b/src/core/js/edit_mode.js index 63b28b08a6c07d4c5b00795f5e9f87d1965e4031..ba478dcd90cc9f6899e678f543d1c928129e1df7 100644 --- a/src/core/js/edit_mode.js +++ b/src/core/js/edit_mode.js @@ -1359,6 +1359,7 @@ var edit_mode = new function () { doc.firstElementChild.appendChild(newrecord.firstElementChild); // TODO I dunno whats wrong here: xml -> str -> xml ??? var x = await transformation.transformEntities(str2xml(xml2str(doc))); + $(x[0]).addClass("caosdb-v-entity-being-edited"); return x[0]; } @@ -1618,6 +1619,8 @@ var edit_mode = new function () { app.entity = $(entity).clone(true)[0]; // remove preview stuff $(app.entity).find(".caosdb-preview-container").remove(); + // add class for styling the entity that's being edited + $(app.entity).addClass("caosdb-v-entity-being-edited"); edit_mode.smooth_replace(app.old, app.entity); edit_mode.add_save_button(app.entity, () => app.update(app.entity)); @@ -1897,7 +1900,9 @@ var edit_mode = new function () { this.create_new_entity = async function (role) { var empty_entity = str2xml('<Response><' + role + '/></Response>'); - return (await transformation.transformEntities(empty_entity))[0]; + var ent_element = await transformation.transformEntities(empty_entity); + $(ent_element).addClass("caosdb-v-entity-being-edited"); + return ent_element[0]; } this.remove_cancel_button = function (entity) { @@ -2097,4 +2102,4 @@ var edit_mode = new function () { */ $(document).ready(function () { edit_mode.init(); -}); \ No newline at end of file +}); diff --git a/src/core/js/ext_prop_display.js b/src/core/js/ext_prop_display.js new file mode 100644 index 0000000000000000000000000000000000000000..802e49c97bb0cac017e8e0bab013001098b848c1 --- /dev/null +++ b/src/core/js/ext_prop_display.js @@ -0,0 +1,209 @@ +/* + * This file is a part of the CaosDB Project. + * + * Copyright (C) 2022 IndiScale GmbH <info@indiscale.com> + * Copyright (C) 2022 Florian Spreckelsen <f.spreckelsen@indiscale.com> + * + * This program is free software: you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License as published by the Free + * Software Foundation, either version 3 of the License, or (at your option) any + * later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + * + */ +'use strict'; + +/** + * @requires jQuery (library) + * @requires log (singleton from loglevel library) + * @requires load_config (function from webcaosdb.js) + */ +var prop_display = new function ($, edit_mode, getEntityName, getEntityRole, getPropertyElements, getPropertyName, getUserName, getUserRoles, logger, load_config, query) { + + /** + * Return the property-display config file; `ext_prop_display.json` by + * default. + * + * @param {string} resource - file name of the config file + */ + this.load_config = async function (resource) { + + var conf = {}; + try { + resource = resource || "ext_prop_display.json"; + conf = await load_config(resource); + } catch (err) { + logger.error(err); + } + + return conf; + } + + this.getEntitiesInView = function () { + // Use all entities, both in entity panel and in preview. + return $(".caosdb-entity-panel,.caosdb-entity-preview"); + } + + this.unhideProperties = function (entities, conf, allTypes, userName, userRoles) { + + for (let ent of entities) { + let parents = getParents(ent).map(par => par.name); + let properties = getPropertyElements(ent); + // either the entity has matching parents OR it is the actual + // RecordType for which a rule is written. + if (parents.some(par => allTypes.allTypesOrChildren.includes(par)) || + (getEntityRole(ent) == "RecordType" && allTypes.allTypesOrChildren.includes(getEntityName(ent)))) { + // we know that there is at least one rule for this type (it is + // in `allTypes.allTypesOrChildren`), but we don't know which tp + // apply yet. + for (let typeName of Object.keys(conf)) { + let typeConf = conf[typeName]; + let allNames = allTypes.typesWithChildren[typeName]; + // only hide something if there is a match in at least one parent type + if (parents.some(par => allNames.includes(par)) || + (getEntityRole(ent) == "RecordType" && allNames.includes(getEntityName(ent)))) { + properties.forEach((prop, index) => { + if (this._hide_property(getPropertyName(prop), userName, userRoles, typeConf)) { + // Should be hidden by default but better safe than sorry + $(prop).addClass("caosdb-v-hidden-property").removeClass("caosdb-v-show-property"); + } else { + // show this property + $(prop).addClass("caosdb-v-show-property").removeClass("caosdb-v-hidden-property"); + } + }); + } + } + } else { + // no rules for this RecordType, so show all properties + properties.forEach((prop, index) => $(prop).addClass("caosdb-v-show-property").removeClass("caosdb-v-hidden-property")); + } + } + } + + this._hide_property = function (propname, userName, userRoles, conf) { + + // is this property only shown for certain users/groups? + if ((conf.show != undefined) && conf.show.length > 0) { + for (let def of conf.show) { + if (propname.toLowerCase() == def.name.toLowerCase()) { + if (!(def.users.includes(userName)) && !(userRoles.some(role => def.roles.includes(role)))) { + return true + } + } + } + } + + // is this property hidden for certain users/groups? + if ((conf.hide != undefined) && conf.hide.length > 0) { + for (let def of conf.hide) { + if (propname.toLowerCase() == def.name.toLowerCase()) { + if (def.users.includes(userName) || userRoles.some(role => def.roles.includes(role))) { + return true + } + } + } + } + + return false; + } + + this._getRecordTypes = async function (conf) { + + const parentTypes = Object.keys(conf); + + var typesWithChildren = {}; + var allTypesOrChildren = []; + + for (let parentName of parentTypes) { + const children = await query(`FIND RECORDTYPE "${parentName}"`); + const names = children.map(ent => getEntityName(ent)); + typesWithChildren[parentName] = names; + allTypesOrChildren = allTypesOrChildren.concat(names); + } + + return { + "typesWithChildren": typesWithChildren, + "allTypesOrChildren": allTypesOrChildren + }; + } + + this.unhideAllProperties = function () { + // Just show all initially hidden properties + $(".caosdb-v-hidden-property").removeClass("caosdb-v-hidden-property"); + } + + this._unhideAllPropertiesWrapper = function (original) { + // construct a function that wirst does the original work, then unhides + // all properties, then returns the original return values. + const result = function (entity) { + var original_return = undefined; + if (typeof original === "function") { + original_return = original(entity); + } + prop_display.unhideAllProperties(); + return original_return; + } + + return result; + } + + this._unhidePropertiesWrapper = function (original, conf, allTypes) { + // Same as above, but for when there actually may be something to hide + // (i.e., build variable is set and config is non-empty). + const result = function (entitiy) { + var original_return = undefined; + if (typeof original === "function") { + original_return = original(entitiy); + } + var entities = prop_display.getEntitiesInView(); + const userName = getUserName(); + const userRoles = getUserRoles(); + prop_display.unhideProperties(entities, conf, allTypes, userName, userRoles); + return original_return; + } + + return result; + } + + this.init = async function () { + const conf = await this.load_config(); + if (Object.keys(conf).length > 0) { + const allTypes = await this._getRecordTypes(conf); + var entities = this.getEntitiesInView(); + const userName = getUserName(); + const userRoles = getUserRoles(); + this.unhideProperties(entities, conf, allTypes, userName, userRoles); + // If we are in the edit mode, (un)hide properties after ending + // the editing of an entity + document.body.addEventListener(edit_mode.start_edit.type, (e) => { + edit_mode.app.onAfterShowResults = this._unhidePropertiesWrapper(edit_mode.app.onAfterShowResults, conf, allTypes); + }, true); + + } else { + // There are no properties to be hidden, so make this clear in HTML body + $("body").attr("data-hidden-properties", "false") + this.unhideAllProperties(); + document.body.addEventListener(edit_mode.start_edit.type, (e) => { + // also unhide properties when leaving the edit mode + // TODO(fspreck): We're lacking a proper state/event here in the + // edit mode, so do this on "init", since this is the state to which + // the state machine returns after either successfully saving an + // entity or canceling the edit. + edit_mode.app.onAfterShowResults = this._unhideAllPropertiesWrapper(edit_mode.app.onAfterShowResults); + }, true); + } + } +}($, edit_mode, getEntityName, getEntityRole, getPropertyElements, getPropertyName, getUserName, getUserRoles, log.getLogger("ext_prop_display"), load_config, query); + +$(document).ready(() => { + if ("${BUILD_MODULE_EXT_PROPERTY_DISPLAY}" == "ENABLED") { + caosdb_modules.register(prop_display); + } +}); diff --git a/src/core/webcaosdb.xsl b/src/core/webcaosdb.xsl index 9a0d6769f1901e860c7a2318fce28957d6461496..38b6461e8793d9063f1d8f0047df9232c138da54 100644 --- a/src/core/webcaosdb.xsl +++ b/src/core/webcaosdb.xsl @@ -66,6 +66,14 @@ <xsl:call-template name="caosdb-head-js" /> </head> <body> + <xsl:choose> + <xsl:when test="'${BUILD_MODULE_EXT_PROPERTY_DISPLAY}'='ENABLED'"> + <xsl:attribute name="data-hidden-properties">true</xsl:attribute> + </xsl:when> + <xsl:otherwise> + <xsl:attribute name="data-hidden-properties">false</xsl:attribute> + </xsl:otherwise> + </xsl:choose> <xsl:attribute name="data-response-count"> <xsl:value-of select="/Response/@count"/> </xsl:attribute> diff --git a/src/core/xsl/entity.xsl b/src/core/xsl/entity.xsl index 82de9e416c2e28f21cd3f386cc6e04419284dc5f..264136f09828dce4e2ba7d324ff09fc14db5842c 100644 --- a/src/core/xsl/entity.xsl +++ b/src/core/xsl/entity.xsl @@ -232,7 +232,15 @@ </xsl:template> <!-- PROPERTIES --> <xsl:template match="Property" mode="entity-body"> - <li class="list-group-item caosdb-v-property-row caosdb-f-entity-property"> + <li> + <xsl:choose> + <xsl:when test="'${BUILD_MODULE_EXT_PROPERTY_DISPLAY}'='ENABLED'"> + <xsl:attribute name="class">list-group-item caosdb-v-property-row caosdb-f-entity-property caosdb-v-hidden-property</xsl:attribute> + </xsl:when> + <xsl:otherwise> + <xsl:attribute name="class">list-group-item caosdb-v-property-row caosdb-f-entity-property</xsl:attribute> + </xsl:otherwise> + </xsl:choose> <xsl:attribute name="id"> <xsl:value-of select="generate-id()"/> </xsl:attribute> diff --git a/src/doc/extension/display_of_properties.rst b/src/doc/extension/display_of_properties.rst new file mode 100644 index 0000000000000000000000000000000000000000..b5fdfe30198cf5042be6ca940fdcf67220d834d9 --- /dev/null +++ b/src/doc/extension/display_of_properties.rst @@ -0,0 +1,86 @@ +Tweaking the display of properties +================================== + +Hide or show properties for specific roles and users +**************************************************** + +.. note:: + + This feature is part of CaosDB WebUI 0.10 and is not available for 0.9.X or + older. + +.. warning:: + + Hiding properties is purely cosmetics and should **never** be considered a + security feature. The hidden properties are still part of the server + response. + +Sometimes it is desirable to hide certain properties for specific users or +roles, e.g., when they might be irrelevant or confusing. For example, an +internal id might only be of interest to curators or administrators, whereas it +is entirely meaningless to most other users. + +To configure the hiding of properties, you first need to enable the build +variable ``BUILD_MODULE_EXT_PROPERTY_DISPLAY``. Then, the display of the +properties is configured in ``conf/ext/json/ext_prop_display.json``. In there, +properties of a specific RecordType can be hidden by specifying the name of the +property, and the names of the roles and/or users from whom it should be hidden. + +.. code-block:: json + + { + "RecordTypeName": { + "hide": [ + { + "name": "property name", + "roles": ["list", "of", "roles"], + "users": ["list", "of", "users"] + }, + ... + ] + }, + ... + } + +In the same way but using the ``show`` keyword, properties can be hidden for +everyone **but** the specified users/roles: + +.. code-block:: json + + { + "RecordTypeName": { + "show": [ + { + "name": "property name", + "roles": ["list", "of", "roles"], + "users": ["list", "of", "users"] + }, + ... + ] + }, + ... + } + + +For example, using the data from demo.indiscale.com, the following would hide +the ``price`` of all ``MusicalInstruments`` from ``anonymous`` and their +``Manufacturer`` from the ``admin`` user. + +.. code-block:: json + + { + "MusicalInstrument": { + "hide": [ + {"name": "price", "roles": ["anonymous"], "users": []}, + {"name": "Manufacturer", "roles": [], "users": ["admin"]} + ] + } + } + +Future +****** + +In the future, this feature will be extended to allow the RecordType-wise +`sorting <https://gitlab.com/caosdb/caosdb-webui/-/issues/189>`__ of properties +and to `toggle <https://gitlab.com/caosdb/caosdb-webui/-/issues/190>`__ +properties. diff --git a/test/core/js/modules/ext_prop_display.js.js b/test/core/js/modules/ext_prop_display.js.js new file mode 100644 index 0000000000000000000000000000000000000000..18d2c54056609bf0cc6aafca2d06705ad7a40b02 --- /dev/null +++ b/test/core/js/modules/ext_prop_display.js.js @@ -0,0 +1,263 @@ +/* + * This file is a part of the CaosDB Project. + * + * Copyright (C) 2022 IndiScale GmbH <info@indiscale.com> + * Copyright (C) 2022 Florian Spreckelsen <f.spreckelsen@indiscale.com> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + */ + +'use strict'; + +QUnit.module("ext_prop_display.js", { + before: function (assert) { + // setup before module + }, + beforeEach: function (assert) { + // setup before each test + // entity list, one entity with three properties (ids 1,2,3 for + // testing), all of them hidden by default. + $(document.body).append('<div class="caosdb-f-main-entities prop-display-test-entities"><div id=115 class="caosdb-entity-panel"><div class="caosdb-entity-panel-heading"><span class="caosdb-f-parent-list"><span class="caosdb-parent-item"><a class="caosdb-parent-name" href="https://demo.indiscale.com/Entity/110">Guitar</a></span></span></div><div class="caosdb-entity-panel-body"><ul class="list-group caosdb-properties"><li id=1 class="caosdb-v-property-row caosdb-f-entity-property caosdb-v-hidden-property"><div class="row"><div class="caosdb-v-property-left-col"><span class="caosdb-property-name">first prop</span></div><div class="caosdb-f-property-value"><span class="caosdb-f-property-single-raw-value caosdb-property-text-value caosdb-f-property-text-value caosdb-v-property-text-value">48.0</span><span class="caosdb-unit">€</span></div></div></li><li id=2 class="caosdb-v-property-row caosdb-f-entity-property caosdb-v-hidden-property"><div class="row"><div class="caosdb-v-property-left-col"><span class="caosdb-property-name">second prop</span></div><div class="caosdb-f-property-value"><span class="caosdb-f-property-single-raw-value caosdb-property-text-value caosdb-f-property-text-value caosdb-v-property-text-value">48.0</span><span class="caosdb-unit">€</span></div></div></li><li id=3 class="caosdb-v-property-row caosdb-f-entity-property caosdb-v-hidden-property"><div class="row"><div class="caosdb-v-property-left-col"><span class="caosdb-property-name">third prop</span></div><div class="caosdb-f-property-value"><span class="caosdb-f-property-single-raw-value caosdb-property-text-value caosdb-f-property-text-value caosdb-v-property-text-value">48.0</span><span class="caosdb-unit">€</span></div></div></li></ul></div></div></div>'); + }, + afterEach: function (assert) { + // teardown after each test + $(".prop-display-test-entities").remove(); + }, + after: function (assert) { + // teardown after module + } +}); + +QUnit.test("unhide all properties", function (assert) { + assert.ok(prop_display.unhideAllProperties, "unhideAllProperties available"); + assert.equal($(document).find(".caosdb-v-hidden-property").length, 3, "all properties hidden initially"); + prop_display.unhideAllProperties(); + assert.equal($(document).find(".caosdb-v-hidden-property").length, 0, "no hidden properties after unhiding"); +}); + +QUnit.test("hide properties garbage type", function (assert) { + assert.ok(prop_display.getEntitiesInView, "getEntitiesInView available"); + assert.ok(prop_display.unhideProperties, "unhideProperties available"); + const conf = { + "DoesntExist": { + "hide": [{ + "name": "first prop", + "roles": ["some_role"], + "users": ["someone"] + }] + } + }; + // only one garbage type + const allTypes = { + "typesWithChildren": { + "DoesntExist": ["DoesntExist"] + }, + "allTypesOrChildren": ["DoesntExist"] + }; + const userName = "someone"; + const userRoles = ["some_role", "some_other_role"]; + const entities = prop_display.getEntitiesInView(); + assert.equal(entities.length, 1, "only one entity in test data"); + assert.equal($(document).find(".caosdb-v-hidden-property").length, 3, "all properties hidden initially"); + prop_display.unhideProperties(entities, conf, allTypes, userName, userRoles); + assert.equal($(document).find(".caosdb-v-hidden-property").length, 0, "no garbage-type entity, so no hidden properties"); + assert.equal($(document).find(".caosdb-v-show-property").length, 3, "all properties are being shown"); +}); + +QUnit.test("hide properties garbage property", function (assert) { + assert.ok(prop_display.getEntitiesInView, "getEntitiesInView available"); + assert.ok(prop_display.unhideProperties, "unhideProperties available"); + const conf = { + "MusicalInstrument": { + "hide": [{ + "name": "prop does not exist", + "roles": ["some_role"], + "users": ["someone"] + }] + } + }; + const allTypes = { + "typesWithChildren": { + "MusicalInstrument": ["MusicalInstrument", "Guitar"] + }, + "allTypesOrChildren": ["MusicalInstrument", "Guitar"] + }; + const userName = "someone"; + const userRoles = ["some_role", "some_other_role"]; + const entities = prop_display.getEntitiesInView(); + assert.equal(entities.length, 1, "only one entity in test data"); + assert.equal($(document).find(".caosdb-v-hidden-property").length, 3, "all properties hidden initially"); + prop_display.unhideProperties(entities, conf, allTypes, userName, userRoles); + assert.equal($(document).find(".caosdb-v-hidden-property").length, 0, "no garbage property, so no hidden properties"); + assert.equal($(document).find(".caosdb-v-show-property").length, 3, "all properties are being shown"); +}); + + +QUnit.test("hide properties", function (assert) { + assert.ok(prop_display.getEntitiesInView, "getEntitiesInView available"); + assert.ok(prop_display.unhideProperties, "unhideProperties available"); + const conf = { + "MusicalInstrument": { + "hide": [{ + "name": "first prop", + "roles": ["some_role"], + "users": ["someone"] + }, + { + "name": "second prop", + "roles": [], + "users": ["someone else"] + }, + { + "name": "third prop", + "roles": ["some_other_role"], + "users": ["someone else"] + } + ] + } + }; + const allTypes = { + "typesWithChildren": { + "MusicalInstrument": ["MusicalInstrument", "Guitar"] + }, + "allTypesOrChildren": ["MusicalInstrument", "Guitar"] + }; + var userName = "someone"; + var userRoles = ["some_role"]; + const entities = prop_display.getEntitiesInView(); + assert.equal(entities.length, 1, "only one entity in test data"); + assert.equal($(document).find(".caosdb-v-hidden-property").length, 3, "all properties hidden initially"); + prop_display.unhideProperties(entities, conf, allTypes, userName, userRoles); + assert.equal($(document).find(".caosdb-v-hidden-property").length, 1, "exactly one hidden property"); + assert.equal($(document).find(".caosdb-v-show-property").length, 2, "the remaining two are shown"); + assert.equal($("#1").hasClass("caosdb-v-hidden-property"), true, "first prop hidden"); + assert.equal($("#2").hasClass("caosdb-v-show-property"), true, "second prop shown"); + assert.equal($("#3").hasClass("caosdb-v-show-property"), true, "third prop shown"); + + // reset + prop_display.unhideProperties(entities, conf, allTypes, "", []); + assert.equal($(document).find(".caosdb-v-show-property").length, 3, "all shown after reset"); + + userRoles = ["some_other_role"]; + prop_display.unhideProperties(entities, conf, allTypes, userName, userRoles); + assert.equal($(document).find(".caosdb-v-hidden-property").length, 2, "two hidden properties"); + assert.equal($(document).find(".caosdb-v-show-property").length, 1, "the remaining one is shown"); + assert.equal($("#1").hasClass("caosdb-v-hidden-property"), true, "first prop hidden"); + assert.equal($("#2").hasClass("caosdb-v-show-property"), true, "second prop shown"); + assert.equal($("#3").hasClass("caosdb-v-hidden-property"), true, "third prop hidden"); + + // reset + prop_display.unhideProperties(entities, conf, allTypes, "", []); + assert.equal($(document).find(".caosdb-v-show-property").length, 3, "all shown after reset"); + + userName = "someone else"; + prop_display.unhideProperties(entities, conf, allTypes, userName, userRoles); + assert.equal($(document).find(".caosdb-v-hidden-property").length, 2, "two hidden properties"); + assert.equal($(document).find(".caosdb-v-show-property").length, 1, "the remaining one is shown"); + assert.equal($("#1").hasClass("caosdb-v-show-property"), true, "first prop shown"); + assert.equal($("#2").hasClass("caosdb-v-hidden-property"), true, "second prop hidden"); + assert.equal($("#3").hasClass("caosdb-v-hidden-property"), true, "third prop hidden"); + + // reset + prop_display.unhideProperties(entities, conf, allTypes, "", []); + assert.equal($(document).find(".caosdb-v-show-property").length, 3, "all shown after reset"); + + userRoles = ["some_role", "some_other_role"] + prop_display.unhideProperties(entities, conf, allTypes, userName, userRoles); + assert.equal($(document).find(".caosdb-v-hidden-property").length, 3, "two hidden properties"); + assert.equal($(document).find(".caosdb-v-show-property").length, 0, "None is shown"); + assert.equal($("#1").hasClass("caosdb-v-hidden-property"), true, "first prop hidden"); + assert.equal($("#2").hasClass("caosdb-v-hidden-property"), true, "second prop hidden"); + assert.equal($("#3").hasClass("caosdb-v-hidden-property"), true, "third prop hidden"); + +}); + +QUnit.test("show properties", function (assert) { + assert.ok(prop_display.getEntitiesInView, "getEntitiesInView available"); + assert.ok(prop_display.unhideProperties, "unhideProperties available"); + const conf = { + "MusicalInstrument": { + "show": [{ + "name": "first prop", + "roles": ["some_role"], + "users": ["someone"] + }, + { + "name": "second prop", + "roles": [], + "users": ["someone else"] + }, + { + "name": "third prop", + "roles": ["some_other_role"], + "users": ["someone else"] + } + ] + } + }; + const allTypes = { + "typesWithChildren": { + "MusicalInstrument": ["MusicalInstrument", "Guitar"] + }, + "allTypesOrChildren": ["MusicalInstrument", "Guitar"] + }; + var userName = "someone"; + var userRoles = ["some_role"]; + const entities = prop_display.getEntitiesInView(); + assert.equal(entities.length, 1, "only one entity in test data"); + assert.equal($(document).find(".caosdb-v-hidden-property").length, 3, "all properties hidden initially"); + prop_display.unhideProperties(entities, conf, allTypes, userName, userRoles); + assert.equal($(document).find(".caosdb-v-hidden-property").length, 2, "two hidden properties"); + assert.equal($(document).find(".caosdb-v-show-property").length, 1, "the remaining one shown"); + assert.equal($("#1").hasClass("caosdb-v-show-property"), true, "first prop shown"); + assert.equal($("#2").hasClass("caosdb-v-hidden-property"), true, "second prop hidden"); + assert.equal($("#3").hasClass("caosdb-v-hidden-property"), true, "third prop hidden"); + + // reset + prop_display.unhideProperties(entities, conf, allTypes, "", []); + assert.equal($(document).find(".caosdb-v-hidden-property").length, 3, "all hidden after reset"); + + userRoles = ["some_other_role"]; + prop_display.unhideProperties(entities, conf, allTypes, userName, userRoles); + assert.equal($(document).find(".caosdb-v-hidden-property").length, 1, "one hidden properties"); + assert.equal($(document).find(".caosdb-v-show-property").length, 2, "the remaining two are shown"); + assert.equal($("#1").hasClass("caosdb-v-show-property"), true, "first prop shown"); + assert.equal($("#2").hasClass("caosdb-v-hidden-property"), true, "second prop hidden"); + assert.equal($("#3").hasClass("caosdb-v-show-property"), true, "third prop shown"); + + // reset + prop_display.unhideProperties(entities, conf, allTypes, "", []); + assert.equal($(document).find(".caosdb-v-hidden-property").length, 3, "all hidden after reset"); + + userName = "someone else"; + prop_display.unhideProperties(entities, conf, allTypes, userName, userRoles); + assert.equal($(document).find(".caosdb-v-hidden-property").length, 1, "one hidden property"); + assert.equal($(document).find(".caosdb-v-show-property").length, 2, "the remaining ones are shown"); + assert.equal($("#1").hasClass("caosdb-v-hidden-property"), true, "first prop hidden"); + assert.equal($("#2").hasClass("caosdb-v-show-property"), true, "second prop shown"); + assert.equal($("#3").hasClass("caosdb-v-show-property"), true, "third prop shown"); + + // reset + prop_display.unhideProperties(entities, conf, allTypes, "", []); + assert.equal($(document).find(".caosdb-v-hidden-property").length, 3, "all hidden after reset"); + + userRoles = ["some_role", "some_other_role"] + prop_display.unhideProperties(entities, conf, allTypes, userName, userRoles); + assert.equal($(document).find(".caosdb-v-hidden-property").length, 0, "no hidden properties"); + assert.equal($(document).find(".caosdb-v-show-property").length, 3, "All are shown"); + assert.equal($("#1").hasClass("caosdb-v-show-property"), true, "first prop shown"); + assert.equal($("#2").hasClass("caosdb-v-show-property"), true, "second prop shown"); + assert.equal($("#3").hasClass("caosdb-v-show-property"), true, "third prop shown"); + +});