# 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
``` 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)