From c31e4253dd76f76156bfd637d48ed10412ef04a8 Mon Sep 17 00:00:00 2001 From: James Brunton Date: Wed, 1 Apr 2026 09:21:26 +0100 Subject: [PATCH] Fix `any` type usage in `proprietary/` (#5949) # Description of Changes Follow on from #5934, expanding `any` type usage ban to the `proprietary/` folder --- frontend/eslint.config.mjs | 5 +- .../proprietary/auth/springAuthClient.test.ts | 16 +- .../src/proprietary/auth/springAuthClient.ts | 4 +- .../shared/ChangeUserPasswordModal.tsx | 7 +- .../components/shared/DividerWithText.tsx | 2 +- .../components/shared/InviteMembersModal.tsx | 22 +-- .../components/shared/ManageBillingButton.tsx | 4 +- .../components/shared/UpgradeBanner.tsx | 6 +- .../configSections/AdminAdvancedSection.tsx | 18 +-- .../configSections/AdminAuditSection.tsx | 5 +- .../AdminConnectionsSection.tsx | 137 ++++++++++++------ .../configSections/AdminDatabaseSection.tsx | 31 ++-- .../configSections/AdminFeaturesSection.tsx | 6 +- .../configSections/AdminGeneralSection.tsx | 8 +- .../configSections/AdminPlanSection.tsx | 4 +- .../configSections/AdminPrivacySection.tsx | 6 +- .../configSections/AdminSecuritySection.tsx | 8 +- .../configSections/AdminUsageSection.tsx | 4 +- .../config/configSections/PeopleSection.tsx | 55 ++++--- .../configSections/TeamDetailsSection.tsx | 48 +++--- .../config/configSections/TeamsSection.tsx | 29 ++-- .../configSections/audit/AuditEventsTable.tsx | 18 +-- .../audit/AuditExportSection.tsx | 2 +- .../configSections/audit/AuditFiltersForm.tsx | 10 +- .../stripeCheckout/hooks/useLicensePolling.ts | 4 +- .../components/workflow/ParticipantView.tsx | 8 +- .../contexts/ServerExperienceContext.tsx | 14 +- .../hooks/workflow/useParticipantSession.ts | 29 ++-- .../src/proprietary/routes/InviteAccept.tsx | 25 ++-- .../proprietary/routes/ShareLinkLoader.tsx | 7 +- .../src/proprietary/routes/ShareLinkPage.tsx | 13 +- .../proprietary/services/shareLinkImport.ts | 8 +- .../src/proprietary/services/teamService.ts | 22 ++- .../services/userManagementService.ts | 22 +-- 34 files changed, 341 insertions(+), 266 deletions(-) diff --git a/frontend/eslint.config.mjs b/frontend/eslint.config.mjs index 6f0ed90cb..efe45f17b 100644 --- a/frontend/eslint.config.mjs +++ b/frontend/eslint.config.mjs @@ -83,7 +83,10 @@ export default defineConfig( }, // Folders that have been cleaned up and are now conformant - stricter rules enforced here { - files: ['src/saas/**/*.{js,mjs,jsx,ts,tsx}'], + files: [ + 'src/proprietary/**/*.{js,mjs,jsx,ts,tsx}', + 'src/saas/**/*.{js,mjs,jsx,ts,tsx}', + ], languageOptions: { parserOptions: { project: true, diff --git a/frontend/src/proprietary/auth/springAuthClient.test.ts b/frontend/src/proprietary/auth/springAuthClient.test.ts index cae070373..40d7ef9da 100644 --- a/frontend/src/proprietary/auth/springAuthClient.test.ts +++ b/frontend/src/proprietary/auth/springAuthClient.test.ts @@ -2,7 +2,7 @@ import { describe, it, expect, beforeEach, vi, afterEach } from 'vitest'; import { springAuth } from '@app/auth/springAuthClient'; import { startOAuthNavigation } from '@app/extensions/oauthNavigation'; import apiClient from '@app/services/apiClient'; -import { AxiosError } from 'axios'; +import { AxiosError, type AxiosResponse, type InternalAxiosRequestConfig } from 'axios'; // Mock apiClient vi.mock('@app/services/apiClient'); @@ -45,7 +45,7 @@ describe('SpringAuthClient', () => { vi.mocked(apiClient.get).mockResolvedValueOnce({ status: 200, data: { user: mockUser }, - } as any); + } as unknown as AxiosResponse); const result = await springAuth.getSession(); @@ -74,7 +74,7 @@ describe('SpringAuthClient', () => { statusText: 'Unauthorized', data: {}, headers: {}, - config: {} as any, + config: {} as InternalAxiosRequestConfig, } ); @@ -102,7 +102,7 @@ describe('SpringAuthClient', () => { statusText: 'Forbidden', data: {}, headers: {}, - config: {} as any, + config: {} as InternalAxiosRequestConfig, } ); @@ -141,7 +141,7 @@ describe('SpringAuthClient', () => { expires_in: 3600, }, }, - } as any); + } as unknown as AxiosResponse); // Spy on window.dispatchEvent const dispatchEventSpy = vi.spyOn(window, 'dispatchEvent'); @@ -208,7 +208,7 @@ describe('SpringAuthClient', () => { vi.mocked(apiClient.post).mockResolvedValueOnce({ status: 200, data: { user: mockUser }, - } as any); + } as unknown as AxiosResponse); const result = await springAuth.signUp(credentials); @@ -259,7 +259,7 @@ describe('SpringAuthClient', () => { vi.mocked(apiClient.post).mockResolvedValueOnce({ status: 200, data: {}, - } as any); + } as unknown as AxiosResponse); const result = await springAuth.signOut(); @@ -308,7 +308,7 @@ describe('SpringAuthClient', () => { expires_in: 3600, }, }, - } as any); + } as unknown as AxiosResponse); const result = await springAuth.refreshSession(); diff --git a/frontend/src/proprietary/auth/springAuthClient.ts b/frontend/src/proprietary/auth/springAuthClient.ts index 373df79c7..b97191bee 100644 --- a/frontend/src/proprietary/auth/springAuthClient.ts +++ b/frontend/src/proprietary/auth/springAuthClient.ts @@ -85,7 +85,7 @@ export interface User { is_anonymous?: boolean; isFirstLogin?: boolean; authenticationType?: string; - app_metadata?: Record; + app_metadata?: Record; } export interface Session { @@ -447,7 +447,7 @@ class SpringAuthClient { */ async signInWithOAuth(params: { provider: OAuthProvider; - options?: { redirectTo?: string; queryParams?: Record }; + options?: { redirectTo?: string; queryParams?: Record }; }): Promise<{ error: AuthError | null }> { try { const redirectPath = normalizeRedirectPath(params.options?.redirectTo); diff --git a/frontend/src/proprietary/components/shared/ChangeUserPasswordModal.tsx b/frontend/src/proprietary/components/shared/ChangeUserPasswordModal.tsx index 9e0cd222c..27f7741a0 100644 --- a/frontend/src/proprietary/components/shared/ChangeUserPasswordModal.tsx +++ b/frontend/src/proprietary/components/shared/ChangeUserPasswordModal.tsx @@ -1,4 +1,5 @@ import { useEffect, useMemo, useState } from 'react'; +import { isAxiosError } from 'axios'; import { useTranslation } from 'react-i18next'; import { ActionIcon, @@ -125,8 +126,10 @@ export default function ChangeUserPasswordModal({ opened, onClose, user, onSucce alert({ alertType: 'success', title: t('workspace.people.changePassword.success', 'Password updated successfully') }); onSuccess(); handleClose(); - } catch (error: any) { - const errorMessage = error.response?.data?.message || error.response?.data?.error || error.message || t('workspace.people.changePassword.error', 'Failed to update password'); + } catch (error: unknown) { + const errorMessage = isAxiosError(error) + ? (error.response?.data?.message || error.response?.data?.error || error.message) + : (error instanceof Error ? error.message : undefined) || t('workspace.people.changePassword.error', 'Failed to update password'); alert({ alertType: 'error', title: errorMessage }); } finally { setProcessing(false); diff --git a/frontend/src/proprietary/components/shared/DividerWithText.tsx b/frontend/src/proprietary/components/shared/DividerWithText.tsx index 888f4acfb..df1e98583 100644 --- a/frontend/src/proprietary/components/shared/DividerWithText.tsx +++ b/frontend/src/proprietary/components/shared/DividerWithText.tsx @@ -12,7 +12,7 @@ interface TextDividerProps { export default function DividerWithText({ text, className = '', style, variant = 'default', respondsToDarkMode = true, opacity }: TextDividerProps) { const variantClass = variant === 'subcategory' ? 'subcategory' : ''; const themeClass = respondsToDarkMode ? '' : 'force-light'; - const styleWithOpacity = opacity !== undefined ? { ...(style || {}), ['--text-divider-opacity' as any]: opacity } : style; + const styleWithOpacity = opacity !== undefined ? { ...(style || {}), ['--text-divider-opacity' as string]: opacity } : style; if (text) { return ( diff --git a/frontend/src/proprietary/components/shared/InviteMembersModal.tsx b/frontend/src/proprietary/components/shared/InviteMembersModal.tsx index 3298ca8e9..24c522acc 100644 --- a/frontend/src/proprietary/components/shared/InviteMembersModal.tsx +++ b/frontend/src/proprietary/components/shared/InviteMembersModal.tsx @@ -1,4 +1,5 @@ import { useState, useEffect, useRef } from 'react'; +import { isAxiosError } from 'axios'; import { useTranslation } from 'react-i18next'; import { Modal, @@ -158,9 +159,11 @@ export default function InviteMembersModal({ opened, onClose, onSuccess }: Invit forceChange: false, forceMFA: false, }); - } catch (error: any) { + } catch (error: unknown) { console.error('Failed to invite user:', error); - const errorMessage = error.response?.data?.message || error.response?.data?.error || error.message || t('workspace.people.addMember.error'); + const errorMessage = isAxiosError(error) + ? (error.response?.data?.message || error.response?.data?.error || error.message) + : (error instanceof Error ? error.message : undefined) || t('workspace.people.addMember.error'); alert({ alertType: 'error', title: errorMessage }); } finally { setProcessing(false); @@ -211,12 +214,11 @@ export default function InviteMembersModal({ opened, onClose, onSuccess }: Invit body: response.errors || response.error }); } - } catch (error: any) { + } catch (error: unknown) { console.error('Failed to invite users:', error); - const errorMessage = error.response?.data?.message || - error.response?.data?.error || - error.message || - t('workspace.people.emailInvite.error', 'Failed to send invites'); + const errorMessage = isAxiosError(error) + ? (error.response?.data?.message || error.response?.data?.error || error.message) + : (error instanceof Error ? error.message : undefined) || t('workspace.people.emailInvite.error', 'Failed to send invites'); alert({ alertType: 'error', title: errorMessage }); } finally { setProcessing(false); @@ -239,9 +241,11 @@ export default function InviteMembersModal({ opened, onClose, onSuccess }: Invit if (inviteLinkForm.sendEmail && inviteLinkForm.email) { alert({ alertType: 'success', title: t('workspace.people.inviteLink.emailSent', 'Invite link generated and sent via email') }); } - } 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 = isAxiosError(error) + ? (error.response?.data?.message || error.response?.data?.error || error.message) + : (error instanceof Error ? error.message : undefined) || t('workspace.people.inviteLink.error', 'Failed to generate invite link'); alert({ alertType: 'error', title: errorMessage }); } finally { setProcessing(false); diff --git a/frontend/src/proprietary/components/shared/ManageBillingButton.tsx b/frontend/src/proprietary/components/shared/ManageBillingButton.tsx index fc523f62f..bdbf49bec 100644 --- a/frontend/src/proprietary/components/shared/ManageBillingButton.tsx +++ b/frontend/src/proprietary/components/shared/ManageBillingButton.tsx @@ -34,12 +34,12 @@ export const ManageBillingButton: React.FC = ({ // Open billing portal in new tab window.open(response.url, '_blank'); setLoading(false); - } catch (error: any) { + } catch (error: unknown) { console.error('Failed to open billing portal:', error); alert({ alertType: 'error', title: t('billing.portal.error', 'Failed to open billing portal'), - body: error.message || 'Please try again or contact support.', + body: (error instanceof Error ? error.message : undefined) || 'Please try again or contact support.', }); setLoading(false); } diff --git a/frontend/src/proprietary/components/shared/UpgradeBanner.tsx b/frontend/src/proprietary/components/shared/UpgradeBanner.tsx index 5b31eedca..e5d65bd4b 100644 --- a/frontend/src/proprietary/components/shared/UpgradeBanner.tsx +++ b/frontend/src/proprietary/components/shared/UpgradeBanner.tsx @@ -86,7 +86,7 @@ const UpgradeBanner: React.FC = () => { const scenarioProvidesInfo = scenarioKey && scenarioKey !== 'unknown' && scenarioKey !== 'licensed'; const derivedIsAdmin = scenarioProvidesInfo - ? scenarioKey!.includes('admin') + ? scenarioKey.includes('admin') : isAdmin; const derivedHasPaidLicense = scenarioKey === 'licensed' @@ -95,10 +95,10 @@ const UpgradeBanner: React.FC = () => { ? hasPaidLicense : false; const derivedIsUnderLimit = scenarioProvidesInfo - ? scenarioKey!.includes('under-limit') + ? scenarioKey.includes('under-limit') : isUnderLimit === true; const derivedIsOverLimit = scenarioProvidesInfo - ? scenarioKey!.includes('over-limit') + ? scenarioKey.includes('over-limit') : isOverLimit === true; const effectiveIsAdmin = scenario diff --git a/frontend/src/proprietary/components/shared/config/configSections/AdminAdvancedSection.tsx b/frontend/src/proprietary/components/shared/config/configSections/AdminAdvancedSection.tsx index 033abd326..ff297b4a4 100644 --- a/frontend/src/proprietary/components/shared/config/configSections/AdminAdvancedSection.tsx +++ b/frontend/src/proprietary/components/shared/config/configSections/AdminAdvancedSection.tsx @@ -1,4 +1,5 @@ import { useCallback, useEffect, useMemo, useState } from 'react'; +import { isAxiosError } from 'axios'; import { useTranslation } from 'react-i18next'; import { NumberInput, Switch, Button, Stack, Paper, Text, Loader, Group, Accordion, TextInput, MultiSelect } from '@mantine/core'; import { alert } from '@app/components/toast'; @@ -72,7 +73,7 @@ export default function AdminAdvancedSection() { isFieldPending, } = useAdminSettings({ sectionName: 'advanced', - fetchTransformer: async (): Promise }> => { + fetchTransformer: async (): Promise }> => { const [systemResponse, processExecutorResponse] = await Promise.all([ apiClient.get('/api/v1/admin/settings/section/system'), apiClient.get('/api/v1/admin/settings/section/processExecutor') @@ -81,7 +82,7 @@ export default function AdminAdvancedSection() { const systemData = systemResponse.data || {}; const processExecutorData = processExecutorResponse.data || {}; - const result: AdvancedSettingsData & { _pending?: Record } = { + const result: AdvancedSettingsData & { _pending?: Record } = { enableAlphaFunctionality: systemData.enableAlphaFunctionality || false, maxDPI: systemData.maxDPI || 0, enableUrlToPDF: systemData.enableUrlToPDF || false, @@ -101,7 +102,7 @@ export default function AdminAdvancedSection() { }; // Merge pending blocks from both endpoints - const pendingBlock: Record = {}; + const pendingBlock: Record = {}; if (systemData._pending?.enableAlphaFunctionality !== undefined) { pendingBlock.enableAlphaFunctionality = systemData._pending.enableAlphaFunctionality; } @@ -131,7 +132,7 @@ export default function AdminAdvancedSection() { return result; }, saveTransformer: (settings) => { - const deltaSettings: Record = { + const deltaSettings: Record = { 'system.enableAlphaFunctionality': settings.enableAlphaFunctionality, 'system.maxDPI': settings.maxDPI, 'system.enableUrlToPDF': settings.enableUrlToPDF, @@ -281,9 +282,8 @@ export default function AdminAdvancedSection() { setManualDownloadLinks([]); } catch (error) { console.error('[AdminAdvancedSection] Download tessdata languages failed', error); - const response = (error as any)?.response; - const status = response?.status; - const serverMessage = response?.data?.message; + const status = isAxiosError(error) ? error.response?.status : undefined; + const serverMessage = isAxiosError(error) ? error.response?.data?.message : undefined; if (status === 403) { console.warn('[AdminAdvancedSection] Tessdata directory not writable, falling back to manual download:', serverMessage); @@ -309,12 +309,12 @@ export default function AdminAdvancedSection() { } let message: string; - if (!response) { + if (!isAxiosError(error) || !error.response) { message = t( 'admin.settings.advanced.tessdataDir.downloadErrorNetwork', 'Download failed due to a network error. Please check your connection and try again.' ); - } else if (status >= 500) { + } else if (status !== undefined && status >= 500) { message = t( 'admin.settings.advanced.tessdataDir.downloadErrorServer', 'The server encountered an error while downloading tessdata languages. Please try again later.' diff --git a/frontend/src/proprietary/components/shared/config/configSections/AdminAuditSection.tsx b/frontend/src/proprietary/components/shared/config/configSections/AdminAuditSection.tsx index 53939a45c..06703d813 100644 --- a/frontend/src/proprietary/components/shared/config/configSections/AdminAuditSection.tsx +++ b/frontend/src/proprietary/components/shared/config/configSections/AdminAuditSection.tsx @@ -1,4 +1,5 @@ import React, { useState, useEffect } from 'react'; +import { isAxiosError } from 'axios'; import { Tabs, Loader, Alert, Stack, Text, Button, Accordion } from '@mantine/core'; import { useTranslation } from 'react-i18next'; import { useNavigate } from 'react-router-dom'; @@ -35,9 +36,9 @@ const AdminAuditSection: React.FC = () => { setError(null); const status = await auditService.getSystemStatus(); setSystemStatus(status); - } catch (err: any) { + } catch (err: unknown) { // Check if this is a permission/license error (403/404) - const status = err?.response?.status; + const status = isAxiosError(err) ? err.response?.status : undefined; if (status === 403 || status === 404) { setError('enterprise-license-required'); } else { diff --git a/frontend/src/proprietary/components/shared/config/configSections/AdminConnectionsSection.tsx b/frontend/src/proprietary/components/shared/config/configSections/AdminConnectionsSection.tsx index f3cec6a1c..fd60e75cb 100644 --- a/frontend/src/proprietary/components/shared/config/configSections/AdminConnectionsSection.tsx +++ b/frontend/src/proprietary/components/shared/config/configSections/AdminConnectionsSection.tsx @@ -44,6 +44,66 @@ interface TelegramSettingsData { feedback?: FeedbackSettings; } +interface MailSettings { + enabled?: boolean; + enableInvites?: boolean; + host?: string; + port?: number; + username?: string; + password?: string; + from?: string; +} + +interface GoogleDriveSettings { + enabled?: boolean; + clientId?: string; + apiKey?: string; + appId?: string; +} + +interface OAuth2GenericSettings { + enabled?: boolean; + provider?: string; + issuer?: string; + clientId?: string; + clientSecret?: string; + scopes?: string; + useAsUsername?: string; + autoCreateUser?: boolean; + blockRegistration?: boolean; +} + +interface Saml2Settings { + enabled?: boolean; + provider?: string; + registrationId?: string; + idpMetadataUri?: string; + idpSingleLoginUrl?: string; + idpSingleLogoutUrl?: string; + idpIssuer?: string; + idpCert?: string; + privateKey?: string; + spCert?: string; + autoCreateUser?: boolean; + blockRegistration?: boolean; +} + +interface OAuth2ClientSettings { + clientId?: string; + clientSecret?: string; + scopes?: string; + useAsUsername?: string; + issuer?: string; +} + +type ProviderSettings = + | MailSettings + | TelegramSettingsData + | GoogleDriveSettings + | OAuth2GenericSettings + | Saml2Settings + | OAuth2ClientSettings; + interface ConnectionsSettingsData { oauth2?: { enabled?: boolean; @@ -55,22 +115,10 @@ interface ConnectionsSettingsData { blockRegistration?: boolean; useAsUsername?: string; scopes?: string; - client?: { - [key: string]: any; - }; - }; - saml2?: { - [key: string]: any; - }; - mail?: { - enabled?: boolean; - enableInvites?: boolean; - host?: string; - port?: number; - username?: string; - password?: string; - from?: string; + client?: Record; }; + saml2?: Saml2Settings; + mail?: MailSettings; telegram?: TelegramSettingsData; ssoAutoLogin?: boolean; enableMobileScanner?: boolean; @@ -93,7 +141,7 @@ export default function AdminConnectionsSection() { const adminSettings = useAdminSettings({ sectionName: 'connections', - fetchTransformer: async (): Promise }> => { + fetchTransformer: async (): Promise }> => { // Fetch security settings (oauth2, saml2) const securityResponse = await apiClient.get('/api/v1/admin/settings/section/security'); const securityData = securityResponse.data || {}; @@ -114,7 +162,7 @@ export default function AdminConnectionsSection() { const systemResponse = await apiClient.get('/api/v1/admin/settings/section/system'); const systemData = systemResponse.data || {}; - const result: ConnectionsSettingsData & { _pending?: Record } = { + const result: ConnectionsSettingsData & { _pending?: Record } = { oauth2: securityData.oauth2 || {}, saml2: securityData.saml2 || {}, mail: mailData || {}, @@ -132,7 +180,7 @@ export default function AdminConnectionsSection() { }; // Merge pending blocks from all endpoints - const pendingBlock: Record = {}; + const pendingBlock: Record = {}; if (securityData._pending?.oauth2) { pendingBlock.oauth2 = securityData._pending.oauth2; } @@ -183,13 +231,13 @@ export default function AdminConnectionsSection() { return result; }, saveTransformer: (currentSettings: ConnectionsSettingsData) => { - const deltaSettings: Record = {}; + const deltaSettings: Record = {}; // Build delta for oauth2 settings if (currentSettings.oauth2) { Object.keys(currentSettings.oauth2).forEach((key) => { if (key !== 'client') { - deltaSettings[`security.oauth2.${key}`] = (currentSettings.oauth2 as Record)[key]; + deltaSettings[`security.oauth2.${key}`] = (currentSettings.oauth2 as Record)[key]; } }); @@ -197,7 +245,7 @@ export default function AdminConnectionsSection() { const oauth2Client = currentSettings.oauth2.client; if (oauth2Client) { Object.keys(oauth2Client).forEach((providerId) => { - const providerSettings = oauth2Client[providerId]; + const providerSettings = oauth2Client[providerId] as Record; Object.keys(providerSettings).forEach((key) => { deltaSettings[`security.oauth2.client.${providerId}.${key}`] = providerSettings[key]; }); @@ -207,22 +255,25 @@ export default function AdminConnectionsSection() { // Build delta for saml2 settings if (currentSettings.saml2) { - Object.keys(currentSettings.saml2).forEach((key) => { - deltaSettings[`security.saml2.${key}`] = (currentSettings.saml2 as Record)[key]; + const saml2 = currentSettings.saml2 as Record; + Object.keys(saml2).forEach((key) => { + deltaSettings[`security.saml2.${key}`] = saml2[key]; }); } // Mail settings if (currentSettings.mail) { - Object.keys(currentSettings.mail).forEach((key) => { - deltaSettings[`mail.${key}`] = (currentSettings.mail as Record)[key]; + const mail = currentSettings.mail as Record; + Object.keys(mail).forEach((key) => { + deltaSettings[`mail.${key}`] = mail[key]; }); } // Telegram settings if (currentSettings.telegram) { - Object.keys(currentSettings.telegram).forEach((key) => { - deltaSettings[`telegram.${key}`] = (currentSettings.telegram as Record)[key]; + const telegram = currentSettings.telegram as Record; + Object.keys(telegram).forEach((key) => { + deltaSettings[`telegram.${key}`] = telegram[key]; }); } @@ -332,7 +383,7 @@ export default function AdminConnectionsSection() { return !!(providerSettings?.clientId); }; - const getProviderSettings = (provider: Provider): Record => { + const getProviderSettings = (provider: Provider): ProviderSettings => { if (provider.id === 'saml2') { return settings?.saml2 || {}; } @@ -346,17 +397,17 @@ export default function AdminConnectionsSection() { } if (provider.id === 'googledrive') { - return { + const gd: GoogleDriveSettings = { enabled: settings?.googleDriveEnabled, clientId: settings?.googleDriveClientId, apiKey: settings?.googleDriveApiKey, appId: settings?.googleDriveAppId, }; + return gd; } if (provider.id === 'oauth2-generic') { - // Generic OAuth2 settings are at the root oauth2 level - return { + const generic: OAuth2GenericSettings = { enabled: settings?.oauth2?.enabled, provider: settings?.oauth2?.provider, issuer: settings?.oauth2?.issuer, @@ -367,6 +418,7 @@ export default function AdminConnectionsSection() { autoCreateUser: settings?.oauth2?.autoCreateUser, blockRegistration: settings?.oauth2?.blockRegistration, }; + return generic; } // Specific OAuth2 provider settings @@ -386,32 +438,35 @@ export default function AdminConnectionsSection() { const linkedProviders = allProviders.filter((p) => isProviderConfigured(p)); const availableProviders = allProviders.filter((p) => !isProviderConfigured(p)); - const updateProviderSettings = (provider: Provider, updatedSettings: Record) => { + const updateProviderSettings = (provider: Provider, updatedSettings: Record) => { if (provider.id === 'smtp') { - setSettings({ ...settings, mail: updatedSettings }); + setSettings({ ...settings, mail: updatedSettings as MailSettings }); } else if (provider.id === 'telegram') { - setSettings({ ...settings, telegram: updatedSettings }); + setSettings({ ...settings, telegram: updatedSettings as TelegramSettingsData }); } else if (provider.id === 'googledrive') { + const gd = updatedSettings as GoogleDriveSettings; setSettings({ ...settings, - googleDriveEnabled: updatedSettings.enabled, - googleDriveClientId: updatedSettings.clientId, - googleDriveApiKey: updatedSettings.apiKey, - googleDriveAppId: updatedSettings.appId, + googleDriveEnabled: gd.enabled, + googleDriveClientId: gd.clientId, + googleDriveApiKey: gd.apiKey, + googleDriveAppId: gd.appId, }); } else if (provider.id === 'saml2') { - setSettings({ ...settings, saml2: updatedSettings }); + setSettings({ ...settings, saml2: updatedSettings as Saml2Settings }); } else if (provider.id === 'oauth2-generic') { - setSettings({ ...settings, oauth2: updatedSettings }); + const generic = updatedSettings as OAuth2GenericSettings; + setSettings({ ...settings, oauth2: { ...settings.oauth2, ...generic } }); } else { // Specific OAuth2 provider + const clientSettings = updatedSettings as OAuth2ClientSettings; setSettings({ ...settings, oauth2: { ...settings.oauth2, client: { ...settings.oauth2?.client, - [provider.id]: updatedSettings + [provider.id]: clientSettings, } } }); diff --git a/frontend/src/proprietary/components/shared/config/configSections/AdminDatabaseSection.tsx b/frontend/src/proprietary/components/shared/config/configSections/AdminDatabaseSection.tsx index a654f5abd..749271d01 100644 --- a/frontend/src/proprietary/components/shared/config/configSections/AdminDatabaseSection.tsx +++ b/frontend/src/proprietary/components/shared/config/configSections/AdminDatabaseSection.tsx @@ -1,4 +1,5 @@ import { useCallback, useEffect, useMemo, useState } from "react"; +import { isAxiosError } from "axios"; import { useTranslation } from "react-i18next"; import { NumberInput, @@ -68,7 +69,7 @@ export default function AdminDatabaseSection() { const { settings, setSettings, loading, saving, fetchSettings, saveSettings, isFieldPending } = useAdminSettings({ sectionName: "database", - fetchTransformer: async (): Promise }> => { + fetchTransformer: async (): Promise }> => { const response = await apiClient.get("/api/v1/admin/settings/section/system"); const systemData = response.data || {}; @@ -85,7 +86,7 @@ export default function AdminDatabaseSection() { }; // Map pending changes from system._pending.datasource to root level - const result: DatabaseSettingsData & { _pending?: Record } = { ...datasource }; + const result: DatabaseSettingsData & { _pending?: Record } = { ...datasource }; if (systemData._pending?.datasource) { result._pending = systemData._pending.datasource; } @@ -94,7 +95,7 @@ export default function AdminDatabaseSection() { }, saveTransformer: (settings: DatabaseSettingsData) => { // Convert flat settings to dot-notation for delta endpoint - const deltaSettings: Record = { + const deltaSettings: Record = { "system.datasource.enableCustomDatabase": settings.enableCustomDatabase, "system.datasource.customDatabaseUrl": settings.customDatabaseUrl, "system.datasource.username": settings.username, @@ -141,8 +142,8 @@ export default function AdminDatabaseSection() { const data = await databaseManagementService.getDatabaseData(); setBackupFiles(data.backupFiles || []); setDatabaseVersion(data.databaseVersion || null); - } catch (error: any) { - const message = error?.response?.data?.message || error?.message; + } catch (error: unknown) { + const message = isAxiosError(error) ? (error.response?.data?.message || error.message) : undefined; alert({ alertType: "error", title: t("admin.settings.database.loadError", "Failed to load database backups"), @@ -189,8 +190,8 @@ export default function AdminDatabaseSection() { await databaseManagementService.createBackup(); alert({ alertType: "success", title: t("admin.settings.database.backupCreated", "Backup created successfully") }); await loadBackupData(); - } catch (error: any) { - const message = error?.response?.data?.message || error?.message; + } catch (error: unknown) { + const message = isAxiosError(error) ? (error.response?.data?.message || error.message) : undefined; alert({ alertType: "error", title: t("admin.settings.database.backupFailed", "Failed to create backup"), @@ -209,8 +210,8 @@ export default function AdminDatabaseSection() { alert({ alertType: "success", title: t("admin.settings.database.importSuccess", "Backup imported successfully") }); setUploadFile(null); await loadBackupData(); - } catch (error: any) { - const message = error?.response?.data?.message || error?.message; + } catch (error: unknown) { + const message = isAxiosError(error) ? (error.response?.data?.message || error.message) : undefined; alert({ alertType: "error", title: t("admin.settings.database.importFailed", "Failed to import backup"), @@ -270,8 +271,8 @@ export default function AdminDatabaseSection() { await databaseManagementService.importFromFileName(fileName); alert({ alertType: "success", title: t("admin.settings.database.importSuccess", "Backup imported successfully") }); await loadBackupData(); - } catch (error: any) { - const message = error?.response?.data?.message || error?.message; + } catch (error: unknown) { + const message = isAxiosError(error) ? (error.response?.data?.message || error.message) : undefined; alert({ alertType: "error", title: t("admin.settings.database.importFailed", "Failed to import backup"), @@ -289,8 +290,8 @@ export default function AdminDatabaseSection() { await databaseManagementService.deleteBackup(fileName); alert({ alertType: "success", title: t("admin.settings.database.deleteSuccess", "Backup deleted") }); await loadBackupData(); - } catch (error: any) { - const message = error?.response?.data?.message || error?.message; + } catch (error: unknown) { + const message = isAxiosError(error) ? (error.response?.data?.message || error.message) : undefined; alert({ alertType: "error", title: t("admin.settings.database.deleteFailed", "Failed to delete backup"), @@ -320,8 +321,8 @@ export default function AdminDatabaseSection() { link.download = fileName; document.body.appendChild(link); link.click(); - } catch (error: any) { - const message = error?.response?.data?.message || error?.message; + } catch (error: unknown) { + const message = isAxiosError(error) ? (error.response?.data?.message || error.message) : undefined; alert({ alertType: "error", title: t("admin.settings.database.downloadFailed", "Failed to download backup"), diff --git a/frontend/src/proprietary/components/shared/config/configSections/AdminFeaturesSection.tsx b/frontend/src/proprietary/components/shared/config/configSections/AdminFeaturesSection.tsx index ed9b6a130..7da712f76 100644 --- a/frontend/src/proprietary/components/shared/config/configSections/AdminFeaturesSection.tsx +++ b/frontend/src/proprietary/components/shared/config/configSections/AdminFeaturesSection.tsx @@ -38,11 +38,11 @@ export default function AdminFeaturesSection() { isFieldPending, } = useAdminSettings({ sectionName: 'features', - fetchTransformer: async (): Promise }> => { + fetchTransformer: async (): Promise }> => { const systemResponse = await apiClient.get('/api/v1/admin/settings/section/system'); const systemData = systemResponse.data || {}; - const result: FeaturesSettingsData & { _pending?: Record } = { + const result: FeaturesSettingsData & { _pending?: Record } = { serverCertificate: systemData.serverCertificate || { enabled: true, organizationName: 'Stirling-PDF', @@ -59,7 +59,7 @@ export default function AdminFeaturesSection() { return result; }, saveTransformer: (settings: FeaturesSettingsData) => { - const deltaSettings: Record = {}; + const deltaSettings: Record = {}; if (settings.serverCertificate) { deltaSettings['system.serverCertificate.enabled'] = settings.serverCertificate.enabled; diff --git a/frontend/src/proprietary/components/shared/config/configSections/AdminGeneralSection.tsx b/frontend/src/proprietary/components/shared/config/configSections/AdminGeneralSection.tsx index 9ca8a6030..39d1758df 100644 --- a/frontend/src/proprietary/components/shared/config/configSections/AdminGeneralSection.tsx +++ b/frontend/src/proprietary/components/shared/config/configSections/AdminGeneralSection.tsx @@ -91,7 +91,7 @@ export default function AdminGeneralSection() { isFieldPending, } = useAdminSettings({ sectionName: 'general', - fetchTransformer: async (): Promise }> => { + fetchTransformer: async (): Promise }> => { const [uiResponse, systemResponse, premiumResponse] = await Promise.all([ apiClient.get('/api/v1/admin/settings/section/ui'), apiClient.get('/api/v1/admin/settings/section/system'), @@ -113,7 +113,7 @@ export default function AdminGeneralSection() { ? watchedFoldersDirs : (pipelinePaths.watchedFoldersDir ? [pipelinePaths.watchedFoldersDir] : []); - const result: GeneralSettingsData & { _pending?: Record } = { + const result: GeneralSettingsData & { _pending?: Record } = { ui, system, customPaths: { @@ -140,7 +140,7 @@ export default function AdminGeneralSection() { }; // Merge pending blocks from all three endpoints - const pendingBlock: Record = {}; + const pendingBlock: Record = {}; if (ui._pending) { pendingBlock.ui = ui._pending; } @@ -161,7 +161,7 @@ export default function AdminGeneralSection() { return result; }, saveTransformer: (settings: GeneralSettingsData) => { - const deltaSettings: Record = { + const deltaSettings: Record = { // UI settings 'ui.appNameNavbar': settings.ui?.appNameNavbar, 'ui.languages': settings.ui?.languages, diff --git a/frontend/src/proprietary/components/shared/config/configSections/AdminPlanSection.tsx b/frontend/src/proprietary/components/shared/config/configSections/AdminPlanSection.tsx index 0b47cf148..d1f42870f 100644 --- a/frontend/src/proprietary/components/shared/config/configSections/AdminPlanSection.tsx +++ b/frontend/src/proprietary/components/shared/config/configSections/AdminPlanSection.tsx @@ -72,12 +72,12 @@ const AdminPlanSection: React.FC = () => { // Open billing portal in new tab window.open(response.url, '_blank'); - } catch (error: any) { + } catch (error: unknown) { console.error('Failed to open billing portal:', error); alert({ alertType: 'error', title: t('billing.portal.error', 'Failed to open billing portal'), - body: error.message || 'Please try again or contact support.', + body: (error instanceof Error ? error.message : undefined) || 'Please try again or contact support.', }); } }, [licenseInfo, t, validateLoginEnabled]); diff --git a/frontend/src/proprietary/components/shared/config/configSections/AdminPrivacySection.tsx b/frontend/src/proprietary/components/shared/config/configSections/AdminPrivacySection.tsx index aea2593bf..80c592f96 100644 --- a/frontend/src/proprietary/components/shared/config/configSections/AdminPrivacySection.tsx +++ b/frontend/src/proprietary/components/shared/config/configSections/AdminPrivacySection.tsx @@ -33,7 +33,7 @@ export default function AdminPrivacySection() { isFieldPending, } = useAdminSettings({ sectionName: 'privacy', - fetchTransformer: async (): Promise }> => { + fetchTransformer: async (): Promise }> => { const [metricsResponse, systemResponse] = await Promise.all([ apiClient.get('/api/v1/admin/settings/section/metrics'), apiClient.get('/api/v1/admin/settings/section/system') @@ -42,14 +42,14 @@ export default function AdminPrivacySection() { const metrics = metricsResponse.data; const system = systemResponse.data; - const result: PrivacySettingsData & { _pending?: Record } = { + const result: PrivacySettingsData & { _pending?: Record } = { enableAnalytics: system.enableAnalytics || false, googleVisibility: system.googlevisibility || false, metricsEnabled: metrics.enabled || false }; // Merge pending blocks from both endpoints - const pendingBlock: Record = {}; + const pendingBlock: Record = {}; if (system._pending?.enableAnalytics !== undefined) { pendingBlock.enableAnalytics = system._pending.enableAnalytics; } diff --git a/frontend/src/proprietary/components/shared/config/configSections/AdminSecuritySection.tsx b/frontend/src/proprietary/components/shared/config/configSections/AdminSecuritySection.tsx index 29dc0c211..f915d9d69 100644 --- a/frontend/src/proprietary/components/shared/config/configSections/AdminSecuritySection.tsx +++ b/frontend/src/proprietary/components/shared/config/configSections/AdminSecuritySection.tsx @@ -67,7 +67,7 @@ export default function AdminSecuritySection() { isFieldPending, } = useAdminSettings({ sectionName: 'security', - fetchTransformer: async (): Promise }> => { + fetchTransformer: async (): Promise }> => { const [securityResponse, premiumResponse, systemResponse] = await Promise.all([ apiClient.get('/api/v1/admin/settings/section/security'), apiClient.get('/api/v1/admin/settings/section/premium'), @@ -93,7 +93,7 @@ export default function AdminSecuritySection() { systemPending: JSON.parse(JSON.stringify(systemPending || {})) }); - const combined: SecuritySettingsData & { _pending?: Record } = { + const combined: SecuritySettingsData & { _pending?: Record } = { ...securityActive }; @@ -108,7 +108,7 @@ export default function AdminSecuritySection() { } // Merge all _pending blocks - const mergedPending: Record = {}; + const mergedPending: Record = {}; if (securityPending) { Object.assign(mergedPending, securityPending); } @@ -128,7 +128,7 @@ export default function AdminSecuritySection() { saveTransformer: (settings: SecuritySettingsData) => { const { audit, html, ...securitySettings } = settings; - const deltaSettings: Record = { + const deltaSettings: Record = { // Security settings 'security.enableLogin': securitySettings.enableLogin, 'security.loginMethod': securitySettings.loginMethod, diff --git a/frontend/src/proprietary/components/shared/config/configSections/AdminUsageSection.tsx b/frontend/src/proprietary/components/shared/config/configSections/AdminUsageSection.tsx index fe551c8bc..a0db28e13 100644 --- a/frontend/src/proprietary/components/shared/config/configSections/AdminUsageSection.tsx +++ b/frontend/src/proprietary/components/shared/config/configSections/AdminUsageSection.tsx @@ -155,10 +155,10 @@ const AdminUsageSection: React.FC = () => { const displayedVisits = endpoints.reduce((sum, e) => sum + e.visits, 0); const totalVisits = Number.isFinite(data?.totalVisits) - ? Math.max(0, data?.totalVisits as number) + ? Math.max(0, data?.totalVisits ?? 0) : displayedVisits; const totalEndpoints = Number.isFinite(data?.totalEndpoints) - ? Math.max(0, data?.totalEndpoints as number) + ? Math.max(0, data?.totalEndpoints ?? 0) : endpoints.length; const displayedPercentage = totalVisits > 0 diff --git a/frontend/src/proprietary/components/shared/config/configSections/PeopleSection.tsx b/frontend/src/proprietary/components/shared/config/configSections/PeopleSection.tsx index 2b784511c..4b45d4fa6 100644 --- a/frontend/src/proprietary/components/shared/config/configSections/PeopleSection.tsx +++ b/frontend/src/proprietary/components/shared/config/configSections/PeopleSection.tsx @@ -1,4 +1,5 @@ import { useState, useEffect } from 'react'; +import { isAxiosError } from 'axios'; import { useTranslation } from 'react-i18next'; import { Stack, @@ -17,6 +18,7 @@ import { CloseButton, Avatar, Box, + type ComboboxItem, } from '@mantine/core'; import LocalIcon from '@app/components/shared/LocalIcon'; import { alert } from '@app/components/toast'; @@ -114,7 +116,7 @@ export default function PeopleSection() { ...user, isActive: adminData.userSessions[user.username] || false, lastRequest: adminData.userLastRequest[user.username] || undefined, - mfaEnabled: adminData.userSettings?.[user.username]?.mfaEnabled === 'true', + mfaEnabled: (adminData.userSettings?.[user.username] as Record | undefined)?.mfaEnabled === 'true', })); setUsers(enrichedUsers); @@ -225,12 +227,11 @@ export default function PeopleSection() { alert({ alertType: 'success', title: t('workspace.people.editMember.success') }); closeEditModal(); fetchData(); - } catch (error: any) { + } catch (error: unknown) { console.error('[PeopleSection] Failed to update user:', error); - const errorMessage = error.response?.data?.message || - error.response?.data?.error || - error.message || - t('workspace.people.editMember.error'); + const errorMessage = isAxiosError(error) + ? (error.response?.data?.message || error.response?.data?.error || error.message) + : (error instanceof Error ? error.message : undefined) || t('workspace.people.editMember.error'); alert({ alertType: 'error', title: errorMessage }); } finally { setProcessing(false); @@ -242,12 +243,11 @@ export default function PeopleSection() { await userManagementService.toggleUserEnabled(user.username, !user.enabled); alert({ alertType: 'success', title: t('workspace.people.toggleEnabled.success') }); fetchData(); - } catch (error: any) { + } catch (error: unknown) { console.error('[PeopleSection] Failed to toggle user status:', error); - const errorMessage = error.response?.data?.message || - error.response?.data?.error || - error.message || - t('workspace.people.toggleEnabled.error'); + const errorMessage = isAxiosError(error) + ? (error.response?.data?.message || error.response?.data?.error || error.message) + : (error instanceof Error ? error.message : undefined) || t('workspace.people.toggleEnabled.error'); alert({ alertType: 'error', title: errorMessage }); } }; @@ -262,12 +262,12 @@ export default function PeopleSection() { await userManagementService.deleteUser(user.username); alert({ alertType: 'success', title: t('workspace.people.deleteUserSuccess', 'User deleted successfully') }); fetchData(); - } catch (error: any) { + } catch (error: unknown) { console.error('[PeopleSection] Failed to delete user:', error); - const errorMessage = error.response?.data?.message || - error.response?.data?.error || - error.message || - t('workspace.people.deleteUserError', 'Failed to delete user'); + const errorMessage = isAxiosError(error) + ? (error.response?.data?.message || error.response?.data?.error || error.message) + : (error instanceof Error ? error.message : undefined) || + t('workspace.people.deleteUserError', 'Failed to delete user'); alert({ alertType: 'error', title: errorMessage }); } }; @@ -282,12 +282,11 @@ export default function PeopleSection() { await userManagementService.unlockUser(user.username); alert({ alertType: 'success', title: t('workspace.people.unlockUserSuccess', 'User account unlocked successfully') }); fetchData(); - } catch (error: any) { + } catch (error: unknown) { console.error('[PeopleSection] Failed to unlock user:', error); - const errorMessage = error.response?.data?.message || - error.response?.data?.error || - error.message || - t('workspace.people.unlockUserError', 'Failed to unlock user account'); + const errorMessage = isAxiosError(error) + ? (error.response?.data?.message || error.response?.data?.error || error.message) + : (error instanceof Error ? error.message : undefined) || t('workspace.people.unlockUserError', 'Failed to unlock user account'); alert({ alertType: 'error', title: errorMessage }); } }; @@ -339,9 +338,9 @@ export default function PeopleSection() { }, ]; - const renderRoleOption = ({ option }: { option: any }) => ( + const renderRoleOption = ({ option }: { option: ComboboxItem & { icon?: string; description?: string } }) => ( - + {option.label} @@ -668,12 +667,12 @@ export default function PeopleSection() { try { await userManagementService.disableMfaByAdmin(user.username); alert({ alertType: 'success', title: t('workspace.people.mfa.adminDisableSuccess', 'MFA disabled successfully for user') }); - } catch (error: any) { + } catch (error: unknown) { console.error('[PeopleSection] Failed to disable MFA for user:', error); - const errorMessage = error.response?.data?.message || - error.response?.data?.error || - error.message || - t('workspace.people.mfa.adminDisableError', 'Failed to disable MFA for user'); + const errorMessage = isAxiosError(error) + ? (error.response?.data?.message || error.response?.data?.error || error.message) + : (error instanceof Error ? error.message : undefined) || + t('workspace.people.mfa.adminDisableError', 'Failed to disable MFA for user'); alert({ alertType: 'error', title: errorMessage }); } }} diff --git a/frontend/src/proprietary/components/shared/config/configSections/TeamDetailsSection.tsx b/frontend/src/proprietary/components/shared/config/configSections/TeamDetailsSection.tsx index dd1f493a4..faf80d6a5 100644 --- a/frontend/src/proprietary/components/shared/config/configSections/TeamDetailsSection.tsx +++ b/frontend/src/proprietary/components/shared/config/configSections/TeamDetailsSection.tsx @@ -1,4 +1,5 @@ import { useState, useEffect } from 'react'; +import { isAxiosError } from 'axios'; import { useTranslation } from 'react-i18next'; import { Stack, @@ -110,12 +111,11 @@ export default function TeamDetailsSection({ teamId, onBack }: TeamDetailsSectio setAddMemberModalOpened(false); setSelectedUserId(''); fetchTeamDetails(); - } catch (error: any) { + } catch (error: unknown) { console.error('Failed to add member:', error); - const errorMessage = error.response?.data?.message || - error.response?.data?.error || - error.message || - t('workspace.teams.addMemberToTeam.error', 'Failed to add user to team'); + const errorMessage = isAxiosError(error) + ? (error.response?.data?.message || error.response?.data?.error || error.message) + : (error instanceof Error ? error.message : undefined) || t('workspace.teams.addMemberToTeam.error', 'Failed to add user to team'); alert({ alertType: 'error', title: errorMessage }); } finally { setProcessing(false); @@ -140,12 +140,11 @@ export default function TeamDetailsSection({ teamId, onBack }: TeamDetailsSectio await teamService.moveUserToTeam(user.username, user.rolesAsString || 'ROLE_USER', defaultTeam.id); alert({ alertType: 'success', title: t('workspace.teams.removeMemberSuccess', 'User removed from team') }); fetchTeamDetails(); - } catch (error: any) { + } catch (error: unknown) { console.error('Failed to remove member:', error); - const errorMessage = error.response?.data?.message || - error.response?.data?.error || - error.message || - t('workspace.teams.removeMemberError', 'Failed to remove user from team'); + const errorMessage = isAxiosError(error) + ? (error.response?.data?.message || error.response?.data?.error || error.message) + : (error instanceof Error ? error.message : undefined) || t('workspace.teams.removeMemberError', 'Failed to remove user from team'); alert({ alertType: 'error', title: errorMessage }); } finally { setProcessing(false); @@ -163,12 +162,12 @@ export default function TeamDetailsSection({ teamId, onBack }: TeamDetailsSectio await userManagementService.deleteUser(user.username); alert({ alertType: 'success', title: t('workspace.people.deleteUserSuccess', 'User deleted successfully') }); fetchTeamDetails(); - } catch (error: any) { + } catch (error: unknown) { console.error('Failed to delete user:', error); - const errorMessage = error.response?.data?.message || - error.response?.data?.error || - error.message || - t('workspace.people.deleteUserError', 'Failed to delete user'); + const errorMessage = isAxiosError(error) + ? (error.response?.data?.message || error.response?.data?.error || error.message) + : (error instanceof Error ? error.message : undefined) || + t('workspace.people.deleteUserError', 'Failed to delete user'); alert({ alertType: 'error', title: errorMessage }); } finally { setProcessing(false); @@ -185,12 +184,11 @@ export default function TeamDetailsSection({ teamId, onBack }: TeamDetailsSectio await userManagementService.unlockUser(user.username); alert({ alertType: 'success', title: t('workspace.people.unlockUserSuccess', 'User account unlocked successfully') }); fetchTeamDetails(); - } catch (error: any) { + } catch (error: unknown) { console.error('[TeamDetailsSection] Failed to unlock user:', error); - const errorMessage = error.response?.data?.message || - error.response?.data?.error || - error.message || - t('workspace.people.unlockUserError', 'Failed to unlock user account'); + const errorMessage = isAxiosError(error) + ? (error.response?.data?.message || error.response?.data?.error || error.message) + : (error instanceof Error ? error.message : undefined) || t('workspace.people.unlockUserError', 'Failed to unlock user account'); alert({ alertType: 'error', title: errorMessage }); } }; @@ -225,12 +223,12 @@ export default function TeamDetailsSection({ teamId, onBack }: TeamDetailsSectio setSelectedUser(null); setSelectedTeamId(''); fetchTeamDetails(); - } catch (error: any) { + } catch (error: unknown) { console.error('Failed to change team:', error); - const errorMessage = error.response?.data?.message || - error.response?.data?.error || - error.message || - t('workspace.teams.changeTeam.error', 'Failed to change team'); + const errorMessage = isAxiosError(error) + ? (error.response?.data?.message || error.response?.data?.error || error.message) + : (error instanceof Error ? error.message : undefined) || + t('workspace.teams.changeTeam.error', 'Failed to change team'); alert({ alertType: 'error', title: errorMessage }); } finally { setProcessing(false); diff --git a/frontend/src/proprietary/components/shared/config/configSections/TeamsSection.tsx b/frontend/src/proprietary/components/shared/config/configSections/TeamsSection.tsx index b2b9b986a..ecaf05806 100644 --- a/frontend/src/proprietary/components/shared/config/configSections/TeamsSection.tsx +++ b/frontend/src/proprietary/components/shared/config/configSections/TeamsSection.tsx @@ -1,4 +1,5 @@ import { useState, useEffect } from 'react'; +import { isAxiosError } from 'axios'; import { useTranslation } from 'react-i18next'; import { Stack, @@ -83,12 +84,11 @@ export default function TeamsSection() { setNewTeamName(''); setCreateModalOpened(false); await fetchTeams(); - } catch (error: any) { + } catch (error: unknown) { console.error('Failed to create team:', error); - const errorMessage = error.response?.data?.message || - error.response?.data?.error || - error.message || - t('workspace.teams.createTeam.error'); + const errorMessage = isAxiosError(error) + ? (error.response?.data?.message || error.response?.data?.error || error.message) + : (error instanceof Error ? error.message : undefined) || t('workspace.teams.createTeam.error'); alert({ alertType: 'error', title: errorMessage }); } finally { setProcessing(false); @@ -109,12 +109,11 @@ export default function TeamsSection() { setSelectedTeam(null); setRenameModalOpened(false); await fetchTeams(); - } catch (error: any) { + } catch (error: unknown) { console.error('Failed to rename team:', error); - const errorMessage = error.response?.data?.message || - error.response?.data?.error || - error.message || - t('workspace.teams.renameTeam.error'); + const errorMessage = isAxiosError(error) + ? (error.response?.data?.message || error.response?.data?.error || error.message) + : (error instanceof Error ? error.message : undefined) || t('workspace.teams.renameTeam.error'); alert({ alertType: 'error', title: errorMessage }); } finally { setProcessing(false); @@ -135,12 +134,12 @@ export default function TeamsSection() { await teamService.deleteTeam(team.id); alert({ alertType: 'success', title: t('workspace.teams.deleteTeam.success') }); await fetchTeams(); - } catch (error: any) { + } catch (error: unknown) { console.error('Failed to delete team:', error); - const errorMessage = error.response?.data?.message || - error.response?.data?.error || - error.message || - t('workspace.teams.deleteTeam.error'); + const errorMessage = isAxiosError(error) + ? (error.response?.data?.message || error.response?.data?.error || error.message) + : (error instanceof Error ? error.message : undefined) || + t('workspace.teams.deleteTeam.error'); alert({ alertType: 'error', title: errorMessage }); } }; diff --git a/frontend/src/proprietary/components/shared/config/configSections/audit/AuditEventsTable.tsx b/frontend/src/proprietary/components/shared/config/configSections/audit/AuditEventsTable.tsx index ba22d3722..f1e60bd02 100644 --- a/frontend/src/proprietary/components/shared/config/configSections/audit/AuditEventsTable.tsx +++ b/frontend/src/proprietary/components/shared/config/configSections/audit/AuditEventsTable.tsx @@ -15,7 +15,7 @@ import { UnstyledButton, } from '@mantine/core'; import { useTranslation } from 'react-i18next'; -import auditService, { AuditEvent } from '@app/services/auditService'; +import auditService, { AuditEvent, 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'; @@ -122,7 +122,7 @@ const AuditEventsTable: React.FC = ({ }, [filters, currentPage, loginEnabled]); // Wrap filter handlers to reset pagination - const handleFilterChangeWithReset = (key: keyof typeof filters, value: any) => { + const handleFilterChangeWithReset = (key: keyof AuditFilters, value: AuditFilters[keyof AuditFilters]) => { handleFilterChange(key, value); setCurrentPage(1); }; @@ -170,8 +170,8 @@ const AuditEventsTable: React.FC = ({ // Apply sorting to current events const sortedEvents = [...events].sort((a, b) => { - let aVal: any; - let bVal: any; + let aVal: string | number | undefined; + let bVal: string | number | undefined; switch (sortKey) { case 'timestamp': @@ -296,14 +296,14 @@ const AuditEventsTable: React.FC = ({ let author = ''; let fileHash = ''; if (event.details && typeof event.details === 'object') { - const details = event.details as Record; + const details = event.details as Record; const files = details.files; if (Array.isArray(files) && files.length > 0) { - const firstFile = files[0] as Record; - documentName = firstFile.name || ''; + const firstFile = files[0] as Record; + documentName = typeof firstFile.name === 'string' ? firstFile.name : ''; if (showAuthor || showFileHash) { - author = firstFile.pdfAuthor || ''; - fileHash = firstFile.fileHash ? firstFile.fileHash.substring(0, 16) + '...' : ''; + author = typeof firstFile.pdfAuthor === 'string' ? firstFile.pdfAuthor : ''; + fileHash = typeof firstFile.fileHash === 'string' ? firstFile.fileHash.substring(0, 16) + '...' : ''; } } } diff --git a/frontend/src/proprietary/components/shared/config/configSections/audit/AuditExportSection.tsx b/frontend/src/proprietary/components/shared/config/configSections/audit/AuditExportSection.tsx index 53f6c53b5..5852c2f1e 100644 --- a/frontend/src/proprietary/components/shared/config/configSections/audit/AuditExportSection.tsx +++ b/frontend/src/proprietary/components/shared/config/configSections/audit/AuditExportSection.tsx @@ -51,7 +51,7 @@ const AuditExportSection: React.FC = ({ try { setExporting(true); - const fieldsParam = Object.keys(selectedFields).filter(k => selectedFields[k as keyof typeof selectedFields]).join(','); + const fieldsParam = Object.keys(selectedFields).filter(k => selectedFields[k]).join(','); const blob = await auditService.exportData(exportFormat, { ...filters, fields: fieldsParam }); diff --git a/frontend/src/proprietary/components/shared/config/configSections/audit/AuditFiltersForm.tsx b/frontend/src/proprietary/components/shared/config/configSections/audit/AuditFiltersForm.tsx index 13c02081b..f04e36c28 100644 --- a/frontend/src/proprietary/components/shared/config/configSections/audit/AuditFiltersForm.tsx +++ b/frontend/src/proprietary/components/shared/config/configSections/audit/AuditFiltersForm.tsx @@ -43,7 +43,7 @@ interface AuditFiltersFormProps { filters: AuditFilters; eventTypes: string[]; users: string[]; - onFilterChange: (key: keyof AuditFilters, value: any) => void; + onFilterChange: (key: keyof AuditFilters, value: AuditFilters[keyof AuditFilters]) => void; onClearFilters: () => void; disabled?: boolean; } @@ -147,8 +147,8 @@ const AuditFiltersForm: React.FC = ({ { - onFilterChange('startDate', value ? formatDateToYMD(value as Date) : undefined); + onChange={(value) => { + onFilterChange('startDate', value ? formatDateToYMD(new Date(value)) : undefined); }} clearable disabled={disabled} @@ -157,8 +157,8 @@ const AuditFiltersForm: React.FC = ({ { - onFilterChange('endDate', value ? formatDateToYMD(value as Date) : undefined); + onChange={(value) => { + onFilterChange('endDate', value ? formatDateToYMD(new Date(value)) : undefined); }} clearable disabled={disabled} diff --git a/frontend/src/proprietary/components/shared/stripeCheckout/hooks/useLicensePolling.ts b/frontend/src/proprietary/components/shared/stripeCheckout/hooks/useLicensePolling.ts index 0978683f3..d9f23b668 100644 --- a/frontend/src/proprietary/components/shared/stripeCheckout/hooks/useLicensePolling.ts +++ b/frontend/src/proprietary/components/shared/stripeCheckout/hooks/useLicensePolling.ts @@ -14,7 +14,7 @@ export const useLicensePolling = ( const pollForLicenseKey = useCallback(async (installId: string) => { // Use shared polling utility const result = await pollLicenseKeyWithBackoff(installId, { - isMounted: () => isMountedRef.current!, + isMounted: () => isMountedRef.current ?? false, onStatusChange: setPollingStatus, }); @@ -23,7 +23,7 @@ export const useLicensePolling = ( // Activate the license key const activation = await activateLicenseKey(result.licenseKey, { - isMounted: () => isMountedRef.current!, + isMounted: () => isMountedRef.current ?? false, onActivated: onLicenseActivated, }); diff --git a/frontend/src/proprietary/components/workflow/ParticipantView.tsx b/frontend/src/proprietary/components/workflow/ParticipantView.tsx index 6717b8820..9c011d68f 100644 --- a/frontend/src/proprietary/components/workflow/ParticipantView.tsx +++ b/frontend/src/proprietary/components/workflow/ParticipantView.tsx @@ -112,8 +112,8 @@ const ParticipantView: React.FC = ({ token }) => { showLogo: true, }); setNotification({ type: 'success', message: 'Signature submitted successfully!' }); - } catch (err: any) { - setNotification({ type: 'error', message: `Failed to submit signature: ${err.message}` }); + } catch (err: unknown) { + setNotification({ type: 'error', message: `Failed to submit signature: ${err instanceof Error ? err.message : String(err)}` }); } finally { setIsSubmitting(false); } @@ -125,8 +125,8 @@ const ParticipantView: React.FC = ({ token }) => { try { await decline(token, declineReason || 'Declined by participant'); setNotification({ type: 'success', message: 'You have declined this signing request.' }); - } catch (err: any) { - setNotification({ type: 'error', message: `Failed to decline: ${err.message}` }); + } catch (err: unknown) { + setNotification({ type: 'error', message: `Failed to decline: ${err instanceof Error ? err.message : String(err)}` }); } } }; diff --git a/frontend/src/proprietary/contexts/ServerExperienceContext.tsx b/frontend/src/proprietary/contexts/ServerExperienceContext.tsx index edbf90077..fedb27618 100644 --- a/frontend/src/proprietary/contexts/ServerExperienceContext.tsx +++ b/frontend/src/proprietary/contexts/ServerExperienceContext.tsx @@ -8,6 +8,7 @@ import { type ReactNode, } from 'react'; import apiClient from '@app/services/apiClient'; +import { isAxiosError } from 'axios'; import { useAppConfig } from '@app/contexts/AppConfigContext'; import { useAuth } from '@app/auth/UseSession'; import { useLicense } from '@app/contexts/LicenseContext'; @@ -95,13 +96,8 @@ function getErrorMessage(error: unknown): string { if (typeof error === 'string') { return error; } - if ( - typeof error === 'object' && - error !== null && - 'response' in error && - typeof (error as any).response?.data?.message === 'string' - ) { - return (error as any).response.data.message; + if (isAxiosError(error) && typeof error.response?.data?.message === 'string') { + return error.response.data.message; } if (error instanceof Error) { return error.message; @@ -196,7 +192,7 @@ export function ServerExperienceProvider({ children }: { children: ReactNode }) ( await apiClient.get<{ totalUsers?: number }>( '/api/v1/proprietary/ui-data/admin-settings', - { suppressErrorToast: true } as any, + { suppressErrorToast: true }, ) ).data; const totalUsers = @@ -219,7 +215,7 @@ export function ServerExperienceProvider({ children }: { children: ReactNode }) ( await apiClient.get('/api/v1/info/wau', { suppressErrorToast: true, - } as any) + }) ).data; const weeklyActiveUsers = typeof responseData?.weeklyActiveUsers === 'number' diff --git a/frontend/src/proprietary/hooks/workflow/useParticipantSession.ts b/frontend/src/proprietary/hooks/workflow/useParticipantSession.ts index e150fc233..fe47a457b 100644 --- a/frontend/src/proprietary/hooks/workflow/useParticipantSession.ts +++ b/frontend/src/proprietary/hooks/workflow/useParticipantSession.ts @@ -1,4 +1,5 @@ import { useState, useCallback, useEffect } from 'react'; +import { isAxiosError } from 'axios'; import workflowService, { WorkflowSessionResponse, ParticipantResponse, @@ -35,9 +36,10 @@ export const useParticipantSession = (token?: string): UseParticipantSessionResu ]); setSession(sessionData); setParticipant(participantData); - } catch (err: any) { - const errorMsg = - err.response?.data?.message || err.message || 'Failed to load session'; + } catch (err: unknown) { + const errorMsg = isAxiosError(err) + ? (err.response?.data?.message || err.message) + : (err instanceof Error ? err.message : undefined) || 'Failed to load session'; setError(errorMsg); } finally { setLoading(false); @@ -55,9 +57,10 @@ export const useParticipantSession = (token?: string): UseParticipantSessionResu if (request.participantToken) { await loadSession(request.participantToken); } - } catch (err: any) { - const errorMsg = - err.response?.data?.message || err.message || 'Failed to submit signature'; + } catch (err: unknown) { + const errorMsg = isAxiosError(err) + ? (err.response?.data?.message || err.message) + : (err instanceof Error ? err.message : undefined) || 'Failed to submit signature'; setError(errorMsg); throw new Error(errorMsg, { cause: err }); } finally { @@ -79,9 +82,10 @@ export const useParticipantSession = (token?: string): UseParticipantSessionResu setParticipant(updatedParticipant); // Reload session await loadSession(token); - } catch (err: any) { - const errorMsg = - err.response?.data?.message || err.message || 'Failed to decline'; + } catch (err: unknown) { + const errorMsg = isAxiosError(err) + ? (err.response?.data?.message || err.message) + : (err instanceof Error ? err.message : undefined) || 'Failed to decline'; setError(errorMsg); throw new Error(errorMsg, { cause: err }); } finally { @@ -104,9 +108,10 @@ export const useParticipantSession = (token?: string): UseParticipantSessionResu a.click(); window.URL.revokeObjectURL(url); document.body.removeChild(a); - } catch (err: any) { - const errorMsg = - err.response?.data?.message || err.message || 'Failed to download document'; + } catch (err: unknown) { + const errorMsg = isAxiosError(err) + ? (err.response?.data?.message || err.message) + : (err instanceof Error ? err.message : undefined) || 'Failed to download document'; setError(errorMsg); } finally { setLoading(false); diff --git a/frontend/src/proprietary/routes/InviteAccept.tsx b/frontend/src/proprietary/routes/InviteAccept.tsx index c145309ca..9f174617b 100644 --- a/frontend/src/proprietary/routes/InviteAccept.tsx +++ b/frontend/src/proprietary/routes/InviteAccept.tsx @@ -1,4 +1,5 @@ import { useState, useEffect } from 'react'; +import { isAxiosError } from 'axios'; import { useParams, useNavigate } from 'react-router-dom'; import { useTranslation } from 'react-i18next'; import { Stack, Text, Paper, Center, Loader, TextInput, PasswordInput, Anchor } from '@mantine/core'; @@ -56,14 +57,14 @@ export default function InviteAccept() { setLoading(true); const response = await apiClient.get(`/api/v1/invite/validate/${token}`, { suppressErrorToast: true, - } as any); + }); setInviteData(response.data); setError(null); - } catch (err: any) { - const errorMessage = - err.response?.data?.error || - err.message || - t('invite.validationError', 'Failed to validate invitation link'); + } catch (err: unknown) { + const errorMessage = isAxiosError(err) + ? (err.response?.data?.error || err.message) + : (err instanceof Error ? err.message : undefined) || + t('invite.validationError', 'Failed to validate invitation link'); setError(errorMessage); } finally { setLoading(false); @@ -108,15 +109,15 @@ export default function InviteAccept() { await apiClient.post(`/api/v1/invite/accept/${token}`, formData, { suppressErrorToast: true, - } as any); + }); // 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'); + } catch (err: unknown) { + const errorMessage = isAxiosError(err) + ? (err.response?.data?.error || err.message) + : (err instanceof Error ? err.message : undefined) || + t('invite.acceptError', 'Failed to create account'); setError(errorMessage); } finally { setSubmitting(false); diff --git a/frontend/src/proprietary/routes/ShareLinkLoader.tsx b/frontend/src/proprietary/routes/ShareLinkLoader.tsx index 54bfbd812..cb660082e 100644 --- a/frontend/src/proprietary/routes/ShareLinkLoader.tsx +++ b/frontend/src/proprietary/routes/ShareLinkLoader.tsx @@ -1,4 +1,5 @@ import { useEffect, useMemo, useRef } from 'react'; +import { isAxiosError } from 'axios'; import { useNavigate } from 'react-router-dom'; import { useTranslation } from 'react-i18next'; import apiClient from '@app/services/apiClient'; @@ -99,7 +100,7 @@ export default function ShareLinkLoader({ token }: ShareLinkLoaderProps) { const idMap = new Map(); for (let i = 0; i < stirlingFiles.length; i += 1) { - idMap.set(sortedEntries[i].logicalId, stirlingFiles[i].fileId as FileId); + idMap.set(sortedEntries[i].logicalId, stirlingFiles[i].fileId); } const rootIdMap = new Map(); @@ -199,9 +200,9 @@ export default function ShareLinkLoader({ token }: ShareLinkLoaderProps) { navActions.setWorkbench('viewer'); navigate('/', { replace: true }); - } catch (error: any) { + } catch (error: unknown) { if (signal.aborted) return; - const status = error?.response?.status; + const status = isAxiosError(error) ? error.response?.status : undefined; if (status === 401 || status === 403) { if (!isAuthenticated && !authLoading) { alert({ diff --git a/frontend/src/proprietary/routes/ShareLinkPage.tsx b/frontend/src/proprietary/routes/ShareLinkPage.tsx index 04f1060ae..71d13c97c 100644 --- a/frontend/src/proprietary/routes/ShareLinkPage.tsx +++ b/frontend/src/proprietary/routes/ShareLinkPage.tsx @@ -1,4 +1,5 @@ import { useCallback, useEffect, useMemo, useState } from 'react'; +import { isAxiosError } from 'axios'; import { useNavigate, useParams } from 'react-router-dom'; import { Alert, Badge, Button, Group, Loader, Paper, Stack, Text, Title } from '@mantine/core'; import { useTranslation } from 'react-i18next'; @@ -45,8 +46,8 @@ export default function ShareLinkPage() { const data = await fetchShareLinkMetadata(normalizedToken); setMetadata(data); setStatus('ready'); - } catch (error: any) { - const statusCode = error?.response?.status as number | undefined; + } catch (error: unknown) { + const statusCode = isAxiosError(error) ? error.response?.status : undefined; if (statusCode === 401) { setStatus('login'); } else if (statusCode === 403) { @@ -83,8 +84,8 @@ export default function ShareLinkPage() { link.click(); link.remove(); URL.revokeObjectURL(url); - } catch (error: any) { - const statusCode = error?.response?.status as number | undefined; + } catch (error: unknown) { + const statusCode = isAxiosError(error) ? error.response?.status : undefined; if (statusCode === 401) { setStatus('login'); } else if (statusCode === 403) { @@ -118,8 +119,8 @@ export default function ShareLinkPage() { } navActions.setWorkbench('viewer'); navigate('/', { replace: true }); - } catch (error: any) { - const statusCode = error?.response?.status as number | undefined; + } catch (error: unknown) { + const statusCode = isAxiosError(error) ? error.response?.status : undefined; if (statusCode === 401) { setStatus('login'); } else if (statusCode === 403) { diff --git a/frontend/src/proprietary/services/shareLinkImport.ts b/frontend/src/proprietary/services/shareLinkImport.ts index 6212ed72e..b7da1b14e 100644 --- a/frontend/src/proprietary/services/shareLinkImport.ts +++ b/frontend/src/proprietary/services/shareLinkImport.ts @@ -24,7 +24,7 @@ export interface ShareLinkMetadata { export async function fetchShareLinkMetadata(token: string): Promise { const response = await apiClient.get( `/api/v1/storage/share-links/${token}/metadata`, - { suppressErrorToast: true, skipAuthRedirect: true } as any + { suppressErrorToast: true, skipAuthRedirect: true } ); return response.data || {}; } @@ -38,7 +38,7 @@ export async function downloadShareLink(token: string): Promise<{ responseType: 'blob', suppressErrorToast: true, skipAuthRedirect: true, - } as any); + }); const contentType = (response.headers && (response.headers['content-type'] || response.headers['Content-Type'])) || ''; @@ -73,7 +73,7 @@ export async function importShareLinkToWorkbench( const idMap = new Map(); for (let i = 0; i < stirlingFiles.length; i += 1) { - idMap.set(sortedEntries[i].logicalId, stirlingFiles[i].fileId as FileId); + idMap.set(sortedEntries[i].logicalId, stirlingFiles[i].fileId); } const rootIdMap = new Map(); @@ -141,7 +141,7 @@ export async function importShareLinkToWorkbench( autoUnzip: false, skipAutoUnzip: false, }); - const ids = stirlingFiles.map((stirlingFile: StirlingFile) => stirlingFile.fileId as FileId); + const ids = stirlingFiles.map((stirlingFile: StirlingFile) => stirlingFile.fileId); if (ids.length > 0) { const sharedUpdates = { remoteStorageId: shareMetadata?.fileId, diff --git a/frontend/src/proprietary/services/teamService.ts b/frontend/src/proprietary/services/teamService.ts index 36434a293..659fe4c7b 100644 --- a/frontend/src/proprietary/services/teamService.ts +++ b/frontend/src/proprietary/services/teamService.ts @@ -1,4 +1,5 @@ import apiClient from '@app/services/apiClient'; +import type { User } from '@app/services/userManagementService'; export interface Team { id: number; @@ -25,6 +26,13 @@ export interface TeamDetailsResponse { availableUsers: TeamMember[]; } +export interface TeamDetailsUIResponse { + team: Team; + teamUsers: User[]; + availableUsers: User[]; + userLastRequest?: Record; +} + /** * Team Management Service * Provides functions to interact with team-related backend APIs @@ -41,8 +49,8 @@ export const teamService = { /** * Get team details including members */ - async getTeamDetails(teamId: number): Promise { - const response = await apiClient.get(`/api/v1/proprietary/ui-data/teams/${teamId}`); + async getTeamDetails(teamId: number): Promise { + const response = await apiClient.get(`/api/v1/proprietary/ui-data/teams/${teamId}`); return response.data; }, @@ -54,7 +62,7 @@ export const teamService = { formData.append('name', name); await apiClient.post('/api/v1/team/create', formData, { suppressErrorToast: true, - } as any); + }); }, /** @@ -66,7 +74,7 @@ export const teamService = { formData.append('newName', newName); await apiClient.post('/api/v1/team/rename', formData, { suppressErrorToast: true, - } as any); + }); }, /** @@ -77,7 +85,7 @@ export const teamService = { formData.append('teamId', teamId.toString()); await apiClient.post('/api/v1/team/delete', formData, { suppressErrorToast: true, - } as any); + }); }, /** @@ -89,7 +97,7 @@ export const teamService = { formData.append('userId', userId.toString()); await apiClient.post('/api/v1/team/addUser', formData, { suppressErrorToast: true, - } as any); + }); }, /** @@ -102,6 +110,6 @@ export const teamService = { formData.append('teamId', teamId.toString()); await apiClient.post('/api/v1/user/admin/changeRole', formData, { suppressErrorToast: true, - } as any); + }); }, }; diff --git a/frontend/src/proprietary/services/userManagementService.ts b/frontend/src/proprietary/services/userManagementService.ts index 0dafb670d..09ff86983 100644 --- a/frontend/src/proprietary/services/userManagementService.ts +++ b/frontend/src/proprietary/services/userManagementService.ts @@ -30,7 +30,7 @@ export interface AdminSettingsData { disabledUsers: number; currentUsername?: string; roleDetails?: Record; - teams?: any[]; + teams?: unknown[]; maxPaidUsers?: number; // License information maxAllowedUsers: number; @@ -39,7 +39,7 @@ export interface AdminSettingsData { licenseMaxUsers: number; premiumEnabled: boolean; mailEnabled: boolean; - userSettings?: Record; + userSettings?: Record; lockedUsers?: string[]; } @@ -155,7 +155,7 @@ export const userManagementService = { } await apiClient.post('/api/v1/user/admin/saveUser', formData, { suppressErrorToast: true, // Component will handle error display - } as any); + }); }, /** @@ -170,7 +170,7 @@ export const userManagementService = { } await apiClient.post('/api/v1/user/admin/changeRole', formData, { suppressErrorToast: true, - } as any); + }); }, /** @@ -181,7 +181,7 @@ export const userManagementService = { formData.append('enabled', enabled.toString()); await apiClient.post(`/api/v1/user/admin/changeUserEnabled/${username}`, formData, { suppressErrorToast: true, - } as any); + }); }, /** @@ -190,7 +190,7 @@ export const userManagementService = { async deleteUser(username: string): Promise { await apiClient.post(`/api/v1/user/admin/deleteUser/${username}`, null, { suppressErrorToast: true, - } as any); + }); }, /** @@ -211,7 +211,7 @@ export const userManagementService = { formData, { suppressErrorToast: true, // Component will handle error display - } as any + } ); return response.data; @@ -245,7 +245,7 @@ export const userManagementService = { formData, { suppressErrorToast: true, - } as any + } ); return response.data; @@ -265,7 +265,7 @@ export const userManagementService = { async revokeInviteLink(inviteId: number): Promise { await apiClient.delete(`/api/v1/invite/revoke/${inviteId}`, { suppressErrorToast: true, - } as any); + }); }, /** @@ -300,7 +300,7 @@ export const userManagementService = { await apiClient.post('/api/v1/user/admin/changePasswordForUser', formData, { suppressErrorToast: true, // Component will handle error display - } as any); + }); }, /** @@ -309,7 +309,7 @@ export const userManagementService = { async unlockUser(username: string): Promise { await apiClient.post(`/api/v1/user/admin/unlockUser/${username}`, null, { suppressErrorToast: true, - } as any); + }); }, /**