From 784e7bd8227fac34721a5efb8ebb1194fbed25b8 Mon Sep 17 00:00:00 2001 From: Vassiliy Yegorov Date: Sun, 5 Jul 2026 14:27:33 +0700 Subject: [PATCH] fix(web): wrap long record values in diff and zone view (no horizontal overflow) RecordRow now splits into a top line (badge/name/read-only, unaffected by value length) and a plain block-level values line below it, so a ~400-char unbreakable DKIM key wraps via break-all instead of stretching the flex row and forcing page-wide horizontal scroll. Zone records table gets break-all on the values cell too. Co-Authored-By: Claude Opus 4.8 (1M context) Claude-Session: https://claude.ai/code/session_01BwxdSt4reTm7Dj1oxRvpP3 --- web/src/components/DiffView.test.tsx | 24 +++++++++++ web/src/components/DiffView.tsx | 59 +++++++++++++++++----------- web/src/pages/DomainDiffPage.tsx | 4 +- 3 files changed, 63 insertions(+), 24 deletions(-) diff --git a/web/src/components/DiffView.test.tsx b/web/src/components/DiffView.test.tsx index 6d58953..5bfce43 100644 --- a/web/src/components/DiffView.test.tsx +++ b/web/src/components/DiffView.test.tsx @@ -27,6 +27,30 @@ test("marks read-only records", () => { expect(screen.getByText(/NS/)).toBeInTheDocument() }) +test("renders a very long unbreakable value (DKIM key) without crashing", () => { + // Real DKIM records ship a ~400-char unbroken p= blob. This must not + // throw and the value must land in the DOM (wrapping itself is a CSS + // concern verified manually, not via jsdom layout). + const longValue = "v=DKIM1; k=rsa; p=" + "A".repeat(400) + const csWithDkim: ChangesetResponse = { + updates: [ + { + kind: "update", + type: "TXT", + name: "default._domainkey.example.com.", + desired: [longValue], + actual: [], + readOnly: false, + }, + ], + prunes: [], + readOnly: [], + inSyncCount: 0, + } + render() + expect(screen.getByText(new RegExp(longValue))).toBeInTheDocument() +}) + test("does not crash when changeset fields are null", () => { // An empty changeset from an older/edge backend can arrive with null slices // instead of []. DiffView must normalise them, not blow up on .length/.map. diff --git a/web/src/components/DiffView.tsx b/web/src/components/DiffView.tsx index 813170f..185344a 100644 --- a/web/src/components/DiffView.tsx +++ b/web/src/components/DiffView.tsx @@ -47,43 +47,56 @@ function RecordRow({ record, tone }: { record: RecordView; tone: Tone }) { return (
- - {record.type} - + {/* Top line: type badge, name, read-only flag — always single-line, + never affected by how long the record values are. */} +
+ + {record.type} + - - {record.name} - + + {record.name} + - + {record.readOnly && ( + + + read-only + + )} +
+ + {/* Values line: plain block-level text (not flex) so a long + unbreakable value like a DKIM key wraps within the row's own + width instead of stretching it — a flex item's content can + otherwise refuse to shrink below its intrinsic width. Indented + to align under the name (badge width + gap). */} +
{showArrow && ( <> - + {" "} + {" "} )} - - - {record.readOnly && ( - - - read-only - - )} +
) } diff --git a/web/src/pages/DomainDiffPage.tsx b/web/src/pages/DomainDiffPage.tsx index 9bc49ff..aaccd1b 100644 --- a/web/src/pages/DomainDiffPage.tsx +++ b/web/src/pages/DomainDiffPage.tsx @@ -167,7 +167,9 @@ export function DomainDiffPage() { {r.type} {r.name} {r.ttl} - {r.values.join("\n")} + + {r.values.join("\n")} + ))}