Repository navigation
feat(workspace): document portability and private reuse - #63
Programcode wants to merge 18 commits into
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
|
Navigate logical layers of code changes, visualize relationships, and explore their blast radius. ℹ️ Recent review info⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Free Run ID: 📒 Files selected for processing (5)
🚧 Files skipped from review as they are similar to previous changes (2)
Included review availability: Your plan provides up to 1 included review per hour; 0 remain after this review. 📝 WalkthroughWalkthroughAdds workspace portability for private writing, document conversion, packet export, and Google Drive. Adds persistence, OAuth-backed Edge Functions, UI workflows, localization, tests, and a local trial deployment harness. ChangesWorkspace portability and Google Drive
Workspace trial deployment and test harness
Estimated code review effort: 5 (Critical) | ~90 minutes Sequence Diagram(s)sequenceDiagram
participant User
participant WorkspacePage
participant WorkspacePortabilityPanel
participant Supabase
participant GoogleDrive
User->>WorkspacePortabilityPanel: select import, export, or Google Drive action
WorkspacePortabilityPanel->>Supabase: load or save portability data
Supabase-->>WorkspacePortabilityPanel: validated items, manifest, or operation status
WorkspacePortabilityPanel->>WorkspacePage: request content insertion or replacement
WorkspacePage->>User: update workspace document
WorkspacePortabilityPanel->>GoogleDrive: import or export document when selected
GoogleDrive-->>WorkspacePortabilityPanel: document metadata or URL
Note 🎁 Summarized by CodeRabbit FreeYour organization is on the Free plan. CodeRabbit will generate a high-level summary and a walkthrough for each pull request. For a comprehensive line-by-line review, please upgrade your subscription to CodeRabbit Essentials by visiting https://app.coderabbit.ai/settings/billing. Comment |
|
@coderabbitai review |
|
|
@coderabbitai review |
|
|
@coderabbitai review |
|
|
@coderabbitai review |
|
|
@coderabbitai review |
|
|
@coderabbitai review |
✅ Action performedReview finished.
|
| await saveWorkspaceDocumentProvenance({ documentId, provenance: preview.provenance, sourceKind: preview.sourceKind, workspaceId }); | ||
| onInsertContent(preview.content, "replace"); |
There was a problem hiding this comment.
When the editor is offline or still waiting for an acknowledgement, this saves the import provenance before the replacement can be applied. If the user switches documents while the replacement is queued, WorkspacePage clears it, leaving durable provenance for content that was never imported. The requested replacement is lost and exported packets can report misleading provenance.
Prompt To Fix With AI
This is a comment left during a code review.
Path: src/components/features/workspace/WorkspacePortabilityPanel.tsx
Line: 138-139
Comment:
**Import can lose content**
When the editor is offline or still waiting for an acknowledgement, this saves the import provenance before the replacement can be applied. If the user switches documents while the replacement is queued, `WorkspacePage` clears it, leaving durable provenance for content that was never imported. The requested replacement is lost and exported packets can report misleading provenance.
---
For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.| const exported = await exportGoogleDocument({ connectionId: selectedConnectionId, markdown: toWorkspaceMarkdown(content), requestId: googleExportRequestId, title: documentTitle }); | ||
| setGoogleExportRequestId(crypto.randomUUID()); | ||
| window.open(exported.url, "_blank", "noopener,noreferrer"); |
There was a problem hiding this comment.
The new tab is opened only after the Edge Function and Google API work completes. By then, the original click's user activation has expired, so popup-blocking browsers can suppress the tab even though the Google document was successfully created. Because the panel does not show a fallback link, the user cannot open the resulting document from this flow.
Prompt To Fix With AI
This is a comment left during a code review.
Path: src/components/features/workspace/WorkspacePortabilityPanel.tsx
Line: 197-199
Comment:
**Export popup gets blocked**
The new tab is opened only after the Edge Function and Google API work completes. By then, the original click's user activation has expired, so popup-blocking browsers can suppress the tab even though the Google document was successfully created. Because the panel does not show a fallback link, the user cannot open the resulting document from this flow.
---
For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.| .setCallback((data) => { | ||
| if (data[picker.Response.ACTION] !== picker.Action.PICKED) return; | ||
| const selected = (data[picker.Response.DOCUMENTS] as Array<Record<string, unknown>> | undefined)?.[0]; | ||
| if (!selected?.id) reject(new Error("Google Picker returned no document")); | ||
| else resolve({ id: String(selected.id), name: String(selected.name ?? "Google document") }); | ||
| }) |
There was a problem hiding this comment.
Picker cancellation hangs panel
When the user closes or cancels Google Picker, the callback receives a non-PICKED action and returns without resolving or rejecting this Promise. The portability panel therefore never reaches its finally block, keeps busy set to true, and leaves its controls disabled until the page is reloaded.
Prompt To Fix With AI
This is a comment left during a code review.
Path: src/lib/workspace/google-drive.ts
Line: 86-91
Comment:
**Picker cancellation hangs panel**
When the user closes or cancels Google Picker, the callback receives a non-`PICKED` action and returns without resolving or rejecting this Promise. The portability panel therefore never reaches its `finally` block, keeps `busy` set to true, and leaves its controls disabled until the page is reloaded.
---
For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.| await auth.adminClient.from("google_connections").delete().eq("id", connectionId).eq("user_id", auth.user.id); | ||
| return json({ disconnected: true }, 200, headers); |
There was a problem hiding this comment.
The database delete result is ignored, so a transient database failure still returns disconnected: true. The client then removes the account from its current view even though the connection and encrypted token row remain, causing the account to reappear after a later refetch.
Prompt To Fix With AI
This is a comment left during a code review.
Path: supabase/functions/google-connections/index.ts
Line: 147-148
Comment:
**Failed delete reports success**
The database delete result is ignored, so a transient database failure still returns `disconnected: true`. The client then removes the account from its current view even though the connection and encrypted token row remain, causing the account to reappear after a later refetch.
---
For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.| const converted = await Promise.race([ | ||
| convertWorkspaceDocx(bytes), | ||
| new Promise<never>((_, reject) => setTimeout(() => reject(new Error("DOCX parsing timed out.")), 5_000)), | ||
| ]); |
There was a problem hiding this comment.
Timeout leaves conversion running
This race rejects the visible import after five seconds but does not cancel Mammoth's decompression or conversion work. A costly user-selected DOCX can therefore continue consuming browser CPU and memory after the timeout, and repeated attempts can leave multiple conversions running at once.
Prompt To Fix With AI
This is a comment left during a code review.
Path: src/lib/workspace/document-conversion.ts
Line: 511-514
Comment:
**Timeout leaves conversion running**
This race rejects the visible import after five seconds but does not cancel Mammoth's decompression or conversion work. A costly user-selected DOCX can therefore continue consuming browser CPU and memory after the timeout, and repeated attempts can leave multiple conversions running at once.
---
For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.| @@ -202,11 +208,14 @@ function parseList(lines: string[], start: number, indent: number) { | |||
| } | |||
| items.push({ | |||
| type: "listItem", | |||
| content: [{ type: "paragraph", content: parseInline(match[2]) }], | |||
| content: [{ type: "paragraph", content: parseInline(match[3]) }], | |||
| }); | |||
| index += 1; | |||
| } | |||
There was a problem hiding this comment.
The parser chooses the list type from the first marker but then continues consuming both numbered and bullet markers. Importing adjacent mixed lists such as 1. First followed by - Separate therefore turns the bullet into another numbered item instead of preserving two distinct lists.
Prompt To Fix With AI
This is a comment left during a code review.
Path: src/lib/workspace/document-conversion.ts
Line: 197-214
Comment:
**Mixed lists lose structure**
The parser chooses the list type from the first marker but then continues consuming both numbered and bullet markers. Importing adjacent mixed lists such as `1. First` followed by `- Separate` therefore turns the bullet into another numbered item instead of preserving two distinct lists.
---
For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.| TRIAL_ORIGIN="https://codex-remote.tailab0ab3.ts.net:18443" | ||
| APP_PORT=18480 | ||
| COLLABORATION_PORT=12345 | ||
| SERVE_PORT=18443 |
There was a problem hiding this comment.
Trial boundary is undocumented
This change introduces a Tailscale-served origin, three dedicated ports, and a new Nginx runtime boundary. The repository directive requires the owning focused documentation to be updated whenever commands, ports, workflows, or runtime boundaries change. That required documentation must be added before merging.
Context Used: AGENTS.md (source)
Prompt To Fix With AI
This is a comment left during a code review.
Path: .superset/workspace-trial.sh
Line: 8-11
Comment:
**Trial boundary is undocumented**
This change introduces a Tailscale-served origin, three dedicated ports, and a new Nginx runtime boundary. The repository directive requires the owning focused documentation to be updated whenever commands, ports, workflows, or runtime boundaries change. That required documentation must be added before merging.
**Context Used:** AGENTS.md ([source](https://github.com/programcode/debatelab/blob/main/AGENTS.md))
---
For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!
Comments Outside DiffThese findings sit on lines the diff does not cover, so they could not be posted inline. Each one leaves this list once its file changes.
|
|
Closing per Adam, not merging. |
Outcome
drive.file, encrypted refresh tokens, PKCE, state, and bounded creation claimsWorking journey
Verification
d52598cc0964d25dd3329df4db43f441c99a0a0bEnvironment limits
This is the final workspace PR and must remain unmerged until Adam explicitly approves the merge.
Summary by CodeRabbit
New Features
Localization
The PR is not yet safe to merge because imports can leave false provenance, Google exports can be blocked after successful creation, and cancelling Picker can permanently hang the portability panel.
Fix with agent prompt
Summary
This PR adds private writing reuse, document import/export and packet generation, multi-account Google Drive integration, database support, and a private Tailscale trial runtime.
Diagram
Reviews (1) · Last reviewed commit: "fix(workspace): route Deno boundary test..."