From f0aaba8b3988ab771cd33c1c4cf6f61838c40841 Mon Sep 17 00:00:00 2001 From: zihluwang Date: Tue, 24 Feb 2026 09:55:57 +0800 Subject: [PATCH] feat: enhance CSV export functionality in JsonViewer with object handling --- src/page/json-viewer/index.tsx | 22 +++++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) diff --git a/src/page/json-viewer/index.tsx b/src/page/json-viewer/index.tsx index 4b879e2..263b437 100644 --- a/src/page/json-viewer/index.tsx +++ b/src/page/json-viewer/index.tsx @@ -27,6 +27,10 @@ export default function JsonViewer() { const [query, setQuery] = useState("$.staff_members[*].name") const [copied, setCopied] = useState(false) + const isPlainObject = (value: unknown): value is Record => { + return value !== null && typeof value === "object" && !Array.isArray(value) + } + // Compute matching results const result = useMemo(() => { let parsed @@ -63,9 +67,21 @@ export default function JsonViewer() { return str } - const header = query - const rows = result.matchedValues.map(escapeCsvValue) - const csv = [header, ...rows].join("\n") + const objectMatches = result.matchedValues.filter(isPlainObject) + const isObjectTable = objectMatches.length > 0 && objectMatches.length === result.matchedValues.length + + const csv = isObjectTable + ? (() => { + const columns = Array.from(new Set(objectMatches.flatMap((item) => Object.keys(item)))) + const headerRow = columns.map(escapeCsvValue).join(",") + const valueRows = objectMatches.map((item) => columns.map((column) => escapeCsvValue(item[column])).join(",")) + return [headerRow, ...valueRows].join("\n") + })() + : (() => { + const header = query + const rows = result.matchedValues.map(escapeCsvValue) + return [header, ...rows].join("\n") + })() navigator.clipboard.writeText(csv).then(() => { setCopied(true)