Add defensive guards and queueing for annotation imports to handle race conditions
This commit is contained in:
@@ -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) => {
|
||||
|
||||
Reference in New Issue
Block a user