diff --git a/apps/code/src/renderer/features/connectivity/connectivityToast.ts b/apps/code/src/renderer/features/connectivity/connectivityToast.ts index 7e3ac6394..e5d5ba781 100644 --- a/apps/code/src/renderer/features/connectivity/connectivityToast.ts +++ b/apps/code/src/renderer/features/connectivity/connectivityToast.ts @@ -5,21 +5,21 @@ import { toast as sonnerToast } from "sonner"; const TOAST_ID = "connectivity-offline"; const OFFLINE_DEBOUNCE_MS = 5_000; +export function showOfflineToast() { + toast.error("No internet connection", { + id: TOAST_ID, + duration: Number.POSITIVE_INFINITY, + description: + "PostHog Code features that need the network are paused until you reconnect.", + }); +} + // Debounces flaky transitions: only surfaces a toast when the app has been // continuously offline for OFFLINE_DEBOUNCE_MS. The stable id guarantees the // toast never stacks; coming back online dismisses it automatically. export function initializeConnectivityToast() { let pendingTimer: ReturnType | null = null; - const showOfflineToast = () => { - toast.error("No internet connection", { - id: TOAST_ID, - duration: Number.POSITIVE_INFINITY, - description: - "PostHog Code features that need the network are paused until you reconnect.", - }); - }; - const clearPending = () => { if (pendingTimer) { clearTimeout(pendingTimer); diff --git a/apps/code/src/renderer/features/sessions/components/SessionView.tsx b/apps/code/src/renderer/features/sessions/components/SessionView.tsx index d195c5ce5..8c99ffb2a 100644 --- a/apps/code/src/renderer/features/sessions/components/SessionView.tsx +++ b/apps/code/src/renderer/features/sessions/components/SessionView.tsx @@ -1,5 +1,6 @@ import { isOtherOption } from "@components/action-selector/constants"; import { PermissionSelector } from "@components/permissions/PermissionSelector"; +import { showOfflineToast } from "@features/connectivity/connectivityToast"; import { PromptInput, type EditorHandle as PromptInputHandle, @@ -17,6 +18,7 @@ import type { Plan } from "@features/sessions/types"; import { useSettingsStore } from "@features/settings/stores/settingsStore"; import { useIsWorkspaceCloudRun } from "@features/workspace/hooks/useWorkspace"; import { useAutoFocusOnTyping } from "@hooks/useAutoFocusOnTyping"; +import { useConnectivity } from "@hooks/useConnectivity"; import { Pause, Spinner, Warning } from "@phosphor-icons/react"; import { Box, Button, ContextMenu, Flex, Text } from "@radix-ui/themes"; import type { TaskRunStatus } from "@shared/types"; @@ -244,6 +246,18 @@ export function SessionView({ [onSendPrompt], ); + const { isOnline } = useConnectivity(); + const handleBeforeSubmit = useCallback( + (text: string, clearEditor: () => void): boolean => { + if (!isOnline) { + showOfflineToast(); + return false; + } + return onBeforeSubmit ? onBeforeSubmit(text, clearEditor) : true; + }, + [isOnline, onBeforeSubmit], + ); + const [isDraggingFile, setIsDraggingFile] = useState(false); const editorRef = useRef(null); const dragCounterRef = useRef(0); @@ -643,7 +657,7 @@ export function SessionView({ /> ) : null } - onBeforeSubmit={onBeforeSubmit} + onBeforeSubmit={handleBeforeSubmit} onSubmit={handleSubmit} onBashCommand={onBashCommand} onCancel={onCancelPrompt}