Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 6 additions & 5 deletions src/components/searchbox/NodeSearchItem.vue
Original file line number Diff line number Diff line change
Expand Up @@ -21,16 +21,17 @@
</div>
</div>
<div class="option-badges">
<Tag
v-if="nodeDef.experimental"
:value="$t('g.experimental')"
severity="primary"
/>
<Tag
v-if="nodeDef.deprecated"
:value="$t('g.deprecated')"
severity="danger"
/>
<Tag
v-if="nodeDef.experimental"
:value="$t('g.experimental')"
severity="primary"
/>
<Tag v-if="nodeDef.dev_only" :value="$t('g.devOnly')" severity="info" />
<Tag
v-if="showNodeFrequency && nodeFrequency > 0"
:value="formatNumberWithSuffix(nodeFrequency, { roundToInt: true })"
Expand Down
8 changes: 8 additions & 0 deletions src/lib/litegraph/src/LGraphNode.ts
Original file line number Diff line number Diff line change
Expand Up @@ -233,6 +233,14 @@ export class LGraphNode
static description?: string
static filter?: string
static skip_list?: boolean
static nodeData?: {
dev_only?: boolean
deprecated?: boolean
experimental?: boolean
output_node?: boolean
api_node?: boolean
name?: string
}

static resizeHandleSize = 15
static resizeEdgeSize = 5
Expand Down
1 change: 1 addition & 0 deletions src/locales/en/main.json
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,7 @@
"customize": "Customize",
"experimental": "BETA",
"deprecated": "DEPR",
"devOnly": "DEV",
"loadWorkflow": "Load Workflow",
"goToNode": "Go to Node",
"setAsBackground": "Set as Background",
Expand Down
1 change: 1 addition & 0 deletions src/schemas/nodeDef/nodeDefSchemaV2.ts
Original file line number Diff line number Diff line change
Expand Up @@ -174,6 +174,7 @@ export const zComfyNodeDef = z.object({
python_module: z.string(),
deprecated: z.boolean().optional(),
experimental: z.boolean().optional(),
dev_only: z.boolean().optional(),
api_node: z.boolean().optional()
})

Expand Down
1 change: 1 addition & 0 deletions src/schemas/nodeDefSchema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -257,6 +257,7 @@ export const zComfyNodeDef = z.object({
python_module: z.string(),
deprecated: z.boolean().optional(),
experimental: z.boolean().optional(),
dev_only: z.boolean().optional(),
/**
* Whether the node is an API node. Running API nodes requires login to
* Comfy Org account.
Expand Down
11 changes: 9 additions & 2 deletions src/services/litegraphService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -261,7 +261,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 }

Expand Down Expand Up @@ -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 }

Expand Down Expand Up @@ -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')
}
}

/**
Expand Down
31 changes: 30 additions & 1 deletion src/stores/nodeDefStore.ts
Original file line number Diff line number Diff line change
@@ -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 {
Expand All @@ -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'
Expand All @@ -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
/**
Expand Down Expand Up @@ -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 ?? {}
Expand Down Expand Up @@ -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 ''
}
}
Expand Down Expand Up @@ -299,12 +304,27 @@ export interface NodeDefFilter {
}

export const useNodeDefStore = defineStore('nodeDef', () => {
const settingStore = useSettingStore()

const nodeDefsByName = ref<Record<string, ComfyNodeDefImpl>>({})
const nodeDefsByDisplayName = ref<Record<string, ComfyNodeDefImpl>>({})
const showDeprecated = ref(false)
const showExperimental = ref(false)
const showDevOnly = computed(() => settingStore.get('Comfy.DevMode'))
const nodeDefFilters = ref<NodeDefFilter[]>([])

// 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
Expand Down Expand Up @@ -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({
Expand All @@ -446,6 +474,7 @@ export const useNodeDefStore = defineStore('nodeDef', () => {
nodeDefsByDisplayName,
showDeprecated,
showExperimental,
showDevOnly,
nodeDefFilters,

nodeDefs,
Expand Down
8 changes: 4 additions & 4 deletions src/utils/nodeFilterUtil.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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('')
Expand Down Expand Up @@ -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])
Expand Down