diff --git a/src/browser/contexts/ThemeContext.tsx b/src/browser/contexts/ThemeContext.tsx index 5e83061b65..fc20eaa609 100644 --- a/src/browser/contexts/ThemeContext.tsx +++ b/src/browser/contexts/ThemeContext.tsx @@ -10,6 +10,7 @@ import React, { } from "react"; import { readPersistedString, usePersistedState } from "@/browser/hooks/usePersistedState"; import { UI_THEME_KEY } from "@/common/constants/storage"; +import { isLightThemeMode } from "@/browser/utils/highlighting/shiki-shared"; export type ThemeMode = "light" | "dark" | "flexoki-light" | "flexoki-dark"; export type ThemePreference = ThemeMode | "auto"; @@ -74,7 +75,8 @@ const FAVICON_BY_SCHEME: Record<"light" | "dark", string> = { /** Map theme mode to CSS color-scheme value */ function getColorScheme(theme: ThemeMode): "light" | "dark" { - return theme === "light" || theme === "flexoki-light" ? "light" : "dark"; + // Reuse the shared `-light` suffix convention so we have one source of truth for the light/dark mapping. + return isLightThemeMode(theme) ? "light" : "dark"; } function applyThemeFavicon(theme: ThemeMode) { diff --git a/src/browser/features/RightSidebar/CodeReview/ReviewPanel.tsx b/src/browser/features/RightSidebar/CodeReview/ReviewPanel.tsx index 202b9802a9..9ca187e0d6 100644 --- a/src/browser/features/RightSidebar/CodeReview/ReviewPanel.tsx +++ b/src/browser/features/RightSidebar/CodeReview/ReviewPanel.tsx @@ -1259,7 +1259,7 @@ export const ReviewPanel: React.FC = ({ filteredHunksRef.current = filteredHunks; // Ensure selectedHunkId is valid after filtering/sorting: - // - If no selection or selection not in filtered list, select first visible hunk + // - If no selection or selection not in the validity list, select first visible hunk // - This runs after sorting, so we always select the top-most hunk in current order // // Immersive review can intentionally navigate to a hunk that is hidden by @@ -1272,15 +1272,11 @@ export const ReviewPanel: React.FC = ({ useEffect(() => { if (filteredHunks.length === 0) return; - if (isImmersive) { - const selectionExists = selectedHunkId && hunks.some((h) => h.id === selectedHunkId); - if (!selectionExists) { - setSelectedHunkId(filteredHunks[0].id); - } - return; - } - - const selectionValid = selectedHunkId && filteredHunks.some((h) => h.id === selectedHunkId); + // Picking the validity list up front keeps the immersive and non-immersive + // behavior in lockstep — the only difference is which list we accept the + // current selection against. + const validityList = isImmersive ? hunks : filteredHunks; + const selectionValid = selectedHunkId && validityList.some((h) => h.id === selectedHunkId); if (!selectionValid) { setSelectedHunkId(filteredHunks[0].id); } diff --git a/src/browser/features/Settings/Sections/ProvidersSection.tsx b/src/browser/features/Settings/Sections/ProvidersSection.tsx index f5ccc4b671..4bf8560d72 100644 --- a/src/browser/features/Settings/Sections/ProvidersSection.tsx +++ b/src/browser/features/Settings/Sections/ProvidersSection.tsx @@ -78,6 +78,7 @@ import type { AddCustomOpenAICompatibleProviderInput, ProviderConfigInfo, } from "@/common/orpc/types"; +import type { ServiceTier } from "@/common/config/schemas/providersConfig"; type MuxGatewayLoginStatus = "idle" | "starting" | "waiting" | "success" | "error"; type CodexOauthFlowStatus = "idle" | "starting" | "waiting" | "error"; @@ -85,7 +86,7 @@ type CopilotLoginStatus = "idle" | "starting" | "waiting" | "success" | "error"; const OPENAI_SERVICE_TIER_UNSET = "unset"; -type OpenAIServiceTier = "auto" | "default" | "flex" | "priority"; +type OpenAIServiceTier = ServiceTier; type OpenAIServiceTierSelectValue = typeof OPENAI_SERVICE_TIER_UNSET | OpenAIServiceTier; function isOpenAIServiceTier(value: string): value is OpenAIServiceTier { diff --git a/src/browser/features/Tools/FileEditToolCall.tsx b/src/browser/features/Tools/FileEditToolCall.tsx index 915d94424a..0d34f82343 100644 --- a/src/browser/features/Tools/FileEditToolCall.tsx +++ b/src/browser/features/Tools/FileEditToolCall.tsx @@ -168,7 +168,9 @@ export const FileEditToolCall: React.FC = ({ const diff = result && result.success ? (uiOnlyDiff ?? result.diff) : undefined; const filePath = extractToolFilePath(args); const largeDiffPreview = diff ? buildLargeDiffPreview(diff) : null; - const shouldShowLargeDiffPreview = Boolean(largeDiffPreview && !showRaw && !showFullDiff); + // Single nullable handle for the active preview so JSX truthiness checks narrow the type + // directly (no separate boolean + repeated `&& largeDiffPreview` guards). + const activeDiffPreview = largeDiffPreview && !showRaw && !showFullDiff ? largeDiffPreview : null; // Copy to clipboard with feedback const { copied, copyToClipboard } = useCopyToClipboard(); @@ -242,12 +244,12 @@ export const FileEditToolCall: React.FC = ({ {result.success && diff && ( <> - {shouldShowLargeDiffPreview && largeDiffPreview && ( + {activeDiffPreview && (
Large diff preview: showing{" "} - {largeDiffPreview.displayedLines.toLocaleString()} of{" "} - {largeDiffPreview.totalLines.toLocaleString()} lines. Full patch is still + {activeDiffPreview.displayedLines.toLocaleString()} of{" "} + {activeDiffPreview.totalLines.toLocaleString()} lines. Full patch is still available from the menu.