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
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:
@@ -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>
|
||||
))}
|
||||
|
||||
Reference in New Issue
Block a user