mirror of
https://github.com/AutoMaker-Org/automaker.git
synced 2026-01-30 06:12:03 +00:00
- Fix 75 ESLint errors by updating eslint.config.mjs: - Add missing browser globals (MouseEvent, AbortController, Response, etc.) - Add Vite define global (__APP_VERSION__) - Configure @ts-nocheck to require descriptions - Add no-unused-vars rule for .mjs scripts - Fix runtime bug in agent-output-modal.tsx (setOutput -> setStreamedContent) - Remove ~120 unused variable warnings across 97 files: - Remove unused imports (React hooks, lucide icons, types) - Remove unused constants and variables - Remove unused function definitions - Prefix intentionally unused parameters with underscore - Add descriptions to all @ts-nocheck comments (25 files) - Clean up misc issues: - Remove invalid deprecation plugin comments - Fix eslint-disable comment placement - Add missing RefreshCw import in code-view.tsx Reduces lint warnings from ~300 to 67 (all remaining are no-explicit-any) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
117 lines
3.8 KiB
TypeScript
117 lines
3.8 KiB
TypeScript
import { cn } from '@/lib/utils';
|
|
import { useAppStore } from '@/store/app-store';
|
|
import type { ModelAlias, CursorModelId, PhaseModelKey, PhaseModelEntry } from '@automaker/types';
|
|
import { PhaseModelSelector } from '@/components/views/settings-view/model-defaults/phase-model-selector';
|
|
|
|
/**
|
|
* Normalize PhaseModelEntry or string to PhaseModelEntry
|
|
*/
|
|
function normalizeEntry(entry: PhaseModelEntry | string): PhaseModelEntry {
|
|
if (typeof entry === 'string') {
|
|
return { model: entry as ModelAlias | CursorModelId };
|
|
}
|
|
return entry;
|
|
}
|
|
|
|
export interface ModelOverrideTriggerProps {
|
|
/** Current effective model entry (from global settings or explicit override) */
|
|
currentModelEntry: PhaseModelEntry;
|
|
/** Callback when user selects override */
|
|
onModelChange: (entry: PhaseModelEntry | null) => void;
|
|
/** Optional: which phase this is for (shows global default) */
|
|
phase?: PhaseModelKey;
|
|
/** Size variants for different contexts */
|
|
size?: 'sm' | 'md' | 'lg';
|
|
/** Show as icon-only or with label */
|
|
variant?: 'icon' | 'button' | 'inline';
|
|
/** Whether the model is currently overridden from global */
|
|
isOverridden?: boolean;
|
|
/** Optional class name */
|
|
className?: string;
|
|
}
|
|
|
|
export function ModelOverrideTrigger({
|
|
currentModelEntry,
|
|
onModelChange,
|
|
phase,
|
|
size = 'sm',
|
|
variant = 'icon',
|
|
isOverridden = false,
|
|
className,
|
|
}: ModelOverrideTriggerProps) {
|
|
const { phaseModels } = useAppStore();
|
|
|
|
const handleChange = (entry: PhaseModelEntry) => {
|
|
// If the new entry matches the global default, clear the override
|
|
// Otherwise, set it as override
|
|
if (phase) {
|
|
const globalDefault = phaseModels[phase];
|
|
const normalizedGlobal = normalizeEntry(globalDefault);
|
|
|
|
// Compare models (and thinking levels if both have them)
|
|
const modelsMatch = entry.model === normalizedGlobal.model;
|
|
const thinkingMatch =
|
|
(entry.thinkingLevel || 'none') === (normalizedGlobal.thinkingLevel || 'none');
|
|
|
|
if (modelsMatch && thinkingMatch) {
|
|
onModelChange(null); // Clear override
|
|
} else {
|
|
onModelChange(entry); // Set override
|
|
}
|
|
} else {
|
|
onModelChange(entry);
|
|
}
|
|
};
|
|
|
|
// Size classes for icon variant
|
|
const sizeClasses = {
|
|
sm: 'h-6 w-6',
|
|
md: 'h-8 w-8',
|
|
lg: 'h-10 w-10',
|
|
};
|
|
|
|
// For icon variant, wrap PhaseModelSelector and hide text/chevron with CSS
|
|
if (variant === 'icon') {
|
|
return (
|
|
<div className={cn('relative inline-block', className)}>
|
|
<div className="relative [&_button>span]:hidden [&_button>svg:last-child]:hidden [&_button]:p-0 [&_button]:min-w-0 [&_button]:w-auto [&_button]:h-auto [&_button]:border-0 [&_button]:bg-transparent">
|
|
<PhaseModelSelector
|
|
value={currentModelEntry}
|
|
onChange={handleChange}
|
|
compact
|
|
triggerClassName={cn(
|
|
'relative rounded-md',
|
|
'transition-colors duration-150',
|
|
'text-muted-foreground hover:text-foreground',
|
|
'hover:bg-accent/50',
|
|
sizeClasses[size],
|
|
className
|
|
)}
|
|
disabled={false}
|
|
align="end"
|
|
/>
|
|
</div>
|
|
{isOverridden && (
|
|
<div className="absolute -top-0.5 -right-0.5 w-2 h-2 bg-brand-500 rounded-full z-10 pointer-events-none" />
|
|
)}
|
|
</div>
|
|
);
|
|
}
|
|
|
|
// For button and inline variants, use PhaseModelSelector in compact mode
|
|
return (
|
|
<div className={cn('relative', className)}>
|
|
<PhaseModelSelector
|
|
value={currentModelEntry}
|
|
onChange={handleChange}
|
|
compact
|
|
triggerClassName={variant === 'button' ? className : undefined}
|
|
disabled={false}
|
|
/>
|
|
{isOverridden && (
|
|
<div className="absolute -top-0.5 -right-0.5 w-2 h-2 bg-brand-500 rounded-full z-10" />
|
|
)}
|
|
</div>
|
|
);
|
|
}
|