diff --git a/omeroweb/webclient/static/webclient/css/dusty.css b/omeroweb/webclient/static/webclient/css/dusty.css index b92e9402a7..035cb5e379 100755 --- a/omeroweb/webclient/static/webclient/css/dusty.css +++ b/omeroweb/webclient/static/webclient/css/dusty.css @@ -478,7 +478,6 @@ button::-moz-focus-inner { .tag_annotation_wrapper .tag, .imagefilter .tag { display:inline-block; - float:left; margin:1px 3px; position:relative; diff --git a/omeroweb/webclient/static/webclient/javascript/ome.right_panel_comments_pane.js b/omeroweb/webclient/static/webclient/javascript/ome.right_panel_comments_pane.js index b4c18f9671..adf4e5f703 100644 --- a/omeroweb/webclient/static/webclient/javascript/ome.right_panel_comments_pane.js +++ b/omeroweb/webclient/static/webclient/javascript/ome.right_panel_comments_pane.js @@ -81,6 +81,13 @@ var CommentsPane = function CommentsPane($element, opts) { }, }); + var compareParentName = function(a, b){ + if (!a.parent.name || !b.parent.name) { + return 1; + } + return a.parent.name.toLowerCase() > b.parent.name.toLowerCase() ? 1 : -1; + }; + this.render = function render() { @@ -95,7 +102,7 @@ var CommentsPane = function CommentsPane($element, opts) { }); request = request.join("&"); - $.getJSON(WEBCLIENT.URLS.webindex + "api/annotations/?type=comment&" + request, function(data){ + $.getJSON(WEBCLIENT.URLS.webindex + "api/annotations/?parents=true&type=comment&" + request, function(data){ // manipulate data... @@ -115,15 +122,117 @@ var CommentsPane = function CommentsPane($element, opts) { return ann; }); + var inh_anns = [] + if (data.hasOwnProperty("parents")){ + inh_anns = data.parents.annotations.map(function(ann) { + ann.owner = experimenters[ann.owner.id]; + if (ann.link && ann.link.owner) { + ann.link.owner = experimenters[ann.link.owner.id]; + } + ann.addedBy = [ann.link.owner.id]; + let class_ = ann.link.parent.class; + let id_ = '' + ann.link.parent.id; + children = data.parents.lineage[class_][id_]; + class_ = children[0].class; + ann.childClass = class_.substring(0, class_.length - 1); + ann.childNames = []; + if (children[0].hasOwnProperty("name")){ + for(j = 0; j < children.length; j++){ + ann.childNames.push(children[j].name); + } + } + return ann; + }); + } + + // If we are batch annotating multiple objects, we show a summary of each ann + if (objects.length > 1) { + + // Map ann.id to summary for that ann + var summary = {}; + anns.forEach(function(ann){ + var annId = ann.id, + linkOwner = ann.link.owner.id; + if (summary[annId] === undefined) { + ann.canRemove = false; + ann.canRemoveCount = 0; + ann.links = []; + ann.addedBy = []; + summary[annId] = ann; + } + // Add link to list... + var l = ann.link; + // slice parent class 'ProjectI' > 'Project' + l.parent.class = l.parent.class.slice(0, -1); + summary[annId].links.push(l); + + // ...and summarise other properties on the ann + if (l.permissions.canDelete) { + summary[annId].canRemoveCount += 1; + } + summary[annId].canRemove = summary[annId].canRemove || l.permissions.canDelete; + if (summary[annId].addedBy.indexOf(linkOwner) === -1) { + summary[annId].addedBy.push(linkOwner); + } + }); + + // convert summary back to list of 'anns' + anns = []; + for (var annId in summary) { + if (summary.hasOwnProperty(annId)) { + summary[annId].links.sort(compareParentName); + anns.push(summary[annId]); + } + } + + // Map ann.id to summary for that ann + summary = {}; + inh_anns.forEach(function(ann){ + var annId = ann.id, + linkOwner = ann.link.owner.id; + if (summary[annId] === undefined) { + ann.canRemove = false; + ann.canRemoveCount = 0; + ann.links = []; + ann.addedBy = []; + summary[annId] = ann; + } + // Add link to list... + var l = ann.link; + // slice parent class 'ProjectI' > 'Project' + l.parent.class = l.parent.class.slice(0, -1); + summary[annId].links.push(l); + + // ...and summarise other properties on the ann + if (summary[annId].addedBy.indexOf(linkOwner) === -1) { + summary[annId].addedBy.push(linkOwner); + } + for(j = 0; j < ann.childNames; j++){ + summary[annId].childNames.push(ann.childNames[j]); + } + }); + + // convert summary back to list of 'anns' + inh_anns = []; + for (var annId in summary) { + if (summary.hasOwnProperty(annId)) { + summary[annId].links.sort(compareParentName); + inh_anns.push(summary[annId]); + } + } + } + // Show most recent comments at the top anns.sort(function(a, b) { return a.date < b.date ? 1 : -1; }); - - // Remove duplicates (same comment on multiple objects) - anns = anns.filter(function(ann, idx){ - // already sorted, so just compare with last item - return (idx === 0 || anns[idx - 1].id !== ann.id); + hierarchy = {"ProjectI":0, "DatasetI":1, "ScreenI":2, "PlateI":3, "PlateAcquisitionI":4, "WellI":5} + inh_anns.sort(function(a, b) { + if (hierarchy[a.link.parent.class] != hierarchy[b.link.parent.class]){ + return hierarchy[a.link.parent.class] > hierarchy[b.link.parent.class] ? 1 : -1; + } else{ + return a.date < b.date ? 1 : -1; + } }); // Update html... @@ -131,8 +240,19 @@ var CommentsPane = function CommentsPane($element, opts) { if (anns.length > 0) { html = commentsTempl({'anns': anns, 'static': WEBCLIENT.URLS.static_webclient, - 'webindex': WEBCLIENT.URLS.webindex}); + 'webindex': WEBCLIENT.URLS.webindex, + 'userId': WEBCLIENT.USER.id, + 'isInherited': false}); } + if (inh_anns.length > 0) { + html = html + commentsTempl({'anns': inh_anns, + 'static': WEBCLIENT.URLS.static_webclient, + 'webindex': WEBCLIENT.URLS.webindex, + 'userId': WEBCLIENT.USER.id, + 'isInherited': true}); + } + + $("#comments_spinner").hide(); $comments_container.html(html); diff --git a/omeroweb/webclient/static/webclient/javascript/ome.right_panel_fileanns_pane.js b/omeroweb/webclient/static/webclient/javascript/ome.right_panel_fileanns_pane.js index a823b96297..3e336a5f64 100644 --- a/omeroweb/webclient/static/webclient/javascript/ome.right_panel_fileanns_pane.js +++ b/omeroweb/webclient/static/webclient/javascript/ome.right_panel_fileanns_pane.js @@ -143,7 +143,7 @@ var FileAnnsPane = function FileAnnsPane($element, opts) { }); request = request.join("&"); - $.getJSON(WEBCLIENT.URLS.webindex + "api/annotations/?type=file&" + request, function(data){ + $.getJSON(WEBCLIENT.URLS.webindex + "api/annotations/?parents=true&type=file&" + request, function(data){ var checkboxesAreVisible = $( "#fileanns_container input[type=checkbox]:visible" @@ -170,11 +170,36 @@ var FileAnnsPane = function FileAnnsPane($element, opts) { // Don't show companion files anns = anns.filter(isNotCompanionFile); - - // If we are batch annotating multiple objects, we show a summary of each tag + var inh_anns = [] + if (data.hasOwnProperty("parents")){ + inh_anns = data.parents.annotations.map(function(ann) { + ann.owner = experimenters[ann.owner.id]; + if (ann.link && ann.link.owner) { + ann.link.owner = experimenters[ann.link.owner.id]; + } + ann.addedBy = [ann.link.owner.id]; + ann.file.size = ann.file.size !== null ? ann.file.size.filesizeformat() : ""; + let class_ = ann.link.parent.class; + let id_ = '' + ann.link.parent.id; + children = data.parents.lineage[class_][id_]; + class_ = children[0].class; + ann.childClass = class_.substring(0, class_.length - 1); + ann.childNames = []; + if (children[0].hasOwnProperty("name")){ + for(j = 0; j < children.length; j++){ + ann.childNames.push(children[j].name); + } + } + return ann; + }); + inh_anns = inh_anns.filter(isNotCompanionFile); + } + + + // If we are batch annotating multiple objects, we show a summary of each ann if (objects.length > 1) { - // Map tag.id to summary for that tag + // Map ann.id to summary for that ann var summary = {}; anns.forEach(function(ann){ var annId = ann.id, @@ -210,6 +235,42 @@ var FileAnnsPane = function FileAnnsPane($element, opts) { anns.push(summary[annId]); } } + + // Map ann.id to summary for that ann + summary = {}; + inh_anns.forEach(function(ann){ + var annId = ann.id, + linkOwner = ann.link.owner.id; + if (summary[annId] === undefined) { + ann.canRemove = false; + ann.canRemoveCount = 0; + ann.links = []; + ann.addedBy = []; + summary[annId] = ann; + } + // Add link to list... + var l = ann.link; + // slice parent class 'ProjectI' > 'Project' + l.parent.class = l.parent.class.slice(0, -1); + summary[annId].links.push(l); + + // ...and summarise other properties on the ann + if (summary[annId].addedBy.indexOf(linkOwner) === -1) { + summary[annId].addedBy.push(linkOwner); + } + for(j = 0; j < ann.childNames; j++){ + summary[annId].childNames.push(ann.childNames[j]); + } + }); + + // convert summary back to list of 'anns' + inh_anns = []; + for (var annId in summary) { + if (summary.hasOwnProperty(annId)) { + summary[annId].links.sort(compareParentName); + inh_anns.push(summary[annId]); + } + } } // Update html... @@ -217,7 +278,14 @@ var FileAnnsPane = function FileAnnsPane($element, opts) { if (anns.length > 0) { html = filesTempl({'anns': anns, 'webindex': WEBCLIENT.URLS.webindex, - 'userId': WEBCLIENT.USER.id}); + 'userId': WEBCLIENT.USER.id, + 'isInherited': false}); + } + if (inh_anns.length > 0) { + html = html + filesTempl({'anns': inh_anns, + 'webindex': WEBCLIENT.URLS.webindex, + 'userId': WEBCLIENT.USER.id, + 'isInherited': true}); } $fileanns_container.html(html); @@ -228,7 +296,7 @@ var FileAnnsPane = function FileAnnsPane($element, opts) { } $(".tooltip", $fileanns_container).tooltip_init(); }); - + } }; diff --git a/omeroweb/webclient/static/webclient/javascript/ome.right_panel_mapanns_pane.js b/omeroweb/webclient/static/webclient/javascript/ome.right_panel_mapanns_pane.js index 8fca4b09a1..fe1c1b7cc5 100644 --- a/omeroweb/webclient/static/webclient/javascript/ome.right_panel_mapanns_pane.js +++ b/omeroweb/webclient/static/webclient/javascript/ome.right_panel_mapanns_pane.js @@ -206,8 +206,10 @@ var MapAnnsPane = function MapAnnsPane($element, opts) { 'showTableHead': false, 'showNs': false, 'clientMapAnn': true, 'showParent': showParent}); html = html + mapAnnsTempl({'anns': map_annotations, 'isInherited': false, 'showTableHead': false, 'showNs': true, 'clientMapAnn': false, 'showParent': showParent}); - html = html + mapAnnsTempl({'anns': inh_map_annotations, 'isInherited': true, - 'showTableHead': false, 'showNs': true, 'clientMapAnn': false, 'showParent': showParent}); + if (inh_map_annotations.length > 0) { + html = html + mapAnnsTempl({'anns': inh_map_annotations, 'isInherited': true, + 'showTableHead': false, 'showNs': true, 'clientMapAnn': false, 'showParent': showParent}); + } $mapAnnContainer.html(html); // re-use the ajaxdata to set Object IDS data on the parent container diff --git a/omeroweb/webclient/static/webclient/javascript/ome.right_panel_ratings_pane.js b/omeroweb/webclient/static/webclient/javascript/ome.right_panel_ratings_pane.js index 76c17b17f8..9635bef053 100644 --- a/omeroweb/webclient/static/webclient/javascript/ome.right_panel_ratings_pane.js +++ b/omeroweb/webclient/static/webclient/javascript/ome.right_panel_ratings_pane.js @@ -96,9 +96,37 @@ var RatingsPane = function RatingsPane($element, opts) { $("#ratings_spinner").show(); - $.getJSON(WEBCLIENT.URLS.webindex + "api/annotations/?type=rating&" + request, function(data){ + $.getJSON(WEBCLIENT.URLS.webindex + "api/annotations/?parents=true&type=rating&" + request, function(data){ + + var experimenters = data.experimenters.reduce(function(prev, exp){ + prev[exp.id + ""] = exp; + return prev; + }, {}); var anns = data.annotations; + var inh_anns = []; + if (data.hasOwnProperty("parents")){ + inh_anns = data.parents.annotations.map(function(ann) { + ann.owner = experimenters[ann.owner.id]; + if (ann.link && ann.link.owner) { + ann.link.owner = experimenters[ann.link.owner.id]; + } + ann.addedBy = [ann.link.owner.id]; + let class_ = ann.link.parent.class; + let id_ = '' + ann.link.parent.id; + children = data.parents.lineage[class_][id_]; + class_ = children[0].class; + ann.childClass = class_.substring(0, class_.length - 1); + ann.childNames = []; + if (children[0].hasOwnProperty("name")){ + for(j = 0; j < children.length; j++){ + ann.childNames.push(children[j].name); + } + } + return ann; + }); + } + var sum = anns.reduce(function(prev, ann){ return prev + ann.longValue; }, 0); @@ -112,7 +140,8 @@ var RatingsPane = function RatingsPane($element, opts) { 'canAnnotate': canAnnotate, 'average': average, 'count': anns.length, - 'static': WEBCLIENT.URLS.static_webclient}); + 'static': WEBCLIENT.URLS.static_webclient, + 'isInherited': false}); $("#ratings_spinner").hide(); $rating_annotations.html(html); diff --git a/omeroweb/webclient/static/webclient/javascript/ome.right_panel_tags_pane.js b/omeroweb/webclient/static/webclient/javascript/ome.right_panel_tags_pane.js index 7aa858bc64..b0f6c0d5d3 100644 --- a/omeroweb/webclient/static/webclient/javascript/ome.right_panel_tags_pane.js +++ b/omeroweb/webclient/static/webclient/javascript/ome.right_panel_tags_pane.js @@ -124,7 +124,7 @@ var TagPane = function TagPane($element, opts) { }); request = request.join("&"); - var annsUrl = WEBCLIENT.URLS.webindex + "api/annotations/?type=tag&" + request + var annsUrl = WEBCLIENT.URLS.webindex + "api/annotations/?parents=true&type=tag&" + request $.getJSON(annsUrl, function(data){ // manipulate data... @@ -143,12 +143,39 @@ var TagPane = function TagPane($element, opts) { } // AddedBy IDs for filtering tag.addedBy = [tag.link.owner.id]; - tag.textValue = tag.textValue; - tag.description = tag.description; + tag.textValue = _.escape(tag.textValue); + tag.description = _.escape(tag.description); tag.canRemove = tag.link.permissions.canDelete; return tag; }); + var inh_tags = [] + if (data.hasOwnProperty("parents")){ + inh_tags = data.parents.annotations.map(function(tag) { + tag.owner = experimenters[tag.owner.id]; + if (tag.link && tag.link.owner) { + tag.link.owner = experimenters[tag.link.owner.id]; + } + // AddedBy IDs for filtering + tag.addedBy = [tag.link.owner.id]; + tag.textValue = _.escape(tag.textValue); + tag.description = _.escape(tag.description); + tag.canRemove = false; + let class_ = tag.link.parent.class; + let id_ = '' + tag.link.parent.id; + children = data.parents.lineage[class_][id_]; + class_ = children[0].class; + tag.childClass = class_.substring(0, class_.length - 1); + tag.childNames = []; + if (children[0].hasOwnProperty("name")){ + for(j = 0; j < children.length; j++){ + tag.childNames.push(children[j].name); + } + } + return tag; + }); + } + // If we are batch annotating multiple objects, we show a summary of each tag if (objects.length > 1) { @@ -158,12 +185,14 @@ var TagPane = function TagPane($element, opts) { var tagId = tag.id, linkOwner = tag.link.owner.id; if (summary[tagId] === undefined) { - summary[tagId] = {'textValue': _.escape(tag.textValue), + summary[tagId] = {'textValue': tag.textValue, + 'description': tag.description, 'id': tag.id, 'canRemove': false, 'canRemoveCount': 0, 'links': [], - 'addedBy': [] + 'addedBy': [], + 'owner': experimenters[linkOwner] }; } // Add link to list... @@ -190,19 +219,68 @@ var TagPane = function TagPane($element, opts) { tags.push(summary[tagId]); } } + + // Map tag.id to summary for that tag + summary = {}; + inh_tags.forEach(function(tag){ + var tagId = tag.id, + linkOwner = tag.link.owner.id; + if (summary[tagId] === undefined) { + summary[tagId] = {'textValue': _.escape(tag.textValue), + 'description': _.escape(tag.description), + 'id': tag.id, + 'canRemove': false, + 'canRemoveCount': 0, + 'links': [], + 'addedBy': [], + 'childClass': tag.childClass, + 'childNames': tag.childNames, + 'owner': experimenters[linkOwner] + }; + } + // Add link to list... + var l = tag.link; + // slice parent class 'ProjectI' > 'Project' + l.parent.class = l.parent.class.slice(0, -1); + summary[tagId].links.push(l); + + // ...and summarise other properties on the tag + if (summary[tagId].addedBy.indexOf(linkOwner) === -1) { + summary[tagId].addedBy.push(linkOwner); + } + for(j = 0; j < tag.childNames; j++){ + summary[tagId].childNames.push(tag.childNames[j]); + } + }); + + // convert summary back to list of 'tags' + inh_tags = []; + for (var tagId in summary) { + if (summary.hasOwnProperty(tagId)) { + summary[tagId].links.sort(compareParentName); + inh_tags.push(summary[tagId]); + } + } } // Update html... var html = tagTmpl({'tags': tags, 'webindex': WEBCLIENT.URLS.webindex, - 'userId': WEBCLIENT.USER.id}); + 'userId': WEBCLIENT.USER.id, + 'isInherited': false}); + if (inh_tags.length > 0) { + html = html + tagTmpl({'tags': inh_tags, + 'webindex': WEBCLIENT.URLS.webindex, + 'userId': WEBCLIENT.USER.id, + 'isInherited': true}); + } $tags_container.html(html); // Finish up... OME.filterAnnotationsAddedBy(); $(".tooltip", $tags_container).tooltip_init(); }); - + } }; diff --git a/omeroweb/webclient/templates/webclient/annotations/comments_underscore.html b/omeroweb/webclient/templates/webclient/annotations/comments_underscore.html index bdf030cef3..a2956f163f 100644 --- a/omeroweb/webclient/templates/webclient/annotations/comments_underscore.html +++ b/omeroweb/webclient/templates/webclient/annotations/comments_underscore.html @@ -1,3 +1,7 @@ +<% if (isInherited) { %> +

Inherited comments



+ <% } %> + <% _.each(anns, function(ann) { %>
@@ -12,11 +16,16 @@ <%- ann.owner.firstName %> <%- ann.owner.lastName %> - at - <% print(OME.formatDate(ann.link.date)) %> + <% if (isInherited) { %> + on + <%- ann.link.parent.class %> <%- ann.link.parent.name.slice(0, 30) %> + <% } else { %> + at + <% print(OME.formatDate(ann.link.date)) %> + <% } %>
- <% if (ann.permissions.canDelete) { %> + <% if (ann.permissions.canDelete && !isInherited) { %> <%- ann.textValue %> - <% if (ann.ns || ann.description) { %> - <% } %> <% }) %> diff --git a/omeroweb/webclient/templates/webclient/annotations/fileanns_underscore.html b/omeroweb/webclient/templates/webclient/annotations/fileanns_underscore.html index 79edbb1948..1577257c0d 100644 --- a/omeroweb/webclient/templates/webclient/annotations/fileanns_underscore.html +++ b/omeroweb/webclient/templates/webclient/annotations/fileanns_underscore.html @@ -1,8 +1,11 @@ +<% if (isInherited) { %> +

Inherited attachements



+<% } %> <% _.each(anns, function(ann) { %> -
  • +
  • @@ -14,14 +17,18 @@ - -
    - - <% if ((ann.ns && ann.ns === 'openmicroscopy.org/omero/bulk_annotations') || ann.file.mimetype == 'OMERO.tables' ){ %> -   + Description: <%- ann.description %>
    + <% if (ann.ns){ %> + Namespace: <%- ann.ns %>
    <% } %> - <% if (ann.link.permissions.canDelete) { %> - + <% if (ann.file.mimetype){ %> + Mimetype: <%- ann.file.mimetype %>
    <% } %> - - <% if (ann.permissions.canDelete) { %> - × + File ID: <%- ann.file.id %>
    + <% if (isInherited && ann.links) { %> + Inherited by:
    + <% _.each(ann.childNames, function(cname) { %> +   <%- cname.slice(0, 28) %>
    + <% }) %> <% } %> + + + <% if (!isInherited) { %> +
    + + <% if ((ann.ns && ann.ns === 'openmicroscopy.org/omero/bulk_annotations') || ann.file.mimetype == 'OMERO.tables' ){ %> +   + <% } %> + <% if (ann.link.permissions.canDelete) { %> + + <% } %> + + <% if (ann.permissions.canDelete) { %> + × + <% } %> -
    +
    + <% } %>
  • <% }) %> diff --git a/omeroweb/webclient/templates/webclient/annotations/mapanns_underscore.html b/omeroweb/webclient/templates/webclient/annotations/mapanns_underscore.html index 71f809b7aa..fd8c719b8b 100644 --- a/omeroweb/webclient/templates/webclient/annotations/mapanns_underscore.html +++ b/omeroweb/webclient/templates/webclient/annotations/mapanns_underscore.html @@ -1,3 +1,7 @@ +<% if (isInherited) { %> +

    Inherited key-value pairs



    +<% } %> + <% _.each(anns, function(ann) { %> diff --git a/omeroweb/webclient/templates/webclient/annotations/ratings_underscore.html b/omeroweb/webclient/templates/webclient/annotations/ratings_underscore.html index c6ff468f7b..f5743640f3 100644 --- a/omeroweb/webclient/templates/webclient/annotations/ratings_underscore.html +++ b/omeroweb/webclient/templates/webclient/annotations/ratings_underscore.html @@ -15,7 +15,7 @@ /> <% if (canAnnotate) { %> - X + X <% } %> @@ -24,4 +24,4 @@ <%= average %> / <%= count %> votes) - \ No newline at end of file + diff --git a/omeroweb/webclient/templates/webclient/annotations/tags_underscore.html b/omeroweb/webclient/templates/webclient/annotations/tags_underscore.html index 3ff977abd1..e82886c3ab 100644 --- a/omeroweb/webclient/templates/webclient/annotations/tags_underscore.html +++ b/omeroweb/webclient/templates/webclient/annotations/tags_underscore.html @@ -1,6 +1,9 @@ +<% if (isInherited) { %> +

    Inherited tags



    + <% } %> <% _.each(tags, function(tag) { %> - @@ -18,13 +21,18 @@ - <% }) %>