feat: add first-run confirmation dialog for stream check

Show an informational dialog when users first click the health check
button, explaining its limitations (OAuth providers, relay services,
Bedrock). The dialog persists the confirmation in settings so it only
appears once per device.
This commit is contained in:
Jason
2026-03-03 21:49:57 +08:00
parent 377c736aad
commit 07568286fc
6 changed files with 67 additions and 2 deletions
+4
View File
@@ -196,6 +196,9 @@ pub struct AppSettings {
/// User has confirmed the usage query first-run notice
#[serde(default, skip_serializing_if = "Option::is_none")]
pub usage_confirmed: Option<bool>,
/// User has confirmed the stream check first-run notice
#[serde(default, skip_serializing_if = "Option::is_none")]
pub stream_check_confirmed: Option<bool>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub language: Option<String>,
@@ -282,6 +285,7 @@ impl Default for AppSettings {
enable_local_proxy: false,
proxy_confirmed: None,
usage_confirmed: None,
stream_check_confirmed: None,
language: None,
visible_apps: None,
claude_config_dir: None,
+46 -2
View File
@@ -41,6 +41,8 @@ import {
import { useCallback } from "react";
import { Input } from "@/components/ui/input";
import { Button } from "@/components/ui/button";
import { ConfirmDialog } from "@/components/ConfirmDialog";
import { settingsApi } from "@/lib/api/settings";
interface ProviderListProps {
providers: Record<string, Provider>;
@@ -176,14 +178,43 @@ export function ProviderList({
const [searchTerm, setSearchTerm] = useState("");
const [isSearchOpen, setIsSearchOpen] = useState(false);
const searchInputRef = useRef<HTMLInputElement>(null);
const [showStreamCheckConfirm, setShowStreamCheckConfirm] = useState(false);
const [pendingTestProvider, setPendingTestProvider] = useState<Provider | null>(null);
// Query settings for streamCheckConfirmed flag
const { data: settings } = useQuery({
queryKey: ["settings"],
queryFn: () => settingsApi.get(),
});
const handleTest = useCallback(
(provider: Provider) => {
checkProvider(provider.id, provider.name);
if (!settings?.streamCheckConfirmed) {
setPendingTestProvider(provider);
setShowStreamCheckConfirm(true);
} else {
checkProvider(provider.id, provider.name);
}
},
[checkProvider],
[checkProvider, settings?.streamCheckConfirmed],
);
const handleStreamCheckConfirm = async () => {
setShowStreamCheckConfirm(false);
try {
if (settings) {
await settingsApi.save({ ...settings, streamCheckConfirmed: true });
await queryClient.invalidateQueries({ queryKey: ["settings"] });
}
} catch (error) {
console.error("Failed to save stream check confirmed:", error);
}
if (pendingTestProvider) {
checkProvider(pendingTestProvider.id, pendingTestProvider.name);
setPendingTestProvider(null);
}
};
// Import current live config as default provider
const queryClient = useQueryClient();
const importMutation = useMutation({
@@ -417,6 +448,19 @@ export function ProviderList({
) : (
renderProviderList()
)}
<ConfirmDialog
isOpen={showStreamCheckConfirm}
variant="info"
title={t("confirm.streamCheck.title")}
message={t("confirm.streamCheck.message")}
confirmText={t("confirm.streamCheck.confirm")}
onConfirm={() => void handleStreamCheckConfirm()}
onCancel={() => {
setShowStreamCheckConfirm(false);
setPendingTestProvider(null);
}}
/>
</div>
);
}
+5
View File
@@ -191,6 +191,11 @@
"title": "Configure Usage Query",
"message": "Usage query requires a custom script or API parameters. Please make sure you have obtained the necessary information from your provider.\n\nIf unsure how to configure, please consult your provider's documentation first.",
"confirm": "I understand, configure"
},
"streamCheck": {
"title": "Model Health Check",
"message": "Health check tests provider connectivity by sending a direct API request. The following may cause check failures:\n\n• Official providers (uses OAuth login, no standalone API Key)\n• Some relay services (verify requests come from Claude Code CLI)\n• AWS Bedrock (uses IAM signature authentication)\n\nA failed check does not mean the provider is unusable — it only means it cannot be verified via a standalone request. Please refer to actual behavior within the application.",
"confirm": "I understand, proceed"
}
},
"settings": {
+5
View File
@@ -191,6 +191,11 @@
"title": "使用量クエリの設定",
"message": "使用量クエリにはカスタムスクリプトまたは API パラメータが必要です。プロバイダーから必要な情報を取得していることをご確認ください。\n\n設定方法が不明な場合は、プロバイダーのドキュメントを先にご確認ください。",
"confirm": "理解しました、設定する"
},
"streamCheck": {
"title": "モデルヘルスチェック",
"message": "ヘルスチェックは API リクエストを直接送信してプロバイダーの接続性をテストします。以下の場合、チェックが失敗する可能性があります:\n\n• 公式プロバイダー(OAuth ログイン使用、独立した API キーなし)\n• 一部の中継サービス(リクエストが Claude Code CLI からのものか検証)\n• AWS BedrockIAM 署名認証を使用)\n\nチェック失敗はプロバイダーが使用不能であることを意味しません。独立したリクエストでの検証ができないことを示すだけです。アプリ内の実際の動作を基準にしてください。",
"confirm": "理解しました、続行する"
}
},
"settings": {
+5
View File
@@ -191,6 +191,11 @@
"title": "配置用量查询",
"message": "用量查询需要配置专用的查询脚本或 API 参数,请确保您已从供应商处获取相关信息。\n\n如不确定如何配置,请先查阅供应商文档。",
"confirm": "我已了解,继续配置"
},
"streamCheck": {
"title": "模型健康检测",
"message": "健康检测通过直接发送 API 请求来测试供应商连通性,以下情况可能导致检测失败:\n\n• 官方供应商(使用 OAuth 登录,无独立 API Key)\n• 部分中转服务(会校验请求是否来自 Claude Code CLI\n• AWS Bedrock(使用 IAM 签名认证)\n\n检测失败不代表供应商不可用,仅表示无法通过独立请求验证。请以应用内的实际情况为准。",
"confirm": "我已了解,继续检测"
}
},
"settings": {
+2
View File
@@ -219,6 +219,8 @@ export interface Settings {
proxyConfirmed?: boolean;
// User has confirmed the usage query first-run notice
usageConfirmed?: boolean;
// User has confirmed the stream check first-run notice
streamCheckConfirmed?: boolean;
// 首选语言(可选,默认中文)
language?: "en" | "zh" | "ja";