diff --git a/src/components/searchbox/NodeSearchItem.vue b/src/components/searchbox/NodeSearchItem.vue index da9a0cd83..a9859eca4 100644 --- a/src/components/searchbox/NodeSearchItem.vue +++ b/src/components/searchbox/NodeSearchItem.vue @@ -21,16 +21,17 @@
- + + { static comfyClass: string static override title: string static override category: string - static nodeData: ComfyNodeDefV1 & ComfyNodeDefV2 + static override nodeData: ComfyNodeDefV1 & ComfyNodeDefV2 _initialMinSize = { width: 1, height: 1 } @@ -394,7 +394,7 @@ export const useLitegraphService = () => { static comfyClass: string static override title: string static override category: string - static nodeData: ComfyNodeDefV1 & ComfyNodeDefV2 + static override nodeData: ComfyNodeDefV1 & ComfyNodeDefV2 _initialMinSize = { width: 1, height: 1 } @@ -496,6 +496,13 @@ export const useLitegraphService = () => { // because `registerNodeType` will overwrite the assignments. node.category = nodeDef.category node.title = nodeDef.display_name || nodeDef.name + + // Set skip_list for dev-only nodes based on current DevMode setting + // This ensures nodes registered after initial load respect the current setting + if (nodeDef.dev_only) { + const settingStore = useSettingStore() + node.skip_list = !settingStore.get('Comfy.DevMode') + } } /** diff --git a/src/stores/nodeDefStore.ts b/src/stores/nodeDefStore.ts index 217b784ca..7bfa17c2c 100644 --- a/src/stores/nodeDefStore.ts +++ b/src/stores/nodeDefStore.ts @@ -1,9 +1,10 @@ import axios from 'axios' import _ from 'es-toolkit/compat' import { defineStore } from 'pinia' -import { computed, ref } from 'vue' +import { computed, ref, watchEffect } from 'vue' import { isProxyWidget } from '@/core/graph/subgraph/proxyWidget' +import { LiteGraph } from '@/lib/litegraph/src/litegraph' import type { LGraphNode } from '@/lib/litegraph/src/litegraph' import { transformNodeDefV1ToV2 } from '@/schemas/nodeDef/migration' import type { @@ -17,6 +18,7 @@ import type { ComfyOutputTypesSpec as ComfyOutputSpecV1, PriceBadge } from '@/schemas/nodeDefSchema' +import { useSettingStore } from '@/platform/settings/settingStore' import { NodeSearchService } from '@/services/nodeSearchService' import { useSubgraphStore } from '@/stores/subgraphStore' import { NodeSourceType, getNodeSource } from '@/types/nodeSource' @@ -41,6 +43,7 @@ export class ComfyNodeDefImpl readonly help: string readonly deprecated: boolean readonly experimental: boolean + readonly dev_only: boolean readonly output_node: boolean readonly api_node: boolean /** @@ -133,6 +136,7 @@ export class ComfyNodeDefImpl this.deprecated = obj.deprecated ?? obj.category === '' this.experimental = obj.experimental ?? obj.category.startsWith('_for_testing') + this.dev_only = obj.dev_only ?? false this.output_node = obj.output_node this.api_node = !!obj.api_node this.input = obj.input ?? {} @@ -174,6 +178,7 @@ export class ComfyNodeDefImpl get nodeLifeCycleBadgeText(): string { if (this.deprecated) return '[DEPR]' if (this.experimental) return '[BETA]' + if (this.dev_only) return '[DEV]' return '' } } @@ -299,12 +304,27 @@ export interface NodeDefFilter { } export const useNodeDefStore = defineStore('nodeDef', () => { + const settingStore = useSettingStore() + const nodeDefsByName = ref>({}) const nodeDefsByDisplayName = ref>({}) const showDeprecated = ref(false) const showExperimental = ref(false) + const showDevOnly = computed(() => settingStore.get('Comfy.DevMode')) const nodeDefFilters = ref([]) + // Update skip_list on all registered node types when dev mode changes + // This ensures LiteGraph's getNodeTypesCategories/getNodeTypesInCategory + // correctly filter dev-only nodes from the right-click context menu + watchEffect(() => { + const devModeEnabled = showDevOnly.value + for (const nodeType of Object.values(LiteGraph.registered_node_types)) { + if (nodeType.nodeData?.dev_only) { + nodeType.skip_list = !devModeEnabled + } + } + }) + const nodeDefs = computed(() => { const subgraphStore = useSubgraphStore() // Blueprints first for discoverability in the node library sidebar @@ -422,6 +442,14 @@ export const useNodeDefStore = defineStore('nodeDef', () => { predicate: (nodeDef) => showExperimental.value || !nodeDef.experimental }) + // Dev-only nodes filter + registerNodeDefFilter({ + id: 'core.dev_only', + name: 'Hide Dev-Only Nodes', + description: 'Hides nodes marked as dev-only unless dev mode is enabled', + predicate: (nodeDef) => showDevOnly.value || !nodeDef.dev_only + }) + // Subgraph nodes filter // Filter out litegraph typed subgraphs, saved blueprints are added in separately registerNodeDefFilter({ @@ -446,6 +474,7 @@ export const useNodeDefStore = defineStore('nodeDef', () => { nodeDefsByDisplayName, showDeprecated, showExperimental, + showDevOnly, nodeDefFilters, nodeDefs, diff --git a/src/utils/nodeFilterUtil.test.ts b/src/utils/nodeFilterUtil.test.ts index 871f66109..0e6149c0d 100644 --- a/src/utils/nodeFilterUtil.test.ts +++ b/src/utils/nodeFilterUtil.test.ts @@ -11,7 +11,7 @@ describe('nodeFilterUtil', () => { ): LGraphNode => { // Create a custom class with the nodeData static property class MockNode extends LGraphNode { - static nodeData = isOutputNode ? { output_node: true } : {} + static override nodeData = isOutputNode ? { output_node: true } : {} } const node = new MockNode('') @@ -71,11 +71,11 @@ describe('nodeFilterUtil', () => { }) it('should handle nodes with undefined output_node', () => { - class MockNodeWithOtherData extends LGraphNode { - static nodeData = { someOtherProperty: true } + class MockNodeWithEmptyData extends LGraphNode { + static override nodeData = {} } - const node = new MockNodeWithOtherData('') + const node = new MockNodeWithEmptyData('') node.id = 1 const result = filterOutputNodes([node])