Skip to content

Conversation

@reddraconi
Copy link

Adds a feature to group thumbnails in the main window by a tag or by a parent tag.
Grouped thumbnails in each section respect the user's other sorting choices (filename/date created, sort direction, etc.)

Features:

  • Hierarchical tag dropdown with grouping of parent/children tags in a table view so large amounts of tags can be handled (hopefully)
  • Collapsible/expandable groups with count badges in thumbnail view
    • The tags that act as headers respect the user's configuration and use the tags' configured colors
  • Auto-refreshes the thumbnail pane and group-by-tag dropdown on tag creation/modification no matter if it was through the tag manager or the right-hand pane
  • Works with all existing search/filter operations

Core Library Changes:

  • Add group_entries_by_tag() method to generate a tag hierarchy
  • Add get_grouping_tag_ids() to fetch grouping tags
  • Extend BrowsingState with group_by_tag_id field
  • Add GroupedSearchResult dataclass with TagGroup hierarchy

UI Components:

  • Added a new dropdown for tag selection to sort by. This works with parent tags so multiple tag groups are created in the thumbnail view. If an item has multiple sibling tags, it'll be put under a "Multiple Tags" grouping.
    • Each Parent gets its own row in the dropdown menu. The siblings under the parent get their own cell. I didn't have a good way to screenshot that, sorry!
  • Implemented GroupHeaderWidget to create collapsible group headers
  • Extended ThumbGridLayout to render hierarchical grouped entries
  • Updated update_browsing_state() to handle grouped results

Files Added:

  • src/tagstudio/qt/mixed/group_header.py
  • src/tagstudio/qt/mixed/group_by_tag_delegate.py

Notes:

  • The QT components and the hierarchy generation were written with tool-assistance (Claude Code 4.5)
  • The new python code was run through black -l100, mypy, and ruff. I did my best to stick to the existing coding style.
  • I've tested this for hours yesterday and today with no ill effects (yet).
  • I asked in the Discord if this had a PR and received positive responses there was one somewhere. I wasn't smart enough to find it, so if this is out of line, please let me know!
  • I added 'Thumbs.db' to the ignore list since other Windows and Mac library-ish things were being ignored too.
  • I found a bug where the search modal had delete buttons for tags, they didn't do anything because the delete_tag() only contained pass. I implemented a full delete_tag() method to fix this so the sort-by-tag dropdown would be able to automatically update correctly.

Summary

Adds a feature to group thumbnails in the main window by a single tag or by a parent tag.
Grouped thumbnails in each section respect the user's other sorting choices (filename/date created, sort direction, etc.)

Tasks Completed

  • Platforms Tested:
    • Windows x86
    • Windows ARM
    • macOS x86
    • macOS ARM
    • Linux x86
    • Linux ARM
  • Tested For:
    • Basic functionality
    • PyInstaller executable
    • Ruff, mypy, and formatting compliance

Screenshots

New Toolbar Dropdown

New toolbar item

Selecting a Parent Tag to Group By

Selecting 'Colors' Parent Tag

Sorting complete

Selected 'Colors' Parent Tag

Example Item with Multiple Sibling Tags

Selected Item with multiple sibling tags

Groups thumbnails using collapsible groups based on tag selection.
Thumbnails within the groups respect the user's other sorting choices.

Features:
- Hierarchical tag dropdown with grouping of parent/children tags in a table view so large amounts of tags can be
  handled (hopefully)
- Collapsible/expandable groups with count badges in thumbnail view
  - The tags that act as headers respect the user's configuration and use the tags' configured colors
- Auto-refreshes the thumbnail pane and group-by-tag dropdown on tag creation/modification no matter if it was through
  the tag manager or the right-hand pane
- Works with all existing search/filter operations

Core Library Changes:
- Add `group_entries_by_tag()` method to generate a tag hierarchy
- Add `get_grouping_tag_ids()` to fetch grouping tags
- Extend `BrowsingState` with `group_by_tag_id` field
- Add `GroupedSearchResult` dataclass with `TagGroup` hierarchy

UI Components:
- Added a new dropdown in main toolbar for tag selection to sort by.
  This works with parent tags so multiple tag groups are created in the thumbnail view.
  If an item has multiple sibling tags, it'll be put under a "Multiple Tags" grouping.
- Implemented `GroupHeaderWidget` to create collapsible group headers
- Extended `ThumbGridLayout` to render hierarchical grouped entries
- Updated `update_browsing_state()` to handle grouped results

Files Added:
- src/tagstudio/qt/mixed/group_header.py
- src/tagstudio/qt/mixed/group_by_tag_delegate.py

Note: The QT components and the hierarchy generation were written with tool-assistance (Claude Code 4.5)
I got overzealous in updating the UI by starting to update the search
element to handle a multi-columned layout. This isn't necessary for this
feature, so I'm reverting it to main.
@reddraconi reddraconi marked this pull request as ready for review December 8, 2025 04:45
block_signals: If True, block signals during population.
"""
if block_signals:
self.main_window.group_by_tag_combobox.blockSignals(True)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a QT thing so I would suggest adding the method to the ignore list for this rule.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I added a quick check for Mock in the new code to prevent the math issues that occurred. I also went back and fixed up the linting issues caused by QT convention.

Added a check for Mock to the new code to handle tests to make sure they don't fail.
Re-ran mypy and ruff.

Fixes:
- Added type check for view.columnWidth() to handle Mock objects in tests
- Fixed test_title_update failures (There was a TypeError with Mock math)
- Fixed test_add_tag_callback Qt event loop errors
- Removed unused imports from group_by_tag_delegate.py (QRect, Qt)
- Added type signatures for Qt method overrides (QModelIndex | QPersistentModelIndex)
- Added linter suppressions for Qt API conventions (noqa: N802, FBT003)

Changes:
- src/tagstudio/qt/ts_qt.py: Added isinstance() check for Mock
- src/tagstudio/qt/mixed/group_by_tag_delegate.py: Fixed imports and type signatures
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants