From 9be1d1aa5a64ec8b8185907339864de3ec01dd94 Mon Sep 17 00:00:00 2001 From: James Brunton Date: Fri, 7 Nov 2025 16:50:48 +0000 Subject: [PATCH] Fix more `any` types after updating to newer V2 --- .../configSections/AdminMailSection.tsx | 4 +- .../configSections/AdminSecuritySection.tsx | 3 +- .../configSections/audit/AuditEventsTable.tsx | 4 +- .../configSections/audit/AuditFiltersForm.tsx | 13 +++-- .../src/core/contexts/AppConfigContext.tsx | 7 ++- .../core/data/useTranslatedToolRegistry.tsx | 2 +- frontend/src/core/hooks/useAdminSettings.ts | 4 +- frontend/src/core/hooks/useAuditFilters.ts | 2 +- frontend/src/core/hooks/useEndpointConfig.ts | 7 ++- frontend/src/core/services/auditService.ts | 10 +++- .../core/services/usageAnalyticsService.ts | 2 +- .../core/services/userManagementService.ts | 10 ++-- .../config/configSections/PeopleSection.tsx | 7 +-- .../src/proprietary/routes/InviteAccept.tsx | 47 ++++++++++++------- 14 files changed, 71 insertions(+), 51 deletions(-) diff --git a/frontend/src/core/components/shared/config/configSections/AdminMailSection.tsx b/frontend/src/core/components/shared/config/configSections/AdminMailSection.tsx index c30bceada..8e754dca7 100644 --- a/frontend/src/core/components/shared/config/configSections/AdminMailSection.tsx +++ b/frontend/src/core/components/shared/config/configSections/AdminMailSection.tsx @@ -4,7 +4,7 @@ import { TextInput, NumberInput, Switch, Button, Stack, Paper, Text, Loader, Gro import { alert } from '@app/components/toast'; import RestartConfirmationModal from '@app/components/shared/config/RestartConfirmationModal'; import { useRestartServer } from '@app/components/shared/config/useRestartServer'; -import { useAdminSettings } from '@app/hooks/useAdminSettings'; +import { useAdminSettings, type SettingsRecord } from '@app/hooks/useAdminSettings'; import PendingBadge from '@app/components/shared/config/PendingBadge'; import apiClient from '@app/services/apiClient'; @@ -73,7 +73,7 @@ export default function AdminMailSection() { saveTransformer: (settings) => { const { frontendUrl, ...mailSettings } = settings; - const deltaSettings: Record = { + const deltaSettings: SettingsRecord = { 'system.frontendUrl': frontendUrl }; diff --git a/frontend/src/core/components/shared/config/configSections/AdminSecuritySection.tsx b/frontend/src/core/components/shared/config/configSections/AdminSecuritySection.tsx index 8f6a8e572..6abdf7665 100644 --- a/frontend/src/core/components/shared/config/configSections/AdminSecuritySection.tsx +++ b/frontend/src/core/components/shared/config/configSections/AdminSecuritySection.tsx @@ -8,7 +8,6 @@ import { useRestartServer } from '@app/components/shared/config/useRestartServer import { useAdminSettings, type SettingsRecord } from '@app/hooks/useAdminSettings'; import PendingBadge from '@app/components/shared/config/PendingBadge'; import apiClient from '@app/services/apiClient'; -import type { SettingsWithPending } from '@app/utils/settingsPendingHelper'; interface SecuritySettingsData extends Record { enableLogin?: boolean; @@ -83,7 +82,7 @@ export default function AdminSecuritySection() { systemPending: JSON.parse(JSON.stringify(systemPending || {})) }); - const combined: SecurityResponse = { + const combined = { ...securityActive }; diff --git a/frontend/src/core/components/shared/config/configSections/audit/AuditEventsTable.tsx b/frontend/src/core/components/shared/config/configSections/audit/AuditEventsTable.tsx index 9deeaed53..637d87bb3 100644 --- a/frontend/src/core/components/shared/config/configSections/audit/AuditEventsTable.tsx +++ b/frontend/src/core/components/shared/config/configSections/audit/AuditEventsTable.tsx @@ -13,7 +13,7 @@ import { Table, } from '@mantine/core'; import { useTranslation } from 'react-i18next'; -import auditService, { AuditEvent } from '@app/services/auditService'; +import auditService, { AuditEvent, type AuditFilters } from '@app/services/auditService'; import { Z_INDEX_OVER_CONFIG_MODAL } from '@app/styles/zIndex'; import { useAuditFilters } from '@app/hooks/useAuditFilters'; import AuditFiltersForm from '@app/components/shared/config/configSections/audit/AuditFiltersForm'; @@ -55,7 +55,7 @@ const AuditEventsTable: React.FC = () => { }, [filters, currentPage]); // Wrap filter handlers to reset pagination - const handleFilterChangeWithReset = (key: keyof typeof filters, value: any) => { + const handleFilterChangeWithReset = (key: K, value: AuditFilters[K]) => { handleFilterChange(key, value); setCurrentPage(1); }; diff --git a/frontend/src/core/components/shared/config/configSections/audit/AuditFiltersForm.tsx b/frontend/src/core/components/shared/config/configSections/audit/AuditFiltersForm.tsx index 28f0ed4d3..2fc621a0d 100644 --- a/frontend/src/core/components/shared/config/configSections/audit/AuditFiltersForm.tsx +++ b/frontend/src/core/components/shared/config/configSections/audit/AuditFiltersForm.tsx @@ -1,15 +1,18 @@ import React from 'react'; import { Group, Select, Button } from '@mantine/core'; import { DateInput } from '@mantine/dates'; +import type { DateValue } from '@mantine/dates'; import { useTranslation } from 'react-i18next'; import { AuditFilters } from '@app/services/auditService'; import { Z_INDEX_OVER_CONFIG_MODAL } from '@app/styles/zIndex'; +type FilterChangeHandler = (key: K, value: AuditFilters[K]) => void; + interface AuditFiltersFormProps { filters: AuditFilters; eventTypes: string[]; users: string[]; - onFilterChange: (key: keyof AuditFilters, value: any) => void; + onFilterChange: FilterChangeHandler; onClearFilters: () => void; } @@ -49,8 +52,8 @@ const AuditFiltersForm: React.FC = ({ - onFilterChange('startDate', value ?? undefined) + onChange={(value: DateValue) => + onFilterChange('startDate', value instanceof Date ? value.toISOString() : undefined) } clearable style={{ flex: 1, minWidth: 150 }} @@ -59,8 +62,8 @@ const AuditFiltersForm: React.FC = ({ - onFilterChange('endDate', value ?? undefined) + onChange={(value: DateValue) => + onFilterChange('endDate', value instanceof Date ? value.toISOString() : undefined) } clearable style={{ flex: 1, minWidth: 150 }} diff --git a/frontend/src/core/contexts/AppConfigContext.tsx b/frontend/src/core/contexts/AppConfigContext.tsx index 5bb05a50b..ffcb38d3c 100644 --- a/frontend/src/core/contexts/AppConfigContext.tsx +++ b/frontend/src/core/contexts/AppConfigContext.tsx @@ -71,10 +71,13 @@ export const AppConfigProvider: React.FC<{ children: ReactNode }> = ({ children console.debug('[AppConfig] Config fetched successfully:', data); setConfig(data); setFetchCount(prev => prev + 1); - } catch (err: any) { + } catch (err: unknown) { // On 401 (not authenticated), use default config with login enabled // This allows the app to work even without authentication - if (err.response?.status === 401) { + const responseStatus = typeof err === 'object' && err !== null && 'response' in err + ? (err as { response?: { status?: number } }).response?.status + : undefined; + if (responseStatus === 401) { console.debug('[AppConfig] 401 error - using default config (login enabled)'); setConfig({ enableLogin: true }); setLoading(false); diff --git a/frontend/src/core/data/useTranslatedToolRegistry.tsx b/frontend/src/core/data/useTranslatedToolRegistry.tsx index 0f00f4646..71bacf82a 100644 --- a/frontend/src/core/data/useTranslatedToolRegistry.tsx +++ b/frontend/src/core/data/useTranslatedToolRegistry.tsx @@ -485,7 +485,7 @@ export function useTranslatedToolCatalog(): TranslatedToolCatalog { categoryId: ToolCategoryId.STANDARD_TOOLS, subcategoryId: SubcategoryId.EXTRACTION, synonyms: getSynonyms(t, "extractPages"), - automationSettings: ExtractPagesSettings, + automationSettings: toAutomationSettings(ExtractPagesSettings), operationConfig: extractPagesOperationConfig, endpoints: ["rearrange-pages"], }, diff --git a/frontend/src/core/hooks/useAdminSettings.ts b/frontend/src/core/hooks/useAdminSettings.ts index 2f58701ac..440094740 100644 --- a/frontend/src/core/hooks/useAdminSettings.ts +++ b/frontend/src/core/hooks/useAdminSettings.ts @@ -117,7 +117,7 @@ export function useAdminSettings( const { sectionData: originalSectionData } = saveTransformer(originalSettings); // Save section data (with delta applied) - compare transformed vs transformed - const sectionDelta = computeDelta(originalSectionData, sectionData); + const sectionDelta = computeDelta(originalSectionData as SettingsRecord, sectionData as SettingsRecord); if (Object.keys(sectionDelta).length > 0) { await apiClient.put(`/api/v1/admin/settings/section/${sectionName}`, sectionDelta); } @@ -133,7 +133,7 @@ export function useAdminSettings( }); // Compare current vs original deltaSettings (both have same backend paths) - const changedDeltaSettings: Record = {}; + const changedDeltaSettings: SettingsRecord = {}; for (const [key, value] of Object.entries(deltaSettings)) { const originalValue = originalDeltaSettings?.[key]; diff --git a/frontend/src/core/hooks/useAuditFilters.ts b/frontend/src/core/hooks/useAuditFilters.ts index ef8f0c7df..06cffa851 100644 --- a/frontend/src/core/hooks/useAuditFilters.ts +++ b/frontend/src/core/hooks/useAuditFilters.ts @@ -33,7 +33,7 @@ export function useAuditFilters(initialFilters: Partial = {}) { fetchMetadata(); }, []); - const handleFilterChange = (key: keyof AuditFilters, value: any) => { + const handleFilterChange = (key: K, value: AuditFilters[K]) => { setFilters((prev) => ({ ...prev, [key]: value })); }; diff --git a/frontend/src/core/hooks/useEndpointConfig.ts b/frontend/src/core/hooks/useEndpointConfig.ts index 83bb34b57..039ca00d9 100644 --- a/frontend/src/core/hooks/useEndpointConfig.ts +++ b/frontend/src/core/hooks/useEndpointConfig.ts @@ -137,9 +137,12 @@ export function useMultipleEndpointsEnabled(endpoints: string[]): { setEndpointStatus(fullStatus); globalFetchedSets.add(endpointsKey); - } catch (err: any) { + } catch (err: unknown) { // On 401 (auth error), use optimistic fallback instead of disabling - if (err.response?.status === 401) { + const responseStatus = typeof err === 'object' && err !== null && 'response' in err + ? (err as { response?: { status?: number } }).response?.status + : undefined; + if (responseStatus === 401) { console.warn('[useEndpointConfig] 401 error - using optimistic fallback'); const optimisticStatus = endpoints.reduce((acc, endpoint) => { acc[endpoint] = true; diff --git a/frontend/src/core/services/auditService.ts b/frontend/src/core/services/auditService.ts index ac2da176b..9e4b6b251 100644 --- a/frontend/src/core/services/auditService.ts +++ b/frontend/src/core/services/auditService.ts @@ -13,7 +13,7 @@ export interface AuditEvent { eventType: string; username: string; ipAddress: string; - details: Record; + details: Record; } export interface AuditEventsResponse { @@ -44,12 +44,18 @@ export interface AuditFilters { pageSize?: number; } +interface AuditStatusApiResponse { + auditEnabled: boolean; + auditLevel: string; + retentionDays: number; +} + const auditService = { /** * Get audit system status */ async getSystemStatus(): Promise { - const response = await apiClient.get('/api/v1/proprietary/ui-data/audit-dashboard'); + const response = await apiClient.get('/api/v1/proprietary/ui-data/audit-dashboard'); const data = response.data; // Map V1 response to expected format diff --git a/frontend/src/core/services/usageAnalyticsService.ts b/frontend/src/core/services/usageAnalyticsService.ts index 4268a91f5..e5ce840bf 100644 --- a/frontend/src/core/services/usageAnalyticsService.ts +++ b/frontend/src/core/services/usageAnalyticsService.ts @@ -25,7 +25,7 @@ const usageAnalyticsService = { limit?: number, dataType: 'all' | 'api' | 'ui' = 'all' ): Promise { - const params: Record = {}; + const params: Record = {}; if (limit !== undefined) { params.limit = limit; diff --git a/frontend/src/core/services/userManagementService.ts b/frontend/src/core/services/userManagementService.ts index 4ae6c9aef..eaeaa4cd8 100644 --- a/frontend/src/core/services/userManagementService.ts +++ b/frontend/src/core/services/userManagementService.ts @@ -236,9 +236,7 @@ export const userManagementService = { const response = await apiClient.post( '/api/v1/invite/generate', formData, - { - suppressErrorToast: true, - } as any + suppressErrorToastConfig() ); return response.data; @@ -256,9 +254,7 @@ export const userManagementService = { * Revoke an invite link (admin only) */ async revokeInviteLink(inviteId: number): Promise { - await apiClient.delete(`/api/v1/invite/revoke/${inviteId}`, { - suppressErrorToast: true, - } as any); + await apiClient.delete(`/api/v1/invite/revoke/${inviteId}`, suppressErrorToastConfig()); }, /** @@ -269,3 +265,5 @@ export const userManagementService = { return response.data; }, }; +type SuppressibleRequestConfig = AxiosRequestConfig & { suppressErrorToast?: boolean }; +const suppressErrorToastConfig = (): SuppressibleRequestConfig => ({ suppressErrorToast: true }); diff --git a/frontend/src/proprietary/components/shared/config/configSections/PeopleSection.tsx b/frontend/src/proprietary/components/shared/config/configSections/PeopleSection.tsx index ada310025..3704553c1 100644 --- a/frontend/src/proprietary/components/shared/config/configSections/PeopleSection.tsx +++ b/frontend/src/proprietary/components/shared/config/configSections/PeopleSection.tsx @@ -274,12 +274,9 @@ const extractErrorMessage = (error: unknown, fallback: string): string => { title: t('workspace.people.inviteLink.success', 'Invite link generated successfully!') }); } - } catch (error: any) { + } catch (error: unknown) { console.error('Failed to generate invite link:', error); - const errorMessage = error.response?.data?.message || - error.response?.data?.error || - error.message || - t('workspace.people.inviteLink.error', 'Failed to generate invite link'); + const errorMessage = extractErrorMessage(error, t('workspace.people.inviteLink.error', 'Failed to generate invite link')); alert({ alertType: 'error', title: errorMessage }); } finally { setProcessing(false); diff --git a/frontend/src/proprietary/routes/InviteAccept.tsx b/frontend/src/proprietary/routes/InviteAccept.tsx index c145309ca..948b5e7f8 100644 --- a/frontend/src/proprietary/routes/InviteAccept.tsx +++ b/frontend/src/proprietary/routes/InviteAccept.tsx @@ -8,6 +8,7 @@ import LoginHeader from '@app/routes/login/LoginHeader'; import ErrorMessage from '@app/routes/login/ErrorMessage'; import { BASE_PATH } from '@app/constants/app'; import apiClient from '@app/services/apiClient'; +import type { AxiosRequestConfig } from 'axios'; interface InviteData { email: string | null; @@ -16,6 +17,28 @@ interface InviteData { emailRequired: boolean; } +type SuppressibleRequestConfig = AxiosRequestConfig & { suppressErrorToast?: boolean }; +const suppressErrorConfig: SuppressibleRequestConfig = { suppressErrorToast: true }; + +type ApiErrorResponse = { + response?: { data?: { error?: string; message?: string } }; + message?: string; +}; + +const extractInviteError = (error: unknown, fallback: string): string => { + if (typeof error === 'object' && error !== null) { + const apiError = error as ApiErrorResponse; + return apiError.response?.data?.error + ?? apiError.response?.data?.message + ?? apiError.message + ?? fallback; + } + if (error instanceof Error) { + return error.message; + } + return fallback; +}; + export default function InviteAccept() { const { token } = useParams<{ token: string }>(); const navigate = useNavigate(); @@ -54,17 +77,11 @@ export default function InviteAccept() { const validateToken = async () => { try { setLoading(true); - const response = await apiClient.get(`/api/v1/invite/validate/${token}`, { - suppressErrorToast: true, - } as any); + const response = await apiClient.get(`/api/v1/invite/validate/${token}`, suppressErrorConfig); setInviteData(response.data); setError(null); - } catch (err: any) { - const errorMessage = - err.response?.data?.error || - err.message || - t('invite.validationError', 'Failed to validate invitation link'); - setError(errorMessage); + } catch (err: unknown) { + setError(extractInviteError(err, t('invite.validationError', 'Failed to validate invitation link'))); } finally { setLoading(false); } @@ -106,18 +123,12 @@ export default function InviteAccept() { } formData.append('password', password); - await apiClient.post(`/api/v1/invite/accept/${token}`, formData, { - suppressErrorToast: true, - } as any); + await apiClient.post(`/api/v1/invite/accept/${token}`, formData, suppressErrorConfig); // Success - redirect to login navigate('/login?messageType=accountCreated'); - } catch (err: any) { - const errorMessage = - err.response?.data?.error || - err.message || - t('invite.acceptError', 'Failed to create account'); - setError(errorMessage); + } catch (err: unknown) { + setError(extractInviteError(err, t('invite.acceptError', 'Failed to create account'))); } finally { setSubmitting(false); }