Skip to content

Decompose App.tsx phase 3: collapse InspectorView's prop wall into domain bundles #2130

Description

@cliffhall

Phase 3 of #2126 — decomposing clients/web/src/App.tsx (5,270 lines).

<InspectorView> takes roughly 130 props, which is ~180 of App.tsx's 324 JSX lines. Group them into per-domain bundles so the JSX shows the component tree instead of a prop wall.

This is last and deliberately separate. It touches InspectorView, everything below it, and its stories — so it must not ride along with the Phase 2 hook extractions, where an unrelated prop rename would make a 400-line relocation impossible to review.

It is also genuinely optional. If Phases 0–2 land and this never does, App.tsx is already at ~700 lines and the parent's goal is met. Treat it as the finishing pass, not a dependency.

The current wall

The props arrive in obvious domain runs. Tools, for example, is spread across nine separate props:

tools={tools}
excludedTools={excludedTools}
toolsListChanged={toolsListChanged}
toolsLoadError={toolsPagination.error}
toolsUi={toolsUi}
onToolsUiChange={onToolsUiChange}
onCallTool={}
onRefreshTools={onRefreshTools}
toolsPagination={toolsPaginationControls}

Prompts, resources, tasks, logs, protocol, network, console, and apps follow the same shape. The server-list group (onServerAdd / onServerImportConfig / onServerImportJson / onServerEdit / onServerClone / onServerRemove / onServerReorder / onServerExport / onServerSettings) is another run, and several of those are inline arrow bodies in the JSX today.

The change

One prop per domain:

<InspectorView
  connection={connection}
  servers={serverList}
  tools={toolsPanel}
  prompts={promptsPanel}
  resources={resourcesPanel}
  apps={appsPanel}
  tasks={tasksPanel}
  logs={logsPanel}
  protocol={protocolPanel}
  network={networkPanel}
  console={consolePanel}
/>

The payoff compounds with Phase 2: a hook can then return exactly a prop bundle, so App.tsx stops assembling props at all and just forwards what a hook handed it. That is the difference between "shorter JSX" and "App.tsx no longer knows what InspectorView needs".

Do this in the same pass

Lift the inline arrow bodies out of the JSX. Several props are multi-line closures declared at the call site — onServerReorder carries a ~15-line .catch with a notifications.show, and onServerAdd / onServerImportConfig / onServerClone each clear the highlight before opening a modal. Those belong in whichever hook owns that domain (useServerListState), not in the tree.

Note the void-wrapping arrows (onToggleConnection, onCallTool, onGetPrompt, onReadResource, onOpenApp, onCancelTask, onDisconnect) exist because @typescript-eslint/no-floating-promises is at error. They can move into the bundles, but each still needs its one-line justification comment per the AGENTS.md rule — do not drop them into a bundle unexplained.

Risks

  • This is the phase most likely to cause churn below InspectorView. Decide up front whether the bundles stop at InspectorView (it destructures and passes down as before) or continue downward. Stopping at InspectorView is the cheaper, more reviewable choice and is the recommendation.
  • 96+ story files exist, and every screen and element component has one. A prop-shape change ripples into fixtures. Budget for it — and the Storybook play functions run headless in npm run ci, so breakage is loud rather than silent.
  • Keep the bundle types beside the components that consume them (components/**/types.ts is already excluded from the coverage include, so type-only modules do not distort the gate).

Coverage

Mostly type-level and prop-plumbing, so the incremental coverage cost is small — but any inline closure lifted out of the JSX lands in a gated hook and needs a test, and the story fixtures must be updated rather than deleted to make the gate pass.

Done when

  • InspectorView takes ~10 domain props instead of ~130
  • No multi-line closures remain in App.tsx's JSX
  • Stories and fixtures updated; test:storybook green
  • App.tsx JSX substantially shorter and the tree legible at a glance
  • No behavior change; npm run ci green

Metadata

Metadata

Assignees

Labels

choreMaintenance: deps, build tooling, CI, cleanup — no user-facing behavior changev2Issues and PRs for v2

Type

No type

Projects

No projects

Milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions