diff options
| author | Adam <[email protected]> | 2026-02-12 11:26:19 -0600 |
|---|---|---|
| committer | GitHub <[email protected]> | 2026-02-12 11:26:19 -0600 |
| commit | da952135cabba2926698298797cd301e7adaf48c (patch) | |
| tree | 78635fe4f7d656266ad3cc1c353b04b56969515c /packages/app/src/pages/session | |
| parent | 789705ea96ae28af7e30801fd6039ce89b6ac48e (diff) | |
| download | opencode-da952135cabba2926698298797cd301e7adaf48c.tar.gz opencode-da952135cabba2926698298797cd301e7adaf48c.zip | |
chore(app): refactor for better solidjs hygiene (#13344)
Diffstat (limited to 'packages/app/src/pages/session')
| -rw-r--r-- | packages/app/src/pages/session/file-tabs.tsx | 27 | ||||
| -rw-r--r-- | packages/app/src/pages/session/helpers.ts | 9 | ||||
| -rw-r--r-- | packages/app/src/pages/session/session-side-panel.tsx | 6 | ||||
| -rw-r--r-- | packages/app/src/pages/session/terminal-panel.tsx | 16 | ||||
| -rw-r--r-- | packages/app/src/pages/session/use-session-hash-scroll.ts | 17 |
5 files changed, 54 insertions, 21 deletions
diff --git a/packages/app/src/pages/session/file-tabs.tsx b/packages/app/src/pages/session/file-tabs.tsx index c94c0ff35..5b3f57dbe 100644 --- a/packages/app/src/pages/session/file-tabs.tsx +++ b/packages/app/src/pages/session/file-tabs.tsx @@ -1,5 +1,5 @@ import { type ValidComponent, createEffect, createMemo, For, Match, on, onCleanup, Show, Switch } from "solid-js" -import { createStore } from "solid-js/store" +import { createStore, produce } from "solid-js/store" import { Dynamic } from "solid-js/web" import { checksum } from "@opencode-ai/util/encode" import { decode64 } from "@/utils/base64" @@ -112,6 +112,12 @@ export function FileTabContent(props: { return props.comments.list(p) }) + const commentLayout = createMemo(() => { + return fileComments() + .map((comment) => `${comment.id}:${comment.selection.start}:${comment.selection.end}`) + .join("|") + }) + const commentedLines = createMemo(() => fileComments().map((comment) => comment.selection)) const [note, setNote] = createStore({ @@ -164,7 +170,22 @@ export function FileTabContent(props: { next[comment.id] = markerTop(el, marker) } - setNote("positions", next) + const removed = Object.keys(note.positions).filter((id) => next[id] === undefined) + const changed = Object.entries(next).filter(([id, top]) => note.positions[id] !== top) + if (removed.length > 0 || changed.length > 0) { + setNote( + "positions", + produce((draft) => { + for (const id of removed) { + delete draft[id] + } + + for (const [id, top] of changed) { + draft[id] = top + } + }), + ) + } const range = note.commenting if (!range) { @@ -186,7 +207,7 @@ export function FileTabContent(props: { } createEffect(() => { - fileComments() + commentLayout() scheduleComments() }) diff --git a/packages/app/src/pages/session/helpers.ts b/packages/app/src/pages/session/helpers.ts index dcf2c8784..6ead7a7f2 100644 --- a/packages/app/src/pages/session/helpers.ts +++ b/packages/app/src/pages/session/helpers.ts @@ -1,4 +1,5 @@ import type { CommandOption } from "@/context/command" +import { batch } from "solid-js" export const focusTerminalById = (id: string) => { const wrapper = document.getElementById(`terminal-wrapper-${id}`) @@ -27,9 +28,11 @@ export const createOpenReviewFile = (input: { loadFile: (path: string) => void }) => { return (path: string) => { - input.showAllFiles() - input.openTab(input.tabForPath(path)) - input.loadFile(path) + batch(() => { + input.showAllFiles() + input.openTab(input.tabForPath(path)) + input.loadFile(path) + }) } } diff --git a/packages/app/src/pages/session/session-side-panel.tsx b/packages/app/src/pages/session/session-side-panel.tsx index 15ad90ffe..33954f64a 100644 --- a/packages/app/src/pages/session/session-side-panel.tsx +++ b/packages/app/src/pages/session/session-side-panel.tsx @@ -72,6 +72,8 @@ export function SessionSidePanel(props: { activeDiff?: string focusReviewDiff: (path: string) => void }) { + const openedTabs = createMemo(() => props.openedTabs()) + return ( <Show when={props.open}> <aside @@ -140,8 +142,8 @@ export function SessionSidePanel(props: { </div> </Tabs.Trigger> </Show> - <SortableProvider ids={props.openedTabs()}> - <For each={props.openedTabs()}> + <SortableProvider ids={openedTabs()}> + <For each={openedTabs()}> {(tab) => <SortableTab tab={tab} onTabClose={props.tabs().close} />} </For> </SortableProvider> diff --git a/packages/app/src/pages/session/terminal-panel.tsx b/packages/app/src/pages/session/terminal-panel.tsx index d3475c714..7ec4356b1 100644 --- a/packages/app/src/pages/session/terminal-panel.tsx +++ b/packages/app/src/pages/session/terminal-panel.tsx @@ -1,4 +1,4 @@ -import { For, Show } from "solid-js" +import { For, Show, createMemo } from "solid-js" import { Tabs } from "@opencode-ai/ui/tabs" import { ResizeHandle } from "@opencode-ai/ui/resize-handle" import { IconButton } from "@opencode-ai/ui/icon-button" @@ -8,7 +8,7 @@ import type { DragEvent } from "@thisbeyond/solid-dnd" import { ConstrainDragYAxis } from "@/utils/solid-dnd" import { SortableTerminalTab } from "@/components/session" import { Terminal } from "@/components/terminal" -import { useTerminal, type LocalPTY } from "@/context/terminal" +import { useTerminal } from "@/context/terminal" import { useLanguage } from "@/context/language" import { useCommand } from "@/context/command" import { terminalTabLabel } from "@/pages/session/terminal-label" @@ -28,6 +28,10 @@ export function TerminalPanel(props: { handleTerminalDragEnd: () => void onCloseTab: () => void }) { + const all = createMemo(() => props.terminal.all()) + const ids = createMemo(() => all().map((pty) => pty.id)) + const byId = createMemo(() => new Map(all().map((pty) => [pty.id, pty]))) + return ( <Show when={props.open}> <div @@ -86,8 +90,8 @@ export function TerminalPanel(props: { class="!h-auto !flex-none" > <Tabs.List class="h-10"> - <SortableProvider ids={props.terminal.all().map((t: LocalPTY) => t.id)}> - <For each={props.terminal.all()}> + <SortableProvider ids={ids()}> + <For each={all()}> {(pty) => ( <SortableTerminalTab terminal={pty} @@ -117,7 +121,7 @@ export function TerminalPanel(props: { </Tabs.List> </Tabs> <div class="flex-1 min-h-0 relative"> - <For each={props.terminal.all()}> + <For each={all()}> {(pty) => ( <div id={`terminal-wrapper-${pty.id}`} @@ -142,7 +146,7 @@ export function TerminalPanel(props: { <Show when={props.activeTerminalDraggable()}> {(draggedId) => { return ( - <Show when={props.terminal.all().find((t: LocalPTY) => t.id === draggedId())}> + <Show when={byId().get(draggedId())}> {(t) => ( <div class="relative p-1 h-10 flex items-center bg-background-stronger text-14-regular"> {terminalTabLabel({ diff --git a/packages/app/src/pages/session/use-session-hash-scroll.ts b/packages/app/src/pages/session/use-session-hash-scroll.ts index 8952bbd98..555761ad1 100644 --- a/packages/app/src/pages/session/use-session-hash-scroll.ts +++ b/packages/app/src/pages/session/use-session-hash-scroll.ts @@ -1,4 +1,4 @@ -import { createEffect, on, onCleanup } from "solid-js" +import { createEffect, createMemo, on, onCleanup } from "solid-js" import { UserMessage } from "@opencode-ai/sdk/v2" export const messageIdFromHash = (hash: string) => { @@ -26,6 +26,10 @@ export const useSessionHashScroll = (input: { scheduleScrollState: (el: HTMLDivElement) => void consumePendingMessage: (key: string) => string | undefined }) => { + const visibleUserMessages = createMemo(() => input.visibleUserMessages()) + const messageById = createMemo(() => new Map(visibleUserMessages().map((m) => [m.id, m]))) + const messageIndex = createMemo(() => new Map(visibleUserMessages().map((m, i) => [m.id, i]))) + const clearMessageHash = () => { if (!window.location.hash) return window.history.replaceState(null, "", window.location.href.replace(/#.*$/, "")) @@ -47,10 +51,9 @@ export const useSessionHashScroll = (input: { } const scrollToMessage = (message: UserMessage, behavior: ScrollBehavior = "smooth") => { - input.setActiveMessage(message) + if (input.currentMessageId() !== message.id) input.setActiveMessage(message) - const msgs = input.visibleUserMessages() - const index = msgs.findIndex((m) => m.id === message.id) + const index = messageIndex().get(message.id) ?? -1 if (index !== -1 && index < input.turnStart()) { input.setTurnStart(index) input.scheduleTurnBackfill() @@ -107,7 +110,7 @@ export const useSessionHashScroll = (input: { const messageId = messageIdFromHash(hash) if (messageId) { input.autoScroll.pause() - const msg = input.visibleUserMessages().find((m) => m.id === messageId) + const msg = messageById().get(messageId) if (msg) { scrollToMessage(msg, behavior) return @@ -144,14 +147,14 @@ export const useSessionHashScroll = (input: { createEffect(() => { if (!input.sessionID() || !input.messagesReady()) return - input.visibleUserMessages().length + visibleUserMessages() input.turnStart() const targetId = input.pendingMessage() ?? messageIdFromHash(window.location.hash) if (!targetId) return if (input.currentMessageId() === targetId) return - const msg = input.visibleUserMessages().find((m) => m.id === targetId) + const msg = messageById().get(targetId) if (!msg) return if (input.pendingMessage() === targetId) input.setPendingMessage(undefined) |
