Filed by the objectui#8376 dev (branch claude/issue-8376-detailsection-emptiness-authority) while converging that file's emptiness tests. ⛔ Not claimed. Out of scope there: #8376 is about which rows count as EMPTY; this is about what the copy affordance WRITES for a row that is filled, and fixing it does not move any emptiness predicate.
What
packages/plugin-detail/src/DetailSection.tsx:
const handleCopyField = React.useCallback((fieldName: string, value: any) => {
const textValue = value !== null && value !== undefined ? String(value) : '';
navigator.clipboard.writeText(textValue).then(...)
String(value) on an object is '[object Object]'. The affordance is offered for every non-empty value — objects included — so on a detail page a reader who clicks the copy button (or the row, or presses Enter on it) on an address, geolocation, JSON, attachment/file, multiselect or expanded lookup cell silently gets [object Object] on the clipboard.
Reachable in read mode on any non-editable object-valued row, which is the common case: the pencil affordance replaces copy only when the field is inline-editable AND the parent threaded onEnterInlineEdit.
Why it is worth fixing rather than removing
The cell next to the button is already rendering that value correctly — AddressCellRenderer prints a formatted postal address (objectui#4037), LocationCellRenderer prints 30.2741, 120.1551, SelectCellRenderer prints option badges. So the rendered text the reader is looking at is exactly what they expect to copy, and the clipboard gets a placeholder string instead. The failure is silent: nothing errors, and it is only noticed on paste.
Fix shape (a suggestion, not a ruling)
Two candidates, and a taker should decide rather than assume:
- A — copy the rendered text. Read the row's rendered
textContent. Matches what the reader sees, and needs no per-type table. Costs a DOM read at click time and depends on the renderer's formatting (a truncated value would have to be handled — TruncatedText is in this path).
- B — a shared value→text formatter. Serialize per type (
formatAddress for address, lat, lng for geolocation, JSON.stringify for json, the option labels for multiselect). Deterministic and testable, but it is a second formatting authority next to the cell renderers — the exact drift shape objectui#4037 closed for formatAddress, so it should reuse those functions rather than re-spell them.
⛔ Not "don't offer copy for objects": the value IS copyable and the reader has a legitimate reason to want it.
The pin should assert what reaches navigator.clipboard.writeText, per type, from a rendered DetailSection — with a control asserting an ordinary string row still copies its own value unchanged.
Measured
Read on branch claude/issue-8376-detailsection-emptiness-authority at b6ed5cdaf. canCopy is hasCellValue(value) as of #8376, and that function classifies every object as a value (deliberately — see its docblock), exactly as the raw test it replaced did. So #8376 neither introduces nor widens this; the String(value) line is untouched by it.
Dedup
search_issues once, self-validating (it returned a card that IS about this file's object-valued cells): the clipboard / [object Object] / detail copy wording returned exactly one issue, objectui#4037 — the address cell renderer, closed. #4037 is read-side only and says nothing about the clipboard; its own body scopes itself to the display registry. Nothing names the clipboard write.
Related
objectui#4037 (formatAddress, the shared address formatting authority a fix B would reuse) · objectui#8376 (hasCellValue, which decides whether the affordance is offered at all)
Filed by the objectui#8376 dev (branch
claude/issue-8376-detailsection-emptiness-authority) while converging that file's emptiness tests. ⛔ Not claimed. Out of scope there: #8376 is about which rows count as EMPTY; this is about what the copy affordance WRITES for a row that is filled, and fixing it does not move any emptiness predicate.What
packages/plugin-detail/src/DetailSection.tsx:String(value)on an object is'[object Object]'. The affordance is offered for every non-empty value — objects included — so on a detail page a reader who clicks the copy button (or the row, or presses Enter on it) on an address, geolocation, JSON, attachment/file, multiselect or expanded lookup cell silently gets[object Object]on the clipboard.Reachable in read mode on any non-editable object-valued row, which is the common case: the pencil affordance replaces copy only when the field is inline-editable AND the parent threaded
onEnterInlineEdit.Why it is worth fixing rather than removing
The cell next to the button is already rendering that value correctly —
AddressCellRendererprints a formatted postal address (objectui#4037),LocationCellRendererprints30.2741, 120.1551,SelectCellRendererprints option badges. So the rendered text the reader is looking at is exactly what they expect to copy, and the clipboard gets a placeholder string instead. The failure is silent: nothing errors, and it is only noticed on paste.Fix shape (a suggestion, not a ruling)
Two candidates, and a taker should decide rather than assume:
textContent. Matches what the reader sees, and needs no per-type table. Costs a DOM read at click time and depends on the renderer's formatting (a truncated value would have to be handled —TruncatedTextis in this path).formatAddressfor address,lat, lngfor geolocation,JSON.stringifyfor json, the option labels for multiselect). Deterministic and testable, but it is a second formatting authority next to the cell renderers — the exact drift shape objectui#4037 closed forformatAddress, so it should reuse those functions rather than re-spell them.⛔ Not "don't offer copy for objects": the value IS copyable and the reader has a legitimate reason to want it.
The pin should assert what reaches
navigator.clipboard.writeText, per type, from a renderedDetailSection— with a control asserting an ordinary string row still copies its own value unchanged.Measured
Read on branch
claude/issue-8376-detailsection-emptiness-authorityatb6ed5cdaf.canCopyishasCellValue(value)as of #8376, and that function classifies every object as a value (deliberately — see its docblock), exactly as the raw test it replaced did. So #8376 neither introduces nor widens this; theString(value)line is untouched by it.Dedup
search_issuesonce, self-validating (it returned a card that IS about this file's object-valued cells): the clipboard /[object Object]/ detail copy wording returned exactly one issue, objectui#4037 — the address cell renderer, closed. #4037 is read-side only and says nothing about the clipboard; its own body scopes itself to the display registry. Nothing names the clipboard write.Related
objectui#4037 (
formatAddress, the shared address formatting authority a fix B would reuse) · objectui#8376 (hasCellValue, which decides whether the affordance is offered at all)