Skip to content

feat(sidebar): persist user-pinned custom project paths in localStorage - #543

Closed
3bluebytes wants to merge 1 commit into
agegr:mainfrom
3bluebytes:feat/persist-custom-projects
Closed

feat(sidebar): persist user-pinned custom project paths in localStorage#543
3bluebytes wants to merge 1 commit into
agegr:mainfrom
3bluebytes:feat/persist-custom-projects

Conversation

@3bluebytes

Copy link
Copy Markdown

Problem

The directory picker's "Custom path" branch validates a path server-side but only stores the choice in component state. The path vanishes on reload and is absent from the project selector, so users have to re-pick the same directory every time they open Pi Web.

Project list (getRecentProjects) is computed purely from session files on disk, so any path the user has only ever browsed (no session started) never appears in the selector.

Fix

Pin successfully-validated custom paths in window.localStorage["pi-web:custom-project-paths"] and merge them into getRecentProjects. Session-derived projects still win on overlap because they are canonicalised against the server's filesystem view.

  • New lib/custom-projects.ts with loadCustomProjects / saveCustomProject / removeCustomProject helpers. Falls back gracefully when storage is unavailable (privacy mode, SSR, denied access).
  • getRecentProjects now accepts an optional customProjects list and exposes isCustomOnlyProject so the sidebar can show a remove button only for entries not backed by any session.
  • The sidebar calls saveCustomProject after a successful /api/cwd/validate and refreshes state from storage. A small × button removes a pinned entry on hover.
  • i18n: new sidebar.removeCustomProject key in en + zh-CN.

Tests

  • New lib/custom-projects.test.mjs covers round-trip, dedup-by-key, malformed entries, removal, and storage-unavailable / SSR fallback.
  • New cases in lib/project-groups.test.mjs cover the merge logic and isCustomOnlyProject.
  • Full suite (npm test): 597/597 pass.
  • npm run lint: clean.
  • npm run build: clean (no new warnings).

Screenshots

Will attach after first reply.

The directory picker's "Custom path" branch validates a path server-side
but only stored the choice in component state, so the path disappeared on
reload and was absent from the project selector. Sidebar sessions had to
be started before a project ever showed up, forcing users to re-pick the
same directory on every visit.

This change pins successfully-validated custom paths in
`window.localStorage["pi-web:custom-project-paths"]` and merges them
into `getRecentProjects`. Session-derived projects still win on overlap
because they are canonicalised against the server's filesystem view.

- New `lib/custom-projects.ts` with load/save/remove helpers that fall
  back gracefully when storage is unavailable (privacy mode, SSR).
- `getRecentProjects` now accepts an optional custom-projects list and
  exposes `isCustomOnlyProject` so the sidebar can show a remove button
  only for entries that are not backed by any session.
- The sidebar calls `saveCustomProject` after a successful
  `/api/cwd/validate` and reloads the list. A small × button removes a
  pinned entry on hover.
- Tests cover the new helpers and the merge logic; the full suite
  (597 tests) and lint stay green.

i18n strings: en + zh-CN.
@agegr

agegr commented Aug 25, 2026

Copy link
Copy Markdown
Owner

I don’t think this is necessary. The project list should only include directories with existing sessions; custom paths can remain temporary until a session is created.

@agegr agegr closed this Aug 25, 2026
@agegr

agegr commented Aug 25, 2026

Copy link
Copy Markdown
Owner

A simpler alternative would be to remember the last successfully selected cwd and prefill the custom picker with it. This avoids adding directories without sessions to the project list.

a5630c1

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