mirror of
https://github.com/AutoMaker-Org/automaker.git
synced 2026-03-25 00:33:08 +00:00
feat: Add process abort control and improve auth detection
This commit is contained in:
@@ -11,6 +11,7 @@ import {
|
||||
import { useSetupStore } from '@/store/setup-store';
|
||||
import { useCodexUsage } from '@/hooks/queries';
|
||||
import type { CodexRateLimitWindow } from '@/store/app-store';
|
||||
import { getExpectedCodexPacePercentage, getPaceStatusLabel } from '@/store/utils/usage-utils';
|
||||
|
||||
const CODEX_USAGE_TITLE = 'Codex Usage';
|
||||
const CODEX_USAGE_SUBTITLE = 'Shows usage limits reported by the Codex CLI.';
|
||||
@@ -73,6 +74,12 @@ export function CodexUsageSection() {
|
||||
}) => {
|
||||
const safePercentage = Math.min(Math.max(limitWindow.usedPercent, 0), MAX_PERCENTAGE);
|
||||
const resetLabel = formatCodexResetTime(limitWindow.resetsAt);
|
||||
const pacePercentage = getExpectedCodexPacePercentage(
|
||||
limitWindow.resetsAt,
|
||||
limitWindow.windowDurationMins
|
||||
);
|
||||
const paceLabel =
|
||||
pacePercentage != null ? getPaceStatusLabel(safePercentage, pacePercentage) : null;
|
||||
|
||||
return (
|
||||
<div className="rounded-xl border border-border/60 bg-card/50 p-4">
|
||||
@@ -85,7 +92,7 @@ export function CodexUsageSection() {
|
||||
{Math.round(safePercentage)}%
|
||||
</span>
|
||||
</div>
|
||||
<div className="mt-3 h-2 w-full rounded-full bg-secondary/60">
|
||||
<div className="relative mt-3 h-2 w-full rounded-full bg-secondary/60">
|
||||
<div
|
||||
className={cn(
|
||||
'h-full rounded-full transition-all duration-300',
|
||||
@@ -93,8 +100,29 @@ export function CodexUsageSection() {
|
||||
)}
|
||||
style={{ width: `${safePercentage}%` }}
|
||||
/>
|
||||
{pacePercentage != null && pacePercentage > 0 && pacePercentage < 100 && (
|
||||
<div
|
||||
className="absolute top-0 h-full w-0.5 bg-foreground/60"
|
||||
style={{ left: `${pacePercentage}%` }}
|
||||
title={`Expected: ${Math.round(pacePercentage)}%`}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
<div className="mt-2 flex items-center justify-between">
|
||||
{paceLabel ? (
|
||||
<p
|
||||
className={cn(
|
||||
'text-xs font-medium',
|
||||
safePercentage > (pacePercentage ?? 0) ? 'text-orange-500' : 'text-green-500'
|
||||
)}
|
||||
>
|
||||
{paceLabel}
|
||||
</p>
|
||||
) : (
|
||||
<div />
|
||||
)}
|
||||
{resetLabel && <p className="text-xs text-muted-foreground">{resetLabel}</p>}
|
||||
</div>
|
||||
{resetLabel && <p className="mt-2 text-xs text-muted-foreground">{resetLabel}</p>}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -2,6 +2,7 @@ import { Fragment, useEffect, useMemo, useRef, useState } from 'react';
|
||||
import { cn } from '@/lib/utils';
|
||||
import { useAppStore } from '@/store/app-store';
|
||||
import { useIsMobile } from '@/hooks/use-media-query';
|
||||
import { useOpencodeModels } from '@/hooks/queries';
|
||||
import type {
|
||||
ModelAlias,
|
||||
CursorModelId,
|
||||
@@ -180,14 +181,16 @@ export function PhaseModelSelector({
|
||||
codexModels,
|
||||
codexModelsLoading,
|
||||
fetchCodexModels,
|
||||
dynamicOpencodeModels,
|
||||
enabledDynamicModelIds,
|
||||
opencodeModelsLoading,
|
||||
fetchOpencodeModels,
|
||||
disabledProviders,
|
||||
claudeCompatibleProviders,
|
||||
} = useAppStore();
|
||||
|
||||
// Use React Query for OpenCode models so that changes made in the settings tab
|
||||
// (which also uses React Query) are immediately reflected here via the shared cache,
|
||||
// without requiring a page refresh.
|
||||
const { data: dynamicOpencodeModels = [] } = useOpencodeModels();
|
||||
|
||||
// Detect mobile devices to use inline expansion instead of nested popovers
|
||||
const isMobile = useIsMobile();
|
||||
|
||||
@@ -211,14 +214,9 @@ export function PhaseModelSelector({
|
||||
}
|
||||
}, [codexModels.length, codexModelsLoading, fetchCodexModels]);
|
||||
|
||||
// Fetch OpenCode models on mount
|
||||
useEffect(() => {
|
||||
if (dynamicOpencodeModels.length === 0 && !opencodeModelsLoading) {
|
||||
fetchOpencodeModels().catch(() => {
|
||||
// Silently fail - user will see only static OpenCode models
|
||||
});
|
||||
}
|
||||
}, [dynamicOpencodeModels.length, opencodeModelsLoading, fetchOpencodeModels]);
|
||||
// OpenCode dynamic models are now fetched via React Query (useOpencodeModels above),
|
||||
// which shares a cache with the settings tab. This ensures that newly enabled models
|
||||
// appear in the selector immediately after the settings tab fetches/invalidates the data.
|
||||
|
||||
// Close expanded group when trigger scrolls out of view
|
||||
useEffect(() => {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { useState, useCallback, useMemo } from 'react';
|
||||
import { useState, useCallback, useMemo, useEffect } from 'react';
|
||||
import { useQueryClient } from '@tanstack/react-query';
|
||||
import { toast } from 'sonner';
|
||||
import { useAppStore } from '@/store/app-store';
|
||||
@@ -20,6 +20,7 @@ export function OpencodeSettingsTab() {
|
||||
toggleOpencodeModel,
|
||||
enabledDynamicModelIds,
|
||||
toggleDynamicModel,
|
||||
setDynamicOpencodeModels,
|
||||
} = useAppStore();
|
||||
|
||||
const [isSaving, setIsSaving] = useState(false);
|
||||
@@ -37,6 +38,16 @@ export function OpencodeSettingsTab() {
|
||||
|
||||
const { data: modelsData = [], isFetching: isFetchingModels } = useOpencodeModels();
|
||||
|
||||
// Sync React Query opencode models data to Zustand store so that the model
|
||||
// selector dropdown (PhaseModelSelector) reflects newly enabled models without
|
||||
// requiring a page refresh. The selector reads from the Zustand store while
|
||||
// this settings tab fetches via React Query — keeping them in sync bridges that gap.
|
||||
useEffect(() => {
|
||||
if (modelsData.length > 0) {
|
||||
setDynamicOpencodeModels(modelsData);
|
||||
}
|
||||
}, [modelsData, setDynamicOpencodeModels]);
|
||||
|
||||
// Transform CLI status to the expected format
|
||||
const cliStatus = useMemo((): SharedCliStatus | null => {
|
||||
if (!cliStatusData) return null;
|
||||
|
||||
Reference in New Issue
Block a user