import { useState } from "react"; import { useSearchParams } from "react-router-dom"; import { useKv, useKvNamespaces } from "../api/hooks.js"; import { formatTime } from "../lib/format.jsx"; const PAGE_SIZE = 50; function previewValue(value) { const json = JSON.stringify(value); if (json == null) return "—"; if (json.length <= 120) return json; return `${json.slice(0, 120)}…`; } export function KvPage() { const [params, setParams] = useSearchParams(); const namespace = params.get("namespace") || ""; const q = params.get("q") || ""; const offset = Math.max(Number(params.get("offset")) || 0, 0); const [expanded, setExpanded] = useState(null); const { data: namespaces = [] } = useKvNamespaces(); const { data, isLoading } = useKv({ namespace: namespace || undefined, q: q || undefined, limit: PAGE_SIZE, offset, }); const items = data?.items ?? []; const total = data?.total ?? 0; const limit = data?.limit ?? PAGE_SIZE; function update(key, value, resetOffset = true) { const next = new URLSearchParams(params); if (value) next.set(key, value); else next.delete(key); if (resetOffset && key !== "offset") next.delete("offset"); setParams(next); setExpanded(null); } function rowId(item) { return `${item.namespace}\0${item.key}`; } return (

KV

update("q", e.target.value)} />
{isLoading ? ( ) : items.length === 0 ? (

No KV entries.

) : ( <>
{items.map((item) => { const id = rowId(item); const open = expanded === id; return ( setExpanded(open ? null : id)} > ); })}
Namespace Key Value Updated Expires
{item.namespace} {item.key} {open ? (
                            {JSON.stringify(item.value, null, 2)}
                          
) : ( {previewValue(item.value)} )}
{formatTime(item.updatedAt)} {item.expiresAt ? formatTime(item.expiresAt) : "—"}
{total === 0 ? "0" : `${offset + 1}–${offset + items.length}`} of {total}
)}
); }