feat: enhance server stats widgets and fix TypeScript/ESLint errors #394
@@ -9,21 +9,7 @@ import {
|
|||||||
AccordionItem,
|
AccordionItem,
|
||||||
AccordionTrigger,
|
AccordionTrigger,
|
||||||
} from "@/components/ui/accordion";
|
} from "@/components/ui/accordion";
|
||||||
import {
|
import { Sheet, SheetContent } from "@/components/ui/sheet";
|
||||||
Sheet,
|
|
||||||
SheetContent,
|
|
||||||
SheetDescription,
|
|
||||||
SheetFooter,
|
|
||||||
SheetHeader,
|
|
||||||
SheetTitle,
|
|
||||||
} from "@/components/ui/sheet";
|
|
||||||
import {
|
|
||||||
Select,
|
|
||||||
SelectContent,
|
|
||||||
SelectItem,
|
|
||||||
SelectTrigger,
|
|
||||||
SelectValue,
|
|
||||||
} from "@/components/ui/select";
|
|
||||||
import {
|
import {
|
||||||
Tooltip,
|
Tooltip,
|
||||||
TooltipContent,
|
TooltipContent,
|
||||||
@@ -37,7 +23,6 @@ import {
|
|||||||
Edit,
|
Edit,
|
||||||
Trash2,
|
Trash2,
|
||||||
Shield,
|
Shield,
|
||||||
Pin,
|
|
||||||
Tag,
|
Tag,
|
||||||
Info,
|
Info,
|
||||||
FolderMinus,
|
FolderMinus,
|
||||||
@@ -75,9 +60,7 @@ export function CredentialsManager({
|
|||||||
const [error, setError] = useState<string | null>(null);
|
const [error, setError] = useState<string | null>(null);
|
||||||
const [searchQuery, setSearchQuery] = useState("");
|
const [searchQuery, setSearchQuery] = useState("");
|
||||||
const [showViewer, setShowViewer] = useState(false);
|
const [showViewer, setShowViewer] = useState(false);
|
||||||
const [viewingCredential, setViewingCredential] = useState<Credential | null>(
|
const [viewingCredential] = useState<Credential | null>(null);
|
||||||
null,
|
|
||||||
);
|
|
||||||
const [draggedCredential, setDraggedCredential] = useState<Credential | null>(
|
const [draggedCredential, setDraggedCredential] = useState<Credential | null>(
|
||||||
null,
|
null,
|
||||||
);
|
);
|
||||||
@@ -153,7 +136,7 @@ export function CredentialsManager({
|
|||||||
const data = await getCredentials();
|
const data = await getCredentials();
|
||||||
setCredentials(data);
|
setCredentials(data);
|
||||||
setError(null);
|
setError(null);
|
||||||
} catch (err) {
|
} catch {
|
||||||
setError(t("credentials.failedToFetchCredentials"));
|
setError(t("credentials.failedToFetchCredentials"));
|
||||||
} finally {
|
} finally {
|
||||||
setLoading(false);
|
setLoading(false);
|
||||||
@@ -256,7 +239,7 @@ export function CredentialsManager({
|
|||||||
);
|
);
|
||||||
await fetchCredentials();
|
await fetchCredentials();
|
||||||
window.dispatchEvent(new CustomEvent("credentials:changed"));
|
window.dispatchEvent(new CustomEvent("credentials:changed"));
|
||||||
} catch (err) {
|
} catch {
|
||||||
toast.error(t("credentials.failedToRemoveFromFolder"));
|
toast.error(t("credentials.failedToRemoveFromFolder"));
|
||||||
} finally {
|
} finally {
|
||||||
setOperationLoading(false);
|
setOperationLoading(false);
|
||||||
@@ -285,7 +268,7 @@ export function CredentialsManager({
|
|||||||
window.dispatchEvent(new CustomEvent("credentials:changed"));
|
window.dispatchEvent(new CustomEvent("credentials:changed"));
|
||||||
setEditingFolder(null);
|
setEditingFolder(null);
|
||||||
setEditingFolderName("");
|
setEditingFolderName("");
|
||||||
} catch (err) {
|
} catch {
|
||||||
toast.error(t("credentials.failedToRenameFolder"));
|
toast.error(t("credentials.failedToRenameFolder"));
|
||||||
} finally {
|
} finally {
|
||||||
setOperationLoading(false);
|
setOperationLoading(false);
|
||||||
@@ -359,7 +342,7 @@ export function CredentialsManager({
|
|||||||
);
|
);
|
||||||
await fetchCredentials();
|
await fetchCredentials();
|
||||||
window.dispatchEvent(new CustomEvent("credentials:changed"));
|
window.dispatchEvent(new CustomEvent("credentials:changed"));
|
||||||
} catch (err) {
|
} catch {
|
||||||
toast.error(t("credentials.failedToMoveToFolder"));
|
toast.error(t("credentials.failedToMoveToFolder"));
|
||||||
} finally {
|
} finally {
|
||||||
setOperationLoading(false);
|
setOperationLoading(false);
|
||||||
|
|||||||
@@ -23,8 +23,6 @@ import {
|
|||||||
Search,
|
Search,
|
||||||
Grid3X3,
|
Grid3X3,
|
||||||
List,
|
List,
|
||||||
Eye,
|
|
||||||
Settings,
|
|
||||||
} from "lucide-react";
|
} from "lucide-react";
|
||||||
import { TerminalWindow } from "./components/TerminalWindow";
|
import { TerminalWindow } from "./components/TerminalWindow";
|
||||||
import type { SSHHost, FileItem } from "../../../types/index.js";
|
import type { SSHHost, FileItem } from "../../../types/index.js";
|
||||||
@@ -87,9 +85,7 @@ function FileManagerContent({ initialHost, onClose }: FileManagerProps) {
|
|||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const { confirmWithToast } = useConfirmation();
|
const { confirmWithToast } = useConfirmation();
|
||||||
|
|
||||||
const [currentHost, setCurrentHost] = useState<SSHHost | null>(
|
const [currentHost] = useState<SSHHost | null>(initialHost || null);
|
||||||
initialHost || null,
|
|
||||||
);
|
|
||||||
const [currentPath, setCurrentPath] = useState(
|
const [currentPath, setCurrentPath] = useState(
|
||||||
initialHost?.defaultPath || "/",
|
initialHost?.defaultPath || "/",
|
||||||
);
|
);
|
||||||
@@ -145,10 +141,9 @@ function FileManagerContent({ initialHost, onClose }: FileManagerProps) {
|
|||||||
const [createIntent, setCreateIntent] = useState<CreateIntent | null>(null);
|
const [createIntent, setCreateIntent] = useState<CreateIntent | null>(null);
|
||||||
const [editingFile, setEditingFile] = useState<FileItem | null>(null);
|
const [editingFile, setEditingFile] = useState<FileItem | null>(null);
|
||||||
|
|
||||||
const { selectedFiles, selectFile, selectAll, clearSelection, setSelection } =
|
const { selectedFiles, clearSelection, setSelection } = useFileSelection();
|
||||||
useFileSelection();
|
|
||||||
|
|
||||||
const { isDragging, dragHandlers } = useDragAndDrop({
|
const { dragHandlers } = useDragAndDrop({
|
||||||
onFilesDropped: handleFilesDropped,
|
onFilesDropped: handleFilesDropped,
|
||||||
onError: (error) => toast.error(error),
|
onError: (error) => toast.error(error),
|
||||||
maxFileSize: 5120,
|
maxFileSize: 5120,
|
||||||
@@ -784,7 +779,7 @@ function FileManagerContent({ initialHost, onClose }: FileManagerProps) {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
async function handleFileOpen(file: FileItem, editMode: boolean = false) {
|
async function handleFileOpen(file: FileItem) {
|
||||||
if (file.type === "directory") {
|
if (file.type === "directory") {
|
||||||
setCurrentPath(file.path);
|
setCurrentPath(file.path);
|
||||||
} else if (file.type === "link") {
|
} else if (file.type === "link") {
|
||||||
@@ -834,14 +829,6 @@ function FileManagerContent({ initialHost, onClose }: FileManagerProps) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleFileEdit(file: FileItem) {
|
|
||||||
handleFileOpen(file, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
function handleFileView(file: FileItem) {
|
|
||||||
handleFileOpen(file, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
function handleContextMenu(event: React.MouseEvent, file?: FileItem) {
|
function handleContextMenu(event: React.MouseEvent, file?: FileItem) {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
|
|
||||||
@@ -1351,18 +1338,16 @@ function FileManagerContent({ initialHost, onClose }: FileManagerProps) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (successCount > 0) {
|
if (successCount > 0) {
|
||||||
const movedFiles = draggedFiles
|
const movedFiles = draggedFiles.slice(0, successCount).map((file) => {
|
||||||
.slice(0, successCount)
|
const targetPath = targetFolder.path.endsWith("/")
|
||||||
.map((file, index) => {
|
? `${targetFolder.path}${file.name}`
|
||||||
const targetPath = targetFolder.path.endsWith("/")
|
: `${targetFolder.path}/${file.name}`;
|
||||||
? `${targetFolder.path}${file.name}`
|
return {
|
||||||
: `${targetFolder.path}/${file.name}`;
|
originalPath: file.path,
|
||||||
return {
|
targetPath: targetPath,
|
||||||
originalPath: file.path,
|
targetName: file.name,
|
||||||
targetPath: targetPath,
|
};
|
||||||
targetName: file.name,
|
});
|
||||||
};
|
|
||||||
});
|
|
||||||
|
|
||||||
const undoAction: UndoAction = {
|
const undoAction: UndoAction = {
|
||||||
type: "cut",
|
type: "cut",
|
||||||
|
|||||||
@@ -80,8 +80,8 @@ export const Terminal = forwardRef<TerminalHandle, SSHTerminalProps>(
|
|||||||
const [visible, setVisible] = useState(false);
|
const [visible, setVisible] = useState(false);
|
||||||
const [isConnected, setIsConnected] = useState(false);
|
const [isConnected, setIsConnected] = useState(false);
|
||||||
const [isConnecting, setIsConnecting] = useState(false);
|
const [isConnecting, setIsConnecting] = useState(false);
|
||||||
const [connectionError, setConnectionError] = useState<string | null>(null);
|
const [, setConnectionError] = useState<string | null>(null);
|
||||||
const [isAuthenticated, setIsAuthenticated] = useState(false);
|
const [, setIsAuthenticated] = useState(false);
|
||||||
const [totpRequired, setTotpRequired] = useState(false);
|
const [totpRequired, setTotpRequired] = useState(false);
|
||||||
const [totpPrompt, setTotpPrompt] = useState<string>("");
|
const [totpPrompt, setTotpPrompt] = useState<string>("");
|
||||||
const isVisibleRef = useRef<boolean>(false);
|
const isVisibleRef = useRef<boolean>(false);
|
||||||
@@ -227,13 +227,6 @@ export const Terminal = forwardRef<TerminalHandle, SSHTerminalProps>(
|
|||||||
[terminal],
|
[terminal],
|
||||||
);
|
);
|
||||||
|
|
||||||
function handleWindowResize() {
|
|
||||||
if (!isVisibleRef.current) return;
|
|
||||||
fitAddonRef.current?.fit();
|
|
||||||
if (terminal) scheduleNotify(terminal.cols, terminal.rows);
|
|
||||||
hardRefresh();
|
|
||||||
}
|
|
||||||
|
|
||||||
function getUseRightClickCopyPaste() {
|
function getUseRightClickCopyPaste() {
|
||||||
return getCookie("rightClickCopyPaste") === "true";
|
return getCookie("rightClickCopyPaste") === "true";
|
||||||
}
|
}
|
||||||
@@ -490,7 +483,7 @@ export const Terminal = forwardRef<TerminalHandle, SSHTerminalProps>(
|
|||||||
setTotpRequired(true);
|
setTotpRequired(true);
|
||||||
setTotpPrompt(msg.prompt || "Verification code:");
|
setTotpPrompt(msg.prompt || "Verification code:");
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch {
|
||||||
toast.error(t("terminal.messageParseError"));
|
toast.error(t("terminal.messageParseError"));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -526,7 +519,7 @@ export const Terminal = forwardRef<TerminalHandle, SSHTerminalProps>(
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
ws.addEventListener("error", (event) => {
|
ws.addEventListener("error", () => {
|
||||||
setIsConnected(false);
|
setIsConnected(false);
|
||||||
isConnectingRef.current = false;
|
isConnectingRef.current = false;
|
||||||
setConnectionError(t("terminal.websocketError"));
|
setConnectionError(t("terminal.websocketError"));
|
||||||
|
|||||||
@@ -12,7 +12,6 @@ import { Unicode11Addon } from "@xterm/addon-unicode11";
|
|||||||
import { WebLinksAddon } from "@xterm/addon-web-links";
|
import { WebLinksAddon } from "@xterm/addon-web-links";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
import { isElectron, getCookie } from "@/ui/main-axios.ts";
|
import { isElectron, getCookie } from "@/ui/main-axios.ts";
|
||||||
import { toast } from "sonner";
|
|
||||||
|
|
||||||
interface HostConfig {
|
interface HostConfig {
|
||||||
id?: number;
|
id?: number;
|
||||||
@@ -52,9 +51,9 @@ export const Terminal = forwardRef<TerminalHandle, SSHTerminalProps>(
|
|||||||
const wasDisconnectedBySSH = useRef(false);
|
const wasDisconnectedBySSH = useRef(false);
|
||||||
const pingIntervalRef = useRef<NodeJS.Timeout | null>(null);
|
const pingIntervalRef = useRef<NodeJS.Timeout | null>(null);
|
||||||
const [visible, setVisible] = useState(false);
|
const [visible, setVisible] = useState(false);
|
||||||
const [isConnected, setIsConnected] = useState(false);
|
const [, setIsConnected] = useState(false);
|
||||||
const [isConnecting, setIsConnecting] = useState(false);
|
const [, setIsConnecting] = useState(false);
|
||||||
const [connectionError, setConnectionError] = useState<string | null>(null);
|
const [, setConnectionError] = useState<string | null>(null);
|
||||||
const [isAuthenticated, setIsAuthenticated] = useState(false);
|
const [isAuthenticated, setIsAuthenticated] = useState(false);
|
||||||
const isVisibleRef = useRef<boolean>(false);
|
const isVisibleRef = useRef<boolean>(false);
|
||||||
const isConnectingRef = useRef(false);
|
const isConnectingRef = useRef(false);
|
||||||
@@ -160,13 +159,6 @@ export const Terminal = forwardRef<TerminalHandle, SSHTerminalProps>(
|
|||||||
[terminal],
|
[terminal],
|
||||||
);
|
);
|
||||||
|
|
||||||
function handleWindowResize() {
|
|
||||||
if (!isVisibleRef.current) return;
|
|
||||||
fitAddonRef.current?.fit();
|
|
||||||
if (terminal) scheduleNotify(terminal.cols, terminal.rows);
|
|
||||||
hardRefresh();
|
|
||||||
}
|
|
||||||
|
|
||||||
function setupWebSocketListeners(
|
function setupWebSocketListeners(
|
||||||
ws: WebSocket,
|
ws: WebSocket,
|
||||||
cols: number,
|
cols: number,
|
||||||
|
|||||||
Reference in New Issue
Block a user