From 71a99b078031351fee41bfdee0b0b7b905e1490e Mon Sep 17 00:00:00 2001 From: chengyongru <61816729+chengyongru@users.noreply.github.com> Date: Mon, 10 Aug 2026 15:22:25 +0800 Subject: [PATCH] fix(webui): improve UX recovery and empty states (#5315) --- webui/src/App.tsx | 78 ++++-- .../src/components/settings/SettingsView.tsx | 248 +++++++++++------- .../src/components/thread/ThreadComposer.tsx | 101 ++++--- webui/src/components/thread/ThreadShell.tsx | 5 +- .../components/thread/WorkspaceControls.tsx | 44 +++- webui/src/i18n/locales/en/common.json | 24 +- webui/src/i18n/locales/es/common.json | 24 +- webui/src/i18n/locales/fr/common.json | 24 +- webui/src/i18n/locales/id/common.json | 24 +- webui/src/i18n/locales/ja/common.json | 24 +- webui/src/i18n/locales/ko/common.json | 22 +- webui/src/i18n/locales/pt-BR/common.json | 24 +- webui/src/i18n/locales/vi/common.json | 24 +- webui/src/i18n/locales/zh-CN/common.json | 24 +- webui/src/i18n/locales/zh-TW/common.json | 24 +- webui/src/tests/app-layout.test.tsx | 143 +++++++++- webui/src/tests/settings-view.test.tsx | 75 +++++- webui/src/tests/thread-composer.test.tsx | 54 ++++ 18 files changed, 755 insertions(+), 231 deletions(-) diff --git a/webui/src/App.tsx b/webui/src/App.tsx index 1b50e0ce6..31bd2cf20 100644 --- a/webui/src/App.tsx +++ b/webui/src/App.tsx @@ -8,7 +8,7 @@ import { useState, type ReactNode, } from "react"; -import { Moon, PanelLeft, ShieldCheck, Sun, X } from "lucide-react"; +import { Eye, EyeOff, Moon, PanelLeft, ShieldCheck, Sun, X } from "lucide-react"; import { useTranslation } from "react-i18next"; import { channelUiPresentation } from "@/channel-plugins/registry"; import { Sidebar } from "@/components/Sidebar"; @@ -316,13 +316,23 @@ function AuthForm({ onSecret: (secret: string) => void; }) { const { t } = useTranslation(); + const inputRef = useRef(null); const [value, setValue] = useState(""); + const [passwordVisible, setPasswordVisible] = useState(false); const [submitting, setSubmitting] = useState(false); + const [validationError, setValidationError] = useState<"required" | "invalid" | null>( + failed ? "invalid" : null, + ); + const errorMessage = validationError ? t(`app.auth.${validationError}`) : null; const handleSubmit = (e: React.FormEvent) => { e.preventDefault(); const secret = value.trim(); - if (!secret) return; + if (!secret) { + setValidationError("required"); + inputRef.current?.focus(); + return; + } setSubmitting(true); onSecret(secret); }; @@ -333,27 +343,57 @@ function AuthForm({ onSubmit={handleSubmit} className="flex w-full max-w-sm flex-col gap-4" > -
-

{t("app.auth.title")}

-

{t("app.auth.hint")}

+
+

+ +

+
+ { + setValue(e.target.value); + setValidationError(null); + }} + disabled={submitting} + aria-invalid={validationError ? true : undefined} + aria-describedby={validationError ? "webui-auth-error" : undefined} + className="pr-10 focus-visible:ring-1 focus-visible:ring-ring/30 focus-visible:ring-offset-0" + autoFocus + /> + +
+ {errorMessage ? ( + + ) : null}
- {failed && ( -

- {t("app.auth.invalid")} -

- )} - setValue(e.target.value)} - disabled={submitting} - autoFocus - /> diff --git a/webui/src/components/settings/SettingsView.tsx b/webui/src/components/settings/SettingsView.tsx index ad1ee727e..59789d8ca 100644 --- a/webui/src/components/settings/SettingsView.tsx +++ b/webui/src/components/settings/SettingsView.tsx @@ -2328,6 +2328,7 @@ export function SettingsView({ onAction={handleAutomationAction} onRequestEdit={setAutomationPendingEdit} onRequestDelete={setAutomationPendingDelete} + onBackToChat={onBackToChat} /> ); case "skills": @@ -2448,7 +2449,7 @@ export function SettingsView({ onSave={handleAutomationEdit} /> -
) : null}
- + ); } @@ -2578,9 +2579,9 @@ function SettingsSidebar({ {t("settings.backToChat")}
-

+

{t("settings.sidebar.title")} -

+