mirror of
https://github.com/diegosouzapw/OmniRoute.git
synced 2026-08-20 06:02:14 +03:00
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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 "stacked". Configure
|
||||
em{" "}
|
||||
Enabled layers run when compression is in "stacked" 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>
|
||||
|
||||
7
src/shared/components/logTableStyles.ts
Normal file
7
src/shared/components/logTableStyles.ts
Normal 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;
|
||||
@@ -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",
|
||||
|
||||
Reference in New Issue
Block a user