Kevin Carter 4d10d75003 fix(cis): fix JSX syntax errors and import paths for Phase 3 build
- Fix broken template literal in transcriptionStore.ts export function
- Fix broken regex in Content-Disposition parser
- Fix broken character class in filename sanitization
- Fix LLMConfigModal import path (5 levels up, not 6)
- Export button JSX properly nested in CCTranscriptionPanel
- Build now passes cleanly
2026-05-21 06:35:09 +00:00

127 lines
4.4 KiB
TypeScript

import React, { useState, useEffect } from 'react';
import Close from '@mui/icons-material/Close';
import { useTranscriptionStore, LLMConfig } from '../../../../../stores/transcriptionStore';
const PROVIDERS = [
{ value: 'openai', label: 'OpenAI' },
{ value: 'anthropic', label: 'Anthropic' },
{ value: 'ollama', label: 'Ollama' },
{ value: 'openrouter', label: 'OpenRouter' },
{ value: 'google', label: 'Google' },
] as const;
const LLMConfigModal: React.FC<{ isOpen: boolean; onClose: () => void }> = ({ isOpen, onClose }) => {
const { llmConfig, setLLMConfig } = useTranscriptionStore();
const [form, setForm] = useState<LLMConfig>(llmConfig);
const [saved, setSaved] = useState(false);
useEffect(() => {
if (isOpen) {
setForm(useTranscriptionStore.getState().llmConfig);
setSaved(false);
}
}, [isOpen]);
const handleSave = () => {
setLLMConfig(form);
setSaved(true);
setTimeout(() => setSaved(false), 2000);
};
if (!isOpen) return null;
return (
<div className="fixed inset-0 z-[9999] overflow-y-auto">
{/* Backdrop */}
<div
className="fixed inset-0 bg-black/50 transition-opacity"
onClick={onClose}
/>
{/* Modal panel */}
<div className="relative transform overflow-hidden rounded-lg bg-white text-left shadow-xl transition-all sm:my-8 w-full max-w-md mx-auto">
{/* Header */}
<div className="bg-gray-50 px-4 py-3 flex items-center justify-between border-b border-gray-200">
<h3 className="text-lg font-medium leading-6 text-gray-900">
LLM Provider Settings
</h3>
<button
onClick={onClose}
className="text-gray-400 hover:text-gray-500 focus:outline-none"
>
<Close sx={{ fontSize: 20 }} />
</button>
</div>
{/* Content */}
<div className="px-4 py-5 sm:p-6 space-y-4">
{/* Provider dropdown */}
<div>
<label className="block text-sm font-medium text-gray-700 mb-1">
Provider
</label>
<select
value={form.provider}
onChange={(e) => setForm({ ...form, provider: e.target.value as LLMConfig['provider'] })}
className="w-full rounded-md border border-gray-300 px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent"
>
{PROVIDERS.map((p) => (
<option key={p.value} value={p.value}>
{p.label}
</option>
))}
</select>
</div>
{/* Model name */}
<div>
<label className="block text-sm font-medium text-gray-700 mb-1">
Model
</label>
<input
type="text"
value={form.model}
onChange={(e) => setForm({ ...form, model: e.target.value })}
placeholder="e.g. gpt-4o, claude-sonnet-4-20250514"
className="w-full rounded-md border border-gray-300 px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent"
/>
</div>
{/* API Key */}
<div>
<label className="block text-sm font-medium text-gray-700 mb-1">
API Key
</label>
<input
type="password"
value={form.apiKey}
onChange={(e) => setForm({ ...form, apiKey: e.target.value })}
placeholder="sk-..."
className="w-full rounded-md border border-gray-300 px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent"
/>
</div>
{/* Note */}
<p className="text-xs text-gray-500">
API keys are stored locally in your browser only. They are never sent to Supabase or stored on any server.
</p>
{/* Save button */}
<button
onClick={handleSave}
className={`w-full rounded-md px-4 py-2 text-sm font-medium text-white transition-colors ${
saved
? 'bg-green-600 hover:bg-green-700'
: 'bg-blue-600 hover:bg-blue-700'
}`}
>
{saved ? '✓ Saved!' : 'Save Settings'}
</button>
</div>
</div>
</div>
);
};
export default LLMConfigModal;