{{ installedVersion }}
-
+
managerStore.isPackInstalled(nodePack?.id))
+const isDisabled = computed(
+ () => isInstalled.value && !managerStore.isPackEnabled(nodePack?.id)
+)
+
const installedVersion = computed(() => {
if (!nodePack.id) return 'nightly'
const version =
diff --git a/src/components/dialog/content/manager/button/PackUpdateButton.vue b/src/components/dialog/content/manager/button/PackUpdateButton.vue
index 447f370f4..50222d105 100644
--- a/src/components/dialog/content/manager/button/PackUpdateButton.vue
+++ b/src/components/dialog/content/manager/button/PackUpdateButton.vue
@@ -1,5 +1,8 @@
()
const isUpdating = ref(false)
diff --git a/src/components/dialog/content/manager/registrySearchBar/RegistrySearchBar.vue b/src/components/dialog/content/manager/registrySearchBar/RegistrySearchBar.vue
index 56cd0f98e..ead99e062 100644
--- a/src/components/dialog/content/manager/registrySearchBar/RegistrySearchBar.vue
+++ b/src/components/dialog/content/manager/registrySearchBar/RegistrySearchBar.vue
@@ -34,7 +34,8 @@
/>
@@ -103,8 +104,11 @@ const { t } = useI18n()
const { missingNodePacks, isLoading, error } = useMissingNodes()
// Use the composable to get update available nodes
-const { hasUpdateAvailable, updateAvailableNodePacks } =
- useUpdateAvailableNodes()
+const {
+ hasUpdateAvailable,
+ enabledUpdateAvailableNodePacks,
+ hasDisabledUpdatePacks
+} = useUpdateAvailableNodes()
const hasResults = computed(
() => searchQuery.value?.trim() && searchResults?.length
diff --git a/src/composables/nodePack/useUpdateAvailableNodes.ts b/src/composables/nodePack/useUpdateAvailableNodes.ts
index 516ffffdb..593c867d5 100644
--- a/src/composables/nodePack/useUpdateAvailableNodes.ts
+++ b/src/composables/nodePack/useUpdateAvailableNodes.ts
@@ -44,9 +44,24 @@ export const useUpdateAvailableNodes = () => {
return filterOutdatedPacks(installedPacks.value)
})
- // Check if there are any outdated packs
+ // Filter only enabled outdated packs
+ const enabledUpdateAvailableNodePacks = computed(() => {
+ return updateAvailableNodePacks.value.filter((pack) =>
+ comfyManagerStore.isPackEnabled(pack.id)
+ )
+ })
+
+ // Check if there are any enabled outdated packs
const hasUpdateAvailable = computed(() => {
- return updateAvailableNodePacks.value.length > 0
+ return enabledUpdateAvailableNodePacks.value.length > 0
+ })
+
+ // Check if there are disabled packs with updates
+ const hasDisabledUpdatePacks = computed(() => {
+ return (
+ updateAvailableNodePacks.value.length >
+ enabledUpdateAvailableNodePacks.value.length
+ )
})
// Automatically fetch installed pack data when composable is used
@@ -58,7 +73,9 @@ export const useUpdateAvailableNodes = () => {
return {
updateAvailableNodePacks,
+ enabledUpdateAvailableNodePacks,
hasUpdateAvailable,
+ hasDisabledUpdatePacks,
isLoading,
error
}
diff --git a/src/locales/en/main.json b/src/locales/en/main.json
index 376eb36fc..46b689458 100644
--- a/src/locales/en/main.json
+++ b/src/locales/en/main.json
@@ -193,6 +193,8 @@
"updateSelected": "Update Selected",
"updateAll": "Update All",
"updatingAllPacks": "Updating all packages",
+ "disabledNodesWontUpdate": "Disabled nodes will not be updated",
+ "enablePackToChangeVersion": "Enable this pack to change versions",
"license": "License",
"nightlyVersion": "Nightly",
"latestVersion": "Latest",
@@ -1470,6 +1472,8 @@
"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}:"
diff --git a/tests-ui/tests/composables/useUpdateAvailableNodes.test.ts b/tests-ui/tests/composables/useUpdateAvailableNodes.test.ts
index f574b5fe7..3e88963d6 100644
--- a/tests-ui/tests/composables/useUpdateAvailableNodes.test.ts
+++ b/tests-ui/tests/composables/useUpdateAvailableNodes.test.ts
@@ -63,12 +63,14 @@ describe('useUpdateAvailableNodes', () => {
const mockStartFetchInstalled = vi.fn()
const mockIsPackInstalled = vi.fn()
const mockGetInstalledPackVersion = vi.fn()
+ const mockIsPackEnabled = vi.fn()
beforeEach(() => {
vi.clearAllMocks()
// Default setup
mockIsPackInstalled.mockReturnValue(true)
+ mockIsPackEnabled.mockReturnValue(true) // Default: all packs are enabled
mockGetInstalledPackVersion.mockImplementation((id: string) => {
switch (id) {
case 'pack-1':
@@ -100,7 +102,8 @@ describe('useUpdateAvailableNodes', () => {
mockUseComfyManagerStore.mockReturnValue({
isPackInstalled: mockIsPackInstalled,
- getInstalledPackVersion: mockGetInstalledPackVersion
+ getInstalledPackVersion: mockGetInstalledPackVersion,
+ isPackEnabled: mockIsPackEnabled
} as any)
mockUseInstalledPacks.mockReturnValue({
@@ -357,4 +360,127 @@ describe('useUpdateAvailableNodes', () => {
expect(mockIsPackInstalled).toHaveBeenCalledWith('pack-4')
})
})
+
+ describe('enabledUpdateAvailableNodePacks', () => {
+ it('returns only enabled packs with updates', () => {
+ mockIsPackEnabled.mockImplementation((id: string) => {
+ // pack-1 is disabled
+ return id !== 'pack-1'
+ })
+
+ mockUseInstalledPacks.mockReturnValue({
+ installedPacks: ref([mockInstalledPacks[0], mockInstalledPacks[1]]),
+ isLoading: ref(false),
+ error: ref(null),
+ startFetchInstalled: mockStartFetchInstalled
+ } as any)
+
+ const { updateAvailableNodePacks, enabledUpdateAvailableNodePacks } =
+ useUpdateAvailableNodes()
+
+ // pack-1 has updates but is disabled
+ expect(updateAvailableNodePacks.value).toHaveLength(1)
+ expect(updateAvailableNodePacks.value[0].id).toBe('pack-1')
+
+ // enabledUpdateAvailableNodePacks should be empty
+ expect(enabledUpdateAvailableNodePacks.value).toHaveLength(0)
+ })
+
+ it('returns all packs when all are enabled', () => {
+ mockUseInstalledPacks.mockReturnValue({
+ installedPacks: ref([mockInstalledPacks[0]]), // pack-1: outdated
+ isLoading: ref(false),
+ error: ref(null),
+ startFetchInstalled: mockStartFetchInstalled
+ } as any)
+
+ const { updateAvailableNodePacks, enabledUpdateAvailableNodePacks } =
+ useUpdateAvailableNodes()
+
+ expect(updateAvailableNodePacks.value).toHaveLength(1)
+ expect(enabledUpdateAvailableNodePacks.value).toHaveLength(1)
+ expect(enabledUpdateAvailableNodePacks.value[0].id).toBe('pack-1')
+ })
+ })
+
+ describe('hasDisabledUpdatePacks', () => {
+ it('returns true when there are disabled packs with updates', () => {
+ mockIsPackEnabled.mockImplementation((id: string) => {
+ // pack-1 is disabled
+ return id !== 'pack-1'
+ })
+
+ mockUseInstalledPacks.mockReturnValue({
+ installedPacks: ref([mockInstalledPacks[0]]), // pack-1: outdated
+ isLoading: ref(false),
+ error: ref(null),
+ startFetchInstalled: mockStartFetchInstalled
+ } as any)
+
+ const { hasDisabledUpdatePacks } = useUpdateAvailableNodes()
+
+ expect(hasDisabledUpdatePacks.value).toBe(true)
+ })
+
+ it('returns false when all packs with updates are enabled', () => {
+ mockUseInstalledPacks.mockReturnValue({
+ installedPacks: ref([mockInstalledPacks[0]]), // pack-1: outdated
+ isLoading: ref(false),
+ error: ref(null),
+ startFetchInstalled: mockStartFetchInstalled
+ } as any)
+
+ const { hasDisabledUpdatePacks } = useUpdateAvailableNodes()
+
+ expect(hasDisabledUpdatePacks.value).toBe(false)
+ })
+
+ it('returns false when no packs have updates', () => {
+ mockUseInstalledPacks.mockReturnValue({
+ installedPacks: ref([mockInstalledPacks[1]]), // pack-2: up to date
+ isLoading: ref(false),
+ error: ref(null),
+ startFetchInstalled: mockStartFetchInstalled
+ } as any)
+
+ const { hasDisabledUpdatePacks } = useUpdateAvailableNodes()
+
+ expect(hasDisabledUpdatePacks.value).toBe(false)
+ })
+ })
+
+ describe('hasUpdateAvailable with disabled packs', () => {
+ it('returns false when only disabled packs have updates', () => {
+ mockIsPackEnabled.mockReturnValue(false) // All packs disabled
+
+ mockUseInstalledPacks.mockReturnValue({
+ installedPacks: ref([mockInstalledPacks[0]]), // pack-1: outdated
+ isLoading: ref(false),
+ error: ref(null),
+ startFetchInstalled: mockStartFetchInstalled
+ } as any)
+
+ const { hasUpdateAvailable } = useUpdateAvailableNodes()
+
+ expect(hasUpdateAvailable.value).toBe(false)
+ })
+
+ it('returns true when at least one enabled pack has updates', () => {
+ mockIsPackEnabled.mockImplementation((id: string) => {
+ // Only pack-1 is enabled
+ return id === 'pack-1'
+ })
+
+ mockUseInstalledPacks.mockReturnValue({
+ installedPacks: ref([mockInstalledPacks[0]]), // pack-1: outdated
+ isLoading: ref(false),
+ error: ref(null),
+ startFetchInstalled: mockStartFetchInstalled
+ } as any)
+
+ const { hasUpdateAvailable } = useUpdateAvailableNodes()
+
+ expect(hasUpdateAvailable.value).toBe(true)
+ })
+ })
})