Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
66 commits
Select commit Hold shift + click to select a range
5846117
migrate manager menu items
christian-byrne Apr 9, 2025
d96265a
Update locales [skip ci]
invalid-email-address Apr 9, 2025
d2d8565
switch to v2 manager API endpoints
christian-byrne Apr 9, 2025
cd7d64a
re-arrange menu items
christian-byrne Apr 11, 2025
fd3362e
await promises. update settings schema
christian-byrne Apr 14, 2025
61fa2fd
move legacy option to startup arg
christian-byrne Apr 14, 2025
be7433b
Add banner indicating how to use legacy manager UI
christian-byrne Apr 14, 2025
29cdd57
Update locales [skip ci]
invalid-email-address Apr 14, 2025
7ec70e5
add "Check for Updates", "Install Missing" menu items
christian-byrne Apr 14, 2025
226f84e
Update locales [skip ci]
invalid-email-address Apr 14, 2025
cf174d3
use correct response shape
christian-byrne Apr 14, 2025
e8e558b
improve command names
christian-byrne Apr 14, 2025
8a2747f
dont show missing nodes button in legacy manager mode
christian-byrne Apr 15, 2025
0f97a6f
[Update to v2 API] update WS done message
christian-byrne Apr 15, 2025
2d117b1
Update locales [skip ci]
invalid-email-address Jul 19, 2025
ec923e2
[fix] Fix json syntax error from rebase (#4607)
christian-byrne Jul 30, 2025
8ceb5e4
Fix errors from rebase (removed `Tag` component import and duplicated…
christian-byrne Jul 30, 2025
a2df972
Update locales [skip ci]
invalid-email-address Jul 30, 2025
808adc0
[Manager] "Restarting" state after clicking restart button (#4637)
viva-jinyi Aug 1, 2025
b7f778b
[feat] Add reactive feature flags foundation (#4817)
christian-byrne Aug 7, 2025
2e4b510
[feat] Add v2/ prefix to manager service base URL (#4872)
christian-byrne Aug 9, 2025
3c3ed2b
[cleanup] Remove unused manager route enums (#4875)
christian-byrne Aug 9, 2025
3352c06
fix: v2 prefix (#5145)
viva-jinyi Aug 21, 2025
7d1659c
Fix: Restore api.ts from main branch after incorrect rebase (#5150)
viva-jinyi Aug 22, 2025
6470869
feat: Add loading state to PackInstallButton and improve UI (#5153)
viva-jinyi Aug 23, 2025
3e3448e
[restore] conflict notification commits restore
viva-jinyi Aug 2, 2025
a1ea18c
[fix] Restore conflict notification work and fix tests
viva-jinyi Aug 2, 2025
aefa3a9
[fix] Use Vue 3.5 destructuring syntax for props with defaults
viva-jinyi Aug 2, 2025
7389790
[feature] dual modal supported
viva-jinyi Aug 2, 2025
134341d
[fix] Fix date format in PackCard test for locale consistency
viva-jinyi Aug 2, 2025
ff31e2d
[fix] title text modified
viva-jinyi Aug 5, 2025
42ad8eb
[fix] Fix conflict red dot not syncing
viva-jinyi Aug 5, 2025
63b6af5
[fix] Add conflict detection when installed packages list updates
viva-jinyi Aug 6, 2025
73f2489
fix: use selected target_branch for PR base in update-manager-types w…
viva-jinyi Aug 6, 2025
87db9cc
[fix] test code timeout error fixed
viva-jinyi Aug 6, 2025
7d0e971
[chore] Update ComfyUI-Manager API types from ComfyUI-Manager@4e6f970…
comfy-pr-bot Aug 6, 2025
4c99172
[types] Add proper types for ImportFailInfo API endpoints (#4783)
viva-jinyi Aug 6, 2025
33bf377
[fix] ci error fixed & button max-width modified
viva-jinyi Aug 7, 2025
59e1945
fix: node pack card width adapted
viva-jinyi Aug 12, 2025
35873fa
fix: prevent duplicate api calls & installedPacksWithVersions instead…
viva-jinyi Aug 12, 2025
a5153cd
feat: run conflict detection after Apply Changes
viva-jinyi Aug 17, 2025
267e07e
refactor: simplify PackInstallButton isInstalling state management
viva-jinyi Aug 27, 2025
91e462d
feat: improve multi-package selection handling (#5116)
viva-jinyi Aug 27, 2025
380f335
feat: Integrate ComfyUI Manager migration with v2 API and enhanced UI
christian-byrne Aug 30, 2025
b5bf6fd
fix: Restore correct interfaces from PR #3367
christian-byrne Aug 31, 2025
154dbb5
fix: Add missing IconTextButton import in PackUninstallButton
christian-byrne Aug 31, 2025
86baabc
docs: Update backup documentation with working state backup
christian-byrne Aug 31, 2025
6426861
[feat] Add manager capability feature flags
christian-byrne Aug 18, 2025
2415b97
[feat] Add managerStateStore for three-state manager UI logic
christian-byrne Aug 18, 2025
8a26b7e
[fix] Fix API URL prefix slash and add error handling
christian-byrne Sep 1, 2025
e1ac09f
[docs] Update backup documentation with PR #5063 integration status
christian-byrne Sep 1, 2025
d2eaffe
[fix] Fix manager button visibility when manager is disabled
christian-byrne Sep 1, 2025
e6aff69
[fix] Correct Install All button visibility for manager UI states
christian-byrne Sep 1, 2025
3853dca
feat: Complete manager migration with bug fixes and locale updates
christian-byrne Sep 1, 2025
183bba0
Complete PR #4654 integration with manager migration
christian-byrne Sep 1, 2025
fdf4ffd
feat: Complete manager migration with conflict detection integration
christian-byrne Sep 1, 2025
3df0a8a
Remove temporary error log files from commits
christian-byrne Sep 1, 2025
2c5b6da
Remove temporary documentation files
christian-byrne Sep 1, 2025
a74085f
feat: Complete manager migration cleanup and integration
christian-byrne Sep 1, 2025
74c03fb
fix: Update CustomNodesManager command to use tri-state manager system
christian-byrne Sep 1, 2025
d673fba
refactor: Remove no-op refreshTaskState function
christian-byrne Sep 1, 2025
a0630cc
Merge branch 'main' into test-pr4654-integration-v2
christian-byrne Sep 1, 2025
7c88dbc
fix: Replace lodash with es-toolkit/compat in useManagerQueue
christian-byrne Sep 1, 2025
bb767a5
fix: Add missing whats-new-dismissed event emission in WhatsNewPopup
christian-byrne Sep 1, 2025
2d922ad
ci: Force CI run for Playwright tests
christian-byrne Sep 1, 2025
2ef8899
test: Temporarily disable workflow.avif test due to missing nodes dialog
christian-byrne Sep 1, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
feat: Complete manager migration cleanup and integration
- Remove outdated legacy manager detection from LoadWorkflowWarning
- Update InfoPanelHeader with conflict detection improvements
- Fix all failing unit tests from state management transition
- Clean up algolia search provider type mappings
- Remove unused @ts-expect-error directives
- Add .nx to .gitignore

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <[email protected]>
  • Loading branch information
christian-byrne and claude committed Sep 1, 2025
commit a74085f8e433512cd2e9ba5926e087cc204a5351
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -76,3 +76,4 @@ vite.config.mts.timestamp-*.mjs
*storybook.log
storybook-static

.nx/
11 changes: 1 addition & 10 deletions src/components/dialog/content/LoadWorkflowWarning.vue
Original file line number Diff line number Diff line change
Expand Up @@ -53,13 +53,12 @@
<script setup lang="ts">
import Button from 'primevue/button'
import ListBox from 'primevue/listbox'
import { computed, onMounted, ref } from 'vue'
import { computed } from 'vue'
import { useI18n } from 'vue-i18n'

import NoResultsPlaceholder from '@/components/common/NoResultsPlaceholder.vue'
import MissingCoreNodesMessage from '@/components/dialog/content/MissingCoreNodesMessage.vue'
import { useMissingNodes } from '@/composables/nodePack/useMissingNodes'
import { useComfyManagerService } from '@/services/comfyManagerService'
import { useDialogService } from '@/services/dialogService'
import { useComfyManagerStore } from '@/stores/comfyManagerStore'
import { useCommandStore } from '@/stores/commandStore'
Expand All @@ -82,7 +81,6 @@ const { missingNodePacks, isLoading, error, missingCoreNodes } =
useMissingNodes()

const comfyManagerStore = useComfyManagerStore()
const isLegacyManager = ref(false)

// Check if any of the missing packs are currently being installed
const isInstalling = computed(() => {
Expand Down Expand Up @@ -155,13 +153,6 @@ const openManager = async () => {
break
}
}

onMounted(async () => {
const isLegacyResponse = await useComfyManagerService().isLegacyManagerUI()
if (isLegacyResponse?.is_legacy_manager_ui) {
isLegacyManager.value = true
}
})
</script>

<style scoped>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
<template>
<div v-if="nodePacks?.length" class="flex flex-col items-center mb-6">
<div v-if="nodePacks?.length" class="flex flex-col items-center">
<slot name="thumbnail">
<PackIcon :node-pack="nodePacks[0]" width="24" height="24" />
<PackIcon :node-pack="nodePacks[0]" width="204" height="106" />
</slot>
<h2
class="text-2xl font-bold text-center mt-4 mb-2"
style="word-break: break-all"
>
<slot name="title">
{{ nodePacks[0].name }}
<span class="inline-block text-base">{{ nodePacks[0].name }}</span>
</slot>
</h2>
<div
Expand All @@ -26,15 +26,14 @@
v-else
v-bind="$attrs"
size="md"
:is-installing="isInstalling"
:node-packs="nodePacks"
:has-conflict="hasConflict || computedHasConflict"
:conflict-info="conflictInfo"
/>
</slot>
</div>
</div>
<div v-else class="flex flex-col items-center mb-6">
<div v-else class="flex flex-col items-center">
<NoResultsPlaceholder
:message="$t('manager.status.unknown')"
:title="$t('manager.tryAgainLater')"
Expand Down Expand Up @@ -77,12 +76,6 @@ watch(
{ immediate: true }
)

// Check if any of the packs are currently being installed
const isInstalling = computed(() => {
if (!nodePacks?.length) return false
return nodePacks.some((pack) => managerStore.isPackInstalling(pack.id))
})

// Add conflict detection for install button dialog
const { checkNodeCompatibility } = useConflictDetection()

Expand Down
9 changes: 0 additions & 9 deletions src/lib/litegraph/test/LinkConnector.integration.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -334,12 +334,9 @@ describe('LinkConnector Integration', () => {
} = graph.getNodeById(nodeId)!

expect(input.link).toBeNull()
// @ts-expect-error toBeOneOf not in type definitions
expect(output.links?.length).toBeOneOf([0, undefined])

// @ts-expect-error toBeOneOf not in type definitions
expect(input._floatingLinks?.size).toBeOneOf([0, undefined])
// @ts-expect-error toBeOneOf not in type definitions
expect(output._floatingLinks?.size).toBeOneOf([0, undefined])
}
})
Expand Down Expand Up @@ -537,12 +534,9 @@ describe('LinkConnector Integration', () => {
} = graph.getNodeById(nodeId)!

expect(input.link).toBeNull()
// @ts-expect-error toBeOneOf not in type definitions
expect(output.links?.length).toBeOneOf([0, undefined])

// @ts-expect-error toBeOneOf not in type definitions
expect(input._floatingLinks?.size).toBeOneOf([0, undefined])
// @ts-expect-error toBeOneOf not in type definitions
expect(output._floatingLinks?.size).toBeOneOf([0, undefined])
}
})
Expand Down Expand Up @@ -856,12 +850,9 @@ describe('LinkConnector Integration', () => {
} = graph.getNodeById(nodeId)!

expect(input.link).toBeNull()
// @ts-expect-error toBeOneOf not in type definitions
expect(output.links?.length).toBeOneOf([0, undefined])

// @ts-expect-error toBeOneOf not in type definitions
expect(input._floatingLinks?.size).toBeOneOf([0, undefined])
// @ts-expect-error toBeOneOf not in type definitions
expect(output._floatingLinks?.size).toBeOneOf([0, undefined])
}
})
Expand Down
1 change: 1 addition & 0 deletions src/services/providers/algoliaSearchProvider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ const toRegistryLatestVersion = (
): RegistryNodePack['latest_version'] => {
return {
version: algoliaNode.latest_version,
createdAt: algoliaNode.update_time,
status: algoliaNode.latest_version_status,
comfy_node_extract_status:
algoliaNode.comfy_node_extract_status ?? undefined
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -66,16 +66,27 @@ const mountComponent = (options: { captureError?: boolean } = {}) => {
legacy: false,
locale: 'en',
messages: {
en: {}
en: {
g: {
progressCountOf: 'of'
},
manager: {
clickToFinishSetup: 'Click',
applyChanges: 'Apply Changes',
toFinishSetup: 'to finish setup',
restartingBackend: 'Restarting backend to apply changes...',
extensionsSuccessfullyInstalled:
'Extension(s) successfully installed and are ready to use!',
restartToApplyChanges: 'To apply changes, please restart ComfyUI',
installingDependencies: 'Installing dependencies...'
}
}
}
})

const config: any = {
global: {
plugins: [pinia, PrimeVue, i18n],
mocks: {
$t: (key: string) => key // Mock i18n translation
}
plugins: [pinia, PrimeVue, i18n]
}
}

Expand All @@ -95,9 +106,14 @@ describe('ManagerProgressFooter', () => {
const mockTaskLogs: TaskLog[] = []

const mockComfyManagerStore = {
uncompletedCount: 0,
taskLogs: mockTaskLogs,
allTasksDone: true,
isProcessingTasks: false,
succeededTasksIds: [] as string[],
failedTasksIds: [] as string[],
taskHistory: {} as Record<string, any>,
taskQueue: null,
resetTaskState: vi.fn(),
clearLogs: vi.fn(),
setStale: vi.fn(),
// Add other required properties
Expand Down Expand Up @@ -195,7 +211,14 @@ describe('ManagerProgressFooter', () => {
describe('State 1: Queue Running', () => {
it('should display loading spinner and progress counter when queue is running', async () => {
// Setup queue running state
mockComfyManagerStore.uncompletedCount = 3
mockComfyManagerStore.isProcessingTasks = true
mockComfyManagerStore.succeededTasksIds = ['1', '2']
mockComfyManagerStore.failedTasksIds = []
mockComfyManagerStore.taskHistory = {
'1': { taskName: 'Installing pack1' },
'2': { taskName: 'Installing pack2' },
'3': { taskName: 'Installing pack3' }
}
mockTaskLogs.push(
{ taskName: 'Installing pack1', taskId: '1', logs: [] },
{ taskName: 'Installing pack2', taskId: '2', logs: [] },
Expand All @@ -211,18 +234,18 @@ describe('ManagerProgressFooter', () => {
expect(wrapper.text()).toContain('Installing pack3')

// Check progress counter (completed: 2 of 3)
expect(wrapper.text()).toMatch(/2.*3/)
expect(wrapper.text()).toMatch(/2.*of.*3/)

// Check expand/collapse button exists
const expandButton = wrapper.find('[aria-label="Expand"]')
expect(expandButton.exists()).toBe(true)

// Check Apply Changes button is NOT shown
expect(wrapper.text()).not.toContain('manager.applyChanges')
expect(wrapper.text()).not.toContain('Apply Changes')
})

it('should toggle expansion when expand button is clicked', async () => {
mockComfyManagerStore.uncompletedCount = 1
mockComfyManagerStore.isProcessingTasks = true
mockTaskLogs.push({ taskName: 'Installing', taskId: '1', logs: [] })

const wrapper = mountComponent()
Expand All @@ -237,7 +260,7 @@ describe('ManagerProgressFooter', () => {
describe('State 2: Tasks Completed (Waiting for Restart)', () => {
it('should display check mark and Apply Changes button when all tasks are done', async () => {
// Setup tasks completed state
mockComfyManagerStore.uncompletedCount = 0
mockComfyManagerStore.isProcessingTasks = false
mockTaskLogs.push(
{ taskName: 'Installed pack1', taskId: '1', logs: [] },
{ taskName: 'Installed pack2', taskId: '2', logs: [] }
Expand All @@ -249,15 +272,16 @@ describe('ManagerProgressFooter', () => {
// Check check mark emoji
expect(wrapper.text()).toContain('✅')

// Check restart message (split into 3 parts)
expect(wrapper.text()).toContain('manager.clickToFinishSetup')
expect(wrapper.text()).toContain('manager.applyChanges')
expect(wrapper.text()).toContain('manager.toFinishSetup')
// Check restart message
expect(wrapper.text()).toContain(
'To apply changes, please restart ComfyUI'
)
expect(wrapper.text()).toContain('Apply Changes')

// Check Apply Changes button exists
const applyButton = wrapper
.findAll('button')
.find((btn) => btn.text().includes('manager.applyChanges'))
.find((btn) => btn.text().includes('Apply Changes'))
expect(applyButton).toBeTruthy()

// Check no progress counter
Expand All @@ -268,28 +292,28 @@ describe('ManagerProgressFooter', () => {
describe('State 3: Restarting', () => {
it('should display restarting message and spinner during restart', async () => {
// Setup completed state first
mockComfyManagerStore.uncompletedCount = 0
mockComfyManagerStore.isProcessingTasks = false
mockComfyManagerStore.allTasksDone = true

const wrapper = mountComponent()

// Click Apply Changes to trigger restart
const applyButton = wrapper
.findAll('button')
.find((btn) => btn.text().includes('manager.applyChanges'))
.find((btn) => btn.text().includes('Apply Changes'))
await applyButton?.trigger('click')

// Wait for state update
await nextTick()

// Check restarting message
expect(wrapper.text()).toContain('manager.restartingBackend')
expect(wrapper.text()).toContain('Restarting backend to apply changes...')

// Check loading spinner during restart
expect(wrapper.find('.inline-flex').exists()).toBe(true)

// Check Apply Changes button is hidden
expect(wrapper.text()).not.toContain('manager.applyChanges')
expect(wrapper.text()).not.toContain('Apply Changes')
})
})

Expand All @@ -298,15 +322,15 @@ describe('ManagerProgressFooter', () => {
vi.useFakeTimers()

// Setup completed state
mockComfyManagerStore.uncompletedCount = 0
mockComfyManagerStore.isProcessingTasks = false
mockComfyManagerStore.allTasksDone = true

const wrapper = mountComponent()

// Trigger restart
const applyButton = wrapper
.findAll('button')
.find((btn) => btn.text().includes('manager.applyChanges'))
.find((btn) => btn.text().includes('Apply Changes'))
await applyButton?.trigger('click')

// Wait for event listener to be set up
Expand All @@ -323,7 +347,7 @@ describe('ManagerProgressFooter', () => {
// Check success message
expect(wrapper.text()).toContain('🎉')
expect(wrapper.text()).toContain(
'manager.extensionsSuccessfullyInstalled'
'Extension(s) successfully installed and are ready to use!'
)

// Check dialog closes after 3 seconds
Expand All @@ -334,7 +358,7 @@ describe('ManagerProgressFooter', () => {
expect(mockDialogStore.closeDialog).toHaveBeenCalledWith({
key: 'global-manager-progress-dialog'
})
expect(mockComfyManagerStore.clearLogs).toHaveBeenCalled()
expect(mockComfyManagerStore.resetTaskState).toHaveBeenCalled()

vi.useRealTimers()
})
Expand Down Expand Up @@ -362,7 +386,7 @@ describe('ManagerProgressFooter', () => {

describe('Toast Management', () => {
it('should suppress reconnection toasts during restart', async () => {
mockComfyManagerStore.uncompletedCount = 0
mockComfyManagerStore.isProcessingTasks = false
mockComfyManagerStore.allTasksDone = true
mockSettingStore.get.mockReturnValue(false) // Original setting

Expand All @@ -371,7 +395,7 @@ describe('ManagerProgressFooter', () => {
// Click Apply Changes
const applyButton = wrapper
.findAll('button')
.find((btn) => btn.text().includes('manager.applyChanges'))
.find((btn) => btn.text().includes('Apply Changes'))
await applyButton?.trigger('click')

// Check toast setting was disabled
Expand All @@ -382,7 +406,7 @@ describe('ManagerProgressFooter', () => {
})

it('should restore toast settings after restart completes', async () => {
mockComfyManagerStore.uncompletedCount = 0
mockComfyManagerStore.isProcessingTasks = false
mockComfyManagerStore.allTasksDone = true
mockSettingStore.get.mockReturnValue(false) // Original setting

Expand All @@ -391,7 +415,7 @@ describe('ManagerProgressFooter', () => {
// Click Apply Changes
const applyButton = wrapper
.findAll('button')
.find((btn) => btn.text().includes('manager.applyChanges'))
.find((btn) => btn.text().includes('Apply Changes'))
await applyButton?.trigger('click')

// Wait for event listener to be set up
Expand All @@ -414,7 +438,7 @@ describe('ManagerProgressFooter', () => {

describe('Error Handling', () => {
it('should restore state and close dialog on restart error', async () => {
mockComfyManagerStore.uncompletedCount = 0
mockComfyManagerStore.isProcessingTasks = false
mockComfyManagerStore.allTasksDone = true

// Mock restart to throw error
Expand All @@ -427,7 +451,7 @@ describe('ManagerProgressFooter', () => {
// Click Apply Changes
const applyButton = wrapper
.findAll('button')
.find((btn) => btn.text().includes('manager.applyChanges'))
.find((btn) => btn.text().includes('Apply Changes'))

expect(applyButton).toBeTruthy()

Expand Down
2 changes: 1 addition & 1 deletion tests-ui/tests/store/comfyManagerStore.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ vi.mock('@/composables/useManagerQueue', () => {
statusMessage: ref(''),
allTasksDone: ref(false),
enqueueTask: enqueueTaskMock,
uncompletedCount: ref(0)
isProcessingTasks: ref(false)
}),
enqueueTask: enqueueTaskMock
}
Expand Down
Loading