Skip to content
Closed
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
43 commits
Select commit Hold shift + click to select a range
c28d451
migrate manager menu items
christian-byrne Apr 9, 2025
588bd99
Update locales [skip ci]
invalid-email-address Apr 9, 2025
de6ed34
switch to v2 manager API endpoints
christian-byrne Apr 9, 2025
54a0981
re-arrange menu items
christian-byrne Apr 11, 2025
eb5c49f
await promises. update settings schema
christian-byrne Apr 14, 2025
aba2e5e
move legacy option to startup arg
christian-byrne Apr 14, 2025
f8953a8
Add banner indicating how to use legacy manager UI
christian-byrne Apr 14, 2025
e780e1d
Update locales [skip ci]
invalid-email-address Apr 14, 2025
b01056e
add "Check for Updates", "Install Missing" menu items
christian-byrne Apr 14, 2025
bdd1230
Update locales [skip ci]
invalid-email-address Apr 14, 2025
1aee434
use correct response shape
christian-byrne Apr 14, 2025
f1610db
improve command names
christian-byrne Apr 14, 2025
4f94707
dont show missing nodes button in legacy manager mode
christian-byrne Apr 15, 2025
8075db4
[Update to v2 API] update WS done message
christian-byrne Apr 15, 2025
1a29fb9
migrate manager menu items
christian-byrne Apr 9, 2025
e0aa0d0
re-arrange menu items
christian-byrne Apr 11, 2025
4a518eb
await promises. update settings schema
christian-byrne Apr 14, 2025
a70d013
move legacy option to startup arg
christian-byrne Apr 14, 2025
edc61a0
Add banner indicating how to use legacy manager UI
christian-byrne Apr 14, 2025
7318ef9
add "Check for Updates", "Install Missing" menu items
christian-byrne Apr 14, 2025
5ad236e
use correct response shape
christian-byrne Apr 14, 2025
0d1da6d
improve command names
christian-byrne Apr 14, 2025
a4c0ab0
dont show missing nodes button in legacy manager mode
christian-byrne Apr 15, 2025
229c0e5
Update locales [skip ci]
invalid-email-address Apr 26, 2025
3af4f82
[manager] Update type definitions and schemas for menu items migration
christian-byrne Jun 13, 2025
9551595
[manager] Update core services for new manager API
christian-byrne Jun 13, 2025
9d58d4e
[manager] Update composables and state management
christian-byrne Jun 13, 2025
2914c67
[manager] Update UI components for new manager interface
christian-byrne Jun 13, 2025
d76702e
[manager] Update tests for new manager API
christian-byrne Jun 13, 2025
7685ca3
[manager] Fix test failures and missing type definitions
christian-byrne Jun 14, 2025
5e285db
fix rebase errors
christian-byrne Jun 21, 2025
9fceda8
[Manager] Filter task queue and history by client id (#4241)
christian-byrne Jun 21, 2025
8a920f1
fix failed task tab state binding
christian-byrne Jun 22, 2025
ea9bc11
[Manager] Fix: failed tasks logs not correctly partitioned in UI (#4242)
christian-byrne Jun 22, 2025
b7ba509
[tests] Update useServerLogs test to handle task-started events
christian-byrne Jun 22, 2025
c2f3a47
fix: logs stops listening after 1st of multiple queue tasks
christian-byrne Jun 23, 2025
88d8d14
remove the temporary check for legacy custom node version of manager
christian-byrne Jun 23, 2025
20b47ef
[tests] Update useServerLogs test after log subscription change
christian-byrne Jun 23, 2025
84542e8
[Manager] Add update all button functionality
viva-jinyi Jun 24, 2025
8e6ed32
[Manager] “Restarting” state after clicking restart button (#4269)
viva-jinyi Jun 26, 2025
ec4e672
fix rebase error
christian-byrne Jul 11, 2025
c10c151
Update locales [skip ci]
invalid-email-address Jul 11, 2025
aa5e8e5
[test] Update PackVersionBadge test to use role selector instead of B…
viva-jinyi Jul 11, 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
[manager] Update UI components for new manager interface
Updated manager dialog components, pack cards, version selectors, and action buttons to work with the new manager API and state management structure.
  • Loading branch information
christian-byrne committed Aug 27, 2025
commit 2914c67052f96614eabf7c0cc7b1ed3556de8cf7
30 changes: 18 additions & 12 deletions src/components/dialog/content/ManagerProgressDialogContent.vue
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
'max-h-0': !isExpanded
}"
>
<div v-for="(panel, index) in taskPanels" :key="index">
<div v-for="(log, index) in focusedLogs" :key="index">
<Panel
:expanded="collapsedPanels[index] || false"
toggleable
Expand All @@ -27,7 +27,7 @@
<template #header>
<div class="flex items-center justify-between w-full py-2">
<div class="flex flex-col text-sm font-medium leading-normal">
<span>{{ panel.taskName }}</span>
<span>{{ log.taskName }}</span>
<span class="text-muted">
{{
isInProgress(index)
Expand All @@ -52,24 +52,24 @@
</template>
<div
:ref="
index === taskPanels.length - 1
index === focusedLogs.length - 1
? (el) => (lastPanelRef = el as HTMLElement)
: undefined
"
class="overflow-y-auto h-64 rounded-lg bg-black"
:class="{
'h-64': index !== taskPanels.length - 1,
'flex-grow': index === taskPanels.length - 1
'h-64': index !== focusedLogs.length - 1,
'flex-grow': index === focusedLogs.length - 1
}"
@scroll="handleScroll"
>
<div class="h-full">
<div
v-for="(log, logIndex) in panel.logs"
v-for="(logLine, logIndex) in log.logs"
:key="logIndex"
class="text-neutral-400 dark-theme:text-muted"
>
<pre class="whitespace-pre-wrap break-words">{{ log }}</pre>
<pre class="whitespace-pre-wrap break-words">{{ logLine }}</pre>
</div>
</div>
</div>
Expand All @@ -90,17 +90,23 @@ import {
useManagerProgressDialogStore
} from '@/stores/comfyManagerStore'

const { taskLogs } = useComfyManagerStore()
const comfyManagerStore = useComfyManagerStore()
const progressDialogContent = useManagerProgressDialogStore()
const managerStore = useComfyManagerStore()

const isInProgress = (index: number) =>
index === taskPanels.value.length - 1 && managerStore.uncompletedCount > 0
index === comfyManagerStore.managerQueue.historyCount - 1 &&
comfyManagerStore.isLoading

const taskPanels = computed(() => taskLogs)
const isExpanded = computed(() => progressDialogContent.isExpanded)
const isCollapsed = computed(() => !isExpanded.value)

const focusedLogs = computed(() => {
if (progressDialogContent.getActiveTabIndex() === 0) {
return comfyManagerStore.succeededTasksLogs
}
return comfyManagerStore.failedTasksLogs
})

const collapsedPanels = ref<Record<number, boolean>>({})
const togglePanel = (index: number) => {
collapsedPanels.value[index] = !collapsedPanels.value[index]
Expand All @@ -115,7 +121,7 @@ const { y: scrollY } = useScroll(sectionsContainerRef, {

const lastPanelRef = ref<HTMLElement | null>(null)
const isUserScrolling = ref(false)
const lastPanelLogs = computed(() => taskPanels.value?.at(-1)?.logs)
const lastPanelLogs = computed(() => focusedLogs.value?.at(-1)?.logs)

const isAtBottom = (el: HTMLElement | null) => {
if (!el) return false
Expand Down
14 changes: 7 additions & 7 deletions src/components/dialog/content/manager/PackVersionBadge.test.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
import { VueWrapper, mount } from '@vue/test-utils'
import { createPinia } from 'pinia'
import Button from 'primevue/button'
import PrimeVue from 'primevue/config'
import { beforeEach, describe, expect, it, vi } from 'vitest'
import { nextTick } from 'vue'
import { createI18n } from 'vue-i18n'

import enMessages from '@/locales/en/main.json'
import { SelectedVersion } from '@/types/comfyManagerTypes'

import PackVersionBadge from './PackVersionBadge.vue'
import PackVersionSelectorPopover from './PackVersionSelectorPopover.vue'
Expand Down Expand Up @@ -118,9 +118,9 @@ describe('PackVersionBadge', () => {
props: { nodePack: noVersionPack }
})

const badge = wrapper.find('[role="button"]')
expect(badge.exists()).toBe(true)
expect(badge.find('span').text()).toBe(SelectedVersion.NIGHTLY)
const button = wrapper.findComponent(Button)
expect(button.exists()).toBe(true)
expect(button.props('label')).toBe('nightly')
})

it('falls back to NIGHTLY when nodePack.id is missing', () => {
Expand All @@ -132,9 +132,9 @@ describe('PackVersionBadge', () => {
props: { nodePack: invalidPack }
})

const badge = wrapper.find('[role="button"]')
expect(badge.exists()).toBe(true)
expect(badge.find('span').text()).toBe(SelectedVersion.NIGHTLY)
const button = wrapper.findComponent(Button)
expect(button.exists()).toBe(true)
expect(button.props('label')).toBe('nightly')
})

it('toggles the popover when button is clicked', async () => {
Expand Down
7 changes: 3 additions & 4 deletions src/components/dialog/content/manager/PackVersionBadge.vue
Original file line number Diff line number Diff line change
Expand Up @@ -42,8 +42,7 @@ import { computed, ref, watch } from 'vue'
import PackVersionSelectorPopover from '@/components/dialog/content/manager/PackVersionSelectorPopover.vue'
import { usePackUpdateStatus } from '@/composables/nodePack/usePackUpdateStatus'
import { useComfyManagerStore } from '@/stores/comfyManagerStore'
import { SelectedVersion } from '@/types/comfyManagerTypes'
import { components } from '@/types/comfyRegistryTypes'
import type { components } from '@/types/comfyRegistryTypes'
import { isSemVer } from '@/utils/formatUtil'

const TRUNCATED_HASH_LENGTH = 7
Expand All @@ -64,11 +63,11 @@ const popoverRef = ref()
const managerStore = useComfyManagerStore()

const installedVersion = computed(() => {
if (!nodePack.id) return SelectedVersion.NIGHTLY
if (!nodePack.id) return 'nightly'
const version =
managerStore.installedPacks[nodePack.id]?.ver ??
nodePack.latest_version?.version ??
SelectedVersion.NIGHTLY
'nightly'

// If Git hash, truncate to 7 characters
return isSemVer(version) ? version : version.slice(0, TRUNCATED_HASH_LENGTH)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@ import { nextTick } from 'vue'
import { createI18n } from 'vue-i18n'

import enMessages from '@/locales/en/main.json'
import { SelectedVersion } from '@/types/comfyManagerTypes'

// SelectedVersion is now using direct strings instead of enum

import PackVersionSelectorPopover from './PackVersionSelectorPopover.vue'

Expand Down Expand Up @@ -123,8 +124,8 @@ describe('PackVersionSelectorPopover', () => {
expect(options.length).toBe(defaultMockVersions.length + 2) // 2 special options + version options

// Check that special options exist
expect(options.some((o) => o.value === SelectedVersion.NIGHTLY)).toBe(true)
expect(options.some((o) => o.value === SelectedVersion.LATEST)).toBe(true)
expect(options.some((o) => o.value === 'nightly')).toBe(true)
expect(options.some((o) => o.value === 'latest')).toBe(true)

// Check that version options exist
expect(options.some((o) => o.value === '1.0.0')).toBe(true)
Expand Down Expand Up @@ -304,7 +305,7 @@ describe('PackVersionSelectorPopover', () => {
await waitForPromises()
const listbox = wrapper.findComponent(Listbox)
expect(listbox.exists()).toBe(true)
expect(listbox.props('modelValue')).toBe(SelectedVersion.NIGHTLY)
expect(listbox.props('modelValue')).toBe('nightly')
})

it('defaults to nightly when publisher name is "Unclaimed"', async () => {
Expand All @@ -325,7 +326,7 @@ describe('PackVersionSelectorPopover', () => {
await waitForPromises()
const listbox = wrapper.findComponent(Listbox)
expect(listbox.exists()).toBe(true)
expect(listbox.props('modelValue')).toBe(SelectedVersion.NIGHTLY)
expect(listbox.props('modelValue')).toBe('nightly')
})
})
})
Original file line number Diff line number Diff line change
Expand Up @@ -69,12 +69,8 @@ import ContentDivider from '@/components/common/ContentDivider.vue'
import NoResultsPlaceholder from '@/components/common/NoResultsPlaceholder.vue'
import { useComfyRegistryService } from '@/services/comfyRegistryService'
import { useComfyManagerStore } from '@/stores/comfyManagerStore'
import {
ManagerChannel,
ManagerDatabaseSource,
SelectedVersion
} from '@/types/comfyManagerTypes'
import { components } from '@/types/comfyRegistryTypes'
import type { components } from '@/types/comfyRegistryTypes'
import { components as ManagerComponents } from '@/types/generatedManagerTypes'
import { isSemVer } from '@/utils/formatUtil'

const { nodePack } = defineProps<{
Expand All @@ -92,19 +88,20 @@ const managerStore = useComfyManagerStore()

const isQueueing = ref(false)

const selectedVersion = ref<string>(SelectedVersion.LATEST)
const selectedVersion = ref<string>('latest')
onMounted(() => {
const initialVersion = getInitialSelectedVersion() ?? SelectedVersion.LATEST
const initialVersion = getInitialSelectedVersion() ?? 'latest'
selectedVersion.value =
// Use NIGHTLY when version is a Git hash
isSemVer(initialVersion) ? initialVersion : SelectedVersion.NIGHTLY
isSemVer(initialVersion) ? initialVersion : 'nightly'
})

const getInitialSelectedVersion = () => {
if (!nodePack.id) return

// If unclaimed, set selected version to nightly
if (nodePack.publisher?.name === 'Unclaimed') return SelectedVersion.NIGHTLY
if (nodePack.publisher?.name === 'Unclaimed')
return 'nightly' as ManagerComponents['schemas']['SelectedVersion']

// If node pack is installed, set selected version to the installed version
if (managerStore.isPackInstalled(nodePack.id))
Expand Down Expand Up @@ -143,15 +140,15 @@ const onNodePackChange = async () => {
// Add Latest option
const defaultVersions = [
{
value: SelectedVersion.LATEST,
value: 'latest' as ManagerComponents['schemas']['SelectedVersion'],
label: t('manager.latestVersion')
}
]

// Add Nightly option if there is a non-empty `repository` field
if (nodePack.repository?.length) {
defaultVersions.push({
value: SelectedVersion.NIGHTLY,
value: 'nightly' as ManagerComponents['schemas']['SelectedVersion'],
label: t('manager.nightlyVersion')
})
}
Expand All @@ -172,12 +169,16 @@ whenever(

const handleSubmit = async () => {
isQueueing.value = true
if (!nodePack.id) {
throw new Error('Node ID is required for installation')
}

await managerStore.installPack.call({
id: nodePack.id,
repository: nodePack.repository ?? '',
channel: ManagerChannel.DEFAULT,
mode: ManagerDatabaseSource.CACHE,
version: selectedVersion.value,
repository: nodePack.repository ?? '',
channel: 'default' as ManagerComponents['schemas']['ManagerChannel'],
mode: 'cache' as ManagerComponents['schemas']['ManagerDatabaseSource'],
selected_version: selectedVersion.value
})

Expand Down
61 changes: 34 additions & 27 deletions src/components/dialog/content/manager/button/PackEnableToggle.vue
Original file line number Diff line number Diff line change
Expand Up @@ -15,50 +15,51 @@ import ToggleSwitch from 'primevue/toggleswitch'
import { computed, ref } from 'vue'

import { useComfyManagerStore } from '@/stores/comfyManagerStore'
import {
InstallPackParams,
ManagerChannel,
SelectedVersion
} from '@/types/comfyManagerTypes'
import type { components } from '@/types/comfyRegistryTypes'
import { components as ManagerComponents } from '@/types/generatedManagerTypes'

const TOGGLE_DEBOUNCE_MS = 256

const { nodePack } = defineProps<{
nodePack: components['schemas']['Node']
}>()

const { isPackEnabled, enablePack, disablePack, installedPacks } =
useComfyManagerStore()
const { isPackEnabled, enablePack, disablePack } = useComfyManagerStore()

const isLoading = ref(false)

const isEnabled = computed(() => isPackEnabled(nodePack.id))
const version = computed(() => {
const id = nodePack.id
if (!id) return SelectedVersion.NIGHTLY
return (
installedPacks[id]?.ver ??
nodePack.latest_version?.version ??
SelectedVersion.NIGHTLY
)
})

const handleEnable = () =>
enablePack.call({
const handleEnable = () => {
if (!nodePack.id) {
throw new Error('Node ID is required for enabling')
}
return enablePack.call({
id: nodePack.id,
version: version.value,
selected_version: version.value,
version:
nodePack.latest_version?.version ??
('latest' as ManagerComponents['schemas']['SelectedVersion']),
selected_version:
nodePack.latest_version?.version ??
('latest' as ManagerComponents['schemas']['SelectedVersion']),
repository: nodePack.repository ?? '',
channel: ManagerChannel.DEFAULT,
mode: 'default' as InstallPackParams['mode']
channel: 'default' as ManagerComponents['schemas']['ManagerChannel'],
mode: 'cache' as ManagerComponents['schemas']['ManagerDatabaseSource'],
skip_post_install: false
})
}

const handleDisable = () =>
disablePack({
const handleDisable = () => {
if (!nodePack.id) {
throw new Error('Node ID is required for disabling')
}
return disablePack({
id: nodePack.id,
version: version.value
version:
nodePack.latest_version?.version ??
('latest' as ManagerComponents['schemas']['SelectedVersion'])
})
}

const handleToggle = async (enable: boolean) => {
if (isLoading.value) return
Expand All @@ -67,10 +68,16 @@ const handleToggle = async (enable: boolean) => {
if (enable) {
await handleEnable()
} else {
handleDisable()
await handleDisable()
}
isLoading.value = false
}

const onToggle = debounce(handleToggle, TOGGLE_DEBOUNCE_MS, { trailing: true })
const onToggle = debounce(
(enable: boolean) => {
void handleToggle(enable)
},
TOGGLE_DEBOUNCE_MS,
{ trailing: true }
)
</script>
Loading