Skip to content

feat(APP-1003): DAO permissions viewer with list and graph views - #1276

Open
evanaronson wants to merge 57 commits into
mainfrom
agent/app-942-permissions-audit-remediation
Open

feat(APP-1003): DAO permissions viewer with list and graph views#1276
evanaronson wants to merge 57 commits into
mainfrom
agent/app-942-permissions-audit-remediation

Conversation

@evanaronson

@evanaronson evanaronson commented Aug 1, 2026

Copy link
Copy Markdown
Contributor

Summary

Adds the DAO settings permissions page: list and graph views of the DAO's on-chain permissions, backed by a single permissions fetch, with two explicit visibility toggles (hide DAO-granted rows, hide rows targeting subplugins) applied identically to both views.

What this contains

  • List + graph — one filtered row set feeds both views; the graph renders actors on governing bodies as per-(who, where) hub nodes (all of an actor's grants on a body stack into one node), and the bundle lazy-loads behind the graph view.
  • Filter semantics — rows are hidden only by the two toggles. No implicit pre-filters: residual, unresolved, and inactive/historical grants are visible by default; permissions-query failures render an error surface instead of an empty state.
  • One responsive list — a single row/detail implementation across breakpoints; the condition field is always present (dash when absent); rows sort by Where; unrecognized conditions suppress the breakdown affordance like unconditional grants.
  • Shared semantics — address rows use DefinitionList.Item link/description/copyValue; condition and token addresses link to the explorer; Safe bodies resolve through the shared PermissionEntityBrandId domain type.
  • Structure — one component per file, the canvas decomposed into layout/flow-element/handles modules, domain entity types in domain/enum/, shared test generators.

Verification

  • Focused suites: 206 settings tests green (31 suites); tsc --noEmit clean; biome clean.
  • Preview verified against the reference DAO (citrea-mainnet): list and graph show the same rows under both toggles; the graph shows one Anyone hub per SPP body with stacked Create proposal / Advance / Execute proposal chips, plus the Safe body.

Refinement pass over the permissions graph (APP-942 finished in #1238).

- Consolidate the view into a single graph screen driven by toggles;
  remove the Granted/Other tabs
- Treat each permission as a distinct node instead of merging under a
  shared "anyone" header
- Standardize resource-link display and show the permission ID above
  the name
- Replace explicit "no condition"/"no description" labels with a dash
  placeholder
- Add graph full-screen mode with Escape-to-exit
- Add informational tooltips to the Who / subplugin filter toggles
- Move DAO self-permission stacks south of the DAO node and align the
  stack handles
- Filter uninstalled/stale plugins out of the graph data
…raph-finish

# Conflicts:
#	apps/app/package.json
#	pnpm-lock.yaml
evanaronson and others added 2 commits August 1, 2026 15:05
… drill-in dialogs

Owner rejected the previous feedback-round implementation: no dialog was
asked for, the summary card duplicated the details, and the details sat
behind a click. Corrected to the graph detail-card pattern: below md
each row renders the permission name as its header, the existing
details definition list directly (extracted verbatim to the shared
PermissionDetailsList, also used by the expanded accordion), and a
Details/Condition toggle only when a condition exists that switches to
the interior condition component. The PERMISSION_DETAILS dialog, its
registry entries, and the PermissionDetailContent initialTab addition
are removed. On md+ the two-column expanded layout is preserved with a
blank right column when no condition exists.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
evanaronson and others added 2 commits August 1, 2026 15:31
…subplugin filter to Where, sort list by Where

Owner feedback round 2, proof-first. Unrecognized conditions (payload
cannot be resolved) behave like unconditional grants for the breakdown
affordances — blank right column on desktop, no toggle on the mobile
card or graph detail card — while the details list still names them
with their address; present-but-unregistered condition types keep their
breakdown. The hide-subplugin toggle now hides rows only when the
target (Where) is a subplugin, with the caller (Who) never counting;
isSubpluginEndpoint and rowTouchesSubplugin fold into one
rowTargetsSubplugin predicate and the tooltip copy states the
Where-based rule. The list view sorts rows by the resolved Where label
(stable, case-insensitive, presentation-only — both views still receive
the identical filtered row array).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Signed-off-by: Evan Aronson <93671071+evanaronson@users.noreply.github.com>
…diation.md

Signed-off-by: Evan Aronson <93671071+evanaronson@users.noreply.github.com>
…details list

Owner-approved simplification round. Test intent is unchanged — the
same fixtures and assertions move into it.each tables (filter keeps/
hides guard tables, entity visuals, graph layout/handle pairs, SPP
Safe-group pairs), five worthless or fully-subsumed tests are deleted
after per-assertion subsumption checks, and two real gaps close: a new
permissionCondition dispatch suite pins all four outcomes (making the
'none' branch reachable, which is why NoConditionSlot stays
registered), and getPermissionRowToggleAvailability gains direct unit
coverage so the page tests only wiring. The unfailable selector-
narrowing test gains a falsifying assertion and the structuredClone
polyfill lives once in jest setup.

Production: PermissionSummaryField is deleted (its labels were
unreachable at every breakpoint since mobile left the accordion), and
the graph detail card renders the shared PermissionDetailsList instead
of its own hand-rolled list — sentinel rows there adopt the list
rendering (single label plus copy affordance) and the redundant
permissionName prop is gone.

Net -597 lines (-89 production, -508 test); tests 221 -> 218.
Cumulative production delta vs the audit base is now net -38 lines.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The Safe branch hoisted brandId into the label but then rendered
parentPluginName as the secondary line, so a Safe body inside a process
displayed the process name (e.g. "Core Governance") underneath its
address — reading as though the address were that plugin, and colliding
with the Where row that legitimately carries the same name. The backend
field is correct; the detail slot names the address, not its container.

The Safe brand table asserted the label but never the detail name,
which is how this survived the earlier brand-precedence fix; both cases
now carry a parentPluginName fixture and pin detailName.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@thekidnamedkd thekidnamedkd changed the title fix(APP-942): Remediate permission-viewer audit findings feat(APP-1003): DAO permissions viewer with list and graph views Aug 1, 2026
…aceholder label

Unknown who/where endpoints rendered a literal "Unknown address" label
in the collapsed cells and graph nodes — both from the local resolver
fallback and from the backend's own hardcoded generic label, which is
now treated as "no name" like the existing "Process internal"
handling. An unresolved address presents as its truncated address; the
expanded row already suppresses the duplicate description line.
"Unresolved contract" stays: the backend recognized a contract there,
which is information the address alone does not carry.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@thekidnamedkd
thekidnamedkd marked this pull request as ready for review August 2, 2026 11:00
@thekidnamedkd
thekidnamedkd requested a review from a team as a code owner August 2, 2026 11:00
Added new permission constants for VeGovernance and linked accounts.

Signed-off-by: Evan Aronson <93671071+evanaronson@users.noreply.github.com>
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