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