Moves phases 08–11 execution artifacts from .planning/phases/ to .planning/milestones/v0.2-phases/ to keep .planning/phases/ clean for the next milestone. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
13 KiB
phase, plan, type, wave, depends_on, files_modified, autonomous, requirements, must_haves
| phase | plan | type | wave | depends_on | files_modified | autonomous | requirements | must_haves | ||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 10-ux-interaction | 10 | execute | 3 |
|
|
true |
|
|
Output:
- New component
frontend/src/components/layout/OsDragOverlay.vue(Options API; Teleport to body; window-level event listeners; emitsfiles-dropped) - App.vue mounts
<OsDragOverlay @files-dropped="..." />and routes to the active view viarouteViewRef.value?.handleOsDrop?.(files) - FileManagerView exposes
handleOsDrop(files)viadefineExposethat calls the existingonFilesSelected({files, autoClassify: true}) - OsDragOverlay test stubs promoted to real tests
<execution_context> @$HOME/.claude/get-shit-done/workflows/execute-plan.md @$HOME/.claude/get-shit-done/templates/summary.md </execution_context>
@CLAUDE.md @.planning/phases/10-ux-interaction/10-CONTEXT.md @.planning/phases/10-ux-interaction/10-RESEARCH.md @.planning/phases/10-ux-interaction/10-PATTERNS.md @frontend/src/App.vue @frontend/src/views/FileManagerView.vue @frontend/src/components/documents/DocumentPreviewModal.vue @frontend/src/components/ui/AppIcon.vue @frontend/src/components/upload/DropZone.vue OsDragOverlay.vue (Options API) - from PATTERNS.md §"OsDragOverlay.vue":Data:
dragDepth: 0(counter)showOverlay: false
Methods:
onDragEnter(e)-> ignore unlesse.dataTransfer?.types.includes('Files'); increment dragDepth; set showOverlay=trueonDragLeave()-> dragDepth = max(0, dragDepth - 1); if dragDepth === 0 set showOverlay=falseonDragOver(e)-> e.preventDefault() (required to allow drop event)onDrop(e)-> e.preventDefault(); reset dragDepth=0, showOverlay=false; emitfiles-droppedwithArray.from(e.dataTransfer.files)(when files.length > 0)
mounted(): addEventListener for dragenter/dragleave/dragover/drop on window.
beforeUnmount(): remove all four listeners.
Template (Teleport to body):
<Teleport to="body">
<Transition name="fade">
<div
v-if="showOverlay"
class="fixed inset-0 z-[9998] bg-indigo-900/40 flex items-center justify-center pointer-events-none"
data-test="os-drag-overlay"
>
<div class="bg-white rounded-2xl px-10 py-8 text-center shadow-xl pointer-events-none">
<AppIcon name="upload" class="w-10 h-10 text-indigo-400 mx-auto mb-3" />
<p class="text-base font-semibold text-gray-800">Drop files to upload</p>
</div>
</div>
</Transition>
</Teleport>
Plus a <style scoped> block with .fade-enter-active, .fade-leave-active { transition: opacity 0.15s ease } .fade-enter-from, .fade-leave-to { opacity: 0 }.
App.vue wiring:
- Import
OsDragOverlay from './components/layout/OsDragOverlay.vue' - Add
<OsDragOverlay @files-dropped="onOsFilesDropped" />to the template (after the ToastContainer mount from 10-04) - Add handler:
function onOsFilesDropped(files) { routeViewRef.value?.handleOsDrop?.(files) }
FileManagerView.vue:
- Extend
defineExposeto also includehandleOsDrop: (files) => onFilesSelected({ files, autoClassify: true }). Reuse the existing onFilesSelected function so the upload path, quota handling, and toast wiring (10-06) work identically to a DropZone drop.
Use `vi.fn()`, dispatch `new DragEvent(...)` or `new CustomEvent('dragenter', { ... })` and patch a fake `dataTransfer` on the event by `Object.defineProperty(event, 'dataTransfer', { value: { types: ['Files'], files: [...] } })`. happy-dom supports these.
Tests fail until Task 2 creates OsDragOverlay.vue.
The overlay element has `class="fixed inset-0 z-[9998] bg-indigo-900/40 flex items-center justify-center pointer-events-none"` and `data-test="os-drag-overlay"`.
Step B - FileManagerView.vue:
Extend the existing `defineExpose` block (added in 10-09) to also include `handleOsDrop`:
```js
defineExpose({
focusSearch: () => browserRef.value?.focusSearch?.(),
triggerUpload: () => browserRef.value?.triggerUpload?.(),
startNewFolder: () => browserRef.value?.startNewFolder?.(),
clearSearch: () => browserRef.value?.clearSearch?.(),
handleOsDrop: (files) => onFilesSelected({ files, autoClassify: true }),
})
```
Do not modify any other logic. The existing onFilesSelected handles the upload + per-file UploadProgress + toast wiring (from 10-06) end to end.
<success_criteria> Dragging one or more files from the OS file explorer over the browser window shows an indigo overlay with an upload icon and "Drop files to upload" prompt. Releasing the files uploads them via the existing FileManagerView upload flow (with per-file progress in UploadProgress and a summary toast). The overlay does not appear when dragging an in-app element (file row, folder row). The overlay does not appear when on non-file-manager routes (admin, settings) because routeViewRef does not expose handleOsDrop there. </success_criteria>
Create `.planning/phases/10-ux-interaction/10-10-SUMMARY.md` when done.