fix(dashboard): show provider names instead of node ids in Usage by Provider
The Usage by Provider table (and related provider cells) rendered raw provider keys, so requests routed through a custom OpenAI-compatible node appeared as "openai-compatible-chat-096baf9a-6433-4f22-b079-20371092555a" instead of the node's display name. - UsageStats: add getProviderLabel() resolving a provider key (built-in id, alias, or custom node id) to a friendly name via the providers state (nodeName > connection name) and AI_PROVIDERS/getProviderByAlias fallback - Apply the label in group headers, detail rows, badges, and recent requests (raw key kept as hover title) - UsageTable: accept providerLabel prop, use it for provider group headers
This commit is contained in:
@@ -2,7 +2,7 @@
|
||||
|
||||
import { useState, useEffect, useMemo, useCallback, useRef } from "react";
|
||||
import { useSearchParams, useRouter } from "next/navigation";
|
||||
import { FREE_PROVIDERS, AI_PROVIDERS } from "@/shared/constants/providers";
|
||||
import { FREE_PROVIDERS, AI_PROVIDERS, getProviderByAlias } from "@/shared/constants/providers";
|
||||
|
||||
// Keep providers without serviceKinds (default LLM) or with "llm" in serviceKinds
|
||||
function isLLMProvider(id) {
|
||||
@@ -104,7 +104,7 @@ function RecentRequests({ requests = [] }) {
|
||||
className="py-1.5 font-mono truncate max-w-[80px] text-text-muted"
|
||||
title={r.provider}
|
||||
>
|
||||
{r.provider || "—"}
|
||||
{getProviderLabel(r.provider) || "—"}
|
||||
</td>
|
||||
<td className="py-1.5 text-right whitespace-nowrap">
|
||||
<span className="text-primary">
|
||||
@@ -310,6 +310,17 @@ export default function UsageStats({
|
||||
const [tableView, setTableView] = useState("provider");
|
||||
const [viewMode, setViewMode] = useState("costs");
|
||||
const [providers, setProviders] = useState([]);
|
||||
|
||||
// Resolve a provider key (built-in id, alias, or custom node id like
|
||||
// "openai-compatible-chat-096baf9a-...") to a human-friendly name.
|
||||
const getProviderLabel = useCallback((providerId) => {
|
||||
if (!providerId) return "Unknown Provider";
|
||||
const match = providers.find((p) => p.provider === providerId || p.id === providerId);
|
||||
if (match) return match.nodeName || match.name || providerId;
|
||||
// Fallback: known built-in provider (by id, alias, or display prefix)
|
||||
const known = getProviderByAlias(providerId) || AI_PROVIDERS[providerId] || FREE_PROVIDERS[providerId];
|
||||
return known?.name || known?.uiAlias || known?.alias || providerId;
|
||||
}, [providers]);
|
||||
const [periodLocal, setPeriodLocal] = useState("today");
|
||||
const isInitialLoad = useRef(true);
|
||||
const hasLoadedStats = useRef(false);
|
||||
@@ -458,7 +469,7 @@ export default function UsageStats({
|
||||
variant={item.pending > 0 ? "primary" : "neutral"}
|
||||
size="sm"
|
||||
>
|
||||
{item.provider}
|
||||
{getProviderLabel(item.provider)}
|
||||
</Badge>
|
||||
</td>
|
||||
<td className="px-6 py-3 text-right">{fmt(item.requests)}</td>
|
||||
@@ -522,7 +533,7 @@ export default function UsageStats({
|
||||
variant={item.pending > 0 ? "primary" : "neutral"}
|
||||
size="sm"
|
||||
>
|
||||
{item.provider}
|
||||
{getProviderLabel(item.provider)}
|
||||
</Badge>
|
||||
</td>
|
||||
<td className="px-6 py-3 text-right">{fmt(item.requests)}</td>
|
||||
@@ -560,7 +571,7 @@ export default function UsageStats({
|
||||
<td className="px-6 py-3">{item.rawModel}</td>
|
||||
<td className="px-6 py-3">
|
||||
<Badge variant="neutral" size="sm">
|
||||
{item.provider}
|
||||
{getProviderLabel(item.provider)}
|
||||
</Badge>
|
||||
</td>
|
||||
<td className="px-6 py-3 text-right">{fmt(item.requests)}</td>
|
||||
@@ -593,7 +604,7 @@ export default function UsageStats({
|
||||
renderDetailCells: (item) => (
|
||||
<>
|
||||
<td className="px-6 py-3 font-medium">
|
||||
{item.provider || item.key}
|
||||
{getProviderLabel(item.provider || item.key)}
|
||||
</td>
|
||||
<td className="px-6 py-3 text-right">{fmt(item.requests)}</td>
|
||||
<td className="px-6 py-3 text-right text-text-muted whitespace-nowrap">
|
||||
@@ -633,7 +644,7 @@ export default function UsageStats({
|
||||
<td className="px-6 py-3">{item.rawModel}</td>
|
||||
<td className="px-6 py-3">
|
||||
<Badge variant="neutral" size="sm">
|
||||
{item.provider}
|
||||
{getProviderLabel(item.provider)}
|
||||
</Badge>
|
||||
</td>
|
||||
<td className="px-6 py-3 text-right">{fmt(item.requests)}</td>
|
||||
@@ -645,7 +656,7 @@ export default function UsageStats({
|
||||
};
|
||||
}
|
||||
}
|
||||
}, [stats, tableView, sortBy, sortOrder]);
|
||||
}, [stats, tableView, sortBy, sortOrder, getProviderLabel]);
|
||||
|
||||
if (!stats && !loading)
|
||||
return (
|
||||
@@ -752,6 +763,7 @@ export default function UsageStats({
|
||||
renderSummaryCells={activeTableConfig.renderSummaryCells}
|
||||
renderDetailCells={activeTableConfig.renderDetailCells}
|
||||
emptyMessage={activeTableConfig.emptyMessage}
|
||||
providerLabel={getProviderLabel}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user