refactor: normalize FlowPilot/Assistant/ScriptBuilder to design system tokens
Replace hardcoded Tailwind color utilities with semantic CSS variable tokens across 31 files in the FlowPilot, Assistant Chat, and Script Builder feature communities — the areas graphify identified as design-system-free. - text-blue-400 → text-accent, bg-blue-500/10 → bg-accent-dim, border-blue-500/20 → border-accent/20 - text-amber-400 → text-warning, bg-amber-400/10 → bg-warning-dim, border-l-amber-500 → border-l-warning - text-rose-400/500 → text-danger, bg-rose-500/10 → bg-danger-dim - text-emerald-400 → text-success, bg-emerald-500/10 → bg-success-dim, border-l-emerald-500 → border-l-success - bg-white/[0.08] → bg-elevated (opacity hack → semantic surface token) - bg-gradient-to-r from-blue-500 to-blue-400 → bg-accent (no gradient surfaces) - bg-[#60a5fa] → bg-accent (hard-coded hex removed) Also adds graphify-out/ to .gitignore. Theme resilience: accent color has changed twice in 5 weeks. Semantic tokens mean the next change is a 1-line edit in index.css, not 110 grep-and-replace. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
4
.gitignore
vendored
4
.gitignore
vendored
@@ -233,3 +233,7 @@ package.json
|
|||||||
package-lock.json
|
package-lock.json
|
||||||
.worktrees/
|
.worktrees/
|
||||||
.gstack/
|
.gstack/
|
||||||
|
|
||||||
|
# graphify knowledge graph outputs
|
||||||
|
graphify-out/
|
||||||
|
.graphify_python
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ export function ChatMessage({ role, content, suggestedFlows }: ChatMessageProps)
|
|||||||
className={`shrink-0 w-8 h-8 rounded-full flex items-center justify-center ${
|
className={`shrink-0 w-8 h-8 rounded-full flex items-center justify-center ${
|
||||||
role === 'assistant'
|
role === 'assistant'
|
||||||
? 'bg-primary/15 text-primary'
|
? 'bg-primary/15 text-primary'
|
||||||
: 'bg-white/[0.08] text-muted-foreground'
|
: 'bg-elevated text-muted-foreground'
|
||||||
}`}
|
}`}
|
||||||
>
|
>
|
||||||
{role === 'assistant' ? <Sparkles size={14} /> : <User size={14} />}
|
{role === 'assistant' ? <Sparkles size={14} /> : <User size={14} />}
|
||||||
|
|||||||
@@ -193,7 +193,7 @@ function ChatItem({
|
|||||||
className={cn(
|
className={cn(
|
||||||
'group flex items-center gap-2 px-3 py-2.5 mx-1.5 rounded-lg cursor-pointer transition-colors',
|
'group flex items-center gap-2 px-3 py-2.5 mx-1.5 rounded-lg cursor-pointer transition-colors',
|
||||||
confirming
|
confirming
|
||||||
? 'bg-rose-500/10 border border-rose-500/20'
|
? 'bg-danger-dim border border-danger/20'
|
||||||
: isActive
|
: isActive
|
||||||
? 'bg-accent-dim text-foreground'
|
? 'bg-accent-dim text-foreground'
|
||||||
: 'text-muted-foreground hover:bg-input hover:text-foreground'
|
: 'text-muted-foreground hover:bg-input hover:text-foreground'
|
||||||
@@ -203,10 +203,10 @@ function ChatItem({
|
|||||||
<div className="flex-1 min-w-0">
|
<div className="flex-1 min-w-0">
|
||||||
{confirming ? (
|
{confirming ? (
|
||||||
<div className="flex items-center gap-2">
|
<div className="flex items-center gap-2">
|
||||||
<span className="text-[0.75rem] text-rose-400 font-medium">Delete?</span>
|
<span className="text-[0.75rem] text-danger font-medium">Delete?</span>
|
||||||
<button
|
<button
|
||||||
onClick={e => { e.stopPropagation(); onDelete(); setConfirming(false) }}
|
onClick={e => { e.stopPropagation(); onDelete(); setConfirming(false) }}
|
||||||
className="text-[0.6875rem] font-medium text-rose-400 hover:text-rose-300 px-1.5 py-0.5 rounded bg-rose-500/15 hover:bg-rose-500/25 transition-colors"
|
className="text-[0.6875rem] font-medium text-danger hover:text-danger px-1.5 py-0.5 rounded bg-danger/15 hover:bg-danger/25 transition-colors"
|
||||||
>
|
>
|
||||||
Yes
|
Yes
|
||||||
</button>
|
</button>
|
||||||
@@ -230,14 +230,14 @@ function ChatItem({
|
|||||||
<div className="flex items-center gap-0.5 opacity-0 group-hover:opacity-100 transition-opacity">
|
<div className="flex items-center gap-0.5 opacity-0 group-hover:opacity-100 transition-opacity">
|
||||||
<button
|
<button
|
||||||
onClick={e => { e.stopPropagation(); onTogglePin() }}
|
onClick={e => { e.stopPropagation(); onTogglePin() }}
|
||||||
className="p-1 rounded hover:bg-white/[0.08]"
|
className="p-1 rounded hover:bg-elevated"
|
||||||
title={chat.pinned ? 'Unpin' : 'Pin'}
|
title={chat.pinned ? 'Unpin' : 'Pin'}
|
||||||
>
|
>
|
||||||
<Pin size={12} className={chat.pinned ? 'text-primary' : ''} />
|
<Pin size={12} className={chat.pinned ? 'text-primary' : ''} />
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
onClick={e => { e.stopPropagation(); setConfirming(true) }}
|
onClick={e => { e.stopPropagation(); setConfirming(true) }}
|
||||||
className="p-1 rounded hover:bg-white/[0.08] text-muted-foreground hover:text-rose-400"
|
className="p-1 rounded hover:bg-elevated text-muted-foreground hover:text-danger"
|
||||||
title="Delete"
|
title="Delete"
|
||||||
>
|
>
|
||||||
<Trash2 size={12} />
|
<Trash2 size={12} />
|
||||||
|
|||||||
@@ -36,7 +36,7 @@ const OUTCOMES: { value: ConclusionOutcome; label: string; description: string;
|
|||||||
label: 'Resolved',
|
label: 'Resolved',
|
||||||
description: 'Issue has been fixed or answered',
|
description: 'Issue has been fixed or answered',
|
||||||
icon: CheckCircle2,
|
icon: CheckCircle2,
|
||||||
color: 'text-emerald-400',
|
color: 'text-success',
|
||||||
bg: 'bg-emerald-400/10',
|
bg: 'bg-emerald-400/10',
|
||||||
border: 'border-emerald-400/30',
|
border: 'border-emerald-400/30',
|
||||||
},
|
},
|
||||||
@@ -45,17 +45,17 @@ const OUTCOMES: { value: ConclusionOutcome; label: string; description: string;
|
|||||||
label: 'Escalate',
|
label: 'Escalate',
|
||||||
description: 'Needs to be handed off or escalated',
|
description: 'Needs to be handed off or escalated',
|
||||||
icon: ArrowUpRight,
|
icon: ArrowUpRight,
|
||||||
color: 'text-amber-400',
|
color: 'text-warning',
|
||||||
bg: 'bg-amber-400/10',
|
bg: 'bg-warning-dim',
|
||||||
border: 'border-amber-400/30',
|
border: 'border-warning/30',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
value: 'paused',
|
value: 'paused',
|
||||||
label: 'Paused',
|
label: 'Paused',
|
||||||
description: 'Continuing later — saving progress',
|
description: 'Continuing later — saving progress',
|
||||||
icon: Pause,
|
icon: Pause,
|
||||||
color: 'text-blue-400',
|
color: 'text-accent',
|
||||||
bg: 'bg-blue-400/10',
|
bg: 'bg-accent-dim',
|
||||||
border: 'border-blue-400/30',
|
border: 'border-blue-400/30',
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
@@ -362,7 +362,7 @@ export function ConcludeSessionModal({
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
{error && (
|
{error && (
|
||||||
<div className="text-sm text-rose-400 bg-rose-400/10 border border-rose-400/20 rounded-lg px-4 py-2">
|
<div className="text-sm text-danger bg-danger-dim border border-danger/20 rounded-lg px-4 py-2">
|
||||||
{error}
|
{error}
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
@@ -410,7 +410,7 @@ export function ConcludeSessionModal({
|
|||||||
<div className="h-3 bg-elevated rounded w-4/5" />
|
<div className="h-3 bg-elevated rounded w-4/5" />
|
||||||
</div>
|
</div>
|
||||||
) : streamError ? (
|
) : streamError ? (
|
||||||
<div className="flex items-center gap-2 text-sm text-amber-400">
|
<div className="flex items-center gap-2 text-sm text-warning">
|
||||||
<AlertTriangle size={14} />
|
<AlertTriangle size={14} />
|
||||||
{streamError}
|
{streamError}
|
||||||
</div>
|
</div>
|
||||||
@@ -467,7 +467,7 @@ export function ConcludeSessionModal({
|
|||||||
{/* Paused/Escalated: generating spinner */}
|
{/* Paused/Escalated: generating spinner */}
|
||||||
{(outcome === 'paused' || outcome === 'escalated') && generatingUpdate && (
|
{(outcome === 'paused' || outcome === 'escalated') && generatingUpdate && (
|
||||||
<div className="flex flex-col items-center justify-center py-8 gap-3">
|
<div className="flex flex-col items-center justify-center py-8 gap-3">
|
||||||
<Loader2 size={24} className="animate-spin text-blue-400" />
|
<Loader2 size={24} className="animate-spin text-accent" />
|
||||||
<p className="text-sm text-muted-foreground">Generating status update...</p>
|
<p className="text-sm text-muted-foreground">Generating status update...</p>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
@@ -544,7 +544,7 @@ export function ConcludeSessionModal({
|
|||||||
{outcome === 'paused' && (
|
{outcome === 'paused' && (
|
||||||
<button
|
<button
|
||||||
onClick={handleResumeNew}
|
onClick={handleResumeNew}
|
||||||
className="flex items-center gap-2 px-4 py-2.5 rounded-lg text-sm font-medium text-blue-400 bg-blue-400/10 border border-blue-400/20 hover:bg-blue-400/15 transition-all"
|
className="flex items-center gap-2 px-4 py-2.5 rounded-lg text-sm font-medium text-accent bg-accent-dim border border-accent/20 hover:bg-accent/15 transition-all"
|
||||||
>
|
>
|
||||||
<RefreshCw size={14} />
|
<RefreshCw size={14} />
|
||||||
Resume in New Chat
|
Resume in New Chat
|
||||||
@@ -566,7 +566,7 @@ export function ConcludeSessionModal({
|
|||||||
className={cn(
|
className={cn(
|
||||||
'flex items-center gap-2 px-4 py-2.5 rounded-lg text-sm font-semibold transition-all',
|
'flex items-center gap-2 px-4 py-2.5 rounded-lg text-sm font-semibold transition-all',
|
||||||
copied
|
copied
|
||||||
? 'bg-emerald-400/15 text-emerald-400 border border-emerald-400/30'
|
? 'bg-emerald-400/15 text-success border border-emerald-400/30'
|
||||||
: 'bg-primary text-white hover:brightness-110 active:scale-[0.98]'
|
: 'bg-primary text-white hover:brightness-110 active:scale-[0.98]'
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
|
|||||||
@@ -360,7 +360,7 @@ export function TaskLane({ questions, actions, sessionId, onSubmit, onClose, loa
|
|||||||
<section>
|
<section>
|
||||||
<div className="sticky top-0 z-10 pb-2" style={{ background: 'var(--color-bg-page)' }}>
|
<div className="sticky top-0 z-10 pb-2" style={{ background: 'var(--color-bg-page)' }}>
|
||||||
<div className="flex items-center gap-2 text-[10px] font-semibold uppercase tracking-[1.2px] text-muted-foreground pl-0.5">
|
<div className="flex items-center gap-2 text-[10px] font-semibold uppercase tracking-[1.2px] text-muted-foreground pl-0.5">
|
||||||
<span className="w-1.5 h-1.5 rounded-full bg-[#60a5fa]" />
|
<span className="w-1.5 h-1.5 rounded-full bg-accent" />
|
||||||
Diagnostic Checks
|
Diagnostic Checks
|
||||||
{actionTasks.every(a => a.state === 'done' || a.state === 'skipped') && (
|
{actionTasks.every(a => a.state === 'done' || a.state === 'skipped') && (
|
||||||
<Check size={10} className="text-success" />
|
<Check size={10} className="text-success" />
|
||||||
|
|||||||
@@ -9,9 +9,9 @@ interface AISessionListItemProps {
|
|||||||
|
|
||||||
const STATUS_CONFIG = {
|
const STATUS_CONFIG = {
|
||||||
active: { icon: Clock, color: 'text-primary', label: 'Active' },
|
active: { icon: Clock, color: 'text-primary', label: 'Active' },
|
||||||
paused: { icon: Pause, color: 'text-amber-400', label: 'Paused' },
|
paused: { icon: Pause, color: 'text-warning', label: 'Paused' },
|
||||||
resolved: { icon: CheckCircle2, color: 'text-emerald-400', label: 'Resolved' },
|
resolved: { icon: CheckCircle2, color: 'text-success', label: 'Resolved' },
|
||||||
escalated: { icon: ArrowUpRight, color: 'text-amber-400', label: 'Escalated' },
|
escalated: { icon: ArrowUpRight, color: 'text-warning', label: 'Escalated' },
|
||||||
abandoned: { icon: AlertCircle, color: 'text-text-muted', label: 'Abandoned' },
|
abandoned: { icon: AlertCircle, color: 'text-text-muted', label: 'Abandoned' },
|
||||||
} as const
|
} as const
|
||||||
|
|
||||||
@@ -64,7 +64,7 @@ export function AISessionListItem({ session }: AISessionListItemProps) {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{session.session_rating && (
|
{session.session_rating && (
|
||||||
<span className="font-sans text-xs text-xs text-amber-400">
|
<span className="font-sans text-xs text-xs text-warning">
|
||||||
{'★'.repeat(session.session_rating)}
|
{'★'.repeat(session.session_rating)}
|
||||||
</span>
|
</span>
|
||||||
)}
|
)}
|
||||||
|
|||||||
@@ -35,9 +35,9 @@ export function EscalateModal({ open, onClose, onEscalate, isProcessing, hasPsaT
|
|||||||
return (
|
return (
|
||||||
<Modal isOpen={open} onClose={handleClose} title="Escalate Session" size="sm">
|
<Modal isOpen={open} onClose={handleClose} title="Escalate Session" size="sm">
|
||||||
<div className="space-y-4">
|
<div className="space-y-4">
|
||||||
<div className="flex items-start gap-3 rounded-xl border border-amber-400/20 bg-amber-400/5 p-3">
|
<div className="flex items-start gap-3 rounded-xl border border-warning/20 bg-warning/5 p-3">
|
||||||
<AlertTriangle size={16} className="text-amber-400 shrink-0 mt-0.5" />
|
<AlertTriangle size={16} className="text-warning shrink-0 mt-0.5" />
|
||||||
<p className="text-sm text-amber-400">
|
<p className="text-sm text-warning">
|
||||||
This will mark the session as requesting escalation. Team members will see it in their escalation queue and can pick it up with full context.
|
This will mark the session as requesting escalation. Team members will see it in their escalation queue and can pick it up with full context.
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
@@ -70,7 +70,7 @@ export function EscalateModal({ open, onClose, onEscalate, isProcessing, hasPsaT
|
|||||||
<button
|
<button
|
||||||
onClick={handleSubmit}
|
onClick={handleSubmit}
|
||||||
disabled={!reason.trim() || reason.trim().length < 5 || isProcessing}
|
disabled={!reason.trim() || reason.trim().length < 5 || isProcessing}
|
||||||
className="flex-1 flex items-center justify-center gap-2 rounded-lg bg-amber-500/90 px-4 py-2.5 min-h-[44px] text-sm font-semibold text-white hover:bg-amber-500 active:scale-[0.98] disabled:opacity-40 transition-all"
|
className="flex-1 flex items-center justify-center gap-2 rounded-lg bg-warning px-4 py-2.5 min-h-[44px] text-sm font-semibold text-white hover:bg-warning active:scale-[0.98] disabled:opacity-40 transition-all"
|
||||||
>
|
>
|
||||||
{isProcessing ? (
|
{isProcessing ? (
|
||||||
<Loader2 size={14} className="animate-spin" />
|
<Loader2 size={14} className="animate-spin" />
|
||||||
|
|||||||
@@ -50,7 +50,7 @@ export function EscalationQueue({ onPickup }: EscalationQueueProps) {
|
|||||||
if (error) {
|
if (error) {
|
||||||
return (
|
return (
|
||||||
<div className="py-12 text-center">
|
<div className="py-12 text-center">
|
||||||
<p className="text-sm text-rose-400">{error}</p>
|
<p className="text-sm text-danger">{error}</p>
|
||||||
<button
|
<button
|
||||||
onClick={loadQueue}
|
onClick={loadQueue}
|
||||||
className="mt-2 text-xs text-muted-foreground hover:text-foreground transition-colors"
|
className="mt-2 text-xs text-muted-foreground hover:text-foreground transition-colors"
|
||||||
@@ -99,7 +99,7 @@ export function EscalationQueue({ onPickup }: EscalationQueueProps) {
|
|||||||
{session.problem_summary || 'Untitled session'}
|
{session.problem_summary || 'Untitled session'}
|
||||||
</p>
|
</p>
|
||||||
{session.escalation_reason && (
|
{session.escalation_reason && (
|
||||||
<p className="mt-1 text-xs text-amber-400 line-clamp-2">
|
<p className="mt-1 text-xs text-warning line-clamp-2">
|
||||||
Reason: {session.escalation_reason}
|
Reason: {session.escalation_reason}
|
||||||
</p>
|
</p>
|
||||||
)}
|
)}
|
||||||
|
|||||||
@@ -91,7 +91,7 @@ export function FlowPilotActionBar({
|
|||||||
<button
|
<button
|
||||||
onClick={() => { setShowResolve(true); setShowEscalate(false) }}
|
onClick={() => { setShowResolve(true); setShowEscalate(false) }}
|
||||||
disabled={!canResolve || isProcessing}
|
disabled={!canResolve || isProcessing}
|
||||||
className="flex items-center justify-center gap-1.5 rounded-lg bg-emerald-500/10 border border-emerald-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-emerald-400 hover:bg-emerald-500/20 disabled:opacity-40 disabled:pointer-events-none transition-colors"
|
className="flex items-center justify-center gap-1.5 rounded-lg bg-success-dim border border-success/20 px-2.5 sm:px-4 py-2 min-h-[40px] sm:min-h-[44px] text-xs sm:text-sm font-medium text-success hover:bg-success/20 disabled:opacity-40 disabled:pointer-events-none transition-colors"
|
||||||
>
|
>
|
||||||
<CheckCircle2 size={15} />
|
<CheckCircle2 size={15} />
|
||||||
Resolve
|
Resolve
|
||||||
@@ -99,7 +99,7 @@ export function FlowPilotActionBar({
|
|||||||
<button
|
<button
|
||||||
onClick={() => setShowEscalate(true)}
|
onClick={() => setShowEscalate(true)}
|
||||||
disabled={!canEscalate || isProcessing}
|
disabled={!canEscalate || isProcessing}
|
||||||
className="flex items-center justify-center gap-1.5 rounded-lg bg-amber-500/10 border border-amber-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-amber-400 hover:bg-amber-500/20 disabled:opacity-40 disabled:pointer-events-none transition-colors"
|
className="flex items-center justify-center gap-1.5 rounded-lg bg-warning-dim border border-warning/20 px-2.5 sm:px-4 py-2 min-h-[40px] sm:min-h-[44px] text-xs sm:text-sm font-medium text-warning hover:bg-warning/20 disabled:opacity-40 disabled:pointer-events-none transition-colors"
|
||||||
>
|
>
|
||||||
<ArrowUpRight size={15} />
|
<ArrowUpRight size={15} />
|
||||||
Escalate
|
Escalate
|
||||||
@@ -108,7 +108,7 @@ export function FlowPilotActionBar({
|
|||||||
<button
|
<button
|
||||||
onClick={() => setShowStatusUpdate(true)}
|
onClick={() => setShowStatusUpdate(true)}
|
||||||
disabled={isProcessing}
|
disabled={isProcessing}
|
||||||
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"
|
className="flex items-center justify-center gap-1.5 rounded-lg bg-accent-dim border border-accent/20 px-2.5 sm:px-4 py-2 min-h-[40px] sm:min-h-[44px] text-xs sm:text-sm font-medium text-accent hover:bg-accent/20 disabled:opacity-40 disabled:pointer-events-none transition-colors"
|
||||||
title="Share Update"
|
title="Share Update"
|
||||||
>
|
>
|
||||||
<FileText size={15} />
|
<FileText size={15} />
|
||||||
@@ -166,7 +166,7 @@ export function FlowPilotActionBar({
|
|||||||
<button
|
<button
|
||||||
onClick={handleResolve}
|
onClick={handleResolve}
|
||||||
disabled={resolutionSummary.length < 5 || submitting}
|
disabled={resolutionSummary.length < 5 || submitting}
|
||||||
className="rounded-lg bg-emerald-500/20 border border-emerald-500/30 px-4 py-2 min-h-[44px] text-sm font-medium text-emerald-400 hover:bg-emerald-500/30 disabled:opacity-50 transition-colors"
|
className="rounded-lg bg-success/20 border border-success/30 px-4 py-2 min-h-[44px] text-sm font-medium text-success hover:bg-success/30 disabled:opacity-50 transition-colors"
|
||||||
>
|
>
|
||||||
{submitting ? 'Resolving...' : 'Resolve Session'}
|
{submitting ? 'Resolving...' : 'Resolve Session'}
|
||||||
</button>
|
</button>
|
||||||
@@ -193,7 +193,7 @@ export function FlowPilotActionBar({
|
|||||||
<button
|
<button
|
||||||
onClick={handleAbandon}
|
onClick={handleAbandon}
|
||||||
disabled={submitting}
|
disabled={submitting}
|
||||||
className="rounded-lg bg-rose-500/20 border border-rose-500/30 px-4 py-2 min-h-[44px] text-sm font-medium text-rose-400 hover:bg-rose-500/30 disabled:opacity-50 transition-colors"
|
className="rounded-lg bg-danger/20 border border-danger/30 px-4 py-2 min-h-[44px] text-sm font-medium text-danger hover:bg-danger/30 disabled:opacity-50 transition-colors"
|
||||||
>
|
>
|
||||||
{submitting ? 'Closing...' : 'Close Session'}
|
{submitting ? 'Closing...' : 'Close Session'}
|
||||||
</button>
|
</button>
|
||||||
|
|||||||
@@ -155,7 +155,7 @@ export function FlowPilotIntake({ onSubmit, isLoading, defaultProblem }: FlowPil
|
|||||||
</div>
|
</div>
|
||||||
<button
|
<button
|
||||||
onClick={handleClearTicket}
|
onClick={handleClearTicket}
|
||||||
className="ml-2 rounded-md p-1 text-muted-foreground hover:bg-white/[0.06] hover:text-foreground transition-colors"
|
className="ml-2 rounded-md p-1 text-muted-foreground hover:bg-elevated hover:text-foreground transition-colors"
|
||||||
>
|
>
|
||||||
<X size={14} />
|
<X size={14} />
|
||||||
</button>
|
</button>
|
||||||
@@ -215,7 +215,7 @@ export function FlowPilotIntake({ onSubmit, isLoading, defaultProblem }: FlowPil
|
|||||||
Pull from Ticket
|
Pull from Ticket
|
||||||
</button>
|
</button>
|
||||||
{psaChecked && !psaConnection && (
|
{psaChecked && !psaConnection && (
|
||||||
<span className="flex items-center gap-1 text-[0.625rem] text-amber-400/80">
|
<span className="flex items-center gap-1 text-[0.625rem] text-warning/80">
|
||||||
<AlertTriangle size={10} />
|
<AlertTriangle size={10} />
|
||||||
No PSA connected
|
No PSA connected
|
||||||
</span>
|
</span>
|
||||||
|
|||||||
@@ -243,17 +243,17 @@ export function FlowPilotMessageBar({ onRespond, disabled = false, isProcessing
|
|||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
onClick={() => handleRemoveUpload(upload.id)}
|
onClick={() => handleRemoveUpload(upload.id)}
|
||||||
className="absolute -top-1 -right-1 w-4 h-4 rounded-full bg-background border border-border flex items-center justify-center hover:bg-rose-500/20 transition-colors"
|
className="absolute -top-1 -right-1 w-4 h-4 rounded-full bg-background border border-border flex items-center justify-center hover:bg-danger/20 transition-colors"
|
||||||
>
|
>
|
||||||
<X size={8} className="text-muted-foreground" />
|
<X size={8} className="text-muted-foreground" />
|
||||||
</button>
|
</button>
|
||||||
)}
|
)}
|
||||||
{upload.status === 'error' && (
|
{upload.status === 'error' && (
|
||||||
<div
|
<div
|
||||||
className="absolute inset-0 bg-rose-500/20 border-2 border-rose-500 flex items-center justify-center cursor-pointer"
|
className="absolute inset-0 bg-danger/20 border-2 border-danger flex items-center justify-center cursor-pointer"
|
||||||
onClick={() => retryUpload(upload.id)}
|
onClick={() => retryUpload(upload.id)}
|
||||||
>
|
>
|
||||||
<RotateCcw size={10} className="text-rose-500" />
|
<RotateCcw size={10} className="text-danger" />
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -148,7 +148,7 @@ export function FlowPilotSession({
|
|||||||
<div className="mb-4">
|
<div className="mb-4">
|
||||||
<button
|
<button
|
||||||
onClick={() => setShowShareCommunication(true)}
|
onClick={() => setShowShareCommunication(true)}
|
||||||
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"
|
className="flex items-center gap-2 rounded-lg bg-accent-dim border border-accent/20 px-4 py-2.5 text-sm font-medium text-accent hover:bg-accent/20 transition-colors"
|
||||||
>
|
>
|
||||||
<FileText size={16} />
|
<FileText size={16} />
|
||||||
{shareLabel}
|
{shareLabel}
|
||||||
|
|||||||
@@ -161,7 +161,7 @@ export function FlowPilotStepCard({ step, isCurrentStep, isProcessing, sessionId
|
|||||||
<div
|
<div
|
||||||
className={cn(
|
className={cn(
|
||||||
'card-flat p-3 sm:p-4 lg:p-5',
|
'card-flat p-3 sm:p-4 lg:p-5',
|
||||||
isResolutionSuggestion && 'border-emerald-500/30'
|
isResolutionSuggestion && 'border-success/30'
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
{/* Context message */}
|
{/* Context message */}
|
||||||
@@ -175,7 +175,7 @@ export function FlowPilotStepCard({ step, isCurrentStep, isProcessing, sessionId
|
|||||||
<div className="flex items-start gap-3 mb-4">
|
<div className="flex items-start gap-3 mb-4">
|
||||||
<span className={cn(
|
<span className={cn(
|
||||||
'mt-0.5 flex h-7 w-7 shrink-0 items-center justify-center rounded-lg',
|
'mt-0.5 flex h-7 w-7 shrink-0 items-center justify-center rounded-lg',
|
||||||
isResolutionSuggestion ? 'bg-emerald-500/10 text-emerald-400' : 'bg-accent-dim text-primary'
|
isResolutionSuggestion ? 'bg-success-dim text-success' : 'bg-accent-dim text-primary'
|
||||||
)}>
|
)}>
|
||||||
<Icon size={14} />
|
<Icon size={14} />
|
||||||
</span>
|
</span>
|
||||||
@@ -197,7 +197,7 @@ export function FlowPilotStepCard({ step, isCurrentStep, isProcessing, sessionId
|
|||||||
<div className="flex flex-col gap-2 sm:flex-row">
|
<div className="flex flex-col gap-2 sm:flex-row">
|
||||||
<button
|
<button
|
||||||
onClick={() => handleResolutionResponse(true)}
|
onClick={() => handleResolutionResponse(true)}
|
||||||
className="flex-1 min-h-[44px] rounded-lg bg-emerald-500/10 border border-emerald-500/20 px-4 py-2.5 text-sm font-medium text-emerald-400 hover:bg-emerald-500/20 transition-colors"
|
className="flex-1 min-h-[44px] rounded-lg bg-success-dim border border-success/20 px-4 py-2.5 text-sm font-medium text-success hover:bg-success/20 transition-colors"
|
||||||
>
|
>
|
||||||
Yes, this is resolved
|
Yes, this is resolved
|
||||||
</button>
|
</button>
|
||||||
|
|||||||
@@ -128,7 +128,7 @@ export function InSessionScriptGenerator({
|
|||||||
onClick={handleCopy}
|
onClick={handleCopy}
|
||||||
className="flex items-center gap-1 text-xs text-muted-foreground hover:text-foreground transition-colors"
|
className="flex items-center gap-1 text-xs text-muted-foreground hover:text-foreground transition-colors"
|
||||||
>
|
>
|
||||||
{copied ? <Check size={12} className="text-emerald-400" /> : <Copy size={12} />}
|
{copied ? <Check size={12} className="text-success" /> : <Copy size={12} />}
|
||||||
{copied ? 'Copied' : 'Copy'}
|
{copied ? 'Copied' : 'Copy'}
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -2,9 +2,9 @@ import { GitBranch, ArrowUpRight, Sparkles, Clock, Hash } from 'lucide-react'
|
|||||||
import type { FlowProposalSummary } from '@/types/flow-proposal'
|
import type { FlowProposalSummary } from '@/types/flow-proposal'
|
||||||
|
|
||||||
const TYPE_CONFIG = {
|
const TYPE_CONFIG = {
|
||||||
new_flow: { label: 'New Flow', color: 'text-emerald-400 bg-emerald-400/10 border-emerald-400/20', icon: Sparkles },
|
new_flow: { label: 'New Flow', color: 'text-success bg-emerald-400/10 border-emerald-400/20', icon: Sparkles },
|
||||||
enhancement: { label: 'Enhancement', color: 'text-amber-400 bg-amber-400/10 border-amber-400/20', icon: ArrowUpRight },
|
enhancement: { label: 'Enhancement', color: 'text-warning bg-warning-dim border-warning/20', icon: ArrowUpRight },
|
||||||
branch_addition: { label: 'Branch', color: 'text-blue-400 bg-blue-400/10 border-blue-400/20', icon: GitBranch },
|
branch_addition: { label: 'Branch', color: 'text-accent bg-accent-dim border-accent/20', icon: GitBranch },
|
||||||
auto_reinforced: { label: 'Reinforced', color: 'text-muted-foreground bg-card border-border', icon: Sparkles },
|
auto_reinforced: { label: 'Reinforced', color: 'text-muted-foreground bg-card border-border', icon: Sparkles },
|
||||||
} as const
|
} as const
|
||||||
|
|
||||||
|
|||||||
@@ -105,7 +105,7 @@ export function ProposalDetail({ proposal, onReview }: ProposalDetailProps) {
|
|||||||
{proposal.proposed_diff && (() => {
|
{proposal.proposed_diff && (() => {
|
||||||
const diff = proposal.proposed_diff as { diff_description?: string; new_nodes?: Array<{ title?: string; question?: string; description?: string }> }
|
const diff = proposal.proposed_diff as { diff_description?: string; new_nodes?: Array<{ title?: string; question?: string; description?: string }> }
|
||||||
return (
|
return (
|
||||||
<div className="card-flat border-l-2 border-l-amber-500 p-4">
|
<div className="card-flat border-l-2 border-l-warning p-4">
|
||||||
<h4 className="font-sans text-xs text-[0.625rem] uppercase tracking-wider text-text-muted mb-2">Proposed Changes</h4>
|
<h4 className="font-sans text-xs text-[0.625rem] uppercase tracking-wider text-text-muted mb-2">Proposed Changes</h4>
|
||||||
{diff.diff_description && (
|
{diff.diff_description && (
|
||||||
<p className="text-sm text-foreground">{diff.diff_description}</p>
|
<p className="text-sm text-foreground">{diff.diff_description}</p>
|
||||||
@@ -114,8 +114,8 @@ export function ProposalDetail({ proposal, onReview }: ProposalDetailProps) {
|
|||||||
<div className="mt-3 space-y-1.5">
|
<div className="mt-3 space-y-1.5">
|
||||||
<p className="text-xs font-medium text-muted-foreground">New nodes:</p>
|
<p className="text-xs font-medium text-muted-foreground">New nodes:</p>
|
||||||
{diff.new_nodes.map((node, i) => (
|
{diff.new_nodes.map((node, i) => (
|
||||||
<div key={i} className="rounded-lg bg-emerald-500/5 border border-emerald-500/10 px-3 py-2 text-xs text-foreground">
|
<div key={i} className="rounded-lg bg-success/5 border border-success/10 px-3 py-2 text-xs text-foreground">
|
||||||
<span className="text-emerald-400">+ </span>
|
<span className="text-success">+ </span>
|
||||||
{node.title || node.question || node.description || 'New node'}
|
{node.title || node.question || node.description || 'New node'}
|
||||||
</div>
|
</div>
|
||||||
))}
|
))}
|
||||||
@@ -196,7 +196,7 @@ export function ProposalDetail({ proposal, onReview }: ProposalDetailProps) {
|
|||||||
<button
|
<button
|
||||||
onClick={() => handleAction('approve')}
|
onClick={() => handleAction('approve')}
|
||||||
disabled={isSubmitting}
|
disabled={isSubmitting}
|
||||||
className="flex items-center gap-2 rounded-lg bg-emerald-500/10 border border-emerald-500/20 px-4 py-2 text-sm font-medium text-emerald-400 hover:bg-emerald-500/20 disabled:opacity-40 transition-colors"
|
className="flex items-center gap-2 rounded-lg bg-success-dim border border-success/20 px-4 py-2 text-sm font-medium text-success hover:bg-success/20 disabled:opacity-40 transition-colors"
|
||||||
>
|
>
|
||||||
{isSubmitting ? <Loader2 size={14} className="animate-spin" /> : <CheckCircle2 size={14} />}
|
{isSubmitting ? <Loader2 size={14} className="animate-spin" /> : <CheckCircle2 size={14} />}
|
||||||
Approve & Publish
|
Approve & Publish
|
||||||
@@ -225,7 +225,7 @@ export function ProposalDetail({ proposal, onReview }: ProposalDetailProps) {
|
|||||||
<button
|
<button
|
||||||
onClick={() => showRejectConfirm ? handleAction('reject') : setShowRejectConfirm(true)}
|
onClick={() => showRejectConfirm ? handleAction('reject') : setShowRejectConfirm(true)}
|
||||||
disabled={isSubmitting}
|
disabled={isSubmitting}
|
||||||
className="flex items-center gap-2 rounded-lg bg-rose-500/10 border border-rose-500/20 px-4 py-2 text-sm font-medium text-rose-500 hover:bg-rose-500/20 disabled:opacity-40 transition-colors"
|
className="flex items-center gap-2 rounded-lg bg-danger-dim border border-danger/20 px-4 py-2 text-sm font-medium text-danger hover:bg-danger/20 disabled:opacity-40 transition-colors"
|
||||||
>
|
>
|
||||||
<XCircle size={14} />
|
<XCircle size={14} />
|
||||||
{showRejectConfirm ? 'Confirm Reject' : 'Reject'}
|
{showRejectConfirm ? 'Confirm Reject' : 'Reject'}
|
||||||
|
|||||||
@@ -38,7 +38,7 @@ export function SessionBriefing({
|
|||||||
const pkg = escalationPackage
|
const pkg = escalationPackage
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="card-flat border-l-2 border-l-amber-500 p-5 space-y-4">
|
<div className="card-flat border-l-2 border-l-warning p-5 space-y-4">
|
||||||
<div>
|
<div>
|
||||||
<h3 className="font-heading text-base font-semibold text-foreground">
|
<h3 className="font-heading text-base font-semibold text-foreground">
|
||||||
Escalation from {originalEngineerName || 'another engineer'}
|
Escalation from {originalEngineerName || 'another engineer'}
|
||||||
@@ -60,7 +60,7 @@ export function SessionBriefing({
|
|||||||
{pkg.escalation_reason && (
|
{pkg.escalation_reason && (
|
||||||
<div>
|
<div>
|
||||||
<h4 className="font-sans text-xs text-[0.625rem] uppercase tracking-wider text-text-muted mb-1">Why escalated</h4>
|
<h4 className="font-sans text-xs text-[0.625rem] uppercase tracking-wider text-text-muted mb-1">Why escalated</h4>
|
||||||
<p className="text-sm text-amber-400">{pkg.escalation_reason}</p>
|
<p className="text-sm text-warning">{pkg.escalation_reason}</p>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
@@ -111,7 +111,7 @@ export function SessionBriefing({
|
|||||||
<ul className="space-y-1">
|
<ul className="space-y-1">
|
||||||
{pkg.suggested_next_steps.map((s, i) => (
|
{pkg.suggested_next_steps.map((s, i) => (
|
||||||
<li key={i} className="text-sm text-foreground flex items-start gap-2">
|
<li key={i} className="text-sm text-foreground flex items-start gap-2">
|
||||||
<span className="text-emerald-400 mt-0.5">→</span>
|
<span className="text-success mt-0.5">→</span>
|
||||||
{s}
|
{s}
|
||||||
</li>
|
</li>
|
||||||
))}
|
))}
|
||||||
|
|||||||
@@ -55,38 +55,38 @@ export function SessionDocView({
|
|||||||
currentPushStatus === 'sent'
|
currentPushStatus === 'sent'
|
||||||
? 'border-emerald-400/20 bg-emerald-400/5'
|
? 'border-emerald-400/20 bg-emerald-400/5'
|
||||||
: currentPushStatus === 'pending_retry'
|
: currentPushStatus === 'pending_retry'
|
||||||
? 'border-amber-400/20 bg-amber-400/5'
|
? 'border-warning/20 bg-warning/5'
|
||||||
: 'border-rose-500/20 bg-rose-500/5'
|
: 'border-danger/20 bg-rose-500/5'
|
||||||
}`}
|
}`}
|
||||||
>
|
>
|
||||||
{currentPushStatus === 'sent' && (
|
{currentPushStatus === 'sent' && (
|
||||||
<>
|
<>
|
||||||
<CheckCircle2 size={16} className="text-emerald-400 shrink-0" />
|
<CheckCircle2 size={16} className="text-success shrink-0" />
|
||||||
<span className="text-sm text-emerald-400">
|
<span className="text-sm text-success">
|
||||||
Documentation pushed to ticket {ticketId ? `#${ticketId}` : ''}
|
Documentation pushed to ticket {ticketId ? `#${ticketId}` : ''}
|
||||||
</span>
|
</span>
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
{currentPushStatus === 'pending_retry' && (
|
{currentPushStatus === 'pending_retry' && (
|
||||||
<>
|
<>
|
||||||
<Loader2 size={16} className="text-amber-400 shrink-0 animate-spin" />
|
<Loader2 size={16} className="text-warning shrink-0 animate-spin" />
|
||||||
<span className="text-sm text-amber-400">
|
<span className="text-sm text-warning">
|
||||||
Documentation queued for push — will sync shortly
|
Documentation queued for push — will sync shortly
|
||||||
</span>
|
</span>
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
{currentPushStatus === 'failed' && (
|
{currentPushStatus === 'failed' && (
|
||||||
<>
|
<>
|
||||||
<AlertTriangle size={16} className="text-rose-500 shrink-0" />
|
<AlertTriangle size={16} className="text-danger shrink-0" />
|
||||||
<div className="flex-1">
|
<div className="flex-1">
|
||||||
<span className="text-sm text-rose-500">
|
<span className="text-sm text-danger">
|
||||||
Failed to push to ticket{currentPushError ? ` — ${currentPushError}` : ''}
|
Failed to push to ticket{currentPushError ? ` — ${currentPushError}` : ''}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<button
|
<button
|
||||||
onClick={handleRetry}
|
onClick={handleRetry}
|
||||||
disabled={retrying}
|
disabled={retrying}
|
||||||
className="flex items-center gap-1.5 rounded-lg bg-rose-500/10 px-3 py-1.5 text-xs font-medium text-rose-500 hover:bg-rose-500/20 transition-colors disabled:opacity-50"
|
className="flex items-center gap-1.5 rounded-lg bg-danger-dim px-3 py-1.5 text-xs font-medium text-danger hover:bg-danger/20 transition-colors disabled:opacity-50"
|
||||||
>
|
>
|
||||||
{retrying ? <Loader2 size={12} className="animate-spin" /> : <RefreshCw size={12} />}
|
{retrying ? <Loader2 size={12} className="animate-spin" /> : <RefreshCw size={12} />}
|
||||||
Retry
|
Retry
|
||||||
@@ -98,9 +98,9 @@ export function SessionDocView({
|
|||||||
|
|
||||||
{/* Member mapping warning */}
|
{/* Member mapping warning */}
|
||||||
{memberMappingWarning && (
|
{memberMappingWarning && (
|
||||||
<div className="rounded-xl border border-blue-400/20 bg-blue-400/5 px-4 py-3 flex items-start gap-3">
|
<div className="rounded-xl border border-accent/20 bg-accent/5 px-4 py-3 flex items-start gap-3">
|
||||||
<Info size={16} className="text-blue-400 shrink-0 mt-0.5" />
|
<Info size={16} className="text-accent shrink-0 mt-0.5" />
|
||||||
<span className="text-sm text-blue-400">
|
<span className="text-sm text-accent">
|
||||||
Time entry was not created — {memberMappingWarning} Session timing is included in the ticket note.
|
Time entry was not created — {memberMappingWarning} Session timing is included in the ticket note.
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
@@ -137,12 +137,12 @@ export function SessionDocView({
|
|||||||
|
|
||||||
{/* Outcome */}
|
{/* Outcome */}
|
||||||
{(documentation.resolution_summary || documentation.escalation_reason) && (
|
{(documentation.resolution_summary || documentation.escalation_reason) && (
|
||||||
<div className={`card-flat p-4 border-l-2 ${documentation.resolution_summary ? 'border-l-emerald-500' : 'border-l-amber-500'}`}>
|
<div className={`card-flat p-4 border-l-2 ${documentation.resolution_summary ? 'border-l-success' : 'border-l-warning'}`}>
|
||||||
<div className="flex items-center gap-2 mb-1">
|
<div className="flex items-center gap-2 mb-1">
|
||||||
{documentation.resolution_summary ? (
|
{documentation.resolution_summary ? (
|
||||||
<CheckCircle2 size={14} className="text-emerald-400" />
|
<CheckCircle2 size={14} className="text-success" />
|
||||||
) : (
|
) : (
|
||||||
<ArrowUpRight size={14} className="text-amber-400" />
|
<ArrowUpRight size={14} className="text-warning" />
|
||||||
)}
|
)}
|
||||||
<span className="font-sans text-xs text-[0.625rem] uppercase tracking-wider text-muted-foreground">
|
<span className="font-sans text-xs text-[0.625rem] uppercase tracking-wider text-muted-foreground">
|
||||||
{documentation.resolution_summary ? 'Resolved' : 'Escalated'}
|
{documentation.resolution_summary ? 'Resolved' : 'Escalated'}
|
||||||
@@ -202,8 +202,8 @@ export function SessionDocView({
|
|||||||
size={20}
|
size={20}
|
||||||
className={
|
className={
|
||||||
(currentRating ?? 0) >= star
|
(currentRating ?? 0) >= star
|
||||||
? 'fill-amber-400 text-amber-400'
|
? 'fill-warning text-warning'
|
||||||
: 'text-muted-foreground hover:text-amber-400'
|
: 'text-muted-foreground hover:text-warning'
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
</button>
|
</button>
|
||||||
|
|||||||
@@ -80,9 +80,9 @@ export function SimilarSessions({ sessionId }: SimilarSessionsProps) {
|
|||||||
className={cn(
|
className={cn(
|
||||||
'text-[0.5rem] font-sans text-xs uppercase',
|
'text-[0.5rem] font-sans text-xs uppercase',
|
||||||
session.status === 'resolved'
|
session.status === 'resolved'
|
||||||
? 'text-emerald-400'
|
? 'text-success'
|
||||||
: session.status === 'escalated'
|
: session.status === 'escalated'
|
||||||
? 'text-amber-400'
|
? 'text-warning'
|
||||||
: 'text-muted-foreground'
|
: 'text-muted-foreground'
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
|
|||||||
@@ -168,7 +168,7 @@ export function StatusUpdateModal({ open, onClose, onGenerate, context = 'status
|
|||||||
{/* Step 3: Generating */}
|
{/* Step 3: Generating */}
|
||||||
{step === 'generating' && (
|
{step === 'generating' && (
|
||||||
<div className="flex flex-col items-center justify-center py-8 gap-3">
|
<div className="flex flex-col items-center justify-center py-8 gap-3">
|
||||||
<Loader2 size={24} className="animate-spin text-blue-400" />
|
<Loader2 size={24} className="animate-spin text-accent" />
|
||||||
<p className="text-sm text-muted-foreground">
|
<p className="text-sm text-muted-foreground">
|
||||||
Generating {audience === 'email_draft' ? 'email draft' : audience === 'client_update' ? 'client update' : 'ticket notes'}...
|
Generating {audience === 'email_draft' ? 'email draft' : audience === 'client_update' ? 'client update' : 'ticket notes'}...
|
||||||
</p>
|
</p>
|
||||||
@@ -180,7 +180,7 @@ export function StatusUpdateModal({ open, onClose, onGenerate, context = 'status
|
|||||||
<div className="space-y-4">
|
<div className="space-y-4">
|
||||||
{/* Meta badges */}
|
{/* Meta badges */}
|
||||||
<div className="flex items-center gap-2 flex-wrap">
|
<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-blue-500/10 text-blue-400 border border-blue-500/20">
|
<span className="inline-flex items-center gap-1 rounded-full px-2.5 py-0.5 text-xs font-medium bg-accent-dim text-accent border border-accent/20">
|
||||||
{AUDIENCES.find(a => a.value === result.audience)?.label}
|
{AUDIENCES.find(a => a.value === result.audience)?.label}
|
||||||
</span>
|
</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)]">
|
<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)]">
|
||||||
@@ -208,8 +208,8 @@ export function StatusUpdateModal({ open, onClose, onGenerate, context = 'status
|
|||||||
className={cn(
|
className={cn(
|
||||||
'flex items-center gap-2 rounded-lg px-4 py-2 min-h-[44px] text-sm font-medium transition-colors',
|
'flex items-center gap-2 rounded-lg px-4 py-2 min-h-[44px] text-sm font-medium transition-colors',
|
||||||
copied
|
copied
|
||||||
? 'bg-emerald-500/20 border border-emerald-500/30 text-emerald-400'
|
? 'bg-success/20 border border-success/30 text-success'
|
||||||
: 'bg-blue-500/10 border border-blue-500/20 text-blue-400 hover:bg-blue-500/20'
|
: 'bg-accent-dim border border-accent/20 text-accent hover:bg-accent/20'
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
{copied ? <Check size={16} /> : <Copy size={16} />}
|
{copied ? <Check size={16} /> : <Copy size={16} />}
|
||||||
|
|||||||
@@ -57,7 +57,7 @@ export function ScriptBuilderChat({
|
|||||||
>
|
>
|
||||||
{msg.role === 'assistant' && (
|
{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">
|
<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-blue-400" />
|
<Bot size={16} className="text-accent" />
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
@@ -99,10 +99,10 @@ export function ScriptBuilderChat({
|
|||||||
{isLoading && (
|
{isLoading && (
|
||||||
<div className="flex gap-3 justify-start">
|
<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">
|
<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-blue-400" />
|
<Bot size={16} className="text-accent" />
|
||||||
</div>
|
</div>
|
||||||
<div className="card-flat rounded-xl px-4 py-3 text-sm flex items-center gap-2">
|
<div className="card-flat rounded-xl px-4 py-3 text-sm flex items-center gap-2">
|
||||||
<Loader2 size={14} className="animate-spin text-blue-400" />
|
<Loader2 size={14} className="animate-spin text-accent" />
|
||||||
<span className="text-muted-foreground">Generating script...</span>
|
<span className="text-muted-foreground">Generating script...</span>
|
||||||
</div>
|
</div>
|
||||||
</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">
|
<div className="mt-3 rounded-lg border bg-[rgba(0,0,0,0.3)] border-[rgba(255,255,255,0.06)] overflow-hidden">
|
||||||
{/* Header */}
|
{/* Header */}
|
||||||
<div className="flex items-center justify-between px-3 py-2 border-b border-[rgba(255,255,255,0.06)]">
|
<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-blue-400 truncate">
|
<span className="font-mono text-xs text-accent truncate">
|
||||||
{filename || 'script'}
|
{filename || 'script'}
|
||||||
</span>
|
</span>
|
||||||
{lineCount != null && (
|
{lineCount != null && (
|
||||||
@@ -110,14 +110,14 @@ export function ScriptCodeBlock({
|
|||||||
"bg-[rgba(255,255,255,0.04)] border border-[rgba(255,255,255,0.06)] text-foreground hover:border-[rgba(255,255,255,0.12)]"
|
"bg-[rgba(255,255,255,0.04)] border border-[rgba(255,255,255,0.06)] text-foreground hover:border-[rgba(255,255,255,0.12)]"
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
{copied ? <Check size={14} className="text-emerald-400" /> : <Copy size={14} />}
|
{copied ? <Check size={14} className="text-success" /> : <Copy size={14} />}
|
||||||
{copied ? 'Copied' : 'Copy'}
|
{copied ? 'Copied' : 'Copy'}
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
onClick={(e) => { e.stopPropagation(); onSave() }}
|
onClick={(e) => { e.stopPropagation(); onSave() }}
|
||||||
className={cn(
|
className={cn(
|
||||||
"flex items-center gap-1.5 px-3 py-1.5 rounded-lg text-xs font-medium transition-colors",
|
"flex items-center gap-1.5 px-3 py-1.5 rounded-lg text-xs font-medium transition-colors",
|
||||||
"bg-emerald-500/10 border border-emerald-500/20 text-emerald-400 hover:bg-emerald-500/15"
|
"bg-success-dim border border-success/20 text-success hover:bg-emerald-500/15"
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
<BookmarkPlus size={14} />
|
<BookmarkPlus size={14} />
|
||||||
|
|||||||
@@ -62,7 +62,7 @@ export function ScriptPreviewModal({
|
|||||||
{/* Header */}
|
{/* 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 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">
|
<div className="flex items-center gap-3 min-w-0">
|
||||||
<span className="font-mono text-sm text-blue-400 truncate">
|
<span className="font-mono text-sm text-accent truncate">
|
||||||
{filename || 'script'}
|
{filename || 'script'}
|
||||||
</span>
|
</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">
|
<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">
|
||||||
@@ -77,14 +77,14 @@ export function ScriptPreviewModal({
|
|||||||
"bg-[rgba(255,255,255,0.04)] border border-[rgba(255,255,255,0.06)] text-foreground hover:border-[rgba(255,255,255,0.12)]"
|
"bg-[rgba(255,255,255,0.04)] border border-[rgba(255,255,255,0.06)] text-foreground hover:border-[rgba(255,255,255,0.12)]"
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
{copied ? <Check size={14} className="text-emerald-400" /> : <Copy size={14} />}
|
{copied ? <Check size={14} className="text-success" /> : <Copy size={14} />}
|
||||||
{copied ? 'Copied' : 'Copy'}
|
{copied ? 'Copied' : 'Copy'}
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
onClick={onSave}
|
onClick={onSave}
|
||||||
className={cn(
|
className={cn(
|
||||||
"flex items-center gap-1.5 px-3 py-1.5 rounded-lg text-xs font-medium transition-colors",
|
"flex items-center gap-1.5 px-3 py-1.5 rounded-lg text-xs font-medium transition-colors",
|
||||||
"bg-emerald-500/10 border border-emerald-500/20 text-emerald-400 hover:bg-emerald-500/15"
|
"bg-success-dim border border-success/20 text-success hover:bg-emerald-500/15"
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
<BookmarkPlus size={14} />
|
<BookmarkPlus size={14} />
|
||||||
|
|||||||
@@ -708,13 +708,13 @@ export default function AssistantChatPage() {
|
|||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
{upload.status === 'done' && (
|
{upload.status === 'done' && (
|
||||||
<button type="button" onClick={() => handleRemoveUpload(upload.id)} className="absolute -top-1 -right-1 w-4 h-4 rounded-full bg-background border border-border flex items-center justify-center hover:bg-rose-500/20 transition-colors">
|
<button type="button" onClick={() => handleRemoveUpload(upload.id)} className="absolute -top-1 -right-1 w-4 h-4 rounded-full bg-background border border-border flex items-center justify-center hover:bg-danger/20 transition-colors">
|
||||||
<X size={8} className="text-muted-foreground" />
|
<X size={8} className="text-muted-foreground" />
|
||||||
</button>
|
</button>
|
||||||
)}
|
)}
|
||||||
{upload.status === 'error' && (
|
{upload.status === 'error' && (
|
||||||
<div className="absolute inset-0 bg-rose-500/20 border-2 border-rose-500 flex items-center justify-center cursor-pointer" onClick={() => retryUpload(upload.id)}>
|
<div className="absolute inset-0 bg-danger/20 border-2 border-danger flex items-center justify-center cursor-pointer" onClick={() => retryUpload(upload.id)}>
|
||||||
<RotateCcw size={10} className="text-rose-500" />
|
<RotateCcw size={10} className="text-danger" />
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
@@ -755,11 +755,11 @@ export default function AssistantChatPage() {
|
|||||||
)}
|
)}
|
||||||
{messages.length >= 2 && (
|
{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-blue-400 hover:bg-blue-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-accent hover:bg-accent-dim transition-colors disabled:opacity-40" title="Share status update">
|
||||||
<FileText size={14} />
|
<FileText size={14} />
|
||||||
<span className="hidden sm:inline">Update</span>
|
<span className="hidden sm:inline">Update</span>
|
||||||
</button>
|
</button>
|
||||||
<button type="button" onClick={() => setShowConclude(true)} disabled={loading} className="flex items-center gap-1.5 rounded-lg px-2 py-1.5 text-xs text-muted-foreground hover:text-amber-400 hover:bg-amber-400/10 transition-colors disabled:opacity-40" title="Conclude session">
|
<button type="button" onClick={() => setShowConclude(true)} disabled={loading} className="flex items-center gap-1.5 rounded-lg px-2 py-1.5 text-xs text-muted-foreground hover:text-warning hover:bg-warning-dim transition-colors disabled:opacity-40" title="Conclude session">
|
||||||
<Flag size={14} />
|
<Flag size={14} />
|
||||||
<span className="hidden sm:inline">Conclude</span>
|
<span className="hidden sm:inline">Conclude</span>
|
||||||
</button>
|
</button>
|
||||||
|
|||||||
@@ -108,7 +108,7 @@ export default function FlowPilotSessionPage() {
|
|||||||
return (
|
return (
|
||||||
<div className="flex items-center justify-center min-h-[50vh]">
|
<div className="flex items-center justify-center min-h-[50vh]">
|
||||||
<div className="card-flat p-6 text-center max-w-md">
|
<div className="card-flat p-6 text-center max-w-md">
|
||||||
<p className="text-sm text-rose-400">{fp.error}</p>
|
<p className="text-sm text-danger">{fp.error}</p>
|
||||||
<button
|
<button
|
||||||
onClick={() => window.location.reload()}
|
onClick={() => window.location.reload()}
|
||||||
className="mt-3 text-xs text-muted-foreground hover:text-foreground transition-colors"
|
className="mt-3 text-xs text-muted-foreground hover:text-foreground transition-colors"
|
||||||
@@ -160,15 +160,15 @@ export default function FlowPilotSessionPage() {
|
|||||||
className="flex items-center gap-3 border-b px-5 py-3 shrink-0"
|
className="flex items-center gap-3 border-b px-5 py-3 shrink-0"
|
||||||
style={{ borderColor: 'var(--color-border-default)' }}
|
style={{ borderColor: 'var(--color-border-default)' }}
|
||||||
>
|
>
|
||||||
<span className="flex h-7 w-7 items-center justify-center rounded-lg bg-amber-500/10">
|
<span className="flex h-7 w-7 items-center justify-center rounded-lg bg-warning-dim">
|
||||||
<Sparkles size={14} className="text-amber-400" />
|
<Sparkles size={14} className="text-warning" />
|
||||||
</span>
|
</span>
|
||||||
<div className="flex-1 min-w-0">
|
<div className="flex-1 min-w-0">
|
||||||
<h1 className="font-heading text-sm font-semibold text-foreground truncate">
|
<h1 className="font-heading text-sm font-semibold text-foreground truncate">
|
||||||
Escalation Pickup — {fp.session.problem_summary || 'FlowPilot Session'}
|
Escalation Pickup — {fp.session.problem_summary || 'FlowPilot Session'}
|
||||||
</h1>
|
</h1>
|
||||||
</div>
|
</div>
|
||||||
<span className="font-sans text-xs rounded-md bg-amber-500/10 px-2 py-0.5 text-[0.625rem] uppercase tracking-wider text-amber-400 border border-amber-500/20">
|
<span className="font-sans text-xs rounded-md bg-warning-dim px-2 py-0.5 text-[0.625rem] uppercase tracking-wider text-warning border border-warning/20">
|
||||||
Awaiting pickup
|
Awaiting pickup
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
@@ -196,8 +196,8 @@ export default function FlowPilotSessionPage() {
|
|||||||
<div className="fixed inset-0 z-50 flex items-center justify-center bg-black/80">
|
<div className="fixed inset-0 z-50 flex items-center justify-center bg-black/80">
|
||||||
<div className="bg-card border border-border rounded-xl w-full max-w-md p-6 shadow-lg">
|
<div className="bg-card border border-border rounded-xl w-full max-w-md p-6 shadow-lg">
|
||||||
<div className="flex items-center gap-3 mb-3">
|
<div className="flex items-center gap-3 mb-3">
|
||||||
<span className="flex h-9 w-9 items-center justify-center rounded-lg bg-amber-500/10">
|
<span className="flex h-9 w-9 items-center justify-center rounded-lg bg-warning-dim">
|
||||||
<AlertTriangle size={18} className="text-amber-400" />
|
<AlertTriangle size={18} className="text-warning" />
|
||||||
</span>
|
</span>
|
||||||
<h2 className="text-lg font-heading font-semibold text-foreground">Active Session</h2>
|
<h2 className="text-lg font-heading font-semibold text-foreground">Active Session</h2>
|
||||||
</div>
|
</div>
|
||||||
@@ -207,7 +207,7 @@ export default function FlowPilotSessionPage() {
|
|||||||
<div className="flex gap-2">
|
<div className="flex gap-2">
|
||||||
<button
|
<button
|
||||||
onClick={() => blocker.reset()}
|
onClick={() => blocker.reset()}
|
||||||
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"
|
className="flex-1 rounded-lg bg-accent px-4 py-2.5 text-sm font-semibold text-white hover:brightness-110 active:scale-[0.98] transition-all"
|
||||||
>
|
>
|
||||||
Stay in Session
|
Stay in Session
|
||||||
</button>
|
</button>
|
||||||
@@ -246,7 +246,7 @@ export default function FlowPilotSessionPage() {
|
|||||||
<button
|
<button
|
||||||
onClick={() => setShowResolve(true)}
|
onClick={() => setShowResolve(true)}
|
||||||
disabled={!fp.canResolve || fp.isProcessing}
|
disabled={!fp.canResolve || fp.isProcessing}
|
||||||
className="flex items-center gap-1.5 rounded-lg bg-emerald-500/10 border border-emerald-500/20 px-3 py-1.5 text-xs font-medium text-emerald-400 hover:bg-emerald-500/20 disabled:opacity-40 disabled:pointer-events-none transition-colors"
|
className="flex items-center gap-1.5 rounded-lg bg-success-dim border border-success/20 px-3 py-1.5 text-xs font-medium text-success hover:bg-success/20 disabled:opacity-40 disabled:pointer-events-none transition-colors"
|
||||||
>
|
>
|
||||||
<CheckCircle2 size={13} />
|
<CheckCircle2 size={13} />
|
||||||
Resolve
|
Resolve
|
||||||
@@ -254,7 +254,7 @@ export default function FlowPilotSessionPage() {
|
|||||||
<button
|
<button
|
||||||
onClick={() => setShowEscalate(true)}
|
onClick={() => setShowEscalate(true)}
|
||||||
disabled={!fp.canEscalate || fp.isProcessing}
|
disabled={!fp.canEscalate || fp.isProcessing}
|
||||||
className="flex items-center gap-1.5 rounded-lg bg-amber-500/10 border border-amber-500/20 px-3 py-1.5 text-xs font-medium text-amber-400 hover:bg-amber-500/20 disabled:opacity-40 disabled:pointer-events-none transition-colors"
|
className="flex items-center gap-1.5 rounded-lg bg-warning-dim border border-warning/20 px-3 py-1.5 text-xs font-medium text-warning hover:bg-warning/20 disabled:opacity-40 disabled:pointer-events-none transition-colors"
|
||||||
>
|
>
|
||||||
<ArrowUpRight size={13} />
|
<ArrowUpRight size={13} />
|
||||||
Escalate
|
Escalate
|
||||||
@@ -263,7 +263,7 @@ export default function FlowPilotSessionPage() {
|
|||||||
<button
|
<button
|
||||||
onClick={() => setShowStatusUpdate(true)}
|
onClick={() => setShowStatusUpdate(true)}
|
||||||
disabled={fp.isProcessing}
|
disabled={fp.isProcessing}
|
||||||
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"
|
className="flex items-center gap-1.5 rounded-lg bg-accent-dim border border-accent/20 px-3 py-1.5 text-xs font-medium text-accent hover:bg-accent/20 disabled:opacity-40 disabled:pointer-events-none transition-colors"
|
||||||
title="Share Update"
|
title="Share Update"
|
||||||
>
|
>
|
||||||
<FileText size={13} />
|
<FileText size={13} />
|
||||||
@@ -291,7 +291,7 @@ export default function FlowPilotSessionPage() {
|
|||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
onClick={() => { setShowOverflow(false); setShowAbandon(true) }}
|
onClick={() => { setShowOverflow(false); setShowAbandon(true) }}
|
||||||
className="flex w-full items-center gap-2 px-3 py-2 text-xs text-muted-foreground hover:text-rose-400 hover:bg-rose-500/10 transition-colors"
|
className="flex w-full items-center gap-2 px-3 py-2 text-xs text-muted-foreground hover:text-danger hover:bg-danger-dim transition-colors"
|
||||||
>
|
>
|
||||||
<X size={13} />
|
<X size={13} />
|
||||||
Close Session
|
Close Session
|
||||||
@@ -317,7 +317,7 @@ export default function FlowPilotSessionPage() {
|
|||||||
<button
|
<button
|
||||||
onClick={() => { setShowOverflow(false); setShowResolve(true) }}
|
onClick={() => { setShowOverflow(false); setShowResolve(true) }}
|
||||||
disabled={!fp.canResolve}
|
disabled={!fp.canResolve}
|
||||||
className="flex w-full items-center gap-2 px-3 py-2.5 text-xs text-emerald-400 hover:bg-emerald-500/10 transition-colors disabled:opacity-40"
|
className="flex w-full items-center gap-2 px-3 py-2.5 text-xs text-success hover:bg-success-dim transition-colors disabled:opacity-40"
|
||||||
>
|
>
|
||||||
<CheckCircle2 size={14} />
|
<CheckCircle2 size={14} />
|
||||||
Resolve
|
Resolve
|
||||||
@@ -325,7 +325,7 @@ export default function FlowPilotSessionPage() {
|
|||||||
<button
|
<button
|
||||||
onClick={() => { setShowOverflow(false); setShowEscalate(true) }}
|
onClick={() => { setShowOverflow(false); setShowEscalate(true) }}
|
||||||
disabled={!fp.canEscalate}
|
disabled={!fp.canEscalate}
|
||||||
className="flex w-full items-center gap-2 px-3 py-2.5 text-xs text-amber-400 hover:bg-amber-500/10 transition-colors disabled:opacity-40"
|
className="flex w-full items-center gap-2 px-3 py-2.5 text-xs text-warning hover:bg-warning-dim transition-colors disabled:opacity-40"
|
||||||
>
|
>
|
||||||
<ArrowUpRight size={14} />
|
<ArrowUpRight size={14} />
|
||||||
Escalate
|
Escalate
|
||||||
@@ -333,7 +333,7 @@ export default function FlowPilotSessionPage() {
|
|||||||
{fp.allSteps.length >= 2 && (
|
{fp.allSteps.length >= 2 && (
|
||||||
<button
|
<button
|
||||||
onClick={() => { setShowOverflow(false); setShowStatusUpdate(true) }}
|
onClick={() => { setShowOverflow(false); setShowStatusUpdate(true) }}
|
||||||
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"
|
className="flex w-full items-center gap-2 px-3 py-2.5 text-xs text-accent hover:bg-accent-dim transition-colors"
|
||||||
>
|
>
|
||||||
<FileText size={14} />
|
<FileText size={14} />
|
||||||
Share Update
|
Share Update
|
||||||
@@ -349,7 +349,7 @@ export default function FlowPilotSessionPage() {
|
|||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
onClick={() => { setShowOverflow(false); setShowAbandon(true) }}
|
onClick={() => { setShowOverflow(false); setShowAbandon(true) }}
|
||||||
className="flex w-full items-center gap-2 px-3 py-2.5 text-xs text-muted-foreground hover:text-rose-400 hover:bg-rose-500/10 transition-colors"
|
className="flex w-full items-center gap-2 px-3 py-2.5 text-xs text-muted-foreground hover:text-danger hover:bg-danger-dim transition-colors"
|
||||||
>
|
>
|
||||||
<X size={14} />
|
<X size={14} />
|
||||||
Close Session
|
Close Session
|
||||||
@@ -364,8 +364,8 @@ export default function FlowPilotSessionPage() {
|
|||||||
{/* Status badge — non-active states */}
|
{/* Status badge — non-active states */}
|
||||||
{fp.session.status !== 'active' && (
|
{fp.session.status !== 'active' && (
|
||||||
<span className={`flex items-center gap-1.5 text-[0.625rem] uppercase tracking-wider font-sans ${
|
<span className={`flex items-center gap-1.5 text-[0.625rem] uppercase tracking-wider font-sans ${
|
||||||
fp.session.status === 'resolved' ? 'text-emerald-400' :
|
fp.session.status === 'resolved' ? 'text-success' :
|
||||||
fp.session.status === 'escalated' ? 'text-amber-400' :
|
fp.session.status === 'escalated' ? 'text-warning' :
|
||||||
fp.session.status === 'paused' ? 'text-muted-foreground' :
|
fp.session.status === 'paused' ? 'text-muted-foreground' :
|
||||||
'text-muted-foreground'
|
'text-muted-foreground'
|
||||||
}`}>
|
}`}>
|
||||||
@@ -437,7 +437,7 @@ export default function FlowPilotSessionPage() {
|
|||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
disabled={resolutionSummary.length < 5 || submitting}
|
disabled={resolutionSummary.length < 5 || submitting}
|
||||||
className="rounded-lg bg-emerald-500/20 border border-emerald-500/30 px-4 py-2 min-h-[44px] text-sm font-medium text-emerald-400 hover:bg-emerald-500/30 disabled:opacity-50 transition-colors"
|
className="rounded-lg bg-success/20 border border-success/30 px-4 py-2 min-h-[44px] text-sm font-medium text-success hover:bg-success/30 disabled:opacity-50 transition-colors"
|
||||||
>
|
>
|
||||||
{submitting ? 'Resolving...' : 'Resolve Session'}
|
{submitting ? 'Resolving...' : 'Resolve Session'}
|
||||||
</button>
|
</button>
|
||||||
@@ -473,7 +473,7 @@ export default function FlowPilotSessionPage() {
|
|||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
disabled={submitting}
|
disabled={submitting}
|
||||||
className="rounded-lg bg-rose-500/20 border border-rose-500/30 px-4 py-2 min-h-[44px] text-sm font-medium text-rose-400 hover:bg-rose-500/30 disabled:opacity-50 transition-colors"
|
className="rounded-lg bg-danger/20 border border-danger/30 px-4 py-2 min-h-[44px] text-sm font-medium text-danger hover:bg-danger/30 disabled:opacity-50 transition-colors"
|
||||||
>
|
>
|
||||||
{submitting ? 'Closing...' : 'Close Session'}
|
{submitting ? 'Closing...' : 'Close Session'}
|
||||||
</button>
|
</button>
|
||||||
|
|||||||
Reference in New Issue
Block a user