Rename Installation to Instance
Follows the portal: the noun is "instance" everywhere the app says it — UI strings, CLI output, error details, docs and comments. The wire keys (`instance_id`, `instance_token`) and the hub route this calls move with it. An existing cloud.json is adopted rather than refused: without the key alias the dataclass fails to parse, which the caller swallows and reads as "never enrolled" instead of "reconnect". `instance_key` on a node type becomes `target_key`. It means the outside thing a node points at, which is a different sense of the word, and keeping both would put two meanings of "instance" in one codebase. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_015YrQnKV3bnQd4K342y8tKj
This commit is contained in:
@@ -9,7 +9,7 @@ import { isPortal } from "@/lib/portal"
|
||||
const ID = "connection-offline"
|
||||
|
||||
/**
|
||||
* Says when the installation cannot be reached, and when it was last heard
|
||||
* Says when the instance cannot be reached, and when it was last heard
|
||||
* from.
|
||||
*
|
||||
* Only ever meaningful under a portal: a local install cannot lose contact with
|
||||
@@ -39,8 +39,8 @@ export function ConnectionNotice() {
|
||||
}
|
||||
notify(
|
||||
connection.lastSeen
|
||||
? `Installation offline — last seen ${ago(connection.lastSeen / 1000)}, reconnecting…`
|
||||
: "Installation offline — reconnecting…",
|
||||
? `Instance offline — last seen ${ago(connection.lastSeen / 1000)}, reconnecting…`
|
||||
: "Instance offline — reconnecting…",
|
||||
"warning",
|
||||
{ id: ID, persistent: true },
|
||||
)
|
||||
|
||||
@@ -19,8 +19,8 @@ const DEFAULT_COLUMNS = 12
|
||||
* How many tiles are worth a request of their own.
|
||||
*
|
||||
* ponytail: the list endpoint carries no placements, so a footprint means
|
||||
* reading that dashboard's document — cheap for the handful an installation
|
||||
* has, and shared with the editor's own cache. The ceiling is an installation
|
||||
* reading that dashboard's document — cheap for the handful an instance
|
||||
* has, and shared with the editor's own cache. The ceiling is an instance
|
||||
* with dozens: the tiles past this show their name and nothing else, and the
|
||||
* fix would be a stored footprint on `DashboardSummary`.
|
||||
*/
|
||||
|
||||
@@ -58,7 +58,7 @@ function hint(entry: SearchEntry): string {
|
||||
}
|
||||
|
||||
/**
|
||||
* Everything in this installation, by name, from anywhere.
|
||||
* Everything in this instance, by name, from anywhere.
|
||||
*
|
||||
* The whole index arrives in one fetch and `cmdk` does the matching, so results
|
||||
* narrow as they are typed without a round trip per keystroke.
|
||||
@@ -190,7 +190,7 @@ export function GlobalSearch({
|
||||
</>
|
||||
) : (
|
||||
<p className="py-6 text-center text-sm text-muted-foreground">
|
||||
Start typing to search this installation.
|
||||
Start typing to search this instance.
|
||||
</p>
|
||||
)}
|
||||
</CommandList>
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
*
|
||||
* A single stack at the top centre, over whatever is below it. Newest on top,
|
||||
* each card going on its own after a few seconds unless it was raised as
|
||||
* persistent — an offline notice stays until the installation answers again.
|
||||
* persistent — an offline notice stays until the instance answers again.
|
||||
*
|
||||
* Raised from anywhere through `notify()` in `lib/notificationStore`, which is
|
||||
* where the semantics live; this only draws them.
|
||||
|
||||
@@ -303,10 +303,10 @@ export function ConfirmDelete({
|
||||
<DialogDescription>
|
||||
{description ?? (
|
||||
<>
|
||||
{names.length === 1 ? "It goes" : "They go"} from the
|
||||
installation at once. The store's git history keeps what was
|
||||
there, but nothing in the app brings{" "}
|
||||
{names.length === 1 ? "it" : "them"} back.
|
||||
{names.length === 1 ? "It goes" : "They go"} from the instance
|
||||
at once. The store's git history keeps what was there, but
|
||||
nothing in the app brings {names.length === 1 ? "it" : "them"}{" "}
|
||||
back.
|
||||
</>
|
||||
)}
|
||||
</DialogDescription>
|
||||
|
||||
@@ -51,7 +51,7 @@ export function PanelsDialog() {
|
||||
const { data: config } = useQuery(panelsQueryOptions())
|
||||
const { data: dashboards } = useQuery(dashboardsQueryOptions())
|
||||
const { user } = useAuth()
|
||||
// Where a screen that cannot reach this installation pairs instead. The
|
||||
// Where a screen that cannot reach this instance pairs instead. The
|
||||
// issuer is the portal as a browser reaches it, which is not always the
|
||||
// address this machine dialled — enrolment may have named a container.
|
||||
const { data: cloud } = useQuery({
|
||||
@@ -60,12 +60,12 @@ export function PanelsDialog() {
|
||||
(await CloudService.readStatus()) as {
|
||||
enrolled: boolean
|
||||
issuer: string | null
|
||||
installation_id: string | null
|
||||
instance_id: string | null
|
||||
},
|
||||
})
|
||||
const remoteHost =
|
||||
cloud?.enrolled && cloud.issuer && cloud.installation_id
|
||||
? `${cloud.issuer.replace(/\/$/, "")}/i/${cloud.installation_id}`
|
||||
cloud?.enrolled && cloud.issuer && cloud.instance_id
|
||||
? `${cloud.issuer.replace(/\/$/, "")}/i/${cloud.instance_id}`
|
||||
: ""
|
||||
const save = useSavePanels()
|
||||
const { showErrorToast } = useCustomToast()
|
||||
@@ -75,7 +75,7 @@ export function PanelsDialog() {
|
||||
|
||||
const panels = config?.panels ?? []
|
||||
const known = dashboards?.data ?? []
|
||||
// The installation's own address, not this browser's: administering through
|
||||
// The instance's own address, not this browser's: administering through
|
||||
// the portal puts the page on the portal's origin, and a screen cannot be
|
||||
// sent there — it has no portal session and could not hold a panel
|
||||
// credential if it had one.
|
||||
@@ -98,7 +98,7 @@ export function PanelsDialog() {
|
||||
<DialogTitle>Panels</DialogTitle>
|
||||
<DialogDescription>
|
||||
A panel is one screen and the dashboards it shows. Point the device at
|
||||
a link and it asks for a code you enter here — this installation's own
|
||||
a link and it asks for a code you enter here — this instance's own
|
||||
address for a screen on your network, or the portal's for one hanging
|
||||
where this machine is not reachable.
|
||||
</DialogDescription>
|
||||
@@ -187,9 +187,9 @@ function PanelRow({
|
||||
onRemove,
|
||||
}: {
|
||||
panel: PanelDef
|
||||
/** Where this installation answers, as it knows itself. */
|
||||
/** Where this instance answers, as it knows itself. */
|
||||
host: string
|
||||
/** Where the portal serves this installation, when it is enrolled. */
|
||||
/** Where the portal serves this instance, when it is enrolled. */
|
||||
remoteHost: string
|
||||
/**
|
||||
* Whether this account may change anything here. Every control below saves
|
||||
@@ -335,7 +335,7 @@ function PanelRow({
|
||||
<Input
|
||||
readOnly
|
||||
value={link}
|
||||
placeholder="This installation has no address set"
|
||||
placeholder="This instance has no address set"
|
||||
aria-label={`Link for ${panel.id}`}
|
||||
className="text-muted-foreground"
|
||||
onFocus={(event) => event.currentTarget.select()}
|
||||
|
||||
@@ -854,7 +854,7 @@ function ParamsForm({
|
||||
* How much of a machine this node takes, and how long it is expected to take.
|
||||
*
|
||||
* A named size is the usual answer: what "gpu-small" means is a property of the
|
||||
* machines this installation has, and those change. The numbers are still there
|
||||
* machines this instance has, and those change. The numbers are still there
|
||||
* for a node that genuinely wants its own.
|
||||
*/
|
||||
function ResourcesSection({
|
||||
|
||||
@@ -100,7 +100,7 @@ export function useParamSuggestions(
|
||||
staleTime: SUGGEST_STALE,
|
||||
})
|
||||
// ponytail: reads every flow to collect them, sharing the editor's own cache
|
||||
// entries; an aggregate endpoint if a big installation makes that hurt.
|
||||
// entries; an aggregate endpoint if a big instance makes that hurt.
|
||||
const details = useQueries({
|
||||
queries: (type ? (flows?.data ?? []) : []).map((flow) => ({
|
||||
...flowQueryOptions(flow.name),
|
||||
|
||||
@@ -32,7 +32,7 @@ type FlowEvent =
|
||||
nodes: { id: string; status: string; error?: string | null }[]
|
||||
paused?: string[]
|
||||
logs?: LogLine[]
|
||||
/** Emission counts per qualified node. Absent on older installations. */
|
||||
/** Emission counts per qualified node. Absent on older instances. */
|
||||
emits?: Record<string, number>
|
||||
}
|
||||
| {
|
||||
@@ -194,7 +194,7 @@ function connect() {
|
||||
liveStore.setStatuses(message.nodes ?? [])
|
||||
liveStore.setPausedFlows(message.paused ?? [])
|
||||
liveStore.setLogs(message.logs ?? [])
|
||||
// Missing against an installation older than this bundle; the graph
|
||||
// Missing against an instance older than this bundle; the graph
|
||||
// then starts from zero the way it always did.
|
||||
liveStore.setEmits(message.emits ?? {})
|
||||
break
|
||||
@@ -321,7 +321,7 @@ function connect() {
|
||||
const payload = JSON.parse(event.data)
|
||||
if (payload?.type === "batch") {
|
||||
// A cascade publishes a dozen events at once and the engine coalesces
|
||||
// them into one frame. An installation older than this bundle sends
|
||||
// them into one frame. An instance older than this bundle sends
|
||||
// them one at a time, which is the branch below.
|
||||
for (const message of payload.events ?? []) handle(message)
|
||||
} else {
|
||||
@@ -347,7 +347,7 @@ function connect() {
|
||||
return
|
||||
}
|
||||
}
|
||||
// 1013 is the portal saying the installation is not attached — the one
|
||||
// 1013 is the portal saying the instance is not attached — the one
|
||||
// close code that means "offline" rather than "the socket dropped".
|
||||
if (event.code === 1013) {
|
||||
connectionStore.setOffline(null)
|
||||
|
||||
@@ -75,7 +75,7 @@ export function HealthOverview({
|
||||
const queue = (summary?.queue ?? {}) as Record<string, number>
|
||||
const degraded = summary?.status === "degraded"
|
||||
const errors = (flows ?? []).reduce((total, row) => total + row.errors, 0)
|
||||
// An installation nobody has run a batch flow on has no runs tile at all —
|
||||
// An instance nobody has run a batch flow on has no runs tile at all —
|
||||
// the same "nothing has been run yet" the Runs screen itself goes by.
|
||||
const running = (runs ?? []).reduce((total, row) => total + row.running, 0)
|
||||
const queued = (runs ?? []).reduce((total, row) => total + row.queued, 0)
|
||||
|
||||
@@ -23,7 +23,7 @@ const GRACE = 3000
|
||||
* stop pulsing and the values stop changing, with nothing to say why. Nothing
|
||||
* at all while the socket is up: a page that works needs no chip saying so.
|
||||
*
|
||||
* Quiet too while the offline notification is up, since an installation that cannot
|
||||
* Quiet too while the offline notification is up, since an instance that cannot
|
||||
* be reached has no socket either and one explanation of that is enough. Named
|
||||
* in words rather than coloured, and deliberately not terracotta: the brain
|
||||
* graph above it already owns that accent for a flow that cannot run.
|
||||
|
||||
@@ -33,7 +33,7 @@ import { type Item, Main } from "./Main"
|
||||
/**
|
||||
* Where the documentation is published.
|
||||
*
|
||||
* A constant rather than something derived: an installation reached over a LAN
|
||||
* A constant rather than something derived: an instance reached over a LAN
|
||||
* address, or at localhost, has no domain to build this from, and the docs are
|
||||
* one site for all of them.
|
||||
*/
|
||||
@@ -70,13 +70,13 @@ export function AppSidebar() {
|
||||
? [...baseItems, { icon: Users, title: "Admin", path: "/admin" }]
|
||||
: baseItems
|
||||
|
||||
// Reached through a portal, the way out is back to the installations list —
|
||||
// Reached through a portal, the way out is back to the instances list —
|
||||
// and the session belongs to the portal, so logging out is its business.
|
||||
const items: Item[] = portal
|
||||
? [
|
||||
{
|
||||
icon: ArrowLeft,
|
||||
title: "All installations",
|
||||
title: "All instances",
|
||||
onClick: () => window.location.assign(portal.portalUrl),
|
||||
},
|
||||
...withAdmin,
|
||||
|
||||
@@ -31,19 +31,19 @@ type CloudStatus = {
|
||||
connected: boolean
|
||||
portal_url: string | null
|
||||
portal_account: string | null
|
||||
installation_id: string | null
|
||||
instance_id: string | null
|
||||
last_error: string | null
|
||||
connected_since: number | null
|
||||
}
|
||||
|
||||
/**
|
||||
* Connecting this installation to a Fluksio portal, or cutting it loose, and
|
||||
* Connecting this instance to a Fluksio portal, or cutting it loose, and
|
||||
* admitting other portal accounts to it.
|
||||
*
|
||||
* Deliberately blunt about what it grants: the account that enrolled is what
|
||||
* the portal owner's sessions act as, and this screen says which one. Anyone
|
||||
* else gets in only by being added here, as a local user of their own.
|
||||
* Everything here is optional — an installation nobody enrolls never contacts
|
||||
* Everything here is optional — an instance nobody enrolls never contacts
|
||||
* anything.
|
||||
*/
|
||||
export function RemoteAccess() {
|
||||
@@ -108,8 +108,8 @@ export function RemoteAccess() {
|
||||
<CardHeader>
|
||||
<CardTitle>Remote access</CardTitle>
|
||||
<CardDescription>
|
||||
Reach this installation from fluksio.com. Entirely optional — without
|
||||
it, this installation talks to nothing outside your network.
|
||||
Reach this instance from fluksio.com. Entirely optional — without it,
|
||||
this instance talks to nothing outside your network.
|
||||
</CardDescription>
|
||||
</CardHeader>
|
||||
<CardContent className="flex flex-col gap-6">
|
||||
@@ -133,9 +133,9 @@ export function RemoteAccess() {
|
||||
own user.
|
||||
</span>
|
||||
</Field>
|
||||
<Field label="Installation">
|
||||
<Field label="Instance">
|
||||
<span className="font-mono text-xs">
|
||||
{status.installation_id ?? "—"}
|
||||
{status.instance_id ?? "—"}
|
||||
</span>
|
||||
</Field>
|
||||
</dl>
|
||||
@@ -156,8 +156,8 @@ export function RemoteAccess() {
|
||||
<div>
|
||||
<h3 className="font-medium">Remote users</h3>
|
||||
<p className="text-sm text-muted-foreground">
|
||||
Let someone else reach this installation through the portal.
|
||||
They get a user of their own here — not yours, and never a
|
||||
Let someone else reach this instance through the portal. They
|
||||
get a user of their own here — not yours, and never a
|
||||
superuser, so they cannot pass access on.
|
||||
</p>
|
||||
</div>
|
||||
@@ -173,9 +173,9 @@ export function RemoteAccess() {
|
||||
}
|
||||
/>
|
||||
<p className="text-xs text-muted-foreground">
|
||||
They get a code at fluksio.com → Installations → Join an
|
||||
installation. Added users appear under Admin → Users; deleting
|
||||
them there ends their access.
|
||||
They get a code at fluksio.com → Instances → Join an instance.
|
||||
Added users appear under Admin → Users; deleting them there
|
||||
ends their access.
|
||||
</p>
|
||||
</div>
|
||||
<div>
|
||||
@@ -210,7 +210,7 @@ export function RemoteAccess() {
|
||||
onChange={(event) => setCode(event.target.value.toUpperCase())}
|
||||
/>
|
||||
<p className="text-xs text-muted-foreground">
|
||||
Get a code at fluksio.com → Installations → Add installation.
|
||||
Get a code at fluksio.com → Instances → Add instance.
|
||||
</p>
|
||||
</div>
|
||||
<div>
|
||||
@@ -235,8 +235,8 @@ export function RemoteAccess() {
|
||||
<DialogTitle>Disconnect from the portal?</DialogTitle>
|
||||
<DialogDescription>
|
||||
Remote access ends immediately and the portal's credentials stop
|
||||
working here. Nothing on this installation is changed or deleted,
|
||||
and you can connect again with a new code.
|
||||
working here. Nothing on this instance is changed or deleted, and
|
||||
you can connect again with a new code.
|
||||
</DialogDescription>
|
||||
</DialogHeader>
|
||||
<DialogFooter>
|
||||
|
||||
Reference in New Issue
Block a user