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()
|
// 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) => {
|
window[`importAnnotations_${apiKey}`] = (json: string) => {
|
||||||
try {
|
try {
|
||||||
const annotationData = typeof json === "string" ? JSON.parse(json) : json;
|
const annotationData = typeof json === "string" ? JSON.parse(json) : json;
|
||||||
// Remove all existing annotations if needed
|
const annotationState = cornerstoneTools?.annotation?.state;
|
||||||
if (cornerstoneTools.annotation.state.removeAllAnnotations) {
|
if (!annotationState || typeof annotationState.addAnnotation !== 'function') {
|
||||||
cornerstoneTools.annotation.state.removeAllAnnotations();
|
// 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)) {
|
if (Array.isArray(annotationData)) {
|
||||||
// For now just add them to a new group
|
|
||||||
//const group = new cornerstoneTools.annotation.AnnotationGroup();
|
|
||||||
annotationData.forEach(ann => {
|
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) {
|
if (renderingEngineRef.current) {
|
||||||
renderingEngineRef.current.render();
|
renderingEngineRef.current.render();
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} 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) => {
|
window[`importLegacyAnnotations_${apiKey}`] = (json: string) => {
|
||||||
|
|||||||
Reference in New Issue
Block a user