feat: task lane persistence + sidebar cleanup #121
@@ -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>
|
||||
)}
|
||||
|
||||
@@ -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">
|
||||
|
||||
@@ -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'}`}>
|
||||
|
||||
@@ -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} />
|
||||
|
||||
@@ -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}
|
||||
|
||||
@@ -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} />}
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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">
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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 && (
|
||||
|
||||
@@ -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">
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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}
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 && (
|
||||
|
||||
@@ -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'
|
||||
)}
|
||||
>
|
||||
|
||||
Reference in New Issue
Block a user