import type { ChangeEvent, ReactNode } from 'react' import { useEffect, useMemo, useRef, useState } from 'react' import { Input } from '@/components/ui/input' import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select' import { Switch } from '@/components/ui/switch' import { Textarea } from '@/components/ui/textarea' import { getElevenLabsVoices, getHermesConfigDefaults, getHermesConfigRecord, getHermesConfigSchema, saveHermesConfig } from '@/hermes' import { cn } from '@/lib/utils' import { notify, notifyError } from '@/store/notifications' import type { ConfigFieldSchema, HermesConfigRecord } from '@/types/hermes' import { CONTROL_TEXT, EMPTY_SELECT_VALUE, FIELD_DESCRIPTIONS, FIELD_LABELS, SECTIONS } from './constants' import { enumOptionsFor, getNested, includesQuery, prettyName, setNested } from './helpers' import { EmptyState, ListRow, LoadingState, SettingsContent } from './primitives' import type { SearchProps } from './types' function ConfigField({ schemaKey, schema, value, enumOptions, optionLabels, onChange }: { schemaKey: string schema: ConfigFieldSchema value: unknown enumOptions?: string[] optionLabels?: Record onChange: (value: unknown) => void }) { const label = FIELD_LABELS[schemaKey] ?? prettyName(schemaKey.split('.').pop() ?? schemaKey) const normalize = (v: string) => v.toLowerCase().replace(/[^a-z0-9]+/g, '') const rawDescription = (FIELD_DESCRIPTIONS[schemaKey] ?? schema.description ?? '').trim() const normalizedDesc = normalize(rawDescription) const description = rawDescription && normalizedDesc !== normalize(label) && normalizedDesc !== normalize(schemaKey) ? rawDescription : undefined const row = (action: ReactNode, wide = false) => ( ) if (schema.type === 'boolean') { return row(
{value ? 'On' : 'Off'}
) } const selectOptions = enumOptions ?? (schema.type === 'select' ? (schema.options ?? []).map(String) : undefined) if (selectOptions) { return row( ) } if (schema.type === 'number') { return row( { const raw = e.target.value const n = raw === '' ? 0 : Number(raw) if (!Number.isNaN(n)) { onChange(n) } }} placeholder="Not set" type="number" value={value === undefined || value === null ? '' : String(value)} /> ) } if (schema.type === 'list') { return row( onChange( e.target.value .split(',') .map(s => s.trim()) .filter(Boolean) ) } placeholder="comma-separated values" value={Array.isArray(value) ? value.join(', ') : String(value ?? '')} /> ) } if (typeof value === 'object' && value !== null) { return row(