mirror of
https://github.com/Comfy-Org/ComfyUI_frontend.git
synced 2026-02-19 22:34:15 +00:00
feat: gate node replacement loading on server feature flag (#8750)
## Summary
Gates the node replacement store's `load()` call behind the
`node_replacements` server feature flag, so the frontend only calls
`/api/node_replacements` when the backend advertises support.
## Changes
- Added `NODE_REPLACEMENTS = 'node_replacements'` to `ServerFeatureFlag`
enum
- Added `nodeReplacementsEnabled` getter to `useFeatureFlags()`
- Added `api.serverSupportsFeature('node_replacements')` guard in
`useNodeReplacementStore.load()`
## Context
Without this guard, the frontend would attempt to fetch node
replacements from backends that don't support the endpoint, causing 404
errors.
Companion backend PR: https://github.com/Comfy-Org/ComfyUI/pull/12362
┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-8750-feat-gate-node-replacement-loading-on-server-feature-flag-3026d73d365081ec9246d77ad88f5bdc)
by [Unito](https://www.unito.io)
---------
Co-authored-by: Jin Yi <jin12cc@gmail.com>
Co-authored-by: Alexander Brown <drjkl@comfy.org>
Co-authored-by: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -20,7 +20,8 @@ export enum ServerFeatureFlag {
|
||||
ONBOARDING_SURVEY_ENABLED = 'onboarding_survey_enabled',
|
||||
LINEAR_TOGGLE_ENABLED = 'linear_toggle_enabled',
|
||||
TEAM_WORKSPACES_ENABLED = 'team_workspaces_enabled',
|
||||
USER_SECRETS_ENABLED = 'user_secrets_enabled'
|
||||
USER_SECRETS_ENABLED = 'user_secrets_enabled',
|
||||
NODE_REPLACEMENTS = 'node_replacements'
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -96,6 +97,9 @@ export function useFeatureFlags() {
|
||||
remoteConfig.value.user_secrets_enabled ??
|
||||
api.getServerFeature(ServerFeatureFlag.USER_SECRETS_ENABLED, false)
|
||||
)
|
||||
},
|
||||
get nodeReplacementsEnabled() {
|
||||
return api.getServerFeature(ServerFeatureFlag.NODE_REPLACEMENTS, false)
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
@@ -15,6 +15,18 @@ vi.mock('./nodeReplacementService', () => ({
|
||||
fetchNodeReplacements: vi.fn()
|
||||
}))
|
||||
|
||||
const mockNodeReplacementsEnabled = vi.hoisted(() => ({ value: true }))
|
||||
|
||||
vi.mock('@/composables/useFeatureFlags', () => ({
|
||||
useFeatureFlags: vi.fn(() => ({
|
||||
flags: {
|
||||
get nodeReplacementsEnabled() {
|
||||
return mockNodeReplacementsEnabled.value
|
||||
}
|
||||
}
|
||||
}))
|
||||
}))
|
||||
|
||||
function mockSettingStore(enabled: boolean) {
|
||||
vi.mocked(useSettingStore, { partial: true }).mockReturnValue({
|
||||
get: vi.fn().mockImplementation((key: string) => {
|
||||
@@ -27,9 +39,10 @@ function mockSettingStore(enabled: boolean) {
|
||||
})
|
||||
}
|
||||
|
||||
function createStore(enabled = true) {
|
||||
function createStore(enabled = true, featureEnabled = true) {
|
||||
setActivePinia(createPinia())
|
||||
mockSettingStore(enabled)
|
||||
mockNodeReplacementsEnabled.value = featureEnabled
|
||||
return useNodeReplacementStore()
|
||||
}
|
||||
|
||||
@@ -38,6 +51,7 @@ describe('useNodeReplacementStore', () => {
|
||||
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks()
|
||||
mockNodeReplacementsEnabled.value = true
|
||||
store = createStore(true)
|
||||
})
|
||||
|
||||
@@ -257,5 +271,15 @@ describe('useNodeReplacementStore', () => {
|
||||
expect(fetchNodeReplacements).not.toHaveBeenCalled()
|
||||
expect(store.isLoaded).toBe(false)
|
||||
})
|
||||
|
||||
it('should not call API when server feature flag is disabled', async () => {
|
||||
vi.mocked(fetchNodeReplacements).mockResolvedValue(mockReplacements)
|
||||
store = createStore(true, false)
|
||||
|
||||
await store.load()
|
||||
|
||||
expect(fetchNodeReplacements).not.toHaveBeenCalled()
|
||||
expect(store.isLoaded).toBe(false)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
@@ -3,6 +3,7 @@ import type { NodeReplacement, NodeReplacementResponse } from './types'
|
||||
import { defineStore } from 'pinia'
|
||||
import { computed, ref } from 'vue'
|
||||
|
||||
import { useFeatureFlags } from '@/composables/useFeatureFlags'
|
||||
import { useSettingStore } from '@/platform/settings/settingStore'
|
||||
import { fetchNodeReplacements } from './nodeReplacementService'
|
||||
|
||||
@@ -14,8 +15,12 @@ export const useNodeReplacementStore = defineStore('nodeReplacement', () => {
|
||||
settingStore.get('Comfy.NodeReplacement.Enabled')
|
||||
)
|
||||
|
||||
const { flags } = useFeatureFlags()
|
||||
|
||||
async function load() {
|
||||
if (!isEnabled.value || isLoaded.value) return
|
||||
if (!flags.nodeReplacementsEnabled) return
|
||||
|
||||
try {
|
||||
replacements.value = await fetchNodeReplacements()
|
||||
isLoaded.value = true
|
||||
|
||||
Reference in New Issue
Block a user