130 lines
6.6 KiB
Markdown
130 lines
6.6 KiB
Markdown
---
|
|
phase: 42-wallpapers-social-format-conversion-voice
|
|
plan: 06
|
|
subsystem: ui
|
|
tags: [react, typescript, drag-drop, format-conversion, deep-link, SSE, FormData, multipart, shadcn, lucide]
|
|
|
|
# Dependency graph
|
|
requires:
|
|
- phase: 42-wallpapers-social-format-conversion-voice
|
|
plan: 03
|
|
provides: POST /api/companies/:companyId/convert (multipart), GET /api/system/converters, ConvertBundle type
|
|
- phase: 40-content-job-infra
|
|
provides: useContentJob hook, getContentJobAsset, SSE job tracking pattern
|
|
|
|
provides:
|
|
- ui/src/api/convert.ts — submitConvertJob (multipart) and getConverterCapabilities API client
|
|
- ui/src/components/ConvertPanel.tsx — drag-drop + grouped format chips + AI fallback notice + download
|
|
- ui/src/pages/ConvertPage.tsx — /convert route with deep-link URL param reading
|
|
- ui/src/App.tsx — three route variants /convert, /convert/:src, /convert/:src/:tgt
|
|
|
|
affects:
|
|
- Any future phase adding nav links to /convert
|
|
|
|
# Tech tracking
|
|
tech-stack:
|
|
added: []
|
|
patterns:
|
|
- Direct fetch (not api.post) for multipart submissions that need per-status-code inspection (422 vs 202)
|
|
- Direct EventSource connection for pre-submitted jobs (bypasses useContentJob.submit which re-submits)
|
|
- FORMAT_GROUPS constant exported from ConvertPanel for reuse in ConvertPage validation
|
|
- normalizeFormatParam helper: toLowerCase + allowlist check, silently returns undefined for invalid params
|
|
|
|
key-files:
|
|
created:
|
|
- ui/src/api/convert.ts
|
|
- ui/src/components/ConvertPanel.tsx
|
|
- ui/src/pages/ConvertPage.tsx
|
|
modified:
|
|
- ui/src/App.tsx
|
|
|
|
key-decisions:
|
|
- "Direct fetch used in submitConvertJob (not api.postForm) to inspect 422 vs 202 status before throwing — api.request() throws on !res.ok, but 422 is a valid business response with MIME error body"
|
|
- "Direct EventSource in ConvertPanel for already-submitted jobs — useContentJob.submit() calls submitContentJob internally and cannot track an existing jobId without re-submitting"
|
|
- "FORMAT_GROUPS exported from ConvertPanel so ConvertPage can import the same constant for allowlist validation without duplicating the list"
|
|
- "AI fallback notice shown per target format group (Images/AV/Docs/Data) based on capabilities, not per individual format pair — matches CONV-08 spec that all paths fall to AI bridge when direct converter unavailable"
|
|
|
|
patterns-established:
|
|
- "Format chip role=radio within role=radiogroup — matches accessibility spec from 42-UI-SPEC.md"
|
|
- "Drop zone uses motion-safe: Tailwind variant to disable transition for prefers-reduced-motion"
|
|
|
|
requirements-completed: [CONV-01, CONV-02, CONV-03, CONV-04, CONV-05, CONV-06, CONV-07, CONV-08, CONV-09]
|
|
|
|
# Metrics
|
|
duration: 12min
|
|
completed: 2026-04-04
|
|
---
|
|
|
|
# Phase 42 Plan 06: Format Conversion UI Summary
|
|
|
|
**Drag-drop ConvertPanel with grouped format chips, AI fallback notice, MIME error display, SSE job tracking, and deep-link /convert/:src/:tgt routing**
|
|
|
|
## Performance
|
|
|
|
- **Duration:** 12 min
|
|
- **Started:** 2026-04-04T22:17:33Z
|
|
- **Completed:** 2026-04-04T22:29:00Z
|
|
- **Tasks:** 2
|
|
- **Files modified:** 4 (3 created, 1 modified)
|
|
|
|
## Accomplishments
|
|
|
|
- Created convert.ts API client: submitConvertJob with direct fetch for 422/202 status differentiation; getConverterCapabilities for startup capability probe
|
|
- Built ConvertPanel with all three visual zones: ConvertSourceZone (drag-drop with idle/dragover/error states), ConvertTargetSelector (grouped chips with AI fallback notice), ConvertActionBar (disabled until ready, download after done)
|
|
- FORMAT_GROUPS constant drives chip rendering and is exported for ConvertPage format validation
|
|
- ConvertPage reads URL params, normalizes to lowercase, silently ignores invalid format strings
|
|
- Three route variants wired in App.tsx: /convert, /convert/:sourceFormat, /convert/:sourceFormat/:targetFormat
|
|
|
|
## Task Commits
|
|
|
|
1. **Task 1: Create convert API client and ConvertPanel component** - `c0040f66` (feat)
|
|
2. **Task 2: Create ConvertPage and wire routes in App.tsx** - `b5587c03` (feat)
|
|
|
|
## Files Created/Modified
|
|
|
|
- `ui/src/api/convert.ts` - submitConvertJob (multipart POST, 422/202 handling), getConverterCapabilities
|
|
- `ui/src/components/ConvertPanel.tsx` - Full ConvertPanel: drag-drop zone, FORMAT_GROUPS chips, AI fallback notice, SSE progress, download
|
|
- `ui/src/pages/ConvertPage.tsx` - Route page reading sourceFormat/targetFormat URL params with case-insensitive normalization
|
|
- `ui/src/App.tsx` - Added ConvertPage lazy import and three /convert route variants inside boardRoutes()
|
|
|
|
## Decisions Made
|
|
|
|
- **Direct fetch in submitConvertJob** — api.request() throws on any !res.ok response, but 422 is a valid business response carrying the MIME mismatch error body. Using raw fetch lets us return it as a ConvertMimeError value instead of catching and re-parsing an ApiError.
|
|
- **Direct EventSource for pre-submitted jobs** — useContentJob.submit() calls submitContentJob internally; it has no "track existing job" API. Since submitConvertJob already dispatched the convert job via the multipart route (not contentJobs route), a standalone EventSource connection is used to track progress.
|
|
- **FORMAT_GROUPS exported from ConvertPanel** — ConvertPage needs the same allowlist for normalizeFormatParam validation. Exporting from ConvertPanel avoids duplication and keeps them in sync.
|
|
- **AI fallback notice per group** — The capabilities object returns converter availability per category (imageConverter, audioVideoConverter, docConverter, dataConverter), not per format pair. Showing the notice at group level matches the granularity available from /api/system/converters.
|
|
|
|
## Deviations from Plan
|
|
|
|
None — plan executed exactly as written.
|
|
|
|
## Known Stubs
|
|
|
|
None — all conversion flows are fully wired to real backend endpoints.
|
|
|
|
## Issues Encountered
|
|
|
|
None — tsc compiles cleanly for all new/modified files. 17 pre-existing errors in unrelated files (AgentConfigForm, useKeyboardShortcuts, useNexusMode, usePiperTts, useVadRecorder, ContentStudio, PersonalAssistant) were present before this plan and not introduced here.
|
|
|
|
## User Setup Required
|
|
|
|
None — no external service configuration required.
|
|
|
|
## Next Phase Readiness
|
|
|
|
- All CONV requirements fulfilled (CONV-01 through CONV-09)
|
|
- /convert, /convert/:src, and /convert/:src/:tgt routes live and navigable
|
|
- Phase 42 is complete — all 6 plans executed
|
|
|
|
---
|
|
*Phase: 42-wallpapers-social-format-conversion-voice*
|
|
*Completed: 2026-04-04*
|
|
|
|
## Self-Check: PASSED
|
|
|
|
- `ui/src/api/convert.ts` — FOUND
|
|
- `ui/src/components/ConvertPanel.tsx` — FOUND
|
|
- `ui/src/pages/ConvertPage.tsx` — FOUND
|
|
- `.planning/phases/42-wallpapers-social-format-conversion-voice/42-06-SUMMARY.md` — FOUND
|
|
- Task 1 commit `c0040f66` — FOUND
|
|
- Task 2 commit `b5587c03` — FOUND
|