This commit is contained in:
2025-10-16 18:03:31 +02:00
parent a8a3d95c40
commit c2b0351598
2 changed files with 36 additions and 36 deletions
+27 -36
View File
@@ -296,10 +296,9 @@ const DetailPanel = ({
const [titleSaving, setTitleSaving] = useState(false);
const [titleError, setTitleError] = useState(null);
const [ocrOpen, setOcrOpen] = useState(false);
const [ocrUrl, setOcrUrl] = useState(null);
const [ocrLoading, setOcrLoading] = useState(false);
const [ocrError, setOcrError] = useState(null);
const [ocrText, setOcrText] = useState('');
const [ocrLoadedDocId, setOcrLoadedDocId] = useState(null);
useEffect(() => {
if (!singleDoc) {
@@ -310,8 +309,7 @@ const DetailPanel = ({
setOcrOpen(false);
setOcrLoading(false);
setOcrError(null);
setOcrText('');
setOcrLoadedDocId(null);
setOcrUrl(null);
return;
}
@@ -327,8 +325,7 @@ const DetailPanel = ({
setOcrOpen(false);
setOcrLoading(false);
setOcrError(null);
setOcrText('');
setOcrLoadedDocId(null);
setOcrUrl(null);
}, [singleDoc?.id]);
const startTitleEdit = useCallback(() => {
@@ -384,29 +381,25 @@ const DetailPanel = ({
[singleDoc, getDocumentAsset],
);
const loadOcrText = useCallback(async () => {
const loadOcrUrl = useCallback(async () => {
if (!singleDoc) {
return;
}
if (ocrLoadedDocId === singleDoc.id && ocrText) {
return;
}
const asset = getDocumentAsset(singleDoc, 'ocr-text');
if (!asset) {
setOcrError('No OCR text available for this document.');
setOcrText('');
setOcrLoadedDocId(singleDoc.id);
setOcrUrl(null);
return;
}
setOcrLoading(true);
setOcrError(null);
try {
let entry = asset;
if (ensureAssetUrl) {
entry = (await ensureAssetUrl(singleDoc.id, asset, { force: false })) || asset;
}
let url = entry?.url || null;
if (!url) {
let url = resolveDocumentAssetUrl(singleDoc, 'ocr-text', {
ensureAssetUrl,
getAsset: getDocumentAsset,
});
if (!url && typeof ensureAssetUrl === 'function') {
await ensureAssetUrl(singleDoc.id, asset, { force: false });
url = resolveDocumentAssetUrl(singleDoc, 'ocr-text', {
ensureAssetUrl,
getAsset: getDocumentAsset,
@@ -415,30 +408,24 @@ const DetailPanel = ({
if (!url) {
throw new Error('OCR text URL is unavailable.');
}
const response = await fetch(url);
if (!response.ok) {
throw new Error(`Failed to fetch OCR text (status ${response.status}).`);
}
const text = await response.text();
setOcrText(text);
setOcrLoadedDocId(singleDoc.id);
setOcrUrl(url);
} catch (error) {
setOcrError(error.message || 'Failed to load OCR text.');
setOcrText('');
setOcrUrl(null);
} finally {
setOcrLoading(false);
}
}, [singleDoc, ensureAssetUrl, getDocumentAsset, ocrLoadedDocId, ocrText]);
}, [singleDoc, ensureAssetUrl, getDocumentAsset]);
const openOcr = useCallback(() => {
const openOcrModal = useCallback(() => {
if (!singleDoc) {
return;
}
setOcrOpen(true);
loadOcrText();
}, [singleDoc, loadOcrText]);
loadOcrUrl();
}, [singleDoc, loadOcrUrl]);
const closeOcr = useCallback(() => {
const closeOcrModal = useCallback(() => {
setOcrOpen(false);
}, []);
@@ -773,7 +760,7 @@ const DetailPanel = ({
</div>
{hasOcrAsset ? (
<div className="detail-ocr-trigger">
<button type="button" className="secondary" onClick={openOcr}>
<button type="button" className="secondary" onClick={openOcrModal}>
View OCR text
</button>
</div>
@@ -819,7 +806,7 @@ const DetailPanel = ({
)}
{hasOcrAsset && ocrOpen
? createPortal(
<div className="modal-backdrop" role="presentation" onClick={closeOcr}>
<div className="modal-backdrop" role="presentation" onClick={closeOcrModal}>
<div
className="modal modal--ocr"
role="dialog"
@@ -832,7 +819,7 @@ const DetailPanel = ({
<button
type="button"
className="icon-button ghost"
onClick={closeOcr}
onClick={closeOcrModal}
aria-label="Close OCR text"
>
×
@@ -843,8 +830,12 @@ const DetailPanel = ({
<div className="meta">Loading OCR text</div>
) : ocrError ? (
<div className="status-inline error">{ocrError}</div>
) : ocrText ? (
<pre>{ocrText}</pre>
) : ocrUrl ? (
<iframe
title="OCR text"
src={ocrUrl}
className="detail-ocr__frame"
/>
) : (
<div className="meta">OCR text empty.</div>
)}
+9
View File
@@ -1539,6 +1539,15 @@ button.icon-button.ghost:hover:not([disabled]) {
line-height: 1.4;
}
.detail-ocr__frame {
width: 100%;
height: 60vh;
border: none;
background: var(--surface-subtle);
border-radius: 4px;
box-shadow: inset 0 1px 2px rgba(15, 23, 42, 0.05);
}
.modal__body {
width: 100%;
}