大量UI显示和i18n优化 (#3973)

Integrated into release/v3.8.27
This commit is contained in:
Randi
2026-06-16 08:57:21 -04:00
committed by GitHub
parent 09278297ae
commit bba97cfc60
36 changed files with 588 additions and 722 deletions

View File

@@ -16,6 +16,14 @@ import {
truncateUrl,
} from "@/shared/utils/formatting";
import { getProviderDisplayLabel } from "@/shared/utils/providerDisplayLabel";
import {
LOG_TABLE_CLASS,
LOG_TABLE_HEAD_CLASS,
LOG_TABLE_HEADER_BG_STYLE,
LOG_TABLE_HEADER_CELL_CLASS,
LOG_TABLE_HEADER_CELL_RIGHT_CLASS,
LOG_TABLE_ROW_CLASS,
} from "./logTableStyles";
const PROXY_COLUMN_KEYS = [
"status",
@@ -396,64 +404,38 @@ export default function ProxyLogger() {
) : sortedLogs.length === 0 ? (
<div className="p-8 text-center text-text-muted">{t("noMatchingLogs")}</div>
) : (
<table className="w-full text-left border-collapse text-xs">
<thead
className="sticky top-0 z-10"
style={{ backgroundColor: "var(--bg-primary, #0f1117)" }}
>
<tr
className="border-b border-border"
style={{ backgroundColor: "var(--bg-primary, #0f1117)" }}
>
<table className={LOG_TABLE_CLASS}>
<thead className={LOG_TABLE_HEAD_CLASS} style={LOG_TABLE_HEADER_BG_STYLE}>
<tr className={LOG_TABLE_ROW_CLASS} style={LOG_TABLE_HEADER_BG_STYLE}>
{visibleColumns.status && (
<th className="px-3 py-2.5 font-semibold text-text-muted uppercase tracking-wider text-[10px]">
{t("colStatus")}
</th>
<th className={LOG_TABLE_HEADER_CELL_CLASS}>{t("colStatus")}</th>
)}
{visibleColumns.proxy && (
<th className="px-3 py-2.5 font-semibold text-text-muted uppercase tracking-wider text-[10px]">
{t("colProxy")}
</th>
<th className={LOG_TABLE_HEADER_CELL_CLASS}>{t("colProxy")}</th>
)}
{visibleColumns.tls && (
<th className="px-3 py-2.5 font-semibold text-text-muted uppercase tracking-wider text-[10px]">
{t("colTls")}
</th>
<th className={LOG_TABLE_HEADER_CELL_CLASS}>{t("colTls")}</th>
)}
{visibleColumns.type && (
<th className="px-3 py-2.5 font-semibold text-text-muted uppercase tracking-wider text-[10px]">
{t("colType")}
</th>
<th className={LOG_TABLE_HEADER_CELL_CLASS}>{t("colType")}</th>
)}
{visibleColumns.level && (
<th className="px-3 py-2.5 font-semibold text-text-muted uppercase tracking-wider text-[10px]">
{t("colLevel")}
</th>
<th className={LOG_TABLE_HEADER_CELL_CLASS}>{t("colLevel")}</th>
)}
{visibleColumns.provider && (
<th className="px-3 py-2.5 font-semibold text-text-muted uppercase tracking-wider text-[10px]">
{t("colProvider")}
</th>
<th className={LOG_TABLE_HEADER_CELL_CLASS}>{t("colProvider")}</th>
)}
{visibleColumns.target && (
<th className="px-3 py-2.5 font-semibold text-text-muted uppercase tracking-wider text-[10px]">
{t("colTarget")}
</th>
<th className={LOG_TABLE_HEADER_CELL_CLASS}>{t("colTarget")}</th>
)}
{visibleColumns.latency && (
<th className="px-3 py-2.5 font-semibold text-text-muted uppercase tracking-wider text-[10px] text-right">
{t("colLatency")}
</th>
<th className={LOG_TABLE_HEADER_CELL_RIGHT_CLASS}>{t("colLatency")}</th>
)}
{visibleColumns.ip && (
<th className="px-3 py-2.5 font-semibold text-text-muted uppercase tracking-wider text-[10px]">
{t("colClientIp")}
</th>
<th className={LOG_TABLE_HEADER_CELL_CLASS}>{t("colClientIp")}</th>
)}
{visibleColumns.time && (
<th className="px-3 py-2.5 font-semibold text-text-muted uppercase tracking-wider text-[10px] text-right">
{t("colTime")}
</th>
<th className={LOG_TABLE_HEADER_CELL_RIGHT_CLASS}>{t("colTime")}</th>
)}
</tr>
</thead>

View File

@@ -39,6 +39,14 @@ import {
readSavedRefreshIntervalSec,
writeSavedRefreshIntervalSec,
} from "./requestLoggerPreferences";
import {
LOG_TABLE_CLASS,
LOG_TABLE_HEAD_CLASS,
LOG_TABLE_HEADER_BG_STYLE,
LOG_TABLE_HEADER_CELL_CLASS,
LOG_TABLE_HEADER_CELL_RIGHT_CLASS,
LOG_TABLE_ROW_CLASS,
} from "./logTableStyles";
// Number of call-log rows fetched per page. The viewer grows its window by this
// amount on "Load more" / infinite scroll so users can browse past the first
@@ -935,79 +943,47 @@ const RequestLoggerV2 = forwardRef<RequestLoggerV2Handle, { initialSelectedId?:
) : sortedLogs.length === 0 ? (
<div className="p-8 text-center text-text-muted">{t("noMatchingLogs")}</div>
) : (
<table className="w-full text-left border-collapse text-xs">
<thead
className="sticky top-0 z-10"
style={{ backgroundColor: "var(--color-bg, #fff)" }}
>
<tr
className="border-b border-border"
style={{ backgroundColor: "var(--color-bg, #fff)" }}
>
<table className={LOG_TABLE_CLASS}>
<thead className={LOG_TABLE_HEAD_CLASS} style={LOG_TABLE_HEADER_BG_STYLE}>
<tr className={LOG_TABLE_ROW_CLASS} style={LOG_TABLE_HEADER_BG_STYLE}>
{visibleColumns.status && (
<th className="px-3 py-2.5 font-semibold text-text-muted uppercase tracking-wider text-[10px]">
{t("columns.status")}
</th>
<th className={LOG_TABLE_HEADER_CELL_CLASS}>{t("columns.status")}</th>
)}
{visibleColumns.cacheSource && (
<th className="px-3 py-2.5 font-semibold text-text-muted uppercase tracking-wider text-[10px]">
{t("columns.cacheSource")}
</th>
<th className={LOG_TABLE_HEADER_CELL_CLASS}>{t("columns.cacheSource")}</th>
)}
{visibleColumns.model && (
<th className="px-3 py-2.5 font-semibold text-text-muted uppercase tracking-wider text-[10px]">
{t("columns.model")}
</th>
<th className={LOG_TABLE_HEADER_CELL_CLASS}>{t("columns.model")}</th>
)}
{visibleColumns.requestedModel && (
<th className="px-3 py-2.5 font-semibold text-text-muted uppercase tracking-wider text-[10px]">
{t("columns.requested")}
</th>
<th className={LOG_TABLE_HEADER_CELL_CLASS}>{t("columns.requested")}</th>
)}
{visibleColumns.provider && (
<th className="px-3 py-2.5 font-semibold text-text-muted uppercase tracking-wider text-[10px]">
{t("columns.provider")}
</th>
<th className={LOG_TABLE_HEADER_CELL_CLASS}>{t("columns.provider")}</th>
)}
{visibleColumns.protocol && (
<th className="px-3 py-2.5 font-semibold text-text-muted uppercase tracking-wider text-[10px]">
{t("columns.protocol")}
</th>
<th className={LOG_TABLE_HEADER_CELL_CLASS}>{t("columns.protocol")}</th>
)}
{visibleColumns.account && (
<th className="px-3 py-2.5 font-semibold text-text-muted uppercase tracking-wider text-[10px]">
{t("columns.account")}
</th>
<th className={LOG_TABLE_HEADER_CELL_CLASS}>{t("columns.account")}</th>
)}
{visibleColumns.apiKey && (
<th className="px-3 py-2.5 font-semibold text-text-muted uppercase tracking-wider text-[10px]">
{t("columns.apiKey")}
</th>
<th className={LOG_TABLE_HEADER_CELL_CLASS}>{t("columns.apiKey")}</th>
)}
{visibleColumns.combo && (
<th className="px-3 py-2.5 font-semibold text-text-muted uppercase tracking-wider text-[10px]">
{t("columns.combo")}
</th>
<th className={LOG_TABLE_HEADER_CELL_CLASS}>{t("columns.combo")}</th>
)}
{visibleColumns.tokens && (
<th className="px-3 py-2.5 font-semibold text-text-muted uppercase tracking-wider text-[10px] text-right">
{t("columns.tokens")}
</th>
<th className={LOG_TABLE_HEADER_CELL_RIGHT_CLASS}>{t("columns.tokens")}</th>
)}
{visibleColumns.tps && (
<th className="px-3 py-2.5 font-semibold text-text-muted uppercase tracking-wider text-[10px] text-right">
{t("columns.tps")}
</th>
<th className={LOG_TABLE_HEADER_CELL_RIGHT_CLASS}>{t("columns.tps")}</th>
)}
{visibleColumns.duration && (
<th className="px-3 py-2.5 font-semibold text-text-muted uppercase tracking-wider text-[10px] text-right">
{t("columns.duration")}
</th>
<th className={LOG_TABLE_HEADER_CELL_RIGHT_CLASS}>{t("columns.duration")}</th>
)}
{visibleColumns.time && (
<th className="px-3 py-2.5 font-semibold text-text-muted uppercase tracking-wider text-[10px] text-right">
{t("columns.time")}
</th>
<th className={LOG_TABLE_HEADER_CELL_RIGHT_CLASS}>{t("columns.time")}</th>
)}
</tr>
</thead>

View File

@@ -242,9 +242,11 @@ export function EngineConfigPage({ engineId }: { engineId: string }) {
<div className="flex flex-col gap-2 rounded-lg border border-border bg-surface p-4">
<div className="flex items-center justify-between">
<div className="flex flex-col gap-0.5">
<span className="text-sm font-medium text-text">Ativar camada</span>
<span className="text-sm font-medium text-text">Enable layer</span>
<span className="text-xs text-text-muted">
{enabled ? "Esta camada está ativa no pipeline padrão." : "Esta camada está inativa."}
{enabled
? "This layer is active in the default pipeline."
: "This layer is inactive."}
</span>
</div>
<input
@@ -253,13 +255,12 @@ export function EngineConfigPage({ engineId }: { engineId: string }) {
checked={enabled}
onChange={handleToggle}
className="h-4 w-4 accent-primary cursor-pointer"
aria-label="Ativar camada"
aria-label="Enable layer"
/>
</div>
{toggleError && <p className="text-xs text-destructive">{toggleError}</p>}
<p className="text-xs text-text-muted" data-testid="stacked-mode-notice">
As camadas ativadas rodam quando a compressão está no modo &quot;stacked&quot;. Configure
em{" "}
Enabled layers run when compression is in &quot;stacked&quot; mode. Configure it in{" "}
<a href="/dashboard/context/settings" className="underline hover:text-text">
Compression Settings
</a>
@@ -269,7 +270,7 @@ export function EngineConfigPage({ engineId }: { engineId: string }) {
{/* ── Config form ── */}
<div className="flex flex-col gap-3 rounded-lg border border-border bg-surface p-4">
<h2 className="text-sm font-semibold text-text">Configuração</h2>
<h2 className="text-sm font-semibold text-text">Configuration</h2>
<EngineConfigForm
schema={engine.configSchema}
value={configState}
@@ -281,7 +282,7 @@ export function EngineConfigPage({ engineId }: { engineId: string }) {
disabled={saving}
className="px-4 py-1.5 rounded bg-primary text-primary-foreground text-sm font-medium disabled:opacity-50"
>
{saving ? "Salvando…" : "Salvar"}
{saving ? "Saving..." : "Save"}
</button>
{saveError && <p className="text-xs text-destructive">{saveError}</p>}
</div>
@@ -302,20 +303,20 @@ export function EngineConfigPage({ engineId }: { engineId: string }) {
disabled={previewLoading}
className="px-4 py-1.5 rounded bg-primary text-primary-foreground text-sm font-medium disabled:opacity-50"
>
{previewLoading ? "Processando…" : "Preview"}
{previewLoading ? "Processing..." : "Preview"}
</button>
</div>
{previewError && <p className="text-xs text-destructive">{previewError}</p>}
{preview && (
<div className="flex gap-4 text-sm pt-1">
<span className="text-text-muted">
Tokens originais: <strong className="text-text">{preview.originalTokens}</strong>
Original tokens: <strong className="text-text">{preview.originalTokens}</strong>
</span>
<span className="text-text-muted">
Tokens comprimidos: <strong className="text-text">{preview.compressedTokens}</strong>
Compressed tokens: <strong className="text-text">{preview.compressedTokens}</strong>
</span>
<span className="text-text-muted">
Economia: <strong className="text-primary">{preview.savingsPct.toFixed(1)}%</strong>
Savings: <strong className="text-primary">{preview.savingsPct.toFixed(1)}%</strong>
</span>
</div>
)}
@@ -323,17 +324,20 @@ export function EngineConfigPage({ engineId }: { engineId: string }) {
{/* ── Analytics strip ── */}
<div className="flex flex-col gap-3 rounded-lg border border-border bg-surface p-4">
<h2 className="text-sm font-semibold text-text">Últimos 7 dias</h2>
<h2 className="text-sm font-semibold text-text">Last 7 days</h2>
{analytics && analytics.runs === 0 ? (
<p className="text-sm text-text-muted">Sem dados ainda / No data yet</p>
<p className="text-sm text-text-muted">No data yet</p>
) : analytics ? (
<div className="grid grid-cols-3 gap-3">
<StatCard label="Execuções" value={analytics.runs.toLocaleString()} />
<StatCard label="Tokens economizados" value={analytics.tokensSaved.toLocaleString()} />
<StatCard label="Economia média" value={`${analytics.avgSavingsPercent.toFixed(1)}%`} />
<StatCard label="Runs" value={analytics.runs.toLocaleString()} />
<StatCard label="Tokens saved" value={analytics.tokensSaved.toLocaleString()} />
<StatCard
label="Average savings"
value={`${analytics.avgSavingsPercent.toFixed(1)}%`}
/>
</div>
) : (
<p className="text-sm text-text-muted">Sem dados ainda / No data yet</p>
<p className="text-sm text-text-muted">No data yet</p>
)}
</div>
</div>

View File

@@ -0,0 +1,7 @@
export const LOG_TABLE_CLASS = "w-full text-left border-collapse text-xs";
export const LOG_TABLE_HEAD_CLASS = "sticky top-0 z-10";
export const LOG_TABLE_ROW_CLASS = "border-b border-border";
export const LOG_TABLE_HEADER_CELL_CLASS =
"px-3 py-2.5 font-semibold text-text-muted uppercase tracking-wider text-[10px]";
export const LOG_TABLE_HEADER_CELL_RIGHT_CLASS = `${LOG_TABLE_HEADER_CELL_CLASS} text-right`;
export const LOG_TABLE_HEADER_BG_STYLE = { backgroundColor: "var(--color-bg, #fff)" } as const;

View File

@@ -85,7 +85,6 @@ export const HIDEABLE_SIDEBAR_ITEM_IDS = [
"batch",
"batch-files",
// Configuration
"settings",
"settings-general",
"settings-appearance",
"settings-ai",
@@ -755,13 +754,6 @@ const BATCH_GROUP: SidebarItemGroup = {
};
const CONFIGURATION_ITEMS: readonly SidebarItemDefinition[] = [
{
id: "settings",
href: "/dashboard/settings",
i18nKey: "settings",
subtitleKey: "settingsSubtitle",
icon: "settings",
},
{
id: "settings-general",
href: "/dashboard/settings/general",
@@ -955,7 +947,7 @@ const MINIMAL_SHOWN: ReadonlySet<HideableSidebarItemId> = new Set([
"costs",
"logs",
"health",
"settings",
"settings-general",
"settings-sidebar",
"docs",
"changelog",
@@ -988,7 +980,7 @@ const DEVELOPER_SHOWN: ReadonlySet<HideableSidebarItemId> = new Set([
"skills",
"mcp",
"a2a",
"settings",
"settings-general",
"settings-routing",
"settings-resilience",
"settings-sidebar",
@@ -1019,7 +1011,6 @@ const ADMIN_SHOWN: ReadonlySet<HideableSidebarItemId> = new Set([
"audit",
"audit-mcp",
"audit-a2a",
"settings",
"settings-general",
"settings-routing",
"settings-resilience",