From 8dd5a9900b10b040a6f6b7e799a2474ced67e902 Mon Sep 17 00:00:00 2001 From: Jin Yi Date: Sun, 16 Nov 2025 05:09:44 +0900 Subject: [PATCH] [refactor] Unify Cloud/OSS Missing Nodes modal (#6673) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Summary - Merged separate Cloud and OSS workflow warning modals into single unified modal - Removed legacy LoadWorkflowWarning.vue - Renamed CloudMissingNodes* components to MissingNodes* for clarity - Environment branching now handled internally via isCloud flag - Restructured i18n: removed loadWorkflowWarning, added missingNodes.cloud/oss sections - Improved OSS button styling to match Cloud consistency ## Key Changes - **OSS**: "Open Manager" + "Install All" buttons - **Cloud**: "Learn More" + "Got It" buttons (unchanged) - Single unified modal displays different UI/text based on environment ## ๐Ÿ“ Note on File Renames This PR renames the following files: - `CloudMissingNodesHeader.vue` โ†’ `MissingNodesHeader.vue` (R053, 53% similarity) - `CloudMissingNodesContent.vue` โ†’ `MissingNodesContent.vue` (R067, 67% similarity) - `LoadWorkflowWarning.vue` โ†’ `MissingNodesFooter.vue` (R051, 51% similarity) - `CloudMissingNodesFooter.vue` โ†’ Deleted (replaced by new MissingNodesFooter) **Why GitHub PR UI doesn't show renames properly:** GitHub detects renames only when file similarity is above 70%. In this PR, the Cloud/OSS unification significantly modified file contents, resulting in 51-67% similarity. However, **Git history correctly records these as renames**. You can verify with: ```bash git show --name-status ``` While GitHub UI shows "additions/deletions", these are actually rename + modification operations. ## Test Plan - [x] Test OSS mode: missing nodes modal shows "Open Manager" and "Install All" buttons - [x] Test Cloud mode: missing nodes modal shows "Learn More" and "Got It" buttons - [x] Verify Install All button functionality in OSS - [x] Verify modal closes automatically after all nodes are installed (OSS) [missingnodes.webm](https://github.com/user-attachments/assets/36d3b4b0-ff8b-4b45-824c-3bc15d93f1a2) ๐Ÿค– Generated with [Claude Code](https://claude.com/claude-code) โ”†Issue is synchronized with this [Notion page](https://www.notion.so/PR-6673-refactor-Unify-Cloud-OSS-Missing-Nodes-modal-2aa6d73d365081a88827d0fa85db4c63) by [Unito](https://www.unito.io) --------- Co-authored-by: Claude --- src/components/button/IconTextButton.vue | 2 +- .../content/CloudMissingNodesFooter.vue | 37 ----- .../content/MissingCoreNodesMessage.vue | 6 +- ...desContent.vue => MissingNodesContent.vue} | 24 ++- ...flowWarning.vue => MissingNodesFooter.vue} | 141 ++++++------------ ...NodesHeader.vue => MissingNodesHeader.vue} | 10 +- src/locales/en/main.json | 22 ++- src/scripts/app.ts | 6 +- src/services/dialogService.ts | 29 ++-- .../manager/button/PackInstallButton.vue | 3 +- 10 files changed, 100 insertions(+), 180 deletions(-) delete mode 100644 src/components/dialog/content/CloudMissingNodesFooter.vue rename src/components/dialog/content/{CloudMissingNodesContent.vue => MissingNodesContent.vue} (62%) rename src/components/dialog/content/{LoadWorkflowWarning.vue => MissingNodesFooter.vue} (51%) rename src/components/dialog/content/{CloudMissingNodesHeader.vue => MissingNodesHeader.vue} (53%) diff --git a/src/components/button/IconTextButton.vue b/src/components/button/IconTextButton.vue index a62aab08b..2b0c8c6e7 100644 --- a/src/components/button/IconTextButton.vue +++ b/src/components/button/IconTextButton.vue @@ -32,7 +32,7 @@ defineOptions({ interface IconTextButtonProps extends BaseButtonProps { iconPosition?: 'left' | 'right' label: string - onClick: () => void + onClick?: () => void } const { diff --git a/src/components/dialog/content/CloudMissingNodesFooter.vue b/src/components/dialog/content/CloudMissingNodesFooter.vue deleted file mode 100644 index ee00cf54b..000000000 --- a/src/components/dialog/content/CloudMissingNodesFooter.vue +++ /dev/null @@ -1,37 +0,0 @@ - - - diff --git a/src/components/dialog/content/MissingCoreNodesMessage.vue b/src/components/dialog/content/MissingCoreNodesMessage.vue index 0489ac20b..ea0dbc942 100644 --- a/src/components/dialog/content/MissingCoreNodesMessage.vue +++ b/src/components/dialog/content/MissingCoreNodesMessage.vue @@ -49,14 +49,14 @@ import { computed } from 'vue' import type { LGraphNode } from '@/lib/litegraph/src/litegraph' import { useSystemStatsStore } from '@/stores/systemStatsStore' -const props = defineProps<{ +const { missingCoreNodes } = defineProps<{ missingCoreNodes: Record }>() const systemStatsStore = useSystemStatsStore() const hasMissingCoreNodes = computed(() => { - return Object.keys(props.missingCoreNodes).length > 0 + return Object.keys(missingCoreNodes).length > 0 }) // Use computed for reactive version tracking @@ -66,7 +66,7 @@ const currentComfyUIVersion = computed(() => { }) const sortedMissingCoreNodes = computed(() => { - return Object.entries(props.missingCoreNodes).sort(([a], [b]) => { + return Object.entries(missingCoreNodes).sort(([a], [b]) => { // Sort by version in descending order (newest first) return compare(b, a) // Reversed for descending order }) diff --git a/src/components/dialog/content/CloudMissingNodesContent.vue b/src/components/dialog/content/MissingNodesContent.vue similarity index 62% rename from src/components/dialog/content/CloudMissingNodesContent.vue rename to src/components/dialog/content/MissingNodesContent.vue index fc6b67c4b..90df45119 100644 --- a/src/components/dialog/content/CloudMissingNodesContent.vue +++ b/src/components/dialog/content/MissingNodesContent.vue @@ -6,15 +6,18 @@

- {{ $t('cloud.missingNodes.description') }} -

- {{ $t('cloud.missingNodes.priorityMessage') }} + {{ + isCloud + ? $t('missingNodes.cloud.description') + : $t('missingNodes.oss.description') + }}

+
{{ node.label }} + {{ node.hint }}

- {{ $t('cloud.missingNodes.replacementInstruction') }} + {{ + isCloud + ? $t('missingNodes.cloud.replacementInstruction') + : $t('missingNodes.oss.replacementInstruction') + }}

@@ -40,12 +48,18 @@ - - diff --git a/src/components/dialog/content/CloudMissingNodesHeader.vue b/src/components/dialog/content/MissingNodesHeader.vue similarity index 53% rename from src/components/dialog/content/CloudMissingNodesHeader.vue rename to src/components/dialog/content/MissingNodesHeader.vue index 21055ac56..4dd483fd0 100644 --- a/src/components/dialog/content/CloudMissingNodesHeader.vue +++ b/src/components/dialog/content/MissingNodesHeader.vue @@ -3,8 +3,16 @@

- {{ $t('cloud.missingNodes.title') }} + {{ + isCloud + ? $t('missingNodes.cloud.title') + : $t('missingNodes.oss.title') + }}

+ + diff --git a/src/locales/en/main.json b/src/locales/en/main.json index 63514a571..5bc2d9ca8 100644 --- a/src/locales/en/main.json +++ b/src/locales/en/main.json @@ -289,7 +289,7 @@ "lastUpdated": "Last Updated", "noDescription": "No description available", "installSelected": "Install Selected", - "installAllMissingNodes": "Install All Missing Nodes", + "installAllMissingNodes": "Install All", "allMissingNodesInstalled": "All missing nodes have been successfully installed", "packsSelected": "packs selected", "mixedSelectionMessage": "Cannot perform bulk action on mixed selection", @@ -1423,13 +1423,6 @@ "missingModels": "Missing Models", "missingModelsMessage": "When loading the graph, the following models were not found" }, - "loadWorkflowWarning": { - "missingNodesTitle": "Some Nodes Are Missing", - "missingNodesDescription": "When loading the graph, the following node types were not found.\nThis may also happen if your installed version is lower and that node type canโ€™t be found.", - "outdatedVersion": "Some nodes require a newer version of ComfyUI (current: {version}). Please update to use all nodes.", - "outdatedVersionGeneric": "Some nodes require a newer version of ComfyUI. Please update to use all nodes.", - "coreNodesFromVersion": "Requires ComfyUI {version}:" - }, "versionMismatchWarning": { "title": "Version Compatibility Warning", "frontendOutdated": "Frontend version {frontendVersion} is outdated. Backend requires version {requiredVersion} or higher.", @@ -2078,16 +2071,19 @@ "vueNodesMigrationMainMenu": { "message": "Switch back to Nodes 2.0 anytime from the main menu." }, - "cloud": { - "missingNodes": { + "missingNodes": { + "cloud": { "title": "These nodes aren't available on Comfy Cloud yet", "description": "This workflow uses custom nodes that aren't supported in the Cloud version yet.", "priorityMessage": "We've automatically flagged these nodes so we can prioritize adding them.", - "missingNodes": "Missing Nodes", "replacementInstruction": "In the meantime, replace these nodes (highlighted red on the canvas) with supported ones if possible, or try a different workflow.", "learnMore": "Learn more", - "gotIt": "Ok, got it", - "cannotRun": "Workflow contains unsupported nodes (highlighted red). Remove these to run the workflow. " + "gotIt": "Ok, got it" + }, + "oss": { + "title": "This workflow has missing nodes", + "description": "This workflow uses custom nodes you haven't installed yet.", + "replacementInstruction": "Install these nodes to run this workflow, or replace them with installed alternatives. Missing nodes are highlighted in red on the canvas." } } } diff --git a/src/scripts/app.ts b/src/scripts/app.ts index 7139373ec..728e35d05 100644 --- a/src/scripts/app.ts +++ b/src/scripts/app.ts @@ -1018,11 +1018,7 @@ export class ComfyApp { private showMissingNodesError(missingNodeTypes: MissingNodeType[]) { if (useSettingStore().get('Comfy.Workflow.ShowMissingNodesWarning')) { - if (isCloud) { - useDialogService().showCloudLoadWorkflowWarning({ missingNodeTypes }) - } else { - useDialogService().showLoadWorkflowWarning({ missingNodeTypes }) - } + useDialogService().showLoadWorkflowWarning({ missingNodeTypes }) } } diff --git a/src/services/dialogService.ts b/src/services/dialogService.ts index 73383f476..3f6901ebc 100644 --- a/src/services/dialogService.ts +++ b/src/services/dialogService.ts @@ -2,12 +2,11 @@ import { merge } from 'es-toolkit/compat' import type { Component } from 'vue' import ApiNodesSignInContent from '@/components/dialog/content/ApiNodesSignInContent.vue' -import CloudMissingNodesContent from '@/components/dialog/content/CloudMissingNodesContent.vue' -import CloudMissingNodesFooter from '@/components/dialog/content/CloudMissingNodesFooter.vue' -import CloudMissingNodesHeader from '@/components/dialog/content/CloudMissingNodesHeader.vue' +import MissingNodesContent from '@/components/dialog/content/MissingNodesContent.vue' +import MissingNodesFooter from '@/components/dialog/content/MissingNodesFooter.vue' +import MissingNodesHeader from '@/components/dialog/content/MissingNodesHeader.vue' import ConfirmationDialogContent from '@/components/dialog/content/ConfirmationDialogContent.vue' import ErrorDialogContent from '@/components/dialog/content/ErrorDialogContent.vue' -import LoadWorkflowWarning from '@/components/dialog/content/LoadWorkflowWarning.vue' import MissingModelsWarning from '@/components/dialog/content/MissingModelsWarning.vue' import PromptDialogContent from '@/components/dialog/content/PromptDialogContent.vue' import SignInContent from '@/components/dialog/content/SignInContent.vue' @@ -47,24 +46,15 @@ export type ConfirmationDialogType = export const useDialogService = () => { const dialogStore = useDialogStore() - function showLoadWorkflowWarning( - props: InstanceType['$props'] - ) { - dialogStore.showDialog({ - key: 'global-load-workflow-warning', - component: LoadWorkflowWarning, - props - }) - } - function showCloudLoadWorkflowWarning( - props: ComponentProps + function showLoadWorkflowWarning( + props: ComponentProps ) { dialogStore.showDialog({ - key: 'global-cloud-missing-nodes', - headerComponent: CloudMissingNodesHeader, - footerComponent: CloudMissingNodesFooter, - component: CloudMissingNodesContent, + key: 'global-missing-nodes', + headerComponent: MissingNodesHeader, + footerComponent: MissingNodesFooter, + component: MissingNodesContent, dialogComponentProps: { closable: true, pt: { @@ -550,7 +540,6 @@ export const useDialogService = () => { return { showLoadWorkflowWarning, - showCloudLoadWorkflowWarning, showMissingModelsWarning, showSettingsDialog, showAboutDialog, diff --git a/src/workbench/extensions/manager/components/manager/button/PackInstallButton.vue b/src/workbench/extensions/manager/components/manager/button/PackInstallButton.vue index 226ae4f20..1322f4db9 100644 --- a/src/workbench/extensions/manager/components/manager/button/PackInstallButton.vue +++ b/src/workbench/extensions/manager/components/manager/button/PackInstallButton.vue @@ -1,9 +1,8 @@