[Manager] Add progress queue dialog (#3091)

Co-authored-by: github-actions <github-actions@github.com>
This commit is contained in:
Christian Byrne
2025-03-17 09:16:36 -07:00
committed by GitHub
parent 891e18af8e
commit bd1be28478
18 changed files with 357 additions and 1 deletions

View File

@@ -0,0 +1,114 @@
<template>
<div
class="overflow-hidden transition-all duration-300"
:class="{
'max-h-[500px]': isExpanded,
'max-h-0 p-0 m-0': !isExpanded
}"
>
<div
ref="sectionsContainerRef"
class="px-6 py-4 overflow-y-auto max-h-[450px] scroll-container"
:style="{
scrollbarWidth: 'thin',
scrollbarColor: 'rgba(156, 163, 175, 0.5) transparent'
}"
:class="{
'max-h-[450px]': isExpanded,
'max-h-0': !isExpanded
}"
>
<div v-for="(panel, index) in taskPanels" :key="index">
<Panel
:expanded="expandedPanels[index] || false"
toggleable
class="shadow-elevation-1 rounded-lg mt-2 dark-theme:bg-black dark-theme:border-black"
>
<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 v-show="expandedPanels[index]" class="text-muted">
{{
index === taskPanels.length - 1
? 'In progress'
: 'Completed '
}}
</span>
</div>
</div>
</template>
<template #toggleicon>
<Button
:icon="
expandedPanels[index]
? 'pi pi-chevron-down'
: 'pi pi-chevron-right'
"
text
class="text-neutral-300"
@click="togglePanel(index)"
/>
</template>
<div
class="overflow-y-auto h-64 rounded-lg bg-black"
:class="{
'h-64': index !== taskPanels.length - 1,
'flex-grow': index === taskPanels.length - 1
}"
>
<div class="h-full">
<div
v-for="(log, logIndex) in panel.logs"
:key="logIndex"
class="text-neutral-400 dark-theme:text-muted"
>
<pre class="whitespace-pre-wrap break-words">{{ log }}</pre>
</div>
</div>
</div>
</Panel>
</div>
</div>
</div>
</template>
<script setup lang="ts">
import { useScroll, whenever } from '@vueuse/core'
import Button from 'primevue/button'
import Panel from 'primevue/panel'
import { computed, onBeforeUnmount, onMounted, ref } from 'vue'
import {
useComfyManagerStore,
useManagerProgressDialogStore
} from '@/stores/comfyManagerStore'
const { taskLogs } = useComfyManagerStore()
const progressDialogContent = useManagerProgressDialogStore()
const taskPanels = computed(() => taskLogs)
const isExpanded = computed(() => progressDialogContent.isExpanded)
const expandedPanels = ref<Record<number, boolean>>({})
const togglePanel = (index: number) => {
expandedPanels.value[index] = !expandedPanels.value[index]
}
const sectionsContainerRef = ref<HTMLElement | null>(null)
const { y: scrollY } = useScroll(sectionsContainerRef)
const scrollToBottom = () => {
scrollY.value = sectionsContainerRef.value?.scrollHeight ?? 0
}
whenever(() => isExpanded.value, scrollToBottom)
onMounted(() => {
expandedPanels.value = {}
scrollToBottom()
})
onBeforeUnmount(() => {
progressDialogContent.collapse()
})
</script>

View File

