From d8f59d312b2de198c47be0f5a18a55270b8b347d Mon Sep 17 00:00:00 2001 From: "opencode-agent[bot]" <219766164+opencode-agent[bot]@users.noreply.github.com> Date: Mon, 24 Aug 2026 12:58:53 +0800 Subject: [PATCH] feat(desktop): hide local server from projects (#44598) Co-authored-by: Brendonovich <14191578+Brendonovich@users.noreply.github.com> --- packages/app/src/home/model.ts | 11 +++++------ packages/app/src/home/projects/controller.tsx | 2 ++ packages/app/src/home/projects/region.tsx | 2 ++ packages/app/src/home/projects/view.tsx | 16 +++++++++++----- packages/app/src/runtime/i18n/en.ts | 2 ++ packages/app/src/runtime/server/registry.tsx | 11 +++++++++++ packages/app/src/servers/registry/controller.ts | 14 +++++++++++++- packages/app/src/servers/registry/row-menu.tsx | 16 ++++++++++++++++ 8 files changed, 62 insertions(+), 12 deletions(-) diff --git a/packages/app/src/home/model.ts b/packages/app/src/home/model.ts index c15fc11211c..7a3b1cc0635 100644 --- a/packages/app/src/home/model.ts +++ b/packages/app/src/home/model.ts @@ -1,6 +1,6 @@ import { useGlobal, useServerCtx } from "@/runtime/server/runtime" import { type HomeProjectSelection, useLayout } from "@/shell/state/layout" -import { ServerConnection } from "@/runtime/server/registry" +import { ServerConnection, useServers } from "@/runtime/server/registry" import { useTabs } from "@/shell/tabs/tabs" import { toggleHomeProjectSelection } from "@/shell/layout/helpers" import { createEffect, createMemo, startTransition } from "solid-js" @@ -8,12 +8,11 @@ import { createEffect, createMemo, startTransition } from "solid-js" export function createHomeController() { const layout = useLayout() const global = useGlobal() + const servers = useServers() const tabs = useTabs() const selection = layout.home.selection const focusedServer = createMemo( - () => - global.servers.list().find((conn) => ServerConnection.key(conn) === selection().server) ?? - global.servers.list()[0], + () => servers.visible.find((conn) => ServerConnection.key(conn) === selection().server) ?? servers.visible[0], ) const focusedServerCtx = useServerCtx(focusedServer) const focusedSync = () => focusedServerCtx()?.sync @@ -29,7 +28,7 @@ export function createHomeController() { ) createEffect(() => { - const list = global.servers.list() + const list = servers.visible if (list.some((conn) => ServerConnection.key(conn) === selection().server)) return const conn = list[0] if (conn) setSelection({ server: ServerConnection.key(conn) }) @@ -54,7 +53,7 @@ export function createHomeController() { void startTransition(() => setSelection({ server: ServerConnection.key(conn) })), }, server: { - list: global.servers.list, + list: () => servers.visible, health: (conn: ServerConnection.Any) => global.servers.health[ServerConnection.key(conn)], context: (conn: ServerConnection.Any) => global.ensureServerCtx(conn), focused: focusedServer, diff --git a/packages/app/src/home/projects/controller.tsx b/packages/app/src/home/projects/controller.tsx index fb55ae7751d..68952f81393 100644 --- a/packages/app/src/home/projects/controller.tsx +++ b/packages/app/src/home/projects/controller.tsx @@ -61,6 +61,8 @@ export function createHomeProjectsController(home: HomeController) { serverManagement.defaults.set(conn ? ServerConnection.key(conn) : null), canRemove: (conn: ServerConnection.Any) => serverManagement.connection.canRemove(ServerConnection.key(conn)), remove: (conn: ServerConnection.Any) => serverManagement.connection.remove(ServerConnection.key(conn)), + canHide: (conn: ServerConnection.Any) => serverManagement.connection.canHide(ServerConnection.key(conn)), + hide: (conn: ServerConnection.Any) => serverManagement.connection.setHidden(ServerConnection.key(conn), true), edit: (conn: ServerConnection.Http) => { void import("@/servers/connect/dialog").then(({ DialogServer }) => { void dialog.show(() => ) diff --git a/packages/app/src/home/projects/region.tsx b/packages/app/src/home/projects/region.tsx index 7f46aeeea6c..45f695d26e5 100644 --- a/packages/app/src/home/projects/region.tsx +++ b/packages/app/src/home/projects/region.tsx @@ -26,6 +26,8 @@ export function HomeProjects(props: { projects: HomeProjectsController; scroll: onSetDefaultServer={props.projects.server.setDefault} canRemoveServer={props.projects.server.canRemove} onRemoveServer={props.projects.server.remove} + canHideServer={props.projects.server.canHide} + onHideServer={props.projects.server.hide} onMoveProject={props.projects.project.move} onSelectProject={props.projects.project.select} onAddProjects={props.projects.project.add} diff --git a/packages/app/src/home/projects/view.tsx b/packages/app/src/home/projects/view.tsx index 51ca80b5014..54dc6765d79 100644 --- a/packages/app/src/home/projects/view.tsx +++ b/packages/app/src/home/projects/view.tsx @@ -49,6 +49,8 @@ export type HomeProjectsViewProps = { onSetDefaultServer: (server: ServerConnection.Any | undefined) => void canRemoveServer: (server: ServerConnection.Any) => boolean onRemoveServer: (server: ServerConnection.Any) => void + canHideServer: (server: ServerConnection.Any) => boolean + onHideServer: (server: ServerConnection.Any) => void onMoveProject: (server: ServerConnection.Any, worktree: string, index: number) => void onSelectProject: (server: ServerConnection.Any, directory: string) => void onAddProjects: (server: ServerConnection.Any, directories: string[]) => void @@ -188,6 +190,8 @@ function HomeServerRow(props: { onSetDefaultServer: HomeProjectsViewProps["onSetDefaultServer"] canRemoveServer: HomeProjectsViewProps["canRemoveServer"] onRemoveServer: HomeProjectsViewProps["onRemoveServer"] + canHideServer: HomeProjectsViewProps["canHideServer"] + onHideServer: HomeProjectsViewProps["onHideServer"] onSetContextMenuOpen: HomeProjectsContextMenuProps["onSetContextMenuOpen"] onChooseProject: HomeProjectsViewProps["onChooseProject"] server: ServerConnection.Any @@ -212,11 +216,11 @@ function HomeServerRow(props: { value={props.language.t("server.row.incompatible", { version: props.health?.version ?? "1" })} >
- props.onFocusServer(props.server)} > @@ -284,10 +288,12 @@ function HomeServerRow(props: { canDefault={props.canDefaultServer} isDefault={props.defaultServerKey === ServerConnection.key(props.server)} canRemove={props.canRemoveServer(props.server)} + canHide={props.canHideServer(props.server)} onEdit={props.onEditServer} onSetDefault={() => props.onSetDefaultServer(props.server)} onRemoveDefault={() => props.onSetDefaultServer(undefined)} onRemove={() => props.onRemoveServer(props.server)} + onHide={() => props.onHideServer(props.server)} open={props.contextMenuOpen(contextMenuID())} onOpenChange={(open) => props.onSetContextMenuOpen(contextMenuID(), open)} /> diff --git a/packages/app/src/runtime/i18n/en.ts b/packages/app/src/runtime/i18n/en.ts index 15c0c425602..2ff367616db 100644 --- a/packages/app/src/runtime/i18n/en.ts +++ b/packages/app/src/runtime/i18n/en.ts @@ -374,6 +374,8 @@ export const dict = { "dialog.server.menu.default": "Set as default", "dialog.server.menu.defaultRemove": "Remove default", "dialog.server.menu.delete": "Delete", + "dialog.server.menu.hide": "Hide from project list", + "dialog.server.menu.show": "Show in project list", "dialog.server.current": "Current Server", "dialog.server.status.default": "Default", "wsl.server.add": "Add WSL server", diff --git a/packages/app/src/runtime/server/registry.tsx b/packages/app/src/runtime/server/registry.tsx index 133fa1db92e..7b44203af45 100644 --- a/packages/app/src/runtime/server/registry.tsx +++ b/packages/app/src/runtime/server/registry.tsx @@ -269,6 +269,7 @@ export const { use: useServers, provider: ServersProvider } = createSimpleContex }, createStore({ list: [] as StoredServer[], + hidden: {} as Record, projects: {} as Record, lastProject: {} as Record, recentlyClosed: {} as Record, @@ -280,6 +281,7 @@ export const { use: useServers, provider: ServersProvider } = createSimpleContex const allServers = createMemo((): Array => { return resolveServerList({ stored: store.list, props: props.servers }) }) + const visibleServers = createMemo(() => allServers().filter((conn) => !store.hidden[ServerConnection.key(conn)])) function add(input: ServerConnection.Http) { const url_ = normalizeServerUrl(input.http.url) @@ -321,6 +323,15 @@ export const { use: useServers, provider: ServersProvider } = createSimpleContex get list() { return allServers() }, + get visible() { + return visibleServers() + }, + isHidden(key: ServerConnection.Key) { + return store.hidden[key] ?? false + }, + setHidden(key: ServerConnection.Key, hidden: boolean) { + setStore("hidden", key, hidden) + }, add, remove, canRemove, diff --git a/packages/app/src/servers/registry/controller.ts b/packages/app/src/servers/registry/controller.ts index 25cbfc65f83..b3ecf635045 100644 --- a/packages/app/src/servers/registry/controller.ts +++ b/packages/app/src/servers/registry/controller.ts @@ -66,7 +66,19 @@ export function useServerActionsController() { } } - return { defaults, connection: { canRemove: server.canRemove, remove } } + return { + defaults, + connection: { + canRemove: server.canRemove, + remove, + canHide: (key: ServerConnection.Key) => { + const conn = server.list.find((item) => ServerConnection.key(item) === key) + return server.visible.length > 1 && !!conn && ServerConnection.builtin(conn) + }, + isHidden: server.isHidden, + setHidden: server.setHidden, + }, + } } export type ServerActionsController = ReturnType diff --git a/packages/app/src/servers/registry/row-menu.tsx b/packages/app/src/servers/registry/row-menu.tsx index f2cfd07de65..b6544bece5a 100644 --- a/packages/app/src/servers/registry/row-menu.tsx +++ b/packages/app/src/servers/registry/row-menu.tsx @@ -22,10 +22,14 @@ export const ServerRowMenu: Component<{ canDefault={props.domain.defaults.available()} isDefault={props.domain.defaults.key() === key} canRemove={props.domain.connection.canRemove(key)} + canHide={props.domain.connection.canHide(key)} + hidden={props.domain.connection.isHidden(key)} onEdit={props.onEdit} onSetDefault={() => props.domain.defaults.set(key)} onRemoveDefault={() => props.domain.defaults.set(null)} onRemove={() => props.domain.connection.remove(key)} + onHide={() => props.domain.connection.setHidden(key, true)} + onShow={() => props.domain.connection.setHidden(key, false)} open={props.open} onOpenChange={props.onOpenChange} /> @@ -40,6 +44,8 @@ export function serverMenuLabels(language: ReturnType) { default: language.t("dialog.server.menu.default"), defaultRemove: language.t("dialog.server.menu.defaultRemove"), delete: language.t("dialog.server.menu.delete"), + hide: language.t("dialog.server.menu.hide"), + show: language.t("dialog.server.menu.show"), } } @@ -49,10 +55,14 @@ export const ServerRowMenuView: Component<{ canDefault: boolean isDefault: boolean canRemove: boolean + canHide?: boolean + hidden?: boolean onEdit: (server: ServerConnection.Http) => void onSetDefault: () => void onRemoveDefault: () => void onRemove: () => void + onHide?: () => void + onShow?: () => void open?: boolean onOpenChange?: (open: boolean) => void }> = (props) => { @@ -86,6 +96,12 @@ export const ServerRowMenuView: Component<{ {props.labels.defaultRemove} + + {props.labels.show} + + + {props.labels.hide} + {props.labels.delete}