96 lines
5.2 KiB
Markdown
96 lines
5.2 KiB
Markdown
# TaskLane Improvements Design
|
||
|
||
> **Date:** 2026-03-26
|
||
> **Status:** Approved
|
||
> **Scope:** `frontend/src/components/assistant/TaskLane.tsx`, `frontend/src/pages/AssistantChatPage.tsx`
|
||
|
||
---
|
||
|
||
## Context
|
||
|
||
The TaskLane is a right-side panel in the AI Assistant chat that renders structured questions and diagnostic actions from the AI. It launched with a working parse → render → submit pipeline, but has four UX issues and a missing submission flow design.
|
||
|
||
## Changes
|
||
|
||
### 1. Progressive Preview + Batch Submit
|
||
|
||
**Problem:** The "Send All Responses" button is disabled until every item is answered or skipped. Engineers often want to submit partial results — answer 2 of 3 questions, paste output from 1 of 4 commands, and let the AI work with what they have.
|
||
|
||
**Design:**
|
||
|
||
- **Submit enabled when ≥1 item is done or skipped.** Remaining pending items are simply omitted from the message (not auto-skipped — they're just not addressed).
|
||
- **Dynamic submit label:** `Send 2 of 6 Responses` when partial, `Send All Responses` when all handled.
|
||
- **Collapsible preview section** above the submit button:
|
||
- Toggle: `▶ Preview (2/6 done)` — collapsed by default
|
||
- Expands to show the formatted markdown message that will be sent to the AI
|
||
- Updates in real-time as items are answered/skipped
|
||
- Uses the same formatting logic as `handleTaskSubmit` (question answers in blockquotes, command output in code fences, skipped items noted)
|
||
- Styled as a `bg-code` block with `font-mono text-xs`, max-height ~150px with overflow scroll
|
||
- **Done items are re-editable.** Clicking anywhere on a completed (green) card reopens it in `active` state for editing. Cards get `cursor-pointer` and a subtle hover state (`hover:border-success/40`) to signal editability. This uses the existing `updateTask(idx, { state: 'active' })` mechanism — no new logic needed, just making the done card itself a click target.
|
||
- **No change to the TaskLane header or pending/active card behavior.** Changes affect the footer area and done card interactivity.
|
||
|
||
**Submission logic changes in `TaskLane.tsx`:**
|
||
- `allHandled` check on submit button changes from "all done/skipped" to "at least 1 done/skipped"
|
||
- `handleSubmit` sends only items that have state `done` or `skipped`
|
||
- Items still in `pending` or `active` state are excluded from the submission payload
|
||
|
||
**Submission logic in `AssistantChatPage.tsx` (`handleTaskSubmit`):**
|
||
- No changes needed — it already formats based on `r.state === 'done'` and `r.state === 'skipped'`, ignoring pending items.
|
||
|
||
### 2. TaskLane Reset on New Chat
|
||
|
||
**Problem:** Starting a new chat via `handleNewChat` doesn't clear the TaskLane. The previous session's questions/actions persist visually.
|
||
|
||
**Fix:** Add three lines to `handleNewChat` in `AssistantChatPage.tsx`:
|
||
```typescript
|
||
setShowTaskLane(false)
|
||
setActiveQuestions([])
|
||
setActiveActions([])
|
||
```
|
||
|
||
Same pattern already exists in `handleTaskSubmit`. Also add to `selectChat` for switching between chats.
|
||
|
||
### 3. Conditional Chat Input Border
|
||
|
||
**Problem:** The chat input area has `border-t border-border` which creates a double-border effect alongside the TaskLane footer's `border-t border-default`.
|
||
|
||
**Fix:** Conditionally remove the chat input's top border when the TaskLane is open:
|
||
```tsx
|
||
<div className={cn("px-3 sm:px-6 py-3 shrink-0", !showTaskLane && "border-t border-border")}>
|
||
```
|
||
|
||
The TaskLane's own left border and footer border provide sufficient visual separation when the panel is open. When closed, the chat input border returns.
|
||
|
||
### 4. Resizable TaskLane with Grip Handle
|
||
|
||
**Design:**
|
||
|
||
- **Drag zone:** 6px wide hit target on the left edge of the TaskLane, absolutely positioned.
|
||
- **Grip indicator:** Centered vertically on the drag zone — a 2×3 grid of small dots (6 dots total, `w-1 h-1 rounded-full bg-current`). Subtle `text-muted/40` by default, `text-muted-foreground` on hover.
|
||
- **Resize behavior:**
|
||
- `onMouseDown` on the grip starts tracking
|
||
- `mousemove` on `document` updates the width
|
||
- `mouseUp` on `document` stops tracking
|
||
- Width clamped between **280px** min and **50vw** max
|
||
- `cursor: col-resize` applied to the grip and to `document.body` during drag (prevents cursor flicker)
|
||
- `user-select: none` on `document.body` during drag (prevents text selection)
|
||
- **Persistence:** Width saved to `localStorage` key `rf-tasklane-width`. Read on mount, written on drag end. Default: `340px`.
|
||
- **Implementation:** All in `TaskLane.tsx` — no external libraries. Uses `useRef` for drag state (avoids re-renders during drag), `useState` for the width value.
|
||
|
||
**CSS change:** Replace `w-[340px]` with `style={{ width: panelWidth }}` on the outer div. Keep `shrink-0` so the chat area flexes.
|
||
|
||
---
|
||
|
||
## Files Modified
|
||
|
||
| File | Change |
|
||
|------|--------|
|
||
| `frontend/src/components/assistant/TaskLane.tsx` | Preview section, submit logic, resize handle, width persistence |
|
||
| `frontend/src/pages/AssistantChatPage.tsx` | TaskLane reset in `handleNewChat`/`selectChat`, conditional border |
|
||
|
||
## Out of Scope
|
||
|
||
- TaskLane rendering when loading historical sessions (markers are stripped from stored messages — no TaskLane on reload)
|
||
- Mobile-specific TaskLane layout (current: hidden on mobile, which is acceptable for now)
|
||
- Keyboard accessibility for resize handle (future enhancement)
|