- SUMMARY.md documents XHR progress pattern and backward-compatible props - STATE.md advanced to plan 2, decisions logged, metrics recorded - ROADMAP.md updated with 2/4 summaries complete for phase 25 - REQUIREMENTS.md marks FILE-05 complete
108 lines
4.3 KiB
Markdown
108 lines
4.3 KiB
Markdown
---
|
|
phase: 25-file-system
|
|
plan: 02
|
|
subsystem: ui
|
|
tags: [react, file-upload, drag-and-drop, clipboard, xhr, lucide]
|
|
|
|
# Dependency graph
|
|
requires:
|
|
- phase: 25-file-system-00
|
|
provides: shared types (ChatFile, ChatFileUploadResponse), validators
|
|
- phase: 25-file-system-01
|
|
provides: server endpoint POST /api/conversations/:id/files
|
|
provides:
|
|
- ChatFileDropZone component with drag-and-drop overlay
|
|
- useChatFileUpload hook with upload lifecycle (uploading/done/error)
|
|
- chatApi.uploadFile using XHR with progress callbacks
|
|
- ChatInput updated with file picker button, paste handler, and pending file chips
|
|
affects: [25-03, 25-04, chat-panel-integration]
|
|
|
|
# Tech tracking
|
|
tech-stack:
|
|
added: []
|
|
patterns:
|
|
- XHR for upload progress tracking (not fetch, which lacks upload progress)
|
|
- PendingFile client-side state lifecycle before server confirmation
|
|
- ChatFileDropZone wraps children with drag overlay without breaking layout
|
|
|
|
key-files:
|
|
created:
|
|
- ui/src/components/ChatFileDropZone.tsx
|
|
- ui/src/hooks/useChatFileUpload.ts
|
|
modified:
|
|
- ui/src/api/chat.ts
|
|
- ui/src/components/ChatInput.tsx
|
|
- ui/src/components/ChatInput.test.tsx
|
|
|
|
key-decisions:
|
|
- "Used XHR instead of fetch for chatApi.uploadFile to enable upload progress events (fetch lacks upload.onprogress)"
|
|
- "ChatFileDropZone checks e.currentTarget.contains(e.relatedTarget) to avoid false drag-leave when crossing child elements"
|
|
- "onFilesPicked is optional — ChatInput works without file support when prop not provided (backward compatible)"
|
|
|
|
patterns-established:
|
|
- "PendingFile pattern: temp client ID assigned immediately, replaced with server ChatFile.id on completion"
|
|
- "Drop zone overlay uses bg-primary/10 and border-primary for theme-neutral visual feedback"
|
|
|
|
requirements-completed: [FILE-05]
|
|
|
|
# Metrics
|
|
duration: 15min
|
|
completed: 2026-04-01
|
|
---
|
|
|
|
# Phase 25 Plan 02: File Upload UI Summary
|
|
|
|
**Drag-and-drop, clipboard paste, and file picker wired into ChatInput via ChatFileDropZone and useChatFileUpload with XHR progress tracking**
|
|
|
|
## Performance
|
|
|
|
- **Duration:** ~15 min
|
|
- **Started:** 2026-04-01T23:10:00Z
|
|
- **Completed:** 2026-04-01T23:25:00Z
|
|
- **Tasks:** 2
|
|
- **Files modified:** 5
|
|
|
|
## Accomplishments
|
|
- chatApi.uploadFile implemented with XMLHttpRequest for upload progress callbacks
|
|
- useChatFileUpload hook manages PendingFile lifecycle (uploading → done/error)
|
|
- ChatFileDropZone component provides drag-over overlay with dashed border and theme-neutral colors
|
|
- ChatInput now accepts all three file input methods: drag-and-drop, clipboard paste (onPaste), file picker (Paperclip button)
|
|
- Pending file chips shown above textarea with spinner, progress %, and remove button
|
|
- 3 new tests added: file attach button presence, onFilesPicked callback, pending chip rendering
|
|
|
|
## Task Commits
|
|
|
|
Each task was committed atomically:
|
|
|
|
1. **Task 1: Add chatApi.uploadFile and create useChatFileUpload hook** - `6a83a362` (feat)
|
|
2. **Task 2: Create ChatFileDropZone and integrate into ChatInput** - `6b530afa` (feat)
|
|
|
|
## Files Created/Modified
|
|
- `ui/src/api/chat.ts` - Added uploadFile method using XHR with FormData and progress callbacks
|
|
- `ui/src/hooks/useChatFileUpload.ts` - Created PendingFile state management hook
|
|
- `ui/src/components/ChatFileDropZone.tsx` - Created drag-and-drop wrapper with overlay
|
|
- `ui/src/components/ChatInput.tsx` - Added file props, paste handler, Paperclip button, pending chips, ChatFileDropZone wrapper
|
|
- `ui/src/components/ChatInput.test.tsx` - Added 3 file upload tests
|
|
|
|
## Decisions Made
|
|
- Used XHR for uploadFile to get upload progress events (fetch API doesn't expose upload.onprogress)
|
|
- ChatFileDropZone uses `e.currentTarget.contains(e.relatedTarget)` guard on dragLeave to prevent flicker when cursor moves over child elements
|
|
- ChatInput backward-compatible: onFilesPicked/pendingFiles/onRemoveFile are all optional props
|
|
|
|
## Deviations from Plan
|
|
|
|
None — plan executed exactly as written.
|
|
|
|
## Issues Encountered
|
|
None.
|
|
|
|
## User Setup Required
|
|
None — no external service configuration required.
|
|
|
|
## Next Phase Readiness
|
|
- File upload UI complete; ChatPanel needs wiring to call useChatFileUpload and pass pendingFiles/onFilesPicked/onRemoveFile to ChatInput
|
|
- Plan 25-03 (server routes) and Plan 25-04 (ChatPanel wiring) can proceed
|
|
|
|
---
|
|
*Phase: 25-file-system*
|
|
*Completed: 2026-04-01*
|