Fix any type usage in proprietary/ (#5949)

# Description of Changes
Follow on from #5934, expanding `any` type usage ban to the
`proprietary/` folder
This commit is contained in:
James Brunton
2026-04-01 08:21:26 +00:00
committed by GitHub
parent a96b95e198
commit c31e4253dd
34 changed files with 341 additions and 266 deletions
+4 -1
View File
@@ -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,
@@ -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();
@@ -85,7 +85,7 @@ export interface User {
is_anonymous?: boolean;
isFirstLogin?: boolean;
authenticationType?: string;
app_metadata?: Record<string, any>;
app_metadata?: Record<string, unknown>;
}
export interface Session {
@@ -447,7 +447,7 @@ class SpringAuthClient {
*/
async signInWithOAuth(params: {
provider: OAuthProvider;
options?: { redirectTo?: string; queryParams?: Record<string, any> };
options?: { redirectTo?: string; queryParams?: Record<string, string> };
}): Promise<{ error: AuthError | null }> {
try {
const redirectPath = normalizeRedirectPath(params.options?.redirectTo);
@@ -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);
@@ -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 (
@@ -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);
@@ -34,12 +34,12 @@ export const ManageBillingButton: React.FC<ManageBillingButtonProps> = ({
// 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);
}
@@ -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
@@ -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<AdvancedSettingsData>({
sectionName: 'advanced',
fetchTransformer: async (): Promise<AdvancedSettingsData & { _pending?: Record<string, any> }> => {
fetchTransformer: async (): Promise<AdvancedSettingsData & { _pending?: Record<string, unknown> }> => {
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<string, any> } = {
const result: AdvancedSettingsData & { _pending?: Record<string, unknown> } = {
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<string, any> = {};
const pendingBlock: Record<string, unknown> = {};
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<string, any> = {
const deltaSettings: Record<string, unknown> = {
'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.'
@@ -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 {
@@ -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<string, OAuth2ClientSettings>;
};
saml2?: Saml2Settings;
mail?: MailSettings;
telegram?: TelegramSettingsData;
ssoAutoLogin?: boolean;
enableMobileScanner?: boolean;
@@ -93,7 +141,7 @@ export default function AdminConnectionsSection() {
const adminSettings = useAdminSettings<ConnectionsSettingsData>({
sectionName: 'connections',
fetchTransformer: async (): Promise<ConnectionsSettingsData & { _pending?: Record<string, any> }> => {
fetchTransformer: async (): Promise<ConnectionsSettingsData & { _pending?: Record<string, unknown> }> => {
// 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<string, any> } = {
const result: ConnectionsSettingsData & { _pending?: Record<string, unknown> } = {
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<string, any> = {};
const pendingBlock: Record<string, unknown> = {};
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<string, any> = {};
const deltaSettings: Record<string, unknown> = {};
// 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<string, any>)[key];
deltaSettings[`security.oauth2.${key}`] = (currentSettings.oauth2 as Record<string, unknown>)[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<string, unknown>;
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<string, any>)[key];
const saml2 = currentSettings.saml2 as Record<string, unknown>;
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<string, any>)[key];
const mail = currentSettings.mail as Record<string, unknown>;
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<string, any>)[key];
const telegram = currentSettings.telegram as Record<string, unknown>;
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<string, any> => {
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<string, any>) => {
const updateProviderSettings = (provider: Provider, updatedSettings: Record<string, unknown>) => {
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,
}
}
});
@@ -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<DatabaseSettingsData>({
sectionName: "database",
fetchTransformer: async (): Promise<DatabaseSettingsData & { _pending?: Record<string, any> }> => {
fetchTransformer: async (): Promise<DatabaseSettingsData & { _pending?: Record<string, unknown> }> => {
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<string, any> } = { ...datasource };
const result: DatabaseSettingsData & { _pending?: Record<string, unknown> } = { ...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<string, any> = {
const deltaSettings: Record<string, unknown> = {
"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"),
@@ -38,11 +38,11 @@ export default function AdminFeaturesSection() {
isFieldPending,
} = useAdminSettings<FeaturesSettingsData>({
sectionName: 'features',
fetchTransformer: async (): Promise<FeaturesSettingsData & { _pending?: Record<string, any> }> => {
fetchTransformer: async (): Promise<FeaturesSettingsData & { _pending?: Record<string, unknown> }> => {
const systemResponse = await apiClient.get('/api/v1/admin/settings/section/system');
const systemData = systemResponse.data || {};
const result: FeaturesSettingsData & { _pending?: Record<string, any> } = {
const result: FeaturesSettingsData & { _pending?: Record<string, unknown> } = {
serverCertificate: systemData.serverCertificate || {
enabled: true,
organizationName: 'Stirling-PDF',
@@ -59,7 +59,7 @@ export default function AdminFeaturesSection() {
return result;
},
saveTransformer: (settings: FeaturesSettingsData) => {
const deltaSettings: Record<string, any> = {};
const deltaSettings: Record<string, unknown> = {};
if (settings.serverCertificate) {
deltaSettings['system.serverCertificate.enabled'] = settings.serverCertificate.enabled;
@@ -91,7 +91,7 @@ export default function AdminGeneralSection() {
isFieldPending,
} = useAdminSettings<GeneralSettingsData>({
sectionName: 'general',
fetchTransformer: async (): Promise<GeneralSettingsData & { _pending?: Record<string, any> }> => {
fetchTransformer: async (): Promise<GeneralSettingsData & { _pending?: Record<string, unknown> }> => {
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<string, any> } = {
const result: GeneralSettingsData & { _pending?: Record<string, unknown> } = {
ui,
system,
customPaths: {
@@ -140,7 +140,7 @@ export default function AdminGeneralSection() {
};
// Merge pending blocks from all three endpoints
const pendingBlock: Record<string, any> = {};
const pendingBlock: Record<string, unknown> = {};
if (ui._pending) {
pendingBlock.ui = ui._pending;
}
@@ -161,7 +161,7 @@ export default function AdminGeneralSection() {
return result;
},
saveTransformer: (settings: GeneralSettingsData) => {
const deltaSettings: Record<string, any> = {
const deltaSettings: Record<string, unknown> = {
// UI settings
'ui.appNameNavbar': settings.ui?.appNameNavbar,
'ui.languages': settings.ui?.languages,
@@ -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]);
@@ -33,7 +33,7 @@ export default function AdminPrivacySection() {
isFieldPending,
} = useAdminSettings<PrivacySettingsData>({
sectionName: 'privacy',
fetchTransformer: async (): Promise<PrivacySettingsData & { _pending?: Record<string, any> }> => {
fetchTransformer: async (): Promise<PrivacySettingsData & { _pending?: Record<string, unknown> }> => {
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<string, any> } = {
const result: PrivacySettingsData & { _pending?: Record<string, unknown> } = {
enableAnalytics: system.enableAnalytics || false,
googleVisibility: system.googlevisibility || false,
metricsEnabled: metrics.enabled || false
};
// Merge pending blocks from both endpoints
const pendingBlock: Record<string, any> = {};
const pendingBlock: Record<string, unknown> = {};
if (system._pending?.enableAnalytics !== undefined) {
pendingBlock.enableAnalytics = system._pending.enableAnalytics;
}
@@ -67,7 +67,7 @@ export default function AdminSecuritySection() {
isFieldPending,
} = useAdminSettings<SecuritySettingsData>({
sectionName: 'security',
fetchTransformer: async (): Promise<SecuritySettingsData & { _pending?: Record<string, any> }> => {
fetchTransformer: async (): Promise<SecuritySettingsData & { _pending?: Record<string, unknown> }> => {
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<string, any> } = {
const combined: SecuritySettingsData & { _pending?: Record<string, unknown> } = {
...securityActive
};
@@ -108,7 +108,7 @@ export default function AdminSecuritySection() {
}
// Merge all _pending blocks
const mergedPending: Record<string, any> = {};
const mergedPending: Record<string, unknown> = {};
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<string, any> = {
const deltaSettings: Record<string, unknown> = {
// Security settings
'security.enableLogin': securitySettings.enableLogin,
'security.loginMethod': securitySettings.loginMethod,
@@ -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
@@ -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<string, unknown> | 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 } }) => (
<Group gap="sm" wrap="nowrap">
<LocalIcon icon={option.icon} width="1.25rem" height="1.25rem" style={{ flexShrink: 0 }} />
<LocalIcon icon={option.icon ?? ''} width="1.25rem" height="1.25rem" style={{ flexShrink: 0 }} />
<Box style={{ flex: 1 }}>
<Text size="sm" fw={500}>{option.label}</Text>
<Text size="xs" c="dimmed" style={{ whiteSpace: 'normal', lineHeight: 1.4 }}>
@@ -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 });
}
}}
@@ -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);
@@ -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 });
}
};
@@ -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<AuditEventsTableProps> = ({
}, [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<AuditEventsTableProps> = ({
// 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<AuditEventsTableProps> = ({
let author = '';
let fileHash = '';
if (event.details && typeof event.details === 'object') {
const details = event.details as Record<string, any>;
const details = event.details as Record<string, unknown>;
const files = details.files;
if (Array.isArray(files) && files.length > 0) {
const firstFile = files[0] as Record<string, any>;
documentName = firstFile.name || '';
const firstFile = files[0] as Record<string, unknown>;
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) + '...' : '';
}
}
}
@@ -51,7 +51,7 @@ const AuditExportSection: React.FC<AuditExportSectionProps> = ({
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 });
@@ -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<AuditFiltersFormProps> = ({
<DateInput
placeholder={t('audit.events.startDate', 'Start date')}
value={filters.startDate ? new Date(filters.startDate) : null}
onChange={(value: any) => {
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<AuditFiltersFormProps> = ({
<DateInput
placeholder={t('audit.events.endDate', 'End date')}
value={filters.endDate ? new Date(filters.endDate) : null}
onChange={(value: any) => {
onFilterChange('endDate', value ? formatDateToYMD(value as Date) : undefined);
onChange={(value) => {
onFilterChange('endDate', value ? formatDateToYMD(new Date(value)) : undefined);
}}
clearable
disabled={disabled}
@@ -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,
});
@@ -112,8 +112,8 @@ const ParticipantView: React.FC<ParticipantViewProps> = ({ 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<ParticipantViewProps> = ({ 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)}` });
}
}
};
@@ -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<WeeklyActiveUsersResponse>('/api/v1/info/wau', {
suppressErrorToast: true,
} as any)
})
).data;
const weeklyActiveUsers =
typeof responseData?.weeklyActiveUsers === 'number'
@@ -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);
@@ -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<InviteData>(`/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);
@@ -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<string, FileId>();
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<string, FileId>();
@@ -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({
@@ -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) {
@@ -24,7 +24,7 @@ export interface ShareLinkMetadata {
export async function fetchShareLinkMetadata(token: string): Promise<ShareLinkMetadata> {
const response = await apiClient.get<ShareLinkMetadata>(
`/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<string, FileId>();
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<string, FileId>();
@@ -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,
@@ -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<string, number>;
}
/**
* 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<any> {
const response = await apiClient.get(`/api/v1/proprietary/ui-data/teams/${teamId}`);
async getTeamDetails(teamId: number): Promise<TeamDetailsUIResponse> {
const response = await apiClient.get<TeamDetailsUIResponse>(`/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);
});
},
};
@@ -30,7 +30,7 @@ export interface AdminSettingsData {
disabledUsers: number;
currentUsername?: string;
roleDetails?: Record<string, string>;
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<string, any>;
userSettings?: Record<string, unknown>;
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<void> {
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<void> {
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<void> {
await apiClient.post(`/api/v1/user/admin/unlockUser/${username}`, null, {
suppressErrorToast: true,
} as any);
});
},
/**