mirror of
https://github.com/Nezumi-2711/9router.git
synced 2026-09-22 13:38:31 +00:00
fix: improve the UI for set the limit token for the user
This commit is contained in:
@@ -38,6 +38,9 @@ function quota(sessionLimit, sessionUsed, weeklyLimit, weeklyUsed) {
|
||||
remainingPercentage: limit > 0 ? Math.round((Math.max(0, limit - used) / limit) * 100) : null,
|
||||
isUnlimited: limit === 0,
|
||||
windowStart,
|
||||
resetAt: windowStart === "2026-07-17T05:00:00.000Z"
|
||||
? "2026-07-17T10:00:00.000Z"
|
||||
: "2026-07-20T17:00:00.000Z",
|
||||
});
|
||||
|
||||
return {
|
||||
@@ -92,8 +95,14 @@ describe("/api/usage/system-quota personal token quota overlay", () => {
|
||||
expect(providerById(payload, "codex").accountCount).toBeUndefined();
|
||||
expect(providerById(payload, "codex").quotaAccountCount).toBeUndefined();
|
||||
expect(providerById(payload, "codex").quotas).toMatchObject([
|
||||
{ name: "Session", tokenBudget: true, limit: 100, used: 25, remaining: 75, remainingPercentage: 75 },
|
||||
{ name: "Weekly", tokenBudget: true, limit: 1000, used: 200, remaining: 800, remainingPercentage: 80 },
|
||||
{
|
||||
name: "Session", tokenBudget: true, limit: 100, used: 25,
|
||||
remaining: 75, remainingPercentage: 75, resetAt: "2026-07-17T10:00:00.000Z",
|
||||
},
|
||||
{
|
||||
name: "Weekly", tokenBudget: true, limit: 1000, used: 200,
|
||||
remaining: 800, remainingPercentage: 80, resetAt: "2026-07-20T17:00:00.000Z",
|
||||
},
|
||||
]);
|
||||
expect(providerById(payload, "orbit-provider").quotas).toMatchObject([
|
||||
{ name: "Session", tokenBudget: true, limit: 100, used: 25 },
|
||||
|
||||
@@ -2,11 +2,13 @@ import { beforeEach, describe, expect, it, vi } from "vitest";
|
||||
|
||||
const getUserTokenLimits = vi.fn();
|
||||
const getUserProviderTokenUsageSince = vi.fn();
|
||||
const getUserProviderEarliestTokenUsageSince = vi.fn();
|
||||
const getUserTokenLimitWindowStart = vi.fn();
|
||||
|
||||
vi.mock("@/lib/db/index.js", () => ({
|
||||
getUserTokenLimits,
|
||||
getUserProviderTokenUsageSince,
|
||||
getUserProviderEarliestTokenUsageSince,
|
||||
}));
|
||||
vi.mock("@/lib/tokenLimitEnforcer.js", () => ({ getUserTokenLimitWindowStart }));
|
||||
|
||||
@@ -23,6 +25,7 @@ describe("user token quota snapshot", () => {
|
||||
beforeEach(() => {
|
||||
getUserTokenLimits.mockReset();
|
||||
getUserProviderTokenUsageSince.mockReset();
|
||||
getUserProviderEarliestTokenUsageSince.mockReset();
|
||||
getUserTokenLimitWindowStart.mockReset();
|
||||
|
||||
getUserTokenLimits.mockResolvedValue({
|
||||
@@ -42,6 +45,7 @@ describe("user token quota snapshot", () => {
|
||||
const windowType = since.getTime() === sessionStart.getTime() ? "session" : "weekly";
|
||||
return usage.get(usageKey(provider, windowType));
|
||||
});
|
||||
getUserProviderEarliestTokenUsageSince.mockResolvedValue(null);
|
||||
});
|
||||
|
||||
it("calculates both provider windows and preserves zero as unlimited", async () => {
|
||||
@@ -58,7 +62,21 @@ describe("user token quota snapshot", () => {
|
||||
},
|
||||
});
|
||||
expect(quota.codex.session.windowStart).toBe(sessionStart.toISOString());
|
||||
expect(quota.codex.session.resetAt).toBeNull();
|
||||
expect(quota.codex.weekly.resetAt).toBe("2026-07-20T17:00:00.000Z");
|
||||
expect(getUserProviderTokenUsageSince).toHaveBeenCalledTimes(4);
|
||||
expect(getUserProviderEarliestTokenUsageSince).toHaveBeenCalledTimes(2);
|
||||
});
|
||||
|
||||
it("reports when the next tokens leave a rolling session window", async () => {
|
||||
getUserProviderEarliestTokenUsageSince.mockImplementation(async (_userId, provider) => (
|
||||
provider === "orbit-provider" ? "2026-07-17T06:30:00.000Z" : null
|
||||
));
|
||||
|
||||
const quota = await getUserTokenQuota("user-1", new Date("2026-07-17T10:00:00.000Z"));
|
||||
|
||||
expect(quota["orbit-provider"].session.resetAt).toBe("2026-07-17T11:30:00.000Z");
|
||||
expect(quota.codex.session.resetAt).toBeNull();
|
||||
});
|
||||
|
||||
it("requires a user id", async () => {
|
||||
|
||||
Reference in New Issue
Block a user