diff --git a/browser_tests/fixtures/ComfyPage.ts b/browser_tests/fixtures/ComfyPage.ts index bd6198251..bb3b046ea 100644 --- a/browser_tests/fixtures/ComfyPage.ts +++ b/browser_tests/fixtures/ComfyPage.ts @@ -840,6 +840,11 @@ export class ComfyPage { .activeWorkflow?.isModified }) } + async getExportedWorkflow({ api = false }: { api?: boolean } = {}) { + return this.page.evaluate(async (api) => { + return (await window['app'].graphToPrompt())[api ? 'output' : 'workflow'] + }, api) + } } export const comfyPageFixture = base.extend<{ comfyPage: ComfyPage }>({ diff --git a/browser_tests/fixtures/components/Topbar.ts b/browser_tests/fixtures/components/Topbar.ts index b57461e59..44ac09db6 100644 --- a/browser_tests/fixtures/components/Topbar.ts +++ b/browser_tests/fixtures/components/Topbar.ts @@ -40,7 +40,14 @@ export class Topbar { return this._saveWorkflow(workflowName, 'Save As') } - async _saveWorkflow(workflowName: string, command: 'Save' | 'Save As') { + exportWorkflow(workflowName: string): Promise { + return this._saveWorkflow(workflowName, 'Export') + } + + async _saveWorkflow( + workflowName: string, + command: 'Save' | 'Save As' | 'Export' + ) { await this.triggerTopbarCommand(['Workflow', command]) await this.getSaveDialog().fill(workflowName) await this.page.keyboard.press('Enter') diff --git a/browser_tests/menu.spec.ts b/browser_tests/menu.spec.ts index 5e67c4fa8..ded2772ec 100644 --- a/browser_tests/menu.spec.ts +++ b/browser_tests/menu.spec.ts @@ -435,6 +435,56 @@ test.describe('Menu', () => { ).toEqual(['*Unsaved Workflow.json', 'workflow3.json', 'workflow4.json']) }) + test('Exported workflow does not contain localized slot names', async ({ + comfyPage + }) => { + await comfyPage.loadWorkflow('default') + const exportedWorkflow = await comfyPage.getExportedWorkflow({ + api: false + }) + expect(exportedWorkflow).toBeDefined() + for (const node of exportedWorkflow.nodes) { + for (const slot of node.inputs) { + expect(slot.localized_name).toBeUndefined() + expect(slot.label).toBeUndefined() + } + for (const slot of node.outputs) { + expect(slot.localized_name).toBeUndefined() + expect(slot.label).toBeUndefined() + } + } + }) + + test('Can export same workflow with different locales', async ({ + comfyPage + }) => { + await comfyPage.loadWorkflow('default') + + // Setup download listener before triggering the export + const downloadPromise = comfyPage.page.waitForEvent('download') + await comfyPage.menu.topbar.exportWorkflow('exported_default.json') + + // Wait for the download and get the file content + const download = await downloadPromise + expect(download.suggestedFilename()).toBe('exported_default.json') + + // Get the exported workflow content + const downloadedContent = await comfyPage.getExportedWorkflow({ + api: false + }) + + await comfyPage.setSetting('Comfy.Locale', 'zh') + await comfyPage.reload() + + const downloadedContentZh = await comfyPage.getExportedWorkflow({ + api: false + }) + + // Compare the exported workflow with the original + expect(downloadedContent).toBeDefined() + expect(downloadedContent).toEqual(downloadedContentZh) + }) + test('Can save workflow as with same name', async ({ comfyPage }) => { await comfyPage.menu.topbar.saveWorkflow('workflow5.json') expect( diff --git a/package-lock.json b/package-lock.json index 0c7401158..c14442128 100644 --- a/package-lock.json +++ b/package-lock.json @@ -11,7 +11,7 @@ "dependencies": { "@atlaskit/pragmatic-drag-and-drop": "^1.3.1", "@comfyorg/comfyui-electron-types": "^0.3.32", - "@comfyorg/litegraph": "^0.8.44", + "@comfyorg/litegraph": "^0.8.45", "@primevue/themes": "^4.0.5", "@vueuse/core": "^11.0.0", "@xterm/addon-fit": "^0.10.0", @@ -1957,9 +1957,9 @@ "license": "GPL-3.0-only" }, "node_modules/@comfyorg/litegraph": { - "version": "0.8.44", - "resolved": "https://registry.npmjs.org/@comfyorg/litegraph/-/litegraph-0.8.44.tgz", - "integrity": "sha512-lQqqEO7MXq0DFS5Rer8JJh5t3rajMbBLSeKUg84EPlZjv49nrn8pFwQp439awRrsRg8nPqGCD48Pck0K/Coknw==", + "version": "0.8.45", + "resolved": "https://registry.npmjs.org/@comfyorg/litegraph/-/litegraph-0.8.45.tgz", + "integrity": "sha512-ypmURaX4QhvQOXrW7NnkDA1Zn4s5CcqsTqCUtvEPQYrizPyt58zPt3QB0duu9MNelRVpbr97XlP/Ag3oFd75Eg==", "license": "MIT" }, "node_modules/@cspotcode/source-map-support": { diff --git a/package.json b/package.json index 10c0dd39a..34eab71d0 100644 --- a/package.json +++ b/package.json @@ -83,7 +83,7 @@ "dependencies": { "@atlaskit/pragmatic-drag-and-drop": "^1.3.1", "@comfyorg/comfyui-electron-types": "^0.3.32", - "@comfyorg/litegraph": "^0.8.44", + "@comfyorg/litegraph": "^0.8.45", "@primevue/themes": "^4.0.5", "@vueuse/core": "^11.0.0", "@xterm/addon-fit": "^0.10.0", diff --git a/src/scripts/app.ts b/src/scripts/app.ts index 098e57cb4..172e60933 100644 --- a/src/scripts/app.ts +++ b/src/scripts/app.ts @@ -63,6 +63,7 @@ import { useWidgetStore } from '@/stores/widgetStore' import { deserialiseAndCreate } from '@/extensions/core/vintageClipboard' import { st } from '@/i18n' import { normalizeI18nKey } from '@/utils/formatUtil' +import { ISerialisedGraph } from '@comfyorg/litegraph' export const ANIM_PREVIEW_WIDGET = '$$comfy_animation_preview' @@ -1942,7 +1943,7 @@ export class ComfyApp { : { shape: LiteGraph.SlotShape.HollowCircle } const inputOptions = { ...shapeOptions, - label: st(nameKey, inputName) + localized_name: st(nameKey, inputName) } this.addInput(inputName, type, inputOptions) widgetCreated = false @@ -1984,7 +1985,7 @@ export class ComfyApp { // e.g. // - type ("INT"); name ("Positive") => translate name // - type ("FLOAT"); name ("FLOAT") => translate type - label: + localized_name: output !== outputName ? st(nameKey, outputName) : st(typeKey, outputName) @@ -2002,7 +2003,7 @@ export class ComfyApp { } configure(data: any) { - // Keep 'name', 'type', 'shape', and 'label' information from the original node definition. + // Keep 'name', 'type', 'shape', and 'localized_name' information from the original node definition. const merge = ( current: Record, incoming: Record @@ -2013,7 +2014,7 @@ export class ComfyApp { this.inputs.push(current as INodeInputSlot) return incoming } - for (const key of ['name', 'type', 'shape', 'label']) { + for (const key of ['name', 'type', 'shape', 'localized_name']) { if (current[key] !== undefined) { result[key] = current[key] } @@ -2353,6 +2354,17 @@ export class ComfyApp { } const workflow = this.serializeGraph(graph) + + // Remove localized_name from the workflow + for (const node of workflow.nodes) { + for (const slot of node.inputs) { + delete slot.localized_name + } + for (const slot of node.outputs) { + delete slot.localized_name + } + } + const output = {} // Process nodes in order of execution for (const outerNode of graph.computeExecutionOrder(false)) {