refactor: Simplify usage data extraction and update refresh interval handling in Claude components

This commit is contained in:
Mohamad Yahia
2025-12-21 11:02:54 +04:00
parent 5be85a45b1
commit 7dff6ea0ed
3 changed files with 30 additions and 62 deletions

View File

@@ -316,17 +316,19 @@ export class ClaudeUsageService {
const searchWindow = lines.slice(sectionIndex, sectionIndex + 5); const searchWindow = lines.slice(sectionIndex, sectionIndex + 5);
for (const line of searchWindow) { for (const line of searchWindow) {
// Extract percentage - look for patterns like "65% left" or "35% used" // Extract percentage - only take the first match (avoid picking up next section's data)
const percentMatch = line.match(/(\d{1,3})\s*%\s*(left|used|remaining)/i); if (percentage === 0) {
if (percentMatch) { const percentMatch = line.match(/(\d{1,3})\s*%\s*(left|used|remaining)/i);
const value = parseInt(percentMatch[1], 10); if (percentMatch) {
const isUsed = percentMatch[2].toLowerCase() === "used"; const value = parseInt(percentMatch[1], 10);
// Convert "left" to "used" percentage (our UI shows % used) const isUsed = percentMatch[2].toLowerCase() === "used";
percentage = isUsed ? value : (100 - value); // Convert "left" to "used" percentage (our UI shows % used)
percentage = isUsed ? value : (100 - value);
}
} }
// Extract reset time // Extract reset time - only take the first match
if (line.toLowerCase().includes("reset")) { if (!resetText && line.toLowerCase().includes("reset")) {
resetText = line; resetText = line;
} }
} }

View File

@@ -31,9 +31,11 @@ type UsageError = {
message: string; message: string;
}; };
// Fixed refresh interval (45 seconds)
const REFRESH_INTERVAL_SECONDS = 45;
export function ClaudeUsagePopover() { export function ClaudeUsagePopover() {
const { claudeRefreshInterval, claudeUsage, claudeUsageLastUpdated, setClaudeUsage } = const { claudeUsage, claudeUsageLastUpdated, setClaudeUsage } = useAppStore();
useAppStore();
const [open, setOpen] = useState(false); const [open, setOpen] = useState(false);
const [loading, setLoading] = useState(false); const [loading, setLoading] = useState(false);
const [error, setError] = useState<UsageError | null>(null); const [error, setError] = useState<UsageError | null>(null);
@@ -94,16 +96,16 @@ export function ClaudeUsagePopover() {
// Auto-refresh interval (only when open) // Auto-refresh interval (only when open)
let intervalId: NodeJS.Timeout | null = null; let intervalId: NodeJS.Timeout | null = null;
if (open && claudeRefreshInterval > 0) { if (open) {
intervalId = setInterval(() => { intervalId = setInterval(() => {
fetchUsage(true); fetchUsage(true);
}, claudeRefreshInterval * 1000); }, REFRESH_INTERVAL_SECONDS * 1000);
} }
return () => { return () => {
if (intervalId) clearInterval(intervalId); if (intervalId) clearInterval(intervalId);
}; };
}, [open, claudeUsage, isStale, claudeRefreshInterval, fetchUsage]); }, [open, claudeUsage, isStale, fetchUsage]);
// Derived status color/icon helper // Derived status color/icon helper
const getStatusInfo = (percentage: number) => { const getStatusInfo = (percentage: number) => {
@@ -244,14 +246,16 @@ export function ClaudeUsagePopover() {
<div className="flex items-center gap-2"> <div className="flex items-center gap-2">
<span className="text-sm font-semibold">Claude Usage</span> <span className="text-sm font-semibold">Claude Usage</span>
</div> </div>
<Button {error && (
variant="ghost" <Button
size="icon" variant="ghost"
className={cn('h-6 w-6', loading && 'opacity-80')} size="icon"
onClick={() => !loading && fetchUsage(false)} className={cn('h-6 w-6', loading && 'opacity-80')}
> onClick={() => !loading && fetchUsage(false)}
<RefreshCw className="w-3.5 h-3.5" /> >
</Button> <RefreshCw className="w-3.5 h-3.5" />
</Button>
)}
</div> </div>
{/* Content */} {/* Content */}
@@ -337,7 +341,7 @@ export function ClaudeUsagePopover() {
Claude Status <ExternalLink className="w-2.5 h-2.5" /> Claude Status <ExternalLink className="w-2.5 h-2.5" />
</a> </a>
<div className="flex gap-2">{/* Could add quick settings link here */}</div> <span className="text-[10px] text-muted-foreground">Updates every minute</span>
</div> </div>
</PopoverContent> </PopoverContent>
</Popover> </Popover>

View File

@@ -1,18 +1,6 @@
import { Clock } from "lucide-react";
import { cn } from "@/lib/utils"; 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() { 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 ( return (
<div <div
className={cn( className={cn(
@@ -40,35 +28,9 @@ export function ClaudeUsageSection() {
<ol className="list-decimal list-inside space-y-1 ml-1"> <ol className="list-decimal list-inside space-y-1 ml-1">
<li>Install Claude Code CLI if not already installed</li> <li>Install Claude Code CLI if not already installed</li>
<li>Run <code className="font-mono bg-muted px-1 rounded">claude login</code> to authenticate</li> <li>Run <code className="font-mono bg-muted px-1 rounded">claude login</code> to authenticate</li>
<li>Usage data will be fetched automatically</li> <li>Usage data will be fetched automatically every ~minute</li>
</ol> </ol>
</div> </div>
{/* Refresh Interval Section */}
<div className="space-y-4">
<div className="space-y-1">
<h3 className="text-sm font-medium text-foreground flex items-center gap-2">
<Clock className="w-4 h-4 text-muted-foreground" />
Refresh Interval
</h3>
<p className="text-xs text-muted-foreground">
How often to check for usage updates.
</p>
</div>
<div className="flex items-center gap-4">
<Slider
value={[Math.max(30, Math.min(120, localInterval || 30))]}
onValueChange={(vals) => setLocalInterval(vals[0])}
onValueCommit={(vals) => setClaudeRefreshInterval(vals[0])}
min={30}
max={120}
step={5}
className="flex-1"
/>
<span className="w-12 text-sm font-mono text-right">{Math.max(30, Math.min(120, localInterval || 30))}s</span>
</div>
</div>
</div> </div>
</div> </div>
); );