refactor: independent sessions for page-split + URL-based pipeline navigation
Page-split now creates independent sessions (no parent_session_id), parent marked as status='split' and hidden from list. Navigation uses useSearchParams for URL-based step tracking (browser back/forward works). page.tsx reduced from 684 to 443 lines via usePipelineNavigation hook. Box sub-sessions (column detection) remain unchanged. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -21,6 +21,7 @@ function getStatusIcon(sub: SubSession): string {
|
||||
return STATUS_ICONS.pending
|
||||
}
|
||||
|
||||
/** Tabs for box sub-sessions (from column detection zone_type='box'). */
|
||||
export function BoxSessionTabs({ parentSessionId, subSessions, activeSessionId, onSessionChange }: BoxSessionTabsProps) {
|
||||
if (subSessions.length === 0) return null
|
||||
|
||||
@@ -28,7 +29,6 @@ export function BoxSessionTabs({ parentSessionId, subSessions, activeSessionId,
|
||||
|
||||
return (
|
||||
<div className="flex items-center gap-1.5 px-1 py-1.5 bg-gray-50 dark:bg-gray-800/50 rounded-xl border border-gray-200 dark:border-gray-700">
|
||||
{/* Main session tab */}
|
||||
<button
|
||||
onClick={() => onSessionChange(parentSessionId)}
|
||||
className={`px-3 py-1.5 rounded-lg text-xs font-medium transition-colors ${
|
||||
@@ -42,7 +42,6 @@ export function BoxSessionTabs({ parentSessionId, subSessions, activeSessionId,
|
||||
|
||||
<div className="w-px h-5 bg-gray-200 dark:bg-gray-700" />
|
||||
|
||||
{/* Sub-session tabs */}
|
||||
{subSessions.map((sub) => {
|
||||
const isActive = activeSessionId === sub.id
|
||||
const icon = getStatusIcon(sub)
|
||||
@@ -59,7 +58,7 @@ export function BoxSessionTabs({ parentSessionId, subSessions, activeSessionId,
|
||||
title={sub.name}
|
||||
>
|
||||
<span className="mr-1">{icon}</span>
|
||||
Seite {sub.box_index + 1}
|
||||
Box {sub.box_index + 1}
|
||||
</button>
|
||||
)
|
||||
})}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
'use client'
|
||||
|
||||
import { useCallback, useEffect, useState } from 'react'
|
||||
import type { OrientationResult, SessionInfo, SubSession } from '@/app/(admin)/ai/ocr-pipeline/types'
|
||||
import type { OrientationResult, SessionInfo } from '@/app/(admin)/ai/ocr-pipeline/types'
|
||||
import { ImageCompareView } from './ImageCompareView'
|
||||
|
||||
const KLAUSUR_API = '/klausur-api'
|
||||
@@ -17,10 +17,10 @@ interface PageSplitResult {
|
||||
interface StepOrientationProps {
|
||||
sessionId?: string | null
|
||||
onNext: (sessionId: string) => void
|
||||
onSubSessionsCreated?: (subs: SubSession[]) => void
|
||||
onSessionList?: () => void
|
||||
}
|
||||
|
||||
export function StepOrientation({ sessionId: existingSessionId, onNext, onSubSessionsCreated }: StepOrientationProps) {
|
||||
export function StepOrientation({ sessionId: existingSessionId, onNext, onSessionList }: StepOrientationProps) {
|
||||
const [session, setSession] = useState<SessionInfo | null>(null)
|
||||
const [orientationResult, setOrientationResult] = useState<OrientationResult | null>(null)
|
||||
const [pageSplitResult, setPageSplitResult] = useState<PageSplitResult | null>(null)
|
||||
@@ -112,16 +112,6 @@ export function StepOrientation({ sessionId: existingSessionId, onNext, onSubSes
|
||||
if (splitRes.ok) {
|
||||
const splitData: PageSplitResult = await splitRes.json()
|
||||
setPageSplitResult(splitData)
|
||||
if (splitData.multi_page && splitData.sub_sessions && onSubSessionsCreated) {
|
||||
onSubSessionsCreated(
|
||||
splitData.sub_sessions.map((s) => ({
|
||||
id: s.id,
|
||||
name: s.name,
|
||||
box_index: s.page_index,
|
||||
current_step: splitData.used_original ? 1 : 2,
|
||||
}))
|
||||
)
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
console.error('Page-split detection failed:', e)
|
||||
@@ -133,7 +123,7 @@ export function StepOrientation({ sessionId: existingSessionId, onNext, onSubSes
|
||||
setUploading(false)
|
||||
setDetecting(false)
|
||||
}
|
||||
}, [sessionName, onSubSessionsCreated])
|
||||
}, [sessionName])
|
||||
|
||||
const handleDrop = useCallback((e: React.DragEvent) => {
|
||||
e.preventDefault()
|
||||
@@ -264,10 +254,10 @@ export function StepOrientation({ sessionId: existingSessionId, onNext, onSubSes
|
||||
{pageSplitResult?.multi_page && (
|
||||
<div className="bg-blue-50 dark:bg-blue-900/20 rounded-lg border border-blue-200 dark:border-blue-700 p-4">
|
||||
<div className="text-sm font-medium text-blue-700 dark:text-blue-300">
|
||||
Doppelseite erkannt — {pageSplitResult.page_count} Seiten
|
||||
Doppelseite erkannt — {pageSplitResult.page_count} unabhaengige Sessions erstellt
|
||||
</div>
|
||||
<p className="text-xs text-blue-600 dark:text-blue-400 mt-1">
|
||||
Jede Seite wird einzeln durch die Pipeline (Begradigung, Entzerrung, Zuschnitt, ...) verarbeitet.
|
||||
Jede Seite wird als eigene Session durch die Pipeline verarbeitet.
|
||||
{pageSplitResult.used_original && ' (Seitentrennung auf dem Originalbild, da die Orientierung die Doppelseite gedreht hat.)'}
|
||||
</p>
|
||||
<div className="flex gap-2 mt-2">
|
||||
@@ -286,12 +276,21 @@ export function StepOrientation({ sessionId: existingSessionId, onNext, onSubSes
|
||||
{/* Next button */}
|
||||
{orientationResult && (
|
||||
<div className="flex justify-end">
|
||||
<button
|
||||
onClick={() => onNext(session.session_id)}
|
||||
className="px-6 py-2 bg-teal-600 text-white rounded-lg hover:bg-teal-700 font-medium transition-colors"
|
||||
>
|
||||
{pageSplitResult?.multi_page ? 'Seiten verarbeiten' : 'Weiter'} →
|
||||
</button>
|
||||
{pageSplitResult?.multi_page ? (
|
||||
<button
|
||||
onClick={() => onSessionList?.()}
|
||||
className="px-6 py-2 bg-teal-600 text-white rounded-lg hover:bg-teal-700 font-medium transition-colors"
|
||||
>
|
||||
Zur Session-Liste →
|
||||
</button>
|
||||
) : (
|
||||
<button
|
||||
onClick={() => onNext(session.session_id)}
|
||||
className="px-6 py-2 bg-teal-600 text-white rounded-lg hover:bg-teal-700 font-medium transition-colors"
|
||||
>
|
||||
Weiter →
|
||||
</button>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user