Skip to content

fix(addresses): reveal rendered addresses - #1345

Open
thekidnamedkd wants to merge 9 commits into
mainfrom
address-tooltip
Open

fix(addresses): reveal rendered addresses#1345
thekidnamedkd wants to merge 9 commits into
mainfrom
address-tooltip

Conversation

@thekidnamedkd

@thekidnamedkd thekidnamedkd commented Aug 27, 2026

Copy link
Copy Markdown
Contributor

Description

Replace direct visible address truncation renders with AddressOutput so users can reveal and copy complete addresses across action details, permissions, finance, governance, navigation, plugin, and voting surfaces.

Related issue: APP-1088

Dependency status

This refit uses @aragon/gov-ui-kit 2.11.3, published from aragon/gov-ui-kit#768 at merge commit 652c9a108f1fa4b3cc10032549b6a6dfa413b131. Its release notes include the DefinitionList.Item on-chain value mode, root-exported InteractiveAncestorContext, inline-safe AddressOutput/Clipboard roots, root-level AddressOutput.className, and DataList interactive-row layout preservation. The published package types additionally confirm AvatarIcon now uses an HTMLSpanElement root, and the bundle includes 32-byte hash truncation. The temporary /tmp tarball override has been removed; the catalog and lockfile now resolve normally to 2.11.3.

Refitted behavior

  • Definition lists: on-chain rows now pass string children to DefinitionList.Item, put href, isExternal, and isOnchainEntity: true on link, and use copyValue whenever the visible label is an ENS/name/token symbol. Raw addresses and 32-byte hashes are passed through for the kit's built-in checksum/hash truncation. There are no AddressOutput descendants under DefinitionList.Item in apps/app.
  • Interactive ancestors: real button-owned surfaces (NavigationDaoHome, selectable AssetInput, permissions accordion headers, and governance-body accordion headers) provide InteractiveAncestorContext once at the wrapper. DataList overlay rows do not receive providers, so copy/reveal controls remain usable. There are no per-instance hasInteractiveAncestor props and therefore no survivors to justify.
  • Hydration markup: simulation-flow and both Alchemix vote address sites remain semantic <p> elements because fix(APP-4058): Fix canSimulate logic to allow simulating in executable state and update simulation dialog UI #768 makes the kit roots inline-safe spans. No hasInteractiveAncestor workaround is added. One boundary is worth recording for future work: the span root makes the link-less AddressOutput valid phrasing content, but passing href wraps the label in the kit Link, whose internal <div class="flex items-center gap-x-1 …"> still triggers In HTML, <div> cannot be a descendant of <p>. None of the three reported sites passes href, and an AST audit confirms apps/app has zero AddressOutput sites that combine href with a <p>/heading parent, so no surface is affected — but href + <p> must stay off-limits.
  • Titles/navigation: Page.Header and its callers retain a string-only title; the presentational page header renders an address title with copy={false}. DAO navigation and wizard chrome are also copy-free.
  • Named entities: PermissionEntityCell and PermissionGraphNode intentionally render one AddressOutput with address plus label, preserving reveal/copy affordances for named entities. PermissionNodeDetailPanel keeps a plain named heading because its dedicated address row owns reveal/copy.
  • Policy settings: IPolicySettingItem remains a plain data contract and keeps copyValue as an input. The page renderer maps its string/plain { address, value, link, copyValue } data into DefinitionList.Item props.
  • Gauge rows: name/address pairs expose at most one copy action. The vote-dialog remove control is a single accessible Remove gauge button, and its test selects by role/name rather than position.
  • Layout classes: redundant label-level truncate classes were removed. navigationDao's w-full and simulation-flow's w-fit remain because fix(APP-4058): Fix canSimulate logic to allow simulating in executable state and update simulation dialog UI #768 applies className to the AddressOutput root.

Milosh review disposition

GitHub exposes Milosh's feedback as one top-level review (pullrequestreview-5049228444) and reports zero inline review threads, so there are no resolvable thread objects. A PR comment answers each review point against that original review.

