Fix more any types after updating to newer V2

This commit is contained in:
James Brunton 2025-11-07 16:50:48 +00:00
parent a1a1394cad
commit 9be1d1aa5a
14 changed files with 71 additions and 51 deletions

View File

@ -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<string, any> = {
const deltaSettings: SettingsRecord = {
'system.frontendUrl': frontendUrl
};

View File

@ -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<string, unknown> {
enableLogin?: boolean;
@ -83,7 +82,7 @@ export default function AdminSecuritySection() {
systemPending: JSON.parse(JSON.stringify(systemPending || {}))
});
const combined: SecurityResponse = {
const combined = {
...securityActive
};

View File

@ -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 = <K extends keyof AuditFilters>(key: K, value: AuditFilters[K]) => {
handleFilterChange(key, value);
setCurrentPage(1);
};

View File

@ -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 = <K extends keyof AuditFilters>(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<AuditFiltersFormProps> = ({
<DateInput
placeholder={t('audit.events.startDate', 'Start date')}
value={filters.startDate ? new Date(filters.startDate) : null}
onChange={(value: string | null) =>
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<AuditFiltersFormProps> = ({
<DateInput
placeholder={t('audit.events.endDate', 'End date')}
value={filters.endDate ? new Date(filters.endDate) : null}
onChange={(value: string | null) =>
onFilterChange('endDate', value ?? undefined)
onChange={(value: DateValue) =>
onFilterChange('endDate', value instanceof Date ? value.toISOString() : undefined)
}
clearable
style={{ flex: 1, minWidth: 150 }}

View File

@ -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);

View File

@ -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"],
},

View File

@ -117,7 +117,7 @@ export function useAdminSettings<T extends object>(
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<T extends object>(
});
// Compare current vs original deltaSettings (both have same backend paths)
const changedDeltaSettings: Record<string, any> = {};
const changedDeltaSettings: SettingsRecord = {};
for (const [key, value] of Object.entries(deltaSettings)) {
const originalValue = originalDeltaSettings?.[key];

View File

@ -33,7 +33,7 @@ export function useAuditFilters(initialFilters: Partial<AuditFilters> = {}) {
fetchMetadata();
}, []);
const handleFilterChange = (key: keyof AuditFilters, value: any) => {
const handleFilterChange = <K extends keyof AuditFilters>(key: K, value: AuditFilters[K]) => {
setFilters((prev) => ({ ...prev, [key]: value }));
};

View File

@ -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;

View File

@ -13,7 +13,7 @@ export interface AuditEvent {
eventType: string;
username: string;
ipAddress: string;
details: Record<string, any>;
details: Record<string, unknown>;
}
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<AuditSystemStatus> {
const response = await apiClient.get<any>('/api/v1/proprietary/ui-data/audit-dashboard');
const response = await apiClient.get<AuditStatusApiResponse>('/api/v1/proprietary/ui-data/audit-dashboard');
const data = response.data;
// Map V1 response to expected format

View File

@ -25,7 +25,7 @@ const usageAnalyticsService = {
limit?: number,
dataType: 'all' | 'api' | 'ui' = 'all'
): Promise<EndpointStatisticsResponse> {
const params: Record<string, any> = {};
const params: Record<string, string | number> = {};
if (limit !== undefined) {
params.limit = limit;

View File

@ -236,9 +236,7 @@ export const userManagementService = {
const response = await apiClient.post<InviteLinkResponse>(
'/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<void> {
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 });

View File

@ -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);

View File

@ -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<InviteData>(`/api/v1/invite/validate/${token}`, {
suppressErrorToast: true,
} as any);
const response = await apiClient.get<InviteData>(`/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);
}