mirror of
https://github.com/anomalyco/opencode.git
synced 2026-07-10 02:48:31 +00:00
fix(desktop): context menu button / tab intermittent issue (#34420)
Co-authored-by: Brendan Allan <git@brendonovich.dev>
This commit is contained in:
parent
1982d9832b
commit
003c22b4a3
4 changed files with 71 additions and 24 deletions
|
|
@ -26,7 +26,7 @@ function openSessionContext(args: {
|
|||
layout: ReturnType<typeof useLayout>
|
||||
tabs: ReturnType<ReturnType<typeof useLayout>["tabs"]>
|
||||
}) {
|
||||
if (!args.view.reviewPanel.opened()) args.view.reviewPanel.open()
|
||||
args.view.reviewPanel.open(args.view.reviewPanel.opened() ? "other" : "context-button")
|
||||
if (args.layout.fileTree.opened() && args.layout.fileTree.tab() !== "all") args.layout.fileTree.setTab("all")
|
||||
void args.tabs.open("context")
|
||||
args.tabs.setActive("context")
|
||||
|
|
@ -64,16 +64,21 @@ export function SessionContextUsage(props: SessionContextUsageProps) {
|
|||
const cost = createMemo(() => {
|
||||
return usd().format(info()?.cost ?? 0)
|
||||
})
|
||||
const contextVisible = createMemo(() => view().reviewPanel.opened() && tabState.activeTab() === "context")
|
||||
const hasOtherTabs = createMemo(() => tabs().all().some((tab) => tab !== "context" && tab !== "review"))
|
||||
|
||||
const openContext = () => {
|
||||
if (!params.id) return
|
||||
|
||||
if (tabState.activeTab() === "context") {
|
||||
const sessionView = view()
|
||||
if (contextVisible()) {
|
||||
tabs().close("context")
|
||||
if (sessionView.reviewPanel.source() === "context-button" && !hasOtherTabs()) sessionView.reviewPanel.close()
|
||||
return
|
||||
}
|
||||
|
||||
openSessionContext({
|
||||
view: view(),
|
||||
view: sessionView,
|
||||
layout,
|
||||
tabs: tabs(),
|
||||
})
|
||||
|
|
@ -81,7 +86,20 @@ export function SessionContextUsage(props: SessionContextUsageProps) {
|
|||
|
||||
const circle = () => (
|
||||
<div class="flex items-center justify-center">
|
||||
<ProgressCircle size={16} strokeWidth={2} percentage={context()?.usage ?? 0} />
|
||||
<ProgressCircle
|
||||
size={16}
|
||||
strokeWidth={2}
|
||||
percentage={context()?.usage ?? 0}
|
||||
style={
|
||||
variant() === "indicator"
|
||||
? {
|
||||
"--progress-circle-background": "var(--v2-background-bg-layer-04, var(--border-weak-base))",
|
||||
"--progress-circle-background-overlay": "var(--v2-overlay-simple-overlay-pressed, transparent)",
|
||||
"--progress-circle-progress": "var(--v2-icon-icon-base, var(--icon-base))",
|
||||
}
|
||||
: undefined
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
)
|
||||
const circleV2 = () => (
|
||||
|
|
@ -119,10 +137,10 @@ export function SessionContextUsage(props: SessionContextUsageProps) {
|
|||
|
||||
return (
|
||||
<Show when={params.id}>
|
||||
<Tooltip value={tooltipValue()} placement={props.placement ?? "top"}>
|
||||
<Switch>
|
||||
<Match when={variant() === "indicator"}>{circle()}</Match>
|
||||
<Match when={buttonAppearance() === "v2"}>
|
||||
<Switch>
|
||||
<Match when={variant() === "indicator"}>{circle()}</Match>
|
||||
<Match when={buttonAppearance() === "v2"}>
|
||||
<Tooltip value={tooltipValue()} placement={props.placement ?? "top"}>
|
||||
<IconButtonV2
|
||||
type="button"
|
||||
variant="ghost-muted"
|
||||
|
|
@ -131,8 +149,10 @@ export function SessionContextUsage(props: SessionContextUsageProps) {
|
|||
onClick={openContext}
|
||||
aria-label={language.t("context.usage.view")}
|
||||
/>
|
||||
</Match>
|
||||
<Match when={true}>
|
||||
</Tooltip>
|
||||
</Match>
|
||||
<Match when={true}>
|
||||
<Tooltip value={tooltipValue()} placement={props.placement ?? "top"}>
|
||||
<Button
|
||||
type="button"
|
||||
variant="ghost"
|
||||
|
|
@ -142,9 +162,9 @@ export function SessionContextUsage(props: SessionContextUsageProps) {
|
|||
>
|
||||
{circle()}
|
||||
</Button>
|
||||
</Match>
|
||||
</Switch>
|
||||
</Tooltip>
|
||||
</Tooltip>
|
||||
</Match>
|
||||
</Switch>
|
||||
</Show>
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -78,6 +78,7 @@ export type LocalProject = Partial<Project> & { worktree: string; expanded: bool
|
|||
export type HomeProjectSelection = { server: ServerConnection.Key; directory?: string }
|
||||
|
||||
export type ReviewDiffStyle = "unified" | "split"
|
||||
export type ReviewPanelSource = "context-button" | "other"
|
||||
|
||||
export type LayoutRoute =
|
||||
| { type: "home" }
|
||||
|
|
@ -304,6 +305,9 @@ export const { use: useLayout, provider: LayoutProvider } = createSimpleContext(
|
|||
},
|
||||
}),
|
||||
)
|
||||
const [ephemeral, setEphemeral] = createStore({
|
||||
reviewPanelSource: "other" as ReviewPanelSource,
|
||||
})
|
||||
|
||||
const MAX_SESSION_KEYS = 50
|
||||
const PENDING_MESSAGE_TTL_MS = 2 * 60 * 1000
|
||||
|
|
@ -780,6 +784,7 @@ export const { use: useLayout, provider: LayoutProvider } = createSimpleContext(
|
|||
const s = createMemo(() => store.sessionView[key()] ?? { scroll: {} })
|
||||
const terminalOpened = createMemo(() => store.terminal?.opened ?? false)
|
||||
const reviewPanelOpened = createMemo(() => store.review?.panelOpened ?? DEFAULT_REVIEW_PANEL_OPENED)
|
||||
const reviewPanelSource = createMemo(() => (reviewPanelOpened() ? ephemeral.reviewPanelSource : "other"))
|
||||
|
||||
function setTerminalOpened(next: boolean) {
|
||||
const current = store.terminal
|
||||
|
|
@ -793,16 +798,26 @@ export const { use: useLayout, provider: LayoutProvider } = createSimpleContext(
|
|||
setStore("terminal", "opened", next)
|
||||
}
|
||||
|
||||
function setReviewPanelOpened(next: boolean) {
|
||||
function setReviewPanelOpened(next: boolean, source: ReviewPanelSource) {
|
||||
const nextSource = next ? source : "other"
|
||||
const current = store.review
|
||||
if (!current) {
|
||||
setStore("review", { diffStyle: "split" as ReviewDiffStyle, panelOpened: next })
|
||||
batch(() => {
|
||||
setStore("review", { diffStyle: "split" as ReviewDiffStyle, panelOpened: next })
|
||||
setEphemeral("reviewPanelSource", nextSource)
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
const value = current.panelOpened ?? DEFAULT_REVIEW_PANEL_OPENED
|
||||
if (value === next) return
|
||||
setStore("review", "panelOpened", next)
|
||||
if (value === next) {
|
||||
if (ephemeral.reviewPanelSource !== nextSource) setEphemeral("reviewPanelSource", nextSource)
|
||||
return
|
||||
}
|
||||
batch(() => {
|
||||
setStore("review", "panelOpened", next)
|
||||
setEphemeral("reviewPanelSource", nextSource)
|
||||
})
|
||||
}
|
||||
|
||||
return {
|
||||
|
|
@ -838,14 +853,15 @@ export const { use: useLayout, provider: LayoutProvider } = createSimpleContext(
|
|||
},
|
||||
reviewPanel: {
|
||||
opened: reviewPanelOpened,
|
||||
open() {
|
||||
setReviewPanelOpened(true)
|
||||
source: reviewPanelSource,
|
||||
open(source: ReviewPanelSource = "other") {
|
||||
setReviewPanelOpened(true, source)
|
||||
},
|
||||
close() {
|
||||
setReviewPanelOpened(false)
|
||||
setReviewPanelOpened(false, "other")
|
||||
},
|
||||
toggle() {
|
||||
setReviewPanelOpened(!reviewPanelOpened())
|
||||
setReviewPanelOpened(!reviewPanelOpened(), "other")
|
||||
},
|
||||
},
|
||||
review: {
|
||||
|
|
|
|||
|
|
@ -2,11 +2,15 @@
|
|||
transform: rotate(-90deg);
|
||||
|
||||
[data-slot="progress-circle-background"] {
|
||||
stroke: var(--border-weak-base);
|
||||
stroke: var(--progress-circle-background, var(--border-weak-base));
|
||||
}
|
||||
|
||||
[data-slot="progress-circle-background-overlay"] {
|
||||
stroke: var(--progress-circle-background-overlay, transparent);
|
||||
}
|
||||
|
||||
[data-slot="progress-circle-progress"] {
|
||||
stroke: var(--border-active);
|
||||
stroke: var(--progress-circle-progress, var(--border-active));
|
||||
transition: stroke-dashoffset 0.35s cubic-bezier(0.65, 0, 0.35, 1);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import { type ComponentProps, createMemo, splitProps } from "solid-js"
|
||||
|
||||
export interface ProgressCircleProps extends Pick<ComponentProps<"svg">, "class" | "classList"> {
|
||||
export interface ProgressCircleProps extends Pick<ComponentProps<"svg">, "class" | "classList" | "style"> {
|
||||
percentage: number
|
||||
size?: number
|
||||
strokeWidth?: number
|
||||
|
|
@ -43,6 +43,13 @@ export function ProgressCircle(props: ProgressCircleProps) {
|
|||
data-slot="progress-circle-background"
|
||||
stroke-width={strokeWidth()}
|
||||
/>
|
||||
<circle
|
||||
cx={center}
|
||||
cy={center}
|
||||
r={radius()}
|
||||
data-slot="progress-circle-background-overlay"
|
||||
stroke-width={strokeWidth()}
|
||||
/>
|
||||
<circle
|
||||
cx={center}
|
||||
cy={center}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue