summaryrefslogtreecommitdiffhomepage
path: root/packages/desktop/src
diff options
context:
space:
mode:
authorAdam <[email protected]>2025-12-18 04:26:17 -0600
committerAdam <[email protected]>2025-12-18 04:26:21 -0600
commite37a75a411c584d3e463662a0219fd342d4247ab (patch)
treeeb3944722e942b3244c4f13466855fca712bc3c6 /packages/desktop/src
parent194ff4919cd1e68caaaa8336da0b13b815c74072 (diff)
downloadopencode-e37a75a411c584d3e463662a0219fd342d4247ab.tar.gz
opencode-e37a75a411c584d3e463662a0219fd342d4247ab.zip
feat(desktop): custom update toast
Diffstat (limited to 'packages/desktop/src')
-rw-r--r--packages/desktop/src/app.tsx91
-rw-r--r--packages/desktop/src/context/platform.tsx6
-rw-r--r--packages/desktop/src/pages/layout.tsx55
3 files changed, 98 insertions, 54 deletions
diff --git a/packages/desktop/src/app.tsx b/packages/desktop/src/app.tsx
index 10bde2202..91952fc9d 100644
--- a/packages/desktop/src/app.tsx
+++ b/packages/desktop/src/app.tsx
@@ -1,5 +1,5 @@
import "@/index.css"
-import { Show } from "solid-js"
+import { ErrorBoundary, Show } from "solid-js"
import { Router, Route, Navigate } from "@solidjs/router"
import { MetaProvider } from "@solidjs/meta"
import { Font } from "@opencode-ai/ui/font"
@@ -20,6 +20,7 @@ import Layout from "@/pages/layout"
import Home from "@/pages/home"
import DirectoryLayout from "@/pages/directory-layout"
import Session from "@/pages/session"
+import { ErrorPage } from "./pages/error"
declare global {
interface Window {
@@ -38,48 +39,50 @@ const url =
export function App() {
return (
- <MetaProvider>
- <Font />
- <DialogProvider>
- <MarkedProvider>
- <DiffComponentProvider component={Diff}>
- <CodeComponentProvider component={Code}>
- <GlobalSDKProvider url={url}>
- <GlobalSyncProvider>
- <LayoutProvider>
- <NotificationProvider>
- <Router
- root={(props) => (
- <CommandProvider>
- <Layout>{props.children}</Layout>
- </CommandProvider>
- )}
- >
- <Route path="/" component={Home} />
- <Route path="/:dir" component={DirectoryLayout}>
- <Route path="/" component={() => <Navigate href="session" />} />
- <Route
- path="/session/:id?"
- component={(p) => (
- <Show when={p.params.id || true} keyed>
- <TerminalProvider>
- <PromptProvider>
- <Session />
- </PromptProvider>
- </TerminalProvider>
- </Show>
- )}
- />
- </Route>
- </Router>
- </NotificationProvider>
- </LayoutProvider>
- </GlobalSyncProvider>
- </GlobalSDKProvider>
- </CodeComponentProvider>
- </DiffComponentProvider>
- </MarkedProvider>
- </DialogProvider>
- </MetaProvider>
+ <ErrorBoundary fallback={ErrorPage}>
+ <MetaProvider>
+ <Font />
+ <DialogProvider>
+ <MarkedProvider>
+ <DiffComponentProvider component={Diff}>
+ <CodeComponentProvider component={Code}>
+ <GlobalSDKProvider url={url}>
+ <GlobalSyncProvider>
+ <LayoutProvider>
+ <NotificationProvider>
+ <Router
+ root={(props) => (
+ <CommandProvider>
+ <Layout>{props.children}</Layout>
+ </CommandProvider>
+ )}
+ >
+ <Route path="/" component={Home} />
+ <Route path="/:dir" component={DirectoryLayout}>
+ <Route path="/" component={() => <Navigate href="session" />} />
+ <Route
+ path="/session/:id?"
+ component={(p) => (
+ <Show when={p.params.id || true} keyed>
+ <TerminalProvider>
+ <PromptProvider>
+ <Session />
+ </PromptProvider>
+ </TerminalProvider>
+ </Show>
+ )}
+ />
+ </Route>
+ </Router>
+ </NotificationProvider>
+ </LayoutProvider>
+ </GlobalSyncProvider>
+ </GlobalSDKProvider>
+ </CodeComponentProvider>
+ </DiffComponentProvider>
+ </MarkedProvider>
+ </DialogProvider>
+ </MetaProvider>
+ </ErrorBoundary>
)
}
diff --git a/packages/desktop/src/context/platform.tsx b/packages/desktop/src/context/platform.tsx
index 92bb2ba15..2ac9f64d4 100644
--- a/packages/desktop/src/context/platform.tsx
+++ b/packages/desktop/src/context/platform.tsx
@@ -19,6 +19,12 @@ export type Platform = {
/** Storage mechanism, defaults to localStorage */
storage?: (name?: string) => SyncStorage | AsyncStorage
+
+ /** Check for updates (Tauri only) */
+ checkUpdate?(): Promise<{ updateAvailable: boolean; version?: string }>
+
+ /** Install updates (Tauri only) */
+ update?(): Promise<void>
}
export const { use: usePlatform, provider: PlatformProvider } = createSimpleContext({
diff --git a/packages/desktop/src/pages/layout.tsx b/packages/desktop/src/pages/layout.tsx
index 540c5d778..fccb6d595 100644
--- a/packages/desktop/src/pages/layout.tsx
+++ b/packages/desktop/src/pages/layout.tsx
@@ -1,4 +1,15 @@
-import { createEffect, createMemo, createSignal, For, Match, ParentProps, Show, Switch, type JSX } from "solid-js"
+import {
+ createEffect,
+ createMemo,
+ createSignal,
+ For,
+ Match,
+ onMount,
+ ParentProps,
+ Show,
+ Switch,
+ type JSX,
+} from "solid-js"
import { DateTime } from "luxon"
import { A, useNavigate, useParams } from "@solidjs/router"
import { useLayout, getAvatarColors } from "@/context/layout"
@@ -28,7 +39,7 @@ import {
} from "@thisbeyond/solid-dnd"
import type { DragEvent } from "@thisbeyond/solid-dnd"
import { useProviders } from "@/hooks/use-providers"
-import { Toast } from "@opencode-ai/ui/toast"
+import { showToast, Toast } from "@opencode-ai/ui/toast"
import { useGlobalSDK } from "@/context/global-sdk"
import { useNotification } from "@/context/notification"
import { Binary } from "@opencode-ai/util/binary"
@@ -46,14 +57,6 @@ export default function Layout(props: ParentProps) {
let scrollContainerRef: HTMLDivElement | undefined
- function scrollToSession(sessionId: string) {
- if (!scrollContainerRef) return
- const element = scrollContainerRef.querySelector(`[data-session-id="${sessionId}"]`)
- if (element) {
- element.scrollIntoView({ block: "center", behavior: "smooth" })
- }
- }
-
const params = useParams()
const globalSDK = useGlobalSDK()
const globalSync = useGlobalSync()
@@ -65,6 +68,30 @@ export default function Layout(props: ParentProps) {
const dialog = useDialog()
const command = useCommand()
+ onMount(async () => {
+ if (platform.checkUpdate && platform.update) {
+ const { updateAvailable, version } = await platform.checkUpdate()
+ if (updateAvailable) {
+ showToast({
+ persistent: true,
+ icon: "download",
+ title: "Update available",
+ description: `A new version of OpenCode (${version}) is now available to install.`,
+ actions: [
+ {
+ label: "Install and restart",
+ onClick: () => platform!.update!(),
+ },
+ {
+ label: "Not yet",
+ onClick: "dismiss",
+ },
+ ],
+ })
+ }
+ }
+ })
+
function flattenSessions(sessions: Session[]): Session[] {
const childrenMap = new Map<string, Session[]>()
for (const session of sessions) {
@@ -87,6 +114,14 @@ export default function Layout(props: ParentProps) {
return result
}
+ function scrollToSession(sessionId: string) {
+ if (!scrollContainerRef) return
+ const element = scrollContainerRef.querySelector(`[data-session-id="${sessionId}"]`)
+ if (element) {
+ element.scrollIntoView({ block: "center", behavior: "smooth" })
+ }
+ }
+
const currentSessions = createMemo(() => {
if (!params.dir) return []
const directory = base64Decode(params.dir)