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
21 changed files with 37 additions and 37 deletions
Showing only changes of commit 61c410e366 - Show all commits

View File

@@ -467,7 +467,7 @@ export function ConcludeSessionModal({
{/* Paused/Escalated: generating spinner */}
{(outcome === 'paused' || outcome === 'escalated') && generatingUpdate && (
<div className="flex flex-col items-center justify-center py-8 gap-3">
<Loader2 size={24} className="animate-spin text-orange-400" />
<Loader2 size={24} className="animate-spin text-blue-400" />
<p className="text-sm text-muted-foreground">Generating status update...</p>
</div>
)}

View File

@@ -31,9 +31,9 @@ export function PreparedSessions() {
<div className="card-flat p-5 fade-in" style={{ animationDelay: '200ms' }}>
<div className="flex items-center justify-between mb-3">
<div className="flex items-center gap-2">
<ClipboardList className="h-4 w-4 text-orange-400" />
<ClipboardList className="h-4 w-4 text-blue-400" />
<h3 className="font-heading text-sm font-semibold text-foreground">Prepared for You</h3>
<span className="flex h-5 w-5 items-center justify-center rounded-full bg-orange-400/20 text-[0.625rem] font-bold text-orange-400">
<span className="flex h-5 w-5 items-center justify-center rounded-full bg-blue-400/20 text-[0.625rem] font-bold text-blue-400">
{sessions.length}
</span>
</div>
@@ -52,7 +52,7 @@ export function PreparedSessions() {
onClick={() => handleStart(session)}
className={cn(
'group flex w-full items-center justify-between gap-3 rounded-lg border border-border px-4 py-3',
'text-left transition-all hover:border-orange-500/30 hover:bg-orange-500/5'
'text-left transition-all hover:border-blue-500/30 hover:bg-blue-500/5'
)}
>
<div className="min-w-0 flex-1">

View File

@@ -56,7 +56,7 @@ export function WeeklyCalendar({ events = {} }: WeeklyCalendarProps) {
borderBottom: day.isToday ? '2px solid #ea580c' : '1px solid var(--color-border-default)',
}}
>
<span className={`font-sans text-xs text-[0.625rem] uppercase tracking-widest ${day.isToday ? 'text-orange-400' : 'text-muted-foreground'}`}>
<span className={`font-sans text-xs text-[0.625rem] uppercase tracking-widest ${day.isToday ? 'text-blue-400' : 'text-muted-foreground'}`}>
{day.label}
</span>
<div className={`text-sm font-heading font-bold ${day.isToday ? 'text-foreground' : 'text-muted-foreground'}`}>

View File

@@ -108,7 +108,7 @@ export function FlowPilotActionBar({
<button
onClick={() => setShowStatusUpdate(true)}
disabled={isProcessing}
className="flex items-center justify-center gap-1.5 rounded-lg bg-orange-500/10 border border-orange-500/20 px-2.5 sm:px-4 py-2 min-h-[40px] sm:min-h-[44px] text-xs sm:text-sm font-medium text-orange-400 hover:bg-orange-500/20 disabled:opacity-40 disabled:pointer-events-none transition-colors"
className="flex items-center justify-center gap-1.5 rounded-lg bg-blue-500/10 border border-blue-500/20 px-2.5 sm:px-4 py-2 min-h-[40px] sm:min-h-[44px] text-xs sm:text-sm font-medium text-blue-400 hover:bg-blue-500/20 disabled:opacity-40 disabled:pointer-events-none transition-colors"
title="Share Update"
>
<FileText size={15} />

View File

@@ -148,7 +148,7 @@ export function FlowPilotSession({
<div className="mb-4">
<button
onClick={() => setShowShareCommunication(true)}
className="flex items-center gap-2 rounded-lg bg-orange-500/10 border border-orange-500/20 px-4 py-2.5 text-sm font-medium text-orange-400 hover:bg-orange-500/20 transition-colors"
className="flex items-center gap-2 rounded-lg bg-blue-500/10 border border-blue-500/20 px-4 py-2.5 text-sm font-medium text-blue-400 hover:bg-blue-500/20 transition-colors"
>
<FileText size={16} />
{shareLabel}

View File

@@ -168,7 +168,7 @@ export function StatusUpdateModal({ open, onClose, onGenerate, context = 'status
{/* Step 3: Generating */}
{step === 'generating' && (
<div className="flex flex-col items-center justify-center py-8 gap-3">
<Loader2 size={24} className="animate-spin text-orange-400" />
<Loader2 size={24} className="animate-spin text-blue-400" />
<p className="text-sm text-muted-foreground">
Generating {audience === 'email_draft' ? 'email draft' : audience === 'client_update' ? 'client update' : 'ticket notes'}...
</p>
@@ -180,7 +180,7 @@ export function StatusUpdateModal({ open, onClose, onGenerate, context = 'status
<div className="space-y-4">
{/* Meta badges */}
<div className="flex items-center gap-2 flex-wrap">
<span className="inline-flex items-center gap-1 rounded-full px-2.5 py-0.5 text-xs font-medium bg-orange-500/10 text-orange-400 border border-orange-500/20">
<span className="inline-flex items-center gap-1 rounded-full px-2.5 py-0.5 text-xs font-medium bg-blue-500/10 text-blue-400 border border-blue-500/20">
{AUDIENCES.find(a => a.value === result.audience)?.label}
</span>
<span className="inline-flex items-center gap-1 rounded-full px-2.5 py-0.5 text-xs font-medium bg-[rgba(255,255,255,0.06)] text-muted-foreground border border-[rgba(255,255,255,0.08)]">
@@ -209,7 +209,7 @@ export function StatusUpdateModal({ open, onClose, onGenerate, context = 'status
'flex items-center gap-2 rounded-lg px-4 py-2 min-h-[44px] text-sm font-medium transition-colors',
copied
? 'bg-emerald-500/20 border border-emerald-500/30 text-emerald-400'
: 'bg-orange-500/10 border border-orange-500/20 text-orange-400 hover:bg-orange-500/20'
: 'bg-blue-500/10 border border-blue-500/20 text-blue-400 hover:bg-blue-500/20'
)}
>
{copied ? <Check size={16} /> : <Copy size={16} />}

View File

@@ -145,7 +145,7 @@ export function TreeGridView({
onClick={() => onPrepareSession(tree)}
className={cn(
'rounded-md border border-border p-2 text-muted-foreground',
'hover:bg-orange-500/10 hover:text-orange-400 hover:border-orange-500/30'
'hover:bg-blue-500/10 hover:text-blue-400 hover:border-blue-500/30'
)}
title="Prepare session for engineer"
aria-label="Prepare session"

View File

@@ -148,7 +148,7 @@ export function TreeListView({
onClick={() => onPrepareSession(tree)}
className={cn(
'rounded-md border border-border p-1.5 text-muted-foreground',
'hover:bg-orange-500/10 hover:text-orange-400 hover:border-orange-500/30'
'hover:bg-blue-500/10 hover:text-blue-400 hover:border-blue-500/30'
)}
title="Prepare session for engineer"
aria-label="Prepare session"

View File

@@ -252,7 +252,7 @@ export function TreeTableView({
onClick={() => onPrepareSession(tree)}
className={cn(
'rounded-md border border-border p-1.5 text-muted-foreground',
'hover:bg-orange-500/10 hover:text-orange-400 hover:border-orange-500/30'
'hover:bg-blue-500/10 hover:text-blue-400 hover:border-blue-500/30'
)}
title="Prepare session for engineer"
aria-label="Prepare session"

View File

@@ -59,10 +59,10 @@ export function InlineVariablePrompt({
disabled={disabled}
className={cn(
'inline-flex items-center gap-1.5 rounded-md border px-2.5 py-1 text-sm font-medium transition-all',
'border-orange-500/40 bg-orange-500/5 text-orange-400',
'hover:border-orange-400/60 hover:bg-orange-500/10 hover:shadow-[0_0_12px_rgba(96,165,250,0.15)]',
'border-blue-500/40 bg-blue-500/5 text-blue-400',
'hover:border-blue-400/60 hover:bg-blue-500/10 hover:shadow-[0_0_12px_rgba(96,165,250,0.15)]',
'disabled:opacity-50 disabled:cursor-not-allowed',
isRequired && 'ring-1 ring-orange-500/20'
isRequired && 'ring-1 ring-blue-500/20'
)}
>
<Variable className="h-3.5 w-3.5" />
@@ -88,7 +88,7 @@ export function InlineVariablePrompt({
onBlur={() => {
if (!value) setIsEditing(false)
}}
className="rounded-md border border-orange-500/40 bg-orange-500/5 px-2.5 py-1 text-sm text-foreground shadow-[0_0_12px_rgba(96,165,250,0.15)] focus:border-orange-400 focus:outline-hidden focus:ring-1 focus:ring-orange-400/30"
className="rounded-md border border-blue-500/40 bg-blue-500/5 px-2.5 py-1 text-sm text-foreground shadow-[0_0_12px_rgba(96,165,250,0.15)] focus:border-blue-400 focus:outline-hidden focus:ring-1 focus:ring-blue-400/30"
>
<option value="">{placeholder}</option>
{options.map((opt) => (
@@ -117,7 +117,7 @@ export function InlineVariablePrompt({
onBlur={handleSubmit}
onKeyDown={handleKeyDown}
placeholder={placeholder}
className="w-48 rounded-md border border-orange-500/40 bg-orange-500/5 px-2.5 py-1 text-sm text-foreground shadow-[0_0_12px_rgba(96,165,250,0.15)] placeholder:text-muted-foreground focus:border-orange-400 focus:outline-hidden focus:ring-1 focus:ring-orange-400/30"
className="w-48 rounded-md border border-blue-500/40 bg-blue-500/5 px-2.5 py-1 text-sm text-foreground shadow-[0_0_12px_rgba(96,165,250,0.15)] placeholder:text-muted-foreground focus:border-blue-400 focus:outline-hidden focus:ring-1 focus:ring-blue-400/30"
/>
{helpText && (
<span className="absolute -bottom-5 left-0 text-[0.625rem] text-muted-foreground whitespace-nowrap">

View File

@@ -94,7 +94,7 @@ export function PrepareSessionModal({
{/* Header */}
<div className="flex items-center justify-between border-b border-border px-5 py-4">
<div className="flex items-center gap-2">
<FileText className="h-4 w-4 text-orange-400" />
<FileText className="h-4 w-4 text-blue-400" />
<h3 className="text-sm font-semibold text-foreground">Prepare Session</h3>
</div>
<button

View File

@@ -57,7 +57,7 @@ export function ScriptBuilderChat({
>
{msg.role === 'assistant' && (
<div className="shrink-0 w-8 h-8 rounded-lg bg-[rgba(96,165,250,0.1)] flex items-center justify-center mt-0.5">
<Bot size={16} className="text-orange-400" />
<Bot size={16} className="text-blue-400" />
</div>
)}
@@ -99,10 +99,10 @@ export function ScriptBuilderChat({
{isLoading && (
<div className="flex gap-3 justify-start">
<div className="shrink-0 w-8 h-8 rounded-lg bg-[rgba(96,165,250,0.1)] flex items-center justify-center">
<Bot size={16} className="text-orange-400" />
<Bot size={16} className="text-blue-400" />
</div>
<div className="card-flat rounded-xl px-4 py-3 text-sm flex items-center gap-2">
<Loader2 size={14} className="animate-spin text-orange-400" />
<Loader2 size={14} className="animate-spin text-blue-400" />
<span className="text-muted-foreground">Generating script...</span>
</div>
</div>

View File

@@ -55,7 +55,7 @@ export function ScriptCodeBlock({
<div className="mt-3 rounded-lg border bg-[rgba(0,0,0,0.3)] border-[rgba(255,255,255,0.06)] overflow-hidden">
{/* Header */}
<div className="flex items-center justify-between px-3 py-2 border-b border-[rgba(255,255,255,0.06)]">
<span className="font-mono text-xs text-orange-400 truncate">
<span className="font-mono text-xs text-blue-400 truncate">
{filename || 'script'}
</span>
{lineCount != null && (

View File

@@ -62,7 +62,7 @@ export function ScriptPreviewModal({
{/* Header */}
<div className="flex items-center justify-between px-5 py-3.5 border-b border-[rgba(255,255,255,0.06)]">
<div className="flex items-center gap-3 min-w-0">
<span className="font-mono text-sm text-orange-400 truncate">
<span className="font-mono text-sm text-blue-400 truncate">
{filename || 'script'}
</span>
<span className="shrink-0 font-mono text-[0.625rem] uppercase tracking-wider px-2 py-0.5 rounded-full bg-[rgba(255,255,255,0.06)] text-muted-foreground">

View File

@@ -440,7 +440,7 @@ export function ParameterizeAndSavePanel({
type="checkbox"
checked={shareWithTeam}
onChange={(e) => setShareWithTeam(e.target.checked)}
className="w-4 h-4 rounded border-border bg-card text-orange-500 focus:ring-orange-500/20"
className="w-4 h-4 rounded border-border bg-card text-blue-500 focus:ring-blue-500/20"
/>
<span className="text-sm text-foreground">Share with team</span>
</label>

View File

@@ -36,7 +36,7 @@ export function TicketLinkIndicator({ session, hasConnection, onLinkClick, onUnl
// Ticket linked
return (
<div className="card-flat inline-flex items-start gap-2.5 rounded-lg border border-border px-3 py-2">
<Ticket className="mt-0.5 h-4 w-4 shrink-0 text-orange-400" />
<Ticket className="mt-0.5 h-4 w-4 shrink-0 text-blue-400" />
<div className="min-w-0">
<p className="text-sm font-medium text-foreground">
CW #{session.psa_ticket_id}

View File

@@ -259,7 +259,7 @@ export function UpdateTicketModal({ open, onClose, sessionId, onPosted }: Props)
value={opt.value}
checked={noteType === opt.value}
onChange={() => setNoteType(opt.value)}
className="mt-0.5 accent-orange-400"
className="mt-0.5 accent-blue-400"
/>
<div className="min-w-0">
<span className="text-sm font-medium text-foreground">{opt.label}</span>

View File

@@ -755,7 +755,7 @@ export default function AssistantChatPage() {
)}
{messages.length >= 2 && (
<>
<button type="button" onClick={() => setShowStatusUpdate(true)} disabled={loading} className="flex items-center gap-1.5 rounded-lg px-2 py-1.5 text-xs text-muted-foreground hover:text-orange-400 hover:bg-orange-500/10 transition-colors disabled:opacity-40" title="Share status update">
<button type="button" onClick={() => setShowStatusUpdate(true)} disabled={loading} className="flex items-center gap-1.5 rounded-lg px-2 py-1.5 text-xs text-muted-foreground hover:text-blue-400 hover:bg-blue-500/10 transition-colors disabled:opacity-40" title="Share status update">
<FileText size={14} />
<span className="hidden sm:inline">Update</span>
</button>

View File

@@ -207,7 +207,7 @@ export default function FlowPilotSessionPage() {
<div className="flex gap-2">
<button
onClick={() => blocker.reset()}
className="flex-1 rounded-lg bg-gradient-to-r from-orange-500 to-orange-400 px-4 py-2.5 text-sm font-semibold text-white hover:brightness-110 active:scale-[0.98] transition-all"
className="flex-1 rounded-lg bg-gradient-to-r from-blue-500 to-blue-400 px-4 py-2.5 text-sm font-semibold text-white hover:brightness-110 active:scale-[0.98] transition-all"
>
Stay in Session
</button>
@@ -263,7 +263,7 @@ export default function FlowPilotSessionPage() {
<button
onClick={() => setShowStatusUpdate(true)}
disabled={fp.isProcessing}
className="flex items-center gap-1.5 rounded-lg bg-orange-500/10 border border-orange-500/20 px-3 py-1.5 text-xs font-medium text-orange-400 hover:bg-orange-500/20 disabled:opacity-40 disabled:pointer-events-none transition-colors"
className="flex items-center gap-1.5 rounded-lg bg-blue-500/10 border border-blue-500/20 px-3 py-1.5 text-xs font-medium text-blue-400 hover:bg-blue-500/20 disabled:opacity-40 disabled:pointer-events-none transition-colors"
title="Share Update"
>
<FileText size={13} />
@@ -333,7 +333,7 @@ export default function FlowPilotSessionPage() {
{fp.allSteps.length >= 2 && (
<button
onClick={() => { setShowOverflow(false); setShowStatusUpdate(true) }}
className="flex w-full items-center gap-2 px-3 py-2.5 text-xs text-orange-400 hover:bg-orange-500/10 transition-colors"
className="flex w-full items-center gap-2 px-3 py-2.5 text-xs text-blue-400 hover:bg-blue-500/10 transition-colors"
>
<FileText size={14} />
Share Update

View File

@@ -872,7 +872,7 @@ export function ProceduralNavigationPage() {
key={field.variable_name}
className={cn(
'rounded-lg border px-3 py-2.5',
isFilled ? 'border-border bg-accent' : 'border-orange-500/20 bg-orange-500/5'
isFilled ? 'border-border bg-accent' : 'border-blue-500/20 bg-blue-500/5'
)}
>
<div className="flex items-center justify-between gap-2">
@@ -880,7 +880,7 @@ export function ProceduralNavigationPage() {
{isFilled ? (
<Check className="h-3.5 w-3.5 shrink-0 text-emerald-400" />
) : (
<AlertCircle className="h-3.5 w-3.5 shrink-0 text-orange-400" />
<AlertCircle className="h-3.5 w-3.5 shrink-0 text-blue-400" />
)}
<span className="text-xs font-medium text-muted-foreground truncate">
{field.label}
@@ -903,7 +903,7 @@ export function ProceduralNavigationPage() {
value={editingVarValue}
onChange={(e) => setEditingVarValue(e.target.value)}
autoFocus
className="w-full rounded-md border border-orange-500/30 bg-card px-2.5 py-1.5 text-sm text-foreground focus:border-orange-400 focus:outline-hidden focus:ring-1 focus:ring-orange-400/30"
className="w-full rounded-md border border-blue-500/30 bg-card px-2.5 py-1.5 text-sm text-foreground focus:border-blue-400 focus:outline-hidden focus:ring-1 focus:ring-blue-400/30"
>
<option value="">{field.placeholder || 'Select...'}</option>
{field.options.map((opt) => (
@@ -917,7 +917,7 @@ export function ProceduralNavigationPage() {
autoFocus
rows={3}
placeholder={field.placeholder}
className="w-full rounded-md border border-orange-500/30 bg-card px-2.5 py-1.5 text-sm text-foreground placeholder:text-muted-foreground focus:border-orange-400 focus:outline-hidden focus:ring-1 focus:ring-orange-400/30"
className="w-full rounded-md border border-blue-500/30 bg-card px-2.5 py-1.5 text-sm text-foreground placeholder:text-muted-foreground focus:border-blue-400 focus:outline-hidden focus:ring-1 focus:ring-blue-400/30"
/>
) : (
<input
@@ -927,7 +927,7 @@ export function ProceduralNavigationPage() {
onKeyDown={(e) => { if (e.key === 'Enter') saveEditingVar() }}
autoFocus
placeholder={field.placeholder}
className="w-full rounded-md border border-orange-500/30 bg-card px-2.5 py-1.5 text-sm text-foreground placeholder:text-muted-foreground focus:border-orange-400 focus:outline-hidden focus:ring-1 focus:ring-orange-400/30"
className="w-full rounded-md border border-blue-500/30 bg-card px-2.5 py-1.5 text-sm text-foreground placeholder:text-muted-foreground focus:border-blue-400 focus:outline-hidden focus:ring-1 focus:ring-blue-400/30"
/>
)}
{field.help_text && (

View File

@@ -564,7 +564,7 @@ export function SessionHistoryPage() {
session.outcome === 'escalated' && 'bg-blue-500/20 text-blue-300',
session.outcome === 'unresolved' && 'bg-rose-500/20 text-rose-300',
session.outcome === 'cancelled' && 'bg-zinc-500/20 text-zinc-300',
session.outcome === 'resolved_externally' && 'bg-orange-500/20 text-orange-300',
session.outcome === 'resolved_externally' && 'bg-blue-500/20 text-blue-300',
!session.outcome && 'bg-accent text-muted-foreground'
)}
>