Files
offscale/web/OffscaleServerPicker.tsx
pastilhas 58fbf12e4b the picker's register link opens the form
reported as "I click register a server and nothing happens", and nothing was broken. three controls on
that screen carry the label. two are buttons that open the form; the one in the server picker — top left,
where you look first — was a plain <Link> to the servers section.

/offscale and /offscale/servers render the same view (useOffscaleSection defaults to servers when there is
no param), so from either one the click navigated to something identical. the URL moved and nothing else
did, and the only visible result was a second button with the same label further down the page.

so the link now carries ?register=1 and ServersView consumes it. the flag is stripped with replace on the
way in, which is not tidiness: left in the URL, closing the form and clicking the picker again would be a
navigation to the URL already showing, and nothing would happen — the same bug, restored.

ServersView.test.tsx pins all three: the form opens on arrival, the flag is consumed, and no flag means no
form. removing the effect fails the first two.
2026-08-17 12:58:47 +00:00

65 lines
3.0 KiB
TypeScript

import { Check, Network, Plus } from 'lucide-react';
import { Link } from 'react-router';
import { offscaleRegisterPath } from './shared';
import { useOffscaleServers } from './useOffscaleServers';
// Top-left panel of the /offscale workspace: which server everything else acts on.
//
// It is its own panel rather than a block inside OffscaleNav because the two answer different questions —
// "which server" and "which section" — and only one of them is navigation. Activating a server is a mutation
// (a DB write that re-scopes every other query), so these stay buttons with no URL of their own, while the
// section list below is real links.
//
// Every registered server is listed, including when there is only one: the panel's whole job is to say what
// the rest of the screen is talking to, and a picker that hides itself at one server makes that invisible.
export const OffscaleServerPicker = () => {
const { servers, active, activate, isLoading } = useOffscaleServers();
return (
<div className="flex h-full flex-col overflow-y-auto bg-muted/30">
<div className="flex items-center gap-3 px-4 py-4">
<div className="flex h-9 w-9 items-center justify-center rounded-xl bg-indigo-500/15 text-indigo-400 ring-1 ring-black/5">
<Network className="h-5 w-5" />
</div>
<div className="min-w-0">
<div className="truncate text-sm font-semibold leading-tight">Offscale</div>
<div className="truncate text-xs text-muted-foreground">{active ? active.name : 'no server'}</div>
</div>
</div>
<div className="flex flex-col gap-0.5 px-2 pb-3">
{servers.map((server) => (
<button
key={server.id}
type="button"
onClick={() => !server.isActive && activate.mutate(server.id)}
disabled={activate.isPending}
title={server.url}
className={`flex items-center gap-2 rounded-lg px-3 py-1.5 text-left text-xs transition-colors ${
server.isActive ? 'bg-muted font-medium text-foreground' : 'text-muted-foreground hover:bg-muted'
}`}
>
<Check className={`h-3.5 w-3.5 shrink-0 ${server.isActive ? 'text-primary' : 'opacity-0'}`} />
<span className="min-w-0 flex-1 truncate">{server.name}</span>
</button>
))}
{/* Goes to the Servers section AND opens the form. A link to the section alone was a no-op from the
place you are most likely to be standing: `/offscale` and `/offscale/servers` render the same
view, so the navigation was invisible and the only visible result was a second button with the
same label. */}
{servers.length === 0 && !isLoading && (
<Link
to={offscaleRegisterPath()}
className="flex items-center gap-2 rounded-lg px-3 py-1.5 text-xs text-muted-foreground transition-colors hover:bg-muted hover:text-foreground"
>
<Plus className="h-3.5 w-3.5 shrink-0" />
Register a server
</Link>
)}
</div>
</div>
);
};