feat(app): add truncation tooltip to server items in status popover
This commit is contained in:
@@ -1,4 +1,4 @@
|
|||||||
import { createEffect, createMemo, createSignal, For, onCleanup, Show } from "solid-js"
|
import { createEffect, createMemo, createSignal, For, onCleanup, onMount, Show } from "solid-js"
|
||||||
import { createStore, reconcile } from "solid-js/store"
|
import { createStore, reconcile } from "solid-js/store"
|
||||||
import { useNavigate } from "@solidjs/router"
|
import { useNavigate } from "@solidjs/router"
|
||||||
import { useDialog } from "@opencode-ai/ui/context/dialog"
|
import { useDialog } from "@opencode-ai/ui/context/dialog"
|
||||||
@@ -7,6 +7,7 @@ import { Tabs } from "@opencode-ai/ui/tabs"
|
|||||||
import { Button } from "@opencode-ai/ui/button"
|
import { Button } from "@opencode-ai/ui/button"
|
||||||
import { Switch } from "@opencode-ai/ui/switch"
|
import { Switch } from "@opencode-ai/ui/switch"
|
||||||
import { Icon } from "@opencode-ai/ui/icon"
|
import { Icon } from "@opencode-ai/ui/icon"
|
||||||
|
import { Tooltip } from "@opencode-ai/ui/tooltip"
|
||||||
import { useSync } from "@/context/sync"
|
import { useSync } from "@/context/sync"
|
||||||
import { useSDK } from "@/context/sdk"
|
import { useSDK } from "@/context/sdk"
|
||||||
import { normalizeServerUrl, serverDisplayName, useServer } from "@/context/server"
|
import { normalizeServerUrl, serverDisplayName, useServer } from "@/context/server"
|
||||||
@@ -210,44 +211,78 @@ export function StatusPopover() {
|
|||||||
const isDefault = () => url === defaultServerUrl()
|
const isDefault = () => url === defaultServerUrl()
|
||||||
const status = () => store.status[url]
|
const status = () => store.status[url]
|
||||||
const isBlocked = () => status()?.healthy === false
|
const isBlocked = () => status()?.healthy === false
|
||||||
|
const [truncated, setTruncated] = createSignal(false)
|
||||||
|
let nameRef: HTMLSpanElement | undefined
|
||||||
|
let versionRef: HTMLSpanElement | undefined
|
||||||
|
|
||||||
|
onMount(() => {
|
||||||
|
const check = () => {
|
||||||
|
const nameTruncated = nameRef ? nameRef.scrollWidth > nameRef.clientWidth : false
|
||||||
|
const versionTruncated = versionRef ? versionRef.scrollWidth > versionRef.clientWidth : false
|
||||||
|
setTruncated(nameTruncated || versionTruncated)
|
||||||
|
}
|
||||||
|
check()
|
||||||
|
window.addEventListener("resize", check)
|
||||||
|
onCleanup(() => window.removeEventListener("resize", check))
|
||||||
|
})
|
||||||
|
|
||||||
|
const tooltipValue = () => {
|
||||||
|
const name = serverDisplayName(url)
|
||||||
|
const version = status()?.version
|
||||||
|
return (
|
||||||
|
<span class="flex items-center gap-2">
|
||||||
|
<span>{name}</span>
|
||||||
|
<Show when={version}>
|
||||||
|
<span class="text-text-invert-base">{version}</span>
|
||||||
|
</Show>
|
||||||
|
</span>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<button
|
<Tooltip value={tooltipValue()} placement="top" inactive={!truncated()}>
|
||||||
type="button"
|
<button
|
||||||
class="flex items-center gap-2 w-full h-8 pl-3 pr-1.5 py-1.5 rounded-md transition-colors text-left"
|
type="button"
|
||||||
classList={{
|
class="flex items-center gap-2 w-full h-8 pl-3 pr-1.5 py-1.5 rounded-md transition-colors text-left"
|
||||||
"opacity-50": isBlocked(),
|
|
||||||
"hover:bg-surface-raised-base-hover": !isBlocked(),
|
|
||||||
"cursor-not-allowed": isBlocked(),
|
|
||||||
}}
|
|
||||||
aria-disabled={isBlocked()}
|
|
||||||
onClick={() => {
|
|
||||||
if (isBlocked()) return
|
|
||||||
server.setActive(url)
|
|
||||||
navigate("/")
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<div
|
|
||||||
classList={{
|
classList={{
|
||||||
"size-1.5 rounded-full shrink-0": true,
|
"opacity-50": isBlocked(),
|
||||||
"bg-icon-success-base": status()?.healthy === true,
|
"hover:bg-surface-raised-base-hover": !isBlocked(),
|
||||||
"bg-icon-critical-base": status()?.healthy === false,
|
"cursor-not-allowed": isBlocked(),
|
||||||
"bg-border-weak-base": status() === undefined,
|
|
||||||
}}
|
}}
|
||||||
/>
|
aria-disabled={isBlocked()}
|
||||||
<span class="text-14-regular text-text-base truncate">{serverDisplayName(url)}</span>
|
onClick={() => {
|
||||||
<Show when={status()?.version}>
|
if (isBlocked()) return
|
||||||
<span class="text-12-regular text-text-weak truncate">{status()?.version}</span>
|
server.setActive(url)
|
||||||
</Show>
|
navigate("/")
|
||||||
<Show when={isDefault()}>
|
}}
|
||||||
<span class="text-11-regular text-text-base bg-surface-base px-1.5 py-0.5 rounded-md">
|
>
|
||||||
Default
|
<div
|
||||||
|
classList={{
|
||||||
|
"size-1.5 rounded-full shrink-0": true,
|
||||||
|
"bg-icon-success-base": status()?.healthy === true,
|
||||||
|
"bg-icon-critical-base": status()?.healthy === false,
|
||||||
|
"bg-border-weak-base": status() === undefined,
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<span ref={nameRef} class="text-14-regular text-text-base truncate">
|
||||||
|
{serverDisplayName(url)}
|
||||||
</span>
|
</span>
|
||||||
</Show>
|
<Show when={status()?.version}>
|
||||||
<div class="flex-1" />
|
<span ref={versionRef} class="text-12-regular text-text-weak truncate">
|
||||||
<Show when={isActive()}>
|
{status()?.version}
|
||||||
<Icon name="check" size="small" class="text-icon-weak shrink-0" />
|
</span>
|
||||||
</Show>
|
</Show>
|
||||||
</button>
|
<Show when={isDefault()}>
|
||||||
|
<span class="text-11-regular text-text-base bg-surface-base px-1.5 py-0.5 rounded-md">
|
||||||
|
Default
|
||||||
|
</span>
|
||||||
|
</Show>
|
||||||
|
<div class="flex-1" />
|
||||||
|
<Show when={isActive()}>
|
||||||
|
<Icon name="check" size="small" class="text-icon-weak shrink-0" />
|
||||||
|
</Show>
|
||||||
|
</button>
|
||||||
|
</Tooltip>
|
||||||
)
|
)
|
||||||
}}
|
}}
|
||||||
</For>
|
</For>
|
||||||
@@ -276,7 +311,7 @@ export function StatusPopover() {
|
|||||||
return (
|
return (
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
class="flex items-center gap-2 w-full h-8 px-2 py-1 rounded-md hover:bg-surface-raised-base-hover transition-colors text-left"
|
class="flex items-center gap-2 w-full h-8 pl-3 pr-2 py-1 rounded-md hover:bg-surface-raised-base-hover transition-colors text-left"
|
||||||
onClick={() => toggleMcp(item.name)}
|
onClick={() => toggleMcp(item.name)}
|
||||||
disabled={loading() === item.name}
|
disabled={loading() === item.name}
|
||||||
>
|
>
|
||||||
|
|||||||
Reference in New Issue
Block a user