+
-
+
diff --git a/src/components/card/CardContainer.vue b/src/components/card/CardContainer.vue
index 1a17d5659b..390e441a0b 100644
--- a/src/components/card/CardContainer.vue
+++ b/src/components/card/CardContainer.vue
@@ -8,15 +8,21 @@
diff --git a/src/components/common/TreeExplorerTreeNode.spec.ts b/src/components/common/TreeExplorerTreeNode.test.ts
similarity index 100%
rename from src/components/common/TreeExplorerTreeNode.spec.ts
rename to src/components/common/TreeExplorerTreeNode.test.ts
diff --git a/src/components/custom/widget/WorkflowTemplateSelectorDialog.vue b/src/components/custom/widget/WorkflowTemplateSelectorDialog.vue
new file mode 100644
index 0000000000..5e8397880d
--- /dev/null
+++ b/src/components/custom/widget/WorkflowTemplateSelectorDialog.vue
@@ -0,0 +1,757 @@
+
+
+
+
+
+
+
+
+ {{
+ $t('sideToolbar.templates', 'Templates')
+ }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{ pageTitle }}
+
+
+
+
+
+
+
+
+
+ {{ $t('templateWorkflows.noResults', 'No templates found') }}
+
+
+ {{
+ $t(
+ 'templateWorkflows.noResultsHint',
+ 'Try adjusting your search or filters'
+ )
+ }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{
+ getTemplateTitle(
+ template,
+ getEffectiveSourceModule(template)
+ )
+ }}
+
+
+
+
+ {{ getTemplateDescription(template) }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{ $t('templateWorkflows.loadingMore', 'Loading more...') }}
+
+
+
+
+
+ {{
+ $t('templateWorkflows.resultsCount', {
+ count: filteredCount,
+ total: totalCount
+ })
+ }}
+
+
+
+
+
+
+
+
diff --git a/src/components/dialog/content/LoadWorkflowWarning.vue b/src/components/dialog/content/LoadWorkflowWarning.vue
index a89c94981e..17c38c29b6 100644
--- a/src/components/dialog/content/LoadWorkflowWarning.vue
+++ b/src/components/dialog/content/LoadWorkflowWarning.vue
@@ -58,11 +58,11 @@ import { useI18n } from 'vue-i18n'
import NoResultsPlaceholder from '@/components/common/NoResultsPlaceholder.vue'
import MissingCoreNodesMessage from '@/components/dialog/content/MissingCoreNodesMessage.vue'
-import { useMissingNodes } from '@/composables/nodePack/useMissingNodes'
import { useToastStore } from '@/platform/updates/common/toastStore'
import { useDialogStore } from '@/stores/dialogStore'
import type { MissingNodeType } from '@/types/comfy'
import PackInstallButton from '@/workbench/extensions/manager/components/manager/button/PackInstallButton.vue'
+import { useMissingNodes } from '@/workbench/extensions/manager/composables/nodePack/useMissingNodes'
import { useManagerState } from '@/workbench/extensions/manager/composables/useManagerState'
import { useComfyManagerStore } from '@/workbench/extensions/manager/stores/comfyManagerStore'
import { ManagerTab } from '@/workbench/extensions/manager/types/comfyManagerTypes'
diff --git a/src/components/dialog/content/setting/SettingItem.spec.ts b/src/components/dialog/content/setting/SettingItem.test.ts
similarity index 100%
rename from src/components/dialog/content/setting/SettingItem.spec.ts
rename to src/components/dialog/content/setting/SettingItem.test.ts
diff --git a/src/components/dialog/content/setting/UsageLogsTable.spec.ts b/src/components/dialog/content/setting/UsageLogsTable.test.ts
similarity index 100%
rename from src/components/dialog/content/setting/UsageLogsTable.spec.ts
rename to src/components/dialog/content/setting/UsageLogsTable.test.ts
diff --git a/src/components/dialog/content/signin/SignInForm.spec.ts b/src/components/dialog/content/signin/SignInForm.test.ts
similarity index 100%
rename from src/components/dialog/content/signin/SignInForm.spec.ts
rename to src/components/dialog/content/signin/SignInForm.test.ts
diff --git a/src/components/graph/GraphCanvas.vue b/src/components/graph/GraphCanvas.vue
index ac33aa2804..260f4b9b65 100644
--- a/src/components/graph/GraphCanvas.vue
+++ b/src/components/graph/GraphCanvas.vue
@@ -62,6 +62,7 @@
+
@@ -87,6 +88,7 @@ import GraphCanvasMenu from '@/components/graph/GraphCanvasMenu.vue'
import NodeTooltip from '@/components/graph/NodeTooltip.vue'
import SelectionToolbox from '@/components/graph/SelectionToolbox.vue'
import TitleEditor from '@/components/graph/TitleEditor.vue'
+import NodeOptions from '@/components/graph/selectionToolbox/NodeOptions.vue'
import NodeSearchboxPopover from '@/components/searchbox/NodeSearchBoxPopover.vue'
import SideToolbar from '@/components/sidebar/SideToolbar.vue'
import SecondRowWorkflowTabs from '@/components/topbar/SecondRowWorkflowTabs.vue'
@@ -165,7 +167,7 @@ const { shouldRenderVueNodes } = useVueFeatureFlags()
// Vue node system
const vueNodeLifecycle = useVueNodeLifecycle()
-const viewportCulling = useViewportCulling()
+const { handleTransformUpdate } = useViewportCulling()
const handleVueNodeLifecycleReset = async () => {
if (shouldRenderVueNodes.value) {
@@ -187,8 +189,9 @@ watch(
}
)
-const allNodes = viewportCulling.allNodes
-const handleTransformUpdate = viewportCulling.handleTransformUpdate
+const allNodes = computed(() =>
+ Array.from(vueNodeLifecycle.vueNodeData.value.values())
+)
watchEffect(() => {
nodeDefStore.showDeprecated = settingStore.get('Comfy.Node.ShowDeprecated')
@@ -307,13 +310,27 @@ watch(
removeSlotError(node)
const nodeErrors = lastNodeErrors?.[node.id]
if (!nodeErrors) continue
- for (const error of nodeErrors.errors) {
- if (error.extra_info && error.extra_info.input_name) {
- const inputIndex = node.findInputSlot(error.extra_info.input_name)
+
+ const validErrors = nodeErrors.errors.filter(
+ (error) => error.extra_info?.input_name !== undefined
+ )
+ const slotErrorsChanged =
+ validErrors.length > 0 &&
+ validErrors.some((error) => {
+ const inputName = error.extra_info!.input_name!
+ const inputIndex = node.findInputSlot(inputName)
if (inputIndex !== -1) {
node.inputs[inputIndex].hasErrors = true
+ return true
}
- }
+ return false
+ })
+
+ // Trigger Vue node data update if slot errors changed
+ if (slotErrorsChanged && comfyApp.graph.onTrigger) {
+ comfyApp.graph.onTrigger('node:slot-errors:changed', {
+ nodeId: node.id
+ })
}
}
diff --git a/src/components/graph/SelectionToolbox.spec.ts b/src/components/graph/SelectionToolbox.test.ts
similarity index 97%
rename from src/components/graph/SelectionToolbox.spec.ts
rename to src/components/graph/SelectionToolbox.test.ts
index 85acaf6cfc..e8e689bb25 100644
--- a/src/components/graph/SelectionToolbox.spec.ts
+++ b/src/components/graph/SelectionToolbox.test.ts
@@ -450,9 +450,9 @@ describe('SelectionToolbox', () => {
describe('Event Handling', () => {
it('should handle wheel events', async () => {
const mockCanvasInteractions = vi.mocked(useCanvasInteractions)
- const handleWheelSpy = vi.fn()
+ const forwardEventToCanvasSpy = vi.fn()
mockCanvasInteractions.mockReturnValue({
- handleWheel: handleWheelSpy
+ forwardEventToCanvas: forwardEventToCanvasSpy
} as any)
const mockExtensionService = vi.mocked(useExtensionService)
@@ -467,7 +467,7 @@ describe('SelectionToolbox', () => {
const panel = wrapper.find('.panel')
await panel.trigger('wheel')
- expect(handleWheelSpy).toHaveBeenCalled()
+ expect(forwardEventToCanvasSpy).toHaveBeenCalled()
})
})
@@ -480,13 +480,6 @@ describe('SelectionToolbox', () => {
} as any)
})
- it('should still show MoreOptions when no items selected', () => {
- canvasStore.selectedItems = []
- const wrapper = mountComponent()
-
- expect(wrapper.find('.more-options').exists()).toBe(true)
- })
-
it('should hide most buttons when no items selected', () => {
canvasStore.selectedItems = []
const wrapper = mountComponent()
diff --git a/src/components/graph/SelectionToolbox.vue b/src/components/graph/SelectionToolbox.vue
index f0a18ed3e3..d3622a5150 100644
--- a/src/components/graph/SelectionToolbox.vue
+++ b/src/components/graph/SelectionToolbox.vue
@@ -13,7 +13,7 @@
header: 'hidden',
content: 'p-1 h-10 flex flex-row gap-1'
}"
- @wheel="canvasInteractions.handleWheel"
+ @wheel="canvasInteractions.forwardEventToCanvas"
>
@@ -38,7 +38,7 @@
:command="command"
/>
-
+
@@ -68,7 +68,7 @@ import { useExtensionService } from '@/services/extensionService'
import { type ComfyCommandImpl, useCommandStore } from '@/stores/commandStore'
import FrameNodes from './selectionToolbox/FrameNodes.vue'
-import MoreOptions from './selectionToolbox/MoreOptions.vue'
+import NodeOptionsButton from './selectionToolbox/NodeOptionsButton.vue'
import VerticalDivider from './selectionToolbox/VerticalDivider.vue'
const commandStore = useCommandStore()
diff --git a/src/components/graph/selectionToolbox/BypassButton.spec.ts b/src/components/graph/selectionToolbox/BypassButton.test.ts
similarity index 100%
rename from src/components/graph/selectionToolbox/BypassButton.spec.ts
rename to src/components/graph/selectionToolbox/BypassButton.test.ts
diff --git a/src/components/graph/selectionToolbox/ColorPickerButton.spec.ts b/src/components/graph/selectionToolbox/ColorPickerButton.test.ts
similarity index 100%
rename from src/components/graph/selectionToolbox/ColorPickerButton.spec.ts
rename to src/components/graph/selectionToolbox/ColorPickerButton.test.ts
diff --git a/src/components/graph/selectionToolbox/ExecuteButton.spec.ts b/src/components/graph/selectionToolbox/ExecuteButton.test.ts
similarity index 100%
rename from src/components/graph/selectionToolbox/ExecuteButton.spec.ts
rename to src/components/graph/selectionToolbox/ExecuteButton.test.ts
diff --git a/src/components/graph/selectionToolbox/InfoButton.spec.ts b/src/components/graph/selectionToolbox/InfoButton.test.ts
similarity index 100%
rename from src/components/graph/selectionToolbox/InfoButton.spec.ts
rename to src/components/graph/selectionToolbox/InfoButton.test.ts
diff --git a/src/components/graph/selectionToolbox/MoreOptions.vue b/src/components/graph/selectionToolbox/NodeOptions.vue
similarity index 82%
rename from src/components/graph/selectionToolbox/MoreOptions.vue
rename to src/components/graph/selectionToolbox/NodeOptions.vue
index f40a49b603..beda4e6ed7 100644
--- a/src/components/graph/selectionToolbox/MoreOptions.vue
+++ b/src/components/graph/selectionToolbox/NodeOptions.vue
@@ -1,20 +1,5 @@