mirror of
https://github.com/AutoMaker-Org/automaker.git
synced 2026-02-03 08:53:36 +00:00
fix: show session usage window on board usage button
This commit is contained in:
1
apps/ui/src/assets/icons/gemini-icon.svg
Normal file
1
apps/ui/src/assets/icons/gemini-icon.svg
Normal file
File diff suppressed because one or more lines are too long
|
After Width: | Height: | Size: 27 KiB |
@@ -1,4 +1,4 @@
|
|||||||
import { useId, type ComponentType, type SVGProps } from 'react';
|
import type { ComponentType, ImgHTMLAttributes, SVGProps } from 'react';
|
||||||
import { cn } from '@/lib/utils';
|
import { cn } from '@/lib/utils';
|
||||||
import type { AgentModel, ModelProvider } from '@automaker/types';
|
import type { AgentModel, ModelProvider } from '@automaker/types';
|
||||||
import { getProviderFromModel } from '@/lib/utils';
|
import { getProviderFromModel } from '@/lib/utils';
|
||||||
@@ -166,16 +166,14 @@ export function CursorIcon(props: Omit<ProviderIconProps, 'provider'>) {
|
|||||||
return <ProviderIcon provider={PROVIDER_ICON_KEYS.cursor} {...props} />;
|
return <ProviderIcon provider={PROVIDER_ICON_KEYS.cursor} {...props} />;
|
||||||
}
|
}
|
||||||
|
|
||||||
const GEMINI_GRADIENT_STOPS = [
|
const GEMINI_ICON_URL = new URL('../../assets/icons/gemini-icon.svg', import.meta.url).toString();
|
||||||
{ offset: '0%', color: '#4285F4' },
|
const GEMINI_ICON_ALT = 'Gemini';
|
||||||
{ offset: '33%', color: '#EA4335' },
|
|
||||||
{ offset: '66%', color: '#FBBC04' },
|
|
||||||
{ offset: '100%', color: '#34A853' },
|
|
||||||
] as const;
|
|
||||||
|
|
||||||
export function GeminiIcon({ title, className, ...props }: Omit<ProviderIconProps, 'provider'>) {
|
type GeminiIconProps = Omit<ImgHTMLAttributes<HTMLImageElement>, 'src'> & {
|
||||||
const definition = PROVIDER_ICON_DEFINITIONS[PROVIDER_ICON_KEYS.gemini];
|
title?: string;
|
||||||
const gradientId = useId();
|
};
|
||||||
|
|
||||||
|
export function GeminiIcon({ title, className, ...props }: GeminiIconProps) {
|
||||||
const {
|
const {
|
||||||
role,
|
role,
|
||||||
'aria-label': ariaLabel,
|
'aria-label': ariaLabel,
|
||||||
@@ -184,30 +182,19 @@ export function GeminiIcon({ title, className, ...props }: Omit<ProviderIconProp
|
|||||||
...rest
|
...rest
|
||||||
} = props;
|
} = props;
|
||||||
const hasAccessibleLabel = Boolean(title || ariaLabel || ariaLabelledby);
|
const hasAccessibleLabel = Boolean(title || ariaLabel || ariaLabelledby);
|
||||||
|
const fallbackAlt = hasAccessibleLabel ? (title ?? ariaLabel ?? GEMINI_ICON_ALT) : '';
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<svg
|
<img
|
||||||
viewBox={definition.viewBox}
|
src={GEMINI_ICON_URL}
|
||||||
className={cn('inline-block', className)}
|
className={cn('inline-block', className)}
|
||||||
role={role ?? (hasAccessibleLabel ? 'img' : 'presentation')}
|
role={role ?? (hasAccessibleLabel ? 'img' : 'presentation')}
|
||||||
aria-hidden={ariaHidden ?? !hasAccessibleLabel}
|
aria-hidden={ariaHidden ?? !hasAccessibleLabel}
|
||||||
focusable="false"
|
aria-label={ariaLabel}
|
||||||
|
aria-labelledby={ariaLabelledby}
|
||||||
|
alt={fallbackAlt}
|
||||||
{...rest}
|
{...rest}
|
||||||
>
|
/>
|
||||||
{title && <title>{title}</title>}
|
|
||||||
<defs>
|
|
||||||
<linearGradient id={gradientId} x1="0%" y1="0%" x2="100%" y2="100%">
|
|
||||||
{GEMINI_GRADIENT_STOPS.map((stop) => (
|
|
||||||
<stop
|
|
||||||
key={stop.offset}
|
|
||||||
offset={stop.offset}
|
|
||||||
style={{ stopColor: stop.color, stopOpacity: 1 }}
|
|
||||||
/>
|
|
||||||
))}
|
|
||||||
</linearGradient>
|
|
||||||
</defs>
|
|
||||||
<path d={definition.path} fill={`url(#${gradientId})`} fillRule={definition.fillRule} />
|
|
||||||
</svg>
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -27,6 +27,8 @@ type UsageError = {
|
|||||||
|
|
||||||
// Fixed refresh interval (45 seconds)
|
// Fixed refresh interval (45 seconds)
|
||||||
const REFRESH_INTERVAL_SECONDS = 45;
|
const REFRESH_INTERVAL_SECONDS = 45;
|
||||||
|
const CLAUDE_SESSION_WINDOW_HOURS = 5;
|
||||||
|
const CLAUDE_SESSION_WINDOW_BADGE = `${CLAUDE_SESSION_WINDOW_HOURS}h`;
|
||||||
|
|
||||||
// Helper to format reset time for Codex
|
// Helper to format reset time for Codex
|
||||||
function formatCodexResetTime(unixTimestamp: number): string {
|
function formatCodexResetTime(unixTimestamp: number): string {
|
||||||
@@ -226,9 +228,7 @@ export function UsagePopover() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// Calculate max percentage for header button
|
// Calculate max percentage for header button
|
||||||
const claudeMaxPercentage = claudeUsage
|
const claudeSessionPercentage = claudeUsage?.sessionPercentage || 0;
|
||||||
? Math.max(claudeUsage.sessionPercentage || 0, claudeUsage.weeklyPercentage || 0)
|
|
||||||
: 0;
|
|
||||||
|
|
||||||
const codexMaxPercentage = codexUsage?.rateLimits
|
const codexMaxPercentage = codexUsage?.rateLimits
|
||||||
? Math.max(
|
? Math.max(
|
||||||
@@ -237,7 +237,6 @@ export function UsagePopover() {
|
|||||||
)
|
)
|
||||||
: 0;
|
: 0;
|
||||||
|
|
||||||
const maxPercentage = Math.max(claudeMaxPercentage, codexMaxPercentage);
|
|
||||||
const isStale = activeTab === 'claude' ? isClaudeStale : isCodexStale;
|
const isStale = activeTab === 'claude' ? isClaudeStale : isCodexStale;
|
||||||
|
|
||||||
const getProgressBarColor = (percentage: number) => {
|
const getProgressBarColor = (percentage: number) => {
|
||||||
@@ -251,7 +250,7 @@ export function UsagePopover() {
|
|||||||
if (activeTab === 'claude') {
|
if (activeTab === 'claude') {
|
||||||
return {
|
return {
|
||||||
icon: AnthropicIcon,
|
icon: AnthropicIcon,
|
||||||
percentage: claudeMaxPercentage,
|
percentage: claudeSessionPercentage,
|
||||||
isStale: isClaudeStale,
|
isStale: isClaudeStale,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@@ -270,6 +269,11 @@ export function UsagePopover() {
|
|||||||
<Button variant="ghost" size="sm" className="h-9 gap-2 bg-secondary border border-border px-3">
|
<Button variant="ghost" size="sm" className="h-9 gap-2 bg-secondary border border-border px-3">
|
||||||
{(claudeUsage || codexUsage) && <ProviderIcon className={cn('w-4 h-4', statusColor)} />}
|
{(claudeUsage || codexUsage) && <ProviderIcon className={cn('w-4 h-4', statusColor)} />}
|
||||||
<span className="text-sm font-medium">Usage</span>
|
<span className="text-sm font-medium">Usage</span>
|
||||||
|
{activeTab === 'claude' && (
|
||||||
|
<span className="text-[10px] font-medium text-muted-foreground">
|
||||||
|
{CLAUDE_SESSION_WINDOW_BADGE}
|
||||||
|
</span>
|
||||||
|
)}
|
||||||
{(claudeUsage || codexUsage) && (
|
{(claudeUsage || codexUsage) && (
|
||||||
<div
|
<div
|
||||||
className={cn(
|
className={cn(
|
||||||
|
|||||||
Reference in New Issue
Block a user