From 4ca6220adf4961afacc1b1faac1c4ff8a8475054 Mon Sep 17 00:00:00 2001 From: pythongosssss <125205205+pythongosssss@users.noreply.github.com> Date: Thu, 14 Aug 2025 22:53:46 +0100 Subject: [PATCH] Refactor app menu items (#4665) * Restructures the application menu - rename Workflow to File - move new & template items to top level - add View menu and related sub items Commands - add "active" state getter shown as checkmark in the menu Node side panel - add refresh node defs - change reset view icon Help center - change to use store for visibility Fixes - Fix bug with mouse down where if you drag mouse out, mouse up wasn't caught - Fix issue with canvas info setting not triggering a redraw on change * Fix missing translation warnings * Add separator under new * tidy * Update locales [skip ci] * fix some tests * fix * Hide icon if there is an active state within the menu item group * Update locales [skip ci] * Fix tests * Implement feedback - Remove queue, node lib, model lib, workflows, manager, help center - Add minimap, link visibility * Update locales [skip ci] * Add plus icon on "New" menu item * Update locales [skip ci] * Fix test * Fix translations * Update locales [skip ci] * Update locales [skip ci] --------- Co-authored-by: github-actions --- browser_tests/fixtures/components/Topbar.ts | 13 +++- browser_tests/tests/groupNode.spec.ts | 9 +-- browser_tests/tests/interaction.spec.ts | 2 +- browser_tests/tests/menu.spec.ts | 2 +- browser_tests/tests/rerouteNode.spec.ts | 2 +- .../tests/workflowTabThumbnail.spec.ts | 6 +- .../sidebar/SidebarHelpCenterIcon.vue | 11 +-- .../sidebar/tabs/NodeLibrarySidebarTab.vue | 11 ++- src/components/topbar/CommandMenubar.vue | 68 +++++++++++++++++-- src/composables/useCoreCommands.ts | 47 +++++++++++-- src/composables/useLitegraphSettings.ts | 1 + src/constants/coreMenuCommands.ts | 9 ++- src/locales/ar/commands.json | 9 +++ src/locales/ar/main.json | 26 ++++--- src/locales/en/commands.json | 9 +++ src/locales/en/main.json | 26 ++++--- src/locales/es/commands.json | 9 +++ src/locales/es/main.json | 26 ++++--- src/locales/fr/commands.json | 9 +++ src/locales/fr/main.json | 26 ++++--- src/locales/ja/commands.json | 9 +++ src/locales/ja/main.json | 26 ++++--- src/locales/ko/commands.json | 9 +++ src/locales/ko/main.json | 26 ++++--- src/locales/ru/commands.json | 9 +++ src/locales/ru/main.json | 26 ++++--- src/locales/zh-TW/commands.json | 9 +++ src/locales/zh-TW/main.json | 26 ++++--- src/locales/zh/commands.json | 9 +++ src/locales/zh/main.json | 26 ++++--- src/stores/commandStore.ts | 3 + src/stores/helpCenterStore.ts | 25 +++++++ src/stores/menuItemStore.ts | 15 +++- src/stores/workspace/sidebarTabStore.ts | 38 +++++++++++ src/utils/mouseDownUtil.ts | 13 ++-- 35 files changed, 451 insertions(+), 139 deletions(-) create mode 100644 src/stores/helpCenterStore.ts diff --git a/browser_tests/fixtures/components/Topbar.ts b/browser_tests/fixtures/components/Topbar.ts index 81fcf6764..b138ff7b7 100644 --- a/browser_tests/fixtures/components/Topbar.ts +++ b/browser_tests/fixtures/components/Topbar.ts @@ -50,7 +50,7 @@ export class Topbar { workflowName: string, command: 'Save' | 'Save As' | 'Export' ) { - await this.triggerTopbarCommand(['Workflow', command]) + await this.triggerTopbarCommand(['File', command]) await this.getSaveDialog().fill(workflowName) await this.page.keyboard.press('Enter') @@ -72,8 +72,8 @@ export class Topbar { } async triggerTopbarCommand(path: string[]) { - if (path.length < 2) { - throw new Error('Path is too short') + if (path.length < 1) { + throw new Error('Path cannot be empty') } const menu = await this.openTopbarMenu() @@ -85,6 +85,13 @@ export class Topbar { .locator('.p-tieredmenu-item') .filter({ has: topLevelMenuItem }) await topLevelMenu.waitFor({ state: 'visible' }) + + // Handle top-level commands (like "New") + if (path.length === 1) { + await topLevelMenuItem.click() + return + } + await topLevelMenu.hover() let currentMenu = topLevelMenu diff --git a/browser_tests/tests/groupNode.spec.ts b/browser_tests/tests/groupNode.spec.ts index a6cb1e67f..fb282e6a7 100644 --- a/browser_tests/tests/groupNode.spec.ts +++ b/browser_tests/tests/groupNode.spec.ts @@ -268,10 +268,7 @@ test.describe('Group Node', () => { await comfyPage.setSetting('Comfy.ConfirmClear', false) // Clear workflow - await comfyPage.menu.topbar.triggerTopbarCommand([ - 'Edit', - 'Clear Workflow' - ]) + await comfyPage.executeCommand('Comfy.ClearWorkflow') await comfyPage.ctrlV() await verifyNodeLoaded(comfyPage, 1) @@ -280,7 +277,7 @@ test.describe('Group Node', () => { test('Copies and pastes group node into a newly created blank workflow', async ({ comfyPage }) => { - await comfyPage.menu.topbar.triggerTopbarCommand(['Workflow', 'New']) + await comfyPage.menu.topbar.triggerTopbarCommand(['New']) await comfyPage.ctrlV() await verifyNodeLoaded(comfyPage, 1) }) @@ -296,7 +293,7 @@ test.describe('Group Node', () => { test('Serializes group node after copy and paste across workflows', async ({ comfyPage }) => { - await comfyPage.menu.topbar.triggerTopbarCommand(['Workflow', 'New']) + await comfyPage.menu.topbar.triggerTopbarCommand(['New']) await comfyPage.ctrlV() const currentGraphState = await comfyPage.page.evaluate(() => window['app'].graph.serialize() diff --git a/browser_tests/tests/interaction.spec.ts b/browser_tests/tests/interaction.spec.ts index a19248c2e..934107792 100644 --- a/browser_tests/tests/interaction.spec.ts +++ b/browser_tests/tests/interaction.spec.ts @@ -684,7 +684,7 @@ test.describe('Load workflow', () => { workflowA = generateUniqueFilename() await comfyPage.menu.topbar.saveWorkflow(workflowA) workflowB = generateUniqueFilename() - await comfyPage.menu.topbar.triggerTopbarCommand(['Workflow', 'New']) + await comfyPage.menu.topbar.triggerTopbarCommand(['New']) await comfyPage.menu.topbar.saveWorkflow(workflowB) // Wait for localStorage to persist the workflow paths before reloading diff --git a/browser_tests/tests/menu.spec.ts b/browser_tests/tests/menu.spec.ts index a771257f2..1eabe222c 100644 --- a/browser_tests/tests/menu.spec.ts +++ b/browser_tests/tests/menu.spec.ts @@ -75,7 +75,7 @@ test.describe('Menu', () => { test('Displays keybinding next to item', async ({ comfyPage }) => { await comfyPage.menu.topbar.openTopbarMenu() - const workflowMenuItem = comfyPage.menu.topbar.getMenuItem('Workflow') + const workflowMenuItem = comfyPage.menu.topbar.getMenuItem('File') await workflowMenuItem.hover() const exportTag = comfyPage.page.locator('.keybinding-tag', { hasText: 'Ctrl + s' diff --git a/browser_tests/tests/rerouteNode.spec.ts b/browser_tests/tests/rerouteNode.spec.ts index 981f62a07..fb39f208e 100644 --- a/browser_tests/tests/rerouteNode.spec.ts +++ b/browser_tests/tests/rerouteNode.spec.ts @@ -18,7 +18,7 @@ test.describe('Reroute Node', () => { [workflowName]: workflowName }) await comfyPage.setup() - await comfyPage.menu.topbar.triggerTopbarCommand(['Workflow', 'New']) + await comfyPage.menu.topbar.triggerTopbarCommand(['New']) // Insert the workflow const workflowsTab = comfyPage.menu.workflowsTab diff --git a/browser_tests/tests/workflowTabThumbnail.spec.ts b/browser_tests/tests/workflowTabThumbnail.spec.ts index a1869430b..31b15067f 100644 --- a/browser_tests/tests/workflowTabThumbnail.spec.ts +++ b/browser_tests/tests/workflowTabThumbnail.spec.ts @@ -63,7 +63,7 @@ test.describe('Workflow Tab Thumbnails', () => { test('Should show thumbnail when hovering over a non-active tab', async ({ comfyPage }) => { - await comfyPage.menu.topbar.triggerTopbarCommand(['Workflow', 'New']) + await comfyPage.menu.topbar.triggerTopbarCommand(['New']) const thumbnailImg = await getTabThumbnailImage( comfyPage, 0, @@ -73,7 +73,7 @@ test.describe('Workflow Tab Thumbnails', () => { }) test('Should not show thumbnail for active tab', async ({ comfyPage }) => { - await comfyPage.menu.topbar.triggerTopbarCommand(['Workflow', 'New']) + await comfyPage.menu.topbar.triggerTopbarCommand(['New']) const thumbnailImg = await getTabThumbnailImage( comfyPage, 1, @@ -105,7 +105,7 @@ test.describe('Workflow Tab Thumbnails', () => { await comfyPage.nextFrame() // Create a new workflow (tab 1) which will be empty - await comfyPage.menu.topbar.triggerTopbarCommand(['Workflow', 'New']) + await comfyPage.menu.topbar.triggerTopbarCommand(['New']) await comfyPage.nextFrame() // Now we have two tabs: tab 0 (default workflow with nodes) and tab 1 (empty) diff --git a/src/components/sidebar/SidebarHelpCenterIcon.vue b/src/components/sidebar/SidebarHelpCenterIcon.vue index c37cd973e..1a15b8487 100644 --- a/src/components/sidebar/SidebarHelpCenterIcon.vue +++ b/src/components/sidebar/SidebarHelpCenterIcon.vue @@ -58,11 +58,12 @@