Skip to content

feat(cluster): explicit cluster home for connecting#1403

Open
dawsontoth wants to merge 21 commits into
claude/suspicious-joliot-b97cd5from
feat/cluster-landing-page
Open

feat(cluster): explicit cluster home for connecting#1403
dawsontoth wants to merge 21 commits into
claude/suspicious-joliot-b97cd5from
feat/cluster-landing-page

Conversation

@dawsontoth

@dawsontoth dawsontoth commented Jul 1, 2026

Copy link
Copy Markdown
Contributor

Stacked on #1400 (JWT direct-connect + #1333). Review/merge that first; this targets its branch so the diff stays scoped to the cluster/org UX.

What & why

Started as a fix for the connect-mode guessing behind #1333 and grew into a cohesive pass over the cluster and org navigation. Instead of the cluster card guessing a connection mode and the route guard auto-Fabric-Connecting, a dedicated cluster home owns the choice explicitly — and the surrounding cards/nav were brought in line with it.

Cluster home (connect choice) — #1333, #1398

  • ClusterHome is now the cluster index (/{org}/{clusterId}/); the in-cluster studio moved to /{org}/{clusterId}/apps. Hero with name/status/instance count, the host linkified (opens in a new tab) with a copy menu (Copy host name / Copy API URL).
  • Unconnected: a Fabric Connect / Direct sign-in picker with a green "Last used" pill (remembered via authStore.setLastConnectMode — a preference, not a secret), purple "Recommended" for first-timers.
  • Connected: a prominent "Enter cluster" card into the studio, with low-key switch/disconnect links.
  • Guards read live authStore rather than the lagging router-context snapshot (the root cause of the direct-sign-in clobber).

Full-card clickable cards — closes #1260

  • Org cards and cluster cards are now clickable across the whole card (stretched-link overlay), except a generous hit area around the menu; right-click still opens the context menu.
  • Reactive hover (subtle grow + ring color shift), plus hover states on the cluster card's copy button and the org card's . Cluster card's "Open →" is right-aligned.

