summaryrefslogtreecommitdiffhomepage
path: root/packages/app/src/components
diff options
context:
space:
mode:
authorAdam <[email protected]>2026-03-12 07:26:43 -0500
committerGitHub <[email protected]>2026-03-12 12:26:43 +0000
commitd4107d51f163b74c96895b50d653828c698d937e (patch)
tree070ae9ad38ebd230d75517d485fc0c86f2263c6b /packages/app/src/components
parentd8fbe0af0151c662008d8a2dbbb7c76ff5db88d4 (diff)
downloadopencode-d4107d51f163b74c96895b50d653828c698d937e.tar.gz
opencode-d4107d51f163b74c96895b50d653828c698d937e.zip
chore: cleanup (#17115)
Diffstat (limited to 'packages/app/src/components')
-rw-r--r--packages/app/src/components/session/session-sortable-terminal-tab.tsx18
-rw-r--r--packages/app/src/components/settings-agents.tsx16
-rw-r--r--packages/app/src/components/settings-commands.tsx16
-rw-r--r--packages/app/src/components/settings-mcp.tsx16
-rw-r--r--packages/app/src/components/settings-permissions.tsx230
5 files changed, 3 insertions, 293 deletions
diff --git a/packages/app/src/components/session/session-sortable-terminal-tab.tsx b/packages/app/src/components/session/session-sortable-terminal-tab.tsx
index 6fe6186d5..4f49911c1 100644
--- a/packages/app/src/components/session/session-sortable-terminal-tab.tsx
+++ b/packages/app/src/components/session/session-sortable-terminal-tab.tsx
@@ -8,6 +8,7 @@ import { DropdownMenu } from "@opencode-ai/ui/dropdown-menu"
import { Icon } from "@opencode-ai/ui/icon"
import { useTerminal, type LocalPTY } from "@/context/terminal"
import { useLanguage } from "@/context/language"
+import { focusTerminalById } from "@/pages/session/helpers"
export function SortableTerminalTab(props: { terminal: LocalPTY; onClose?: () => void }): JSX.Element {
const terminal = useTerminal()
@@ -53,21 +54,8 @@ export function SortableTerminalTab(props: { terminal: LocalPTY; onClose?: () =>
const focus = () => {
if (store.editing) return
-
- if (document.activeElement instanceof HTMLElement) {
- document.activeElement.blur()
- }
- const wrapper = document.getElementById(`terminal-wrapper-${props.terminal.id}`)
- const element = wrapper?.querySelector('[data-component="terminal"]') as HTMLElement
- if (!element) return
-
- const textarea = element.querySelector("textarea") as HTMLTextAreaElement
- if (textarea) {
- textarea.focus()
- return
- }
- element.focus()
- element.dispatchEvent(new PointerEvent("pointerdown", { bubbles: true, cancelable: true }))
+ if (document.activeElement instanceof HTMLElement) document.activeElement.blur()
+ focusTerminalById(props.terminal.id)
}
const edit = (e?: Event) => {
diff --git a/packages/app/src/components/settings-agents.tsx b/packages/app/src/components/settings-agents.tsx
deleted file mode 100644
index 74a942f77..000000000
--- a/packages/app/src/components/settings-agents.tsx
+++ /dev/null
@@ -1,16 +0,0 @@
-import { Component } from "solid-js"
-import { useLanguage } from "@/context/language"
-
-export const SettingsAgents: Component = () => {
- // TODO: Replace this placeholder with full agents settings controls.
- const language = useLanguage()
-
- return (
- <div class="flex flex-col h-full overflow-y-auto">
- <div class="flex flex-col gap-6 p-6 max-w-[600px]">
- <h2 class="text-16-medium text-text-strong">{language.t("settings.agents.title")}</h2>
- <p class="text-14-regular text-text-weak">{language.t("settings.agents.description")}</p>
- </div>
- </div>
- )
-}
diff --git a/packages/app/src/components/settings-commands.tsx b/packages/app/src/components/settings-commands.tsx
deleted file mode 100644
index e158d231c..000000000
--- a/packages/app/src/components/settings-commands.tsx
+++ /dev/null
@@ -1,16 +0,0 @@
-import { Component } from "solid-js"
-import { useLanguage } from "@/context/language"
-
-export const SettingsCommands: Component = () => {
- // TODO: Replace this placeholder with full commands settings controls.
- const language = useLanguage()
-
- return (
- <div class="flex flex-col h-full overflow-y-auto">
- <div class="flex flex-col gap-6 p-6 max-w-[600px]">
- <h2 class="text-16-medium text-text-strong">{language.t("settings.commands.title")}</h2>
- <p class="text-14-regular text-text-weak">{language.t("settings.commands.description")}</p>
- </div>
- </div>
- )
-}
diff --git a/packages/app/src/components/settings-mcp.tsx b/packages/app/src/components/settings-mcp.tsx
deleted file mode 100644
index 507e041aa..000000000
--- a/packages/app/src/components/settings-mcp.tsx
+++ /dev/null
@@ -1,16 +0,0 @@
-import { Component } from "solid-js"
-import { useLanguage } from "@/context/language"
-
-export const SettingsMcp: Component = () => {
- // TODO: Replace this placeholder with full MCP settings controls.
- const language = useLanguage()
-
- return (
- <div class="flex flex-col h-full overflow-y-auto">
- <div class="flex flex-col gap-6 p-6 max-w-[600px]">
- <h2 class="text-16-medium text-text-strong">{language.t("settings.mcp.title")}</h2>
- <p class="text-14-regular text-text-weak">{language.t("settings.mcp.description")}</p>
- </div>
- </div>
- )
-}
diff --git a/packages/app/src/components/settings-permissions.tsx b/packages/app/src/components/settings-permissions.tsx
deleted file mode 100644
index 5c922ba44..000000000
--- a/packages/app/src/components/settings-permissions.tsx
+++ /dev/null
@@ -1,230 +0,0 @@
-import { Select } from "@opencode-ai/ui/select"
-import { showToast } from "@opencode-ai/ui/toast"
-import { Component, For, createMemo, type JSX } from "solid-js"
-import { useGlobalSync } from "@/context/global-sync"
-import { useLanguage } from "@/context/language"
-
-type PermissionAction = "allow" | "ask" | "deny"
-
-type PermissionObject = Record<string, PermissionAction>
-type PermissionValue = PermissionAction | PermissionObject | string[] | undefined
-type PermissionMap = Record<string, PermissionValue>
-
-type PermissionItem = {
- id: string
- title: string
- description: string
-}
-
-const ACTIONS = [
- { value: "allow", label: "settings.permissions.action.allow" },
- { value: "ask", label: "settings.permissions.action.ask" },
- { value: "deny", label: "settings.permissions.action.deny" },
-] as const
-
-const ITEMS = [
- {
- id: "read",
- title: "settings.permissions.tool.read.title",
- description: "settings.permissions.tool.read.description",
- },
- {
- id: "edit",
- title: "settings.permissions.tool.edit.title",
- description: "settings.permissions.tool.edit.description",
- },
- {
- id: "glob",
- title: "settings.permissions.tool.glob.title",
- description: "settings.permissions.tool.glob.description",
- },
- {
- id: "grep",
- title: "settings.permissions.tool.grep.title",
- description: "settings.permissions.tool.grep.description",
- },
- {
- id: "list",
- title: "settings.permissions.tool.list.title",
- description: "settings.permissions.tool.list.description",
- },
- {
- id: "bash",
- title: "settings.permissions.tool.bash.title",
- description: "settings.permissions.tool.bash.description",
- },
- {
- id: "task",
- title: "settings.permissions.tool.task.title",
- description: "settings.permissions.tool.task.description",
- },
- {
- id: "skill",
- title: "settings.permissions.tool.skill.title",
- description: "settings.permissions.tool.skill.description",
- },
- {
- id: "lsp",
- title: "settings.permissions.tool.lsp.title",
- description: "settings.permissions.tool.lsp.description",
- },
- {
- id: "todoread",
- title: "settings.permissions.tool.todoread.title",
- description: "settings.permissions.tool.todoread.description",
- },
- {
- id: "todowrite",
- title: "settings.permissions.tool.todowrite.title",
- description: "settings.permissions.tool.todowrite.description",
- },
- {
- id: "webfetch",
- title: "settings.permissions.tool.webfetch.title",
- description: "settings.permissions.tool.webfetch.description",
- },
- {
- id: "websearch",
- title: "settings.permissions.tool.websearch.title",
- description: "settings.permissions.tool.websearch.description",
- },
- {
- id: "codesearch",
- title: "settings.permissions.tool.codesearch.title",
- description: "settings.permissions.tool.codesearch.description",
- },
- {
- id: "external_directory",
- title: "settings.permissions.tool.external_directory.title",
- description: "settings.permissions.tool.external_directory.description",
- },
- {
- id: "doom_loop",
- title: "settings.permissions.tool.doom_loop.title",
- description: "settings.permissions.tool.doom_loop.description",
- },
-] as const
-
-const VALID_ACTIONS = new Set<PermissionAction>(["allow", "ask", "deny"])
-
-function toMap(value: unknown): PermissionMap {
- if (value && typeof value === "object" && !Array.isArray(value)) return value as PermissionMap
-
- const action = getAction(value)
- if (action) return { "*": action }
-
- return {}
-}
-
-function getAction(value: unknown): PermissionAction | undefined {
- if (typeof value === "string" && VALID_ACTIONS.has(value as PermissionAction)) return value as PermissionAction
- return
-}
-
-function getRuleDefault(value: unknown): PermissionAction | undefined {
- const action = getAction(value)
- if (action) return action
-
- if (!value || typeof value !== "object" || Array.isArray(value)) return
-
- return getAction((value as Record<string, unknown>)["*"])
-}
-
-export const SettingsPermissions: Component = () => {
- const globalSync = useGlobalSync()
- const language = useLanguage()
-
- const actions = createMemo(
- (): Array<{ value: PermissionAction; label: string }> =>
- ACTIONS.map((action) => ({
- value: action.value,
- label: language.t(action.label),
- })),
- )
-
- const permission = createMemo(() => {
- return toMap(globalSync.data.config.permission)
- })
-
- const actionFor = (id: string): PermissionAction => {
- const value = permission()[id]
- const direct = getRuleDefault(value)
- if (direct) return direct
-
- const wildcard = getRuleDefault(permission()["*"])
- if (wildcard) return wildcard
-
- return "allow"
- }
-
- const setPermission = async (id: string, action: PermissionAction) => {
- const before = globalSync.data.config.permission
- const map = toMap(before)
- const existing = map[id]
-
- const nextValue =
- existing && typeof existing === "object" && !Array.isArray(existing) ? { ...existing, "*": action } : action
-
- const rollback = (err: unknown) => {
- globalSync.set("config", "permission", before)
- const message = err instanceof Error ? err.message : String(err)
- showToast({ title: language.t("settings.permissions.toast.updateFailed.title"), description: message })
- }
-
- globalSync.set("config", "permission", { ...map, [id]: nextValue })
- globalSync.updateConfig({ permission: { [id]: nextValue } }).catch(rollback)
- }
-
- return (
- <div class="flex flex-col h-full overflow-y-auto no-scrollbar">
- <div class="sticky top-0 z-10 bg-[linear-gradient(to_bottom,var(--surface-stronger-non-alpha)_calc(100%_-_24px),transparent)]">
- <div class="flex flex-col gap-1 px-4 py-8 sm:p-8 max-w-[720px]">
- <h2 class="text-16-medium text-text-strong">{language.t("settings.permissions.title")}</h2>
- <p class="text-14-regular text-text-weak">{language.t("settings.permissions.description")}</p>
- </div>
- </div>
-
- <div class="flex flex-col gap-6 px-4 py-6 sm:p-8 sm:pt-6 max-w-[720px]">
- <div class="flex flex-col gap-2">
- <h3 class="text-14-medium text-text-strong">{language.t("settings.permissions.section.tools")}</h3>
- <div class="border border-border-weak-base rounded-lg overflow-hidden">
- <For each={ITEMS}>
- {(item) => (
- <SettingsRow title={language.t(item.title)} description={language.t(item.description)}>
- <Select
- options={actions()}
- current={actions().find((o) => o.value === actionFor(item.id))}
- value={(o) => o.value}
- label={(o) => o.label}
- onSelect={(option) => option && setPermission(item.id, option.value)}
- variant="secondary"
- size="small"
- triggerVariant="settings"
- />
- </SettingsRow>
- )}
- </For>
- </div>
- </div>
- </div>
- </div>
- )
-}
-
-interface SettingsRowProps {
- title: string
- description: string
- children: JSX.Element
-}
-
-const SettingsRow: Component<SettingsRowProps> = (props) => {
- return (
- <div class="flex flex-wrap items-center justify-between gap-4 px-4 py-3 border-b border-border-weak-base last:border-none">
- <div class="flex flex-col gap-0.5 min-w-0">
- <span class="text-14-medium text-text-strong">{props.title}</span>
- <span class="text-12-regular text-text-weak">{props.description}</span>
- </div>
- <div class="flex-shrink-0">{props.children}</div>
- </div>
- )
-}