97 lines · 3.7 KB · TypeScript
RawDownload
import type { ConnectionCatalogEntry } from "@t3tools/client-runtime/connection";import type { ServerConfig } from "@t3tools/contracts";import { useMemo } from "react"; import { useEnvironments, usePrimaryEnvironmentId } from "~/state/environments";import { isDesktopLocalConnectionTarget } from "~/connection/desktopLocal";import {  buildLocalEnvironmentUpdateGroups,  deriveEnvironmentDisplayLabel,  type EnvironmentUpdateConnectionState,  type LocalEnvironmentProvidersInput,  type LocalEnvironmentUpdateGroup,} from "./ProviderUpdateLaunchNotification.logic"; /** * A local environment is either the same-origin primary backend or a * desktop-local secondary (the parallel WSL backend), which connects over * loopback with a bearer token and carries a `local:<backendInstanceId>` * connection id. SSH, relay, and other remote targets are excluded. */function isLocalConnectionTarget(target: ConnectionCatalogEntry["target"]): boolean {  return target._tag === "PrimaryConnectionTarget" || isDesktopLocalConnectionTarget(target);} function normalizeConnectionState(phase: string | undefined): EnvironmentUpdateConnectionState {  switch (phase) {    case "connected":      return "ready";    case "connecting":    case "reconnecting":      return "connecting";    case "error":      return "error";    case "offline":      return "disconnected";    default:      // "available" (or anything not yet observed) — the backend has not      // confirmed it is serving yet, so treat it as still settling so the      // popover waits for it.      return "connecting";  }} /** * Reactively enumerate the enabled local environments (the primary plus any * desktop-local secondary such as WSL) with each one's full provider list and a * flag for whether any is still connecting. Drives the launch popover's gating * and its per-environment update triggers. */export function useLocalEnvironmentUpdateGroups(): {  readonly groups: LocalEnvironmentUpdateGroup[];  readonly isAnySettling: boolean;} {  const { environments } = useEnvironments();  const primaryEnvironmentId = usePrimaryEnvironmentId();   return useMemo(() => {    const inputs: LocalEnvironmentProvidersInput[] = [];     for (const environment of environments) {      if (!isLocalConnectionTarget(environment.entry.target)) {        continue;      }       const isPrimary = environment.environmentId === primaryEnvironmentId;      const serverConfig: ServerConfig | null = environment.serverConfig;       inputs.push({        environmentId: environment.environmentId,        // Secondaries carry a meaningful label straight from the platform source        // (e.g. "WSL (Ubuntu)"). The primary's catalog label can be the account        // name, so fall back to its platform OS so the row reads "Windows"/"Linux".        label: isPrimary          ? deriveEnvironmentDisplayLabel({              isWsl: false,              wslDistro: null,              platformOs: serverConfig?.environment.platform.os,              fallbackLabel: environment.label,            })          : environment.label,        isPrimary,        // The primary is the backend serving this renderer, so it is ready        // whenever its providers are available; secondaries report their live        // connection phase.        connectionState: isPrimary          ? "ready"          : normalizeConnectionState(environment.connection.phase),        providers: serverConfig?.providers ?? [],      });    }     // Primary first, then the rest in catalog order.    inputs.sort((left, right) => Number(right.isPrimary) - Number(left.isPrimary));     return buildLocalEnvironmentUpdateGroups(inputs);  }, [environments, primaryEnvironmentId]);}