diff --git a/dicom-viewer/src/App.tsx b/dicom-viewer/src/App.tsx index 179d38a..51dae38 100644 --- a/dicom-viewer/src/App.tsx +++ b/dicom-viewer/src/App.tsx @@ -2545,27 +2545,68 @@ function App({ container_id, imageStacks, autoCacheStack, annotationJson, viewer }; // Import and restore all annotations using cornerstoneTools.annotation.state.restoreAnnotations() + // Add defensive guards and queueing so callers can call importAnnotations before the + // viewer/annotation state is fully initialized in rare race conditions. + // @ts-expect-error window augmentation + window.__pendingImportAnnotations = window.__pendingImportAnnotations || {}; + const flushPending = (key: string) => { + try { + // @ts-expect-error global + const pending = window.__pendingImportAnnotations && window.__pendingImportAnnotations[key]; + if (!pending || !pending.length) return; + const annotationState = cornerstoneTools?.annotation?.state; + if (!annotationState || typeof annotationState.addAnnotation !== 'function') return; + // Drain the queue + while ((window.__pendingImportAnnotations[key] || []).length) { + const annotationData = (window.__pendingImportAnnotations[key] || []).shift(); + if (!annotationData) continue; + if (Array.isArray(annotationData)) { + annotationData.forEach(ann => { + try { annotationState.addAnnotation(ann, ann.annotationUID); } catch (err) { console.error('Failed to add queued annotation', err, ann); } + }); + } + } + if (renderingEngineRef.current) renderingEngineRef.current.render(); + } catch (err) { + console.error('Error flushing pending annotations:', err); + } + }; + + // @ts-expect-error window augmentation window[`importAnnotations_${apiKey}`] = (json: string) => { try { const annotationData = typeof json === "string" ? JSON.parse(json) : json; - // Remove all existing annotations if needed - if (cornerstoneTools.annotation.state.removeAllAnnotations) { - cornerstoneTools.annotation.state.removeAllAnnotations(); + const annotationState = cornerstoneTools?.annotation?.state; + if (!annotationState || typeof annotationState.addAnnotation !== 'function') { + // Queue the annotations until the annotation state is ready + // @ts-expect-error window augmentation + window.__pendingImportAnnotations[apiKey] = window.__pendingImportAnnotations[apiKey] || []; + window.__pendingImportAnnotations[apiKey].push(annotationData); + console.warn('importAnnotations: annotation state not ready, queued import', apiKey); + // schedule a flush attempt + setTimeout(() => flushPending(apiKey), 500); + return; } - // Add each annotation from the imported data + + // Remove all existing annotations if needed + if (annotationState.removeAllAnnotations) { + try { annotationState.removeAllAnnotations(); } catch (err) { console.warn('removeAllAnnotations failed', err); } + } + if (Array.isArray(annotationData)) { - // For now just add them to a new group - //const group = new cornerstoneTools.annotation.AnnotationGroup(); annotationData.forEach(ann => { - cornerstoneTools.annotation.state.addAnnotation(ann, ann.annotationUID); + try { annotationState.addAnnotation(ann, ann.annotationUID); } catch (err) { console.error('Failed to add annotation', err, ann); } }); } if (renderingEngineRef.current) { renderingEngineRef.current.render(); } } catch (e) { - alert("Failed to import annotations: " + e); + console.error("Failed to import annotations:", e, { apiKey, cornerstoneTools: !!cornerstoneTools, renderingEngine: !!renderingEngineRef.current }); + try { alert("Failed to import annotations: " + e); } catch (ignored) {} } + // Attempt to flush any queued imports (in case multiple imports were queued) + try { flushPending(apiKey); } catch (ignored) {} }; window[`importLegacyAnnotations_${apiKey}`] = (json: string) => {