feat: add "Shared with me" sidebar section - #74
Conversation
Folders and notes shared directly with a user were reachable only by URL: shared folders were never returned by the page list, and a note shared from inside a folder was orphaned under a parent the recipient can't see, so it rendered nowhere in the sidebar. Add a recipient-scoped way to surface them: - API: ShareStore.ListSharedWithUser (pg + memstore) joins shares to the pages table for page/folder shares, projecting title/type/permission/ sharer; exposed as GET /shares/shared-with-me. New model.SharedItem. - Frontend: ApiShareRepository.sharedWithMe(), a shared.svelte.ts store loaded at mount, a SharedList sidebar component, and a "Shared with me" section in Sidebar.svelte (API mode, folders → folder board, notes → note; viewer badge). Refreshes on tab focus/visibility so new shares appear without a reload. Tests: Go unit tests for the store/handler; e2e/shared-sidebar.spec.ts covers folder surfacing + board link, the orphaned-note case, empty state, revocation, and the editor-vs-viewer badge. Full api E2E suite passes (154 passed). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01JBNnP4Gz2dqm5e2FZLDAeN
|
🤖 Starting work on this now. |
|
🤖 Watch live or take over the session here: https://claude.ai/code/session_01Lck5TZ8vR7FrF5sjggH9m8 |
There was a problem hiding this comment.
Solid feature — the recipient-scoped endpoint is correctly not owner-gated but still requireSessionAuth-gated, the inner join / memstore both drop deleted resources, and coverage (Go unit + e2e) is thorough. Build and the touched Go packages pass locally. Two things worth a look before merge; the folder-context-menu bug you already documented is a fine follow-up and out of scope here.
- +layout.svelte: load sharedStore off the critical Promise.all so a non-auth failure fetching /shares/shared-with-me can't trip the app-wide loadError path and block notes/tasks from rendering. handleAuthError still runs the redirect for a real UnauthorizedError before .catch swallows the re-throw. - Sidebar.svelte: dedupe the section against the page tree. A note shared at the owner's root is returned by GET /pages and renders at the recipient's tree root, so it was listed twice; now only items not reachable in the tree (folder shares and folder-nested notes) show in "Shared with me". - e2e: add a test asserting a root-shared note renders once (tree only, absent from the section). Full api suite passes (155 passed). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01JBNnP4Gz2dqm5e2FZLDAeN
|
Both review points addressed in ec5bce4:
Full The folder-context-menu |
The frontend CI job's `pnpm audit --prod` step failed on new devalue advisories (uneval/CPU amplification, __proto__ bypass, sparse-array DoS) affecting versions up to 5.9.2, pulled in transitively via svelte. The existing override only covered <=5.8.0, so 5.9.2 slipped through. Broaden it to `devalue@<5.9.3` → `>=5.9.3 <6` (resolves to 5.9.4). The <6 cap keeps it within svelte's `^5.8.1` range and avoids 6.x's Node >=22.17 engine requirement, which would fail engine-strict installs. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01JBNnP4Gz2dqm5e2FZLDAeN
Problem
Folders and notes shared directly with a user were reachable only by URL — there was no way to discover them from the app:
GET /pages(its access filter only checksresource_type = 'page').parentIdpoints to a folder the recipient can't see, so the tree orphans it and it renders nowhere.Change
A recipient-scoped path to surface shared items, plus a sidebar section for them.
API
ShareStore.ListSharedWithUser(pg + memstore) joinsshares→pagesforpage/foldershares, projecting title, type, permission, and sharer (inner join drops shares whose resource was deleted).GET /api/v1/shares/shared-with-me(not owner-gated — you can always see what's shared with you). Newmodel.SharedItem.Frontend
ApiShareRepository.sharedWithMe(), ashared.svelte.tsstore loaded at mount, aSharedList.sveltecomponent, and a "Shared with me" section inSidebar.svelte(API mode only; folders link to the folder board, notes to the note; viewer-only items show a View badge).visibilitychange(coalesced) so shares granted while the tab was open appear without a full reload.Tests
e2e/shared-sidebar.spec.tscovers: shared folder surfacing + board link + viewer badge, the orphaned-note case (absent from the tree, present in the section), empty state, revocation, and the editor-vs-viewer badge.apiE2E suite passes: 154 passed, 3 skipped, 0 failed (run on a local ferry/k8s cluster).Note / follow-up (not in this PR)
While building this I found a pre-existing bug: the sidebar context-menu "Share" on a folder hardcodes
resourceType="page"(TreeNodeItem.svelte:333), so folder shares from the sidebar send a page-type share and the backend 404s them. The working folder-share path is the folder board's Share button (resourceType: 'folder'), which this feature surfaces correctly. Happy to fix the sidebar path in a follow-up.🤖 Generated with Claude Code
https://claude.ai/code/session_01JBNnP4Gz2dqm5e2FZLDAeN