From cd82f676add5cfc812cae436c462d376cb465290 Mon Sep 17 00:00:00 2001 From: Brianna Major Date: Tue, 30 Jun 2026 12:34:40 -0400 Subject: [PATCH 1/3] Add a show/hide toggle for all annotations in a group Add a visibility toggle icon to each annotation group (folder) header in the annotation selector panel. Clicking it toggles the `displayed` state of every annotation in that group at once. --- .../web_client/panels/AnnotationSelector.js | 19 +++++++++++++++++++ .../panels/annotationSelector.styl | 5 +++++ .../templates/panels/annotationSelector.pug | 5 +++++ 3 files changed, 29 insertions(+) diff --git a/histomicsui/web_client/panels/AnnotationSelector.js b/histomicsui/web_client/panels/AnnotationSelector.js index 4148cce2..476d7ce8 100644 --- a/histomicsui/web_client/panels/AnnotationSelector.js +++ b/histomicsui/web_client/panels/AnnotationSelector.js @@ -35,6 +35,7 @@ var AnnotationSelector = Panel.extend({ 'input #h-annotation-opacity': '_changeGlobalOpacity', 'input #h-annotation-fill-opacity': '_changeGlobalFillOpacity', 'click .h-annotation-select-by-region': 'selectAnnotationByRegion', + 'click .h-toggle-group-annotations': 'toggleGroupAnnotations', 'click .h-annotation-group-name': '_toggleExpandGroup' }), @@ -624,6 +625,24 @@ var AnnotationSelector = Panel.extend({ this.trigger('h:annotationFillOpacity', this._fillOpacity); }, + toggleGroupAnnotations(evt) { + // prevent the click from also expanding/collapsing the group + evt.stopPropagation(); + const group = $(evt.currentTarget).closest('.h-annotation-group').data('groupName'); + const annotations = this.collection.filter((model) => _.contains(model.get('groups'), group)); + const allDisplayed = annotations.length && annotations.every((model) => model.get('displayed')); + + this._showAllAnnotationsState = false; + annotations.forEach((model) => { + model.set('displayed', !allDisplayed); + if (allDisplayed) { + model.unset('highlight'); + this._deselectAnnotationElements(model); + this._deactivateAnnotation(model); + } + }); + }, + _toggleExpandGroup(evt) { const name = $(evt.currentTarget).parent().data('groupName'); if (this._expandedGroups.has(name)) { diff --git a/histomicsui/web_client/stylesheets/panels/annotationSelector.styl b/histomicsui/web_client/stylesheets/panels/annotationSelector.styl index ad39efed..ce650f53 100644 --- a/histomicsui/web_client/stylesheets/panels/annotationSelector.styl +++ b/histomicsui/web_client/stylesheets/panels/annotationSelector.styl @@ -67,6 +67,11 @@ white-space nowrap min-width 0 + .h-toggle-group-annotations + flex-shrink 0 + cursor pointer + color #6b6b6b + .h-annotation-group-legend width 18px height 18px diff --git a/histomicsui/web_client/templates/panels/annotationSelector.pug b/histomicsui/web_client/templates/panels/annotationSelector.pug index 1685b33d..329c110d 100644 --- a/histomicsui/web_client/templates/panels/annotationSelector.pug +++ b/histomicsui/web_client/templates/panels/annotationSelector.pug @@ -28,6 +28,7 @@ block content var annotations = annotationGroups[groupName]; var expanded = expandedGroups.has(groupName); var expandedClass = expanded ? 'h-group-expanded' : 'h-group-collapsed'; + var groupDisplayed = annotations.length && annotations.every((a) => a.get('displayed')); var samplestyle={}; annotations.some((a) => { var elems = (a.get('annotation') || {}).elements; @@ -57,6 +58,10 @@ block content i.icon-folder .h-annotation-group-text = groupName + if groupDisplayed + span.icon-eye.h-toggle-group-annotations(title='Hide all annotations in this group') + else + span.icon-eye-off.h-toggle-group-annotations(title='Show all annotations in this group') span.h-annotation-group-legend(style=samplestyle) if expanded each annotation in annotations From 1a5cb234de5e573ee9af5dc4c1af1a848f6eca15 Mon Sep 17 00:00:00 2001 From: Brianna Major Date: Wed, 1 Jul 2026 13:06:53 -0400 Subject: [PATCH 2/3] Add test coverage --- tests/web_client_specs/annotationSpec.js | 26 ++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/tests/web_client_specs/annotationSpec.js b/tests/web_client_specs/annotationSpec.js index fbf94516..cdfe4f27 100644 --- a/tests/web_client_specs/annotationSpec.js +++ b/tests/web_client_specs/annotationSpec.js @@ -884,6 +884,32 @@ girderTest.promise.done(function () { }, 'annotation to toggle on'); }); + it('toggle visibility of all annotations in a group', function () { + var $group = $('.h-annotation-selector .h-annotation-group[data-group-name="Other"]'); + var wasExpanded = $group.hasClass('h-group-expanded'); + + runs(function () { + expect($group.find('.icon-eye.h-toggle-group-annotations').length).toBe(1); + $group.find('.h-toggle-group-annotations').click(); + }); + waitsFor(function () { + $group = $('.h-annotation-selector .h-annotation-group[data-group-name="Other"]'); + return $group.find('.icon-eye-off.h-toggle-group-annotations').length === 1 && + $group.find('.icon-eye.h-toggle-annotation').length === 0; + }, 'all annotations in group to hide'); + + runs(function () { + // clicking the group toggle must not collapse/expand the group + expect($group.hasClass('h-group-expanded')).toBe(wasExpanded); + $group.find('.h-toggle-group-annotations').click(); + }); + waitsFor(function () { + $group = $('.h-annotation-selector .h-annotation-group[data-group-name="Other"]'); + return $group.find('.icon-eye.h-toggle-group-annotations').length === 1 && + $group.find('.icon-eye-off.h-toggle-annotation').length === 0; + }, 'all annotations in group to show'); + }); + it('select annotations by rect - no hits', function () { var interactor = huiTest.geojsMap().interactor(); expect($('.h-annotation-select-by-region').length).toBe(1); From 7bea70c9eb92a5336c066a60cdf7c3efb9e6371d Mon Sep 17 00:00:00 2001 From: Brianna Major Date: Wed, 1 Jul 2026 13:17:25 -0400 Subject: [PATCH 3/3] Fix group show/hide toggle for ungrouped annotations Ungrouped annotations are displayed under the 'Other' group, but their stored group value is null. Map the 'Other' display name back to null before filtering. --- histomicsui/web_client/panels/AnnotationSelector.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/histomicsui/web_client/panels/AnnotationSelector.js b/histomicsui/web_client/panels/AnnotationSelector.js index 476d7ce8..930bd760 100644 --- a/histomicsui/web_client/panels/AnnotationSelector.js +++ b/histomicsui/web_client/panels/AnnotationSelector.js @@ -628,7 +628,10 @@ var AnnotationSelector = Panel.extend({ toggleGroupAnnotations(evt) { // prevent the click from also expanding/collapsing the group evt.stopPropagation(); - const group = $(evt.currentTarget).closest('.h-annotation-group').data('groupName'); + let group = $(evt.currentTarget).closest('.h-annotation-group').data('groupName'); + // The ungrouped annotations are displayed under the 'Other' group, but + // their group value is null + group = group === 'Other' ? null : group; const annotations = this.collection.filter((model) => _.contains(model.get('groups'), group)); const allDisplayed = annotations.length && annotations.every((model) => model.get('displayed'));