feat(dialog-select-server): add icon button for server removal (#8053)

This commit is contained in:
OpeOginni
2026-01-12 22:26:58 +01:00
committed by GitHub
parent 08d4d6d4af
commit b3a1360ad9
2 changed files with 42 additions and 17 deletions

View File

@@ -5,6 +5,7 @@ import { Dialog } from "@opencode-ai/ui/dialog"
import { List } from "@opencode-ai/ui/list"
import { TextField } from "@opencode-ai/ui/text-field"
import { Button } from "@opencode-ai/ui/button"
import { IconButton } from "@opencode-ai/ui/icon-button"
import { normalizeServerUrl, serverDisplayName, useServer } from "@/context/server"
import { usePlatform } from "@/context/platform"
import { createOpencodeClient } from "@opencode-ai/sdk/v2/client"
@@ -116,6 +117,10 @@ export function DialogSelectServer() {
select(value, true)
}
async function handleRemove(url: string) {
server.remove(url)
}
return (
<Dialog title="Servers" description="Switch which OpenCode server this app connects to.">
<div class="flex flex-col gap-4 pb-4">
@@ -130,20 +135,33 @@ export function DialogSelectServer() {
}}
>
{(i) => (
<div
class="flex items-center gap-2 min-w-0 flex-1"
classList={{ "opacity-50": store.status[i]?.healthy === false }}
>
<div class="flex items-center gap-2 min-w-0 flex-1 group/item">
<div
classList={{
"size-1.5 rounded-full shrink-0": true,
"bg-icon-success-base": store.status[i]?.healthy === true,
"bg-icon-critical-base": store.status[i]?.healthy === false,
"bg-border-weak-base": store.status[i] === undefined,
}}
/>
<span class="truncate">{serverDisplayName(i)}</span>
<span class="text-text-weak">{store.status[i]?.version}</span>
class="flex items-center gap-2 min-w-0 flex-1"
classList={{ "opacity-50": store.status[i]?.healthy === false }}
>
<div
classList={{
"size-1.5 rounded-full shrink-0": true,
"bg-icon-success-base": store.status[i]?.healthy === true,
"bg-icon-critical-base": store.status[i]?.healthy === false,
"bg-border-weak-base": store.status[i] === undefined,
}}
/>
<span class="truncate">{serverDisplayName(i)}</span>
<span class="text-text-weak">{store.status[i]?.version}</span>
</div>
<Show when={current() !== i && server.list.includes(i)}>
<IconButton
icon="circle-x"
variant="ghost"
class="bg-transparent transition-opacity shrink-0 hover:scale-110"
onClick={(e) => {
e.stopPropagation()
handleRemove(i)
}}
/>
</Show>
</div>
)}
</List>

View File

@@ -22,10 +22,17 @@ export function useFilteredList<T>(props: FilteredListProps<T>) {
const empty: Group[] = []
const [grouped, { refetch }] = createResource(
() => ({
filter: store.filter,
items: typeof props.items === "function" ? undefined : props.items,
}),
() => {
// When items is a function (not async filter function), call it to track changes
const itemsValue = typeof props.items === "function"
? (props.items as () => T[])() // Call synchronous function to track it
: props.items
return {
filter: store.filter,
items: itemsValue,
}
},
async ({ filter, items }) => {
const needle = filter?.toLowerCase()
const all = (items ?? (await (props.items as (filter: string) => T[] | Promise<T[]>)(needle))) || []