Verification

  • pnpm install --no-frozen-lockfile — passed with the published 2.11.3 package; no local file override remains.
  • pnpm --filter @aragon/app type-check — passed against published 2.11.3.
  • pnpm --filter @aragon/app lint:check — passed; 2,750 files checked, no fixes.
  • Full pnpm exec jest suite in apps/app — 390 suites / 2,534 tests passed, with zero cannot be a descendant / hydration output across the run.
  • New simulationFlowVisualizationItem.test.tsx — the one previously-untested affected surface now has coverage asserting the fallback address renders as valid phrasing content (no p div, no descendant error) and that the linked variant exposes exactly one Copy control. Both assertions were confirmed to be discriminating: the p div selector detects a real <div>-in-<p>, and an href-inside-<p> render does emit React's descendant error.
  • alchemixSubmitVote.test.tsx — 1 suite / 20 tests passed with the <p> address markup and no React DOM nesting/hydration warning output.
  • Behavioral render probe of the new kit contract (throwaway, not committed) — a DefinitionList.Item with link={{ href, isExternal, isOnchainEntity: true }} and a raw address child renders exactly 1 anchor, exactly 1 Copy button, and the value truncated to 0x1234…7890; the copyValue + label variant renders the label with a single copy control. This exercises the contract behind all 37 on-chain items rather than inferring it.
  • Static TypeScript-AST audit — 0 AddressOutput descendants under DefinitionList.Item.
  • Static source audit — 0 hasInteractiveAncestor props; no ReactNode page-title widening; git diff --check passed.
  • Real pnpm dev server — Next.js 16.3.0 started successfully at http://localhost:3000; the public landing page rendered in Chrome DevTools.
  • DAO surface smoke limitation — the configured dev backend returned HTTP 403 for DAO requests (https://dev.backend.aragonservices.in/v3/daos/ethereum-mainnet/ens/boundless.dao.eth), so dashboard, member details, proposal details, settings/policy, gauge dialogs, simulation-flow, and the Alchemix vote surface could not render. Browser/server evidence was captured; no claim is made for those blocked surfaces. The browser also showed pre-existing CSP/WalletConnect local-development diagnostics unrelated to these changes.

Type of Change

  • Major: Breaking change which causes existing functionality not to work as expected
  • Minor: Non-breaking feature
  • Patch: Enhancement
  • Patch: Bug fix

Developer Checklist

  • Manually smoke tested all affected DAO surfaces (blocked by backend HTTP 403; see verification)
  • Confirmed there are no warnings/errors in the browser console (blocked surfaces did not render; public-page console has unrelated local CSP/WalletConnect diagnostics)
  • Confirmed there are no new warnings on automated tests
  • Merged and published dependent downstream change (gov-ui-kit fix(APP-4058): Fix canSimulate logic to allow simulating in executable state and update simulation dialog UI #768 shipped in 2.11.3)
  • Selected the correct base branch
  • Followed the code style guidelines
  • Reviewed the local changed-file set for scope
  • Confirmed the dependency update is committed and pushed to the PR branch

Review Checklist

  • Tested all acceptance criteria in preview/local (DAO-backed surfaces blocked by backend HTTP 403)
  • Confirmed changes follow the code style guidelines

Use AddressOutput for visible address slots while leaving string-only and hash paths unchanged.\n\nRefs APP-1088
@thekidnamedkd
thekidnamedkd requested a review from a team as a code owner August 27, 2026 17:46
@linear-code

linear-code Bot commented Aug 27, 2026

Copy link
Copy Markdown

APP-1088

@thekidnamedkd thekidnamedkd changed the title Reveal rendered addresses with AddressOutput fix(APP-1088): Add AddressOutput to address renders Aug 27, 2026
@thekidnamedkd thekidnamedkd changed the title fix(APP-1088): Add AddressOutput to address renders fix(addresses): reveal rendered addresses Aug 27, 2026

@milosh86 milosh86 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A couple of valid points, I confirmed them:

Bugs

  1. <div> inside <p>— hydration error and dropped styling (3 sites)

AddressOutput renders a root <div class="flex min-w-0 items-center gap-2"> unless hasInteractiveAncestor is set (which switches it to a <span>). Three call sites drop it straight into a <p>:

apps/app/src/modules/capitalFlow/components/simulationFlowVisualization/simulationFlowVisualizationItem.tsx:111

apps/app/src/daos/alchemix/components/alchemixSubmitVote/alchemixSubmitVote.tsx:295

apps/app/src/daos/alchemix/components/alchemixSubmitVote/alchemixSubmitVote.tsx:341

React 19 flags it directly:

In HTML, `<div>` cannot be a descendant of `<p>`. This will cause a hydration error.
  > <p className="text-neutral-500 text-sm leading-tight">
      <_p address="0x12345678...">
  >     <div className="flex min-w-0 items-center gap-2">

Second effect, confirmed by feeding the SSR markup through a real HTML parser: the parser auto-closes the <p> and hoists the address out as a sibling, so the <p> ends up empty and its classes never reach the address. text-neutral-500 text-sm leading-tight (simulation flow) and truncate font-semibold text-base text-neutral-800 (alchemix) are silently lost.

The branch already gets this right in ~8 other <p> sites via hasInteractiveAncestor — these three were missed. But note the fix differs here: none of the three has an interactive ancestor, so adding that flag would wrongly strip the copy control and keyboard access. Swap the <p> for a <div> (keeping the classes on it) instead.

  1. Two copy buttons for the same address in one row

[apps/app/src/plugins/gaugeVoterPlugin/dialogs/gaugeVoterVoteDialog/gaugeVoterVoteDialogItem/gaugeVoterVoteDialogItem.tsx:103-112]
(https://github.com/aragon/app/blob/address-tooltip/apps/app/src/plugins/gaugeVoterPlugin/dialogs/gaugeVoterVoteDialog/gaugeVoterVoteDialogItem/gaugeVoterVoteDialogItem.tsx#L103-L112) — the name line and the address line are both bare AddressOutput, and copy defaults to true. One dialog row now carries two identical copy controls for gaugeAddress, plus two extra tab stops. The sibling component doing the same name/address pair, gaugeVoterGaugeListItemStructure.tsx, passes hasInteractiveAncestor and gets exactly one; governanceBodyInfo.tsx likewise.

  1. Copy button injected into the wizard header chrome

apps/app/src/modules/application/components/navigations/navigationWizard/navigationWizard.tsx:131 — the parent is <div className="flex items-center gap-x-2"> holding the DAO name then DaoAvatar. Since AddressOutput's root is itself a flex row ending in a copy button, the rendered order becomes name → copy button → avatar. Page titles in this same branch use copy={false} for exactly this reason (dashboardDefaultHeader.tsx:69, daoMemberDetailsPageClient.tsx:243).

Nits

  • className targets the label span, not the root. Verified: it lands on the innermost <span class="inline-block min-w-0 max-w-full …">. So className="w-full …" in navigationDao.tsx:137 (replacing <Clipboard className="w-full">) and className="w-fit" in simulationFlowVisualizationItem.tsx:103 (replacing <Link className="w-fit">) are now no-ops — both sit inside a max-w-fit anchor. Cosmetic; the kit applies its own truncate so ellipsis still works.
  • gaugeVoterVoteDialogItem.test.tsx:90 closeButtons.at(-1) is positional and just drifted once for this reason; getByRole('button', { name: … }) wouldn't.
  • IPolicySettingItem.copyValue (daoPolicyDetailsClientUtils.ts:24) is dead now that the page stopped reading it.

@thekidnamedkd
thekidnamedkd marked this pull request as draft August 28, 2026 09:24
@thekidnamedkd
thekidnamedkd marked this pull request as ready for review September 3, 2026 16:47
# Conflicts:
#	apps/app/src/modules/governance/pages/daoProposalDetailsPage/daoProposalDetailsPageClient.tsx
#	pnpm-lock.yaml
#	pnpm-workspace.yaml
@github-actions

github-actions Bot commented Sep 3, 2026

Copy link
Copy Markdown

🚀 Preview Deployment: View Here

@github-actions

github-actions Bot commented Sep 3, 2026

Copy link
Copy Markdown

E2E results (preview)

Smoke

Base URL https://app-next-o6hjrkvw9-aragon-app.vercel.app
Suite smoke
Playwright result ❌ failed
Summary 80 passed, 2 failed
HTML report View report
GitHub job ✅ completed

View run #5120

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants