fix: make serverFeatureFlags reactive via Vue ref (#9051)

This commit is contained in:
Dante
2026-02-21 18:43:58 +09:00
committed by GitHub
parent 17f34788dc
commit de131133bd
3 changed files with 42 additions and 27 deletions

View File

@@ -37,12 +37,9 @@ test.describe('Feature Flags', { tag: ['@slow', '@settings'] }, () => {
// Monitor for server feature flags // Monitor for server feature flags
const checkInterval = setInterval(() => { const checkInterval = setInterval(() => {
if ( const flags = window.app?.api?.serverFeatureFlags?.value
window.app?.api?.serverFeatureFlags && if (flags && Object.keys(flags).length > 0) {
Object.keys(window.app.api.serverFeatureFlags).length > 0 window.__capturedMessages!.serverFeatureFlags = flags
) {
window.__capturedMessages!.serverFeatureFlags =
window.app.api.serverFeatureFlags
clearInterval(checkInterval) clearInterval(checkInterval)
} }
}, 100) }, 100)
@@ -96,7 +93,7 @@ test.describe('Feature Flags', { tag: ['@slow', '@settings'] }, () => {
}) => { }) => {
// Get the actual server feature flags from the backend // Get the actual server feature flags from the backend
const serverFlags = await comfyPage.page.evaluate(() => { const serverFlags = await comfyPage.page.evaluate(() => {
return window.app!.api.serverFeatureFlags return window.app!.api.serverFeatureFlags.value
}) })
// Verify we received real feature flags from the backend // Verify we received real feature flags from the backend
@@ -129,8 +126,8 @@ test.describe('Feature Flags', { tag: ['@slow', '@settings'] }, () => {
// Test that the method only returns true for boolean true values // Test that the method only returns true for boolean true values
const testResults = await comfyPage.page.evaluate(() => { const testResults = await comfyPage.page.evaluate(() => {
// Temporarily modify serverFeatureFlags to test behavior // Temporarily modify serverFeatureFlags to test behavior
const original = window.app!.api.serverFeatureFlags const original = window.app!.api.serverFeatureFlags.value
window.app!.api.serverFeatureFlags = { window.app!.api.serverFeatureFlags.value = {
bool_true: true, bool_true: true,
bool_false: false, bool_false: false,
string_value: 'yes', string_value: 'yes',
@@ -147,7 +144,7 @@ test.describe('Feature Flags', { tag: ['@slow', '@settings'] }, () => {
} }
// Restore original // Restore original
window.app!.api.serverFeatureFlags = original window.app!.api.serverFeatureFlags.value = original
return results return results
}) })
@@ -282,8 +279,8 @@ test.describe('Feature Flags', { tag: ['@slow', '@settings'] }, () => {
// Monitor when feature flags arrive by checking periodically // Monitor when feature flags arrive by checking periodically
const checkFeatureFlags = setInterval(() => { const checkFeatureFlags = setInterval(() => {
if ( if (
window.app?.api?.serverFeatureFlags?.supports_preview_metadata !== window.app?.api?.serverFeatureFlags?.value
undefined ?.supports_preview_metadata !== undefined
) { ) {
window.__appReadiness!.featureFlagsReceived = true window.__appReadiness!.featureFlagsReceived = true
clearInterval(checkFeatureFlags) clearInterval(checkFeatureFlags)
@@ -320,8 +317,8 @@ test.describe('Feature Flags', { tag: ['@slow', '@settings'] }, () => {
// Wait for feature flags to be received // Wait for feature flags to be received
await newPage.waitForFunction( await newPage.waitForFunction(
() => () =>
window.app?.api?.serverFeatureFlags?.supports_preview_metadata !== window.app?.api?.serverFeatureFlags?.value
undefined, ?.supports_preview_metadata !== undefined,
{ {
timeout: 10000 timeout: 10000
} }
@@ -331,7 +328,7 @@ test.describe('Feature Flags', { tag: ['@slow', '@settings'] }, () => {
const readiness = await newPage.evaluate(() => { const readiness = await newPage.evaluate(() => {
return { return {
...window.__appReadiness, ...window.__appReadiness,
currentFlags: window.app!.api.serverFeatureFlags currentFlags: window.app!.api.serverFeatureFlags.value
} }
}) })

View File

@@ -1,5 +1,6 @@
import type { Mock } from 'vitest' import type { Mock } from 'vitest'
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest' import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'
import { computed, nextTick } from 'vue'
import { api } from '@/scripts/api' import { api } from '@/scripts/api'
@@ -38,7 +39,7 @@ describe('API Feature Flags', () => {
}) })
// Reset API state // Reset API state
api.serverFeatureFlags = {} api.serverFeatureFlags.value = {}
// Mock getClientFeatureFlags to return test feature flags // Mock getClientFeatureFlags to return test feature flags
vi.spyOn(api, 'getClientFeatureFlags').mockReturnValue({ vi.spyOn(api, 'getClientFeatureFlags').mockReturnValue({
@@ -102,7 +103,7 @@ describe('API Feature Flags', () => {
await initPromise await initPromise
// Check that server features were stored // Check that server features were stored
expect(api.serverFeatureFlags).toEqual({ expect(api.serverFeatureFlags.value).toEqual({
supports_preview_metadata: true, supports_preview_metadata: true,
async_execution: true, async_execution: true,
supported_formats: ['webp', 'jpeg', 'png'], supported_formats: ['webp', 'jpeg', 'png'],
@@ -144,14 +145,14 @@ describe('API Feature Flags', () => {
await initPromise await initPromise
// Server features should remain empty // Server features should remain empty
expect(api.serverFeatureFlags).toEqual({}) expect(api.serverFeatureFlags.value).toEqual({})
}) })
}) })
describe('Feature checking methods', () => { describe('Feature checking methods', () => {
beforeEach(() => { beforeEach(() => {
// Set up some test features // Set up some test features
api.serverFeatureFlags = { api.serverFeatureFlags.value = {
supports_preview_metadata: true, supports_preview_metadata: true,
async_execution: false, async_execution: false,
capabilities: ['isolated_nodes', 'dynamic_models'] capabilities: ['isolated_nodes', 'dynamic_models']
@@ -208,12 +209,28 @@ describe('API Feature Flags', () => {
describe('Integration with preview messages', () => { describe('Integration with preview messages', () => {
it('should affect preview message handling based on feature support', () => { it('should affect preview message handling based on feature support', () => {
// Test with metadata support // Test with metadata support
api.serverFeatureFlags = { supports_preview_metadata: true } api.serverFeatureFlags.value = { supports_preview_metadata: true }
expect(api.serverSupportsFeature('supports_preview_metadata')).toBe(true) expect(api.serverSupportsFeature('supports_preview_metadata')).toBe(true)
// Test without metadata support // Test without metadata support
api.serverFeatureFlags = {} api.serverFeatureFlags.value = {}
expect(api.serverSupportsFeature('supports_preview_metadata')).toBe(false) expect(api.serverSupportsFeature('supports_preview_metadata')).toBe(false)
}) })
}) })
describe('Reactivity', () => {
it('should trigger computed updates when serverFeatureFlags changes', async () => {
api.serverFeatureFlags.value = {}
const flag = computed(() =>
api.getServerFeature('supports_preview_metadata', false)
)
expect(flag.value).toBe(false)
api.serverFeatureFlags.value = { supports_preview_metadata: true }
await nextTick()
expect(flag.value).toBe(true)
})
})
}) })

View File

@@ -2,6 +2,7 @@ import { promiseTimeout, until } from '@vueuse/core'
import axios from 'axios' import axios from 'axios'
import { get } from 'es-toolkit/compat' import { get } from 'es-toolkit/compat'
import { trimEnd } from 'es-toolkit' import { trimEnd } from 'es-toolkit'
import { ref } from 'vue'
import defaultClientFeatureFlags from '@/config/clientFeatureFlags.json' with { type: 'json' } import defaultClientFeatureFlags from '@/config/clientFeatureFlags.json' with { type: 'json' }
import type { import type {
@@ -340,7 +341,7 @@ export class ComfyApi extends EventTarget {
/** /**
* Feature flags received from the backend server. * Feature flags received from the backend server.
*/ */
serverFeatureFlags: Record<string, unknown> = {} serverFeatureFlags = ref<Record<string, unknown>>({})
/** /**
* The auth token for the comfy org account if the user is logged in. * The auth token for the comfy org account if the user is logged in.
@@ -695,10 +696,10 @@ export class ComfyApi extends EventTarget {
break break
case 'feature_flags': case 'feature_flags':
// Store server feature flags // Store server feature flags
this.serverFeatureFlags = msg.data this.serverFeatureFlags.value = msg.data
console.log( console.log(
'Server feature flags received:', 'Server feature flags received:',
this.serverFeatureFlags this.serverFeatureFlags.value
) )
this.dispatchCustomEvent('feature_flags', msg.data) this.dispatchCustomEvent('feature_flags', msg.data)
break break
@@ -1291,7 +1292,7 @@ export class ComfyApi extends EventTarget {
* @returns true if the feature is supported, false otherwise * @returns true if the feature is supported, false otherwise
*/ */
serverSupportsFeature(featureName: string): boolean { serverSupportsFeature(featureName: string): boolean {
return get(this.serverFeatureFlags, featureName) === true return get(this.serverFeatureFlags.value, featureName) === true
} }
/** /**
@@ -1301,7 +1302,7 @@ export class ComfyApi extends EventTarget {
* @returns The feature value or default * @returns The feature value or default
*/ */
getServerFeature<T = unknown>(featureName: string, defaultValue?: T): T { getServerFeature<T = unknown>(featureName: string, defaultValue?: T): T {
return get(this.serverFeatureFlags, featureName, defaultValue) as T return get(this.serverFeatureFlags.value, featureName, defaultValue) as T
} }
/** /**
@@ -1309,7 +1310,7 @@ export class ComfyApi extends EventTarget {
* @returns Copy of all server feature flags * @returns Copy of all server feature flags
*/ */
getServerFeatures(): Record<string, unknown> { getServerFeatures(): Record<string, unknown> {
return { ...this.serverFeatureFlags } return { ...this.serverFeatureFlags.value }
} }
async getFuseOptions(): Promise<IFuseOptions<TemplateInfo> | null> { async getFuseOptions(): Promise<IFuseOptions<TemplateInfo> | null> {