feat: folder picker UI for "Scan Specific Path" modal#56
Merged
Conversation
Adds .idea/ (IntelliJ), CLAUDE.local.md, and .claude/CLAUDE.local.md so personal IDE state and local-only AI prompt overrides don't leak into the repo. The shared CLAUDE.md / .claude/ stay local-only via .git/info/exclude rather than .gitignore. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Replaces the free-text textarea in the Scan Specific Paths modal with a clickable folder tree. Users browse the configured SCAN_PATHS roots, expand subdirectories, and pick paths via a + button into a chip list. Backend: new GET /api/browse?path=<abs> in src/server.ts. Returns the configured SCAN_PATHS as virtual top-level entries when no path is given, otherwise enumerates immediate children of the requested path. Refuses any path that does not resolve (via realpath, on both the request and the configured roots) inside one of the configured roots, so the endpoint cannot be coaxed into leaking arbitrary filesystem structure. Returns the user-supplied path in the response rather than the realpath so the UI shows paths as the user clicked them. Frontend: hand-rolled in vanilla JS to match the project's existing no-build, no-deps frontend style — no jQuery, no tree-widget library. Lazy-loads children on expand. Folder rows have a chevron, folder icon, and + button (visible on hover). File rows are shown for context but are display-only — file icon, dimmed text, no chevron, no + (the sync engine still operates on directories, this just lets users see what's inside before picking). Selected paths render as a chip list with × to remove. Hovering a chip expands it inline so the full path is visible even when truncated. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Owner
|
This is awesome, thanks for the contribution ! |
Owner
|
This is now available in v1.2.16 on Docker Hub. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Why
Typing absolute container paths into a textarea is annoying. If I have to hand-construct
/movies/Action/2024somewhere else first, I might as well skip the UI and call the CLI. The modal needed to be something worth using.What changed
Replaces the textarea in the Scan Specific Paths modal with a clickable folder picker. Backend adds a single
GET /api/browseendpoint, scoped to the configuredSCAN_PATHS.Before
After
Opening the modal lists the configured

SCAN_PATHSas collapsed roots.Expanding a folder lazy-loads its children. Folders show a chevron, folder icon, and an

Addbutton on hover. Files appear for context as display-only rows (file icon, dimmed, no+) — the sync engine still only operates on directories, but seeing what's inside helps confirm you're picking the right folder.+pushes the folder into the chip list.×removes it.Works across multiple watched roots — one pick from each:

Long paths get truncated with

…. Hovering a chip expands it inline to show the full path:Design decisions
Backend scoped to
SCAN_PATHS, not the whole filesystem.GET /api/browseresolves both the requested path and the configured roots throughrealpath, and rejects anything that isn't a descendant of one of those roots. The operator already trustsSCAN_PATHS— reusing it as the picker's scope avoided shipping a general-purpose filesystem-listing endpoint that could leak directory structure if the container were ever exposed. Also keeps the feature useful even whenCRON_SCHEDULE=disabled— the watched folders alone drive the picker.No third-party library. The dominant vanilla-JS tree widget (
jsTree) requires jQuery, and this project has zero frontend dependencies and no build step. Adding two CDN scripts (jQuery + jsTree) for one modal wasn't worth it. The picker is ~120 LOC of vanilla JS inpublic/app.js, written in the same style as the rest of the file.Files shown but not selectable. Initial pass listed only directories, which made it hard to tell if a folder was the right one to add. Showing files as display-only rows gives the same context Finder/Explorer does, without changing what the sync engine operates on.
Inline chip expansion on hover. Native
titletooltips have a ~1s delay. A floating CSS tooltip kept getting clipped by the chip list'soverflow: auto. Expanding the chip text inline on:hoveravoids the clip entirely and feels more direct.Request path preserved in the response.
realpathis used internally for the security check, but the endpoint returns the path as the user supplied it. So a click on/tmp/subsyncarr/tree-pickershows up in the chip list as/tmp/..., not/private/tmp/...(macOS/tmpsymlink). Operationally invisible in Docker, just less surprising during local dev.AI disclosure
Built with Claude Code; this PR description was also drafted with Claude. I didn't see anything in the contribution guidelines against AI-assisted contributions — happy to discuss if that's not the case. The feature commit has a
Co-Authored-Bytrailer making the tool use explicit. I designed the changes (scope, library choice, UX behavior); the AI executed against my direction. I stand behind every line.🤖 Generated with Claude Code
Co-Authored-By: Claude Opus 4.7 (1M context) noreply@anthropic.com