summaryrefslogtreecommitdiffhomepage
path: root/src/app/register-views.ts
blob: 05afd89fcef79d414b861136d1d740799391dbaf (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
/**
 * Built-in view registration — the composition root's view vocabulary.
 *
 * One thin wrapper component per existing view (src/app/views/*.svelte), each
 * closing over exactly the props/ports App.svelte's `viewContent` snippet used
 * to pass — INCLUDING each view's `{#key}` remount semantics (moved INSIDE the
 * wrappers). Registry ids match the old `viewKinds` ids exactly: no
 * user-facing renaming, no persistence-key changes.
 *
 * `chat` / `composer` / `message-queue` are CONTENT views (decision 5): they
 * register with `panelEligible: false` so they never appear in the panel
 * dropdowns. All 15 sidebar views keep the eligible default.
 *
 * Imported ONCE by App.svelte's module script — before any tile renders.
 */

import type { Component } from "svelte";
import { registerView, type ViewComponent, type ViewRegistration } from "../features/layout";
import type { AppViewPorts } from "./view-ports";
import AccountUsagePane from "./views/AccountUsagePane.svelte";
import CacheWarmingPane from "./views/CacheWarmingPane.svelte";
import ChatPane from "./views/ChatPane.svelte";
import CompactionPane from "./views/CompactionPane.svelte";
import ComposerPane from "./views/ComposerPane.svelte";
import ConcurrencyPane from "./views/ConcurrencyPane.svelte";
import ExtensionsPane from "./views/ExtensionsPane.svelte";
import HeartbeatPane from "./views/HeartbeatPane.svelte";
import LspPane from "./views/LspPane.svelte";
import McpPane from "./views/McpPane.svelte";
import MessageQueuePane from "./views/MessageQueuePane.svelte";
import ModelPane from "./views/ModelPane.svelte";
import NamedAgentsPane from "./views/NamedAgentsPane.svelte";
import SettingsPane from "./views/SettingsPane.svelte";
import SystemPromptPane from "./views/SystemPromptPane.svelte";
import TabsPane from "./views/TabsPane.svelte";
import TasksPane from "./views/TasksPane.svelte";
import VisionPane from "./views/VisionPane.svelte";

/**
 * Every wrapper takes `{ ports: AppViewPorts }` and TileLeaf supplies it — but
 * the registry is a HETEROGENEOUS bag of components (generic `Component`), so
 * the composition root bridges each wrapper's concrete props type to the
 * registry's opaque one. ONE controlled cast at this seam (the renderer always
 * passes the port bag; the wrappers re-narrow it) instead of `any` in the
 * contract.
 */
type WrapperComponent = Component<{ ports: AppViewPorts }>;
function asView(component: WrapperComponent): ViewComponent {
  return component as unknown as ViewComponent;
}

export function registerBuiltinViews(): void {
  const views: readonly ViewRegistration[] = [
    // --- sidebar views (panel-eligible by default — the 14 old viewKinds + account-usage)
    { id: "tabs", label: "Tabs", component: asView(TabsPane) },
    { id: "model", label: "Model", component: asView(ModelPane) },
    { id: "named-agents", label: "Named Agents", component: asView(NamedAgentsPane) },
    { id: "lsp", label: "Language Servers", component: asView(LspPane) },
    { id: "mcp", label: "MCP Servers", component: asView(McpPane) },
    { id: "extensions", label: "Extensions", component: asView(ExtensionsPane) },
    { id: "cache-warming", label: "Cache Warming", component: asView(CacheWarmingPane) },
    { id: "tasks", label: "Tasks", component: asView(TasksPane) },
    { id: "compaction", label: "Compaction", component: asView(CompactionPane) },
    { id: "vision", label: "Vision", component: asView(VisionPane) },
    { id: "heartbeat", label: "Heartbeat", component: asView(HeartbeatPane) },
    { id: "concurrency", label: "Concurrency", component: asView(ConcurrencyPane) },
    { id: "account-usage", label: "Usage", component: asView(AccountUsagePane) },
    { id: "system-prompt", label: "System Prompt", component: asView(SystemPromptPane) },
    { id: "settings", label: "Settings", component: asView(SettingsPane) },
    // --- content views (never in the panel dropdowns — decision 5)
    { id: "chat", label: "Chat", component: asView(ChatPane), panelEligible: false },
    { id: "composer", label: "Composer", component: asView(ComposerPane), panelEligible: false },
    {
      id: "message-queue",
      label: "Message Queue",
      component: asView(MessageQueuePane),
      panelEligible: false,
    },
  ];
  for (const view of views) registerView(view);
}