mirror of
https://github.com/Nezumi-2711/9router.git
synced 2026-09-22 20:00:47 +00:00
- Added new model "Claude Opus 4.6" to the provider models.
This commit is contained in:
@@ -5,15 +5,6 @@ import { formatResetTime } from "./utils";
|
||||
|
||||
// Calculate color based on remaining percentage
|
||||
const getColorClasses = (remainingPercentage) => {
|
||||
if (remainingPercentage === 0) {
|
||||
return {
|
||||
text: "text-gray-400",
|
||||
bg: "bg-gray-400",
|
||||
bgLight: "bg-gray-400/10",
|
||||
emoji: "⚫"
|
||||
};
|
||||
}
|
||||
|
||||
if (remainingPercentage > 70) {
|
||||
return {
|
||||
text: "text-green-500",
|
||||
@@ -32,6 +23,7 @@ const getColorClasses = (remainingPercentage) => {
|
||||
};
|
||||
}
|
||||
|
||||
// 0-29% including 0% (out of quota) - show red
|
||||
return {
|
||||
text: "text-red-500",
|
||||
bg: "bg-red-500",
|
||||
|
||||
@@ -40,15 +40,6 @@ function formatResetTimeDisplay(resetTime) {
|
||||
* Get color classes based on remaining percentage
|
||||
*/
|
||||
function getColorClasses(remainingPercentage) {
|
||||
if (remainingPercentage === 0) {
|
||||
return {
|
||||
text: "text-text-muted",
|
||||
bg: "bg-bg-muted",
|
||||
bgLight: "bg-bg-muted/20",
|
||||
emoji: "⚫"
|
||||
};
|
||||
}
|
||||
|
||||
if (remainingPercentage > 70) {
|
||||
return {
|
||||
text: "text-green-600 dark:text-green-400",
|
||||
@@ -67,6 +58,7 @@ function getColorClasses(remainingPercentage) {
|
||||
};
|
||||
}
|
||||
|
||||
// 0-29% including 0% (out of quota) - show red
|
||||
return {
|
||||
text: "text-red-600 dark:text-red-400",
|
||||
bg: "bg-red-500",
|
||||
@@ -85,7 +77,12 @@ export default function QuotaTable({ quotas = [] }) {
|
||||
|
||||
return (
|
||||
<div className="overflow-x-auto">
|
||||
<table className="w-full">
|
||||
<table className="w-full table-fixed">
|
||||
<colgroup>
|
||||
<col className="w-[30%]" /> {/* Model Name */}
|
||||
<col className="w-[45%]" /> {/* Limit Progress */}
|
||||
<col className="w-[25%]" /> {/* Reset Time */}
|
||||
</colgroup>
|
||||
<tbody>
|
||||
{quotas.map((quota, index) => {
|
||||
const remaining = quota.remainingPercentage !== undefined
|
||||
@@ -136,18 +133,22 @@ export default function QuotaTable({ quotas = [] }) {
|
||||
|
||||
{/* Reset Time */}
|
||||
<td className="py-2 px-3">
|
||||
<div className="space-y-0.5">
|
||||
{countdown !== "-" && (
|
||||
<div className="text-sm text-text-primary font-medium">
|
||||
in {countdown}
|
||||
</div>
|
||||
)}
|
||||
{resetDisplay && (
|
||||
<div className="text-xs text-text-muted">
|
||||
{resetDisplay}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
{countdown !== "-" || resetDisplay ? (
|
||||
<div className="space-y-0.5">
|
||||
{countdown !== "-" && (
|
||||
<div className="text-sm text-text-primary font-medium">
|
||||
in {countdown}
|
||||
</div>
|
||||
)}
|
||||
{resetDisplay && (
|
||||
<div className="text-xs text-text-muted">
|
||||
{resetDisplay}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
) : (
|
||||
<div className="text-sm text-text-muted italic">N/A</div>
|
||||
)}
|
||||
</td>
|
||||
</tr>
|
||||
);
|
||||
|
||||
@@ -358,85 +358,68 @@ export default function ProviderLimits() {
|
||||
const isLoading = loading[conn.id];
|
||||
const error = errors[conn.id];
|
||||
|
||||
// Use table layout for Antigravity and Kiro, card layout for others
|
||||
if (conn.provider === "antigravity" || conn.provider === "kiro") {
|
||||
return (
|
||||
<Card key={conn.id} padding="none">
|
||||
<div className="p-6 border-b border-black/10 dark:border-white/10">
|
||||
<div className="flex items-center justify-between">
|
||||
<div className="flex items-center gap-3">
|
||||
<div className="w-10 h-10 rounded-lg flex items-center justify-center overflow-hidden">
|
||||
<Image
|
||||
src={`/providers/${conn.provider}.png`}
|
||||
alt={conn.provider}
|
||||
width={40}
|
||||
height={40}
|
||||
className="object-contain"
|
||||
sizes="40px"
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<h3 className="text-base font-semibold text-text-primary capitalize">
|
||||
{conn.provider}
|
||||
</h3>
|
||||
{conn.name && (
|
||||
<p className="text-sm text-text-muted">{conn.name}</p>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<button
|
||||
onClick={() => refreshProvider(conn.id, conn.provider)}
|
||||
disabled={isLoading}
|
||||
className="p-2 rounded-lg hover:bg-black/5 dark:hover:bg-white/5 transition-colors disabled:opacity-50"
|
||||
title="Refresh quota"
|
||||
>
|
||||
<span className={`material-symbols-outlined text-[20px] text-text-muted ${isLoading ? "animate-spin" : ""}`}>
|
||||
refresh
|
||||
</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="p-6">
|
||||
{isLoading ? (
|
||||
<div className="text-center py-8 text-text-muted">
|
||||
<span className="material-symbols-outlined text-[32px] animate-spin">
|
||||
progress_activity
|
||||
</span>
|
||||
</div>
|
||||
) : error ? (
|
||||
<div className="text-center py-8">
|
||||
<span className="material-symbols-outlined text-[32px] text-red-500">
|
||||
error
|
||||
</span>
|
||||
<p className="mt-2 text-sm text-text-muted">{error}</p>
|
||||
</div>
|
||||
) : quota?.message ? (
|
||||
<div className="text-center py-8">
|
||||
<p className="text-sm text-text-muted">{quota.message}</p>
|
||||
</div>
|
||||
) : (
|
||||
<QuotaTable quotas={quota?.quotas} />
|
||||
)}
|
||||
</div>
|
||||
</Card>
|
||||
);
|
||||
}
|
||||
|
||||
// Use card layout for other providers
|
||||
// Use table layout for all providers
|
||||
return (
|
||||
<ProviderLimitCard
|
||||
key={conn.id}
|
||||
provider={conn.provider}
|
||||
name={conn.name}
|
||||
plan={quota?.plan}
|
||||
quotas={quota?.quotas}
|
||||
message={quota?.message}
|
||||
loading={isLoading}
|
||||
error={error}
|
||||
onRefresh={() => refreshProvider(conn.id, conn.provider)}
|
||||
/>
|
||||
<Card key={conn.id} padding="none">
|
||||
<div className="p-6 border-b border-black/10 dark:border-white/10">
|
||||
<div className="flex items-center justify-between">
|
||||
<div className="flex items-center gap-3">
|
||||
<div className="w-10 h-10 rounded-lg flex items-center justify-center overflow-hidden">
|
||||
<Image
|
||||
src={`/providers/${conn.provider}.png`}
|
||||
alt={conn.provider}
|
||||
width={40}
|
||||
height={40}
|
||||
className="object-contain"
|
||||
sizes="40px"
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<h3 className="text-base font-semibold text-text-primary capitalize">
|
||||
{conn.provider}
|
||||
</h3>
|
||||
{conn.name && (
|
||||
<p className="text-sm text-text-muted">{conn.name}</p>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<button
|
||||
onClick={() => refreshProvider(conn.id, conn.provider)}
|
||||
disabled={isLoading}
|
||||
className="p-2 rounded-lg hover:bg-black/5 dark:hover:bg-white/5 transition-colors disabled:opacity-50"
|
||||
title="Refresh quota"
|
||||
>
|
||||
<span className={`material-symbols-outlined text-[20px] text-text-muted ${isLoading ? "animate-spin" : ""}`}>
|
||||
refresh
|
||||
</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="p-6">
|
||||
{isLoading ? (
|
||||
<div className="text-center py-8 text-text-muted">
|
||||
<span className="material-symbols-outlined text-[32px] animate-spin">
|
||||
progress_activity
|
||||
</span>
|
||||
</div>
|
||||
) : error ? (
|
||||
<div className="text-center py-8">
|
||||
<span className="material-symbols-outlined text-[32px] text-red-500">
|
||||
error
|
||||
</span>
|
||||
<p className="mt-2 text-sm text-text-muted">{error}</p>
|
||||
</div>
|
||||
) : quota?.message ? (
|
||||
<div className="text-center py-8">
|
||||
<p className="text-sm text-text-muted">{quota.message}</p>
|
||||
</div>
|
||||
) : (
|
||||
<QuotaTable quotas={quota?.quotas} />
|
||||
)}
|
||||
</div>
|
||||
</Card>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
|
||||
@@ -42,31 +42,23 @@ export function formatResetTime(date) {
|
||||
/**
|
||||
* Get Tailwind color class based on percentage
|
||||
* @param {number} percentage - Remaining percentage (0-100)
|
||||
* @returns {string} Color name: "green" | "yellow" | "red" | "gray"
|
||||
* @returns {string} Color name: "green" | "yellow" | "red"
|
||||
*/
|
||||
export function getStatusColor(percentage) {
|
||||
if (percentage === 0 || percentage === null || percentage === undefined) {
|
||||
return "gray";
|
||||
}
|
||||
|
||||
if (percentage > 70) return "green";
|
||||
if (percentage >= 30) return "yellow";
|
||||
return "red";
|
||||
return "red"; // 0-29% including 0% (out of quota) - show red
|
||||
}
|
||||
|
||||
/**
|
||||
* Get status emoji based on percentage
|
||||
* @param {number} percentage - Remaining percentage (0-100)
|
||||
* @returns {string} Emoji: "🟢" | "🟡" | "🔴" | "⚫"
|
||||
* @returns {string} Emoji: "🟢" | "🟡" | "🔴"
|
||||
*/
|
||||
export function getStatusEmoji(percentage) {
|
||||
if (percentage === 0 || percentage === null || percentage === undefined) {
|
||||
return "⚫";
|
||||
}
|
||||
|
||||
if (percentage > 70) return "🟢";
|
||||
if (percentage >= 30) return "🟡";
|
||||
return "🔴";
|
||||
return "🔴"; // 0-29% including 0% (out of quota) - show red
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user