From 7e532da932912d1d71ab6c64dac5e7d143d42ea5 Mon Sep 17 00:00:00 2001 From: shiva Date: Sun, 1 Nov 2026 06:02:55 +0530 Subject: [PATCH] fix(annotations): list measurements in the order they were placed Each view creates its placing tool ahead of time, so tool IDs follow the creation of those placeholders rather than the order annotations are finished, and a new ruler could show up in the middle of the Measurements list. Move a tool to the end of the tool list when it is placed. --- .../tools/__tests__/placementOrder.spec.ts | 44 +++++++++++++++++++ src/store/tools/useAnnotationTool.ts | 6 +++ 2 files changed, 50 insertions(+) create mode 100644 src/store/tools/__tests__/placementOrder.spec.ts diff --git a/src/store/tools/__tests__/placementOrder.spec.ts b/src/store/tools/__tests__/placementOrder.spec.ts new file mode 100644 index 000000000..6a2d849e6 --- /dev/null +++ b/src/store/tools/__tests__/placementOrder.spec.ts @@ -0,0 +1,44 @@ +import { beforeEach, describe, expect, it } from 'vitest'; +import { setActivePinia, createPinia } from 'pinia'; +import vtkImageData from '@kitware/vtk.js/Common/DataModel/ImageData'; + +import { useImageCacheStore } from '@/src/store/image-cache'; +import { useRulerStore } from '@/src/store/tools/rulers'; +import { useRectangleStore } from '@/src/store/tools/rectangles'; +import { usePolygonStore } from '@/src/store/tools/polygons'; +import { useViewStore } from '@/src/store/views'; + +const IMAGE_ID = 'img-1'; + +describe.each([ + ['ruler', useRulerStore], + ['rectangle', useRectangleStore], + ['polygon', usePolygonStore], +] as const)('%s placement order', (_name, useStore) => { + beforeEach(() => { + setActivePinia(createPinia()); + useImageCacheStore().addVTKImageData(vtkImageData.newInstance(), 'CT', { + id: IMAGE_ID, + }); + useViewStore().setDataForAllViews(IMAGE_ID); + }); + + it('lists and saves finished tools in placement order, excluding unfinished tools', () => { + const store = useStore(); + const existing = store.addTool({ imageID: IMAGE_ID }); + // each view creates its placing tool up front + const lowerLeft = store.addTool({ imageID: IMAGE_ID, placing: true }); + const upperLeft = store.addTool({ imageID: IMAGE_ID, placing: true }); + + store.addTool({ imageID: IMAGE_ID, placing: true }); + + store.placeTool(upperLeft); + store.placeTool(lowerLeft); + + const expected = [existing, upperLeft, lowerLeft]; + expect(store.finishedTools.map((tool) => tool.id)).toEqual(expected); + expect(store.serializeTools().tools.map((tool) => tool.id)).toEqual( + expected + ); + }); +}); diff --git a/src/store/tools/useAnnotationTool.ts b/src/store/tools/useAnnotationTool.ts index 0ee6b50b4..ed31f040d 100644 --- a/src/store/tools/useAnnotationTool.ts +++ b/src/store/tools/useAnnotationTool.ts @@ -145,6 +145,12 @@ export const useAnnotationTool = < function placeTool(id: ToolID) { resolveToolSegment(id); updateTool(id, { placing: false } as ToolPatch); + // Placing tools are created ahead of time per view, so their IDs are not in + // the order they get placed. Move the placed tool last so lists follow it. + if (id in toolByID.value) { + removeFromArray(toolIDs.value, id); + toolIDs.value.push(id); + } } // Delete-base cleanup: a removed image's tools