mirror of
https://github.com/sst/opencode.git
synced 2025-12-23 10:11:41 +00:00
tui: hide MCP section when no servers are configured and use cached data
- Only show MCP section in sidebar and status dialog when MCP servers exist - Use cached MCP data from sync context instead of making separate API calls - Improves performance by reducing redundant network requests
This commit is contained in:
parent
113a7b5996
commit
d2cf9610e6
3 changed files with 76 additions and 80 deletions
|
|
@ -1,57 +1,52 @@
|
|||
import { TextAttributes } from "@opentui/core"
|
||||
import { Theme } from "../context/theme"
|
||||
import { useSDK } from "../context/sdk"
|
||||
import { useSync } from "@tui/context/sync"
|
||||
import { createResource, For, Match, Switch } from "solid-js"
|
||||
import { For, Match, Switch, Show } from "solid-js"
|
||||
|
||||
export type DialogStatusProps = {}
|
||||
|
||||
export function DialogStatus() {
|
||||
const sdk = useSDK()
|
||||
const sync = useSync()
|
||||
|
||||
const [mcp] = createResource(async () => {
|
||||
const result = await sdk.mcp.status()
|
||||
return result.data
|
||||
})
|
||||
|
||||
return (
|
||||
<box paddingLeft={2} paddingRight={2} gap={1} paddingBottom={1}>
|
||||
<box flexDirection="row" justifyContent="space-between">
|
||||
<text attributes={TextAttributes.BOLD}>Status</text>
|
||||
<text fg={Theme.textMuted}>esc</text>
|
||||
</box>
|
||||
<box>
|
||||
<text>{Object.values(mcp() ?? {}).length} MCP Servers</text>
|
||||
<For each={Object.entries(mcp() ?? {})}>
|
||||
{([key, item]) => (
|
||||
<box flexDirection="row" gap={1}>
|
||||
<text
|
||||
flexShrink={0}
|
||||
style={{
|
||||
fg: {
|
||||
connected: Theme.success,
|
||||
failed: Theme.error,
|
||||
disabled: Theme.textMuted,
|
||||
}[item.status],
|
||||
}}
|
||||
>
|
||||
•
|
||||
</text>
|
||||
<text wrapMode="word">
|
||||
<b>{key}</b>{" "}
|
||||
<span style={{ fg: Theme.textMuted }}>
|
||||
<Switch>
|
||||
<Match when={item.status === "connected"}>Connected</Match>
|
||||
<Match when={item.status === "failed" && item}>{(val) => val().error}</Match>
|
||||
<Match when={item.status === "disabled"}>Disabled in configuration</Match>
|
||||
</Switch>
|
||||
</span>
|
||||
</text>
|
||||
</box>
|
||||
)}
|
||||
</For>
|
||||
</box>
|
||||
<Show when={Object.keys(sync.data.mcp).length > 0}>
|
||||
<box>
|
||||
<text>{Object.keys(sync.data.mcp).length} MCP Servers</text>
|
||||
<For each={Object.entries(sync.data.mcp)}>
|
||||
{([key, item]) => (
|
||||
<box flexDirection="row" gap={1}>
|
||||
<text
|
||||
flexShrink={0}
|
||||
style={{
|
||||
fg: {
|
||||
connected: Theme.success,
|
||||
failed: Theme.error,
|
||||
disabled: Theme.textMuted,
|
||||
}[item.status],
|
||||
}}
|
||||
>
|
||||
•
|
||||
</text>
|
||||
<text wrapMode="word">
|
||||
<b>{key}</b>{" "}
|
||||
<span style={{ fg: Theme.textMuted }}>
|
||||
<Switch>
|
||||
<Match when={item.status === "connected"}>Connected</Match>
|
||||
<Match when={item.status === "failed" && item}>{(val) => val().error}</Match>
|
||||
<Match when={item.status === "disabled"}>Disabled in configuration</Match>
|
||||
</Switch>
|
||||
</span>
|
||||
</text>
|
||||
</box>
|
||||
)}
|
||||
</For>
|
||||
</box>
|
||||
</Show>
|
||||
{sync.data.lsp.length > 0 && (
|
||||
<box>
|
||||
<text>{sync.data.lsp.length} LSP Servers</text>
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ import type {
|
|||
Command,
|
||||
Permission,
|
||||
LspStatus,
|
||||
McpStatus,
|
||||
} from "@opencode-ai/sdk"
|
||||
import { createStore, produce, reconcile } from "solid-js/store"
|
||||
import { useSDK } from "@tui/context/sdk"
|
||||
|
|
@ -38,6 +39,9 @@ export const { use: useSync, provider: SyncProvider } = createSimpleContext({
|
|||
[messageID: string]: Part[]
|
||||
}
|
||||
lsp: LspStatus[]
|
||||
mcp: {
|
||||
[key: string]: McpStatus
|
||||
}
|
||||
}>({
|
||||
config: {},
|
||||
ready: false,
|
||||
|
|
@ -50,6 +54,7 @@ export const { use: useSync, provider: SyncProvider } = createSimpleContext({
|
|||
message: {},
|
||||
part: {},
|
||||
lsp: [],
|
||||
mcp: {},
|
||||
})
|
||||
|
||||
const sdk = useSDK()
|
||||
|
|
@ -206,6 +211,7 @@ export const { use: useSync, provider: SyncProvider } = createSimpleContext({
|
|||
sdk.config.get().then((x) => setStore("config", x.data!)),
|
||||
sdk.command.list().then((x) => setStore("command", x.data ?? [])),
|
||||
sdk.lsp.status().then((x) => setStore("lsp", x.data!)),
|
||||
sdk.mcp.status().then((x) => setStore("mcp", x.data!)),
|
||||
]).then(() => setStore("ready", true))
|
||||
|
||||
const result = {
|
||||
|
|
|
|||
|
|
@ -1,13 +1,11 @@
|
|||
import { useSync } from "@tui/context/sync"
|
||||
import { createMemo, For, Show, createResource, Switch, Match } from "solid-js"
|
||||
import { createMemo, For, Show, Switch, Match } from "solid-js"
|
||||
import { Theme } from "../../context/theme"
|
||||
import { useSDK } from "../../context/sdk"
|
||||
import { Locale } from "@/util/locale"
|
||||
import type { AssistantMessage } from "@opencode-ai/sdk"
|
||||
|
||||
export function Sidebar(props: { sessionID: string }) {
|
||||
const sync = useSync()
|
||||
const sdk = useSDK()
|
||||
const session = createMemo(() => sync.session.get(props.sessionID)!)
|
||||
const todo = createMemo(() => sync.data.todo[props.sessionID] ?? [])
|
||||
const messages = createMemo(() => sync.data.message[props.sessionID] ?? [])
|
||||
|
|
@ -26,11 +24,6 @@ export function Sidebar(props: { sessionID: string }) {
|
|||
return [...result.values()].sort((a, b) => a.length - b.length)
|
||||
})
|
||||
|
||||
const [mcp] = createResource(async () => {
|
||||
const result = await sdk.mcp.status()
|
||||
return result.data
|
||||
})
|
||||
|
||||
const cost = createMemo(() => {
|
||||
const total = messages().reduce((sum, x) => sum + (x.role === "assistant" ? x.cost : 0), 0)
|
||||
return new Intl.NumberFormat("en-US", {
|
||||
|
|
@ -70,39 +63,41 @@ export function Sidebar(props: { sessionID: string }) {
|
|||
<text fg={Theme.textMuted}>{context()?.percentage ?? 0}% used</text>
|
||||
<text fg={Theme.textMuted}>{cost()} spent</text>
|
||||
</box>
|
||||
<box>
|
||||
<text>
|
||||
<b>MCP</b>
|
||||
</text>
|
||||
<For each={Object.entries(mcp() ?? {})}>
|
||||
{([key, item]) => (
|
||||
<box flexDirection="row" gap={1}>
|
||||
<text
|
||||
flexShrink={0}
|
||||
style={{
|
||||
fg: {
|
||||
connected: Theme.success,
|
||||
failed: Theme.error,
|
||||
disabled: Theme.textMuted,
|
||||
}[item.status],
|
||||
}}
|
||||
>
|
||||
•
|
||||
</text>
|
||||
<text wrapMode="word">
|
||||
{key}{" "}
|
||||
<span style={{ fg: Theme.textMuted }}>
|
||||
<Switch>
|
||||
<Match when={item.status === "connected"}>Connected</Match>
|
||||
<Match when={item.status === "failed" && item}>{(val) => <i>{val().error}</i>}</Match>
|
||||
<Match when={item.status === "disabled"}>Disabled in configuration</Match>
|
||||
</Switch>
|
||||
</span>
|
||||
</text>
|
||||
</box>
|
||||
)}
|
||||
</For>
|
||||
</box>
|
||||
<Show when={Object.keys(sync.data.mcp).length > 0}>
|
||||
<box>
|
||||
<text>
|
||||
<b>MCP</b>
|
||||
</text>
|
||||
<For each={Object.entries(sync.data.mcp)}>
|
||||
{([key, item]) => (
|
||||
<box flexDirection="row" gap={1}>
|
||||
<text
|
||||
flexShrink={0}
|
||||
style={{
|
||||
fg: {
|
||||
connected: Theme.success,
|
||||
failed: Theme.error,
|
||||
disabled: Theme.textMuted,
|
||||
}[item.status],
|
||||
}}
|
||||
>
|
||||
•
|
||||
</text>
|
||||
<text wrapMode="word">
|
||||
{key}{" "}
|
||||
<span style={{ fg: Theme.textMuted }}>
|
||||
<Switch>
|
||||
<Match when={item.status === "connected"}>Connected</Match>
|
||||
<Match when={item.status === "failed" && item}>{(val) => <i>{val().error}</i>}</Match>
|
||||
<Match when={item.status === "disabled"}>Disabled in configuration</Match>
|
||||
</Switch>
|
||||
</span>
|
||||
</text>
|
||||
</box>
|
||||
)}
|
||||
</For>
|
||||
</box>
|
||||
</Show>
|
||||
<Show when={sync.data.lsp.length > 0}>
|
||||
<box>
|
||||
<text>
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue