/* Copyright 2026 Marimo. All rights reserved. */ import { useAtomValue } from "jotai"; import { DatabaseZapIcon, RefreshCwIcon, Trash2Icon } from "lucide-react"; import React, { useState } from "react"; import { useLocale } from "react-aria"; import { Spinner } from "@/components/icons/spinner"; import { Button } from "@/components/ui/button"; import { ConfirmationButton } from "@/components/ui/confirmation-button"; import { toast } from "@/components/ui/use-toast"; import { cacheInfoAtom } from "@/core/cache/requests"; import { useRequestClient } from "@/core/network/requests"; import { useAsyncData } from "@/hooks/useAsyncData"; import { cn } from "@/utils/cn"; import { formatBytes, formatTime } from "@/utils/formatting"; import { prettyNumber } from "@/utils/numbers"; import { PanelEmptyState } from "./empty-state"; const CachePanel = () => { const { clearCache, getCacheInfo } = useRequestClient(); const cacheInfo = useAtomValue(cacheInfoAtom); const [purging, setPurging] = useState(false); const { locale } = useLocale(); const { isPending, isFetching, refetch } = useAsyncData(async () => { await getCacheInfo(); // Artificially spin the icon if the request is really fast await new Promise((resolve) => setTimeout(resolve, 500)); }, []); const handlePurge = async () => { try { setPurging(true); await clearCache(); toast({ title: "Cache purged", description: "All cached data has been cleared", }); // Request updated cache info after purge refetch(); } catch (error) { toast({ title: "Error", description: error instanceof Error ? error.message : "Failed to purge cache", variant: "danger", }); } finally { setPurging(false); } }; // Show spinner only on initial load if (isPending && !cacheInfo) { return ; } const refreshButton = ( ); if (!cacheInfo) { return ( } action={refreshButton} /> ); } const totalHits = cacheInfo.hits; const totalMisses = cacheInfo.misses; const totalTime = cacheInfo.time; const diskTotal = cacheInfo.disk_total; const diskToFree = cacheInfo.disk_to_free; const totalRequests = totalHits + totalMisses; const hitRate = totalRequests > 0 ? (totalHits / totalRequests) * 100 : 0; // Show empty state if no cache activity if (totalRequests === 0) { return ( } action={refreshButton} /> ); } return (
{/* Header with Refresh Button */}
{/* Statistics Section */}

Statistics

0 ? `${prettyNumber(hitRate, locale)}%` : "—" } description={`${prettyNumber(totalHits, locale)} hits / ${prettyNumber(totalRequests, locale)} total`} />
{/* Storage Section */} {diskTotal > 0 && (

Storage

0 ? `${formatBytes(diskToFree, locale)} can be freed` : "Cache storage on disk" } />
)}
{/* Actions Section */}
); }; const StatCard: React.FC<{ label: string; value: string; description?: string; }> = ({ label, value, description }) => { return (
{label} {value} {description && ( {description} )}
); }; export default CachePanel;