import { Plus, Trash2 } from 'lucide-react'; import { useState } from 'react'; import { useI18n } from '../i18n'; import type { MessageKey } from '../i18n/resources'; import { isRecord, maskSecret, readString } from '../services/managementApi'; import { effectiveProviderKey, providerKeyDraft, providerKeyOverrides, type ProviderKeyDraft } from '../services/providerGroups'; import '../styles/provider-groups.css'; type Props = { keys: ProviderKeyDraft[]; shared: Record; section: string; disabled: boolean; onChange: (keys: ProviderKeyDraft[]) => void; }; export function ProviderGroupKeysEditor({ keys, shared, section, disabled, onChange }: Props) { const { t } = useI18n(); const [visible, setVisible] = useState>({}); const update = (id: string, patch: (draft: ProviderKeyDraft) => ProviderKeyDraft) => onChange(keys.map((draft) => draft.id === id ? patch(draft) : draft)); const set = (id: string, field: string, value: unknown) => update(id, (draft) => { const next = { ...draft.value }; if (value === undefined) delete next[field]; else next[field] = value; const text = { ...draft.text }; delete text[field]; return { ...draft, value: next, text }; }); const text = (id: string, field: string, value: string) => update(id, (draft) => ({ ...draft, text: { ...draft.text, [field]: value } })); const fields: { field: string; label: MessageKey; kind: 'number' | 'text' | 'boolean' | 'lines'; initial: unknown }[] = [ { field: 'priority', label: 'apiAccess.field.priority', kind: 'number', initial: 0 }, { field: 'proxy-url', label: 'apiAccess.field.proxyUrl', kind: 'text', initial: '' }, { field: 'prefix', label: 'apiAccess.field.prefix', kind: 'text', initial: '' }, { field: 'request-retry', label: 'apiAccess.groups.retry', kind: 'number', initial: 0 }, { field: 'disable-cooling', label: 'apiAccess.cooling.title', kind: 'boolean', initial: false }, { field: 'headers', label: 'apiAccess.field.headers', kind: 'lines', initial: {} }, { field: 'excluded-models', label: 'apiAccess.field.excludedModels', kind: 'lines', initial: [] }, ]; return
{t('apiAccess.groups.keys')}

{t('apiAccess.groups.keysHint')}

{!keys.length ?

{t('apiAccess.groups.emptyKeys')}

: null} {keys.map((draft, index) => { const key = draft.value; const overrideCount = providerKeyOverrides(key).length; const effective = effectiveProviderKey(shared, key); return
{t('apiAccess.groups.keyNumber', { number: index + 1 })}
{t('apiAccess.groups.keySettings')} ยท {overrideCount ? t('apiAccess.groups.overrides', { count: overrideCount }) : t('apiAccess.groups.inherits')}

{t('apiAccess.groups.overrideHint')}

{fields.map(({ field, label, kind, initial }) => { const overridden = key[field] != null; const content = draft.text?.[field] ?? (field === 'headers' && isRecord(key[field]) ? Object.entries(key[field]).map(([name, value]) => `${name}: ${value}`).join('\n') : Array.isArray(key[field]) ? key[field].join('\n') : String(key[field] ?? '')); return
{overridden ? kind === 'lines' ?