more correct

This commit is contained in:
Brendan Allan
2026-02-18 16:01:38 +08:00
parent d7358f22ff
commit 78686fe87a
7 changed files with 42 additions and 39 deletions

View File

@@ -138,7 +138,7 @@ export function AppBaseProviders(props: ParentProps) {
function ServerKey(props: ParentProps) {
const server = useServer()
return (
<Show when={server.url} keyed>
<Show when={server.key} keyed>
{props.children}
</Show>
)

View File

@@ -176,7 +176,7 @@ export function DialogSelectServer() {
const { previewStatus } = useServerPreview(fetcher)
let listRoot: HTMLDivElement | undefined
const [store, setStore] = createStore({
status: {} as Record<string, ServerHealth | undefined>,
status: {} as Record<ServerConnection.Key, ServerHealth | undefined>,
addServer: {
url: "",
adding: false,
@@ -213,7 +213,7 @@ export function DialogSelectServer() {
}
const replaceServer = (original: ServerConnection.Http, next: string) => {
const active = server.url
const active = server.key
const newConn = server.add(next)
if (!newConn) return
@@ -230,7 +230,7 @@ export function DialogSelectServer() {
return [current, ...list.filter((x) => x !== current)]
})
const current = createMemo(() => items().find((x) => x.http.url === server.url) ?? items()[0])
const current = createMemo(() => items().find((x) => ServerConnection.key(x) === server.key) ?? items()[0])
const sortedItems = createMemo(() => {
const list = items()
@@ -245,17 +245,17 @@ export function DialogSelectServer() {
return list.slice().sort((a, b) => {
if (a === active) return -1
if (b === active) return 1
const diff = rank(store.status[a.http.url]) - rank(store.status[b.http.url])
const diff = rank(store.status[ServerConnection.key(a)]) - rank(store.status[ServerConnection.key(b)])
if (diff !== 0) return diff
return (order.get(a) ?? 0) - (order.get(b) ?? 0)
})
})
async function refreshHealth() {
const results: Record<string, ServerHealth> = {}
const results: Record<ServerConnection.Key, ServerHealth> = {}
await Promise.all(
items().map(async ({ http }) => {
results[http.url] = await checkServerHealth(http, fetcher)
items().map(async (conn) => {
results[ServerConnection.key(conn)] = await checkServerHealth(conn.http, fetcher)
}),
)
setStore("status", reconcile(results))
@@ -268,15 +268,15 @@ export function DialogSelectServer() {
onCleanup(() => clearInterval(interval))
})
async function select(value: ServerConnection.Any, persist?: boolean) {
if (!persist && store.status[value.http.url]?.healthy === false) return
async function select(conn: ServerConnection.Any, persist?: boolean) {
if (!persist && store.status[ServerConnection.key(conn)]?.healthy === false) return
dialog.close()
if (persist) {
server.add(value.http.url)
server.add(conn.http.url)
navigate("/")
return
}
server.setActive(ServerConnection.key(value))
server.setActive(ServerConnection.key(conn))
navigate("/")
}
@@ -446,8 +446,8 @@ export function DialogSelectServer() {
>
<ServerRow
conn={i}
status={store.status[i.http.url]}
dimmed={store.status[i.http.url]?.healthy === false}
status={store.status[ServerConnection.key(i)]}
dimmed={store.status[ServerConnection.key(i)]?.healthy === false}
class="flex items-center gap-3 px-4 min-w-0 flex-1"
badge={
<Show when={defaultUrl() === i.http.url}>
@@ -482,13 +482,13 @@ export function DialogSelectServer() {
id: i.http.url,
value: i.http.url,
error: "",
status: store.status[i.http.url]?.healthy,
status: store.status[ServerConnection.key(i)]?.healthy,
})
}}
>
<DropdownMenu.ItemLabel>{language.t("dialog.server.menu.edit")}</DropdownMenu.ItemLabel>
</DropdownMenu.Item>
<Show when={canDefault() && defaultUrl() !== i.http.url && i.type === "http"}>
<Show when={canDefault() && defaultUrl() !== i.http.url}>
<DropdownMenu.Item onSelect={() => setDefault(i.http.url)}>
<DropdownMenu.ItemLabel>
{language.t("dialog.server.menu.default")}

View File

@@ -26,7 +26,7 @@ export function ServerRow(props: ServerRowProps) {
const [truncated, setTruncated] = createSignal(false)
let nameRef: HTMLSpanElement | undefined
let versionRef: HTMLSpanElement | undefined
const name = createMemo(() => props.conn.displayName ?? serverDisplayName(props.conn.http.url))
const name = createMemo(() => serverDisplayName(props.conn))
const check = () => {
const nameTruncated = nameRef ? nameRef.scrollWidth > nameRef.clientWidth : false

View File

@@ -33,7 +33,7 @@ const pluginEmptyMessage = (value: string, file: string): JSXElement => {
const listServersByHealth = (
list: ServerConnection.Any[],
active: string | undefined,
active: ServerConnection.Key | undefined,
status: Record<string, ServerHealth | undefined>,
) => {
if (!list.length) return list
@@ -45,9 +45,9 @@ const listServersByHealth = (
}
return list.slice().sort((a, b) => {
if (a.http.url === active) return -1
if (b.http.url === active) return 1
const diff = rank(status[a.http.url]) - rank(status[b.http.url])
if (ServerConnection.key(a) === active) return -1
if (ServerConnection.key(b) === active) return 1
const diff = rank(status[ServerConnection.key(a)]) - rank(status[ServerConnection.key(b)])
if (diff !== 0) return diff
return (order.get(a) ?? 0) - (order.get(b) ?? 0)
})
@@ -170,7 +170,7 @@ export function StatusPopover() {
return [current, ...list.filter((item) => ServerConnection.key(item) !== ServerConnection.key(current))]
})
const health = useServerHealth(servers, fetcher)
const sortedServers = createMemo(() => listServersByHealth(servers(), server.url, health))
const sortedServers = createMemo(() => listServersByHealth(servers(), server.key, health))
const mcp = useMcpToggle({ sync, sdk, language })
const defaultServer = useDefaultServerUrl(platform.getDefaultServerUrl)
const mcpNames = createMemo(() => Object.keys(sync.data.mcp ?? {}).sort((a, b) => a.localeCompare(b)))
@@ -264,6 +264,7 @@ export function StatusPopover() {
aria-disabled={isBlocked()}
onClick={() => {
if (isBlocked()) return
console.log("onClick")
server.setActive(ServerConnection.key(s))
navigate("/")
}}
@@ -284,7 +285,9 @@ export function StatusPopover() {
}
>
<div class="flex-1" />
<Show when={s.http.url === server.url}>
<Show
when={server.current && ServerConnection.key(s) === ServerConnection.key(server.current)}
>
<Icon name="check" size="small" class="text-icon-weak shrink-0" />
</Show>
</ServerRow>

View File

@@ -19,9 +19,9 @@ export const { use: useGlobalSDK, provider: GlobalSDKProvider } = createSimpleCo
const abort = new AbortController()
const eventFetch = (() => {
if (!platform.fetch) return
if (!platform.fetch || !server.current) return
try {
const url = new URL(server.url)
const url = new URL(server.current.http.url)
const loopback = url.hostname === "localhost" || url.hostname === "127.0.0.1" || url.hostname === "::1"
if (url.protocol === "http:" && !loopback) return platform.fetch
} catch {
@@ -35,7 +35,7 @@ export const { use: useGlobalSDK, provider: GlobalSDKProvider } = createSimpleCo
const eventSdk = createSdkForServer({
signal: abort.signal,
fetch: eventFetch,
server: server.current.http,
server: currentServer.http,
})
const emitter = createGlobalEmitter<{
[key: string]: Event
@@ -126,7 +126,7 @@ export const { use: useGlobalSDK, provider: GlobalSDKProvider } = createSimpleCo
if (streamErrorLogged) return
streamErrorLogged = true
console.error("[global-sdk] event stream error", {
url: server.url,
url: currentServer.http.url,
fetch: eventFetch ? "platform" : "webview",
error,
})
@@ -159,7 +159,7 @@ export const { use: useGlobalSDK, provider: GlobalSDKProvider } = createSimpleCo
if (!aborted(error) && !streamErrorLogged) {
streamErrorLogged = true
console.error("[global-sdk] event stream failed", {
url: server.url,
url: currentServer.http.url,
fetch: eventFetch ? "platform" : "webview",
error,
})
@@ -200,7 +200,7 @@ export const { use: useGlobalSDK, provider: GlobalSDKProvider } = createSimpleCo
})
return {
url: server.url,
url: currentServer.http.url,
client: sdk,
event: emitter,
createClient(opts: Omit<Parameters<typeof createSdkForServer>[0], "server" | "fetch">) {

View File

@@ -15,9 +15,10 @@ export function normalizeServerUrl(input: string) {
return withProtocol.replace(/\/+$/, "")
}
export function serverDisplayName(url: string) {
if (!url) return ""
return url.replace(/^https?:\/\//, "").replace(/\/+$/, "")
export function serverDisplayName(conn?: ServerConnection.Any) {
if (!conn) return ""
if (conn.displayName) return conn.displayName
return conn.http.url.replace(/^https?:\/\//, "").replace(/\/+$/, "")
}
function projectsKey(url: string) {
@@ -148,9 +149,8 @@ export const { use: useServer, provider: ServerProvider } = createSimpleContext(
}
function setActive(input: ServerConnection.Key) {
const url = normalizeServerUrl(input)
if (!url) return
setState("active", url)
console.log("setActive", { input })
if (state.active !== input) setState("active", input)
}
function add(input: string) {
@@ -208,11 +208,11 @@ export const { use: useServer, provider: ServerProvider } = createSimpleContext(
ready: isReady,
healthy,
isLocal,
get url() {
get key() {
return state.active
},
get name() {
return serverDisplayName(state.active)
return serverDisplayName(current())
},
get list() {
return allServers()

View File

@@ -447,7 +447,7 @@ render(() => {
<AppBaseProviders>
<ServerGate>
{(data) => {
const [servers] = createStore<Array<ServerConnection.Sidecar>>([
const servers: Array<ServerConnection.Sidecar> = [
{
displayName: "Local Server",
type: "sidecar",
@@ -458,7 +458,7 @@ render(() => {
password: data().password ?? undefined,
},
},
])
]
function Inner() {
const cmd = useCommand()