mirror of
https://github.com/AutoMaker-Org/automaker.git
synced 2026-03-18 10:23:07 +00:00
Feat: Show Gemini Usage in usage dropdown and mobile sidebar
This commit is contained in:
@@ -82,6 +82,7 @@ export function BoardHeader({
|
||||
);
|
||||
const codexAuthStatus = useSetupStore((state) => state.codexAuthStatus);
|
||||
const zaiAuthStatus = useSetupStore((state) => state.zaiAuthStatus);
|
||||
const geminiAuthStatus = useSetupStore((state) => state.geminiAuthStatus);
|
||||
|
||||
// Worktree panel visibility (per-project)
|
||||
const worktreePanelVisibleByProject = useAppStore((state) => state.worktreePanelVisibleByProject);
|
||||
@@ -116,6 +117,9 @@ export function BoardHeader({
|
||||
// z.ai usage tracking visibility logic
|
||||
const showZaiUsage = !!zaiAuthStatus?.authenticated;
|
||||
|
||||
// Gemini usage tracking visibility logic
|
||||
const showGeminiUsage = !!geminiAuthStatus?.authenticated;
|
||||
|
||||
// State for mobile actions panel
|
||||
const [showActionsPanel, setShowActionsPanel] = useState(false);
|
||||
const [isRefreshingBoard, setIsRefreshingBoard] = useState(false);
|
||||
@@ -163,9 +167,11 @@ export function BoardHeader({
|
||||
</Tooltip>
|
||||
)}
|
||||
{/* Usage Popover - show if any provider is authenticated, only on desktop */}
|
||||
{isMounted && !isTablet && (showClaudeUsage || showCodexUsage || showZaiUsage) && (
|
||||
<UsagePopover />
|
||||
)}
|
||||
{isMounted &&
|
||||
!isTablet &&
|
||||
(showClaudeUsage || showCodexUsage || showZaiUsage || showGeminiUsage) && (
|
||||
<UsagePopover />
|
||||
)}
|
||||
|
||||
{/* Tablet/Mobile view: show hamburger menu with all controls */}
|
||||
{isMounted && isTablet && (
|
||||
@@ -185,6 +191,7 @@ export function BoardHeader({
|
||||
showClaudeUsage={showClaudeUsage}
|
||||
showCodexUsage={showCodexUsage}
|
||||
showZaiUsage={showZaiUsage}
|
||||
showGeminiUsage={showGeminiUsage}
|
||||
/>
|
||||
)}
|
||||
|
||||
|
||||
@@ -31,6 +31,7 @@ interface HeaderMobileMenuProps {
|
||||
showClaudeUsage: boolean;
|
||||
showCodexUsage: boolean;
|
||||
showZaiUsage?: boolean;
|
||||
showGeminiUsage?: boolean;
|
||||
}
|
||||
|
||||
export function HeaderMobileMenu({
|
||||
@@ -49,13 +50,14 @@ export function HeaderMobileMenu({
|
||||
showClaudeUsage,
|
||||
showCodexUsage,
|
||||
showZaiUsage = false,
|
||||
showGeminiUsage = false,
|
||||
}: HeaderMobileMenuProps) {
|
||||
return (
|
||||
<>
|
||||
<HeaderActionsPanelTrigger isOpen={isOpen} onToggle={onToggle} />
|
||||
<HeaderActionsPanel isOpen={isOpen} onClose={onToggle} title="Board Controls">
|
||||
{/* Usage Bar - show if any provider is authenticated */}
|
||||
{(showClaudeUsage || showCodexUsage || showZaiUsage) && (
|
||||
{(showClaudeUsage || showCodexUsage || showZaiUsage || showGeminiUsage) && (
|
||||
<div className="space-y-2">
|
||||
<span className="text-xs font-medium text-muted-foreground uppercase tracking-wide">
|
||||
Usage
|
||||
@@ -64,6 +66,7 @@ export function HeaderMobileMenu({
|
||||
showClaudeUsage={showClaudeUsage}
|
||||
showCodexUsage={showCodexUsage}
|
||||
showZaiUsage={showZaiUsage}
|
||||
showGeminiUsage={showGeminiUsage}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
|
||||
@@ -4,12 +4,14 @@ import { cn } from '@/lib/utils';
|
||||
import { Spinner } from '@/components/ui/spinner';
|
||||
import { getElectronAPI } from '@/lib/electron';
|
||||
import { useAppStore } from '@/store/app-store';
|
||||
import { AnthropicIcon, OpenAIIcon, ZaiIcon } from '@/components/ui/provider-icon';
|
||||
import { AnthropicIcon, OpenAIIcon, ZaiIcon, GeminiIcon } from '@/components/ui/provider-icon';
|
||||
import type { GeminiUsage } from '@/store/app-store';
|
||||
|
||||
interface MobileUsageBarProps {
|
||||
showClaudeUsage: boolean;
|
||||
showCodexUsage: boolean;
|
||||
showZaiUsage?: boolean;
|
||||
showGeminiUsage?: boolean;
|
||||
}
|
||||
|
||||
// Helper to get progress bar color based on percentage
|
||||
@@ -152,6 +154,7 @@ export function MobileUsageBar({
|
||||
showClaudeUsage,
|
||||
showCodexUsage,
|
||||
showZaiUsage = false,
|
||||
showGeminiUsage = false,
|
||||
}: MobileUsageBarProps) {
|
||||
const { claudeUsage, claudeUsageLastUpdated, setClaudeUsage } = useAppStore();
|
||||
const { codexUsage, codexUsageLastUpdated, setCodexUsage } = useAppStore();
|
||||
@@ -159,12 +162,17 @@ export function MobileUsageBar({
|
||||
const [isClaudeLoading, setIsClaudeLoading] = useState(false);
|
||||
const [isCodexLoading, setIsCodexLoading] = useState(false);
|
||||
const [isZaiLoading, setIsZaiLoading] = useState(false);
|
||||
const [isGeminiLoading, setIsGeminiLoading] = useState(false);
|
||||
const [geminiUsage, setGeminiUsage] = useState<GeminiUsage | null>(null);
|
||||
const [geminiUsageLastUpdated, setGeminiUsageLastUpdated] = useState<number | null>(null);
|
||||
|
||||
// Check if data is stale (older than 2 minutes)
|
||||
const isClaudeStale =
|
||||
!claudeUsageLastUpdated || Date.now() - claudeUsageLastUpdated > 2 * 60 * 1000;
|
||||
const isCodexStale = !codexUsageLastUpdated || Date.now() - codexUsageLastUpdated > 2 * 60 * 1000;
|
||||
const isZaiStale = !zaiUsageLastUpdated || Date.now() - zaiUsageLastUpdated > 2 * 60 * 1000;
|
||||
const isGeminiStale =
|
||||
!geminiUsageLastUpdated || Date.now() - geminiUsageLastUpdated > 2 * 60 * 1000;
|
||||
|
||||
const fetchClaudeUsage = useCallback(async () => {
|
||||
setIsClaudeLoading(true);
|
||||
@@ -214,6 +222,23 @@ export function MobileUsageBar({
|
||||
}
|
||||
}, [setZaiUsage]);
|
||||
|
||||
const fetchGeminiUsage = useCallback(async () => {
|
||||
setIsGeminiLoading(true);
|
||||
try {
|
||||
const api = getElectronAPI();
|
||||
if (!api.gemini) return;
|
||||
const data = await api.gemini.getUsage();
|
||||
if (!('error' in data)) {
|
||||
setGeminiUsage(data);
|
||||
setGeminiUsageLastUpdated(Date.now());
|
||||
}
|
||||
} catch {
|
||||
// Silently fail - usage display is optional
|
||||
} finally {
|
||||
setIsGeminiLoading(false);
|
||||
}
|
||||
}, []);
|
||||
|
||||
const getCodexWindowLabel = (durationMins: number) => {
|
||||
if (durationMins < 60) return `${durationMins}m Window`;
|
||||
if (durationMins < 1440) return `${Math.round(durationMins / 60)}h Window`;
|
||||
@@ -239,8 +264,14 @@ export function MobileUsageBar({
|
||||
}
|
||||
}, [showZaiUsage, isZaiStale, fetchZaiUsage]);
|
||||
|
||||
useEffect(() => {
|
||||
if (showGeminiUsage && isGeminiStale) {
|
||||
fetchGeminiUsage();
|
||||
}
|
||||
}, [showGeminiUsage, isGeminiStale, fetchGeminiUsage]);
|
||||
|
||||
// Don't render if there's nothing to show
|
||||
if (!showClaudeUsage && !showCodexUsage && !showZaiUsage) {
|
||||
if (!showClaudeUsage && !showCodexUsage && !showZaiUsage && !showGeminiUsage) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -340,6 +371,58 @@ export function MobileUsageBar({
|
||||
)}
|
||||
</UsageItem>
|
||||
)}
|
||||
|
||||
{showGeminiUsage && (
|
||||
<UsageItem
|
||||
icon={GeminiIcon}
|
||||
label="Gemini"
|
||||
isLoading={isGeminiLoading}
|
||||
onRefresh={fetchGeminiUsage}
|
||||
>
|
||||
{geminiUsage ? (
|
||||
geminiUsage.authenticated ? (
|
||||
geminiUsage.flashQuota || geminiUsage.proQuota ? (
|
||||
<>
|
||||
{geminiUsage.flashQuota && (
|
||||
<UsageBar
|
||||
label="Flash"
|
||||
percentage={geminiUsage.flashQuota.usedPercent}
|
||||
isStale={isGeminiStale}
|
||||
resetText={geminiUsage.flashQuota.resetText}
|
||||
/>
|
||||
)}
|
||||
{geminiUsage.proQuota && (
|
||||
<UsageBar
|
||||
label="Pro"
|
||||
percentage={geminiUsage.proQuota.usedPercent}
|
||||
isStale={isGeminiStale}
|
||||
resetText={geminiUsage.proQuota.resetText}
|
||||
/>
|
||||
)}
|
||||
</>
|
||||
) : (
|
||||
<div className="text-[10px]">
|
||||
<p className="text-green-500 font-medium">
|
||||
Connected via{' '}
|
||||
{geminiUsage.authMethod === 'cli_login'
|
||||
? 'CLI Login'
|
||||
: geminiUsage.authMethod === 'api_key'
|
||||
? 'API Key'
|
||||
: geminiUsage.authMethod}
|
||||
</p>
|
||||
<p className="text-muted-foreground italic mt-0.5">
|
||||
{geminiUsage.error || 'No usage yet'}
|
||||
</p>
|
||||
</div>
|
||||
)
|
||||
) : (
|
||||
<p className="text-[10px] text-yellow-500">Not authenticated</p>
|
||||
)
|
||||
) : (
|
||||
<p className="text-[10px] text-muted-foreground italic">Loading usage data...</p>
|
||||
)}
|
||||
</UsageItem>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user