From 87106ccb9552e35c3c1a688c8c0a057c7a67eb65 Mon Sep 17 00:00:00 2001 From: Jin Yi Date: Thu, 20 Nov 2025 14:22:32 +0900 Subject: [PATCH] [bugfix] Fix execute button incorrectly disabled on empty workflows (#6774) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Summary Fixes a bug where the queue/execute button was incorrectly disabled with a warning icon when creating a new empty workflow, due to stale missing nodes data persisting from a previous workflow. ## Root Cause When switching from a workflow with missing nodes to an empty workflow, the `getWorkflowPacks()` function in `useWorkflowPacks.ts` would return early without clearing the `workflowPacks.value` ref, causing stale missing node data to persist. ## Changes - **`useWorkflowPacks.ts`**: Explicitly clear `workflowPacks.value = []` when switching to empty workflow - **`useMissingNodes.test.ts`**: Add test case to verify missing nodes state clears when switching to empty workflow ## Test Plan - [x] Added unit test covering the empty workflow scenario - [x] All 20 unit tests pass - [x] TypeScript type checking passes - [x] Manual verification: Create workflow with missing nodes → Create new empty workflow → Button should be enabled ## Before 1. Open workflow with missing nodes → Button disabled ✅ (correct) 2. Create new empty workflow → Button still disabled ❌ (bug) 3. Click valid workflow → Button enabled ✅ ## After 1. Open workflow with missing nodes → Button disabled ✅ 2. Create new empty workflow → Button enabled ✅ (fixed) 3. Click valid workflow → Button enabled ✅ [screen-capture (2).webm](https://github.com/user-attachments/assets/833355d6-6b4b-4e77-94b9-d7964454cfce) 🤖 Generated with [Claude Code](https://claude.com/claude-code) ┆Issue is synchronized with this [Notion page](https://www.notion.so/PR-6774-bugfix-Fix-execute-button-incorrectly-disabled-on-empty-workflows-2b16d73d365081e3a050c3f7c0a20cc6) by [Unito](https://www.unito.io) --- .../composables/nodePack/useWorkflowPacks.ts | 5 +++- .../tests/composables/useMissingNodes.test.ts | 26 +++++++++++++++++++ 2 files changed, 30 insertions(+), 1 deletion(-) diff --git a/src/workbench/extensions/manager/composables/nodePack/useWorkflowPacks.ts b/src/workbench/extensions/manager/composables/nodePack/useWorkflowPacks.ts index b7ff5b38d..b83508ddd 100644 --- a/src/workbench/extensions/manager/composables/nodePack/useWorkflowPacks.ts +++ b/src/workbench/extensions/manager/composables/nodePack/useWorkflowPacks.ts @@ -114,7 +114,10 @@ export const useWorkflowPacks = (options: UseNodePacksOptions = {}) => { const getWorkflowPacks = async () => { if (!app.graph) return [] const allNodes = collectAllNodes(app.graph) - if (!allNodes.length) return [] + if (!allNodes.length) { + workflowPacks.value = [] + return [] + } const packs = await Promise.all(allNodes.map(workflowNodeToPack)) workflowPacks.value = packs.filter((pack) => pack !== undefined) } diff --git a/tests-ui/tests/composables/useMissingNodes.test.ts b/tests-ui/tests/composables/useMissingNodes.test.ts index 9dbfa8a56..41bd098bb 100644 --- a/tests-ui/tests/composables/useMissingNodes.test.ts +++ b/tests-ui/tests/composables/useMissingNodes.test.ts @@ -277,6 +277,32 @@ describe('useMissingNodes', () => { // Should update missing packs (2 missing since pack-3 is installed) expect(missingNodePacks.value).toHaveLength(2) }) + + it('clears missing nodes when switching to empty workflow', async () => { + const workflowPacksRef = ref(mockWorkflowPacks) + mockUseWorkflowPacks.mockReturnValue({ + workflowPacks: workflowPacksRef, + isLoading: ref(false), + error: ref(null), + startFetchWorkflowPacks: mockStartFetchWorkflowPacks, + isReady: ref(true), + filterWorkflowPack: vi.fn() + }) + + const { hasMissingNodes, missingNodePacks } = useMissingNodes() + + // Should have missing nodes initially (2 missing since pack-3 is installed) + expect(missingNodePacks.value).toHaveLength(2) + expect(hasMissingNodes.value).toBe(true) + + // Switch to empty workflow (simulates creating a new empty workflow) + workflowPacksRef.value = [] + await nextTick() + + // Should clear missing nodes + expect(missingNodePacks.value).toHaveLength(0) + expect(hasMissingNodes.value).toBe(false) + }) }) describe('missing core nodes detection', () => {