Skip to content

fix(frontend): restore engine flavor actor navigation after top bar redesign#5242

Open
NicholasKissel wants to merge 1 commit into
mainfrom
NicholasKissel/fix-local-inspector
Open

fix(frontend): restore engine flavor actor navigation after top bar redesign#5242
NicholasKissel wants to merge 1 commit into
mainfrom
NicholasKissel/fix-local-inspector

Conversation

@NicholasKissel

Copy link
Copy Markdown
Member

Problem

The local inspector (rivet-engine at localhost:6420/ui) is unusable when the route can't auto-select an actor instance. It dead-ends on "No Actor Name selected. Select an Actor Name from the list on the left." with no list anywhere on the page.

The top bar redesign (#5064) removed the old left sidebar and gave the cloud flavor replacements (the ActorsGrid namespace landing + breadcrumb segment popovers), but the engine flavor never got them:

  • The engine /ns/$namespace/ index route still auto-redirected into the first build's first actor and fell through to a dead-end empty state when there was none.
  • ActorsGrid unconditionally called useCloudNamespaceDataProvider(), which throws outside the cloud route tree, so it couldn't be reused.
  • The top bar's namespace dropdown opened an empty popover on engine routes (its content requires an organization param), and the actor-name breadcrumb segment never rendered for the engine match.

Fix

Mirror the cloud flavor in the engine flavor:

  • routes/_context/ns.$namespace/index.tsx — render the ActorsGrid landing when no actor name is selected (with a skeleton pending component), and only auto-select the first instance of the selected name. This also fixes a latent bug where selecting a name redirected into the first build's actor instead of the selected one.
  • app/actors-grid.tsx — make the grid engine-safe: move the managed-pool Logs button and the Deployments section behind features.compute wrappers so cloud-only data provider hooks never mount in the engine flavor.
  • app/context-switcher.tsx — add an engine branch to the inline context switcher: a namespace segment popover (find/switch/create, backed by the engine data provider, preserving the leaf route and clearing the namespace-scoped actor selection) plus the existing ActorBreadcrumbSegment.
  • components/actors/actors-list.tsx — replace the stale "list on the left" copy with a "Browse Actor Names" button that navigates to the grid landing.

Verification

Stood up the engine flavor end-to-end (published rivet-engine binary on 6420, rivetkit fixture app registering counter with 2 instances and chatRoom with 0, dev server in engine flavor, driven by Playwright):

  • Landing at /ns/default shows the grid with both actor names.
  • Clicking chatRoom (zero instances — the previously broken case) shows the "No actors created" quickstart instead of the dead-end.
  • Clicking counter auto-opens its first instance.
  • Top bar Default / counter popovers both work (namespace list was previously an empty box).
  • pnpm check-types passes, biome findings on touched files are identical to main, and the production build:engine embedded build compiles.

🤖 Generated with Claude Code

@railway-app

railway-app Bot commented Jun 12, 2026

Copy link
Copy Markdown

🚅 Deployed to the rivet-pr-5242 environment in rivet-frontend

Service Status Web Updated (UTC)
website 😴 Sleeping (View Logs) Web Jun 12, 2026 at 9:48 pm
kitchen-sink ❌ Build Failed (View Logs) Web Jun 12, 2026 at 9:46 pm
frontend-inspector ❌ Build Failed (View Logs) Web Jun 12, 2026 at 9:40 pm
frontend-cloud ❌ Build Failed (View Logs) Web Jun 12, 2026 at 9:39 pm
ladle ❌ Build Failed (View Logs) Web Jun 12, 2026 at 9:39 pm
mcp-hub ✅ Success (View Logs) Web Jun 12, 2026 at 9:38 pm

@claude

claude Bot commented Jun 12, 2026

Copy link
Copy Markdown
Contributor

Code Review

PR: fix(frontend): restore engine flavor actor navigation after top bar redesign

This PR correctly fixes the local inspector (rivet-engine at localhost:6420/ui) that became unusable after the top-bar redesign in #5064. The approach — mirroring the cloud flavor's actor grid landing page in the engine flavor, adding a namespace segment popover, and replacing the dead-end copy with an actionable button — is sound.


Correctness / Potential Bugs

NamespaceLogsButton unconditionally calls useCloudNamespaceDataProvider() (medium)

The component is only mounted inside {features.compute ? <NamespaceLogsButton /> : null}, which is safe because features.compute is a build-time constant. However the component body itself has no guard, so if this component were ever used outside that gate (copy-paste, future refactor), it would silently call a cloud-only hook in the engine flavor. The pattern established by DeploymentsSectionInner — wrapping the entire mount in a DeploymentsSection parent that checks the flag before rendering — is more defensive. Adding if (!features.compute) return null; at the top of NamespaceLogsButton would be belt-and-suspenders.

data?.sort() mutates the useInfiniteQuery select result in-place (low)

EngineNamespaceList calls data?.sort(...) inline. namespacesQueryOptions's select produces a new array via flatMap, so this does not currently corrupt the TanStack Query cache. But it is fragile: if select is ever changed to return a stable reference, this would corrupt cached data silently. The correct form (used in the pre-existing ActorSegmentPopover and ActorsList) is [...(data ?? [])].sort(...). Note this same issue exists in the pre-existing ProjectList and NamespaceList — it predates this PR.

Loader early-exit skips actorKey check (very low / pre-existing)

In ns.$namespace/index.tsx: if (deps.n && actorId) { await runnerPrefetch; return; } — if a URL has n set but uses actorKey instead of actorId, the early-return is bypassed and the loader may issue a redirect that overwrites actorKey with an actorId. This is the same asymmetry as the cloud counterpart — not a regression, but worth noting.


Code Quality / Style

Duplicated search-extraction block between RouteComponent and PendingComponent

Both components in ns.$namespace/index.tsx independently extract actorId, actorKey, n, and hasSelection from search. The cloud variant avoids this via a shared NamespaceContent inner component. A useNamespaceSearch() helper or shared inner component would reduce the drift.

PendingComponent returns null when hasSelection is true

The cloud counterpart renders a skeleton during pending transitions even when an actor is selected. The engine variant returns null, leaving no loading UI during namespace transitions. Actors has internal loading states so there is no blank screen, but it is an intentional asymmetry.

Unsafe as Record<string, unknown> cast on Route.useSearch()

This bypasses TanStack Router's typed search params — a pattern that exists in the cloud index route too, but is a candidate for cleanup when the route search schema is tightened.


Architecture / Convention Compliance

Correct feature flag gating ✓ — DeploymentsSectionInner is only mounted when features.compute is true, preventing cloud-only hooks from running in the engine flavor.

Loader prefetch logic is correct ✓ — When n[0] is absent (grid landing), the loader prefetches currentNamespaceQueryOptions() so NamespaceLanding's useSuspenseQuery does not block. When n[0] is present, NamespaceLanding is not mounted, so the omitted prefetch is correct.

Breadcrumb slash separator ✓ — ActorBreadcrumbSegment renders its own leading slash icon, so the engine breadcrumb reads Default / counter correctly.

"New Namespace" button wiring ✓ — Navigating to modal: "create-ns" is handled at the _context.tsx / EngineModals level.


Summary

The fix is correct and ready to merge. The items above are either low-risk edge cases or style inconsistencies inherited from surrounding pre-existing code, none of which are blockers.

Priority follow-ups (can be separate PRs):

  1. Use [...(data ?? [])].sort(...) in EngineNamespaceList (and pre-existing ProjectList/NamespaceList) to avoid fragile in-place sort.
  2. Extract the search-param block into a shared helper to reduce duplication between RouteComponent and PendingComponent.

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.

1 participant