@@ -0,0 +1,107 @@
<template>
<div
class="w-full px-6 py-4 shadow-lg flex items-center justify-between"
:class="{
'rounded-t-none': progressDialogContent.isExpanded,
'rounded-lg': !progressDialogContent.isExpanded
}"
>
<div class="justify-center text-sm font-bold leading-none">
<div class="flex items-center">
<template v-if="isInProgress">
<i class="pi pi-spin pi-spinner mr-2 text-3xl" />
<span>{{ currentTaskName }}</span>
</template>
<template v-else>
<i class="pi pi-check-circle mr-2 text-green-500" />
<span class="leading-none">{{
$t('manager.restartToApplyChanges')
}}</span>
</template>
</div>
</div>
<div class="flex items-center gap-4">
<span v-if="isInProgress" class="text-xs font-bold text-neutral-600">
{{ comfyManagerStore.uncompletedCount }} of
{{ comfyManagerStore.taskLogs.length }}
</span>
<div class="flex items-center">
<Button
v-if="!isInProgress"
rounded
outlined
class="px-4 py-2 rounded-md mr-4"
@click="handleRestart"
>
{{ $t('g.restart') }}
</Button>
<Button
:icon="
progressDialogContent.isExpanded
? 'pi pi-chevron-up'
: 'pi pi-chevron-right'
"
text
rounded
size="small"
severity="secondary"
:aria-label="progressDialogContent.isExpanded ? 'Collapse' : 'Expand'"
@click.stop="progressDialogContent.toggle"
/>
<Button
icon="pi pi-times"
text
rounded
size="small"
severity="secondary"
aria-label="Close"
@click.stop="closeDialog"
/>
</div>
</div>
</div>
</template>
<script setup lang="ts">
import { useEventListener } from '@vueuse/core'
import Button from 'primevue/button'
import { computed } from 'vue'
import { useI18n } from 'vue-i18n'
import { api } from '@/scripts/api'
import { useComfyManagerService } from '@/services/comfyManagerService'
import {
useComfyManagerStore,
useManagerProgressDialogStore
} from '@/stores/comfyManagerStore'
import { useCommandStore } from '@/stores/commandStore'
import { useDialogStore } from '@/stores/dialogStore'
const { t } = useI18n()
const dialogStore = useDialogStore()
const progressDialogContent = useManagerProgressDialogStore()
const comfyManagerStore = useComfyManagerStore()
const isInProgress = computed(() => comfyManagerStore.uncompletedCount > 0)
const closeDialog = () => {
dialogStore.closeDialog({ key: 'global-manager-progress-dialog' })
}
const fallbackTaskName = t('g.installing')
const currentTaskName = computed(() => {
if (!comfyManagerStore.taskLogs.length) return fallbackTaskName
const task = comfyManagerStore.taskLogs.at(-1)
return task?.taskName ?? fallbackTaskName
})
const handleRestart = async () => {
await useComfyManagerService().rebootComfyUI()
closeDialog()
const onReconnect = () => {
useCommandStore().execute('Comfy.RefreshNodeDefinitions')
}
useEventListener(api, 'reconnected', onReconnect, { once: true })
}
</script>

View File

@@ -0,0 +1,29 @@
<template>
<div
v-if="progressDialogContent.isExpanded"
class="px-4 py-2 flex items-center"
>
<TabMenu
v-model:activeIndex="activeTabIndex"
:model="tabs"
class="w-full border-none"
:pt="{
menu: { class: 'border-none' },
menuitem: { class: 'font-medium' },
action: { class: 'px-4 py-2' }
}"
/>
</div>
</template>
<script setup lang="ts">
import TabMenu from 'primevue/tabmenu'
import { ref } from 'vue'
import { useManagerProgressDialogStore } from '@/stores/comfyManagerStore'
const progressDialogContent = useManagerProgressDialogStore()
const activeTabIndex = ref(0)
const tabs = [{ label: 'Installation Queue' }, { label: 'Failed (0)' }]
</script>

View File

@@ -590,6 +590,15 @@ export function useCoreCommands(): ComfyCommand[] {
function: () => {
dialogService.showManagerDialog()
}
},
{
id: 'Comfy.Manager.ToggleManagerProgressDialog',
icon: 'pi pi-spinner',
label: 'Toggle Progress Dialog',
versionAdded: '1.13.9',
function: () => {
dialogService.showManagerProgressDialog()
}
}
]
}

View File

@@ -128,6 +128,9 @@
"Comfy_Manager_CustomNodesManager": {
"label": "Custom Nodes Manager"
},
"Comfy_Manager_ToggleManagerProgressDialog": {
"label": "Toggle Progress Dialog"
},
"Comfy_NewBlankWorkflow": {
"label": "New Blank Workflow"
},

View File

