Fix StepBoxGridReview: match GridTable props interface
Some checks failed
CI / go-lint (push) Has been skipped
CI / python-lint (push) Has been skipped
CI / nodejs-lint (push) Has been skipped
CI / test-go-school (push) Successful in 46s
CI / test-go-edu-search (push) Successful in 43s
CI / test-python-klausur (push) Failing after 2m50s
CI / test-python-agent-core (push) Successful in 37s
CI / test-nodejs-website (push) Successful in 38s

GridTable expects zone (singular), onSelectCell, onCellTextChange,
onToggleColumnBold, onToggleRowHeader, onNavigate — not the
incorrect prop names from the first version.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Benjamin Admin
2026-04-12 22:39:38 +02:00
parent 058eadb0e4
commit 12b194ad1a

View File

@@ -33,6 +33,8 @@ export function StepBoxGridReview({ sessionId, onNext }: StepBoxGridReviewProps)
loadGrid,
saveGrid,
updateCellText,
toggleColumnBold,
toggleRowHeader,
undo,
redo,
canUndo,
@@ -44,6 +46,10 @@ export function StepBoxGridReview({ sessionId, onNext }: StepBoxGridReviewProps)
clearCellSelection,
toggleSelectedBold,
setCellColor,
deleteColumn,
addColumn,
deleteRow,
addRow,
} = useGridEditor(sessionId)
const [building, setBuilding] = useState(false)
@@ -77,7 +83,6 @@ export function StepBoxGridReview({ sessionId, onNext }: StepBoxGridReviewProps)
const data = await res.json().catch(() => ({}))
throw new Error(data.detail || `HTTP ${res.status}`)
}
// Reload grid to see updated box zones
await loadGrid()
} catch (e) {
setBuildError(e instanceof Error ? e.message : String(e))
@@ -87,18 +92,19 @@ export function StepBoxGridReview({ sessionId, onNext }: StepBoxGridReviewProps)
}, [sessionId, loadGrid])
// Handle layout type change for a specific box zone
const changeLayoutType = useCallback(async (zoneIndex: number, layoutType: string) => {
await buildBoxGrids({ [String(zoneIndex)]: layoutType })
const changeLayoutType = useCallback(async (boxIdx: number, layoutType: string) => {
await buildBoxGrids({ [String(boxIdx)]: layoutType })
}, [buildBoxGrids])
// Auto-build on first load if box zones have no cells
useEffect(() => {
if (!grid || loading || building) return
const needsBuild = boxZones.some(z => !z.cells || z.cells.length === 0)
if (needsBuild && boxZones.length > 0) {
const needsBuild = boxZones.length === 0 || boxZones.some(z => !z.cells || z.cells.length === 0)
// Only auto-build if we know there are boxes (check structure_result via a quick fetch)
if (needsBuild && sessionId) {
buildBoxGrids()
}
}, [grid, loading]) // eslint-disable-line react-hooks/exhaustive-deps
}, [grid?.zones?.length, loading]) // eslint-disable-line react-hooks/exhaustive-deps
if (loading) {
return (
@@ -109,8 +115,8 @@ export function StepBoxGridReview({ sessionId, onNext }: StepBoxGridReviewProps)
)
}
// No boxes detected — skip step
if (boxZones.length === 0) {
// No boxes after build attempt — skip step
if (!building && boxZones.length === 0) {
return (
<div className="bg-white dark:bg-gray-800 rounded-xl border border-gray-200 dark:border-gray-700 p-8 text-center">
<div className="text-4xl mb-3">📦</div>
@@ -136,7 +142,7 @@ export function StepBoxGridReview({ sessionId, onNext }: StepBoxGridReviewProps)
<div className="flex items-center justify-between">
<div>
<h3 className="text-lg font-semibold text-gray-900 dark:text-white">
📦 Box-Review ({boxZones.length} {boxZones.length === 1 ? 'Box' : 'Boxen'})
Box-Review ({boxZones.length} {boxZones.length === 1 ? 'Box' : 'Boxen'})
</h3>
<p className="text-sm text-gray-500 dark:text-gray-400">
Eingebettete Boxen prüfen und korrigieren. Layout-Typ kann pro Box angepasst werden.
@@ -186,7 +192,7 @@ export function StepBoxGridReview({ sessionId, onNext }: StepBoxGridReviewProps)
)}
{/* Box zones */}
{boxZones.map((zone) => (
{boxZones.map((zone, boxIdx) => (
<div
key={zone.zone_index}
className="bg-white dark:bg-gray-800 rounded-xl border-2 border-amber-300 dark:border-amber-700 overflow-hidden"
@@ -197,11 +203,12 @@ export function StepBoxGridReview({ sessionId, onNext }: StepBoxGridReviewProps)
<span className="text-lg">📦</span>
<div>
<span className="font-medium text-gray-900 dark:text-white">
Box {zone.zone_index + 1}
Box {boxIdx + 1}
</span>
<span className="text-xs text-gray-500 dark:text-gray-400 ml-2">
{zone.bbox_px.w}×{zone.bbox_px.h}px
{zone.cells?.length ? ` ${zone.cells.length} Zellen` : ''}
{zone.bbox_px?.w}x{zone.bbox_px?.h}px
{zone.cells?.length ? ` | ${zone.cells.length} Zellen` : ''}
{zone.box_layout_type ? ` | ${LAYOUT_LABELS[zone.box_layout_type as BoxLayoutType] || zone.box_layout_type}` : ''}
</span>
</div>
</div>
@@ -209,7 +216,7 @@ export function StepBoxGridReview({ sessionId, onNext }: StepBoxGridReviewProps)
<label className="text-xs text-gray-500 dark:text-gray-400">Layout:</label>
<select
value={zone.box_layout_type || 'flowing'}
onChange={(e) => changeLayoutType(zone.zone_index, e.target.value)}
onChange={(e) => changeLayoutType(boxIdx, e.target.value)}
disabled={building}
className="text-xs px-2 py-1 rounded border border-gray-300 dark:border-gray-600 bg-white dark:bg-gray-700 text-gray-700 dark:text-gray-200"
>
@@ -220,60 +227,39 @@ export function StepBoxGridReview({ sessionId, onNext }: StepBoxGridReviewProps)
</div>
</div>
{/* Box content — image + grid side by side */}
<div className="flex gap-0">
{/* Box image crop */}
{sessionId && (
<div className="w-1/3 border-r border-gray-200 dark:border-gray-700 p-2 bg-gray-50 dark:bg-gray-900">
<div className="relative overflow-hidden rounded-lg border border-gray-200 dark:border-gray-700">
<img
src={`${KLAUSUR_API}/api/v1/ocr-pipeline/sessions/${sessionId}/image/cropped`}
alt={`Box ${zone.zone_index + 1}`}
className="w-full h-auto"
style={{
objectFit: 'none',
objectPosition: `-${zone.bbox_pct?.x ?? 0}% -${zone.bbox_pct?.y ?? 0}%`,
// Use clip-path to show only the box region
}}
onError={(e) => {
// Fallback: hide image if endpoint doesn't exist
(e.target as HTMLImageElement).style.display = 'none'
}}
/>
</div>
{/* Box grid table */}
<div className="p-3">
{zone.cells && zone.cells.length > 0 ? (
<GridTable
zone={zone}
selectedCell={selectedCell}
selectedCells={selectedCells}
onSelectCell={setSelectedCell}
onCellTextChange={updateCellText}
onToggleColumnBold={toggleColumnBold}
onToggleRowHeader={toggleRowHeader}
onNavigate={(cellId, dir) => {
const next = getAdjacentCell(cellId, dir)
if (next) setSelectedCell(next)
}}
onDeleteColumn={deleteColumn}
onAddColumn={addColumn}
onDeleteRow={deleteRow}
onAddRow={addRow}
onToggleCellSelection={toggleCellSelection}
onSetCellColor={setCellColor}
/>
) : (
<div className="text-center py-8 text-gray-400">
<p className="text-sm">Keine Zellen erkannt.</p>
<button
onClick={() => buildBoxGrids({ [String(boxIdx)]: 'flowing' })}
className="mt-2 text-xs text-amber-600 hover:text-amber-700"
>
Als Fließtext verarbeiten
</button>
</div>
)}
{/* Box grid table */}
<div className="flex-1 p-2 overflow-x-auto">
{zone.cells && zone.cells.length > 0 ? (
<GridTable
zones={[zone]}
selectedCell={selectedCell}
onCellSelect={setSelectedCell}
onCellChange={updateCellText}
onGetAdjacentCell={getAdjacentCell}
imageWidth={grid?.image_width || 0}
imageHeight={grid?.image_height || 0}
commitUndoPoint={commitUndoPoint}
selectedCells={selectedCells}
onToggleCellSelection={toggleCellSelection}
onClearCellSelection={clearCellSelection}
onToggleSelectedBold={toggleSelectedBold}
onSetCellColor={setCellColor}
/>
) : (
<div className="text-center py-8 text-gray-400">
<p className="text-sm">Keine Zellen erkannt.</p>
<button
onClick={() => buildBoxGrids({ [String(zone.zone_index)]: 'flowing' })}
className="mt-2 text-xs text-amber-600 hover:text-amber-700"
>
Als Fließtext verarbeiten
</button>
</div>
)}
</div>
</div>
</div>
))}