Skip to content

feat: adds upload feature - #6

Merged
hali-coding merged 1 commit into
mainfrom
feat/upload
Aug 26, 2026
Merged

feat: adds upload feature#6
hali-coding merged 1 commit into
mainfrom
feat/upload

Conversation

@hali-coding

Copy link
Copy Markdown
Owner

Changes

  • feat: adds upload / download feature in tracker

Copilot AI lite review requested due to automatic review settings August 26, 2026 17:06
@hali-coding
hali-coding merged commit 6fe4966 into main Aug 26, 2026
1 check passed
@hali-coding
hali-coding deleted the feat/upload branch August 26, 2026 17:08

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

The new global drag/drop handler prevents default for all drops (not just files), which can break normal drop behavior inside apps (e.g., dropping text into inputs).

Once you've addressed the issues Copilot identified, you can request another Copilot review.

Pull request overview

Adds host ↔ virtual-disk file transfer capabilities to BeanWeb, wiring import/export into Tracker and Terminal while providing a shared implementation and tests for the core transfer logic.

Changes:

  • Introduces src/lib/transfer.ts to centralize host file picking/import and node export/download.
  • Adds Tracker UI entry points (File menu + drag-and-drop) and Terminal commands (import, export).
  • Adds a Vitest suite covering import collision rules, refusals, and export behavior.
File summaries
File Description
tests/transfer.test.ts Adds jsdom-driven unit tests for import/export behavior in lib/transfer.
src/shell/Desktop.tsx Adds global drag/drop default-cancellation to avoid browser navigation on drops.
src/lib/transfer.ts Implements shared import/export logic between host and virtual FS (picker, validation, download).
src/apps/Tracker.tsx Wires import/export into Tracker’s File menu and adds file drag-and-drop import.
src/apps/tracker.css Adds a visual drop-ring styling when dragging files over Tracker.
src/apps/Terminal.tsx Adds import and export commands backed by the shared transfer library.
CLAUDE.md Documents the new transfer.ts module in the architecture overview.
Review details
  • Files reviewed: 7/7 changed files
  • Comments generated: 3
  • Review effort level: Lite

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread src/shell/Desktop.tsx
Comment on lines +26 to +38
// A file dropped anywhere the desktop does not handle is navigated to by the
// browser, which unloads the tab and takes the whole session with it. These
// two listeners sit on the window so they run after any app's own handler
// has had its turn, and only cancel the default.
useEffect(() => {
const swallow = (e: DragEvent) => e.preventDefault()
window.addEventListener('dragover', swallow)
window.addEventListener('drop', swallow)
return () => {
window.removeEventListener('dragover', swallow)
window.removeEventListener('drop', swallow)
}
}, [])
Comment thread src/lib/transfer.ts
Comment on lines +70 to +73
for (const file of files) {
// A directory drop hands over paths, not bare names.
const name = file.name.split(/[\/]/).pop() ?? ''
if (!name) continue
Comment thread tests/transfer.test.ts
Comment on lines +1 to +28
import { beforeEach, describe, expect, it, vi } from 'vitest'
import { MAX_IMPORT_BYTES, exportNode, importFiles } from '@/lib/transfer'
import { useDesktop } from '@/store/desktop'
import { useFs } from '@/store/fs'

/**
* jsdom has no host picker, no downloads directory and no real drag, so these
* drive `lib/transfer` directly with hand-built Files -- which is the reason
* the logic lives there and not inside Tracker. `pickFiles` and the drop
* handler are browser-only and are verified by hand.
*/

const fs = () => useFs.getState()
const alerts = () => useDesktop.getState().alerts

let clicks: HTMLAnchorElement[] = []

beforeEach(() => {
clicks = []
// Neither of these exists in jsdom.
URL.createObjectURL = vi.fn(() => 'blob:test')
URL.revokeObjectURL = vi.fn()
vi.spyOn(HTMLAnchorElement.prototype, 'click').mockImplementation(function (
this: HTMLAnchorElement,
) {
clicks.push(this)
})
})
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