feat: task lane persistence + sidebar cleanup #121

Merged
chihlasm merged 49 commits from feat/task-lane-persistence into main 2026-03-29 16:59:41 +00:00
3 changed files with 16 additions and 4 deletions
Showing only changes of commit 96602a6676 - Show all commits

View File

@@ -117,6 +117,9 @@ def _build_session_detail(session: AISession) -> AISessionDetail:
resolved_at=session.resolved_at,
steps=step_responses,
conversation_messages=session.conversation_messages or [],
pending_task_lane=session.pending_task_lane,
is_branching=getattr(session, 'is_branching', False),
active_branch_id=str(session.active_branch_id) if getattr(session, 'active_branch_id', None) else None,
)

View File

@@ -1,4 +1,4 @@
import { useState, useEffect } from 'react'
import { useState, useEffect, useRef } from 'react'
import { ArrowLeft, Loader2, Save, Scan, Trash2 } from 'lucide-react'
import { Input } from '@/components/ui/Input'
import { Textarea } from '@/components/ui/Textarea'
@@ -64,16 +64,19 @@ export function ScriptTemplateEditor({ templateId, onBack, onSaved }: Props) {
const [detectedCandidates, setDetectedCandidates] = useState<ParameterCandidate[]>([])
const [showStepper, setShowStepper] = useState(false)
const [detectionSummary, setDetectionSummary] = useState<string | null>(null)
const acceptingCandidateRef = useRef(false)
const { canShareScriptTemplate } = usePermissions()
// Dismiss stepper if user edits the script body during detection
// Dismiss stepper if user manually edits the script body during detection
// (but NOT when handleAcceptCandidate programmatically updates script_body)
const scriptBodyRef = form.script_body
useEffect(() => {
if (showStepper) {
if (showStepper && !acceptingCandidateRef.current) {
setShowStepper(false)
setDetectedCandidates([])
}
acceptingCandidateRef.current = false
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [scriptBodyRef])
@@ -263,6 +266,7 @@ export function ScriptTemplateEditor({ templateId, onBack, onSaved }: Props) {
sensitive: overrides.sensitive,
}
acceptingCandidateRef.current = true
setForm(f => ({
...f,
script_body: updatedScript,

View File

@@ -102,7 +102,9 @@ export default function AssistantChatPage() {
// Restore session from sessionStorage on mount (when URL has no session ID)
useEffect(() => {
console.log('[AssistantChat] Mount restore check — urlSessionId:', urlSessionId, 'activeChatId:', activeChatId)
if (!urlSessionId && activeChatId) {
console.log('[AssistantChat] Calling selectChat to restore:', activeChatId)
selectChat(activeChatId)
}
}, []) // eslint-disable-line react-hooks/exhaustive-deps
@@ -207,6 +209,7 @@ export default function AssistantChatPage() {
}
const selectChat = useCallback(async (chatId: string) => {
console.log('[AssistantChat] selectChat called with:', chatId)
setActiveChatId(chatId)
// Clear TaskLane when switching chats — will restore from backend if available
setShowTaskLane(false)
@@ -214,6 +217,7 @@ export default function AssistantChatPage() {
setActiveActions([])
try {
const detail = await aiSessionsApi.getSession(chatId)
console.log('[AssistantChat] getSession response — messages:', detail.conversation_messages?.length, 'pending_task_lane:', !!detail.pending_task_lane)
setMessages(
(detail.conversation_messages || []).map(m => ({
role: m.role as 'user' | 'assistant',
@@ -237,7 +241,8 @@ export default function AssistantChatPage() {
}
}
}
} catch {
} catch (err) {
console.error('[AssistantChat] Failed to load chat session:', err)
setMessages([])
}
}, [])