// modal-new-recorder.jsx — New Recorder dialog (SRT / RTMP / SDI) function NewRecorderModal({ open, onClose }) { const { PROJECTS, NODES } = window.ZAMPP_DATA; const [name, setName] = React.useState(''); const [sourceType, setSourceType] = React.useState('SRT'); const [srtUrl, setSrtUrl] = React.useState('srt://10.0.4.18:4200'); const [rtmpUrl, setRtmpUrl] = React.useState('rtmp://stream.local/live/cam_a'); const [sdiDeviceIdx, setSdiDeviceIdx] = React.useState(0); const [sdiNodeId, setSdiNodeId] = React.useState(() => { const n = window.ZAMPP_DATA.NODES[0]; return n ? (n.id || n.hostname || '') : ''; }); const [sdiDevices, setSdiDevices] = React.useState(null); const [recTab, setRecTab] = React.useState('video'); const [proxyTab, setProxyTab] = React.useState('video'); const [proxyOn, setProxyOn] = React.useState(true); const [projectId, setProjectId] = React.useState(PROJECTS[0]?.id || ''); const [submitting, setSubmitting] = React.useState(false); const [submitErr, setSubmitErr] = React.useState(null); React.useEffect(() => { if (sourceType !== 'SDI' || sdiDevices !== null) return; window.ZAMPP_API.fetch('/cluster/devices/blackmagic') .then(d => setSdiDevices(Array.isArray(d) ? d : [])) .catch(() => setSdiDevices([])); }, [sourceType]); const handleCreate = () => { if (!name.trim()) { setSubmitErr('Recorder name is required.'); return; } if (sourceType === 'SDI' && !sdiNodeId) { setSubmitErr('Select a capture node for SDI.'); return; } setSubmitting(true); setSubmitErr(null); const body = { name: name.trim(), source_type: sourceType.toLowerCase(), project_id: projectId || undefined, generate_proxy: proxyOn, }; if (sourceType === 'SRT') { body.source_config = { url: srtUrl }; } else if (sourceType === 'RTMP') { body.source_config = { url: rtmpUrl }; } else { // SDI: device_index and node_id are top-level fields body.source_config = {}; body.device_index = sdiDeviceIdx; body.node_id = sdiNodeId || undefined; } window.ZAMPP_API.fetch('/recorders', { method: 'POST', body: JSON.stringify(body) }) .then(() => { setSubmitting(false); onClose(); }) .catch(e => { setSubmitting(false); setSubmitErr(e.message || 'Failed to create recorder'); }); }; if (!open) return null; return (