From b35708e7b94c69452fdce8a2b7cd1fa8e697562b Mon Sep 17 00:00:00 2001 From: Louis Knight-Webb Date: Mon, 17 Nov 2025 22:54:11 +0000 Subject: [PATCH] =?UTF-8?q?##=20=E2=9C=85=20Batch=20D=20Complete=20(#1313)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Successfully fixed all low-priority `any` types and catch blocks across 7 files: ### Changes Made: **1. [lib/types.ts](file:///private/var/folders/m1/9q_ct1913z10v6wbnv54j25r0000gn/T/vibe-kanban/worktrees/3da6-batch-d-fix-low/frontend/src/lib/types.ts)** - Added imports: `NormalizedEntry`, `ExecutionProcessStatus` - `entry: any` → `entry: NormalizedEntry` - `process: any` → `process: ExecutionProcess` - `processStatus: string` → `processStatus: ExecutionProcessStatus` **2. [lib/modals.ts](file:///private/var/folders/m1/9q_ct1913z10v6wbnv54j25r0000gn/T/vibe-kanban/worktrees/3da6-batch-d-fix-low/frontend/src/lib/modals.ts)** - Removed `any[]` and `component as any` - Properly typed function arguments with `ShowArgs

` - Used `React.FC>` for NiceModal compatibility **3. [EditBranchNameDialog.tsx](file:///private/var/folders/m1/9q_ct1913z10v6wbnv54j25r0000gn/T/vibe-kanban/worktrees/3da6-batch-d-fix-low/frontend/src/components/dialogs/tasks/EditBranchNameDialog.tsx)** - `catch (err: any)` → `catch (err: unknown)` - Used `getErrorMessage(err)` helper **4. [TagEditDialog.tsx](file:///private/var/folders/m1/9q_ct1913z10v6wbnv54j25r0000gn/T/vibe-kanban/worktrees/3da6-batch-d-fix-low/frontend/src/components/dialogs/tasks/TagEditDialog.tsx)** - `catch (err: any)` → `catch (err: unknown)` - Used `getErrorMessage(err)` helper **5. [GhCliSetupDialog.tsx](file:///private/var/folders/m1/9q_ct1913z10v6wbnv54j25r0000gn/T/vibe-kanban/worktrees/3da6-batch-d-fix-low/frontend/src/components/dialogs/auth/GhCliSetupDialog.tsx)** - `catch (err: any)` → `catch (err: unknown)` - Added safe type narrowing with `isGhCliSetupError` guard - Used `getErrorMessage(err)` helper **6. [ImageUploadSection.tsx](file:///private/var/folders/m1/9q_ct1913z10v6wbnv54j25r0000gn/T/vibe-kanban/worktrees/3da6-batch-d-fix-low/frontend/src/components/ui/ImageUploadSection.tsx)** - `catch (error: any)` → `catch (error: unknown)` - Used `instanceof Error` check **7. [McpSettings.tsx](file:///private/var/folders/m1/9q_ct1913z10v6wbnv54j25r0000gn/T/vibe-kanban/worktrees/3da6-batch-d-fix-low/frontend/src/pages/settings/McpSettings.tsx)** - `catch (err: any)` → `catch (err: unknown)` - `Record` → `Record` for preconfigured/meta/servers - Added safe narrowing for meta access All type checks pass ✓ All formatting complete ✓ --- .../dialogs/auth/GhCliSetupDialog.tsx | 24 ++++++++++++++----- .../dialogs/tasks/EditBranchNameDialog.tsx | 6 ++--- .../dialogs/tasks/TagEditDialog.tsx | 7 +++--- .../src/components/ui/ImageUploadSection.tsx | 6 +++-- frontend/src/lib/modals.ts | 11 +++++---- frontend/src/lib/types.ts | 12 ++++++---- frontend/src/pages/settings/McpSettings.tsx | 23 ++++++++++++------ 7 files changed, 60 insertions(+), 29 deletions(-) diff --git a/frontend/src/components/dialogs/auth/GhCliSetupDialog.tsx b/frontend/src/components/dialogs/auth/GhCliSetupDialog.tsx index 95520866..c8f69d6d 100644 --- a/frontend/src/components/dialogs/auth/GhCliSetupDialog.tsx +++ b/frontend/src/components/dialogs/auth/GhCliSetupDialog.tsx @@ -7,7 +7,7 @@ import { } from '@/components/ui/dialog'; import { Button } from '@/components/ui/button'; import NiceModal, { useModal } from '@ebay/nice-modal-react'; -import { defineModal } from '@/lib/modals'; +import { defineModal, getErrorMessage } from '@/lib/modals'; import { attemptsApi } from '@/lib/api'; import type { GhCliSetupError } from 'shared/types'; import { useRef, useState } from 'react'; @@ -143,13 +143,25 @@ const GhCliSetupDialogImpl = NiceModal.create( hasResolvedRef.current = true; modal.resolve(null); modal.hide(); - } catch (err: any) { + } catch (err: unknown) { const rawMessage = - typeof err?.message === 'string' - ? err.message - : t('settings:integrations.github.cliSetup.errors.setupFailed'); + getErrorMessage(err) || + t('settings:integrations.github.cliSetup.errors.setupFailed'); + + const maybeErrorData = + typeof err === 'object' && err !== null && 'error_data' in err + ? (err as { error_data?: unknown }).error_data + : undefined; + + const isGhCliSetupError = (x: unknown): x is GhCliSetupError => + x === 'BREW_MISSING' || + x === 'SETUP_HELPER_NOT_SUPPORTED' || + (typeof x === 'object' && x !== null && 'OTHER' in x); + + const errorData = isGhCliSetupError(maybeErrorData) + ? maybeErrorData + : undefined; - const errorData = err?.error_data as GhCliSetupError | undefined; const resolvedError: GhCliSetupError = errorData ?? { OTHER: { message: rawMessage }, }; diff --git a/frontend/src/components/dialogs/tasks/EditBranchNameDialog.tsx b/frontend/src/components/dialogs/tasks/EditBranchNameDialog.tsx index 0efbdf2b..5ac6879d 100644 --- a/frontend/src/components/dialogs/tasks/EditBranchNameDialog.tsx +++ b/frontend/src/components/dialogs/tasks/EditBranchNameDialog.tsx @@ -11,7 +11,7 @@ import { import { Button } from '@/components/ui/button'; import { Input } from '@/components/ui/input'; import NiceModal, { useModal } from '@ebay/nice-modal-react'; -import { defineModal } from '@/lib/modals'; +import { defineModal, getErrorMessage } from '@/lib/modals'; import { useRenameBranch } from '@/hooks/useRenameBranch'; export interface EditBranchNameDialogProps { @@ -40,8 +40,8 @@ const EditBranchNameDialogImpl = NiceModal.create( } as EditBranchNameDialogResult); modal.hide(); }, - (err: any) => { - setError(err?.message || 'Failed to rename branch'); + (err: unknown) => { + setError(getErrorMessage(err) || 'Failed to rename branch'); } ); diff --git a/frontend/src/components/dialogs/tasks/TagEditDialog.tsx b/frontend/src/components/dialogs/tasks/TagEditDialog.tsx index da06dae1..77d367e1 100644 --- a/frontend/src/components/dialogs/tasks/TagEditDialog.tsx +++ b/frontend/src/components/dialogs/tasks/TagEditDialog.tsx @@ -16,7 +16,7 @@ import { Loader2 } from 'lucide-react'; import { tagsApi } from '@/lib/api'; import type { Tag, CreateTag, UpdateTag } from 'shared/types'; import NiceModal, { useModal } from '@ebay/nice-modal-react'; -import { defineModal } from '@/lib/modals'; +import { defineModal, getErrorMessage } from '@/lib/modals'; export interface TagEditDialogProps { tag?: Tag | null; // null for create mode @@ -79,9 +79,10 @@ const TagEditDialogImpl = NiceModal.create(({ tag }) => { modal.resolve('saved' as TagEditResult); modal.hide(); - } catch (err: any) { + } catch (err: unknown) { setError( - err.message || t('settings.general.tags.dialog.errors.saveFailed') + getErrorMessage(err) || + t('settings.general.tags.dialog.errors.saveFailed') ); } finally { setSaving(false); diff --git a/frontend/src/components/ui/ImageUploadSection.tsx b/frontend/src/components/ui/ImageUploadSection.tsx index e839a563..684cf38e 100644 --- a/frontend/src/components/ui/ImageUploadSection.tsx +++ b/frontend/src/components/ui/ImageUploadSection.tsx @@ -151,10 +151,12 @@ export const ImageUploadSection = forwardRef< } setErrorMessage(null); - } catch (error: any) { + } catch (error: unknown) { console.error('Failed to upload image:', error); const message = - error.message || 'Failed to upload image. Please try again.'; + error instanceof Error + ? error.message + : 'Failed to upload image. Please try again.'; setErrorMessage(message); } finally { setUploadingFiles((prev) => { diff --git a/frontend/src/lib/modals.ts b/frontend/src/lib/modals.ts index 18ed8577..87a0cfd0 100644 --- a/frontend/src/lib/modals.ts +++ b/frontend/src/lib/modals.ts @@ -23,10 +23,13 @@ export function defineModal( component: React.ComponentType & NiceModalHocProps> ): Modalized { const c = component as unknown as Modalized; - c.show = ((...args: any[]) => - NiceModal.show(component as any, args[0])) as Modalized['show']; - c.hide = () => NiceModal.hide(component as any); - c.remove = () => NiceModal.remove(component as any); + c.show = ((...args: ShowArgs

) => + NiceModal.show( + component as React.FC>, + args[0] as ComponentProps

+ ) as Promise) as Modalized['show']; + c.hide = () => NiceModal.hide(component as React.FC>); + c.remove = () => NiceModal.remove(component as React.FC>); return c; } diff --git a/frontend/src/lib/types.ts b/frontend/src/lib/types.ts index 1074cceb..b5549133 100644 --- a/frontend/src/lib/types.ts +++ b/frontend/src/lib/types.ts @@ -1,4 +1,8 @@ -import { ExecutionProcess } from 'shared/types'; +import { + ExecutionProcess, + NormalizedEntry, + ExecutionProcessStatus, +} from 'shared/types'; export type AttemptData = { processes: ExecutionProcess[]; @@ -6,12 +10,12 @@ export type AttemptData = { }; export interface ConversationEntryDisplayType { - entry: any; + entry: NormalizedEntry; processId: string; processPrompt?: string; - processStatus: string; + processStatus: ExecutionProcessStatus; processIsRunning: boolean; - process: any; + process: ExecutionProcess; isFirstInProcess: boolean; processIndex: number; entryIndex: number; diff --git a/frontend/src/pages/settings/McpSettings.tsx b/frontend/src/pages/settings/McpSettings.tsx index e246bb02..a30718ae 100644 --- a/frontend/src/pages/settings/McpSettings.tsx +++ b/frontend/src/pages/settings/McpSettings.tsx @@ -91,8 +91,11 @@ export function McpSettings() { const configJson = JSON.stringify(fullConfig, null, 2); setMcpServers(configJson); setMcpConfigPath(result.config_path); - } catch (err: any) { - if (err?.message && err.message.includes('does not support MCP')) { + } catch (err: unknown) { + if ( + err instanceof Error && + err.message.includes('does not support MCP') + ) { setMcpError(err.message); } else { console.error('Error loading MCP servers:', err); @@ -210,14 +213,20 @@ export function McpSettings() { } }; - const preconfigured = (mcpConfig?.preconfigured ?? {}) as Record; - const meta = (preconfigured.meta ?? {}) as Record< + const preconfiguredObj = (mcpConfig?.preconfigured ?? {}) as Record< string, - { name?: string; description?: string; url?: string; icon?: string } + unknown >; + const meta = + typeof preconfiguredObj.meta === 'object' && preconfiguredObj.meta !== null + ? (preconfiguredObj.meta as Record< + string, + { name?: string; description?: string; url?: string; icon?: string } + >) + : {}; const servers = Object.fromEntries( - Object.entries(preconfigured).filter(([k]) => k !== 'meta') - ) as Record; + Object.entries(preconfiguredObj).filter(([k]) => k !== 'meta') + ) as Record; const getMetaFor = (key: string) => meta[key] || {}; if (!config) {