NodeUI Refactor Notes
This refactor split the Harbor NodeUI monolith into an app shell, page-level feature modules, and shared helpers without intentionally changing user-facing behavior.
NodeUI Refactor Notes
Summary
This refactor split the Harbor NodeUI monolith into an app shell, page-level feature modules, and shared helpers without intentionally changing user-facing behavior.
The primary goal was to stop apps/harbor-ui/src/App.tsx from being the render wall and navigation/controller surface for the entire app.
What moved where
App shell
- now only re-exports the real app entrypoint
- top-level app bootstrap
- shell layout and page composition
- top navigation and page switching UI
- shared success/error/banner rendering
- page switch registry
- controller context boundary for feature pages
apps/harbor-ui/src/App.tsxapps/harbor-ui/src/app/App.tsxapps/harbor-ui/src/app/AppShell.tsxapps/harbor-ui/src/app/TopNav.tsxapps/harbor-ui/src/app/GlobalBanners.tsxapps/harbor-ui/src/app/pageRegistry.tsxapps/harbor-ui/src/app/AppControllerContext.tsx
Shared helpers
- Harbor client creation and node-target auth wiring
- display formatting, labels, Dock sync text, plan text
- managed node target normalization and status helpers
apps/harbor-ui/src/shared/api/createClient.tsapps/harbor-ui/src/shared/lib/formatters.tsapps/harbor-ui/src/shared/lib/nodeTargets.ts
Feature pages
apps/harbor-ui/src/features/home/HomePage.tsxapps/harbor-ui/src/features/manager/ManagerPage.tsxapps/harbor-ui/src/features/ports/PortsPage.tsxapps/harbor-ui/src/features/ports/PortWorkspacePage.tsxapps/harbor-ui/src/features/fleet/FleetPage.tsxapps/harbor-ui/src/features/executions/ExecutionsPage.tsxapps/harbor-ui/src/features/audit/AuditPage.tsxapps/harbor-ui/src/features/security/SecurityPage.tsxapps/harbor-ui/src/features/settings/SettingsPage.tsxapps/harbor-ui/src/features/plan/PlanPage.tsx
Ports feature split
The ports workflow is now explicitly divided into a list/create surface and a selected-port workspace surface.
- composes: - components/PortTools.tsx - components/PortList.tsx - components/AddPortPanel.tsx
- composes: - components/PortSummarySection.tsx - components/LiveActionsSection.tsx - components/ActionDetailsSection.tsx - components/ExecuteActionSection.tsx - components/ApprovalsSection.tsx - components/DraftWorkspaceSection.tsx - components/DraftListSection.tsx - components/LatestDockImportSection.tsx
- owns the ports list/workspace state, Dock sync state, OAuth polling, action execution inputs, draft authoring flow, and port mutation handlers
- owns agent profile/token state, profile detail loading, override editing, token filtering, and security actions
- owns manager config/policy state, managed-worker inventory, bootstrap flows, and manager action handlers
- owns audit filtering, selected event state, approval detail state, and approval resolution flow
- owns Fleet enrollment state, pairing inputs, managed-target state, and cloud enrollment actions
- owns local config draft state, operator-auth/session flows, remote access key management, notification filters, and backup export actions
- owns execution filters, selected execution state, delivery loading, cancellation, and execution refresh behavior
- owns Dock catalog shelf state, featured/newest/trending entry lists, and Hub refresh behavior
- owns cloning/reset helpers for node-local config drafts used by Settings and Executions
apps/harbor-ui/src/features/ports/PortsPage.tsxapps/harbor-ui/src/features/ports/PortWorkspacePage.tsxapps/harbor-ui/src/features/ports/usePortsDomain.tsapps/harbor-ui/src/features/security/useSecurityDomain.tsapps/harbor-ui/src/features/manager/useManagerDomain.tsapps/harbor-ui/src/features/audit/useAuditDomain.tsapps/harbor-ui/src/features/fleet/useFleetDomain.tsapps/harbor-ui/src/features/settings/useNodeSettingsDomain.tsapps/harbor-ui/src/features/executions/useExecutionsDomain.tsapps/harbor-ui/src/features/dock/useDockCatalogDomain.tsapps/harbor-ui/src/shared/lib/nodeConfig.ts
Feature-local helpers
apps/harbor-ui/src/features/home/homeUtils.tsapps/harbor-ui/src/features/security/securityUtils.tsapps/harbor-ui/src/features/ports/portUtils.ts
Intentional deviations from the original target shape
- The page-oriented architecture is in place, but cross-page coordination still flows through
apps/harbor-ui/src/app/useAppController.tsx. ports,security,manager,audit,fleet,settings,executions, anddocknow own their state/handlers in feature-domain hooks and are composed by the app controller.- Page hooks such as
usePortsPage,usePortWorkspace,useManagerPage, anduseSecurityPageare still adapters over the shared controller boundary rather than independent per-page providers. - I kept the existing class names and page flow instead of trying to normalize layout patterns during the same pass.
Technical debt left behind
apps/harbor-ui/src/app/useAppController.tsxis still the main cross-page coordinator for node targeting, overview refresh, polling, and shared derived view models, even though it is now down to roughly 1.3k lines instead of being the full monolith.- Some page hooks are still thin wrappers and can be deepened later into real feature controllers or narrowed selectors.
- Cross-feature refresh behavior still routes through the shared controller, even though most domain logic now lives with the features that own it.
Suggested next refactor targets
- Move more feature-specific refresh/load logic closer to each domain hook so the top-level controller only owns cross-page concerns.
- Narrow the page hooks from full-context adapters into feature-shaped selectors once the remaining controller domains are split.
- Apply the same feature-domain/controller pattern to the other apps after validating the Harbor UI layout over a few commits.
Validation
pnpm --filter @harbor/harbor-ui typecheckpnpm --filter @harbor/harbor-ui buildpnpm --filter @harbor/harbor-ui lintpnpm -r build
The current lint script is intentionally lightweight in this milestone, so TypeScript and the production build remain the main correctness checks.