- Replace all rgba(6,182,212,...) cyan focus borders and accents with rgba(249,115,22,...) ember orange across 21+ component files - Remove all var(--glass-border) references (undefined variable) with var(--color-border-default) across 24 files - Remove deprecated blur orbs and glass-morphism effects from SurveyPage, SurveyThankYouPage, and LoginPage - Migrate landing.css from hardcoded hex to CSS custom properties (~97 replacements for single-source theming) - Fix off-palette grays in FlowPilotAnalyticsPage chart styling (#8891a0 → #848b9b, #18191f → var(--color-bg-card)) - Update stale comments: "cyan brand" → "accent brand" in GlowEdge, "gradient cyan square" → "gradient orange square" in BrandLogo - Rename glow-cyan SVG filter ID to glow-accent - Fix category color comment: "cyan" → "deep orange" Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
120 lines
4.1 KiB
TypeScript
120 lines
4.1 KiB
TypeScript
import { useState, useEffect } from 'react'
|
|
import { Save, Loader2, Clock } from 'lucide-react'
|
|
import { assistantChatApi } from '@/api/assistantChat'
|
|
|
|
export default function ChatRetentionSettingsPage() {
|
|
const [loading, setLoading] = useState(true)
|
|
const [saving, setSaving] = useState(false)
|
|
const [retentionDays, setRetentionDays] = useState('')
|
|
const [maxCount, setMaxCount] = useState('')
|
|
const [success, setSuccess] = useState(false)
|
|
|
|
useEffect(() => {
|
|
loadSettings()
|
|
}, [])
|
|
|
|
const loadSettings = async () => {
|
|
try {
|
|
const data = await assistantChatApi.getRetentionSettings()
|
|
setRetentionDays(data.chat_retention_days?.toString() ?? '90')
|
|
setMaxCount(data.chat_retention_max_count?.toString() ?? '100')
|
|
} catch {
|
|
// silently handle
|
|
} finally {
|
|
setLoading(false)
|
|
}
|
|
}
|
|
|
|
const handleSave = async () => {
|
|
setSaving(true)
|
|
setSuccess(false)
|
|
try {
|
|
await assistantChatApi.updateRetentionSettings({
|
|
chat_retention_days: parseInt(retentionDays) || null,
|
|
chat_retention_max_count: parseInt(maxCount) || null,
|
|
})
|
|
setSuccess(true)
|
|
setTimeout(() => setSuccess(false), 3000)
|
|
} catch {
|
|
// silently handle
|
|
} finally {
|
|
setSaving(false)
|
|
}
|
|
}
|
|
|
|
if (loading) {
|
|
return (
|
|
<div className="flex items-center justify-center py-20">
|
|
<Loader2 className="animate-spin text-primary" size={24} />
|
|
</div>
|
|
)
|
|
}
|
|
|
|
return (
|
|
<div className="max-w-2xl mx-auto py-8 px-6">
|
|
<div className="flex items-center gap-3 mb-6">
|
|
<Clock size={20} className="text-primary" />
|
|
<h1 className="text-xl font-heading font-bold text-foreground">Chat Retention</h1>
|
|
</div>
|
|
|
|
<div className="card-flat rounded-2xl p-6 space-y-6">
|
|
<p className="text-sm text-muted-foreground">
|
|
Configure how long AI assistant conversations are retained. Pinned chats are never automatically deleted.
|
|
</p>
|
|
|
|
<div className="space-y-4">
|
|
<div>
|
|
<label className="font-sans text-xs text-[0.625rem] uppercase tracking-widest text-muted-foreground block mb-1.5">
|
|
Retention Period (days)
|
|
</label>
|
|
<input
|
|
type="number"
|
|
value={retentionDays}
|
|
onChange={e => setRetentionDays(e.target.value)}
|
|
min={1}
|
|
max={365}
|
|
className="w-full rounded-xl border bg-card text-foreground text-sm px-4 py-2.5 focus:outline-hidden focus:border-primary/30"
|
|
style={{ borderColor: 'var(--color-border-default)' }}
|
|
/>
|
|
<p className="text-xs text-muted-foreground mt-1">
|
|
Chats older than this will be automatically deleted (1-365 days)
|
|
</p>
|
|
</div>
|
|
|
|
<div>
|
|
<label className="font-sans text-xs text-[0.625rem] uppercase tracking-widest text-muted-foreground block mb-1.5">
|
|
Max Conversations
|
|
</label>
|
|
<input
|
|
type="number"
|
|
value={maxCount}
|
|
onChange={e => setMaxCount(e.target.value)}
|
|
min={10}
|
|
max={10000}
|
|
className="w-full rounded-xl border bg-card text-foreground text-sm px-4 py-2.5 focus:outline-hidden focus:border-primary/30"
|
|
style={{ borderColor: 'var(--color-border-default)' }}
|
|
/>
|
|
<p className="text-xs text-muted-foreground mt-1">
|
|
When this limit is exceeded, oldest unpinned chats are deleted
|
|
</p>
|
|
</div>
|
|
</div>
|
|
|
|
<div className="flex items-center gap-3 pt-2">
|
|
<button
|
|
onClick={handleSave}
|
|
disabled={saving}
|
|
className="bg-primary text-white font-semibold text-sm rounded-lg px-5 py-2.5 hover:brightness-110 active:scale-[0.98] transition-all disabled:opacity-40 flex items-center gap-2"
|
|
>
|
|
{saving ? <Loader2 size={14} className="animate-spin" /> : <Save size={14} />}
|
|
Save Settings
|
|
</button>
|
|
{success && (
|
|
<span className="text-sm text-emerald-400">Settings saved</span>
|
|
)}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
)
|
|
}
|