Records: fix override panel not opening

Open panel immediately on row click (panelOpen state), then load full
record async. Previously the panel condition depended on selectedRecord
or panelLoading both of which are set after async work, so if id was
missing or the API call failed the panel never appeared.

Also shows a message if id is missing (view needs regeneration).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Paul Trowbridge 2026-04-15 21:11:28 -04:00
parent c9b830b286
commit fd67bb03af

View File

@ -32,6 +32,8 @@ export default function Records({ source }) {
const LIMIT = 100 const LIMIT = 100
// Override panel // Override panel
const [panelOpen, setPanelOpen] = useState(false)
const [selectedRow, setSelectedRow] = useState(null) // raw view row (has id)
const [selectedRecord, setSelectedRecord] = useState(null) // full record from API const [selectedRecord, setSelectedRecord] = useState(null) // full record from API
const [overrideDraft, setOverrideDraft] = useState({}) // { field: newValue } const [overrideDraft, setOverrideDraft] = useState({}) // { field: newValue }
const [panelLoading, setPanelLoading] = useState(false) const [panelLoading, setPanelLoading] = useState(false)
@ -45,6 +47,8 @@ export default function Records({ source }) {
setFilters([]) setFilters([])
setViewError(null) setViewError(null)
setSelectedRecord(null) setSelectedRecord(null)
setSelectedRow(null)
setPanelOpen(false)
load(0, null, 'asc', []) load(0, null, 'asc', [])
}, [source]) }, [source])
@ -100,12 +104,20 @@ export default function Records({ source }) {
function next() { const o = offset + LIMIT; setOffset(o); load(o, sort.col, sort.dir, filters) } function next() { const o = offset + LIMIT; setOffset(o); load(o, sort.col, sort.dir, filters) }
async function openPanel(row) { async function openPanel(row) {
const id = row.id // Open panel immediately, then load full record async
if (!id) return setPanelOpen(true)
setPanelLoading(true) setSelectedRow(row)
setPanelMsg(null)
setSelectedRecord(null) setSelectedRecord(null)
setOverrideDraft({}) setOverrideDraft({})
setPanelMsg(null)
const id = row.id
if (!id) {
setPanelMsg({ text: 'No record ID — regenerate the view in Sources.', ok: false })
return
}
setPanelLoading(true)
try { try {
const rec = await api.getRecord(id) const rec = await api.getRecord(id)
setSelectedRecord(rec) setSelectedRecord(rec)
@ -118,6 +130,8 @@ export default function Records({ source }) {
} }
function closePanel() { function closePanel() {
setPanelOpen(false)
setSelectedRow(null)
setSelectedRecord(null) setSelectedRecord(null)
setOverrideDraft({}) setOverrideDraft({})
setPanelMsg(null) setPanelMsg(null)
@ -267,7 +281,7 @@ export default function Records({ source }) {
<tbody> <tbody>
{rows.map((row, i) => { {rows.map((row, i) => {
const isOverridden = row._overridden const isOverridden = row._overridden
const isSelected = selectedRecord?.id === row.id const isSelected = selectedRow?.id != null && selectedRow.id === row.id
return ( return (
<tr <tr
key={i} key={i}
@ -306,7 +320,7 @@ export default function Records({ source }) {
</div> </div>
{/* Override panel */} {/* Override panel */}
{(selectedRecord || panelLoading) && ( {panelOpen && (
<div className="w-80 border-l border-gray-200 bg-white flex flex-col overflow-hidden flex-shrink-0"> <div className="w-80 border-l border-gray-200 bg-white flex flex-col overflow-hidden flex-shrink-0">
<div className="flex items-center justify-between px-3 py-2 border-b border-gray-100"> <div className="flex items-center justify-between px-3 py-2 border-b border-gray-100">
<span className="text-xs font-semibold text-gray-600 uppercase tracking-wide">Override</span> <span className="text-xs font-semibold text-gray-600 uppercase tracking-wide">Override</span>