refactor: migrate FlowPilot components to Design System v4

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Michael Chihlas
2026-03-22 01:56:27 -04:00
parent 97a20a4225
commit 56ff792f8e
17 changed files with 219 additions and 221 deletions

View File

@@ -8,7 +8,7 @@ interface AISessionListItemProps {
} }
const STATUS_CONFIG = { const STATUS_CONFIG = {
active: { icon: Clock, color: 'text-primary', label: 'Active' }, active: { icon: Clock, color: 'text-[#22d3ee]', label: 'Active' },
paused: { icon: Pause, color: 'text-amber-400', label: 'Paused' }, paused: { icon: Pause, color: 'text-amber-400', label: 'Paused' },
resolved: { icon: CheckCircle2, color: 'text-emerald-400', label: 'Resolved' }, resolved: { icon: CheckCircle2, color: 'text-emerald-400', label: 'Resolved' },
escalated: { icon: ArrowUpRight, color: 'text-amber-400', label: 'Escalated' }, escalated: { icon: ArrowUpRight, color: 'text-amber-400', label: 'Escalated' },
@@ -22,16 +22,16 @@ export function AISessionListItem({ session }: AISessionListItemProps) {
return ( return (
<Link <Link
to={`/pilot/${session.id}`} to={`/pilot/${session.id}`}
className="glass-card block p-4 transition-all" className="card-interactive block p-4 transition-all"
> >
<div className="flex items-start justify-between gap-3"> <div className="flex items-start justify-between gap-3">
<div className="flex-1 min-w-0"> <div className="flex-1 min-w-0">
<p className="text-sm font-medium text-foreground truncate"> <p className="text-sm font-medium text-[#e2e5eb] truncate">
{session.problem_summary || 'Untitled session'} {session.problem_summary || 'Untitled session'}
</p> </p>
<div className="mt-1.5 flex items-center gap-3 flex-wrap"> <div className="mt-1.5 flex items-center gap-3 flex-wrap">
{session.problem_domain && ( {session.problem_domain && (
<span className="font-label rounded-md bg-primary/10 px-2 py-0.5 text-[0.625rem] uppercase tracking-wider text-primary"> <span className="font-sans text-xs rounded-md bg-[rgba(34,211,238,0.10)] px-2 py-0.5 text-[0.625rem] uppercase tracking-wider text-[#22d3ee]">
{session.problem_domain} {session.problem_domain}
</span> </span>
)} )}
@@ -39,7 +39,7 @@ export function AISessionListItem({ session }: AISessionListItemProps) {
<StatusIcon size={12} /> <StatusIcon size={12} />
{config.label} {config.label}
</span> </span>
<span className="text-xs text-muted-foreground"> <span className="text-xs text-[#848b9b]">
{session.step_count} steps {session.step_count} steps
</span> </span>
<span className="text-xs text-[#5a6170]"> <span className="text-xs text-[#5a6170]">
@@ -50,7 +50,7 @@ export function AISessionListItem({ session }: AISessionListItemProps) {
</div> </div>
</div> </div>
{session.session_rating && ( {session.session_rating && (
<span className="font-label text-xs text-amber-400"> <span className="font-sans text-xs text-xs text-amber-400">
{'★'.repeat(session.session_rating)} {'★'.repeat(session.session_rating)}
</span> </span>
)} )}

View File

@@ -30,12 +30,12 @@ export function ConfidenceIndicator({ tier, score, className }: ConfidenceIndica
return ( return (
<div className={cn('group relative inline-flex items-center gap-2', className)}> <div className={cn('group relative inline-flex items-center gap-2', className)}>
<span className={cn('h-2 w-2 rounded-full', config.color)} /> <span className={cn('h-2 w-2 rounded-full', config.color)} />
<span className="font-label text-xs text-muted-foreground">{config.label}</span> <span className="font-sans text-xs text-xs text-[#848b9b]">{config.label}</span>
{/* Tooltip */} {/* Tooltip */}
<div className="pointer-events-none absolute left-0 top-full z-50 mt-2 w-56 rounded-lg border border-border bg-card p-3 opacity-0 shadow-lg transition-opacity group-hover:pointer-events-auto group-hover:opacity-100"> <div className="pointer-events-none absolute left-0 top-full z-50 mt-2 w-56 rounded-lg border border-[#1e2130] bg-[#14161d] p-3 opacity-0 shadow-lg transition-opacity group-hover:pointer-events-auto group-hover:opacity-100">
<p className="text-xs text-muted-foreground">{config.description}</p> <p className="text-xs text-[#848b9b]">{config.description}</p>
<p className="mt-1 font-label text-[0.625rem] text-[#5a6170]"> <p className="mt-1 font-sans text-xs text-[0.625rem] text-[#5a6170]">
Confidence: {Math.round(score * 100)}% Confidence: {Math.round(score * 100)}%
</p> </p>
</div> </div>

View File

@@ -43,7 +43,7 @@ export function EscalateModal({ open, onClose, onEscalate, isProcessing, hasPsaT
</div> </div>
<div> <div>
<label className="mb-1.5 block text-sm font-medium text-foreground"> <label className="mb-1.5 block text-sm font-medium text-[#e2e5eb]">
Why are you escalating? Why are you escalating?
</label> </label>
<RichTextInput <RichTextInput
@@ -63,14 +63,14 @@ export function EscalateModal({ open, onClose, onEscalate, isProcessing, hasPsaT
<button <button
onClick={handleClose} onClick={handleClose}
disabled={isProcessing} disabled={isProcessing}
className="flex-1 rounded-lg bg-[rgba(255,255,255,0.04)] border border-[rgba(255,255,255,0.06)] px-4 py-2.5 min-h-[44px] text-sm font-medium text-foreground hover:border-[rgba(255,255,255,0.12)] transition-colors disabled:opacity-50" className="flex-1 rounded-lg bg-[rgba(255,255,255,0.04)] border border-[rgba(255,255,255,0.06)] px-4 py-2.5 min-h-[44px] text-sm font-medium text-[#e2e5eb] hover:border-[rgba(255,255,255,0.12)] transition-colors disabled:opacity-50"
> >
Cancel Cancel
</button> </button>
<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-[#101114] hover:bg-amber-500 active:scale-[0.97] disabled:opacity-40 transition-all" 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"
> >
{isProcessing ? ( {isProcessing ? (
<Loader2 size={14} className="animate-spin" /> <Loader2 size={14} className="animate-spin" />

View File

@@ -42,7 +42,7 @@ export function EscalationQueue({ onPickup }: EscalationQueueProps) {
if (isLoading) { if (isLoading) {
return ( return (
<div className="flex items-center justify-center py-12"> <div className="flex items-center justify-center py-12">
<Loader2 size={20} className="animate-spin text-muted-foreground" /> <Loader2 size={20} className="animate-spin text-[#848b9b]" />
</div> </div>
) )
} }
@@ -53,7 +53,7 @@ export function EscalationQueue({ onPickup }: EscalationQueueProps) {
<p className="text-sm text-rose-400">{error}</p> <p className="text-sm text-rose-400">{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-[#848b9b] hover:text-[#e2e5eb] transition-colors"
> >
Try again Try again
</button> </button>
@@ -64,11 +64,11 @@ export function EscalationQueue({ onPickup }: EscalationQueueProps) {
if (sessions.length === 0) { if (sessions.length === 0) {
return ( return (
<div className="py-12 text-center"> <div className="py-12 text-center">
<AlertTriangle size={24} className="mx-auto mb-2 text-muted-foreground/40" /> <AlertTriangle size={24} className="mx-auto mb-2 text-[#848b9b]/40" />
<p className="text-sm text-muted-foreground">No sessions awaiting escalation</p> <p className="text-sm text-[#848b9b]">No sessions awaiting escalation</p>
<button <button
onClick={loadQueue} onClick={loadQueue}
className="mt-3 flex items-center gap-1.5 mx-auto text-xs text-muted-foreground hover:text-foreground transition-colors" className="mt-3 flex items-center gap-1.5 mx-auto text-xs text-[#848b9b] hover:text-[#e2e5eb] transition-colors"
> >
<RefreshCw size={12} /> <RefreshCw size={12} />
Refresh Refresh
@@ -80,12 +80,12 @@ export function EscalationQueue({ onPickup }: EscalationQueueProps) {
return ( return (
<div className="space-y-3"> <div className="space-y-3">
<div className="flex items-center justify-between px-1"> <div className="flex items-center justify-between px-1">
<h3 className="font-label text-[0.625rem] uppercase tracking-wider text-[#5a6170]"> <h3 className="font-sans text-xs text-[0.625rem] uppercase tracking-wider text-[#5a6170]">
Awaiting pickup ({sessions.length}) Awaiting pickup ({sessions.length})
</h3> </h3>
<button <button
onClick={loadQueue} onClick={loadQueue}
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-[#848b9b] hover:text-[#e2e5eb] transition-colors"
> >
<RefreshCw size={10} /> <RefreshCw size={10} />
Refresh Refresh
@@ -93,9 +93,9 @@ export function EscalationQueue({ onPickup }: EscalationQueueProps) {
</div> </div>
{sessions.map((session) => ( {sessions.map((session) => (
<div key={session.id} className="glass-card p-3 sm:p-4 space-y-3"> <div key={session.id} className="card-interactive p-3 sm:p-4 space-y-3">
<div> <div>
<p className="text-sm font-semibold text-foreground"> <p className="text-sm font-semibold text-[#e2e5eb]">
{session.problem_summary || 'Untitled session'} {session.problem_summary || 'Untitled session'}
</p> </p>
{session.escalation_reason && ( {session.escalation_reason && (
@@ -105,9 +105,9 @@ export function EscalationQueue({ onPickup }: EscalationQueueProps) {
)} )}
</div> </div>
<div className="flex flex-wrap items-center gap-x-3 gap-y-1 text-xs text-muted-foreground"> <div className="flex flex-wrap items-center gap-x-3 gap-y-1 text-xs text-[#848b9b]">
{session.problem_domain && ( {session.problem_domain && (
<span className="font-label rounded-md bg-primary/10 px-1.5 py-0.5 text-[0.5625rem] uppercase tracking-wider text-primary"> <span className="font-sans text-xs rounded-md bg-[rgba(34,211,238,0.10)] px-1.5 py-0.5 text-[0.5625rem] uppercase tracking-wider text-[#22d3ee]">
{session.problem_domain} {session.problem_domain}
</span> </span>
)} )}
@@ -120,7 +120,7 @@ export function EscalationQueue({ onPickup }: EscalationQueueProps) {
{new Date(session.created_at).toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' })} {new Date(session.created_at).toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' })}
</span> </span>
{session.psa_ticket_id && ( {session.psa_ticket_id && (
<span className="flex items-center gap-1 text-primary"> <span className="flex items-center gap-1 text-[#22d3ee]">
<Ticket size={10} /> <Ticket size={10} />
#{session.psa_ticket_id} #{session.psa_ticket_id}
</span> </span>
@@ -129,7 +129,7 @@ export function EscalationQueue({ onPickup }: EscalationQueueProps) {
<button <button
onClick={() => handlePickup(session.id)} onClick={() => handlePickup(session.id)}
className="w-full min-h-[44px] rounded-lg bg-gradient-brand px-4 py-2 text-sm font-semibold text-[#101114] shadow-lg shadow-primary/20 hover:opacity-90 active:scale-[0.97] transition-all" className="w-full min-h-[44px] rounded-lg bg-[#22d3ee] text-white px-4 py-2 text-sm font-semibold hover:brightness-110 active:scale-[0.98] transition-all"
> >
Pick Up Session Pick Up Session
</button> </button>

View File

@@ -70,8 +70,8 @@ export function FlowPilotActionBar({
<> <>
{/* Bottom bar — fixed to viewport bottom, works regardless of height chain */} {/* Bottom bar — fixed to viewport bottom, works regardless of height chain */}
<div <div
className="fixed bottom-0 right-0 z-40 flex flex-col gap-2 sm:flex-row sm:items-center sm:gap-3 border-t px-3 py-3 sm:px-5" className="fixed bottom-0 right-0 z-40 flex flex-col gap-2 sm:flex-row sm:items-center sm:gap-3 border-t border-[#1e2130] bg-[#14161d] px-3 py-3 sm:px-5"
style={{ borderColor: 'var(--glass-border)', background: 'rgba(16, 17, 20, 0.95)', backdropFilter: 'blur(16px)', left: 'var(--sidebar-w, 0px)' }} style={{ left: 'var(--sidebar-w, 0px)' }}
> >
<div className="flex gap-2 sm:gap-3"> <div className="flex gap-2 sm:gap-3">
<button <button
@@ -96,7 +96,7 @@ export function FlowPilotActionBar({
<button <button
onClick={handlePause} onClick={handlePause}
disabled={isProcessing || submitting} disabled={isProcessing || submitting}
className="flex items-center justify-center gap-2 rounded-lg bg-[rgba(255,255,255,0.04)] border border-[rgba(255,255,255,0.06)] px-4 py-2 min-h-[44px] text-sm font-medium text-muted-foreground hover:text-foreground hover:border-[rgba(255,255,255,0.12)] disabled:opacity-40 disabled:pointer-events-none transition-colors" className="flex items-center justify-center gap-2 rounded-lg bg-[rgba(255,255,255,0.04)] border border-[rgba(255,255,255,0.06)] px-4 py-2 min-h-[44px] text-sm font-medium text-[#848b9b] hover:text-[#e2e5eb] hover:border-[rgba(255,255,255,0.12)] disabled:opacity-40 disabled:pointer-events-none transition-colors"
> >
<Pause size={16} /> <Pause size={16} />
Pause Pause
@@ -106,7 +106,7 @@ export function FlowPilotActionBar({
<button <button
onClick={() => setShowAbandon(true)} onClick={() => setShowAbandon(true)}
disabled={isProcessing || submitting} disabled={isProcessing || submitting}
className="flex items-center justify-center gap-2 rounded-lg bg-[rgba(255,255,255,0.04)] border border-[rgba(255,255,255,0.06)] px-4 py-2 min-h-[44px] text-sm font-medium text-muted-foreground hover:text-foreground hover:border-[rgba(255,255,255,0.12)] disabled:opacity-40 disabled:pointer-events-none transition-colors" className="flex items-center justify-center gap-2 rounded-lg bg-[rgba(255,255,255,0.04)] border border-[rgba(255,255,255,0.06)] px-4 py-2 min-h-[44px] text-sm font-medium text-[#848b9b] hover:text-[#e2e5eb] hover:border-[rgba(255,255,255,0.12)] disabled:opacity-40 disabled:pointer-events-none transition-colors"
> >
<X size={16} /> <X size={16} />
Close Close
@@ -118,21 +118,21 @@ export function FlowPilotActionBar({
{/* Resolve modal */} {/* Resolve modal */}
{showResolve && ( {showResolve && (
<div className="fixed inset-0 z-50 flex items-end sm:items-center justify-center bg-black/60 backdrop-blur-sm"> <div className="fixed inset-0 z-50 flex items-end sm:items-center justify-center bg-black/60 backdrop-blur-sm">
<div className="glass-card-static w-full max-w-full sm:max-w-lg mx-0 sm:mx-4 p-4 sm:p-6 rounded-t-2xl sm:rounded-2xl"> <div className="card-flat w-full max-w-full sm:max-w-lg mx-0 sm:mx-4 p-4 sm:p-6 rounded-t-2xl sm:rounded-2xl">
<h3 className="font-heading text-lg font-semibold text-foreground mb-1">Resolve Session</h3> <h3 className="font-heading text-lg font-semibold text-[#e2e5eb] mb-1">Resolve Session</h3>
<p className="text-sm text-muted-foreground mb-4">Summarize what fixed the issue. This will be included in the auto-generated documentation.</p> <p className="text-sm text-[#848b9b] mb-4">Summarize what fixed the issue. This will be included in the auto-generated documentation.</p>
<textarea <textarea
value={resolutionSummary} value={resolutionSummary}
onChange={(e) => setResolutionSummary(e.target.value)} onChange={(e) => setResolutionSummary(e.target.value)}
placeholder="What resolved the issue?" placeholder="What resolved the issue?"
className="w-full rounded-lg border border-border bg-card px-3 py-2 text-sm text-foreground placeholder:text-muted-foreground focus:border-[rgba(6,182,212,0.3)] focus:outline-none resize-none" className="w-full rounded-lg border border-[#1e2130] bg-[#14161d] px-3 py-2 text-sm text-[#e2e5eb] placeholder:text-[#848b9b] focus:border-[rgba(6,182,212,0.3)] focus:outline-none resize-none"
rows={4} rows={4}
autoFocus autoFocus
/> />
<div className="mt-4 flex flex-col-reverse gap-2 sm:flex-row sm:justify-end"> <div className="mt-4 flex flex-col-reverse gap-2 sm:flex-row sm:justify-end">
<button <button
onClick={() => setShowResolve(false)} onClick={() => setShowResolve(false)}
className="rounded-lg px-4 py-2 min-h-[44px] text-sm text-muted-foreground hover:text-foreground transition-colors" className="rounded-lg px-4 py-2 min-h-[44px] text-sm text-[#848b9b] hover:text-[#e2e5eb] transition-colors"
> >
Cancel Cancel
</button> </button>
@@ -151,15 +151,15 @@ export function FlowPilotActionBar({
{/* Close/Abandon confirmation */} {/* Close/Abandon confirmation */}
{showAbandon && ( {showAbandon && (
<div className="fixed inset-0 z-50 flex items-end sm:items-center justify-center bg-black/60 backdrop-blur-sm"> <div className="fixed inset-0 z-50 flex items-end sm:items-center justify-center bg-black/60 backdrop-blur-sm">
<div className="glass-card-static w-full max-w-full sm:max-w-lg mx-0 sm:mx-4 p-4 sm:p-6 rounded-t-2xl sm:rounded-2xl"> <div className="card-flat w-full max-w-full sm:max-w-lg mx-0 sm:mx-4 p-4 sm:p-6 rounded-t-2xl sm:rounded-2xl">
<h3 className="font-heading text-lg font-semibold text-foreground mb-1">Close Session</h3> <h3 className="font-heading text-lg font-semibold text-[#e2e5eb] mb-1">Close Session</h3>
<p className="text-sm text-muted-foreground mb-4"> <p className="text-sm text-[#848b9b] mb-4">
Are you sure you want to close this session? The session history will be kept but it won't count as resolved. Are you sure you want to close this session? The session history will be kept but it won't count as resolved.
</p> </p>
<div className="flex flex-col-reverse gap-2 sm:flex-row sm:justify-end"> <div className="flex flex-col-reverse gap-2 sm:flex-row sm:justify-end">
<button <button
onClick={() => setShowAbandon(false)} onClick={() => setShowAbandon(false)}
className="rounded-lg px-4 py-2 min-h-[44px] text-sm text-muted-foreground hover:text-foreground transition-colors" className="rounded-lg px-4 py-2 min-h-[44px] text-sm text-[#848b9b] hover:text-[#e2e5eb] transition-colors"
> >
Cancel Cancel
</button> </button>

View File

@@ -100,11 +100,11 @@ export function FlowPilotIntake({ onSubmit, isLoading, defaultProblem }: FlowPil
return ( return (
<div className="flex items-center justify-center min-h-[50vh]"> <div className="flex items-center justify-center min-h-[50vh]">
<div className="text-center"> <div className="text-center">
<div className="mx-auto mb-4 flex h-12 w-12 items-center justify-center rounded-2xl bg-primary/10"> <div className="mx-auto mb-4 flex h-12 w-12 items-center justify-center rounded-2xl bg-[rgba(34,211,238,0.10)]">
<Sparkles size={24} className="text-primary animate-pulse" /> <Sparkles size={24} className="text-[#22d3ee] animate-pulse" />
</div> </div>
<p className="text-sm font-medium text-foreground">Analyzing your issue...</p> <p className="text-sm font-medium text-[#e2e5eb]">Analyzing your issue...</p>
<p className="mt-1 text-xs text-muted-foreground">FlowPilot is classifying the problem and searching for relevant flows</p> <p className="mt-1 text-xs text-[#848b9b]">FlowPilot is classifying the problem and searching for relevant flows</p>
</div> </div>
</div> </div>
) )
@@ -118,26 +118,26 @@ export function FlowPilotIntake({ onSubmit, isLoading, defaultProblem }: FlowPil
<div className="flex items-start justify-center px-3 sm:px-4 pt-[6vh] sm:pt-[10vh]"> <div className="flex items-start justify-center px-3 sm:px-4 pt-[6vh] sm:pt-[10vh]">
<div className="w-full max-w-2xl"> <div className="w-full max-w-2xl">
<div className="text-center mb-4 sm:mb-6"> <div className="text-center mb-4 sm:mb-6">
<h1 className="font-heading text-xl sm:text-2xl font-bold tracking-tight text-foreground"> <h1 className="font-heading text-xl sm:text-2xl font-bold tracking-tight text-[#e2e5eb]">
What are you troubleshooting? What are you troubleshooting?
</h1> </h1>
<p className="mt-2 text-sm text-muted-foreground"> <p className="mt-2 text-sm text-[#848b9b]">
Describe the issue, paste an error message, or pull context from a ticket Describe the issue, paste an error message, or pull context from a ticket
</p> </p>
</div> </div>
<div className="glass-card-static p-3 sm:p-5 space-y-4"> <div className="card-flat p-3 sm:p-5 space-y-4">
{/* Selected ticket card */} {/* Selected ticket card */}
{selectedTicket && selectedTicketId && ( {selectedTicket && selectedTicketId && (
<div className="rounded-xl border border-primary/20 bg-primary/5 p-4"> <div className="rounded-xl border border-primary/20 bg-primary/5 p-4">
<div className="flex items-start justify-between"> <div className="flex items-start justify-between">
<div className="min-w-0 flex-1"> <div className="min-w-0 flex-1">
<p className="text-sm font-semibold text-foreground"> <p className="text-sm font-semibold text-[#e2e5eb]">
<span className="text-primary">#{selectedTicketId}</span> <span className="text-[#22d3ee]">#{selectedTicketId}</span>
{' — '} {' — '}
{selectedTicket.summary} {selectedTicket.summary}
</p> </p>
<div className="mt-1 flex flex-wrap items-center gap-x-2 text-xs text-muted-foreground"> <div className="mt-1 flex flex-wrap items-center gap-x-2 text-xs text-[#848b9b]">
{selectedTicket.company_name && <span>{selectedTicket.company_name}</span>} {selectedTicket.company_name && <span>{selectedTicket.company_name}</span>}
{selectedTicket.priority_name && ( {selectedTicket.priority_name && (
<> <>
@@ -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-[#848b9b] hover:bg-white/[0.06] hover:text-[#e2e5eb] transition-colors"
> >
<X size={14} /> <X size={14} />
</button> </button>
@@ -166,7 +166,7 @@ export function FlowPilotIntake({ onSubmit, isLoading, defaultProblem }: FlowPil
value={additionalContext} value={additionalContext}
onChange={(e) => setAdditionalContext(e.target.value)} onChange={(e) => setAdditionalContext(e.target.value)}
placeholder="Add extra context (optional) — e.g. 'User called back and said it's also affecting their second monitor'" placeholder="Add extra context (optional) — e.g. 'User called back and said it's also affecting their second monitor'"
className="mt-3 w-full rounded-lg border border-border bg-card px-3 py-2 text-sm text-foreground placeholder:text-muted-foreground focus:border-[rgba(6,182,212,0.3)] focus:outline-none resize-none" className="mt-3 w-full rounded-lg border border-[#1e2130] bg-[#14161d] px-3 py-2 text-sm text-[#e2e5eb] placeholder:text-[#848b9b] focus:border-[rgba(6,182,212,0.3)] focus:outline-none resize-none"
rows={3} rows={3}
/> />
</div> </div>
@@ -190,8 +190,8 @@ export function FlowPilotIntake({ onSubmit, isLoading, defaultProblem }: FlowPil
onClick={() => setShowLogs(!showLogs)} onClick={() => setShowLogs(!showLogs)}
className={`flex items-center gap-1.5 rounded-lg px-3 py-1.5 text-xs font-medium transition-colors ${ className={`flex items-center gap-1.5 rounded-lg px-3 py-1.5 text-xs font-medium transition-colors ${
showLogs showLogs
? 'bg-primary/10 text-primary border border-primary/20' ? 'bg-[rgba(34,211,238,0.10)] text-[#22d3ee] border border-primary/20'
: 'bg-card/50 text-muted-foreground border border-border hover:text-foreground' : 'bg-[#14161d]/50 text-[#848b9b] border border-[#1e2130] hover:text-[#e2e5eb]'
}`} }`}
> >
<Terminal size={12} /> <Terminal size={12} />
@@ -206,8 +206,8 @@ export function FlowPilotIntake({ onSubmit, isLoading, defaultProblem }: FlowPil
disabled={!psaChecked || !psaConnection} disabled={!psaChecked || !psaConnection}
className={`flex items-center gap-1.5 rounded-lg px-3 py-1.5 text-xs font-medium transition-colors ${ className={`flex items-center gap-1.5 rounded-lg px-3 py-1.5 text-xs font-medium transition-colors ${
psaConnection psaConnection
? 'bg-card/50 text-muted-foreground border border-border hover:text-foreground hover:border-primary/20' ? 'bg-[#14161d]/50 text-[#848b9b] border border-[#1e2130] hover:text-[#e2e5eb] hover:border-primary/20'
: 'bg-card/50 text-[#5a6170] border border-border opacity-50 cursor-not-allowed' : 'bg-[#14161d]/50 text-[#5a6170] border border-[#1e2130] opacity-50 cursor-not-allowed'
}`} }`}
title={!psaConnection ? 'Connect your PSA in Settings → Integrations' : 'Search for a ConnectWise ticket'} title={!psaConnection ? 'Connect your PSA in Settings → Integrations' : 'Search for a ConnectWise ticket'}
> >
@@ -229,7 +229,7 @@ export function FlowPilotIntake({ onSubmit, isLoading, defaultProblem }: FlowPil
value={logContent} value={logContent}
onChange={(e) => setLogContent(e.target.value)} onChange={(e) => setLogContent(e.target.value)}
placeholder="Paste log output, error messages, or Event Viewer entries here..." placeholder="Paste log output, error messages, or Event Viewer entries here..."
className="w-full rounded-lg border border-border bg-card px-4 py-3 font-mono text-xs text-foreground placeholder:text-muted-foreground focus:border-[rgba(6,182,212,0.3)] focus:outline-none resize-none" className="w-full rounded-lg border border-[#1e2130] bg-[#14161d] px-4 py-3 font-mono text-xs text-[#e2e5eb] placeholder:text-[#848b9b] focus:border-[rgba(6,182,212,0.3)] focus:outline-none resize-none"
rows={6} rows={6}
/> />
)} )}
@@ -242,7 +242,7 @@ export function FlowPilotIntake({ onSubmit, isLoading, defaultProblem }: FlowPil
<button <button
onClick={handleSubmit} onClick={handleSubmit}
disabled={!hasContent} disabled={!hasContent}
className="w-full sm:w-auto min-h-[44px] rounded-lg bg-gradient-brand px-5 py-2.5 text-sm font-semibold text-[#101114] shadow-lg shadow-primary/20 hover:opacity-90 active:scale-[0.97] disabled:opacity-40 disabled:shadow-none transition-all whitespace-nowrap" className="w-full sm:w-auto min-h-[44px] rounded-lg bg-[#22d3ee] text-white px-5 py-2.5 text-sm font-semibold hover:brightness-110 active:scale-[0.98] disabled:opacity-40 transition-all whitespace-nowrap"
> >
{submitLabel} {submitLabel}
</button> </button>

View File

@@ -48,10 +48,10 @@ export function FlowPilotMessageBar({ onRespond, disabled = false, isProcessing
className={cn( className={cn(
'flex items-end gap-2 rounded-xl border p-3 transition-colors', 'flex items-end gap-2 rounded-xl border p-3 transition-colors',
isDisabled isDisabled
? 'border-border/50 opacity-50' ? 'border-[#1e2130]/50 opacity-50'
: 'border-border focus-within:border-[rgba(6,182,212,0.3)]' : 'border-[#1e2130] focus-within:border-[rgba(6,182,212,0.3)]'
)} )}
style={{ background: 'rgba(16, 17, 20, 0.95)', backdropFilter: 'blur(16px)' }} style={{ background: '#14161d' }}
> >
<textarea <textarea
ref={textareaRef} ref={textareaRef}
@@ -61,7 +61,7 @@ export function FlowPilotMessageBar({ onRespond, disabled = false, isProcessing
placeholder={isProcessing ? 'FlowPilot is thinking...' : 'Type a message...'} placeholder={isProcessing ? 'FlowPilot is thinking...' : 'Type a message...'}
disabled={isDisabled} disabled={isDisabled}
rows={1} rows={1}
className="flex-1 resize-none bg-transparent text-sm text-foreground placeholder:text-muted-foreground focus:outline-none disabled:cursor-not-allowed py-1.5 px-2" className="flex-1 resize-none bg-transparent text-sm text-[#e2e5eb] placeholder:text-[#848b9b] focus:outline-none disabled:cursor-not-allowed py-1.5 px-2"
/> />
<button <button
onClick={handleSubmit} onClick={handleSubmit}
@@ -70,8 +70,8 @@ export function FlowPilotMessageBar({ onRespond, disabled = false, isProcessing
className={cn( className={cn(
'flex h-9 w-9 shrink-0 items-center justify-center rounded-lg transition-all', 'flex h-9 w-9 shrink-0 items-center justify-center rounded-lg transition-all',
message.trim() && !isDisabled message.trim() && !isDisabled
? 'bg-gradient-brand text-[#101114] hover:opacity-90 active:scale-[0.97]' ? 'bg-[#22d3ee] text-white hover:brightness-110 active:scale-[0.98]'
: 'bg-[rgba(255,255,255,0.04)] text-muted-foreground cursor-not-allowed' : 'bg-[rgba(255,255,255,0.04)] text-[#848b9b] cursor-not-allowed'
)} )}
> >
<Send size={16} /> <Send size={16} />

View File

@@ -32,20 +32,20 @@ export function FlowPilotOptions({ options, onSelect, disabled }: FlowPilotOptio
'hover:border-[rgba(6,182,212,0.3)] hover:shadow-[0_0_20px_rgba(6,182,212,0.08)]', 'hover:border-[rgba(6,182,212,0.3)] hover:shadow-[0_0_20px_rgba(6,182,212,0.08)]',
'focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary/40', 'focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary/40',
isSelected isSelected
? 'border-primary/40 bg-primary/10' ? 'border-primary/40 bg-[rgba(34,211,238,0.10)]'
: 'border-border bg-card/50', : 'border-[#1e2130] bg-[#14161d]/50',
disabled && 'pointer-events-none opacity-60' disabled && 'pointer-events-none opacity-60'
)} )}
> >
<div className="flex items-start justify-between gap-3"> <div className="flex items-start justify-between gap-3">
<div className="flex-1"> <div className="flex-1">
<p className="text-sm font-medium text-foreground">{option.label}</p> <p className="text-sm font-medium text-[#e2e5eb]">{option.label}</p>
{option.followup_hint && ( {option.followup_hint && (
<p className="mt-1 text-xs text-muted-foreground">{option.followup_hint}</p> <p className="mt-1 text-xs text-[#848b9b]">{option.followup_hint}</p>
)} )}
</div> </div>
{isSelected && ( {isSelected && (
<span className="flex h-5 w-5 shrink-0 items-center justify-center rounded-full bg-primary/20 text-primary"> <span className="flex h-5 w-5 shrink-0 items-center justify-center rounded-full bg-primary/20 text-[#22d3ee]">
<Check size={12} /> <Check size={12} />
</span> </span>
)} )}

View File

@@ -141,9 +141,9 @@ export function FlowPilotSession({
onClick={() => setShowMobileSidebar(!showMobileSidebar)} onClick={() => setShowMobileSidebar(!showMobileSidebar)}
className="flex w-full items-center justify-between px-3 py-2 sm:px-4" className="flex w-full items-center justify-between px-3 py-2 sm:px-4"
> >
<div className="flex items-center gap-3 text-xs text-muted-foreground overflow-x-auto"> <div className="flex items-center gap-3 text-xs text-[#848b9b] overflow-x-auto">
{session.problem_domain && ( {session.problem_domain && (
<span className="font-label rounded-md bg-primary/10 px-1.5 py-0.5 text-[0.5625rem] uppercase tracking-wider text-primary shrink-0"> <span className="font-sans text-xs rounded-md bg-[rgba(34,211,238,0.10)] px-1.5 py-0.5 text-[0.5625rem] uppercase tracking-wider text-[#22d3ee] shrink-0">
{session.problem_domain} {session.problem_domain}
</span> </span>
)} )}
@@ -156,7 +156,7 @@ export function FlowPilotSession({
score={currentStep?.confidence_score ?? 0} score={currentStep?.confidence_score ?? 0}
/> />
</div> </div>
{showMobileSidebar ? <ChevronUp size={14} className="text-muted-foreground shrink-0" /> : <ChevronDown size={14} className="text-muted-foreground shrink-0" />} {showMobileSidebar ? <ChevronUp size={14} className="text-[#848b9b] shrink-0" /> : <ChevronDown size={14} className="text-[#848b9b] shrink-0" />}
</button> </button>
{showMobileSidebar && ( {showMobileSidebar && (
<div className="px-3 pb-3 sm:px-4 space-y-3"> <div className="px-3 pb-3 sm:px-4 space-y-3">
@@ -169,7 +169,7 @@ export function FlowPilotSession({
<button <button
onClick={() => setShowTicketPicker(true)} onClick={() => setShowTicketPicker(true)}
disabled={linkingTicket} disabled={linkingTicket}
className="w-full flex items-center gap-2 rounded-xl border border-dashed border-border px-3 py-2.5 text-xs text-muted-foreground hover:text-foreground hover:border-primary/30 transition-colors disabled:opacity-50 min-h-[44px]" className="w-full flex items-center gap-2 rounded-xl border border-dashed border-[#1e2130] px-3 py-2.5 text-xs text-[#848b9b] hover:text-[#e2e5eb] hover:border-primary/30 transition-colors disabled:opacity-50 min-h-[44px]"
> >
<Ticket size={14} /> <Ticket size={14} />
{linkingTicket ? 'Linking...' : 'Link Ticket'} {linkingTicket ? 'Linking...' : 'Link Ticket'}
@@ -177,14 +177,14 @@ export function FlowPilotSession({
) : null} ) : null}
{session.problem_summary && ( {session.problem_summary && (
<div> <div>
<h4 className="font-label text-[0.625rem] uppercase tracking-wider text-[#5a6170] mb-1">Problem</h4> <h4 className="font-sans text-xs text-[0.625rem] uppercase tracking-wider text-[#5a6170] mb-1">Problem</h4>
<p className="text-sm text-foreground">{session.problem_summary}</p> <p className="text-sm text-[#e2e5eb]">{session.problem_summary}</p>
</div> </div>
)} )}
{session.matched_flow_id && ( {session.matched_flow_id && (
<div className="flex items-center gap-2"> <div className="flex items-center gap-2">
<Network size={14} className="text-muted-foreground" /> <Network size={14} className="text-[#848b9b]" />
<span className="text-xs text-foreground"> <span className="text-xs text-[#e2e5eb]">
{session.match_score ? `${Math.round(session.match_score * 100)}% match` : 'Match found'} {session.match_score ? `${Math.round(session.match_score * 100)}% match` : 'Match found'}
</span> </span>
</div> </div>
@@ -228,7 +228,7 @@ export function FlowPilotSession({
<button <button
onClick={() => setShowTicketPicker(true)} onClick={() => setShowTicketPicker(true)}
disabled={linkingTicket} disabled={linkingTicket}
className="w-full flex items-center gap-2 rounded-xl border border-dashed border-border px-3 py-2.5 text-xs text-muted-foreground hover:text-foreground hover:border-primary/30 transition-colors disabled:opacity-50" className="w-full flex items-center gap-2 rounded-xl border border-dashed border-[#1e2130] px-3 py-2.5 text-xs text-[#848b9b] hover:text-[#e2e5eb] hover:border-primary/30 transition-colors disabled:opacity-50"
> >
<Ticket size={14} /> <Ticket size={14} />
{linkingTicket ? 'Linking...' : 'Link Ticket'} {linkingTicket ? 'Linking...' : 'Link Ticket'}
@@ -238,20 +238,20 @@ export function FlowPilotSession({
{/* Problem summary */} {/* Problem summary */}
{session.problem_summary && ( {session.problem_summary && (
<div> <div>
<h4 className="font-label text-[0.625rem] uppercase tracking-wider text-[#5a6170] mb-1"> <h4 className="font-sans text-xs text-[0.625rem] uppercase tracking-wider text-[#5a6170] mb-1">
Problem Problem
</h4> </h4>
<p className="text-sm text-foreground">{session.problem_summary}</p> <p className="text-sm text-[#e2e5eb]">{session.problem_summary}</p>
</div> </div>
)} )}
{/* Domain */} {/* Domain */}
{session.problem_domain && ( {session.problem_domain && (
<div> <div>
<h4 className="font-label text-[0.625rem] uppercase tracking-wider text-[#5a6170] mb-1"> <h4 className="font-sans text-xs text-[0.625rem] uppercase tracking-wider text-[#5a6170] mb-1">
Domain Domain
</h4> </h4>
<span className="font-label rounded-md bg-primary/10 px-2 py-0.5 text-[0.625rem] uppercase tracking-wider text-primary"> <span className="font-sans text-xs rounded-md bg-[rgba(34,211,238,0.10)] px-2 py-0.5 text-[0.625rem] uppercase tracking-wider text-[#22d3ee]">
{session.problem_domain} {session.problem_domain}
</span> </span>
</div> </div>
@@ -259,7 +259,7 @@ export function FlowPilotSession({
{/* Confidence */} {/* Confidence */}
<div> <div>
<h4 className="font-label text-[0.625rem] uppercase tracking-wider text-[#5a6170] mb-1"> <h4 className="font-sans text-xs text-[0.625rem] uppercase tracking-wider text-[#5a6170] mb-1">
Confidence Confidence
</h4> </h4>
<ConfidenceIndicator <ConfidenceIndicator
@@ -271,12 +271,12 @@ export function FlowPilotSession({
{/* Matched flow */} {/* Matched flow */}
{session.matched_flow_id && ( {session.matched_flow_id && (
<div> <div>
<h4 className="font-label text-[0.625rem] uppercase tracking-wider text-[#5a6170] mb-1"> <h4 className="font-sans text-xs text-[0.625rem] uppercase tracking-wider text-[#5a6170] mb-1">
Matched flow Matched flow
</h4> </h4>
<div className="flex items-center gap-2"> <div className="flex items-center gap-2">
<Network size={14} className="text-muted-foreground" /> <Network size={14} className="text-[#848b9b]" />
<span className="text-xs text-foreground"> <span className="text-xs text-[#e2e5eb]">
{session.match_score ? `${Math.round(session.match_score * 100)}% match` : 'Match found'} {session.match_score ? `${Math.round(session.match_score * 100)}% match` : 'Match found'}
</span> </span>
</div> </div>
@@ -286,12 +286,12 @@ export function FlowPilotSession({
{/* Steps */} {/* Steps */}
<div className="flex items-center gap-4"> <div className="flex items-center gap-4">
<div className="flex items-center gap-1.5"> <div className="flex items-center gap-1.5">
<Hash size={12} className="text-muted-foreground" /> <Hash size={12} className="text-[#848b9b]" />
<span className="text-xs text-muted-foreground">{session.step_count} steps</span> <span className="text-xs text-[#848b9b]">{session.step_count} steps</span>
</div> </div>
<div className="flex items-center gap-1.5"> <div className="flex items-center gap-1.5">
<Clock size={12} className="text-muted-foreground" /> <Clock size={12} className="text-[#848b9b]" />
<span className="text-xs text-muted-foreground"> <span className="text-xs text-[#848b9b]">
{new Date(session.created_at).toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' })} {new Date(session.created_at).toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' })}
</span> </span>
</div> </div>
@@ -330,13 +330,12 @@ export function FlowPilotSession({
{/* Paused banner */} {/* Paused banner */}
{session.status === 'paused' && onResume && ( {session.status === 'paused' && onResume && (
<div <div
className="flex flex-col gap-2 sm:flex-row sm:items-center sm:justify-between border-t px-3 py-3 sm:px-5" className="flex flex-col gap-2 sm:flex-row sm:items-center sm:justify-between border-t border-[#1e2130] bg-[#14161d] px-3 py-3 sm:px-5"
style={{ borderColor: 'var(--glass-border)', background: 'rgba(16, 17, 20, 0.8)', backdropFilter: 'blur(12px)' }}
> >
<span className="text-sm text-muted-foreground">Session paused</span> <span className="text-sm text-[#848b9b]">Session paused</span>
<button <button
onClick={onResume} onClick={onResume}
className="flex items-center gap-2 rounded-lg bg-gradient-brand px-4 py-2 text-sm font-semibold text-[#101114] shadow-lg shadow-primary/20 hover:opacity-90 active:scale-[0.97] transition-all" className="flex items-center gap-2 rounded-lg bg-[#22d3ee] text-white px-4 py-2 text-sm font-semibold hover:brightness-110 active:scale-[0.98] transition-all"
> >
<Play size={14} /> <Play size={14} />
Resume Session Resume Session

View File

@@ -62,12 +62,12 @@ export function FlowPilotStepCard({ step, isCurrentStep, isProcessing, sessionId
return ( return (
<button <button
onClick={() => setIsCollapsed(false)} onClick={() => setIsCollapsed(false)}
className="w-full text-left glass-card-static p-3 sm:p-4 opacity-70 hover:opacity-90 transition-opacity" className="w-full text-left card-flat p-3 sm:p-4 opacity-70 hover:opacity-90 transition-opacity"
> >
<div className="flex items-center gap-3"> <div className="flex items-center gap-3">
<Icon size={16} className="shrink-0 text-muted-foreground" /> <Icon size={16} className="shrink-0 text-[#848b9b]" />
<p className="text-sm text-foreground truncate flex-1">{stepText}</p> <p className="text-sm text-[#e2e5eb] truncate flex-1">{stepText}</p>
<ChevronDown size={14} className="shrink-0 text-muted-foreground" /> <ChevronDown size={14} className="shrink-0 text-[#848b9b]" />
</div> </div>
</button> </button>
) )
@@ -76,20 +76,20 @@ export function FlowPilotStepCard({ step, isCurrentStep, isProcessing, sessionId
// Expanded completed step // Expanded completed step
if (!isCurrentStep && !isCollapsed) { if (!isCurrentStep && !isCollapsed) {
return ( return (
<div className="glass-card-static p-3 sm:p-4 opacity-80"> <div className="card-flat p-3 sm:p-4 opacity-80">
<button <button
onClick={() => setIsCollapsed(true)} onClick={() => setIsCollapsed(true)}
className="mb-2 flex w-full items-center justify-between text-left" className="mb-2 flex w-full items-center justify-between text-left"
> >
<div className="flex items-center gap-2"> <div className="flex items-center gap-2">
<Icon size={16} className="text-muted-foreground" /> <Icon size={16} className="text-[#848b9b]" />
<span className="font-label text-[0.625rem] uppercase tracking-wider text-muted-foreground"> <span className="font-sans text-xs text-[0.625rem] uppercase tracking-wider text-[#848b9b]">
Step {step.step_order + 1} Step {step.step_order + 1}
</span> </span>
</div> </div>
<ChevronUp size={14} className="text-muted-foreground" /> <ChevronUp size={14} className="text-[#848b9b]" />
</button> </button>
<MarkdownContent content={stepText} className="text-sm text-foreground" /> <MarkdownContent content={stepText} className="text-sm text-[#e2e5eb]" />
</div> </div>
) )
} }
@@ -98,14 +98,14 @@ export function FlowPilotStepCard({ step, isCurrentStep, isProcessing, sessionId
return ( return (
<div <div
className={cn( className={cn(
'glass-card-static 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-emerald-500/30'
)} )}
> >
{/* Context message */} {/* Context message */}
{step.context_message && ( {step.context_message && (
<div className="mb-3 rounded-lg bg-primary/5 px-3 py-2 border border-primary/10"> <div className="mb-3 rounded-lg bg-primary/5 px-3 py-2 border border-primary/10">
<MarkdownContent content={step.context_message} className="text-xs text-muted-foreground" /> <MarkdownContent content={step.context_message} className="text-xs text-[#848b9b]" />
</div> </div>
)} )}
@@ -113,14 +113,14 @@ 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-primary/10 text-primary' isResolutionSuggestion ? 'bg-emerald-500/10 text-emerald-400' : 'bg-[rgba(34,211,238,0.10)] text-[#22d3ee]'
)}> )}>
<Icon size={14} /> <Icon size={14} />
</span> </span>
<div className="min-w-0 flex-1"> <div className="min-w-0 flex-1">
<MarkdownContent content={stepText} className="text-sm" /> <MarkdownContent content={stepText} className="text-sm" />
{isResolutionSuggestion && typeof content.resolution_summary === 'string' && ( {isResolutionSuggestion && typeof content.resolution_summary === 'string' && (
<p className="mt-2 text-sm text-muted-foreground"> <p className="mt-2 text-sm text-[#848b9b]">
{content.resolution_summary} {content.resolution_summary}
</p> </p>
)} )}
@@ -141,7 +141,7 @@ export function FlowPilotStepCard({ step, isCurrentStep, isProcessing, sessionId
</button> </button>
<button <button
onClick={() => handleResolutionResponse(false)} onClick={() => handleResolutionResponse(false)}
className="flex-1 min-h-[44px] rounded-lg bg-card/50 border border-border px-4 py-2.5 text-sm font-medium text-foreground hover:bg-card transition-colors" className="flex-1 min-h-[44px] rounded-lg bg-[#14161d]/50 border border-[#1e2130] px-4 py-2.5 text-sm font-medium text-[#e2e5eb] hover:bg-[#14161d] transition-colors"
> >
No, keep investigating No, keep investigating
</button> </button>
@@ -180,7 +180,7 @@ export function FlowPilotStepCard({ step, isCurrentStep, isProcessing, sessionId
window.open('/script-builder?from=flowpilot', '_blank') window.open('/script-builder?from=flowpilot', '_blank')
onRespond({ action_result: { success: true, details: 'Opened Script Builder' } }) onRespond({ action_result: { success: true, details: 'Opened Script Builder' } })
}} }}
className="flex-1 min-h-[44px] rounded-lg bg-gradient-brand px-4 py-2.5 text-sm font-semibold text-[#101114] hover:opacity-90 active:scale-[0.97] transition-all" className="flex-1 min-h-[44px] rounded-lg bg-[#22d3ee] text-white px-4 py-2.5 text-sm font-semibold hover:brightness-110 active:scale-[0.98] transition-all"
> >
Open Script Builder Open Script Builder
</button> </button>
@@ -191,13 +191,13 @@ 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={() => handleActionComplete(true)} onClick={() => handleActionComplete(true)}
className="flex-1 min-h-[44px] rounded-lg bg-primary/10 border border-primary/20 px-4 py-2.5 text-sm font-medium text-primary hover:bg-primary/20 transition-colors" className="flex-1 min-h-[44px] rounded-lg bg-[rgba(34,211,238,0.10)] border border-primary/20 px-4 py-2.5 text-sm font-medium text-[#22d3ee] hover:bg-primary/20 transition-colors"
> >
I've completed this action I've completed this action
</button> </button>
<button <button
onClick={() => handleActionComplete(false)} onClick={() => handleActionComplete(false)}
className="flex-1 min-h-[44px] rounded-lg bg-card/50 border border-border px-4 py-2.5 text-sm font-medium text-foreground hover:bg-card transition-colors" className="flex-1 min-h-[44px] rounded-lg bg-[#14161d]/50 border border-[#1e2130] px-4 py-2.5 text-sm font-medium text-[#e2e5eb] hover:bg-[#14161d] transition-colors"
> >
This didn't work This didn't work
</button> </button>
@@ -208,7 +208,7 @@ export function FlowPilotStepCard({ step, isCurrentStep, isProcessing, sessionId
{!isResolutionSuggestion && step.allow_skip && ( {!isResolutionSuggestion && step.allow_skip && (
<button <button
onClick={handleSkip} onClick={handleSkip}
className="flex items-center gap-1.5 text-xs text-[#5a6170] hover:text-muted-foreground transition-colors" className="flex items-center gap-1.5 text-xs text-[#5a6170] hover:text-[#848b9b] transition-colors"
> >
<SkipForward size={12} /> <SkipForward size={12} />
I can't check this right now I can't check this right now
@@ -221,7 +221,7 @@ export function FlowPilotStepCard({ step, isCurrentStep, isProcessing, sessionId
{isProcessing && ( {isProcessing && (
<div className="flex items-center gap-2 pt-2"> <div className="flex items-center gap-2 pt-2">
<div className="h-1.5 w-1.5 rounded-full bg-primary animate-pulse" /> <div className="h-1.5 w-1.5 rounded-full bg-primary animate-pulse" />
<span className="text-xs text-muted-foreground">FlowPilot is thinking...</span> <span className="text-xs text-[#848b9b]">FlowPilot is thinking...</span>
</div> </div>
)} )}
</div> </div>

View File

@@ -65,14 +65,14 @@ export function InSessionScriptGenerator({
return ( return (
<div className="mt-3 rounded-xl border border-primary/20 bg-primary/5 p-3 sm:p-4 space-y-3"> <div className="mt-3 rounded-xl border border-primary/20 bg-primary/5 p-3 sm:p-4 space-y-3">
<div className="flex items-center gap-2"> <div className="flex items-center gap-2">
<Terminal size={14} className="text-primary" /> <Terminal size={14} className="text-[#22d3ee]" />
<span className="font-label text-[0.625rem] uppercase tracking-wider text-primary"> <span className="font-sans text-xs text-[0.625rem] uppercase tracking-wider text-[#22d3ee]">
Script Generator Script Generator
</span> </span>
</div> </div>
{instructions && ( {instructions && (
<p className="text-xs text-muted-foreground">{instructions}</p> <p className="text-xs text-[#848b9b]">{instructions}</p>
)} )}
{/* Parameter editing */} {/* Parameter editing */}
@@ -80,7 +80,7 @@ export function InSessionScriptGenerator({
<> <>
<button <button
onClick={() => setShowParams(!showParams)} onClick={() => setShowParams(!showParams)}
className="flex items-center gap-1.5 text-xs text-muted-foreground hover:text-foreground transition-colors" className="flex items-center gap-1.5 text-xs text-[#848b9b] hover:text-[#e2e5eb] transition-colors"
> >
{showParams ? <ChevronDown size={12} /> : <ChevronRight size={12} />} {showParams ? <ChevronDown size={12} /> : <ChevronRight size={12} />}
Parameters ({Object.keys(params).length}) Parameters ({Object.keys(params).length})
@@ -90,13 +90,13 @@ export function InSessionScriptGenerator({
<div className="space-y-2"> <div className="space-y-2">
{Object.entries(params).map(([key, value]) => ( {Object.entries(params).map(([key, value]) => (
<div key={key}> <div key={key}>
<label className="block text-xs font-medium text-muted-foreground mb-1"> <label className="block text-xs font-medium text-[#848b9b] mb-1">
{key.replace(/_/g, ' ')} {key.replace(/_/g, ' ')}
</label> </label>
<input <input
value={value} value={value}
onChange={(e) => setParams(prev => ({ ...prev, [key]: e.target.value }))} onChange={(e) => setParams(prev => ({ ...prev, [key]: e.target.value }))}
className="w-full rounded-lg border border-border bg-card px-3 py-1.5 text-sm text-foreground placeholder:text-muted-foreground focus:border-[rgba(6,182,212,0.3)] focus:outline-none" className="w-full rounded-lg border border-[#1e2130] bg-[#14161d] px-3 py-1.5 text-sm text-[#e2e5eb] placeholder:text-[#848b9b] focus:border-[rgba(6,182,212,0.3)] focus:outline-none"
/> />
</div> </div>
))} ))}
@@ -106,7 +106,7 @@ export function InSessionScriptGenerator({
<button <button
onClick={handleGenerate} onClick={handleGenerate}
disabled={isGenerating} disabled={isGenerating}
className="w-full min-h-[44px] flex items-center justify-center gap-2 rounded-lg bg-gradient-brand px-4 py-2 text-sm font-semibold text-[#101114] shadow-lg shadow-primary/20 hover:opacity-90 active:scale-[0.97] disabled:opacity-40 transition-all" className="w-full min-h-[44px] flex items-center justify-center gap-2 rounded-lg bg-[#22d3ee] text-white px-4 py-2 text-sm font-semibold hover:brightness-110 active:scale-[0.98] disabled:opacity-40 transition-all"
> >
{isGenerating ? ( {isGenerating ? (
<Loader2 size={14} className="animate-spin" /> <Loader2 size={14} className="animate-spin" />
@@ -121,12 +121,12 @@ export function InSessionScriptGenerator({
{/* Generated script display */} {/* Generated script display */}
{generatedScript && ( {generatedScript && (
<> <>
<div className="relative rounded-lg bg-card/80 border border-border overflow-hidden"> <div className="relative rounded-lg bg-[#14161d]/80 border border-[#1e2130] overflow-hidden">
<div className="flex items-center justify-between px-3 py-1.5 border-b border-border/50"> <div className="flex items-center justify-between px-3 py-1.5 border-b border-[#1e2130]/50">
<span className="text-xs text-muted-foreground font-mono">PowerShell</span> <span className="text-xs text-[#848b9b] font-mono">PowerShell</span>
<button <button
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-[#848b9b] hover:text-[#e2e5eb] transition-colors"
> >
{copied ? <Check size={12} className="text-emerald-400" /> : <Copy size={12} />} {copied ? <Check size={12} className="text-emerald-400" /> : <Copy size={12} />}
{copied ? 'Copied' : 'Copy'} {copied ? 'Copied' : 'Copy'}
@@ -141,13 +141,13 @@ export function InSessionScriptGenerator({
<div className="flex flex-col gap-2 pt-1 sm:flex-row"> <div className="flex flex-col gap-2 pt-1 sm:flex-row">
<button <button
onClick={() => handleContinue(true)} onClick={() => handleContinue(true)}
className="flex-1 min-h-[44px] rounded-lg bg-primary/10 border border-primary/20 px-4 py-2 text-sm font-medium text-primary hover:bg-primary/20 transition-colors" className="flex-1 min-h-[44px] rounded-lg bg-[rgba(34,211,238,0.10)] border border-primary/20 px-4 py-2 text-sm font-medium text-[#22d3ee] hover:bg-primary/20 transition-colors"
> >
Script worked continue Script worked continue
</button> </button>
<button <button
onClick={() => handleContinue(false)} onClick={() => handleContinue(false)}
className="flex-1 min-h-[44px] rounded-lg bg-card/50 border border-border px-4 py-2 text-sm font-medium text-foreground hover:bg-card transition-colors" className="flex-1 min-h-[44px] rounded-lg bg-[#14161d]/50 border border-[#1e2130] px-4 py-2 text-sm font-medium text-[#e2e5eb] hover:bg-[#14161d] transition-colors"
> >
Didn't resolve it Didn't resolve it
</button> </button>

View File

@@ -5,7 +5,7 @@ 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-emerald-400 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-amber-400 bg-amber-400/10 border-amber-400/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-blue-400 bg-blue-400/10 border-blue-400/20', icon: GitBranch },
auto_reinforced: { label: 'Reinforced', color: 'text-muted-foreground bg-card border-border', icon: Sparkles }, auto_reinforced: { label: 'Reinforced', color: 'text-[#848b9b] bg-[#14161d] border-[#1e2130]', icon: Sparkles },
} as const } as const
interface ProposalCardProps { interface ProposalCardProps {
@@ -24,24 +24,24 @@ export function ProposalCard({ proposal, isSelected, onClick }: ProposalCardProp
className={`w-full text-left rounded-xl border p-3 space-y-2 transition-all ${ className={`w-full text-left rounded-xl border p-3 space-y-2 transition-all ${
isSelected isSelected
? 'border-primary/30 bg-primary/5' ? 'border-primary/30 bg-primary/5'
: 'border-[rgba(255,255,255,0.06)] bg-[rgba(24,26,31,0.55)] hover:border-[rgba(255,255,255,0.12)]' : 'border-[rgba(255,255,255,0.06)] bg-[#14161d] hover:border-[rgba(255,255,255,0.12)]'
}`} }`}
> >
<div className="flex items-start justify-between gap-2"> <div className="flex items-start justify-between gap-2">
<p className="text-sm font-semibold text-foreground line-clamp-2">{proposal.title}</p> <p className="text-sm font-semibold text-[#e2e5eb] line-clamp-2">{proposal.title}</p>
<span className={`shrink-0 flex items-center gap-1 rounded-md border px-1.5 py-0.5 font-label text-[0.5625rem] uppercase tracking-wider ${typeConfig.color}`}> <span className={`shrink-0 flex items-center gap-1 rounded-md border px-1.5 py-0.5 font-sans text-xs text-[0.5625rem] uppercase tracking-wider ${typeConfig.color}`}>
<TypeIcon size={10} /> <TypeIcon size={10} />
{typeConfig.label} {typeConfig.label}
</span> </span>
</div> </div>
{proposal.description && ( {proposal.description && (
<p className="text-xs text-muted-foreground line-clamp-2">{proposal.description}</p> <p className="text-xs text-[#848b9b] line-clamp-2">{proposal.description}</p>
)} )}
<div className="flex flex-wrap items-center gap-x-3 gap-y-1 text-xs text-muted-foreground"> <div className="flex flex-wrap items-center gap-x-3 gap-y-1 text-xs text-[#848b9b]">
{proposal.problem_domain && ( {proposal.problem_domain && (
<span className="font-label rounded-md bg-primary/10 px-1.5 py-0.5 text-[0.5625rem] uppercase tracking-wider text-primary"> <span className="font-sans text-xs rounded-md bg-[rgba(34,211,238,0.10)] px-1.5 py-0.5 text-[0.5625rem] uppercase tracking-wider text-[#22d3ee]">
{proposal.problem_domain} {proposal.problem_domain}
</span> </span>
)} )}
@@ -53,7 +53,7 @@ export function ProposalCard({ proposal, isSelected, onClick }: ProposalCardProp
<Clock size={10} /> <Clock size={10} />
{new Date(proposal.created_at).toLocaleDateString()} {new Date(proposal.created_at).toLocaleDateString()}
</span> </span>
<span className="text-primary"> <span className="text-[#22d3ee]">
{Math.round(proposal.confidence_score * 100)}% {Math.round(proposal.confidence_score * 100)}%
</span> </span>
</div> </div>

View File

@@ -61,13 +61,13 @@ export function ProposalDetail({ proposal, onReview }: ProposalDetailProps) {
<div className="flex h-full flex-col"> <div className="flex h-full flex-col">
{/* Header */} {/* Header */}
<div className="border-b px-6 py-4" style={{ borderColor: 'var(--glass-border)' }}> <div className="border-b px-6 py-4" style={{ borderColor: 'var(--glass-border)' }}>
<h2 className="font-heading text-lg font-semibold text-foreground">{proposal.title}</h2> <h2 className="font-heading text-lg font-semibold text-[#e2e5eb]">{proposal.title}</h2>
{proposal.description && ( {proposal.description && (
<p className="mt-1 text-sm text-muted-foreground">{proposal.description}</p> <p className="mt-1 text-sm text-[#848b9b]">{proposal.description}</p>
)} )}
<div className="mt-3 flex flex-wrap items-center gap-3 text-xs text-muted-foreground"> <div className="mt-3 flex flex-wrap items-center gap-3 text-xs text-[#848b9b]">
{proposal.problem_domain && ( {proposal.problem_domain && (
<span className="font-label rounded-md bg-primary/10 px-2 py-0.5 text-[0.625rem] uppercase tracking-wider text-primary"> <span className="font-sans text-xs rounded-md bg-[rgba(34,211,238,0.10)] px-2 py-0.5 text-[0.625rem] uppercase tracking-wider text-[#22d3ee]">
{proposal.problem_domain} {proposal.problem_domain}
</span> </span>
)} )}
@@ -89,12 +89,12 @@ export function ProposalDetail({ proposal, onReview }: ProposalDetailProps) {
{/* Content */} {/* Content */}
<div className="flex-1 overflow-y-auto p-6 space-y-5"> <div className="flex-1 overflow-y-auto p-6 space-y-5">
{/* Source session link */} {/* Source session link */}
<div className="glass-card-static p-4"> <div className="card-flat p-4">
<h4 className="font-label text-[0.625rem] uppercase tracking-wider text-[#5a6170] mb-2">Source Session</h4> <h4 className="font-sans text-xs text-[0.625rem] uppercase tracking-wider text-[#5a6170] mb-2">Source Session</h4>
<Link <Link
to={`/pilot/${proposal.source_session_id}`} to={`/pilot/${proposal.source_session_id}`}
target="_blank" target="_blank"
className="flex items-center gap-2 text-sm text-primary hover:underline" className="flex items-center gap-2 text-sm text-[#22d3ee] hover:underline"
> >
<ExternalLink size={12} /> <ExternalLink size={12} />
View session that generated this proposal View session that generated this proposal
@@ -105,16 +105,16 @@ 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="glass-card-static border-l-2 border-l-amber-500 p-4"> <div className="card-flat border-l-2 border-l-amber-500 p-4">
<h4 className="font-label text-[0.625rem] uppercase tracking-wider text-[#5a6170] mb-2">Proposed Changes</h4> <h4 className="font-sans text-xs text-[0.625rem] uppercase tracking-wider text-[#5a6170] 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-[#e2e5eb]">{diff.diff_description}</p>
)} )}
{diff.new_nodes && diff.new_nodes.length > 0 && ( {diff.new_nodes && diff.new_nodes.length > 0 && (
<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-[#848b9b]">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-emerald-500/5 border border-emerald-500/10 px-3 py-2 text-xs text-[#e2e5eb]">
<span className="text-emerald-400">+ </span> <span className="text-emerald-400">+ </span>
{node.title || node.question || node.description || 'New node'} {node.title || node.question || node.description || 'New node'}
</div> </div>
@@ -126,16 +126,16 @@ export function ProposalDetail({ proposal, onReview }: ProposalDetailProps) {
})()} })()}
{/* Flow data preview */} {/* Flow data preview */}
<div className="glass-card-static p-4"> <div className="card-flat p-4">
<button <button
onClick={() => setShowFlowData(!showFlowData)} onClick={() => setShowFlowData(!showFlowData)}
className="flex items-center gap-1.5 font-label text-[0.625rem] uppercase tracking-wider text-[#5a6170] hover:text-foreground transition-colors" className="flex items-center gap-1.5 font-sans text-xs text-[0.625rem] uppercase tracking-wider text-[#5a6170] hover:text-[#e2e5eb] transition-colors"
> >
{showFlowData ? <ChevronDown size={12} /> : <ChevronRight size={12} />} {showFlowData ? <ChevronDown size={12} /> : <ChevronRight size={12} />}
Flow Data (JSON) Flow Data (JSON)
</button> </button>
{showFlowData && ( {showFlowData && (
<pre className="mt-3 max-h-[400px] overflow-auto rounded-lg bg-card/80 p-3 text-xs text-muted-foreground font-mono"> <pre className="mt-3 max-h-[400px] overflow-auto rounded-lg bg-[#14161d]/80 p-3 text-xs text-[#848b9b] font-mono">
{JSON.stringify(proposal.proposed_flow_data, null, 2)} {JSON.stringify(proposal.proposed_flow_data, null, 2)}
</pre> </pre>
)} )}
@@ -143,8 +143,8 @@ export function ProposalDetail({ proposal, onReview }: ProposalDetailProps) {
{/* Supporting sessions */} {/* Supporting sessions */}
{proposal.supporting_session_ids.length > 1 && ( {proposal.supporting_session_ids.length > 1 && (
<div className="glass-card-static p-4"> <div className="card-flat p-4">
<h4 className="font-label text-[0.625rem] uppercase tracking-wider text-[#5a6170] mb-2"> <h4 className="font-sans text-xs text-[0.625rem] uppercase tracking-wider text-[#5a6170] mb-2">
Supporting Sessions ({proposal.supporting_session_ids.length}) Supporting Sessions ({proposal.supporting_session_ids.length})
</h4> </h4>
<div className="space-y-1"> <div className="space-y-1">
@@ -153,7 +153,7 @@ export function ProposalDetail({ proposal, onReview }: ProposalDetailProps) {
key={sid} key={sid}
to={`/pilot/${sid}`} to={`/pilot/${sid}`}
target="_blank" target="_blank"
className="block text-xs text-primary hover:underline truncate" className="block text-xs text-[#22d3ee] hover:underline truncate"
> >
{sid} {sid}
</Link> </Link>
@@ -164,14 +164,14 @@ export function ProposalDetail({ proposal, onReview }: ProposalDetailProps) {
{/* Review info (for already-reviewed proposals) */} {/* Review info (for already-reviewed proposals) */}
{proposal.reviewed_at && ( {proposal.reviewed_at && (
<div className="glass-card-static p-4"> <div className="card-flat p-4">
<h4 className="font-label text-[0.625rem] uppercase tracking-wider text-[#5a6170] mb-2">Review</h4> <h4 className="font-sans text-xs text-[0.625rem] uppercase tracking-wider text-[#5a6170] mb-2">Review</h4>
<p className="text-sm text-foreground"> <p className="text-sm text-[#e2e5eb]">
<span className="capitalize">{proposal.status}</span> on{' '} <span className="capitalize">{proposal.status}</span> on{' '}
{new Date(proposal.reviewed_at).toLocaleString()} {new Date(proposal.reviewed_at).toLocaleString()}
</p> </p>
{proposal.reviewer_notes && ( {proposal.reviewer_notes && (
<p className="mt-1 text-xs text-muted-foreground">{proposal.reviewer_notes}</p> <p className="mt-1 text-xs text-[#848b9b]">{proposal.reviewer_notes}</p>
)} )}
</div> </div>
)} )}
@@ -180,15 +180,14 @@ export function ProposalDetail({ proposal, onReview }: ProposalDetailProps) {
{/* Review actions bar */} {/* Review actions bar */}
{canReview && ( {canReview && (
<div <div
className="border-t px-5 py-3 space-y-3" className="border-t border-[#1e2130] bg-[#14161d] px-5 py-3 space-y-3"
style={{ borderColor: 'var(--glass-border)', background: 'rgba(16, 17, 20, 0.8)', backdropFilter: 'blur(12px)' }}
> >
{/* Notes input */} {/* Notes input */}
<input <input
value={reviewNotes} value={reviewNotes}
onChange={(e) => setReviewNotes(e.target.value)} onChange={(e) => setReviewNotes(e.target.value)}
placeholder="Reviewer notes (optional)" placeholder="Reviewer notes (optional)"
className="w-full rounded-lg border border-border bg-card px-3 py-2 text-sm text-foreground placeholder:text-muted-foreground focus:border-[rgba(6,182,212,0.3)] focus:outline-none" className="w-full rounded-lg border border-[#1e2130] bg-[#14161d] px-3 py-2 text-sm text-[#e2e5eb] placeholder:text-[#848b9b] focus:border-[rgba(6,182,212,0.3)] focus:outline-none"
/> />
{/* Action buttons */} {/* Action buttons */}
@@ -203,14 +202,14 @@ export function ProposalDetail({ proposal, onReview }: ProposalDetailProps) {
Approve & Publish Approve & Publish
</button> </button>
) : ( ) : (
<span className="text-xs text-muted-foreground italic px-2"> <span className="text-xs text-[#848b9b] italic px-2">
Enhancement proposals require Edit & Publish Enhancement proposals require Edit & Publish
</span> </span>
)} )}
<button <button
onClick={handleEditAndPublish} onClick={handleEditAndPublish}
disabled={isSubmitting} disabled={isSubmitting}
className="flex items-center gap-2 rounded-lg bg-[rgba(255,255,255,0.04)] border border-[rgba(255,255,255,0.06)] px-4 py-2 text-sm font-medium text-foreground hover:border-[rgba(255,255,255,0.12)] disabled:opacity-40 transition-colors" className="flex items-center gap-2 rounded-lg bg-[rgba(255,255,255,0.04)] border border-[rgba(255,255,255,0.06)] px-4 py-2 text-sm font-medium text-[#e2e5eb] hover:border-[rgba(255,255,255,0.12)] disabled:opacity-40 transition-colors"
> >
<Pencil size={14} /> <Pencil size={14} />
Edit & Publish Edit & Publish
@@ -218,7 +217,7 @@ export function ProposalDetail({ proposal, onReview }: ProposalDetailProps) {
<button <button
onClick={() => handleAction('dismiss')} onClick={() => handleAction('dismiss')}
disabled={isSubmitting} disabled={isSubmitting}
className="flex items-center gap-2 rounded-lg bg-[rgba(255,255,255,0.04)] border border-[rgba(255,255,255,0.06)] px-4 py-2 text-sm font-medium text-muted-foreground hover:text-foreground hover:border-[rgba(255,255,255,0.12)] disabled:opacity-40 transition-colors ml-auto" className="flex items-center gap-2 rounded-lg bg-[rgba(255,255,255,0.04)] border border-[rgba(255,255,255,0.06)] px-4 py-2 text-sm font-medium text-[#848b9b] hover:text-[#e2e5eb] hover:border-[rgba(255,255,255,0.12)] disabled:opacity-40 transition-colors ml-auto"
> >
<EyeOff size={14} /> <EyeOff size={14} />
Dismiss Dismiss

View File

@@ -38,12 +38,12 @@ export function SessionBriefing({
const pkg = escalationPackage const pkg = escalationPackage
return ( return (
<div className="glass-card-static border-l-2 border-l-amber-500 p-5 space-y-4"> <div className="card-flat border-l-2 border-l-amber-500 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-[#e2e5eb]">
Escalation from {originalEngineerName || 'another engineer'} Escalation from {originalEngineerName || 'another engineer'}
</h3> </h3>
<p className="mt-1 text-sm text-muted-foreground"> <p className="mt-1 text-sm text-[#848b9b]">
Review the briefing below, then choose how to proceed. Review the briefing below, then choose how to proceed.
</p> </p>
</div> </div>
@@ -51,15 +51,15 @@ export function SessionBriefing({
{/* Problem */} {/* Problem */}
{pkg.problem_summary && ( {pkg.problem_summary && (
<div> <div>
<h4 className="font-label text-[0.625rem] uppercase tracking-wider text-[#5a6170] mb-1">Problem</h4> <h4 className="font-sans text-xs text-[0.625rem] uppercase tracking-wider text-[#5a6170] mb-1">Problem</h4>
<p className="text-sm text-foreground">{pkg.problem_summary}</p> <p className="text-sm text-[#e2e5eb]">{pkg.problem_summary}</p>
</div> </div>
)} )}
{/* Escalation reason */} {/* Escalation reason */}
{pkg.escalation_reason && ( {pkg.escalation_reason && (
<div> <div>
<h4 className="font-label text-[0.625rem] uppercase tracking-wider text-[#5a6170] mb-1">Why escalated</h4> <h4 className="font-sans text-xs text-[0.625rem] uppercase tracking-wider text-[#5a6170] mb-1">Why escalated</h4>
<p className="text-sm text-amber-400">{pkg.escalation_reason}</p> <p className="text-sm text-amber-400">{pkg.escalation_reason}</p>
</div> </div>
)} )}
@@ -69,7 +69,7 @@ export function SessionBriefing({
<div> <div>
<button <button
onClick={() => setShowSteps(!showSteps)} onClick={() => setShowSteps(!showSteps)}
className="flex items-center gap-1.5 font-label text-[0.625rem] uppercase tracking-wider text-[#5a6170] hover:text-foreground transition-colors" className="flex items-center gap-1.5 font-sans text-xs text-[0.625rem] uppercase tracking-wider text-[#5a6170] hover:text-[#e2e5eb] transition-colors"
> >
{showSteps ? <ChevronDown size={12} /> : <ChevronRight size={12} />} {showSteps ? <ChevronDown size={12} /> : <ChevronRight size={12} />}
Steps taken ({pkg.steps_tried.length}) Steps taken ({pkg.steps_tried.length})
@@ -77,10 +77,10 @@ export function SessionBriefing({
{showSteps && ( {showSteps && (
<div className="mt-2 space-y-1.5"> <div className="mt-2 space-y-1.5">
{pkg.steps_tried.map((step, i) => ( {pkg.steps_tried.map((step, i) => (
<div key={i} className="rounded-lg bg-card/50 px-3 py-2 text-xs"> <div key={i} className="rounded-lg bg-[#14161d]/50 px-3 py-2 text-xs">
<p className="text-foreground">{i + 1}. {step.description}</p> <p className="text-[#e2e5eb]">{i + 1}. {step.description}</p>
{step.response && ( {step.response && (
<p className="mt-0.5 text-primary"> {step.response}</p> <p className="mt-0.5 text-[#22d3ee]"> {step.response}</p>
)} )}
</div> </div>
))} ))}
@@ -92,11 +92,11 @@ export function SessionBriefing({
{/* Remaining hypotheses */} {/* Remaining hypotheses */}
{pkg.remaining_hypotheses && pkg.remaining_hypotheses.length > 0 && ( {pkg.remaining_hypotheses && pkg.remaining_hypotheses.length > 0 && (
<div> <div>
<h4 className="font-label text-[0.625rem] uppercase tracking-wider text-[#5a6170] mb-1">Remaining hypotheses</h4> <h4 className="font-sans text-xs text-[0.625rem] uppercase tracking-wider text-[#5a6170] mb-1">Remaining hypotheses</h4>
<ul className="space-y-1"> <ul className="space-y-1">
{pkg.remaining_hypotheses.map((h, i) => ( {pkg.remaining_hypotheses.map((h, i) => (
<li key={i} className="text-sm text-foreground flex items-start gap-2"> <li key={i} className="text-sm text-[#e2e5eb] flex items-start gap-2">
<span className="text-primary mt-0.5"></span> <span className="text-[#22d3ee] mt-0.5"></span>
{h} {h}
</li> </li>
))} ))}
@@ -107,10 +107,10 @@ export function SessionBriefing({
{/* Suggested next steps */} {/* Suggested next steps */}
{pkg.suggested_next_steps && pkg.suggested_next_steps.length > 0 && ( {pkg.suggested_next_steps && pkg.suggested_next_steps.length > 0 && (
<div> <div>
<h4 className="font-label text-[0.625rem] uppercase tracking-wider text-[#5a6170] mb-1">Suggested next steps</h4> <h4 className="font-sans text-xs text-[0.625rem] uppercase tracking-wider text-[#5a6170] mb-1">Suggested next steps</h4>
<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-[#e2e5eb] flex items-start gap-2">
<span className="text-emerald-400 mt-0.5"></span> <span className="text-emerald-400 mt-0.5"></span>
{s} {s}
</li> </li>
@@ -125,7 +125,7 @@ export function SessionBriefing({
<button <button
onClick={onContinue} onClick={onContinue}
disabled={isProcessing} disabled={isProcessing}
className="flex-1 flex items-center justify-center gap-2 rounded-lg bg-gradient-brand px-4 py-2.5 text-sm font-semibold text-[#101114] shadow-lg shadow-primary/20 hover:opacity-90 active:scale-[0.97] disabled:opacity-40 transition-all" className="flex-1 flex items-center justify-center gap-2 rounded-lg bg-[#22d3ee] text-white px-4 py-2.5 text-sm font-semibold hover:brightness-110 active:scale-[0.98] disabled:opacity-40 transition-all"
> >
<ArrowRight size={14} /> <ArrowRight size={14} />
Continue Where They Left Off Continue Where They Left Off
@@ -133,7 +133,7 @@ export function SessionBriefing({
<button <button
onClick={() => setFreshMode(true)} onClick={() => setFreshMode(true)}
disabled={isProcessing} disabled={isProcessing}
className="flex-1 flex items-center justify-center gap-2 rounded-lg bg-[rgba(255,255,255,0.04)] border border-[rgba(255,255,255,0.06)] px-4 py-2.5 text-sm font-medium text-foreground hover:border-[rgba(255,255,255,0.12)] disabled:opacity-40 transition-colors" className="flex-1 flex items-center justify-center gap-2 rounded-lg bg-[rgba(255,255,255,0.04)] border border-[rgba(255,255,255,0.06)] px-4 py-2.5 text-sm font-medium text-[#e2e5eb] hover:border-[rgba(255,255,255,0.12)] disabled:opacity-40 transition-colors"
> >
<MessageSquare size={14} /> <MessageSquare size={14} />
Start Fresh With Context Start Fresh With Context
@@ -145,7 +145,7 @@ export function SessionBriefing({
value={freshContext} value={freshContext}
onChange={(e) => setFreshContext(e.target.value)} onChange={(e) => setFreshContext(e.target.value)}
placeholder="What additional information do you have, or what would you like to investigate first?" placeholder="What additional information do you have, or what would you like to investigate first?"
className="w-full rounded-lg border border-border bg-card px-4 py-3 text-sm text-foreground placeholder:text-muted-foreground focus:border-[rgba(6,182,212,0.3)] focus:outline-none resize-none" className="w-full rounded-lg border border-[#1e2130] bg-[#14161d] px-4 py-3 text-sm text-[#e2e5eb] placeholder:text-[#848b9b] focus:border-[rgba(6,182,212,0.3)] focus:outline-none resize-none"
rows={3} rows={3}
autoFocus autoFocus
/> />
@@ -153,14 +153,14 @@ export function SessionBriefing({
<button <button
onClick={() => setFreshMode(false)} onClick={() => setFreshMode(false)}
disabled={isProcessing} disabled={isProcessing}
className="rounded-lg bg-[rgba(255,255,255,0.04)] border border-[rgba(255,255,255,0.06)] px-4 py-2 text-sm font-medium text-foreground hover:border-[rgba(255,255,255,0.12)] disabled:opacity-40 transition-colors" className="rounded-lg bg-[rgba(255,255,255,0.04)] border border-[rgba(255,255,255,0.06)] px-4 py-2 text-sm font-medium text-[#e2e5eb] hover:border-[rgba(255,255,255,0.12)] disabled:opacity-40 transition-colors"
> >
Back Back
</button> </button>
<button <button
onClick={() => freshContext.trim() && onFresh(freshContext.trim())} onClick={() => freshContext.trim() && onFresh(freshContext.trim())}
disabled={!freshContext.trim() || isProcessing} disabled={!freshContext.trim() || isProcessing}
className="flex-1 flex items-center justify-center gap-2 rounded-lg bg-gradient-brand px-4 py-2 text-sm font-semibold text-[#101114] shadow-lg shadow-primary/20 hover:opacity-90 active:scale-[0.97] disabled:opacity-40 transition-all" className="flex-1 flex items-center justify-center gap-2 rounded-lg bg-[#22d3ee] text-white px-4 py-2 text-sm font-semibold hover:brightness-110 active:scale-[0.98] disabled:opacity-40 transition-all"
> >
<ArrowRight size={14} /> <ArrowRight size={14} />
Start Diagnosis Start Diagnosis

View File

@@ -107,27 +107,27 @@ export function SessionDocView({
)} )}
{/* Header */} {/* Header */}
<div className="glass-card-static p-3 sm:p-4 lg:p-5"> <div className="card-flat p-3 sm:p-4 lg:p-5">
<div className="flex items-start gap-3"> <div className="flex items-start gap-3">
<span className="flex h-8 w-8 shrink-0 items-center justify-center rounded-lg bg-primary/10 text-primary"> <span className="flex h-8 w-8 shrink-0 items-center justify-center rounded-lg bg-[rgba(34,211,238,0.10)] text-[#22d3ee]">
<FileText size={16} /> <FileText size={16} />
</span> </span>
<div className="flex-1"> <div className="flex-1">
<h3 className="font-heading text-lg font-semibold text-foreground">Session Documentation</h3> <h3 className="font-heading text-lg font-semibold text-[#e2e5eb]">Session Documentation</h3>
<p className="mt-1 text-sm text-muted-foreground">{documentation.problem_summary}</p> <p className="mt-1 text-sm text-[#848b9b]">{documentation.problem_summary}</p>
<div className="mt-2 flex items-center gap-3 flex-wrap"> <div className="mt-2 flex items-center gap-3 flex-wrap">
{documentation.problem_domain && ( {documentation.problem_domain && (
<span className="font-label rounded-md bg-primary/10 px-2 py-0.5 text-[0.625rem] uppercase tracking-wider text-primary"> <span className="font-sans text-xs rounded-md bg-[rgba(34,211,238,0.10)] px-2 py-0.5 text-[0.625rem] uppercase tracking-wider text-[#22d3ee]">
{documentation.problem_domain} {documentation.problem_domain}
</span> </span>
)} )}
{documentation.duration_display && ( {documentation.duration_display && (
<span className="flex items-center gap-1 text-xs text-muted-foreground"> <span className="flex items-center gap-1 text-xs text-[#848b9b]">
<Clock size={12} /> <Clock size={12} />
{documentation.duration_display} {documentation.duration_display}
</span> </span>
)} )}
<span className="text-xs text-muted-foreground"> <span className="text-xs text-[#848b9b]">
{documentation.total_steps} steps {documentation.total_steps} steps
</span> </span>
</div> </div>
@@ -137,49 +137,49 @@ export function SessionDocView({
{/* Outcome */} {/* Outcome */}
{(documentation.resolution_summary || documentation.escalation_reason) && ( {(documentation.resolution_summary || documentation.escalation_reason) && (
<div className={`glass-card-static 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-emerald-500' : 'border-l-amber-500'}`}>
<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-emerald-400" />
) : ( ) : (
<ArrowUpRight size={14} className="text-amber-400" /> <ArrowUpRight size={14} className="text-amber-400" />
)} )}
<span className="font-label text-[0.625rem] uppercase tracking-wider text-muted-foreground"> <span className="font-sans text-xs text-[0.625rem] uppercase tracking-wider text-[#848b9b]">
{documentation.resolution_summary ? 'Resolved' : 'Escalated'} {documentation.resolution_summary ? 'Resolved' : 'Escalated'}
</span> </span>
</div> </div>
<p className="text-sm text-foreground"> <p className="text-sm text-[#e2e5eb]">
{documentation.resolution_summary || documentation.escalation_reason} {documentation.resolution_summary || documentation.escalation_reason}
</p> </p>
</div> </div>
)} )}
{/* Intake summary */} {/* Intake summary */}
<div className="glass-card-static p-3 sm:p-4"> <div className="card-flat p-3 sm:p-4">
<h4 className="font-label text-[0.625rem] uppercase tracking-wider text-muted-foreground mb-2"> <h4 className="font-sans text-xs text-[0.625rem] uppercase tracking-wider text-[#848b9b] mb-2">
Original intake Original intake
</h4> </h4>
<p className="text-sm text-foreground whitespace-pre-wrap">{documentation.intake_summary}</p> <p className="text-sm text-[#e2e5eb] whitespace-pre-wrap">{documentation.intake_summary}</p>
</div> </div>
{/* Diagnostic steps */} {/* Diagnostic steps */}
<div className="space-y-2"> <div className="space-y-2">
<h4 className="font-label text-[0.625rem] uppercase tracking-wider text-muted-foreground px-1"> <h4 className="font-sans text-xs text-[0.625rem] uppercase tracking-wider text-[#848b9b] px-1">
Diagnostic trail Diagnostic trail
</h4> </h4>
{documentation.diagnostic_steps.map((step) => ( {documentation.diagnostic_steps.map((step) => (
<div key={step.step_number} className="glass-card-static p-3 sm:p-4"> <div key={step.step_number} className="card-flat p-3 sm:p-4">
<div className="flex items-start gap-3"> <div className="flex items-start gap-3">
<span className="font-label flex h-5 w-5 shrink-0 items-center justify-center rounded-full bg-card text-[0.625rem] text-muted-foreground border border-border"> <span className="font-sans text-xs flex h-5 w-5 shrink-0 items-center justify-center rounded-full bg-[#14161d] text-[0.625rem] text-[#848b9b] border border-[#1e2130]">
{step.step_number} {step.step_number}
</span> </span>
<div className="flex-1"> <div className="flex-1">
<p className="text-sm text-foreground">{step.description}</p> <p className="text-sm text-[#e2e5eb]">{step.description}</p>
{step.engineer_response && ( {step.engineer_response && (
<p className="mt-1 text-xs text-primary"> {step.engineer_response}</p> <p className="mt-1 text-xs text-[#22d3ee]"> {step.engineer_response}</p>
)} )}
{step.outcome && ( {step.outcome && (
<p className="mt-1 text-xs text-muted-foreground">Outcome: {step.outcome}</p> <p className="mt-1 text-xs text-[#848b9b]">Outcome: {step.outcome}</p>
)} )}
</div> </div>
</div> </div>
@@ -189,8 +189,8 @@ export function SessionDocView({
{/* Rating */} {/* Rating */}
{onRate && ( {onRate && (
<div className="glass-card-static p-3 sm:p-4 text-center"> <div className="card-flat p-3 sm:p-4 text-center">
<p className="text-sm text-muted-foreground mb-2">How helpful was this session?</p> <p className="text-sm text-[#848b9b] mb-2">How helpful was this session?</p>
<div className="flex items-center justify-center gap-1"> <div className="flex items-center justify-center gap-1">
{[1, 2, 3, 4, 5].map((star) => ( {[1, 2, 3, 4, 5].map((star) => (
<button <button
@@ -203,7 +203,7 @@ export function SessionDocView({
className={ className={
(currentRating ?? 0) >= star (currentRating ?? 0) >= star
? 'fill-amber-400 text-amber-400' ? 'fill-amber-400 text-amber-400'
: 'text-muted-foreground hover:text-amber-400' : 'text-[#848b9b] hover:text-amber-400'
} }
/> />
</button> </button>

View File

@@ -36,7 +36,7 @@ export function SessionTicketCard({ ticketId, ticketData, siteUrl }: SessionTick
return ( return (
<div className="rounded-xl border border-primary/20 bg-primary/5 p-3 space-y-2"> <div className="rounded-xl border border-primary/20 bg-primary/5 p-3 space-y-2">
<div className="flex items-start justify-between"> <div className="flex items-start justify-between">
<h4 className="font-label text-[0.625rem] uppercase tracking-wider text-[#5a6170]"> <h4 className="font-sans text-xs text-[0.625rem] uppercase tracking-wider text-[#5a6170]">
Linked Ticket Linked Ticket
</h4> </h4>
{ticketUrl && ( {ticketUrl && (
@@ -44,7 +44,7 @@ export function SessionTicketCard({ ticketId, ticketData, siteUrl }: SessionTick
href={ticketUrl} href={ticketUrl}
target="_blank" target="_blank"
rel="noopener noreferrer" rel="noopener noreferrer"
className="text-muted-foreground hover:text-primary transition-colors" className="text-[#848b9b] hover:text-[#22d3ee] transition-colors"
title="Open in ConnectWise" title="Open in ConnectWise"
> >
<ExternalLink size={12} /> <ExternalLink size={12} />
@@ -52,14 +52,14 @@ export function SessionTicketCard({ ticketId, ticketData, siteUrl }: SessionTick
)} )}
</div> </div>
<p className="text-sm font-semibold text-foreground"> <p className="text-sm font-semibold text-[#e2e5eb]">
<span className="text-primary">#{ticketId}</span> <span className="text-[#22d3ee]">#{ticketId}</span>
{ticket?.summary && ( {ticket?.summary && (
<span> {ticket.summary}</span> <span> {ticket.summary}</span>
)} )}
</p> </p>
<div className="flex flex-wrap items-center gap-x-2 gap-y-1 text-xs text-muted-foreground"> <div className="flex flex-wrap items-center gap-x-2 gap-y-1 text-xs text-[#848b9b]">
{company?.name && ( {company?.name && (
<span className="flex items-center gap-1"> <span className="flex items-center gap-1">
<Building2 size={10} /> <Building2 size={10} />
@@ -81,13 +81,13 @@ export function SessionTicketCard({ ticketId, ticketData, siteUrl }: SessionTick
</div> </div>
{configs && configs.length > 0 && ( {configs && configs.length > 0 && (
<div className="border-t border-border/50 pt-2 mt-2"> <div className="border-t border-[#1e2130]/50 pt-2 mt-2">
<p className="font-label text-[0.5625rem] uppercase tracking-wider text-[#5a6170] mb-1"> <p className="font-sans text-xs text-[0.5625rem] uppercase tracking-wider text-[#5a6170] mb-1">
Devices Devices
</p> </p>
<div className="space-y-0.5"> <div className="space-y-0.5">
{configs.slice(0, 3).map((cfg, i) => ( {configs.slice(0, 3).map((cfg, i) => (
<div key={i} className="flex items-center gap-1.5 text-xs text-muted-foreground"> <div key={i} className="flex items-center gap-1.5 text-xs text-[#848b9b]">
<Cpu size={10} /> <Cpu size={10} />
<span>{cfg.device_identifier}</span> <span>{cfg.device_identifier}</span>
{cfg.type && <span className="text-[#5a6170]">({cfg.type})</span>} {cfg.type && <span className="text-[#5a6170]">({cfg.type})</span>}

View File

@@ -35,8 +35,8 @@ export function SimilarSessions({ sessionId }: SimilarSessionsProps) {
if (loading) { if (loading) {
return ( return (
<div className="flex items-center gap-1.5 py-1"> <div className="flex items-center gap-1.5 py-1">
<Loader2 size={10} className="animate-spin text-muted-foreground" /> <Loader2 size={10} className="animate-spin text-[#848b9b]" />
<span className="text-[0.625rem] text-muted-foreground font-label">Loading similar sessions</span> <span className="text-[0.625rem] text-[#848b9b] font-sans text-xs">Loading similar sessions</span>
</div> </div>
) )
} }
@@ -47,42 +47,42 @@ export function SimilarSessions({ sessionId }: SimilarSessionsProps) {
return ( return (
<div className="space-y-2"> <div className="space-y-2">
<h4 className="font-label text-[0.625rem] uppercase tracking-[0.1em] text-muted-foreground"> <h4 className="font-sans text-xs text-[0.625rem] uppercase tracking-[0.1em] text-[#848b9b]">
Similar Past Sessions Similar Past Sessions
</h4> </h4>
{sessions.map((session) => ( {sessions.map((session) => (
<Link <Link
key={session.id} key={session.id}
to={`/pilot/${session.id}`} to={`/pilot/${session.id}`}
className="glass-card p-3 block hover:border-[rgba(255,255,255,0.12)] transition-all" className="card-interactive p-3 block hover:border-[rgba(255,255,255,0.12)] transition-all"
> >
<div className="flex items-start justify-between gap-2"> <div className="flex items-start justify-between gap-2">
<p className="text-xs text-foreground line-clamp-2"> <p className="text-xs text-[#e2e5eb] line-clamp-2">
{session.problem_summary || 'Untitled session'} {session.problem_summary || 'Untitled session'}
</p> </p>
<span className="text-[0.625rem] font-label text-primary shrink-0"> <span className="text-[0.625rem] font-sans text-xs text-[#22d3ee] shrink-0">
{Math.round(session.similarity * 100)}% {Math.round(session.similarity * 100)}%
</span> </span>
</div> </div>
{session.resolution_summary && ( {session.resolution_summary && (
<p className="text-[0.625rem] text-muted-foreground mt-1 line-clamp-1"> <p className="text-[0.625rem] text-[#848b9b] mt-1 line-clamp-1">
{session.resolution_summary} {session.resolution_summary}
</p> </p>
)} )}
<div className="flex items-center gap-2 mt-1.5"> <div className="flex items-center gap-2 mt-1.5">
{session.problem_domain && ( {session.problem_domain && (
<span className="text-[0.5rem] font-label uppercase tracking-wider text-muted-foreground/70"> <span className="text-[0.5rem] font-sans text-xs uppercase tracking-wider text-[#848b9b]/70">
{session.problem_domain} {session.problem_domain}
</span> </span>
)} )}
<span <span
className={cn( className={cn(
'text-[0.5rem] font-label uppercase', 'text-[0.5rem] font-sans text-xs uppercase',
session.status === 'resolved' session.status === 'resolved'
? 'text-emerald-400' ? 'text-emerald-400'
: session.status === 'escalated' : session.status === 'escalated'
? 'text-amber-400' ? 'text-amber-400'
: 'text-muted-foreground' : 'text-[#848b9b]'
)} )}
> >
{session.status} {session.status}