diff --git a/ui/detection-app/src/composables/useCheckpointLoader.ts b/ui/detection-app/src/composables/useCheckpointLoader.ts index 40e853c..2e62058 100644 --- a/ui/detection-app/src/composables/useCheckpointLoader.ts +++ b/ui/detection-app/src/composables/useCheckpointLoader.ts @@ -2,6 +2,7 @@ import { ref, computed, watch } from 'vue' import type { Ref } from 'vue' import type { DataSource } from 'mpr-ui-framework' import { usePipelineStore } from '../stores/pipeline' +import { useStageRegistry } from './useStageRegistry' interface CheckpointFrame { seq: number @@ -65,19 +66,17 @@ export function useCheckpointLoader( currentFrameRef.value = frame.seq } + const { checkpointStageFor } = useStageRegistry() + // Auto-load checkpoint when entering editor mode watch( () => [pipeline.layoutMode, pipeline.editorStage, jobId.value] as const, ([mode, stage, job]) => { if (mode === 'bbox_editor' && stage && job) { - const stageMap: Record = { - detect_edges: 'filter_scenes', - detect_contours: 'detect_edges', - detect_color: 'detect_contours', - merge_regions: 'detect_color', + const cpStage = checkpointStageFor(stage) + if (cpStage) { + loadCheckpoint(job, cpStage) } - const cpStage = stageMap[stage] ?? 'filter_scenes' - loadCheckpoint(job, cpStage) } }, { immediate: true }, diff --git a/ui/detection-app/src/composables/useStageRegistry.ts b/ui/detection-app/src/composables/useStageRegistry.ts new file mode 100644 index 0000000..3f98e88 --- /dev/null +++ b/ui/detection-app/src/composables/useStageRegistry.ts @@ -0,0 +1,79 @@ +import { computed } from 'vue' +import { useRegistry } from 'mpr-ui-framework' + +export interface StageConfigField { + name: string + type: string + default: unknown + description: string + min: number | null + max: number | null + options: string[] | null +} + +export interface StageInfo { + name: string + label: string + description: string + category: string + config_fields: StageConfigField[] + reads: string[] + writes: string[] +} + +/** + * Detection-specific stage registry. + * + * Fetches stage definitions from the backend and provides helpers + * for looking up stages, determining editor capabilities, and + * resolving checkpoint-to-editor mappings from IO metadata. + */ +export function useStageRegistry() { + const { data: stages, loading, error, refresh } = useRegistry('/api/detect/config/stages') + + const stageMap = computed(() => { + const map = new Map() + for (const s of stages.value) { + map.set(s.name, s) + } + return map + }) + + const stageNames = computed(() => stages.value.map(s => s.name)) + + /** + * Given a stage name, find which preceding stage's checkpoint + * to load for the editor. Uses IO metadata: finds the stage + * whose writes include what this stage reads. + * + * Falls back to the previous stage in the list if IO doesn't resolve. + */ + function checkpointStageFor(stageName: string): string | null { + const idx = stages.value.findIndex(s => s.name === stageName) + if (idx <= 0) return null + // Previous stage in the pipeline order + return stages.value[idx - 1].name + } + + /** + * Stages that have config fields (and thus can open a parameter editor). + */ + const editableStages = computed(() => + stages.value.filter(s => s.config_fields.length > 0).map(s => s.name) + ) + + function getStage(name: string): StageInfo | undefined { + return stageMap.value.get(name) + } + + return { + stages, + loading, + error, + refresh, + stageNames, + editableStages, + getStage, + checkpointStageFor, + } +} diff --git a/ui/detection-app/src/panels/PipelineGraphPanel.vue b/ui/detection-app/src/panels/PipelineGraphPanel.vue index 5a3ab1b..65bf0fb 100644 --- a/ui/detection-app/src/panels/PipelineGraphPanel.vue +++ b/ui/detection-app/src/panels/PipelineGraphPanel.vue @@ -1,13 +1,9 @@