diff --git a/src/App.tsx b/src/App.tsx index 8a57d7ec..7e27827a 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -1088,12 +1088,10 @@ const App: Component = () => { diff --git a/src/lib/notifications.tsx b/src/lib/notifications.tsx index d4910e9e..75da3370 100644 --- a/src/lib/notifications.tsx +++ b/src/lib/notifications.tsx @@ -9,41 +9,53 @@ export type ToastPayload = { duration?: number } -const variantAccent: Record = { +const variantAccent: Record< + ToastVariant, + { + badge: string + container: string + headline: string + body: string + } +> = { info: { - badge: "bg-blue-500", - border: "border-blue-500/40", - text: "text-blue-100", + badge: "bg-sky-500/40", + container: "bg-slate-900/95 border-slate-700 text-slate-100", + headline: "text-slate-50", + body: "text-slate-200/80", }, success: { - badge: "bg-emerald-500", - border: "border-emerald-500/40", - text: "text-emerald-100", + badge: "bg-emerald-500/40", + container: "bg-emerald-950/90 border-emerald-800 text-emerald-50", + headline: "text-emerald-50", + body: "text-emerald-100/80", }, warning: { - badge: "bg-amber-500", - border: "border-amber-500/40", - text: "text-amber-100", + badge: "bg-amber-500/40", + container: "bg-amber-950/90 border-amber-800 text-amber-50", + headline: "text-amber-50", + body: "text-amber-100/80", }, error: { - badge: "bg-rose-500", - border: "border-rose-500/40", - text: "text-rose-100", + badge: "bg-rose-500/40", + container: "bg-rose-950/90 border-rose-800 text-rose-50", + headline: "text-rose-50", + body: "text-rose-100/80", }, } export function showToastNotification(payload: ToastPayload) { const accent = variantAccent[payload.variant] - const duration = payload.duration ?? 5000 + const duration = payload.duration ?? 10000 toast.custom( () => ( -
-
+
+
- {payload.title &&

{payload.title}

} -

{payload.message}

+ {payload.title &&

{payload.title}

} +

{payload.message}

diff --git a/src/lib/sse-manager.ts b/src/lib/sse-manager.ts index 05bfb8ac..338948df 100644 --- a/src/lib/sse-manager.ts +++ b/src/lib/sse-manager.ts @@ -30,6 +30,13 @@ interface TuiToastEvent { } } +interface SessionIdleEvent { + type: "session.idle" + properties: { + sessionID: string + } +} + const [connectionStatus, setConnectionStatus] = createSignal< Map >(new Map()) @@ -118,7 +125,7 @@ class SSEManager { this.onTuiToast?.(instanceId, event as TuiToastEvent) break case "session.idle": - console.log("[SSE] Session idle") + this.onSessionIdle?.(instanceId, event as SessionIdleEvent) break default: console.warn("[SSE] Unknown event type:", event.type) @@ -161,6 +168,7 @@ class SSEManager { onSessionCompacted?: (instanceId: string, event: any) => void onSessionError?: (instanceId: string, event: any) => void onTuiToast?: (instanceId: string, event: TuiToastEvent) => void + onSessionIdle?: (instanceId: string, event: SessionIdleEvent) => void getStatus(instanceId: string): "connecting" | "connected" | "disconnected" | "error" | null { return connectionStatus().get(instanceId) ?? null diff --git a/src/stores/sessions.ts b/src/stores/sessions.ts index 3b733e36..113d14bf 100644 --- a/src/stores/sessions.ts +++ b/src/stores/sessions.ts @@ -1767,6 +1767,19 @@ function handleSessionCompacted(instanceId: string, event: any): void { console.log(`[SSE] Session compacted: ${sessionID}`) loadMessages(instanceId, sessionID, true).catch(console.error) + + const instanceSessions = sessions().get(instanceId) + const session = instanceSessions?.get(sessionID) + const label = session?.title?.trim() ? session.title : sessionID + const instanceFolder = instances().get(instanceId)?.folder ?? instanceId + const instanceName = instanceFolder.split(/[\\/]/).filter(Boolean).pop() ?? instanceFolder + + showToastNotification({ + title: instanceName, + message: `Session ${label ? `"${label}"` : sessionID} was compacted`, + variant: "info", + duration: 10000, + }) } function handleSessionError(instanceId: string, event: any): void { @@ -1821,6 +1834,24 @@ function handleTuiToast(_instanceId: string, event: any): void { }) } +function handleSessionIdle(instanceId: string, event: any): void { + const sessionID = event.properties?.sessionID + if (!sessionID) return + + const instanceSessions = sessions().get(instanceId) + const session = instanceSessions?.get(sessionID) + const label = session?.title?.trim() ? session.title : sessionID + const instanceFolder = instances().get(instanceId)?.folder ?? instanceId + const instanceName = instanceFolder.split(/[\\/]/).filter(Boolean).pop() ?? instanceFolder + + showToastNotification({ + title: instanceName, + message: `Session ${label ? `"${label}"` : sessionID} is idle`, + variant: "info", + duration: 10000, + }) +} + sseManager.onMessageUpdate = handleMessageUpdate sseManager.onMessageRemoved = handleMessageRemoved sseManager.onMessagePartRemoved = handleMessagePartRemoved @@ -1828,6 +1859,7 @@ sseManager.onSessionUpdate = handleSessionUpdate sseManager.onSessionCompacted = handleSessionCompacted sseManager.onSessionError = handleSessionError sseManager.onTuiToast = handleTuiToast +sseManager.onSessionIdle = handleSessionIdle export { sessions,