Component props from DataManagementProps.
The rendered data management tab.
export function DataManagementTab({
cachesToClear,
isClearing,
isCacheCleared,
selectedBackupFile,
backupValidationError,
isDebugEnabled,
isStorageDebuggerEnabled,
isLogViewerEnabled,
isLogRedactionEnabled,
isStateInspectorEnabled,
isIpcViewerEnabled,
isEventLoggerEnabled,
isConfidenceTestExporterEnabled,
isPerformanceMonitorEnabled,
searchQuery,
highlightedSectionId,
scheduleConfig,
nextScheduledBackup,
lastScheduledBackup,
isTriggeringBackup,
isRestoringBackup,
onCachesToClearChange,
onClearCaches,
onRestoreBackup,
onRestoreBackupFile,
onFileSelect,
onScheduleConfigChange,
onTriggerBackup,
onToggleDebug,
onStorageDebuggerChange,
onLogViewerChange,
onLogRedactionChange,
onStateInspectorChange,
onIpcViewerChange,
onEventLoggerChange,
onConfidenceTestExporterChange,
onPerformanceMonitorChange,
collapsedSections,
onToggleSection,
}: Readonly<DataManagementProps>) {
const pillBaseClass =
"rounded-full px-3 py-1 text-[11px] font-medium uppercase tracking-wide";
const formatTimestamp = (timestamp: number | null) => {
if (!timestamp) {
return "Not scheduled";
}
const date = new Date(timestamp);
if (Number.isNaN(date.getTime())) {
return "Not scheduled";
}
return date.toLocaleString(undefined, {
month: "short",
day: "numeric",
hour: "2-digit",
minute: "2-digit",
});
};
const selectedCacheCount =
Object.values(cachesToClear).filter(Boolean).length;
const cacheStatusLabel = getCacheStatusLabel(
isClearing,
isCacheCleared,
selectedCacheCount,
);
const cacheBadgeClass = getCacheBadgeClass(
pillBaseClass,
isClearing,
isCacheCleared,
selectedCacheCount,
);
const cacheDescription = getCacheDescription(selectedCacheCount);
const cacheCaption = getCacheCaption(isClearing, isCacheCleared);
const nextBackupDisplay = formatTimestamp(
nextScheduledBackup ?? scheduleConfig.nextBackupTimestamp ?? null,
);
const lastBackupDisplay = formatTimestamp(
lastScheduledBackup ?? scheduleConfig.lastBackupTimestamp ?? null,
);
const backupBadgeLabel = getBackupBadgeLabel(
backupValidationError,
scheduleConfig.enabled,
);
const backupBadgeClass = getBackupBadgeClass(
pillBaseClass,
backupValidationError,
scheduleConfig.enabled,
);
const backupDescription = getBackupDescription(
backupValidationError,
scheduleConfig.enabled,
nextBackupDisplay,
);
const backupCaption = `Last backup ${lastBackupDisplay}.`;
const debugBadgeLabel = isDebugEnabled ? "Enabled" : "Disabled";
const debugBadgeClass = getDebugBadgeClass(pillBaseClass, isDebugEnabled);
const debugMenuToolFlags = [
isStorageDebuggerEnabled,
isLogViewerEnabled,
isStateInspectorEnabled,
isIpcViewerEnabled,
isEventLoggerEnabled,
isPerformanceMonitorEnabled,
];
const activeMenuToolsCount = isDebugEnabled
? debugMenuToolFlags.filter(Boolean).length
: 0;
const activeDebugTools = activeMenuToolsCount;
const debugDescription = isDebugEnabled
? "Developer instrumentation is visible this session."
: "Developer instrumentation is hidden until enabled.";
const debugCaption = getDebugToolsDescription(activeDebugTools);
const quickStats: QuickStat[] = [
{
id: "cache",
title: "Cache readiness",
description: cacheDescription,
caption: cacheCaption,
icon: HardDrive,
iconWrapperClass:
"bg-cyan-500/15 text-cyan-600 dark:bg-cyan-500/20 dark:text-cyan-200",
accentClass: "from-cyan-500/70 via-sky-500/70 to-teal-400/70",
badge: { label: cacheStatusLabel, className: cacheBadgeClass },
},
{
id: "backup",
title: "Backup posture",
description: backupDescription,
caption: backupCaption,
icon: Clock3,
iconWrapperClass:
"bg-purple-500/15 text-purple-600 dark:bg-purple-500/20 dark:text-purple-200",
accentClass: "from-purple-500/70 via-violet-500/70 to-sky-500/70",
badge: { label: backupBadgeLabel, className: backupBadgeClass },
},
{
id: "debug",
title: "Debug visibility",
description: debugDescription,
caption: debugCaption,
icon: ShieldCheck,
iconWrapperClass:
"bg-emerald-500/15 text-emerald-600 dark:bg-emerald-500/20 dark:text-emerald-200",
accentClass: "from-emerald-500/70 via-teal-500/70 to-green-400/70",
badge: { label: debugBadgeLabel, className: debugBadgeClass },
},
];
return (
<motion.div
variants={itemVariants}
initial="hidden"
animate="show"
className="space-y-8"
>
<motion.div
initial={{ opacity: 0, y: 14 }}
animate={{ opacity: 1, y: 0 }}
transition={{ duration: 0.45, delay: 0.1 }}
className="bg-linear-to-br from-cyan-500/12 relative overflow-hidden rounded-3xl border border-cyan-500/20 via-cyan-500/5 to-transparent p-6 shadow-[0_35px_110px_-70px_rgba(10,54,79,0.45)] dark:border-cyan-500/25 dark:from-cyan-500/20 dark:via-slate-950/70 dark:to-slate-950/40"
>
<div className="absolute -left-24 -top-24 h-48 w-48 rounded-full bg-cyan-500/10 blur-3xl" />
<div className="relative flex items-start gap-4">
<div className="flex h-12 w-12 items-center justify-center rounded-2xl bg-white/85 text-cyan-600 shadow-md backdrop-blur dark:bg-white/10 dark:text-cyan-200">
<Database className="h-5 w-5" />
</div>
<div className="space-y-1">
<h2 className="text-lg font-semibold text-slate-900 dark:text-white">
Data controls
</h2>
<p className="max-w-2xl text-sm text-slate-600 dark:text-slate-300">
Manage cached results, schedule backups, and enable debugging
tooling to keep Kenmei running smoothly across sessions.
</p>
</div>
</div>
</motion.div>
<motion.div
initial={{ opacity: 0, y: 12 }}
animate={{ opacity: 1, y: 0 }}
transition={{ duration: 0.45, delay: 0.18 }}
className="grid gap-4 md:grid-cols-2 xl:grid-cols-3"
>
{quickStats.map((stat) => (
<div
key={stat.id}
className="relative flex items-start gap-4 overflow-hidden rounded-2xl border border-slate-200/70 bg-white/85 p-5 shadow-[0_28px_100px_-70px_rgba(15,23,42,0.38)] dark:border-white/10 dark:bg-slate-950/50 dark:shadow-[0_30px_110px_-75px_rgba(15,23,42,0.85)]"
>
<span
aria-hidden="true"
className={cn(
"bg-linear-to-r pointer-events-none absolute inset-x-0 top-0 h-0.5 opacity-90",
stat.accentClass,
)}
/>
<div
className={cn(
"flex h-11 w-11 shrink-0 items-center justify-center rounded-2xl",
stat.iconWrapperClass,
)}
>
<stat.icon className="h-5 w-5" />
</div>
<div className="flex-1 space-y-2">
<div className="flex flex-wrap items-center gap-2">
<p className="text-sm font-semibold text-slate-900 dark:text-slate-50">
{stat.title}
</p>
{stat.badge ? (
<span className={stat.badge.className}>
{stat.badge.label}
</span>
) : null}
</div>
<p className="text-xs leading-relaxed text-slate-600 dark:text-slate-300">
{stat.description}
</p>
{stat.caption ? (
<p className="text-[11px] font-semibold uppercase tracking-wide text-slate-400 dark:text-slate-500">
{stat.caption}
</p>
) : null}
</div>
</div>
))}
</motion.div>
<SettingsSectionShell
id="data-management"
isCollapsible={true}
isCollapsed={collapsedSections["data-management"] ?? false}
onCollapsedChange={() => onToggleSection("data-management")}
icon={Database}
title="Cache & local data"
description="Control cached data stored locally by the application."
accent="from-cyan-500/20 via-sky-500/15 to-transparent"
contentClassName="space-y-6"
className={cn(
"transition-shadow duration-300 hover:shadow-[0_32px_120px_-80px_rgba(15,23,42,0.5)]",
highlightedSectionId === "data-cache" &&
"ring-2 ring-cyan-500 ring-offset-2 ring-offset-white dark:ring-cyan-400 dark:ring-offset-slate-950",
)}
>
<CacheManagementSection
cachesToClear={cachesToClear}
isClearing={isClearing}
isCacheCleared={isCacheCleared}
searchQuery={searchQuery}
highlightedSectionId={highlightedSectionId}
onCachesToClearChange={onCachesToClearChange}
onClearCaches={onClearCaches}
/>
</SettingsSectionShell>
<SettingsSectionShell
id="backup-restore"
isCollapsible={true}
isCollapsed={collapsedSections["backup-restore"] ?? false}
onCollapsedChange={() => onToggleSection("backup-restore")}
icon={Download}
title="Backup & restore"
description="Export and import application data for safe keeping or migration."
accent="from-violet-500/20 via-purple-500/15 to-transparent"
contentClassName="space-y-6"
className={cn(
"transition-shadow duration-300 hover:shadow-[0_32px_120px_-80px_rgba(15,23,42,0.5)]",
highlightedSectionId === "data-backup" &&
"ring-2 ring-purple-500 ring-offset-2 ring-offset-white dark:ring-purple-400 dark:ring-offset-slate-950",
)}
>
{backupValidationError ? (
<Alert className="rounded-2xl border border-rose-400/40 bg-rose-500/10 text-rose-900 dark:border-rose-500/25 dark:bg-rose-500/15 dark:text-rose-100">
<div className="flex items-start gap-3">
<AlertTriangle className="mt-0.5 h-4 w-4" />
<div>
<AlertTitle className="text-sm font-semibold text-rose-900 dark:text-rose-50">
Backup file needs attention
</AlertTitle>
<AlertDescription className="mt-1 text-xs leading-relaxed">
{backupValidationError}
</AlertDescription>
</div>
</div>
</Alert>
) : null}
<BackupRestoreSection
searchQuery={searchQuery}
highlightedSectionId={highlightedSectionId}
scheduleConfig={scheduleConfig}
nextScheduledBackup={nextScheduledBackup}
lastScheduledBackup={lastScheduledBackup}
isTriggeringBackup={isTriggeringBackup}
isRestoringBackup={isRestoringBackup}
selectedBackupFile={selectedBackupFile}
backupValidationError={backupValidationError}
onScheduleConfigChange={onScheduleConfigChange}
onTriggerBackup={onTriggerBackup}
onRestoreBackup={onRestoreBackup}
onRestoreBackupFile={onRestoreBackupFile}
onFileSelect={onFileSelect}
/>
</SettingsSectionShell>
<SettingsSectionShell
id="debug-tools"
isCollapsible={true}
isCollapsed={collapsedSections["debug-tools"] ?? false}
onCollapsedChange={() => onToggleSection("debug-tools")}
icon={Bug}
title="Debug tools"
description="Advanced utilities for troubleshooting and development."
accent="from-orange-500/20 via-rose-500/15 to-transparent"
contentClassName="space-y-6"
className={cn(
"transition-shadow duration-300 hover:shadow-[0_32px_120px_-80px_rgba(15,23,42,0.5)]",
highlightedSectionId === "data-debug" &&
"ring-2 ring-rose-500 ring-offset-2 ring-offset-white dark:ring-rose-400 dark:ring-offset-slate-950",
)}
>
<DebugToolsSection
isDebugEnabled={isDebugEnabled}
isStorageDebuggerEnabled={isStorageDebuggerEnabled}
isLogViewerEnabled={isLogViewerEnabled}
isLogRedactionEnabled={isLogRedactionEnabled}
isStateInspectorEnabled={isStateInspectorEnabled}
isIpcViewerEnabled={isIpcViewerEnabled}
isEventLoggerEnabled={isEventLoggerEnabled}
isConfidenceTestExporterEnabled={isConfidenceTestExporterEnabled}
isPerformanceMonitorEnabled={isPerformanceMonitorEnabled}
searchQuery={searchQuery}
highlightedSectionId={highlightedSectionId}
onToggleDebug={onToggleDebug}
onStorageDebuggerChange={onStorageDebuggerChange}
onLogViewerChange={onLogViewerChange}
onLogRedactionChange={onLogRedactionChange}
onStateInspectorChange={onStateInspectorChange}
onIpcViewerChange={onIpcViewerChange}
onEventLoggerChange={onEventLoggerChange}
onConfidenceTestExporterChange={onConfidenceTestExporterChange}
onPerformanceMonitorChange={onPerformanceMonitorChange}
/>
</SettingsSectionShell>
</motion.div>
);
}
Data management tab content component. Orchestrates rendering of cache, backup, and debug sections.