// An editable ARIA combobox with manual selection. Credentials stay on the server. function salesforceRecordLabel(type) { return { Case: "Case", Bug__c: "Bug", Ticket__c: "Ticket" }[type] || "Record"; } function primarySalesforceRecord(investigation) { if (investigation.primary_record) return investigation.primary_record; if (!investigation.case_number && !investigation.case_url) return null; const type = investigation.case_url?.match( /\/lightning\/r\/(Case|Bug__c|Ticket__c)\//, )?.[1] || "Case"; return { type, number: investigation.case_number, url: investigation.case_url, }; } function SalesforceRecordLookup({ value, onChange, disabled = false, initialType = "Case", }) { const [recordType, setRecordType] = React.useState( value?.type || initialType, ); const recordLabel = salesforceRecordLabel(recordType); const id = React.useId(); const input = React.useRef(null); const requestVersion = React.useRef(0); const [query, setQuery] = React.useState(""); const [records, setRecords] = React.useState([]); const [busy, setBusy] = React.useState(false); const [error, setError] = React.useState(null); const [searched, setSearched] = React.useState(false); const [expanded, setExpanded] = React.useState(false); const [active, setActive] = React.useState(-1); const [retry, setRetry] = React.useState(0); const invalidate = () => { requestVersion.current += 1; setRecords([]); setActive(-1); setError(null); setSearched(false); setBusy(false); }; React.useEffect(() => { const version = ++requestVersion.current; const controller = new AbortController(); const term = query.trim(); if (value || term.length < 2) return; setBusy(true); const timer = setTimeout(async () => { try { const response = await fetch( `/api/salesforce/records?${new URLSearchParams({ type: recordType, q: term })}`, { credentials: "same-origin", signal: controller.signal }, ); const data = await handleResponse(response); if (version !== requestVersion.current) return; if (!response.ok || data.error) throw new Error(data.error || "Search failed. Try again."); setRecords(data.records || []); setSearched(true); } catch (e) { if (e.name !== "AbortError" && version === requestVersion.current) setError(e.message); } finally { if (version === requestVersion.current) setBusy(false); } }, 300); return () => { clearTimeout(timer); controller.abort(); }; }, [query, value, retry, recordType]); React.useEffect(() => { if (expanded && active >= 0) document .getElementById(`${id}-option-${active}`) ?.scrollIntoView({ block: "nearest" }); }, [active, expanded]); const select = (record) => { invalidate(); onChange(record); setExpanded(false); }; const onKeyDown = (e) => { if (e.key === "Escape") { e.preventDefault(); setExpanded(false); setActive(-1); } if ((e.key === "ArrowDown" || e.key === "ArrowUp") && records.length) { e.preventDefault(); setExpanded(true); setActive((index) => e.key === "ArrowDown" ? Math.min(index + 1, records.length - 1) : index < 0 ? records.length - 1 : Math.max(0, index - 1), ); } if (e.key === "Enter") { e.preventDefault(); if (expanded && active >= 0) select(records[active]); } }; const open = expanded && records.length > 0 && !value; return (

Search with your current Salesforce login. Only records you can access are returned.

= 0 ? `${id}-option-${active}` : undefined } aria-describedby={`${id}-help ${id}-status`} aria-invalid={!!error} autoComplete="off" maxLength={100} disabled={disabled} value={value ? `${value.number} · ${value.title}` : query} placeholder={ recordType === "Case" ? "Case number or subject" : recordType === "Bug__c" ? "Bug name or title" : "Ticket code or name" } onFocus={() => setExpanded(true)} onKeyDown={onKeyDown} onChange={(e) => { invalidate(); onChange(null); setQuery(e.target.value); setExpanded(true); }} />

Enter at least 2 characters. Use ↑ / ↓ to browse, Enter to select, or choose a result.

{busy ? "Searching Salesforce…" : value ? `${recordLabel} ${value.number} selected. Ready to connect.` : searched ? records.length ? `${records.length} result${records.length === 1 ? "" : "s"}${records.length === 20 ? ". Showing the 20 most recently updated matches; refine your search" : ""}.` : "No matches. Try a different number, name or title." : ""}

{error && ( { invalidate(); setRetry((n) => n + 1); setExpanded(true); input.current?.focus(); }} > Retry search )} {value && (
{value.number} · {value.title} {value.status || `Salesforce ${recordLabel.toLowerCase()}`}
{ invalidate(); onChange(null); setQuery(""); input.current?.focus(); }} > Clear selection
)} ); }