summaryrefslogtreecommitdiffhomepage
path: root/src/features/workspace/logic/view-model.ts
diff options
context:
space:
mode:
Diffstat (limited to 'src/features/workspace/logic/view-model.ts')
-rw-r--r--src/features/workspace/logic/view-model.ts130
1 files changed, 0 insertions, 130 deletions
diff --git a/src/features/workspace/logic/view-model.ts b/src/features/workspace/logic/view-model.ts
deleted file mode 100644
index bc9b30b..0000000
--- a/src/features/workspace/logic/view-model.ts
+++ /dev/null
@@ -1,130 +0,0 @@
-import type { LspServerInfo, LspServerState } from "@dispatch/transport-contract";
-
-/**
- * Pure core for the workspace feature — zero DOM, zero effects, zero Svelte.
- *
- * The workspace feature exposes a conversation's per-tab working directory (cwd)
- * and the live status of the language servers configured for that cwd. This
- * module holds the pure logic: cwd normalization/validation, the mapping of a
- * backend `LspServerState` to a display badge, and a one-line server summary.
- * The effects (the HTTP get/set cwd + get LSP status) are INJECTED via the ports
- * below; the composition root implements them.
- */
-
-// ── Injected ports (consumer-defines-port; the composition root adapts the
-// store's HTTP calls to these shapes). ──────────────────────────────────────
-
-/** Outcome of `PUT /conversations/:id/cwd`; `null` when no real conversation is focused. */
-export type CwdSaveResult =
- | { readonly ok: true; readonly cwd: string | null }
- | { readonly ok: false; readonly error: string };
-
-export type SaveCwd = (cwd: string) => Promise<CwdSaveResult | null>;
-
-/** Outcome of `GET /conversations/:id/lsp`; `null` when no real conversation is focused. */
-export type LspStatusResult =
- | { readonly ok: true; readonly cwd: string | null; readonly servers: readonly LspServerInfo[] }
- | { readonly ok: false; readonly error: string };
-
-export type LoadLspStatus = () => Promise<LspStatusResult | null>;
-
-// ── cwd helpers ───────────────────────────────────────────────────────────────
-
-/** Trim surrounding whitespace; the backend rejects an empty cwd. */
-export function normalizeCwd(raw: string): string {
- return raw.trim();
-}
-
-/** Whether a typed cwd is submittable (non-empty after trim). */
-export function isSubmittableCwd(raw: string): boolean {
- return normalizeCwd(raw).length > 0;
-}
-
-/**
- * Whether saving `typed` would change the persisted `current` cwd. A no-op save
- * (unchanged, or empty) should be disabled.
- */
-export function cwdChanged(typed: string, current: string | null): boolean {
- const next = normalizeCwd(typed);
- if (next.length === 0) return false;
- return next !== (current ?? "");
-}
-
-// ── LSP server status → display view ──────────────────────────────────────────
-
-export type Badge = "success" | "warning" | "error" | "neutral";
-
-export interface LspServerView {
- readonly id: string;
- readonly name: string;
- readonly root: string;
- /** Space-joined extension list, e.g. ".ts .tsx". */
- readonly extensionsLabel: string;
- readonly state: LspServerState;
- readonly statusLabel: string;
- readonly badge: Badge;
- /** True while the state is transient (show a spinner). */
- readonly busy: boolean;
- /** The error reason when `state === "error"`, else null. */
- readonly error: string | null;
-}
-
-/** Map a server's state to a display label + badge severity + busy flag. */
-export function viewLspServer(server: LspServerInfo): LspServerView {
- let statusLabel: string;
- let badge: Badge;
- let busy = false;
- switch (server.state) {
- case "connected":
- statusLabel = "Connected";
- badge = "success";
- break;
- case "starting":
- statusLabel = "Starting…";
- badge = "warning";
- busy = true;
- break;
- case "not-started":
- statusLabel = "Not started";
- badge = "neutral";
- busy = true;
- break;
- case "error":
- statusLabel = "Error";
- badge = "error";
- break;
- }
- return {
- id: server.id,
- name: server.name,
- root: server.root,
- extensionsLabel: server.extensions.join(" "),
- state: server.state,
- statusLabel,
- badge,
- busy,
- error: server.state === "error" ? (server.error ?? "Failed to start") : null,
- };
-}
-
-export function viewLspServers(servers: readonly LspServerInfo[]): readonly LspServerView[] {
- return servers.map(viewLspServer);
-}
-
-/** A short one-line summary, e.g. "2 connected" / "1 connected, 1 error". */
-export function summarizeServers(servers: readonly LspServerInfo[]): string {
- if (servers.length === 0) return "No language servers";
- let connected = 0;
- let errored = 0;
- let pending = 0;
- for (const s of servers) {
- if (s.state === "connected") connected++;
- else if (s.state === "error") errored++;
- else pending++;
- }
- const parts: string[] = [];
- if (connected > 0) parts.push(`${connected} connected`);
- if (pending > 0) parts.push(`${pending} starting`);
- if (errored > 0) parts.push(`${errored} error${errored === 1 ? "" : "s"}`);
- return parts.join(", ");
-}