fix: replace explicit any types with proper TypeScript types

- Create explicit interfaces for Request extensions (AuthenticatedRequest, RequestWithHeaders)
- Add type definitions for WebSocket messages and SSH connection data
- Use generic types in DataCrypto methods instead of any return types
- Define proper interfaces for file manager data structures
- Replace catch block any types with unknown and proper type assertions
- Add HostConfig and TabData interfaces for Server component

Fixes 32 @typescript-eslint/no-explicit-any violations across 5 files
This commit is contained in:
ZacharyZcR
2025-10-09 18:23:16 +08:00
parent d7e98cda04
commit aa6473fb48
5 changed files with 295 additions and 165 deletions

View File

@@ -23,6 +23,35 @@ import {
} from "@/ui/main-axios.ts";
import { toast } from "sonner";
interface RecentFileData {
id: number;
name: string;
path: string;
lastOpened?: string;
[key: string]: unknown;
}
interface PinnedFileData {
id: number;
name: string;
path: string;
[key: string]: unknown;
}
interface ShortcutData {
id: number;
name: string;
path: string;
[key: string]: unknown;
}
interface DirectoryItemData {
name: string;
path: string;
type: string;
[key: string]: unknown;
}
export interface SidebarItem {
id: string;
name: string;
@@ -88,31 +117,37 @@ export function FileManagerSidebar({
try {
const recentData = await getRecentFiles(currentHost.id);
const recentItems = recentData.slice(0, 5).map((item: any) => ({
id: `recent-${item.id}`,
name: item.name,
path: item.path,
type: "recent" as const,
lastAccessed: item.lastOpened,
}));
const recentItems = (recentData as RecentFileData[])
.slice(0, 5)
.map((item: RecentFileData) => ({
id: `recent-${item.id}`,
name: item.name,
path: item.path,
type: "recent" as const,
lastAccessed: item.lastOpened,
}));
setRecentItems(recentItems);
const pinnedData = await getPinnedFiles(currentHost.id);
const pinnedItems = pinnedData.map((item: any) => ({
id: `pinned-${item.id}`,
name: item.name,
path: item.path,
type: "pinned" as const,
}));
const pinnedItems = (pinnedData as PinnedFileData[]).map(
(item: PinnedFileData) => ({
id: `pinned-${item.id}`,
name: item.name,
path: item.path,
type: "pinned" as const,
}),
);
setPinnedItems(pinnedItems);
const shortcutData = await getFolderShortcuts(currentHost.id);
const shortcutItems = shortcutData.map((item: any) => ({
id: `shortcut-${item.id}`,
name: item.name,
path: item.path,
type: "shortcut" as const,
}));
const shortcutItems = (shortcutData as ShortcutData[]).map(
(item: ShortcutData) => ({
id: `shortcut-${item.id}`,
name: item.name,
path: item.path,
type: "shortcut" as const,
}),
);
setShortcuts(shortcutItems);
} catch (error) {
console.error("Failed to load quick access data:", error);
@@ -230,12 +265,12 @@ export function FileManagerSidebar({
try {
const response = await listSSHFiles(sshSessionId, "/");
const rootFiles = response.files || [];
const rootFiles = (response.files || []) as DirectoryItemData[];
const rootFolders = rootFiles.filter(
(item: any) => item.type === "directory",
(item: DirectoryItemData) => item.type === "directory",
);
const rootTreeItems = rootFolders.map((folder: any) => ({
const rootTreeItems = rootFolders.map((folder: DirectoryItemData) => ({
id: `folder-${folder.name}`,
name: folder.name,
path: folder.path,
@@ -298,12 +333,12 @@ export function FileManagerSidebar({
try {
const subResponse = await listSSHFiles(sshSessionId, folderPath);
const subFiles = subResponse.files || [];
const subFiles = (subResponse.files || []) as DirectoryItemData[];
const subFolders = subFiles.filter(
(item: any) => item.type === "directory",
(item: DirectoryItemData) => item.type === "directory",
);
const subTreeItems = subFolders.map((folder: any) => ({
const subTreeItems = subFolders.map((folder: DirectoryItemData) => ({
id: `folder-${folder.path.replace(/\//g, "-")}`,
name: folder.name,
path: folder.path,

View File

@@ -27,8 +27,28 @@ import {
SystemWidget,
} from "./widgets";
interface HostConfig {
id: number;
name: string;
ip: string;
username: string;
folder?: string;
enableFileManager?: boolean;
tunnelConnections?: unknown[];
statsConfig?: string | StatsConfig;
[key: string]: unknown;
}
interface TabData {
id: number;
type: string;
title?: string;
hostConfig?: HostConfig;
[key: string]: unknown;
}
interface ServerProps {
hostConfig?: any;
hostConfig?: HostConfig;
title?: string;
isVisible?: boolean;
isTopbarOpen?: boolean;
@@ -44,7 +64,10 @@ export function Server({
}: ServerProps): React.ReactElement {
const { t } = useTranslation();
const { state: sidebarState } = useSidebar();
const { addTab, tabs } = useTabs() as any;
const { addTab, tabs } = useTabs() as {
addTab: (tab: { type: string; [key: string]: unknown }) => number;
tabs: TabData[];
};
const [serverStatus, setServerStatus] = React.useState<"online" | "offline">(
"offline",
);
@@ -163,13 +186,16 @@ export function Server({
if (!cancelled) {
setServerStatus(res?.status === "online" ? "online" : "offline");
}
} catch (error: any) {
} catch (error: unknown) {
if (!cancelled) {
if (error?.response?.status === 503) {
const err = error as {
response?: { status?: number };
};
if (err?.response?.status === 503) {
setServerStatus("offline");
} else if (error?.response?.status === 504) {
} else if (err?.response?.status === 504) {
setServerStatus("offline");
} else if (error?.response?.status === 404) {
} else if (err?.response?.status === 404) {
setServerStatus("offline");
} else {
setServerStatus("offline");
@@ -193,14 +219,18 @@ export function Server({
});
setShowStatsUI(true);
}
} catch (error: any) {
} catch (error: unknown) {
if (!cancelled) {
setMetrics(null);
setShowStatsUI(false);
const err = error as {
code?: string;
response?: { status?: number; data?: { error?: string } };
};
if (
error?.code === "TOTP_REQUIRED" ||
(error?.response?.status === 403 &&
error?.response?.data?.error === "TOTP_REQUIRED")
err?.code === "TOTP_REQUIRED" ||
(err?.response?.status === 403 &&
err?.response?.data?.error === "TOTP_REQUIRED")
) {
toast.error(t("serverStats.totpUnavailable"));
} else {
@@ -236,7 +266,7 @@ export function Server({
const isFileManagerAlreadyOpen = React.useMemo(() => {
if (!currentHostConfig) return false;
return tabs.some(
(tab: any) =>
(tab: TabData) =>
tab.type === "file_manager" &&
tab.hostConfig?.id === currentHostConfig.id,
);
@@ -291,32 +321,37 @@ export function Server({
);
setMetrics(data);
setShowStatsUI(true);
} catch (error: any) {
} catch (error: unknown) {
const err = error as {
code?: string;
status?: number;
response?: { status?: number; data?: { error?: string } };
};
if (
error?.code === "TOTP_REQUIRED" ||
(error?.response?.status === 403 &&
error?.response?.data?.error === "TOTP_REQUIRED")
err?.code === "TOTP_REQUIRED" ||
(err?.response?.status === 403 &&
err?.response?.data?.error === "TOTP_REQUIRED")
) {
toast.error(t("serverStats.totpUnavailable"));
setMetrics(null);
setShowStatsUI(false);
} else if (
error?.response?.status === 503 ||
error?.status === 503
err?.response?.status === 503 ||
err?.status === 503
) {
setServerStatus("offline");
setMetrics(null);
setShowStatsUI(false);
} else if (
error?.response?.status === 504 ||
error?.status === 504
err?.response?.status === 504 ||
err?.status === 504
) {
setServerStatus("offline");
setMetrics(null);
setShowStatsUI(false);
} else if (
error?.response?.status === 404 ||
error?.status === 404
err?.response?.status === 404 ||
err?.status === 404
) {
setServerStatus("offline");
setMetrics(null);