fix: clear cockpit state on session switch and add loading placeholders

- Reset triageMeta, psaTicketId, steps, and completedSteps when
  activeChatId changes (prevents stale triage data from previous session
  showing while AI processes the new one)
- Split the activeChatId and activeActions reset effects so triage
  only resets on session switch, not on every new action set
- Add loading placeholders to cockpit work zone: spinner + "analyzing"
  text in steps panel, "questions will appear here" in right panel
- Add centered "Starting session..." loader to FlowPilot page when
  loading with no messages yet (prefill creation period)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
chihlasm
2026-04-03 05:56:29 +00:00
parent b03f84aecf
commit 91e3f80707
2 changed files with 55 additions and 21 deletions

View File

@@ -87,11 +87,23 @@ export default function CockpitPage() {
prevMessageCountRef.current = session.messages.length
}, [session.messages.length, showOnboarding])
// Reset local step UI when switching cases or when a new action set arrives.
// Reset all cockpit-local state when switching cases.
// Triage data gets repopulated via onSessionLoadedRef after the async fetch.
useEffect(() => {
setActiveStepIndex(0)
setCompletedSteps(new Set())
}, [session.activeChatId, session.activeActions])
setTriageMeta({
client_name: null, asset_name: null, issue_category: null,
triage_hypothesis: null, evidence_items: [],
})
setPsaTicketId(null)
}, [session.activeChatId])
// Reset step UI when a new action set arrives from AI.
useEffect(() => {
setActiveStepIndex(0)
setCompletedSteps(new Set())
}, [session.activeActions])
// ── Triage handlers ──
@@ -306,28 +318,44 @@ export default function CockpitPage() {
<div className="flex min-h-0 overflow-hidden" style={{ height: `${workZonePct}%` }}>
{/* Left: Steps panel */}
<div className="flex-[55] min-w-0 p-3 overflow-y-auto border-r border-default">
<StepsPanel
actions={session.activeActions}
activeIndex={activeStepIndex}
completedSteps={completedSteps}
onStepComplete={handleStepComplete}
onStepSelect={handleStepSelect}
/>
{session.loading && session.activeActions.length === 0 ? (
<div className="flex flex-col items-center justify-center h-full text-center gap-2">
<Loader2 size={20} className="animate-spin text-accent" />
<p className="text-xs text-muted-foreground">FlowPilot is analyzing the issue...</p>
</div>
) : (
<StepsPanel
actions={session.activeActions}
activeIndex={activeStepIndex}
completedSteps={completedSteps}
onStepComplete={handleStepComplete}
onStepSelect={handleStepSelect}
/>
)}
</div>
{/* Right: FlowPilot Asks + What We Know */}
<div className="flex-[45] min-w-0 p-3 overflow-y-auto flex flex-col gap-3">
<FlowPilotAsks
questions={session.activeQuestions}
onAnswer={(answer) => {
void session.sendMessage(answer, { clearComposer: false })
}}
loading={session.loading}
/>
<WhatWeKnow
items={triageMeta.evidence_items}
onAdd={handleEvidenceAdd}
onEdit={handleEvidenceEdit}
/>
{session.loading && session.activeQuestions.length === 0 && triageMeta.evidence_items.length === 0 ? (
<div className="flex flex-col items-center justify-center h-full text-center gap-2">
<Sparkles size={18} className="text-muted" />
<p className="text-xs text-muted-foreground">Questions and evidence will appear here</p>
</div>
) : (
<>
<FlowPilotAsks
questions={session.activeQuestions}
onAnswer={(answer) => {
void session.sendMessage(answer, { clearComposer: false })
}}
loading={session.loading}
/>
<WhatWeKnow
items={triageMeta.evidence_items}
onAdd={handleEvidenceAdd}
onEdit={handleEvidenceEdit}
/>
</>
)}
</div>
</div>

View File

@@ -149,6 +149,12 @@ export default function FlowPilotPage() {
</p>
</div>
)}
{session.messages.length === 0 && session.loading && (
<div className="flex flex-col items-center justify-center h-full text-center gap-3">
<Loader2 size={24} className="animate-spin text-primary" />
<p className="text-sm text-muted-foreground">Starting session...</p>
</div>
)}
{session.messages.map((msg, i) => (
<ChatMessage
key={i}