Skip to content

Groups panel mirrors the directory structure (phase 4, #10930) - #740

Open
koppor wants to merge 17 commits into
directory-write-backfrom
directory-groups
Open

koppor wants to merge 17 commits into
directory-write-backfrom
directory-groups

Conversation

@koppor

@koppor koppor commented Jul 14, 2026 •

Copy link
Copy Markdown
Member

📚 Directory-as-library stack — bottom → top, each builds on the one below:

  1. Programmatic Hayagriva writer (directory-as-library, phase 0) #736 · Hayagriva YAML writer
  2. Open folder as library (directory as library, phase 1) #737 · Open folder as library
  3. Live inbound sync for directory libraries (phase 2) #738 · Inbound file sync
  4. Write-back to Hayagriva sidecars (directory as library, phase 3) #739 · Write-back to sidecars
  5. Groups panel mirrors the directory structure (phase 4, #10930) #740 · Directory-structure groups ← this PR
  6. Pattern-driven pair renames for directory libraries (phase 5a) #741 · Pattern-driven pair renames
  7. Mirror directory libraries into a .bib with git-sync merge-back #743 · .bib mirror + merge-back
  8. Convert .bib libraries into directory libraries #744 · Convert .bib → directory
  9. Make directory libraries reachable through the REST API #745 · REST API support
  10. Split DirectoryLibrarySynchronizer into collaborators #760 · Split the synchronizer

Related issues and pull requests

Phase 4 of the "directory as library" plan (PLAN.md), stacked on #739 (base branch directory-write-back). Implements the directory-library part of JabRef#10930 (dynamic groups mirroring the file system) — not closing it, since the issue also covers plain .bib libraries.

PR Description

🤖 The groups panel of a directory library now mirrors its folder tree: each subdirectory appears as a group holding the entries whose files live there, nested folders included. The groups are read-only and follow external file changes as they happen. Saving the library as a .bib still works — parsed back outside a directory library, the groups are simply empty.

jabref-contrib-policy:4.2:reviewed​:ok

Analogies

Like honey stored cell by cell, every entry sits visibly in the comb it came from — the folder becomes the group. Like a chocolate bar's grooves, the directory tree gives natural break lines that the groups panel simply traces. And like the moon mirrored on water, the panel is a live reflection: move the folder underneath, and the image follows without anyone redrawing it.

Steps to test

  1. Open a folder with subdirectories as library (File > Open folder as library...), show the groups panel (View > Groups).
  2. The library's folder appears as a group with one subgroup per subdirectory; selecting a subgroup filters the table to the entries whose files live there (hit counts shown):

Groups panel mirroring the folder structure, conference selected filters to its entry

  1. Rename or add a .yml in a subdirectory externally — the tree and counts follow.

Guarded by DirectoryStructureGroupTest (chain building, tree merging, containment semantics, serialize/parse round trip) and a scanner test asserting the installed groups tree.

AI usage

Claude Code (model claude-fable-5).

AI CHECKLIST.md walkthrough

1. Code self-review

  • JSpecify conventions followed (model group classes match their unannotated neighbors); Optional chains for the lookup; no Objects.requireNonNull.
  • No broad catches, no RuntimeException/IllegalStateException thrown.
  • Modern Java (pattern-matching switch labels, records untouched); Markdown Javadoc; no commented-out code.
  • [/] User-facing text: group names are folder names; the "All entries" root reuses GroupsFactory's localized name.
  • [/] Security: no HTML output.
  • Tests assert object contents, plain JUnit, no @DisplayName.

2. Verification commands

  • ./gradlew :jablib:check — only the known environmental Remote*Test port-conflict failures on this machine (green on CI).
  • ./gradlew :jablib:checkstyleMain :jablib:checkstyleTest :jabgui:checkstyleMain.
  • ./gradlew :jablib:modernizer, ./gradlew traceRequirements (new req~directory-library.groups~1 covered), ./gradlew :rewriteRun clean.
  • npx markdownlint-cli2 on changed Markdown.
  • [/] IntelliJ-format docker image — not runnable on this machine; CI format job is the backstop.

3. Documentation

  • CHANGELOG.md entry (TODO replaced with this PR's link after creation).
  • Requirement req~directory-library.groups~1 added with impl marker.
  • [/] ADR — ADR-0072 already sketches this phase (groups section).

4. Pull request

  • Body from the template, all sections filled, HTML comments removed, created from a body file via gh api (stacked cross-repo).
  • CHANGELOG TODO replaced after creation, committed and pushed.

Checklist

  • I own the copyright of the code submitted and I license it under the MIT license
  • If AI tools were used, I disclosed them in the "AI usage" section and reviewed, understood, and take full ownership of all AI-generated code
  • I manually tested my changes in running JabRef (opened the demo folder on the X display: the groups panel showed the folder tree, selecting a folder group filtered the table with correct hit counts; see screenshot)
  • I added JUnit tests for changes (if applicable)
  • I added screenshots in the PR description (if change is visible to the user)
  • [/] I added a screenshot in the PR description showing a library with a single entry with me as author and as title the issue number
  • I added one sentence (max 20 words) to CHANGELOG.md describing the change from the user's point of view (if the change is visible to the user)
  • I checked the user documentation for up to dateness and submitted a pull request to our user documentation repository — deferred until the feature stabilizes; tracked in PLAN.md phase 5

🤖 Generated with Claude Code

koppor and others added 2 commits July 14, 2026 10:44
An open directory library installs a DirectoryStructureGroup (issue
10930): like the other automatic groups it materializes its subgroups
from the entries — one DirectoryPathGroup per subdirectory, matching
every entry whose source file lives in that directory or below. The
lookup reads the live catalog, and the synchronizer invalidates the
groups view after structural changes, so the tree follows external
renames and additions. The directory groups are read-only in the UI;
serialization support keeps "Save as" working (parsed back without a
library, the group simply stays empty).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
koppor and others added 8 commits July 17, 2026 02:00
# Conflicts:
#	jablib/src/main/java/org/jabref/logic/directorylibrary/DirectoryLibraryScanner.java
Resync layer 5 of the stack (no conflicts).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DDcHNMt9fPWnpYaHheFvry
…asses

The groups panel rebuilds the directory subgroups when the synchronizer invalidates the groups binding; the group classes are null-marked, drop the redundant equality override, and build the subgroup chain without null tracking.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Vr3E1Gg5DRU4LQDDVnhPys
# Conflicts:
#	jablib/src/main/java/org/jabref/logic/directorylibrary/DirectoryLibrarySynchronizer.java
#	jablib/src/test/java/org/jabref/logic/directorylibrary/DirectoryLibraryScannerTest.java
Fixes the CI format check.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DDcHNMt9fPWnpYaHheFvry
Resync with upstream (no conflicts).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DDcHNMt9fPWnpYaHheFvry
Upstream added a 0071 ADR after this stack claimed the number, so the
MADR duplicate-ID check failed.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

This branch has not been deployed

No deployments
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.

1 participant