@@ -94,10 +94,12 @@
"filter": "Filter",
"apply": "Apply",
"enabled": "Enabled",
"installed": "Installed"
"installed": "Installed",
"restart": "Restart"
},
"manager": {
"title": "Custom Nodes Manager",
"restartToApplyChanges": "To apply changes, please restart ComfyUI",
"loadingVersions": "Loading versions...",
"selectVersion": "Select Version",
"downloads": "Downloads",
@@ -615,6 +617,7 @@
"Interrupt": "Interrupt",
"Load Default Workflow": "Load Default Workflow",
"Custom Nodes Manager": "Custom Nodes Manager",
"Toggle Progress Dialog": "Toggle Progress Dialog",
"New": "New",
"Clipspace": "Clipspace",
"Open": "Open",

View File

@@ -128,6 +128,9 @@
"Comfy_Manager_CustomNodesManager": {
"label": "Gestionnaire de Nœuds Personnalisés"
},
"Comfy_Manager_ToggleManagerProgressDialog": {
"label": "Basculer la boîte de dialogue de progression"
},
"Comfy_NewBlankWorkflow": {
"label": "Nouveau flux de travail vierge"
},

View File

@@ -188,6 +188,7 @@
"reportSent": "Rapport soumis",
"reset": "Réinitialiser",
"resetKeybindingsTooltip": "Réinitialiser les raccourcis clavier par défaut",
"restart": "Redémarrer",
"resultsCount": "{count} Résultats Trouvés",
"save": "Enregistrer",
"saving": "Enregistrement",
@@ -397,6 +398,7 @@
"nodePack": "Pack de Nœuds",
"packsSelected": "Packs sélectionnés",
"repository": "Référentiel",
"restartToApplyChanges": "Pour appliquer les modifications, veuillez redémarrer ComfyUI",
"searchPlaceholder": "Recherche",
"selectVersion": "Sélectionner la version",
"sort": {
@@ -530,6 +532,7 @@
"Toggle Logs Bottom Panel": "Basculer le panneau inférieur des journaux",
"Toggle Model Library Sidebar": "Basculer la barre latérale de la bibliothèque de modèles",
"Toggle Node Library Sidebar": "Basculer la barre latérale de la bibliothèque de nœuds",
"Toggle Progress Dialog": "Basculer la boîte de dialogue de progression",
"Toggle Queue Sidebar": "Basculer la barre latérale de la file d'attente",
"Toggle Search Box": "Basculer la boîte de recherche",
"Toggle Terminal Bottom Panel": "Basculer le panneau inférieur du terminal",

View File

@@ -128,6 +128,9 @@
"Comfy_Manager_CustomNodesManager": {
"label": "カスタムノードマネージャ"
},
"Comfy_Manager_ToggleManagerProgressDialog": {
"label": "プログレスダイアログの切り替え"
},
"Comfy_NewBlankWorkflow": {
"label": "新しい空のワークフロー"
},

View File

@@ -188,6 +188,7 @@
"reportSent": "レポートが送信されました",
"reset": "リセット",
"resetKeybindingsTooltip": "キーバインディングをデフォルトにリセット",
"restart": "再起動",
"resultsCount": "{count}件の結果が見つかりました",
"save": "保存",
"saving": "保存中",
@@ -397,6 +398,7 @@
"nodePack": "ノードパック",
"packsSelected": "選択したパック",
"repository": "リポジトリ",
"restartToApplyChanges": "変更を適用するには、ComfyUIを再起動してください",
"searchPlaceholder": "検索",
"selectVersion": "バージョンを選択",
"sort": {
@@ -530,6 +532,7 @@
"Toggle Logs Bottom Panel": "ログパネル下部を切り替え",
"Toggle Model Library Sidebar": "モデルライブラリサイドバーを切り替え",
"Toggle Node Library Sidebar": "ノードライブラリサイドバーを切り替え",
"Toggle Progress Dialog": "進行状況ダイアログの切り替え",
"Toggle Queue Sidebar": "キューサイドバーを切り替え",
"Toggle Search Box": "検索ボックスの切り替え",
"Toggle Terminal Bottom Panel": "ターミナルパネル下部を切り替え",

View File

@@ -128,6 +128,9 @@
"Comfy_Manager_CustomNodesManager": {
"label": "사용자 정의 노드 관리자"
},
"Comfy_Manager_ToggleManagerProgressDialog": {
"label": "프로그레스 대화 상자 전환"
},
"Comfy_NewBlankWorkflow": {
"label": "새로운 빈 워크플로"
},

View File

@@ -188,6 +188,7 @@
"reportSent": "보고서 제출됨",
"reset": "재설정",
"resetKeybindingsTooltip": "키 바인딩을 기본값으로 재설정",
"restart": "재시작",
"resultsCount": "{count} 개의 결과를 찾았습니다",
"save": "저장",
"saving": "저장 중",
@@ -397,6 +398,7 @@
"nodePack": "노드 팩",
"packsSelected": "선택한 팩",
"repository": "저장소",
"restartToApplyChanges": "변경 사항을 적용하려면 ComfyUI를 재시작해 주세요",
"searchPlaceholder": "검색",
"selectVersion": "버전 선택",
"sort": {
@@ -530,6 +532,7 @@
"Toggle Logs Bottom Panel": "로그 하단 패널 전환",
"Toggle Model Library Sidebar": "모델 라이브러리 사이드바 전환",
"Toggle Node Library Sidebar": "노드 라이브러리 사이드바 전환",
"Toggle Progress Dialog": "진행 상황 대화 상자 전환",
"Toggle Queue Sidebar": "실행 큐 사이드바 전환",
"Toggle Search Box": "검색 상자 전환",
"Toggle Terminal Bottom Panel": "터미널 하단 패널 전환",

View File

@@ -128,6 +128,9 @@
"Comfy_Manager_CustomNodesManager": {
"label": "Менеджер Пользовательских Узлов"
},
"Comfy_Manager_ToggleManagerProgressDialog": {
"label": "Переключить диалоговое окно прогресса"
},
"Comfy_NewBlankWorkflow": {
"label": "Новый пустой рабочий процесс"
},

View File

@@ -188,6 +188,7 @@
"reportSent": "Отчёт отправлен",
"reset": "Сбросить",
"resetKeybindingsTooltip": "Сбросить сочетания клавиш по умолчанию",
"restart": "Перезапустить",
"resultsCount": "Найдено {count} результатов",
"save": "Сохранить",
"saving": "Сохранение",
@@ -397,6 +398,7 @@
"nodePack": "Пакет Узлов",
"packsSelected": "Выбрано пакетов",
"repository": "Репозиторий",
"restartToApplyChanges": "Чтобы применить изменения, пожалуйста, перезапустите ComfyUI",
"searchPlaceholder": "Поиск",
"selectVersion": "Выберите версию",
"sort": {
@@ -530,6 +532,7 @@
"Toggle Logs Bottom Panel": "Переключение нижней панели журналов",
"Toggle Model Library Sidebar": "Переключение боковой панели библиотеки моделей",
"Toggle Node Library Sidebar": "Переключение боковой панели библиотеки нод",
"Toggle Progress Dialog": "Переключить диалоговое окно прогресса",
"Toggle Queue Sidebar": "Переключение боковой панели очереди",
"Toggle Search Box": "Переключить поисковую панель",
"Toggle Terminal Bottom Panel": "Переключение нижней панели терминала",

View File

@@ -128,6 +128,9 @@
"Comfy_Manager_CustomNodesManager": {
"label": "自定义节点管理器"
},
"Comfy_Manager_ToggleManagerProgressDialog": {
"label": "切换进度对话框"
},
"Comfy_NewBlankWorkflow": {
"label": "新建空白工作流"
},

View File

@@ -188,6 +188,7 @@
"reportSent": "报告已提交",
"reset": "重置",
"resetKeybindingsTooltip": "将快捷键重置为默认",
"restart": "重新启动",
"resultsCount": "找到 {count} 个结果",
"save": "保存",
"saving": "正在保存",
@@ -397,6 +398,7 @@
"nodePack": "节点包",
"packsSelected": "选定的包",
"repository": "仓库",
"restartToApplyChanges": "要应用更改请重新启动ComfyUI",
"searchPlaceholder": "搜索",
"selectVersion": "选择版本",
"sort": {
@@ -530,6 +532,7 @@
"Toggle Logs Bottom Panel": "切换日志底部面板",
"Toggle Model Library Sidebar": "切换模型库侧边栏",
"Toggle Node Library Sidebar": "切换节点库侧边栏",
"Toggle Progress Dialog": "切换进度对话框",
"Toggle Queue Sidebar": "切换队列侧边栏",
"Toggle Search Box": "切换搜索框",
"Toggle Terminal Bottom Panel": "切换终端底部面板",

View File

@@ -2,11 +2,14 @@ import ConfirmationDialogContent from '@/components/dialog/content/ConfirmationD
import ExecutionErrorDialogContent from '@/components/dialog/content/ExecutionErrorDialogContent.vue'
import IssueReportDialogContent from '@/components/dialog/content/IssueReportDialogContent.vue'
import LoadWorkflowWarning from '@/components/dialog/content/LoadWorkflowWarning.vue'
import ManagerProgressDialogContent from '@/components/dialog/content/ManagerProgressDialogContent.vue'
import MissingModelsWarning from '@/components/dialog/content/MissingModelsWarning.vue'
import PromptDialogContent from '@/components/dialog/content/PromptDialogContent.vue'
import SettingDialogContent from '@/components/dialog/content/SettingDialogContent.vue'
import ManagerDialogContent from '@/components/dialog/content/manager/ManagerDialogContent.vue'
import ManagerHeader from '@/components/dialog/content/manager/ManagerHeader.vue'
import ManagerProgressFooter from '@/components/dialog/footer/ManagerProgressFooter.vue'
import ManagerProgressHeader from '@/components/dialog/header/ManagerProgressHeader.vue'
import SettingDialogHeader from '@/components/dialog/header/SettingDialogHeader.vue'
import TemplateWorkflowsContent from '@/components/templates/TemplateWorkflowsContent.vue'
import TemplateWorkflowsDialogHeader from '@/components/templates/TemplateWorkflowsDialogHeader.vue'
@@ -121,6 +124,29 @@ export const useDialogService = () => {
})
}
function showManagerProgressDialog(options?: {
props?: InstanceType<typeof ManagerProgressDialogContent>['$props']
}) {
return dialogStore.showDialog({
key: 'global-manager-progress-dialog',
component: ManagerProgressDialogContent,
headerComponent: ManagerProgressHeader,
footerComponent: ManagerProgressFooter,
props: options?.props,
dialogComponentProps: {
closable: false,
modal: false,
position: 'bottom',
pt: {
root: { class: 'w-[80%] max-w-2xl mx-auto border-none' },
content: { class: '!p-0' },
header: { class: '!p-0 border-none' },
footer: { class: '!p-0 border-none' }
}
}
})
}
async function prompt({
title,
message,
@@ -203,6 +229,7 @@ export const useDialogService = () => {
showTemplateWorkflowsDialog,
showIssueReportDialog,
showManagerDialog,
showManagerProgressDialog,
prompt,
confirm
}

View File

@@ -6,6 +6,7 @@ import { useCachedRequest } from '@/composables/useCachedRequest'
import { useManagerQueue } from '@/composables/useManagerQueue'
import { useServerLogs } from '@/composables/useServerLogs'
import { useComfyManagerService } from '@/services/comfyManagerService'
import { useDialogService } from '@/services/dialogService'
import {
InstallPackParams,
InstalledPacksResponse,
@@ -20,6 +21,8 @@ import {
*/
export const useComfyManagerStore = defineStore('comfyManager', () => {
const managerService = useComfyManagerService()
const { showManagerProgressDialog } = useDialogService()
const installedPacks = ref<InstalledPacksResponse>({})
const enabledPacksIds = ref<Set<string>>(new Set())
const disabledPacksIds = ref<Set<string>>(new Set())
@@ -110,6 +113,7 @@ export const useComfyManagerStore = defineStore('comfyManager', () => {
}
whenever(isStale, refreshInstalledList, { immediate: true })
whenever(uncompletedCount, () => showManagerProgressDialog())
const withLogs = (task: () => Promise<null>, taskName: string) => {
const { startListening, stopListening, logs } = useServerLogs()
@@ -213,3 +217,33 @@ export const useComfyManagerStore = defineStore('comfyManager', () => {
enablePack: installPack // Enable is done via install endpoint with a disabled pack
}
})
/**
* Store for state of the manager progress dialog content.
* The dialog itself is managed by the dialog store. This store is used to
* manage the visibility of the dialog's content, header, footer.
*/
export const useManagerProgressDialogStore = defineStore(
'managerProgressDialog',
() => {
const isExpanded = ref(false)
const toggle = () => {
isExpanded.value = !isExpanded.value
}
const collapse = () => {
isExpanded.value = false
}
const expand = () => {
isExpanded.value = true
}
return {
isExpanded,
toggle,
collapse,
expand
}
}
)