- Add new "Quota Tracker" item to the sidebar navigation.
This commit is contained in:
parent
4e92a66379
commit
bfd9614fa2
7 changed files with 127 additions and 68 deletions
|
|
@ -14,6 +14,7 @@ const navItems = [
|
|||
{ href: "/dashboard/providers", label: "Providers", icon: "dns" },
|
||||
{ href: "/dashboard/combos", label: "Combos", icon: "layers" },
|
||||
{ href: "/dashboard/usage", label: "Usage", icon: "bar_chart" },
|
||||
{ href: "/dashboard/quota", label: "Quota Tracker", icon: "data_usage" },
|
||||
{ href: "/dashboard/cli-tools", label: "CLI Tools", icon: "terminal" },
|
||||
];
|
||||
|
||||
|
|
|
|||
|
|
@ -2,7 +2,6 @@
|
|||
|
||||
import { useState, useEffect, useMemo, useCallback } from "react";
|
||||
import { useSearchParams, useRouter } from "next/navigation";
|
||||
import { CardSkeleton } from "./Loading";
|
||||
import Badge from "./Badge";
|
||||
import Card from "./Card";
|
||||
import OverviewCards from "@/app/(dashboard)/dashboard/usage/components/OverviewCards";
|
||||
|
|
@ -348,27 +347,34 @@ export default function UsageStats() {
|
|||
}
|
||||
}, [stats, tableView, sortBy, sortOrder]);
|
||||
|
||||
if (loading) return <CardSkeleton />;
|
||||
if (!stats) return <div className="text-text-muted">Failed to load usage statistics.</div>;
|
||||
if (!stats && !loading) return <div className="text-text-muted">Failed to load usage statistics.</div>;
|
||||
|
||||
const spinner = (
|
||||
<div className="flex items-center justify-center py-12 text-text-muted">
|
||||
<span className="material-symbols-outlined text-[32px] animate-spin">progress_activity</span>
|
||||
</div>
|
||||
);
|
||||
|
||||
return (
|
||||
<div className="flex flex-col gap-6">
|
||||
{/* Overview cards */}
|
||||
<OverviewCards stats={stats} />
|
||||
{loading ? spinner : <OverviewCards stats={stats} />}
|
||||
|
||||
{/* Provider topology + Recent Requests */}
|
||||
<div className="grid grid-cols-1 lg:grid-cols-[2fr_1fr] gap-2 items-stretch">
|
||||
<ProviderTopology
|
||||
providers={providers}
|
||||
activeRequests={stats.activeRequests || []}
|
||||
lastProvider={stats.recentRequests?.[0]?.provider || ""}
|
||||
errorProvider={stats.errorProvider || ""}
|
||||
/>
|
||||
<RecentRequests requests={stats.recentRequests || []} />
|
||||
</div>
|
||||
{loading ? spinner : (
|
||||
<div className="grid grid-cols-1 lg:grid-cols-[2fr_1fr] gap-2 items-stretch">
|
||||
<ProviderTopology
|
||||
providers={providers}
|
||||
activeRequests={stats.activeRequests || []}
|
||||
lastProvider={stats.recentRequests?.[0]?.provider || ""}
|
||||
errorProvider={stats.errorProvider || ""}
|
||||
/>
|
||||
<RecentRequests requests={stats.recentRequests || []} />
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Token / Cost chart */}
|
||||
<UsageChart />
|
||||
{loading ? spinner : <UsageChart />}
|
||||
|
||||
{/* Table with dropdown selector */}
|
||||
<div className="flex flex-col gap-3">
|
||||
|
|
@ -383,7 +389,7 @@ export default function UsageStats() {
|
|||
))}
|
||||
</select>
|
||||
</div>
|
||||
{activeTableConfig && (
|
||||
{loading ? spinner : activeTableConfig && (
|
||||
<UsageTable
|
||||
title=""
|
||||
columns={activeTableConfig.columns}
|
||||
|
|
|
|||
|
|
@ -17,8 +17,8 @@ export const CLI_TOOLS = {
|
|||
modelAliases: ["default", "sonnet", "opus", "haiku", "opusplan"],
|
||||
settingsFile: "~/.claude/settings.json",
|
||||
defaultModels: [
|
||||
{ id: "opus", name: "Claude Opus", alias: "opus", envKey: "ANTHROPIC_DEFAULT_OPUS_MODEL", defaultValue: "cc/claude-opus-4-5-20251101" },
|
||||
{ id: "sonnet", name: "Claude Sonnet", alias: "sonnet", envKey: "ANTHROPIC_DEFAULT_SONNET_MODEL", defaultValue: "cc/claude-sonnet-4-5-20250929" },
|
||||
{ id: "opus", name: "Claude Opus", alias: "opus", envKey: "ANTHROPIC_DEFAULT_OPUS_MODEL", defaultValue: "cc/claude-opus-4-6" },
|
||||
{ id: "sonnet", name: "Claude Sonnet", alias: "sonnet", envKey: "ANTHROPIC_DEFAULT_SONNET_MODEL", defaultValue: "cc/claude-sonnet-4-6" },
|
||||
{ id: "haiku", name: "Claude Haiku", alias: "haiku", envKey: "ANTHROPIC_DEFAULT_HAIKU_MODEL", defaultValue: "cc/claude-haiku-4-5-20251001" },
|
||||
],
|
||||
},
|
||||
|
|
@ -30,6 +30,23 @@ export const CLI_TOOLS = {
|
|||
description: "OpenAI Codex CLI",
|
||||
configType: "custom",
|
||||
},
|
||||
antigravity: {
|
||||
id: "antigravity",
|
||||
name: "Antigravity",
|
||||
image: "/providers/antigravity.png",
|
||||
color: "#4285F4",
|
||||
description: "Google Antigravity IDE with MITM",
|
||||
configType: "mitm",
|
||||
modelAliases: ["claude-opus-4-6-thinking", "claude-sonnet-4-6", "gemini-3-flash", "gpt-oss-120b-medium", "gemini-3-pro-high", "gemini-3-pro-low"],
|
||||
defaultModels: [
|
||||
{ id: "gemini-3.1-pro-high", name: "Gemini 3.1 Pro High", alias: "gemini-3.1-pro-high" },
|
||||
{ id: "gemini-3.1-pro-low", name: "Gemini 3.1 Pro Low", alias: "gemini-3.1-pro-low" },
|
||||
{ id: "gemini-3-flash", name: "Gemini 3 Flash", alias: "gemini-3-flash" },
|
||||
{ id: "claude-sonnet-4-6", name: "Claude Sonnet 4.6", alias: "claude-sonnet-4-6" },
|
||||
{ id: "claude-opus-4-6-thinking", name: "Claude Opus 4.6 Thinking", alias: "claude-opus-4-6-thinking" },
|
||||
{ id: "gpt-oss-120b-medium", name: "GPT OSS 120B Medium", alias: "gpt-oss-120b-medium" },
|
||||
],
|
||||
},
|
||||
droid: {
|
||||
id: "droid",
|
||||
name: "Factory Droid",
|
||||
|
|
@ -72,16 +89,65 @@ export const CLI_TOOLS = {
|
|||
name: "Cline",
|
||||
image: "/providers/cline.png",
|
||||
color: "#00D1B2",
|
||||
description: "CLINE AI Assistant",
|
||||
description: "Cline AI Coding Assistant",
|
||||
configType: "guide",
|
||||
guideSteps: [
|
||||
{ step: 1, title: "Open Settings", desc: "Go to CLINE Settings panel" },
|
||||
{ step: 2, title: "Select Provider", desc: "Choose API Provider → Ollama" },
|
||||
{ step: 3, title: "Base URL", value: "{{baseUrl}}", copyable: true },
|
||||
{ step: 1, title: "Open Settings", desc: "Go to Cline Settings panel" },
|
||||
{ step: 2, title: "Select Provider", desc: "Choose API Provider → OpenAI Compatible" },
|
||||
{ step: 3, title: "Base URL", value: "{{baseUrl}}/v1", copyable: true },
|
||||
{ step: 4, title: "API Key", type: "apiKeySelector" },
|
||||
{ step: 5, title: "Select Model", type: "modelSelector" },
|
||||
],
|
||||
},
|
||||
kilo: {
|
||||
id: "kilo",
|
||||
name: "Kilo Code",
|
||||
image: "/providers/kilocode.png",
|
||||
color: "#FF6B6B",
|
||||
description: "Kilo Code AI Assistant",
|
||||
configType: "guide",
|
||||
guideSteps: [
|
||||
{ step: 1, title: "Open Settings", desc: "Go to Kilo Code Settings panel" },
|
||||
{ step: 2, title: "Select Provider", desc: "Choose API Provider → OpenAI Compatible" },
|
||||
{ step: 3, title: "Base URL", value: "{{baseUrl}}/v1", copyable: true },
|
||||
{ step: 4, title: "API Key", type: "apiKeySelector" },
|
||||
{ step: 5, title: "Select Model", type: "modelSelector" },
|
||||
],
|
||||
},
|
||||
copilot: {
|
||||
id: "copilot",
|
||||
name: "GitHub Copilot",
|
||||
image: "/providers/copilot.png",
|
||||
color: "#1F6FEB",
|
||||
description: "GitHub Copilot Chat — VS Code Extension",
|
||||
configType: "guide",
|
||||
guideSteps: [
|
||||
{ step: 1, title: "Open VS Code Settings", desc: "Open Command Palette → \"Open User Settings (JSON)\"" },
|
||||
{ step: 2, title: "Add config to chatLanguageModels.json", desc: "Add an entry using the Azure vendor pattern:" },
|
||||
{ step: 3, title: "Base URL (endpoint)", value: "{{baseUrl}}/chat/completions#models.ai.azure.com", copyable: true },
|
||||
{ step: 4, title: "API Key", type: "apiKeySelector" },
|
||||
{ step: 5, title: "Select Model", type: "modelSelector" },
|
||||
],
|
||||
codeBlock: {
|
||||
language: "json",
|
||||
code: `{
|
||||
"name": "9Router",
|
||||
"vendor": "azure",
|
||||
"apiKey": "{{apiKey}}",
|
||||
"models": [
|
||||
{
|
||||
"id": "{{model}}",
|
||||
"name": "{{model}}",
|
||||
"url": "{{baseUrl}}/chat/completions#models.ai.azure.com",
|
||||
"toolCalling": true,
|
||||
"vision": false,
|
||||
"maxInputTokens": 128000,
|
||||
"maxOutputTokens": 16000
|
||||
}
|
||||
]
|
||||
}`,
|
||||
},
|
||||
},
|
||||
roo: {
|
||||
id: "roo",
|
||||
name: "Roo",
|
||||
|
|
@ -121,23 +187,6 @@ export const CLI_TOOLS = {
|
|||
}`,
|
||||
},
|
||||
},
|
||||
antigravity: {
|
||||
id: "antigravity",
|
||||
name: "Antigravity",
|
||||
image: "/providers/antigravity.png",
|
||||
color: "#4285F4",
|
||||
description: "Google Antigravity IDE with MITM",
|
||||
configType: "mitm",
|
||||
modelAliases: ["claude-opus-4-6-thinking", "claude-sonnet-4-6", "gemini-3-flash", "gpt-oss-120b-medium", "gemini-3-pro-high", "gemini-3-pro-low"],
|
||||
defaultModels: [
|
||||
{ id: "gemini-3.1-pro-high", name: "Gemini 3.1 Pro High", alias: "gemini-3.1-pro-high" },
|
||||
{ id: "gemini-3.1-pro-low", name: "Gemini 3.1 Pro Low", alias: "gemini-3.1-pro-low" },
|
||||
{ id: "gemini-3-flash", name: "Gemini 3 Flash", alias: "gemini-3-flash" },
|
||||
{ id: "claude-sonnet-4-6", name: "Claude Sonnet 4.6", alias: "claude-sonnet-4-6" },
|
||||
{ id: "claude-opus-4-6-thinking", name: "Claude Opus 4.6 Thinking", alias: "claude-opus-4-6-thinking" },
|
||||
{ id: "gpt-oss-120b-medium", name: "GPT OSS 120B Medium", alias: "gpt-oss-120b-medium" },
|
||||
],
|
||||
},
|
||||
// HIDDEN: gemini-cli
|
||||
// "gemini-cli": {
|
||||
// id: "gemini-cli",
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue