Compare commits

...

2 Commits

4 changed files with 92 additions and 1 deletions
@@ -0,0 +1,38 @@
import { render, screen } from "@testing-library/react";
import { describe, it, expect, vi } from "vitest";
import { ConnectionStatusModal } from "../connection-status-modal";
vi.mock("../base-modal/base-modal", () => ({
BaseModal: ({
children,
isOpen,
}: {
children: React.ReactNode;
isOpen: boolean;
}) => (isOpen ? <div>{children}</div> : null),
}));
vi.mock("react-i18next", () => ({
useTranslation: () => ({
t: (key: string) =>
key === "MODAL$UNSTABLE_CONNECTION"
? "Connection is unstable, attempting to reconnect..."
: key,
}),
}));
describe("ConnectionStatusModal", () => {
it("should show modal when connection is unstable", () => {
render(<ConnectionStatusModal isOpen />);
expect(
screen.getByText("Connection is unstable, attempting to reconnect..."),
).toBeInTheDocument();
});
it("should not show modal when connection is stable", () => {
render(<ConnectionStatusModal isOpen={false} />);
expect(
screen.queryByText("Connection is unstable, attempting to reconnect..."),
).not.toBeInTheDocument();
});
});
@@ -0,0 +1,28 @@
import { useTranslation } from "react-i18next";
import { BaseModal } from "./base-modal/base-modal";
import { LoadingSpinner } from "../loading-spinner";
import { I18nKey } from "#/i18n/declaration";
interface ConnectionStatusModalProps {
isOpen: boolean;
}
export function ConnectionStatusModal({ isOpen }: ConnectionStatusModalProps) {
const { t } = useTranslation();
return (
<BaseModal
isOpen={isOpen}
onClose={() => {}}
showCloseButton={false}
className="max-w-md"
>
<div className="flex flex-col items-center justify-center p-6 space-y-4">
<LoadingSpinner className="w-8 h-8" />
<p className="text-lg font-medium text-gray-700">
{t(I18nKey.MODAL$UNSTABLE_CONNECTION)}
</p>
</div>
</BaseModal>
);
}
+11 -1
View File
@@ -12,6 +12,7 @@ import {
AssistantMessageAction,
UserMessageAction,
} from "#/types/core/actions";
import { ConnectionStatusModal } from "#/components/shared/modals/connection-status-modal";
const isOpenHandsEvent = (event: unknown): event is OpenHandsParsedEvent =>
typeof event === "object" &&
@@ -218,7 +219,16 @@ export function WsClientProvider({
[status, messageRateHandler.isUnderThreshold, events],
);
return <WsClientContext value={value}>{children}</WsClientContext>;
return (
<>
<WsClientContext.Provider value={value}>
{children}
</WsClientContext.Provider>
<ConnectionStatusModal
isOpen={status === WsClientProviderStatus.DISCONNECTED}
/>
</>
);
}
export function useWsClient() {
+15
View File
@@ -1,4 +1,19 @@
{
"MODAL$UNSTABLE_CONNECTION": {
"en": "Connection is unstable, attempting to reconnect...",
"ja": "接続が不安定です。再接続を試みています...",
"zh-CN": "连接不稳定,正在尝试重新连接...",
"zh-TW": "連線不穩定,正在嘗試重新連線...",
"ko-KR": "연결이 불안정합니다. 재연결을 시도하는 중...",
"no": "Tilkoblingen er ustabil, prøver å koble til på nytt...",
"it": "La connessione è instabile, tentativo di riconnessione in corso...",
"pt": "A conexão está instável, tentando reconectar...",
"es": "La conexión es inestable, intentando reconectar...",
"ar": "الاتصال غير مستقر، جاري محاولة إعادة الاتصال...",
"fr": "La connexion est instable, tentative de reconnexion...",
"tr": "Bağlantı kararsız, yeniden bağlanmaya çalışılıyor...",
"de": "Verbindung ist instabil, versuche neu zu verbinden..."
},
"APP$TITLE": {
"en": "App",
"ja": "アプリ",