fix(app): non-fatal error handling
This commit is contained in:
@@ -1,22 +1,36 @@
|
||||
import { createMemo, Show, type ParentProps } from "solid-js"
|
||||
import { createEffect, createMemo, Show, type ParentProps } from "solid-js"
|
||||
import { useNavigate, useParams } from "@solidjs/router"
|
||||
import { SDKProvider, useSDK } from "@/context/sdk"
|
||||
import { SyncProvider, useSync } from "@/context/sync"
|
||||
import { LocalProvider } from "@/context/local"
|
||||
|
||||
import { base64Decode } from "@opencode-ai/util/encode"
|
||||
import { DataProvider } from "@opencode-ai/ui/context"
|
||||
import { iife } from "@opencode-ai/util/iife"
|
||||
import type { QuestionAnswer } from "@opencode-ai/sdk/v2"
|
||||
import { decode64 } from "@/utils/base64"
|
||||
import { showToast } from "@opencode-ai/ui/toast"
|
||||
import { useLanguage } from "@/context/language"
|
||||
|
||||
export default function Layout(props: ParentProps) {
|
||||
const params = useParams()
|
||||
const navigate = useNavigate()
|
||||
const language = useLanguage()
|
||||
const directory = createMemo(() => {
|
||||
return base64Decode(params.dir!)
|
||||
return decode64(params.dir) ?? ""
|
||||
})
|
||||
|
||||
createEffect(() => {
|
||||
if (!params.dir) return
|
||||
if (directory()) return
|
||||
showToast({
|
||||
variant: "error",
|
||||
title: language.t("common.requestFailed"),
|
||||
description: "Invalid directory in URL.",
|
||||
})
|
||||
navigate("/")
|
||||
})
|
||||
return (
|
||||
<Show when={params.dir}>
|
||||
<Show when={directory()}>
|
||||
<SDKProvider directory={directory()}>
|
||||
<SyncProvider>
|
||||
{iife(() => {
|
||||
|
||||
@@ -19,7 +19,8 @@ import { A, useNavigate, useParams } from "@solidjs/router"
|
||||
import { useLayout, getAvatarColors, LocalProject } from "@/context/layout"
|
||||
import { useGlobalSync } from "@/context/global-sync"
|
||||
import { Persist, persisted } from "@/utils/persist"
|
||||
import { base64Decode, base64Encode } from "@opencode-ai/util/encode"
|
||||
import { base64Encode } from "@opencode-ai/util/encode"
|
||||
import { decode64 } from "@/utils/base64"
|
||||
import { Avatar } from "@opencode-ai/ui/avatar"
|
||||
import { ResizeHandle } from "@opencode-ai/ui/resize-handle"
|
||||
import { Button } from "@opencode-ai/ui/button"
|
||||
@@ -420,7 +421,7 @@ export default function Layout(props: ParentProps) {
|
||||
}
|
||||
}
|
||||
|
||||
const currentDir = params.dir ? base64Decode(params.dir) : undefined
|
||||
const currentDir = decode64(params.dir)
|
||||
const currentSession = params.id
|
||||
if (directory === currentDir && props.sessionID === currentSession) return
|
||||
if (directory === currentDir && session?.parentID === currentSession) return
|
||||
@@ -449,7 +450,7 @@ export default function Layout(props: ParentProps) {
|
||||
onCleanup(unsub)
|
||||
|
||||
createEffect(() => {
|
||||
const currentDir = params.dir ? base64Decode(params.dir) : undefined
|
||||
const currentDir = decode64(params.dir)
|
||||
const currentSession = params.id
|
||||
if (!currentDir || !currentSession) return
|
||||
const sessionKey = `${currentDir}:${currentSession}`
|
||||
@@ -503,7 +504,7 @@ export default function Layout(props: ParentProps) {
|
||||
}
|
||||
|
||||
const currentProject = createMemo(() => {
|
||||
const directory = params.dir ? base64Decode(params.dir) : undefined
|
||||
const directory = decode64(params.dir)
|
||||
if (!directory) return
|
||||
|
||||
const projects = layout.projects.list()
|
||||
@@ -638,7 +639,7 @@ export default function Layout(props: ParentProps) {
|
||||
const compare = sortSessions(Date.now())
|
||||
if (workspaceSetting()) {
|
||||
const dirs = workspaceIds(project)
|
||||
const activeDir = params.dir ? base64Decode(params.dir) : ""
|
||||
const activeDir = decode64(params.dir) ?? ""
|
||||
const result: Session[] = []
|
||||
for (const dir of dirs) {
|
||||
const expanded = store.workspaceExpanded[dir] ?? dir === project.worktree
|
||||
@@ -1188,7 +1189,7 @@ export default function Layout(props: ParentProps) {
|
||||
layout.projects.close(directory)
|
||||
layout.projects.open(root)
|
||||
|
||||
if (params.dir && base64Decode(params.dir) === directory) {
|
||||
if (params.dir && decode64(params.dir) === directory) {
|
||||
navigateToProject(root)
|
||||
}
|
||||
}
|
||||
@@ -1431,7 +1432,8 @@ export default function Layout(props: ParentProps) {
|
||||
const dir = value.dir
|
||||
const id = value.id
|
||||
if (!dir || !id) return
|
||||
const directory = base64Decode(dir)
|
||||
const directory = decode64(dir)
|
||||
if (!directory) return
|
||||
setStore("lastSession", directory, id)
|
||||
notification.session.markViewed(id)
|
||||
const expanded = untrack(() => store.workspaceExpanded[directory])
|
||||
@@ -1454,7 +1456,7 @@ export default function Layout(props: ParentProps) {
|
||||
if (!project) return
|
||||
|
||||
if (workspaceSetting()) {
|
||||
const activeDir = params.dir ? base64Decode(params.dir) : ""
|
||||
const activeDir = decode64(params.dir) ?? ""
|
||||
const dirs = [project.worktree, ...(project.sandboxes ?? [])]
|
||||
for (const directory of dirs) {
|
||||
const expanded = store.workspaceExpanded[directory] ?? directory === project.worktree
|
||||
@@ -1504,7 +1506,7 @@ export default function Layout(props: ParentProps) {
|
||||
const local = project.worktree
|
||||
const dirs = [local, ...(project.sandboxes ?? [])]
|
||||
const active = currentProject()
|
||||
const directory = active?.worktree === project.worktree && params.dir ? base64Decode(params.dir) : undefined
|
||||
const directory = active?.worktree === project.worktree ? decode64(params.dir) : undefined
|
||||
const extra = directory && directory !== local && !dirs.includes(directory) ? directory : undefined
|
||||
const pending = extra ? WorktreeState.get(extra)?.status === "pending" : false
|
||||
|
||||
@@ -1930,7 +1932,7 @@ export default function Layout(props: ParentProps) {
|
||||
})
|
||||
const local = createMemo(() => props.directory === props.project.worktree)
|
||||
const active = createMemo(() => {
|
||||
const current = params.dir ? base64Decode(params.dir) : ""
|
||||
const current = decode64(params.dir) ?? ""
|
||||
return current === props.directory
|
||||
})
|
||||
const workspaceValue = createMemo(() => {
|
||||
@@ -2131,7 +2133,7 @@ export default function Layout(props: ParentProps) {
|
||||
const SortableProject = (props: { project: LocalProject; mobile?: boolean }): JSX.Element => {
|
||||
const sortable = createSortable(props.project.worktree)
|
||||
const selected = createMemo(() => {
|
||||
const current = params.dir ? base64Decode(params.dir) : ""
|
||||
const current = decode64(params.dir) ?? ""
|
||||
return props.project.worktree === current || props.project.sandboxes?.includes(current)
|
||||
})
|
||||
|
||||
|
||||
@@ -28,7 +28,7 @@ import { useSync } from "@/context/sync"
|
||||
import { useTerminal, type LocalPTY } from "@/context/terminal"
|
||||
import { useLayout } from "@/context/layout"
|
||||
import { Terminal } from "@/components/terminal"
|
||||
import { checksum, base64Encode, base64Decode } from "@opencode-ai/util/encode"
|
||||
import { checksum, base64Encode } from "@opencode-ai/util/encode"
|
||||
import { findLast } from "@opencode-ai/util/array"
|
||||
import { useDialog } from "@opencode-ai/ui/context/dialog"
|
||||
import { DialogSelectFile } from "@/components/dialog-select-file"
|
||||
@@ -47,6 +47,7 @@ import { useComments, type LineComment } from "@/context/comments"
|
||||
import { extractPromptFromParts } from "@/utils/prompt"
|
||||
import { ConstrainDragYAxis, getDraggableId } from "@/utils/solid-dnd"
|
||||
import { usePermission } from "@/context/permission"
|
||||
import { decode64 } from "@/utils/base64"
|
||||
import { showToast } from "@opencode-ai/ui/toast"
|
||||
import {
|
||||
SessionHeader,
|
||||
@@ -2126,8 +2127,28 @@ export default function Page() {
|
||||
if (!isSvg()) return
|
||||
const c = state()?.content
|
||||
if (!c) return
|
||||
if (c.encoding === "base64") return base64Decode(c.content)
|
||||
return c.content
|
||||
if (c.encoding !== "base64") return c.content
|
||||
return decode64(c.content)
|
||||
})
|
||||
|
||||
const svgDecodeFailed = createMemo(() => {
|
||||
if (!isSvg()) return false
|
||||
const c = state()?.content
|
||||
if (!c) return false
|
||||
if (c.encoding !== "base64") return false
|
||||
return svgContent() === undefined
|
||||
})
|
||||
|
||||
const svgToast = { shown: false }
|
||||
createEffect(() => {
|
||||
if (!svgDecodeFailed()) return
|
||||
if (svgToast.shown) return
|
||||
svgToast.shown = true
|
||||
showToast({
|
||||
variant: "error",
|
||||
title: language.t("toast.file.loadFailed.title"),
|
||||
description: "Invalid base64 content.",
|
||||
})
|
||||
})
|
||||
const svgPreviewUrl = createMemo(() => {
|
||||
if (!isSvg()) return
|
||||
|
||||
Reference in New Issue
Block a user