mirror of
https://github.com/decolua/9router.git
synced 2026-05-08 12:01:28 +00:00
Add provider filter and expiry sorting to quota dashboard (#769)
Co-authored-by: Delynn Assistant <zhen@dkzhen.org>
This commit is contained in:
@@ -27,6 +27,8 @@ export default function ProviderLimits() {
|
||||
const [showEditModal, setShowEditModal] = useState(false);
|
||||
const [selectedConnection, setSelectedConnection] = useState(null);
|
||||
const [proxyPools, setProxyPools] = useState([]);
|
||||
const [providerFilter, setProviderFilter] = useState("all");
|
||||
const [expiringFirst, setExpiringFirst] = useState(false);
|
||||
|
||||
const intervalRef = useRef(null);
|
||||
const countdownRef = useRef(null);
|
||||
@@ -362,14 +364,32 @@ export default function ProviderLimits() {
|
||||
conn.authType === "oauth",
|
||||
);
|
||||
|
||||
// Sort providers by USAGE_SUPPORTED_PROVIDERS order, then alphabetically
|
||||
const sortedConnections = [...filteredConnections].sort((a, b) => {
|
||||
const providerFilteredConnections = filteredConnections.filter(
|
||||
(conn) => providerFilter === "all" || conn.provider === providerFilter,
|
||||
);
|
||||
|
||||
const getEarliestResetTime = (conn) => {
|
||||
const resetTimes = (quotaData[conn.id]?.quotas || [])
|
||||
.map((quota) => quota.resetAt ? new Date(quota.resetAt).getTime() : Number.POSITIVE_INFINITY)
|
||||
.filter((time) => Number.isFinite(time));
|
||||
return resetTimes.length > 0 ? Math.min(...resetTimes) : Number.POSITIVE_INFINITY;
|
||||
};
|
||||
|
||||
// Sort providers by USAGE_SUPPORTED_PROVIDERS order, then alphabetically.
|
||||
// Optionally surface accounts with quotas expiring soonest first.
|
||||
const sortedConnections = [...providerFilteredConnections].sort((a, b) => {
|
||||
if (expiringFirst) {
|
||||
const expiryDiff = getEarliestResetTime(a) - getEarliestResetTime(b);
|
||||
if (expiryDiff !== 0) return expiryDiff;
|
||||
}
|
||||
const orderA = USAGE_SUPPORTED_PROVIDERS.indexOf(a.provider);
|
||||
const orderB = USAGE_SUPPORTED_PROVIDERS.indexOf(b.provider);
|
||||
if (orderA !== orderB) return orderA - orderB;
|
||||
return a.provider.localeCompare(b.provider);
|
||||
});
|
||||
|
||||
const providerOptions = Array.from(new Set(filteredConnections.map((conn) => conn.provider))).sort();
|
||||
|
||||
// Calculate summary stats
|
||||
const totalProviders = sortedConnections.length;
|
||||
const activeWithLimits = Object.values(quotaData).filter(
|
||||
@@ -422,6 +442,26 @@ export default function ProviderLimits() {
|
||||
</div>
|
||||
|
||||
<div className="flex items-center gap-2">
|
||||
<select
|
||||
value={providerFilter}
|
||||
onChange={(event) => setProviderFilter(event.target.value)}
|
||||
className="h-10 rounded-lg border border-black/10 bg-transparent px-3 text-sm text-text-primary dark:border-white/10"
|
||||
aria-label="Filter quota providers"
|
||||
>
|
||||
<option value="all">All providers</option>
|
||||
{providerOptions.map((provider) => (
|
||||
<option key={provider} value={provider}>{provider}</option>
|
||||
))}
|
||||
</select>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => setExpiringFirst((prev) => !prev)}
|
||||
className={`flex items-center gap-2 rounded-lg border px-3 py-2 text-sm transition-colors ${expiringFirst ? "border-amber-500/40 bg-amber-500/10 text-amber-500" : "border-black/10 text-text-primary hover:bg-black/5 dark:border-white/10 dark:hover:bg-white/5"}`}
|
||||
title="Sort accounts by earliest quota reset time"
|
||||
>
|
||||
<span className="material-symbols-outlined text-[18px]">hourglass_top</span>
|
||||
Expiring first
|
||||
</button>
|
||||
{/* Auto-refresh toggle */}
|
||||
<button
|
||||
onClick={() => setAutoRefresh((prev) => !prev)}
|
||||
|
||||
Reference in New Issue
Block a user