* feat: extend quota providers and add usage dropdown Add new quota providers: - Claude (Anthropic API) - Codex (OpenAI/ChatGPT) - GitHub Copilot (base + add-on) - Kimi for Coding - OpenRouter UI enhancements: - Add rate limits dropdown in header with timer icon - Desktop: sticky header with Used/Remaining toggle, refresh button - Mobile: full-screen dropdown with same controls - Per-provider sticky headers with provider logos - Auto-refresh on open if no data exists Usage settings page: - Provider icon next to header - Show in dropdown toggle per provider - Global display selector (Usage vs Quota remaining) - Auto-refresh controls in sidebar Settings persistence: - Add usageDisplayMode and usageDropdownProviders settings - Server-side sanitization for new settings Provider logo aliases: - codex -> openai, claude -> anthropic Bug fixes: - Fix React error #310 by calling hooks before early returns - Add aria-describedby to SettingsWindow dialog - Remove horizontal scroll from dropdown * fix: Remove duplicate github copilot declarations
This commit is contained in:
@@ -11,6 +11,8 @@ const DEFAULT_REFRESH_INTERVAL_MS = 60000;
|
||||
interface QuotaSettingsState {
|
||||
autoRefresh: boolean;
|
||||
refreshIntervalMs: number;
|
||||
displayMode: 'usage' | 'remaining';
|
||||
dropdownProviderIds: QuotaProviderId[];
|
||||
}
|
||||
|
||||
interface QuotaStore extends QuotaSettingsState {
|
||||
@@ -27,9 +29,12 @@ interface QuotaStore extends QuotaSettingsState {
|
||||
setSelectedProvider: (providerId: QuotaProviderId | null) => void;
|
||||
setAutoRefresh: (enabled: boolean) => void;
|
||||
setRefreshInterval: (intervalMs: number) => void;
|
||||
setDisplayMode: (mode: 'usage' | 'remaining') => void;
|
||||
setDropdownProviderIds: (providerIds: QuotaProviderId[]) => void;
|
||||
}
|
||||
|
||||
const parseSettings = (data: Record<string, unknown> | null): QuotaSettingsState => {
|
||||
const allProviderIds = QUOTA_PROVIDERS.map((provider) => provider.id);
|
||||
const autoRefresh = typeof data?.usageAutoRefresh === 'boolean'
|
||||
? data.usageAutoRefresh
|
||||
: false;
|
||||
@@ -38,7 +43,17 @@ const parseSettings = (data: Record<string, unknown> | null): QuotaSettingsState
|
||||
? Math.max(30000, Math.min(300000, Math.round(data.usageRefreshIntervalMs)))
|
||||
: DEFAULT_REFRESH_INTERVAL_MS;
|
||||
|
||||
return { autoRefresh, refreshIntervalMs };
|
||||
const displayMode = data?.usageDisplayMode === 'remaining' ? 'remaining' : 'usage';
|
||||
const rawDropdownProviders = Array.isArray(data?.usageDropdownProviders)
|
||||
? data?.usageDropdownProviders
|
||||
: null;
|
||||
const dropdownProviderIds = rawDropdownProviders
|
||||
? rawDropdownProviders.filter((entry): entry is QuotaProviderId =>
|
||||
typeof entry === 'string' && allProviderIds.includes(entry as QuotaProviderId)
|
||||
)
|
||||
: allProviderIds;
|
||||
|
||||
return { autoRefresh, refreshIntervalMs, displayMode, dropdownProviderIds };
|
||||
};
|
||||
|
||||
const loadSettingsFromRuntime = async (): Promise<QuotaSettingsState> => {
|
||||
@@ -69,7 +84,12 @@ const loadSettingsFromRuntime = async (): Promise<QuotaSettingsState> => {
|
||||
}
|
||||
}
|
||||
|
||||
return { autoRefresh: false, refreshIntervalMs: DEFAULT_REFRESH_INTERVAL_MS };
|
||||
return {
|
||||
autoRefresh: false,
|
||||
refreshIntervalMs: DEFAULT_REFRESH_INTERVAL_MS,
|
||||
displayMode: 'usage',
|
||||
dropdownProviderIds: QUOTA_PROVIDERS.map((provider) => provider.id)
|
||||
};
|
||||
};
|
||||
|
||||
export const useQuotaStore = create<QuotaStore>()(
|
||||
@@ -83,6 +103,8 @@ export const useQuotaStore = create<QuotaStore>()(
|
||||
error: null,
|
||||
autoRefresh: false,
|
||||
refreshIntervalMs: DEFAULT_REFRESH_INTERVAL_MS,
|
||||
displayMode: 'usage',
|
||||
dropdownProviderIds: QUOTA_PROVIDERS.map((provider) => provider.id),
|
||||
|
||||
loadSettings: async () => {
|
||||
try {
|
||||
@@ -155,7 +177,9 @@ export const useQuotaStore = create<QuotaStore>()(
|
||||
setRefreshInterval: (intervalMs) => {
|
||||
const clamped = Math.max(30000, Math.min(300000, Math.round(intervalMs)));
|
||||
set({ refreshIntervalMs: clamped });
|
||||
}
|
||||
},
|
||||
setDisplayMode: (mode) => set({ displayMode: mode }),
|
||||
setDropdownProviderIds: (providerIds) => set({ dropdownProviderIds: providerIds })
|
||||
}),
|
||||
{ name: 'quota-store' }
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user