mirror of
https://github.com/Termix-SSH/Termix.git
synced 2026-08-29 10:21:34 +00:00
fix: stop connection screens crashing outside the connection log provider
This commit is contained in:
@@ -1,5 +1,5 @@
|
|||||||
import React, { useEffect, useRef, useState } from "react";
|
import React, { useEffect, useRef, useState } from "react";
|
||||||
import { useConnectionLog } from "@/ssh/connection-log/ConnectionLogContext.tsx";
|
import { useOptionalConnectionLog } from "@/ssh/connection-log/ConnectionLogContext.tsx";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
import { copyToClipboard } from "@/lib/clipboard.ts";
|
import { copyToClipboard } from "@/lib/clipboard.ts";
|
||||||
import { Button } from "@/components/button.tsx";
|
import { Button } from "@/components/button.tsx";
|
||||||
@@ -34,20 +34,21 @@ export function ConnectionLogPanel({
|
|||||||
className,
|
className,
|
||||||
}: ConnectionLogPanelProps) {
|
}: ConnectionLogPanelProps) {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
|
const connectionLog = useOptionalConnectionLog();
|
||||||
const { logs, clearLogs, isExpanded, toggleExpanded, setIsExpanded } =
|
const { logs, clearLogs, isExpanded, toggleExpanded, setIsExpanded } =
|
||||||
useConnectionLog();
|
connectionLog ?? {};
|
||||||
const lastLogRef = useRef<HTMLDivElement>(null);
|
const lastLogRef = useRef<HTMLDivElement>(null);
|
||||||
const [manuallyCollapsed, setManuallyCollapsed] = useState(false);
|
const [manuallyCollapsed, setManuallyCollapsed] = useState(false);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (hasConnectionError) {
|
if (hasConnectionError && setIsExpanded) {
|
||||||
setManuallyCollapsed(false);
|
setManuallyCollapsed(false);
|
||||||
setIsExpanded(true);
|
setIsExpanded(true);
|
||||||
}
|
}
|
||||||
}, [hasConnectionError, setIsExpanded]);
|
}, [hasConnectionError, setIsExpanded]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (isConnected && !hasConnectionError && !isConnecting) {
|
if (isConnected && !hasConnectionError && !isConnecting && clearLogs) {
|
||||||
clearLogs();
|
clearLogs();
|
||||||
setManuallyCollapsed(false);
|
setManuallyCollapsed(false);
|
||||||
}
|
}
|
||||||
@@ -60,7 +61,9 @@ export function ConnectionLogPanel({
|
|||||||
}, [logs]);
|
}, [logs]);
|
||||||
|
|
||||||
const shouldShow =
|
const shouldShow =
|
||||||
!isConnected && (isConnecting || hasConnectionError || logs.length > 0);
|
!!connectionLog &&
|
||||||
|
!isConnected &&
|
||||||
|
(isConnecting || hasConnectionError || logs.length > 0);
|
||||||
|
|
||||||
if (!shouldShow) {
|
if (!shouldShow) {
|
||||||
return null;
|
return null;
|
||||||
|
|||||||
@@ -88,3 +88,9 @@ export function useConnectionLog() {
|
|||||||
}
|
}
|
||||||
return context;
|
return context;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Loading and error screens render outside any provider, so they get undefined
|
||||||
|
// instead of a crash.
|
||||||
|
export function useOptionalConnectionLog() {
|
||||||
|
return useContext(ConnectionLogContext);
|
||||||
|
}
|
||||||
|
|||||||
@@ -0,0 +1,46 @@
|
|||||||
|
import { describe, it, expect, vi, afterEach } from "vitest";
|
||||||
|
import { render, screen, cleanup } from "@testing-library/react";
|
||||||
|
|
||||||
|
vi.mock("react-i18next", () => ({
|
||||||
|
useTranslation: () => ({ t: (key: string) => key }),
|
||||||
|
}));
|
||||||
|
|
||||||
|
import { ConnectionScreen } from "../../../components/connection/ConnectionScreen";
|
||||||
|
import { ConnectionLogProvider } from "../../../ssh/connection-log/ConnectionLogContext";
|
||||||
|
|
||||||
|
afterEach(cleanup);
|
||||||
|
|
||||||
|
describe("ConnectionScreen", () => {
|
||||||
|
// Loading and host-not-found screens render before the provider is mounted,
|
||||||
|
// which used to throw and take down the whole RDP/VNC/Telnet tab.
|
||||||
|
it("renders without a ConnectionLogProvider", () => {
|
||||||
|
expect(() =>
|
||||||
|
render(<ConnectionScreen status="connecting" message="common.loading" />),
|
||||||
|
).not.toThrow();
|
||||||
|
|
||||||
|
expect(screen.getByText("common.loading")).toBeTruthy();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("renders the disconnected state without a provider", () => {
|
||||||
|
expect(() =>
|
||||||
|
render(
|
||||||
|
<ConnectionScreen
|
||||||
|
status="disconnected"
|
||||||
|
message="guacamole.hostNotFound"
|
||||||
|
/>,
|
||||||
|
),
|
||||||
|
).not.toThrow();
|
||||||
|
|
||||||
|
expect(screen.getByText("guacamole.hostNotFound")).toBeTruthy();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("still shows the connection log when a provider is present", () => {
|
||||||
|
render(
|
||||||
|
<ConnectionLogProvider>
|
||||||
|
<ConnectionScreen status="connecting" message="common.loading" />
|
||||||
|
</ConnectionLogProvider>,
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(screen.getByText(/terminal\.connectionLogTitle/)).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
||||||
Reference in New Issue
Block a user