Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
69 changes: 57 additions & 12 deletions packages/app/src/components/session/session-header.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,12 @@ export function SessionHeader() {
const projectDirectory = createMemo(() => base64Decode(params.dir ?? ""))

const sessions = createMemo(() => (sync.data.session ?? []).filter((s) => !s.parentID))
const currentSession = createMemo(() => sessions().find((s) => s.id === params.id))
const currentSession = createMemo(() => sync.data.session.find((s) => s.id === params.id))
const parentSession = createMemo(() => {
const current = currentSession()
if (!current?.parentID) return undefined
return sync.data.session.find((s) => s.id === current.parentID)
})
const shareEnabled = createMemo(() => sync.data.config.share !== "disabled")

function navigateToProject(directory: string) {
Expand All @@ -43,6 +48,8 @@ export function SessionHeader() {

function navigateToSession(session: Session | undefined) {
if (!session) return
// Only navigate if we're actually changing to a different session
if (session.id === params.id) return
navigate(`/${params.dir}/session/${session.id}`)
}

Expand Down Expand Up @@ -77,18 +84,56 @@ export function SessionHeader() {
</Select>
<div class="text-text-weaker">/</div>
</div>
<Select
options={sessions()}
current={currentSession()}
placeholder="New session"
label={(x) => x.title}
value={(x) => x.id}
onSelect={navigateToSession}
class="text-14-regular text-text-base max-w-[calc(100vw-180px)] md:max-w-md"
variant="ghost"
/>
<Show
when={parentSession()}
fallback={
<>
<Select
options={sessions()}
current={currentSession()}
placeholder="New session"
label={(x) => x.title}
value={(x) => x.id}
onSelect={navigateToSession}
class="text-14-regular text-text-base max-w-[calc(100vw-180px)] md:max-w-md"
variant="ghost"
/>
</>
}
>
<div class="flex items-center gap-2 min-w-0">
<Select
options={sessions()}
current={parentSession()}
placeholder="Back to parent session"
label={(x) => x.title}
value={(x) => x.id}
onSelect={(session) => {
// Only navigate if selecting a different session than current parent
const currentParent = parentSession()
if (session && currentParent && session.id !== currentParent.id) {
navigateToSession(session)
}
}}
class="text-14-regular text-text-base max-w-[calc(100vw-180px)] md:max-w-md"
variant="ghost"
/>
<div class="text-text-weaker">/</div>
<div class="flex items-center gap-1.5 min-w-0">
<Tooltip value="Back to parent session">
<button
type="button"
class="flex items-center justify-center gap-1 p-1 rounded hover:bg-surface-raised-base-hover active:bg-surface-raised-base-active transition-colors flex-shrink-0"
onClick={() => navigateToSession(parentSession())}
>
<Icon name="arrow-left" size="small" class="text-icon-base" />
</button>
</Tooltip>
</div>
</div>
</Show>
</div>
<Show when={currentSession()}>
<Show when={currentSession() && !parentSession()}>
<TooltipKeybind class="hidden xl:block" title="New session" keybind={command.keybind("session.new")}>
<IconButton as={A} href={`/${params.dir}/session`} icon="edit-small-2" variant="ghost" />
</TooltipKeybind>
Expand Down
14 changes: 12 additions & 2 deletions packages/app/src/pages/directory-layout.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { createMemo, Show, type ParentProps } from "solid-js"
import { useParams } from "@solidjs/router"
import { useNavigate, useParams } from "@solidjs/router"
import { SDKProvider, useSDK } from "@/context/sdk"
import { SyncProvider, useSync } from "@/context/sync"
import { LocalProvider } from "@/context/local"
Expand All @@ -10,6 +10,7 @@ import { iife } from "@opencode-ai/util/iife"

export default function Layout(props: ParentProps) {
const params = useParams()
const navigate = useNavigate()
const directory = createMemo(() => {
return base64Decode(params.dir!)
})
Expand All @@ -26,8 +27,17 @@ export default function Layout(props: ParentProps) {
response: "once" | "always" | "reject"
}) => sdk.client.permission.respond(input)

const navigateToSession = (sessionID: string) => {
navigate(`/${params.dir}/session/${sessionID}`)
}

return (
<DataProvider data={sync.data} directory={directory()} onPermissionRespond={respond}>
<DataProvider
data={sync.data}
directory={directory()}
onPermissionRespond={respond}
onNavigateToSession={navigateToSession}
>
<LocalProvider>{props.children}</LocalProvider>
</DataProvider>
)
Expand Down
10 changes: 10 additions & 0 deletions packages/ui/src/components/basic-tool.css
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,16 @@
line-height: var(--line-height-large);
letter-spacing: var(--letter-spacing-normal);
color: var(--text-weak);

&.clickable {
cursor: pointer;
text-decoration: underline;
transition: color 0.15s ease;

&:hover {
color: var(--text-base);
}
}
}

[data-slot="basic-tool-tool-arg"] {
Expand Down
8 changes: 8 additions & 0 deletions packages/ui/src/components/basic-tool.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ export interface BasicToolProps {
hideDetails?: boolean
defaultOpen?: boolean
forceOpen?: boolean
onSubtitleClick?: () => void
}

export function BasicTool(props: BasicToolProps) {
Expand Down Expand Up @@ -59,6 +60,13 @@ export function BasicTool(props: BasicToolProps) {
data-slot="basic-tool-tool-subtitle"
classList={{
[trigger().subtitleClass ?? ""]: !!trigger().subtitleClass,
clickable: !!props.onSubtitleClick,
}}
onClick={(e) => {
if (props.onSubtitleClick) {
e.stopPropagation()
props.onSubtitleClick()
}
}}
>
{trigger().subtitle}
Expand Down
9 changes: 9 additions & 0 deletions packages/ui/src/components/message-part.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -759,6 +759,13 @@ ToolRegistry.register({
})
}

const handleSubtitleClick = () => {
const sessionId = childSessionId()
if (sessionId && data.navigateToSession) {
data.navigateToSession(sessionId)
}
}

const renderChildToolPart = () => {
const toolData = childToolPart()
if (!toolData) return null
Expand Down Expand Up @@ -797,6 +804,7 @@ ToolRegistry.register({
titleClass: "capitalize",
subtitle: props.input.description,
}}
onSubtitleClick={handleSubtitleClick}
/>
}
>
Expand Down Expand Up @@ -826,6 +834,7 @@ ToolRegistry.register({
titleClass: "capitalize",
subtitle: props.input.description,
}}
onSubtitleClick={handleSubtitleClick}
>
<div
ref={autoScroll.scrollRef}
Expand Down
10 changes: 9 additions & 1 deletion packages/ui/src/context/data.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,16 @@ export type PermissionRespondFn = (input: {
response: "once" | "always" | "reject"
}) => void

export type NavigateToSessionFn = (sessionID: string) => void

export const { use: useData, provider: DataProvider } = createSimpleContext({
name: "Data",
init: (props: { data: Data; directory: string; onPermissionRespond?: PermissionRespondFn }) => {
init: (props: {
data: Data
directory: string
onPermissionRespond?: PermissionRespondFn
onNavigateToSession?: NavigateToSessionFn
}) => {
return {
get store() {
return props.data
Expand All @@ -41,6 +48,7 @@ export const { use: useData, provider: DataProvider } = createSimpleContext({
return props.directory
},
respondToPermission: props.onPermissionRespond,
navigateToSession: props.onNavigateToSession,
}
},
})