mirror of
https://github.com/farion1231/cc-switch.git
synced 2026-10-26 01:34:51 +08:00
fix(usage): show load errors in the request detail panel
The panel only checked whether data was present, so a failed query fell through to "Request not found". That is how the ambiguous-column error in get_request_detail looked like a missing feature. Show a danger notice with the error message and a retry button when the query fails, and keep "Request not found" for a lookup that returned nothing.
This commit is contained in:
1 parent
5be4451dcd
commit
a39af812e1
6 files changed
+63
-2
No files matched your search
@@ -1,5 +1,7 @@
|
||||
import type { ReactNode } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { Notice } from "@/components/ui/notice";
|
||||
import {
|
||||
Sheet,
|
||||
SheetBody,
|
||||
@@ -15,6 +17,7 @@ import {
|
||||
type RequestLog,
|
||||
} from "@/types/usage";
|
||||
import { cn } from "@/lib/utils";
|
||||
import { extractErrorMessage } from "@/utils/errorUtils";
|
||||
import {
|
||||
SPEED_ESTIMATE_MIN_OUTPUT_TOKENS,
|
||||
SPEED_MIN_OUTPUT_TOKENS,
|
||||
@@ -342,7 +345,12 @@ export function RequestDetailPanel({
|
||||
onClose,
|
||||
}: RequestDetailPanelProps) {
|
||||
const { t } = useTranslation();
|
||||
const { data: request, isLoading } = useRequestDetail(requestId ?? "");
|
||||
const {
|
||||
data: request,
|
||||
isLoading,
|
||||
error,
|
||||
refetch,
|
||||
} = useRequestDetail(requestId ?? "");
|
||||
|
||||
const subtitle = request
|
||||
? [
|
||||
@@ -371,6 +379,23 @@ export function RequestDetailPanel({
|
||||
<div className="h-[320px] animate-pulse rounded-panel bg-subtle" />
|
||||
) : request ? (
|
||||
<RequestDetailBody request={request} />
|
||||
) : error ? (
|
||||
// 查询失败和「没有这条记录」分开说:前者能重试,也要让人看到原因
|
||||
<Notice
|
||||
tone="danger"
|
||||
title={t("usage.requestLoadFailed")}
|
||||
actions={
|
||||
<Button
|
||||
variant="neutral"
|
||||
size="compact"
|
||||
onClick={() => refetch()}
|
||||
>
|
||||
{t("common.retry")}
|
||||
</Button>
|
||||
}
|
||||
>
|
||||
{extractErrorMessage(error) || String(error)}
|
||||
</Notice>
|
||||
) : (
|
||||
<p className="py-10 text-center text-body text-fg-3">
|
||||
{t("usage.requestNotFound")}
|
||||
|
||||
@@ -1980,6 +1980,7 @@
|
||||
"withMultiplier": "with multiplier",
|
||||
"requestDetail": "Request Detail",
|
||||
"requestNotFound": "Request not found",
|
||||
"requestLoadFailed": "Couldn't load request details",
|
||||
"basicInfo": "Basic Info",
|
||||
"tokenUsage": "Token Usage",
|
||||
"cacheCreationCost": "Cache Creation Cost",
|
||||
|
||||
@@ -1980,6 +1980,7 @@
|
||||
"withMultiplier": "倍率込み",
|
||||
"requestDetail": "リクエスト詳細",
|
||||
"requestNotFound": "リクエストが見つかりません",
|
||||
"requestLoadFailed": "リクエスト詳細を読み込めませんでした",
|
||||
"basicInfo": "基本情報",
|
||||
"tokenUsage": "Token 使用量",
|
||||
"cacheCreationCost": "キャッシュ作成コスト",
|
||||
|
||||
@@ -1981,6 +1981,7 @@
|
||||
"withMultiplier": "含倍率",
|
||||
"requestDetail": "請求詳情",
|
||||
"requestNotFound": "請求未找到",
|
||||
"requestLoadFailed": "請求詳情載入失敗",
|
||||
"basicInfo": "基本資訊",
|
||||
"tokenUsage": "Token 使用量",
|
||||
"cacheCreationCost": "快取寫入成本",
|
||||
|
||||
@@ -1980,6 +1980,7 @@
|
||||
"withMultiplier": "含倍率",
|
||||
"requestDetail": "请求详情",
|
||||
"requestNotFound": "请求未找到",
|
||||
"requestLoadFailed": "请求详情加载失败",
|
||||
"basicInfo": "基本信息",
|
||||
"tokenUsage": "Token 使用量",
|
||||
"cacheCreationCost": "缓存写入成本",
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { render, screen } from "@testing-library/react";
|
||||
import { fireEvent, render, screen } from "@testing-library/react";
|
||||
import { describe, expect, it, vi } from "vitest";
|
||||
import { RequestDetailPanel } from "@/components/usage/RequestDetailPanel";
|
||||
import type { RequestLog } from "@/types/usage";
|
||||
@@ -119,4 +119,36 @@ describe("RequestDetailPanel", () => {
|
||||
).toBeInTheDocument();
|
||||
expect(screen.getByText("usage.detail.sourceSession")).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it("shows the error and a retry button when loading fails", () => {
|
||||
const refetch = vi.fn();
|
||||
useRequestDetailMock.mockReturnValue({
|
||||
data: undefined,
|
||||
isLoading: false,
|
||||
error: "ambiguous column name: created_at",
|
||||
refetch,
|
||||
});
|
||||
render(<RequestDetailPanel requestId="req_1" onClose={vi.fn()} />);
|
||||
|
||||
expect(screen.getByText("usage.requestLoadFailed")).toBeInTheDocument();
|
||||
expect(
|
||||
screen.getByText("ambiguous column name: created_at"),
|
||||
).toBeInTheDocument();
|
||||
expect(screen.queryByText("usage.requestNotFound")).toBeNull();
|
||||
|
||||
fireEvent.click(screen.getByRole("button", { name: "common.retry" }));
|
||||
expect(refetch).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
it("says the request is not found only when the query returned nothing", () => {
|
||||
useRequestDetailMock.mockReturnValue({
|
||||
data: null,
|
||||
isLoading: false,
|
||||
error: null,
|
||||
});
|
||||
render(<RequestDetailPanel requestId="req_1" onClose={vi.fn()} />);
|
||||
|
||||
expect(screen.getByText("usage.requestNotFound")).toBeInTheDocument();
|
||||
expect(screen.queryByText("usage.requestLoadFailed")).toBeNull();
|
||||
});
|
||||
});
|
||||
Reference in new issue
Block a user