diff --git a/frontend/.eslintrc b/frontend/.eslintrc index c89d89c857..3efd6aea69 100644 --- a/frontend/.eslintrc +++ b/frontend/.eslintrc @@ -18,6 +18,8 @@ "i18next/no-literal-string": "error", "unused-imports/no-unused-imports": "error", "prettier/prettier": ["error"], + // Enforce using optional chaining (?.) instead of && chains for null/undefined checks + "@typescript-eslint/prefer-optional-chain": "error", // Resolves https://stackoverflow.com/questions/59265981/typescript-eslint-missing-file-extension-ts-import-extensions/59268871#59268871 "import/extensions": [ "error", diff --git a/frontend/src/components/features/browser/browser.tsx b/frontend/src/components/features/browser/browser.tsx index 8c3842edd4..95c8f1fa1a 100644 --- a/frontend/src/components/features/browser/browser.tsx +++ b/frontend/src/components/features/browser/browser.tsx @@ -12,10 +12,9 @@ export function BrowserPanel() { reset(); }, [conversationId, reset]); - const imgSrc = - screenshotSrc && screenshotSrc.startsWith("data:image/png;base64,") - ? screenshotSrc - : `data:image/png;base64,${screenshotSrc || ""}`; + const imgSrc = screenshotSrc?.startsWith("data:image/png;base64,") + ? screenshotSrc + : `data:image/png;base64,${screenshotSrc ?? ""}`; return (
diff --git a/frontend/src/components/features/chat/event-content-helpers/get-observation-content.ts b/frontend/src/components/features/chat/event-content-helpers/get-observation-content.ts index 435a686918..11276a4e39 100644 --- a/frontend/src/components/features/chat/event-content-helpers/get-observation-content.ts +++ b/frontend/src/components/features/chat/event-content-helpers/get-observation-content.ts @@ -140,7 +140,7 @@ const getTaskTrackingObservationContent = ( content += "\n\n**Task List:** Empty"; } - if (event.content && event.content.trim()) { + if (event.content?.trim()) { content += `\n\n**Result:** ${event.content.trim()}`; } diff --git a/frontend/src/components/features/chat/messages.tsx b/frontend/src/components/features/chat/messages.tsx index 0d9032164d..6e68089b13 100644 --- a/frontend/src/components/features/chat/messages.tsx +++ b/frontend/src/components/features/chat/messages.tsx @@ -192,8 +192,7 @@ export const Messages: React.FC = React.memo( ) => { const conversationInstructions = `Target file: ${target}\n\nDescription: ${query}\n\nTriggers: ${triggers.join(", ")}`; if ( - !conversation || - !conversation.selected_repository || + !conversation?.selected_repository || !conversation.selected_branch || !conversation.git_provider || !selectedEventId diff --git a/frontend/src/components/features/home/git-provider-dropdown/git-provider-dropdown.tsx b/frontend/src/components/features/home/git-provider-dropdown/git-provider-dropdown.tsx index fdc9b21b00..c5ab171ca8 100644 --- a/frontend/src/components/features/home/git-provider-dropdown/git-provider-dropdown.tsx +++ b/frontend/src/components/features/home/git-provider-dropdown/git-provider-dropdown.tsx @@ -75,7 +75,7 @@ export function GitProviderDropdown({ } // If no input value, show all providers - if (!inputValue || !inputValue.trim()) { + if (!inputValue?.trim()) { return providers; } diff --git a/frontend/src/components/features/home/git-repo-dropdown/git-repo-dropdown.tsx b/frontend/src/components/features/home/git-repo-dropdown/git-repo-dropdown.tsx index 485f574f79..45b75bbd9f 100644 --- a/frontend/src/components/features/home/git-repo-dropdown/git-repo-dropdown.tsx +++ b/frontend/src/components/features/home/git-repo-dropdown/git-repo-dropdown.tsx @@ -99,7 +99,7 @@ export function GitRepoDropdown({ ); // If no input value, return all recent repos for this provider - if (!inputValue || !inputValue.trim()) { + if (!inputValue?.trim()) { return providerFilteredRepos; } @@ -139,7 +139,7 @@ export function GitRepoDropdown({ baseRepositories = repositories; } // If no input value, show all repositories - else if (!inputValue || !inputValue.trim()) { + else if (!inputValue?.trim()) { baseRepositories = repositories; } // For URL inputs, use the processed search input for filtering @@ -246,8 +246,7 @@ export function GitRepoDropdown({ // Create sticky footer item for GitHub provider const stickyFooterItem = useMemo(() => { if ( - !config || - !config.APP_SLUG || + !config?.APP_SLUG || provider !== ProviderOptions.github || config.APP_MODE !== "saas" ) diff --git a/frontend/src/components/features/home/shared/dropdown-item.tsx b/frontend/src/components/features/home/shared/dropdown-item.tsx index 08e22dc12b..36a0e25967 100644 --- a/frontend/src/components/features/home/shared/dropdown-item.tsx +++ b/frontend/src/components/features/home/shared/dropdown-item.tsx @@ -45,7 +45,7 @@ export function DropdownItem({ // eslint-disable-next-line react/jsx-props-no-spreading
  • - {renderIcon && renderIcon(item)} + {renderIcon?.(item)} {getDisplayText(item)}
  • diff --git a/frontend/src/components/v1/chat/event-content-helpers/parse-message-from-event.ts b/frontend/src/components/v1/chat/event-content-helpers/parse-message-from-event.ts index 17824a51c8..8e2a0cb253 100644 --- a/frontend/src/components/v1/chat/event-content-helpers/parse-message-from-event.ts +++ b/frontend/src/components/v1/chat/event-content-helpers/parse-message-from-event.ts @@ -5,7 +5,7 @@ export const parseMessageFromEvent = (event: MessageEvent): string => { const message = event.llm_message; // Safety check: ensure llm_message exists and has content - if (!message || !message.content) { + if (!message?.content) { return ""; } diff --git a/frontend/src/mocks/secrets-handlers.ts b/frontend/src/mocks/secrets-handlers.ts index 3d5570943a..18c4dc98fd 100644 --- a/frontend/src/mocks/secrets-handlers.ts +++ b/frontend/src/mocks/secrets-handlers.ts @@ -34,7 +34,7 @@ export const SECRETS_HANDLERS = [ http.post("/api/secrets", async ({ request }) => { const body = (await request.json()) as CustomSecret; - if (typeof body === "object" && body && body.name) { + if (typeof body === "object" && body?.name) { secrets.set(body.name, body); return HttpResponse.json(true); } @@ -48,7 +48,7 @@ export const SECRETS_HANDLERS = [ if (typeof id === "string" && typeof body === "object") { const secret = secrets.get(id); - if (secret && body && body.name) { + if (secret && body?.name) { const newSecret: CustomSecret = { ...secret, ...body }; secrets.delete(id); secrets.set(body.name, newSecret); diff --git a/frontend/src/mocks/settings-handlers.ts b/frontend/src/mocks/settings-handlers.ts index c08cd8dc36..e0d7b1ed11 100644 --- a/frontend/src/mocks/settings-handlers.ts +++ b/frontend/src/mocks/settings-handlers.ts @@ -134,7 +134,7 @@ export const SETTINGS_HANDLERS = [ const providerTokensSet: Partial> = Object.fromEntries( Object.entries(rawTokens) - .filter(([, val]) => val && val.token) + .filter(([, val]) => val?.token) .map(([provider]) => [provider as Provider, ""]), ); diff --git a/frontend/src/routes/vscode-tab.tsx b/frontend/src/routes/vscode-tab.tsx index 0d64180c1d..e1bb2e8fe4 100644 --- a/frontend/src/routes/vscode-tab.tsx +++ b/frontend/src/routes/vscode-tab.tsx @@ -51,7 +51,7 @@ function VSCodeTab() { ); } - if (error || (data && data.error) || !data?.url || iframeError) { + if (error || data?.error || !data?.url || iframeError) { return (
    {iframeError || diff --git a/frontend/src/utils/extract-model-and-provider.ts b/frontend/src/utils/extract-model-and-provider.ts index 93ef12d8bf..ab0836079f 100644 --- a/frontend/src/utils/extract-model-and-provider.ts +++ b/frontend/src/utils/extract-model-and-provider.ts @@ -16,7 +16,7 @@ import { * splitIsActuallyVersion(split) // returns true */ const splitIsActuallyVersion = (split: string[]) => - split[1] && split[1][0] && isNumber(split[1][0]); + split[1]?.[0] && isNumber(split[1][0]); /** * Given a model string, extract the provider and model name. Currently the supported separators are "/" and "."