diff --git a/CHANGELOG.md b/CHANGELOG.md index 09ad5718..4da77c24 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Fixed - Job args: preserve large numeric JSON values exactly when displaying and copying args, while keeping object keys sorted. [Fixes #593](https://github.com/riverqueue/riverui/issues/593). [PR #594](https://github.com/riverqueue/riverui/pull/594). +- JSON viewer: render empty and escaped object property keys as valid JSON strings. [PR #632](https://github.com/riverqueue/riverui/pull/632). ## [v0.17.0] - 2026-07-31 diff --git a/src/components/JSONView.test.tsx b/src/components/JSONView.test.tsx index eedf24de..58c16928 100644 --- a/src/components/JSONView.test.tsx +++ b/src/components/JSONView.test.tsx @@ -97,6 +97,19 @@ describe("JSONView Component", () => { expect(bravoBeforeZulu).toBeTruthy(); }); + it("renders empty and escaped object keys as valid JSON strings", () => { + const data = JSON.parse( + String.raw`{"":"empty key","quote\"key":"quoted key"}`, + ) as Record; + + render(); + + expect(screen.getByText('""')).toBeInTheDocument(); + expect(screen.getByText(String.raw`"quote\"key"`)).toBeInTheDocument(); + expect(screen.getByText('"empty key"')).toBeInTheDocument(); + expect(screen.getByText('"quoted key"')).toBeInTheDocument(); + }); + it("renders nested JSON data with collapsed nodes but visible keys by default", () => { render(); diff --git a/src/components/JSONView.tsx b/src/components/JSONView.tsx index dff10ec0..512a4ea3 100644 --- a/src/components/JSONView.tsx +++ b/src/components/JSONView.tsx @@ -181,7 +181,7 @@ function JSONNodeRenderer({ const color = styleConfig.json.key; // For primitive values, render key and value inline - if (propKey && isPrimitiveValue(data)) { + if (propKey !== null && isPrimitiveValue(data)) { return ( - "{propKey}" + {JSON.stringify(propKey)} {typeof data === "string" ? ( @@ -213,7 +213,7 @@ function JSONNodeRenderer({ } // For non-primitive values (objects/arrays) or non-property values, use the normal rendering - if (!propKey) { + if (propKey === null) { return renderValue( data, valueColor, @@ -234,7 +234,7 @@ function JSONNodeRenderer({ if (count === 0) { return ( - "{propKey}" + {JSON.stringify(propKey)} {isArray ? "[]" : "{}"} @@ -294,7 +294,7 @@ function JSONNodeRenderer({ /> )} - "{propKey}" + {JSON.stringify(propKey)} {isArray ? "[" : "{"} {!open && (