feat: classify missing nodes by replacement availability (#8483)

## Summary
- Extend `MissingNodeType` with `isReplaceable` and `replacement` fields
- Classify missing nodes by checking
`nodeReplacementStore.getReplacementFor()` during graph load
- Wrap hardcoded node patches (T2IAdapterLoader, ConditioningAverage,
etc.) in `if (!isEnabled)` guard so they only run when node replacement
setting is disabled
- Change `useNodeReplacementStore().load()` from fire-and-forget
(`void`) to `await` so replacement data is available before missing node
detection
- Fix guard condition order in `nodeReplacementStore.load()`: check
`isEnabled` before `isLoaded`
- Align `InputMap` types with actual API response (flat
`old_id`/`set_value` fields instead of nested `assign` wrapper)

## Test plan
- [x] Load workflow with deprecated nodes (T2IAdapterLoader,
Load3DAnimation, SDV_img2vid_Conditioning)
- [x] Verify missing nodes are classified with `isReplaceable: true` and
`replacement` object
- [x] Verify hardcoded patches only run when node replacement setting is
OFF
- [x] Verify `nodeReplacementStore.load()` is not called when setting is
disabled
- [x] Unit tests pass (`nodeReplacementStore.test.ts` - 16 tests)
- [x] Typecheck passes

🤖 Generated with [Claude Code](https://claude.ai/code)
This commit is contained in:
Jin Yi
2026-02-15 11:26:46 +09:00
committed by GitHub
parent 58182ddda7
commit 96b9e886ea
6 changed files with 42 additions and 30 deletions

View File

@@ -247,5 +247,15 @@ describe('useNodeReplacementStore', () => {
expect(fetchNodeReplacements).toHaveBeenCalledOnce()
})
it('should not call API when setting is disabled', async () => {
vi.mocked(fetchNodeReplacements).mockResolvedValue(mockReplacements)
store = createStore(false)
await store.load()
expect(fetchNodeReplacements).not.toHaveBeenCalled()
expect(store.isLoaded).toBe(false)
})
})
})

View File

@@ -15,8 +15,7 @@ export const useNodeReplacementStore = defineStore('nodeReplacement', () => {
)
async function load() {
if (isLoaded.value || !isEnabled.value) return
if (!isEnabled.value || isLoaded.value) return
try {
replacements.value = await fetchNodeReplacements()
isLoaded.value = true

View File

@@ -1,17 +1,14 @@
interface InputAssignOldId {
assign_type: 'old_id'
interface InputMapOldId {
new_id: string
old_id: string
}
interface InputAssignSetValue {
assign_type: 'set_value'
value: unknown
interface InputMapSetValue {
new_id: string
set_value: unknown
}
interface InputMap {
new_id: string
assign: InputAssignOldId | InputAssignSetValue
}
type InputMap = InputMapOldId | InputMapSetValue
interface OutputMap {
new_idx: number