Sub-nav rails (Config-page paradigm)

  • Org page gets a responsive left rail (dropdown when narrow): Clusters / Users / Roles / Billing (→ Payment Method, Invoices) / Settings — pulling Users/Roles/Billing out of the global header into the org, permission-gated. Global header slimmed to Docs/Profile/theme/Sign out.
  • Cluster gets a matching persistent rail: Overview / Scaling / Version / Domains / Instances, gated by cluster permissions. Scaling → /edit, Version → /edit/version (both exact so they don't cross-highlight); editing scaling/version keeps the rail.
  • Cluster "Filter by name" moved into the list frame as a full-width underline input (no background pill).

Design decisions (agreed while building)

  • Cluster home is the index; cluster-level connect scope; "Last used" green pill over static "Recommended".
  • Shared layout components (SubNavRail, OrgPageLayout, ClusterPageLayout) rendered per page, rather than restructuring the route tree — keeps getParentRoute/addChildren in lockstep per CLAUDE.md (router-matching regression test stays green).
  • Single-cluster orgs intentionally do not auto-skip the org page — the enriched details are worth landing on.

Verification

Typecheck, lint, format, full suite (1036 passing) incl. the router-matching regression test. Browser-verified on a live authenticated dev server across cluster / instance / local-studio modes: index promotion, card clickability, both rails and their active states, the connect picker, and the host copy menu.

Closes #1260
Refs #1398, #1333

🤖 Generated with Claude Code

First cut of the cluster landing page (stacked on the JWT/direct-connect work).
Instead of the cluster card guessing a connection mode and the route guard
auto-Fabric-Connecting, a dedicated home page owns the choice.

- ClusterHome: hero + status, a Fabric Connect / Direct sign-in picker when
  unconnected, connected status with switch/disconnect, and a "Manage" grid
  (Instances, Databases, Scaling, Domains) that surfaces the buried ⋯ actions.
- The last chosen mode is remembered (authStore.setLastConnectMode, persisted)
  and highlighted with a green "Last used" pill; first-timers see "Recommended"
  on Fabric Connect.
- Mounted at /{org}/{clusterId}/home (safe sibling route — keeps getParentRoute
  and addChildren in lockstep). The cluster card now just opens the home rather
  than guessing Fabric/Direct/Direct Sign In.

Follow-up (needs browser validation): promote the home to the cluster index and
move the instance dashboard behind the Databases tile; redirect unconnected
deep-links to the home instead of auto-connecting.

Refs #1398

@gemini-code-assist gemini-code-assist Bot 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.

Code Review

This pull request introduces a new cluster landing page (ClusterHome) that centralizes the connection options (Fabric Connect and Direct sign-in) and displays the cluster's connection status and management options. It also adds persistence for the last used connection mode in localStorage to highlight it on subsequent visits. The feedback focuses on enhancing security during disconnects by fully clearing local authentication flags, handling permission checks before redirecting users to setup pages when a password reset is required, and adding appropriate size classes to the ArrowRight and Loader2 icons to ensure consistent UI rendering.

Comment thread src/features/cluster/ClusterHome.tsx
Comment thread src/features/cluster/ClusterHome.tsx
Comment thread src/features/cluster/ClusterHome.tsx Outdated
Comment thread src/features/cluster/ClusterHome.tsx
dawsontoth and others added 19 commits July 1, 2026 15:15
The home rendered directly under clusterLayoutRoute (a bare Outlet), so its
hero sat behind the fixed 80px app header. Add the standard cluster sub-nav
breadcrumb bar (fixed top-20) + mt-32 content offset, matching the sign-in page.
The "Open" action is now the full card via a stretched link to the cluster
home, with a generous 40x40 hit area for the ⋯ menu (lifted above the overlay
with stopPropagation so it opens the menu instead of navigating). Right-click
still opens the context menu (unchanged — the card is wrapped in
EntityContextMenu). Edge states (no FQDN → Instances, resetPassword → Finish
Setup / Pending Owner Setup) keep their own explicit CTA and aren't full-card.
The purple accents used --primary (#403b8a), a dark purple that nearly
disappears on the dark card/grey-700 surfaces (icon vs card ~1.2:1). Keep
--primary on light and switch to a bright violet-300/400 on dark for the hero,
tile, and connect-option icons, the "Recommended" pill, and its border.
The cluster home is now the cluster index (/{org}/{clusterId}) — clicking the
cluster in the breadcrumb lands on it, and there's no more "Home" crumb. The
within-cluster tabs move under it:
- /{org}/{clusterId}        → ClusterHome (no instance nav chrome)
- /{org}/{clusterId}/apps   → Applications (was the index)
- /{org}/{clusterId}/databases, /status, /logs, /config, /apis

Applications only re-paths to /apps in cluster mode; local and instance modes
keep it at the index (verified both still resolve), so local studio is
unaffected. The Apps nav tab and ClusterHome's Enter/Databases links point at
the new paths; the cluster card opens the index.

Also make the cards reactive: cluster cards and the home's Manage tiles grow
slightly and shift border/background on hover.

Refs #1398
The content offset (mt-32 = 128px) landed exactly at the fixed breadcrumb bar's
bottom (128px), so the hero icon/name abutted the breadcrumbs. Bump to mt-40 for
a 32px gap.
Apply the same hover reactivity to org cards as cluster cards: grow slightly,
lift (shadow), and shift color. Since Card uses a ring (not a border), the
earlier hover:border-primary was invisible — switch both org and cluster cards
to hover:ring-2 hover:ring-primary/60 (dark: violet-400) so the color shift
actually shows.
- Org cards get the same stretched-link treatment as cluster cards: the whole
  card opens the org, with the ⋯ menu lifted above the overlay (z-10 +
  stopPropagation) and right-click still opening the context menu. "View"
  becomes a visual affordance; update its test to find the card link by role.
- Right-align the cluster card's "Open" action (ml-auto).
The cluster card's copy-to-clipboard control was a bare icon with no hover
feedback — wrap it in a button with a rounded bg/text hover, matching the
cluster ⋯ menu. Give the org card's ⋯ trigger the same rounded bg hover instead
of a text-only color change, so both cards' controls feel consistent.
Adds an OrgPageLayout shell with a responsive org sub-nav (left rail on desktop,
dropdown when small) — Clusters, Users, Roles, Billing, Settings — gated by the
same permissions the org card menu uses. Wraps the five org-level pages
(clusters list, users, roles, billing, settings) so those sections are
discoverable from the org page itself, mirroring the instance Config pattern.

With that in place, remove Organizations (it's in the breadcrumbs) and
Roles / Users / Billing (now in the org sub-nav) from the global header; Profile,
Docs, Report an Issue, Discord, and Sign Out stay.

Routing is unchanged — the shell is a shared component each page renders, not a
route layout — so there's no risk to param matching.
Pull "Filter by name" out of the breadcrumb bar and into the top of the cluster
list content (a light search input above the grid, list bumped down). The
breadcrumb bar keeps only the New Cluster action.
Give the org sub-nav support for nested items that expand under the active
section. Billing now expands to Payment Method / Invoices and Payments in the
rail, so its own two-column inner nav is removed — the billing page just hosts
the active sub-page. Sub-items expand on desktop and in the mobile dropdown.
Drop the pill (no background/border/rounding, incl. the dark:bg override) and
make "Filter by name" a full-width underlined input across the list.
Extract the responsive sub-nav (left rail on desktop, dropdown when small, with
expandable sub-items) into a shared SubNavRail so the org and cluster layouts
use the same plumbing. Add ClusterPageLayout with an Overview / Instances /
Scaling / Domains rail (permission-gated; domains hides for self-managed) and
apply it across those cluster-scoped pages so the rail persists — the in-cluster
studio (apps, databases, …) keeps its own top nav.

The cluster home now renders inside the rail (its old horizontal "Manage" tiles
are gone — the rail replaces them); Instances, Scaling, and Domains adopt it too
(StartingUp stays plain — nothing to manage pre-provision).
- Make the connected-state "Enter cluster" a big accented card (rocket + what's
  inside), drop the status banner to a one-line label, and demote Disconnect /
  Direct sign out to a quiet text link.
- Point the Scaling rail item at /edit (the cluster editor) to match the card's
  "Edit Scaling", instead of the /scaling update-progress screen.
Turn the cluster's host on the home page into a link (opens https://host) and
add a copy button beside it with "Copy host name" and "Copy API URL", so both
are reachable from the home like they are on the cluster card.
UpsertCluster keeps the plain layout for new clusters, but wraps the edit and
edit-version cases in ClusterPageLayout so the cluster sub-nav rail persists
while editing scaling or version (new-cluster has no cluster context, so no rail).
Adds a Version item (→ /edit/version) beside Scaling in the cluster rail so
the version editor is reachable directly. Both Scaling (/edit) and Version
(/edit/version) are now exact matches so /edit/version doesn't also light up
Scaling. Gated like Domains: manage permission and not self-managed.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@dawsontoth dawsontoth marked this pull request as ready for review July 1, 2026 21:01
@dawsontoth dawsontoth requested a review from a team as a code owner July 1, 2026 21:01
Addresses PR review on ClusterHome:
- onDisconnect now clears the Fabric Connect flag and Basic Auth credentials
  from localStorage even when the logout POST fails (previously the swallowed
  error left them behind).
- reset-password clusters no longer redirect view-only members into the
  finish-setup flow they can't complete; they see a Pending Owner Setup
  message instead, matching ClusterCardAction.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.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.

1 participant