Add provider filter and expiry sorting to quota dashboard (#769)
Co-authored-by: Delynn Assistant <zhen@dkzhen.org>
This commit is contained in:
parent
54a67dbeb8
commit
296e21c8ad
1 changed files with 42 additions and 2 deletions
|
|
@ -27,6 +27,8 @@ export default function ProviderLimits() {
|
||||||
const [showEditModal, setShowEditModal] = useState(false);
|
const [showEditModal, setShowEditModal] = useState(false);
|
||||||
const [selectedConnection, setSelectedConnection] = useState(null);
|
const [selectedConnection, setSelectedConnection] = useState(null);
|
||||||
const [proxyPools, setProxyPools] = useState([]);
|
const [proxyPools, setProxyPools] = useState([]);
|
||||||
|
const [providerFilter, setProviderFilter] = useState("all");
|
||||||
|
const [expiringFirst, setExpiringFirst] = useState(false);
|
||||||
|
|
||||||
const intervalRef = useRef(null);
|
const intervalRef = useRef(null);
|
||||||
const countdownRef = useRef(null);
|
const countdownRef = useRef(null);
|
||||||
|
|
@ -362,14 +364,32 @@ export default function ProviderLimits() {
|
||||||
conn.authType === "oauth",
|
conn.authType === "oauth",
|
||||||
);
|
);
|
||||||
|
|
||||||
// Sort providers by USAGE_SUPPORTED_PROVIDERS order, then alphabetically
|
const providerFilteredConnections = filteredConnections.filter(
|
||||||
const sortedConnections = [...filteredConnections].sort((a, b) => {
|
(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 orderA = USAGE_SUPPORTED_PROVIDERS.indexOf(a.provider);
|
||||||
const orderB = USAGE_SUPPORTED_PROVIDERS.indexOf(b.provider);
|
const orderB = USAGE_SUPPORTED_PROVIDERS.indexOf(b.provider);
|
||||||
if (orderA !== orderB) return orderA - orderB;
|
if (orderA !== orderB) return orderA - orderB;
|
||||||
return a.provider.localeCompare(b.provider);
|
return a.provider.localeCompare(b.provider);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const providerOptions = Array.from(new Set(filteredConnections.map((conn) => conn.provider))).sort();
|
||||||
|
|
||||||
// Calculate summary stats
|
// Calculate summary stats
|
||||||
const totalProviders = sortedConnections.length;
|
const totalProviders = sortedConnections.length;
|
||||||
const activeWithLimits = Object.values(quotaData).filter(
|
const activeWithLimits = Object.values(quotaData).filter(
|
||||||
|
|
@ -422,6 +442,26 @@ export default function ProviderLimits() {
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="flex items-center gap-2">
|
<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 */}
|
{/* Auto-refresh toggle */}
|
||||||
<button
|
<button
|
||||||
onClick={() => setAutoRefresh((prev) => !prev)}
|
onClick={() => setAutoRefresh((prev) => !prev)}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue