mirror of
https://github.com/NanmiCoder/cc-haha
synced 2026-07-26 15:03:34 +08:00
fix: official card at top, modal state reset on close, remove official from presets
- Official provider shown as fixed card in provider list (click to activate) - Add Provider modal conditionally rendered — state resets on close (fixes API key leak) - Remove official from preset chips (not applicable to Add flow) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
1b190524e5
commit
ed8114ce68
@ -115,6 +115,27 @@ function ProviderSettings() {
|
|||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
{/* Official provider — always visible at top */}
|
||||||
|
<div
|
||||||
|
className={`relative flex items-center gap-4 px-4 py-3.5 rounded-xl border transition-all mb-2 ${
|
||||||
|
isOfficialActive
|
||||||
|
? 'border-[var(--color-brand)] bg-[var(--color-primary-fixed)]'
|
||||||
|
: 'border-[var(--color-border)] hover:border-[var(--color-border-focus)] cursor-pointer'
|
||||||
|
}`}
|
||||||
|
onClick={() => !isOfficialActive && handleActivateOfficial()}
|
||||||
|
>
|
||||||
|
<span className={`w-2.5 h-2.5 rounded-full flex-shrink-0 ${isOfficialActive ? 'bg-[var(--color-success)]' : 'bg-[var(--color-text-tertiary)]'}`} />
|
||||||
|
<div className="flex-1 min-w-0">
|
||||||
|
<div className="flex items-center gap-2">
|
||||||
|
<span className="text-sm font-semibold text-[var(--color-text-primary)]">Claude Official</span>
|
||||||
|
{isOfficialActive && (
|
||||||
|
<span className="px-1.5 py-0.5 text-[10px] font-bold rounded bg-[var(--color-brand)] text-white leading-none">ACTIVE</span>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
<div className="text-xs text-[var(--color-text-tertiary)] mt-0.5">Anthropic native — no API key required</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
{/* Saved providers */}
|
{/* Saved providers */}
|
||||||
{isLoading && providers.length === 0 ? (
|
{isLoading && providers.length === 0 ? (
|
||||||
<div className="flex justify-center py-8">
|
<div className="flex justify-center py-8">
|
||||||
@ -171,8 +192,10 @@ function ProviderSettings() {
|
|||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{/* Create Modal */}
|
{/* Create Modal — conditionally rendered so state resets on close */}
|
||||||
<ProviderFormModal open={showCreateModal} onClose={() => setShowCreateModal(false)} mode="create" />
|
{showCreateModal && (
|
||||||
|
<ProviderFormModal open={true} onClose={() => setShowCreateModal(false)} mode="create" />
|
||||||
|
)}
|
||||||
|
|
||||||
{/* Edit Modal */}
|
{/* Edit Modal */}
|
||||||
{editingProvider && (
|
{editingProvider && (
|
||||||
@ -195,7 +218,7 @@ function ProviderFormModal({ open, onClose, mode, provider }: ProviderFormProps)
|
|||||||
const { createProvider, updateProvider, testConfig } = useProviderStore()
|
const { createProvider, updateProvider, testConfig } = useProviderStore()
|
||||||
const fetchSettings = useSettingsStore((s) => s.fetchAll)
|
const fetchSettings = useSettingsStore((s) => s.fetchAll)
|
||||||
|
|
||||||
const availablePresets = PROVIDER_PRESETS
|
const availablePresets = PROVIDER_PRESETS.filter((p) => p.id !== 'official')
|
||||||
const initialPreset = provider ? availablePresets.find((p) => p.id === provider.presetId) || availablePresets.at(-1)! : availablePresets[0]
|
const initialPreset = provider ? availablePresets.find((p) => p.id === provider.presetId) || availablePresets.at(-1)! : availablePresets[0]
|
||||||
|
|
||||||
const [selectedPreset, setSelectedPreset] = useState(initialPreset)
|
const [selectedPreset, setSelectedPreset] = useState(initialPreset)
|
||||||
@ -210,14 +233,10 @@ function ProviderFormModal({ open, onClose, mode, provider }: ProviderFormProps)
|
|||||||
const [settingsJson, setSettingsJson] = useState('')
|
const [settingsJson, setSettingsJson] = useState('')
|
||||||
const [settingsJsonError, setSettingsJsonError] = useState<string | null>(null)
|
const [settingsJsonError, setSettingsJsonError] = useState<string | null>(null)
|
||||||
|
|
||||||
// Load current settings.json and merge provider env (or show as-is for official)
|
// Load current settings.json and merge provider env vars
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
import('../api/settings').then(({ settingsApi }) => {
|
import('../api/settings').then(({ settingsApi }) => {
|
||||||
settingsApi.getUser().then((settings) => {
|
settingsApi.getUser().then((settings) => {
|
||||||
if (selectedPreset.id === 'official') {
|
|
||||||
// Official: show current settings as-is (env keys will be cleared on save)
|
|
||||||
setSettingsJson(JSON.stringify(settings, null, 2))
|
|
||||||
} else {
|
|
||||||
const merged = {
|
const merged = {
|
||||||
...settings,
|
...settings,
|
||||||
env: {
|
env: {
|
||||||
@ -231,7 +250,6 @@ function ProviderFormModal({ open, onClose, mode, provider }: ProviderFormProps)
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
setSettingsJson(JSON.stringify(merged, null, 2))
|
setSettingsJson(JSON.stringify(merged, null, 2))
|
||||||
}
|
|
||||||
}).catch(() => {
|
}).catch(() => {
|
||||||
setSettingsJson(JSON.stringify({}, null, 2))
|
setSettingsJson(JSON.stringify({}, null, 2))
|
||||||
})
|
})
|
||||||
@ -248,8 +266,7 @@ function ProviderFormModal({ open, onClose, mode, provider }: ProviderFormProps)
|
|||||||
}
|
}
|
||||||
|
|
||||||
const isCustom = selectedPreset.id === 'custom'
|
const isCustom = selectedPreset.id === 'custom'
|
||||||
const isOfficial = selectedPreset.id === 'official'
|
const canSubmit = name.trim() && baseUrl.trim() && (mode === 'edit' || apiKey.trim()) && models.main.trim() && !settingsJsonError
|
||||||
const canSubmit = isOfficial || (name.trim() && baseUrl.trim() && (mode === 'edit' || apiKey.trim()) && models.main.trim() && !settingsJsonError)
|
|
||||||
|
|
||||||
const handleSubmit = async () => {
|
const handleSubmit = async () => {
|
||||||
if (!canSubmit) return
|
if (!canSubmit) return
|
||||||
@ -266,17 +283,6 @@ function ProviderFormModal({ open, onClose, mode, provider }: ProviderFormProps)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isOfficial) {
|
|
||||||
try {
|
|
||||||
await useProviderStore.getState().activateOfficial()
|
|
||||||
await fetchSettings()
|
|
||||||
} catch (err) {
|
|
||||||
console.error('Failed to activate official:', err)
|
|
||||||
}
|
|
||||||
onClose()
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if (mode === 'create') {
|
if (mode === 'create') {
|
||||||
await createProvider({
|
await createProvider({
|
||||||
presetId: selectedPreset.id,
|
presetId: selectedPreset.id,
|
||||||
@ -367,9 +373,6 @@ function ProviderFormModal({ open, onClose, mode, provider }: ProviderFormProps)
|
|||||||
|
|
||||||
<Input label="Notes" value={notes} onChange={(e) => setNotes(e.target.value)} placeholder="Optional notes..." />
|
<Input label="Notes" value={notes} onChange={(e) => setNotes(e.target.value)} placeholder="Optional notes..." />
|
||||||
|
|
||||||
{/* Non-official: Base URL, API Key, Model Mapping, Test */}
|
|
||||||
{!isOfficial && (
|
|
||||||
<>
|
|
||||||
{/* Base URL */}
|
{/* Base URL */}
|
||||||
{isCustom || mode === 'edit' ? (
|
{isCustom || mode === 'edit' ? (
|
||||||
<Input label="Base URL" required value={baseUrl} onChange={(e) => setBaseUrl(e.target.value)} placeholder="https://api.example.com/anthropic" />
|
<Input label="Base URL" required value={baseUrl} onChange={(e) => setBaseUrl(e.target.value)} placeholder="https://api.example.com/anthropic" />
|
||||||
@ -413,8 +416,6 @@ function ProviderFormModal({ open, onClose, mode, provider }: ProviderFormProps)
|
|||||||
</span>
|
</span>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
</>
|
|
||||||
)}
|
|
||||||
|
|
||||||
{/* Settings JSON — editable, shown for all presets including official */}
|
{/* Settings JSON — editable, shown for all presets including official */}
|
||||||
<div>
|
<div>
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user