From 7dff6ea0ed3a6e4a8179d53d43c72d3473140daa Mon Sep 17 00:00:00 2001 From: Mohamad Yahia Date: Sun, 21 Dec 2025 11:02:54 +0400 Subject: [PATCH] refactor: Simplify usage data extraction and update refresh interval handling in Claude components --- .../src/services/claude-usage-service.ts | 20 +++++----- .../src/components/claude-usage-popover.tsx | 32 ++++++++------- .../api-keys/claude-usage-section.tsx | 40 +------------------ 3 files changed, 30 insertions(+), 62 deletions(-) diff --git a/apps/server/src/services/claude-usage-service.ts b/apps/server/src/services/claude-usage-service.ts index 7b745bae..409437b6 100644 --- a/apps/server/src/services/claude-usage-service.ts +++ b/apps/server/src/services/claude-usage-service.ts @@ -316,17 +316,19 @@ export class ClaudeUsageService { const searchWindow = lines.slice(sectionIndex, sectionIndex + 5); for (const line of searchWindow) { - // Extract percentage - look for patterns like "65% left" or "35% used" - const percentMatch = line.match(/(\d{1,3})\s*%\s*(left|used|remaining)/i); - if (percentMatch) { - const value = parseInt(percentMatch[1], 10); - const isUsed = percentMatch[2].toLowerCase() === "used"; - // Convert "left" to "used" percentage (our UI shows % used) - percentage = isUsed ? value : (100 - value); + // Extract percentage - only take the first match (avoid picking up next section's data) + if (percentage === 0) { + const percentMatch = line.match(/(\d{1,3})\s*%\s*(left|used|remaining)/i); + if (percentMatch) { + const value = parseInt(percentMatch[1], 10); + const isUsed = percentMatch[2].toLowerCase() === "used"; + // Convert "left" to "used" percentage (our UI shows % used) + percentage = isUsed ? value : (100 - value); + } } - // Extract reset time - if (line.toLowerCase().includes("reset")) { + // Extract reset time - only take the first match + if (!resetText && line.toLowerCase().includes("reset")) { resetText = line; } } diff --git a/apps/ui/src/components/claude-usage-popover.tsx b/apps/ui/src/components/claude-usage-popover.tsx index 60b22f29..625ce8f2 100644 --- a/apps/ui/src/components/claude-usage-popover.tsx +++ b/apps/ui/src/components/claude-usage-popover.tsx @@ -31,9 +31,11 @@ type UsageError = { message: string; }; +// Fixed refresh interval (45 seconds) +const REFRESH_INTERVAL_SECONDS = 45; + export function ClaudeUsagePopover() { - const { claudeRefreshInterval, claudeUsage, claudeUsageLastUpdated, setClaudeUsage } = - useAppStore(); + const { claudeUsage, claudeUsageLastUpdated, setClaudeUsage } = useAppStore(); const [open, setOpen] = useState(false); const [loading, setLoading] = useState(false); const [error, setError] = useState(null); @@ -94,16 +96,16 @@ export function ClaudeUsagePopover() { // Auto-refresh interval (only when open) let intervalId: NodeJS.Timeout | null = null; - if (open && claudeRefreshInterval > 0) { + if (open) { intervalId = setInterval(() => { fetchUsage(true); - }, claudeRefreshInterval * 1000); + }, REFRESH_INTERVAL_SECONDS * 1000); } return () => { if (intervalId) clearInterval(intervalId); }; - }, [open, claudeUsage, isStale, claudeRefreshInterval, fetchUsage]); + }, [open, claudeUsage, isStale, fetchUsage]); // Derived status color/icon helper const getStatusInfo = (percentage: number) => { @@ -244,14 +246,16 @@ export function ClaudeUsagePopover() {
Claude Usage
- + {error && ( + + )} {/* Content */} @@ -337,7 +341,7 @@ export function ClaudeUsagePopover() { Claude Status -
{/* Could add quick settings link here */}
+ Updates every minute diff --git a/apps/ui/src/components/views/settings-view/api-keys/claude-usage-section.tsx b/apps/ui/src/components/views/settings-view/api-keys/claude-usage-section.tsx index 2ca061da..cfde650d 100644 --- a/apps/ui/src/components/views/settings-view/api-keys/claude-usage-section.tsx +++ b/apps/ui/src/components/views/settings-view/api-keys/claude-usage-section.tsx @@ -1,18 +1,6 @@ -import { Clock } from "lucide-react"; import { cn } from "@/lib/utils"; -import { useState, useEffect } from "react"; -import { Slider } from "@/components/ui/slider"; -import { useAppStore } from "@/store/app-store"; export function ClaudeUsageSection() { - const { claudeRefreshInterval, setClaudeRefreshInterval } = useAppStore(); - const [localInterval, setLocalInterval] = useState(claudeRefreshInterval); - - // Sync local state with store when store changes (e.g. initial load) - useEffect(() => { - setLocalInterval(claudeRefreshInterval); - }, [claudeRefreshInterval]); - return (
  • Install Claude Code CLI if not already installed
  • Run claude login to authenticate
  • -
  • Usage data will be fetched automatically
  • +
  • Usage data will be fetched automatically every ~minute
  • - - {/* Refresh Interval Section */} -
    -
    -

    - - Refresh Interval -

    -

    - How often to check for usage updates. -

    -
    - -
    - setLocalInterval(vals[0])} - onValueCommit={(vals) => setClaudeRefreshInterval(vals[0])} - min={30} - max={120} - step={5} - className="flex-1" - /> - {Math.max(30, Math.min(120, localInterval || 30))}s -
    -
    );