mirror of
https://github.com/Comfy-Org/ComfyUI_frontend.git
synced 2026-04-19 22:09:37 +00:00
## Summary - move queue batch controls to the left of the run button - align run control styling to the Figma queue modal spec using PrimeVue PT/Tailwind (secondary background on batch + dropdown, primary run button) - normalize control heights to match actionbar buttons and tighten dropdown hit area - update run typography/spacing and replace all three chevrons (dropdown + batch up/down) with the requested SVG Design: https://www.figma.com/design/LVilZgHGk5RwWOkVN6yCEK/Queue-Progress-Modal?node-id=3845-23904&m=dev <img width="303" height="122" alt="image" src="https://github.com/user-attachments/assets/4ed80ee7-3ceb-4512-96ce-f55ec6da835e" /> ┆Issue is synchronized with this [Notion page](https://www.notion.so/PR-9134-fix-align-run-controls-with-queue-modal-design-3106d73d36508160afcedbcfe4b98291) by [Unito](https://www.unito.io) --------- Co-authored-by: github-actions <github-actions@github.com> Co-authored-by: GitHub Action <action@github.com>
240 lines
7.0 KiB
Vue
240 lines
7.0 KiB
Vue
<template>
|
|
<BaseViewTemplate dark>
|
|
<div class="relative min-h-screen">
|
|
<!-- Terminal Background Layer (always visible during loading) -->
|
|
<div v-if="!isError" class="fixed inset-0 z-0 overflow-hidden">
|
|
<div class="size-full">
|
|
<BaseTerminal @created="terminalCreated" />
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Semi-transparent overlay -->
|
|
<div v-if="!isError" class="fixed inset-0 z-5 bg-neutral-900/80"></div>
|
|
|
|
<!-- Smooth radial gradient overlay -->
|
|
<div
|
|
v-if="!isError"
|
|
class="fixed inset-0 z-8"
|
|
style="
|
|
background: radial-gradient(
|
|
ellipse 800px 600px at center,
|
|
rgb(23 23 23 / 0.95) 0%,
|
|
rgb(23 23 23 / 0.93) 10%,
|
|
rgb(23 23 23 / 0.9) 20%,
|
|
rgb(23 23 23 / 0.85) 30%,
|
|
rgb(23 23 23 / 0.75) 40%,
|
|
rgb(23 23 23 / 0.6) 50%,
|
|
rgb(23 23 23 / 0.4) 60%,
|
|
rgb(23 23 23 / 0.2) 70%,
|
|
rgb(23 23 23 / 0.1) 80%,
|
|
rgb(23 23 23 / 0.05) 90%,
|
|
transparent 100%
|
|
);
|
|
"
|
|
></div>
|
|
|
|
<div class="relative z-10">
|
|
<!-- Main startup display using StartupDisplay component -->
|
|
<StartupDisplay
|
|
:title="displayTitle"
|
|
:status-text="displayStatusText"
|
|
:progress-percentage="installStageProgress"
|
|
:hide-progress="isError"
|
|
/>
|
|
|
|
<!-- Error Section (positioned at bottom) -->
|
|
<div
|
|
v-if="isError"
|
|
class="absolute inset-x-0 bottom-20 flex flex-col items-center gap-4"
|
|
>
|
|
<div class="flex justify-center gap-4">
|
|
<Button
|
|
icon="pi pi-flag"
|
|
:label="$t('serverStart.reportIssue')"
|
|
severity="secondary"
|
|
@click="reportIssue"
|
|
/>
|
|
<Button
|
|
icon="pi pi-file"
|
|
:label="$t('serverStart.openLogs')"
|
|
severity="secondary"
|
|
@click="openLogs"
|
|
/>
|
|
<Button
|
|
icon="pi pi-wrench"
|
|
:label="$t('serverStart.troubleshoot')"
|
|
@click="troubleshoot"
|
|
/>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Terminal Output (positioned at bottom when manually toggled in error state) -->
|
|
<div
|
|
v-if="terminalVisible && isError"
|
|
class="absolute inset-x-4 bottom-4 z-10 mx-auto max-w-4xl"
|
|
>
|
|
<div
|
|
class="h-[300px] rounded-lg border border-neutral-700 bg-neutral-900/95 p-4"
|
|
>
|
|
<BaseTerminal @created="terminalCreated" />
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</BaseViewTemplate>
|
|
</template>
|
|
|
|
<script setup lang="ts">
|
|
import { InstallStage, ProgressStatus } from '@comfyorg/comfyui-electron-types'
|
|
import type {
|
|
InstallStageInfo,
|
|
InstallStageName
|
|
} from '@comfyorg/comfyui-electron-types'
|
|
import type { Terminal } from '@xterm/xterm'
|
|
import Button from 'primevue/button'
|
|
import type { Ref } from 'vue'
|
|
import { computed, onMounted, onUnmounted, ref } from 'vue'
|
|
import { useI18n } from 'vue-i18n'
|
|
|
|
import BaseTerminal from '@/components/bottomPanel/tabs/terminal/BaseTerminal.vue'
|
|
import StartupDisplay from '@/components/common/StartupDisplay.vue'
|
|
import type { useTerminal } from '@/composables/bottomPanelTabs/useTerminal'
|
|
import { electronAPI } from '@/utils/envUtil'
|
|
import BaseViewTemplate from '@/views/templates/BaseViewTemplate.vue'
|
|
|
|
const { t } = useI18n()
|
|
const electron = electronAPI()
|
|
|
|
const status = ref<ProgressStatus>(ProgressStatus.INITIAL_STATE)
|
|
const electronVersion = ref<string>('')
|
|
const terminalVisible = ref(false)
|
|
|
|
const installStage = ref<InstallStageName | null>(null)
|
|
const installStageMessage = ref<string>('')
|
|
const installStageProgress = ref<number | undefined>(undefined)
|
|
|
|
let xterm: Terminal | undefined
|
|
|
|
/**
|
|
* Handles installation stage updates from the desktop
|
|
*/
|
|
const updateInstallStage = (stageInfo: InstallStageInfo) => {
|
|
console.warn('[InstallStage.onUpdate] Received:', {
|
|
stage: stageInfo.stage,
|
|
progress: stageInfo.progress,
|
|
message: stageInfo.message,
|
|
error: stageInfo.error,
|
|
timestamp: stageInfo.timestamp,
|
|
fullInfo: stageInfo
|
|
})
|
|
|
|
installStage.value = stageInfo.stage
|
|
installStageMessage.value = stageInfo.message || ''
|
|
installStageProgress.value = stageInfo.progress
|
|
}
|
|
|
|
const currentStatusLabel = computed(() => {
|
|
// Use the message from the Electron API if available
|
|
if (installStageMessage.value) {
|
|
return installStageMessage.value
|
|
}
|
|
return t(`serverStart.process.${status.value}`)
|
|
})
|
|
|
|
const isError = computed(
|
|
() =>
|
|
status.value === ProgressStatus.ERROR ||
|
|
installStage.value === InstallStage.ERROR
|
|
)
|
|
|
|
const isInstallationStage = computed(() => {
|
|
const installationStages: InstallStageName[] = [
|
|
InstallStage.WELCOME_SCREEN,
|
|
InstallStage.INSTALL_OPTIONS_SELECTION,
|
|
InstallStage.CREATING_DIRECTORIES,
|
|
InstallStage.INITIALIZING_CONFIG,
|
|
InstallStage.PYTHON_ENVIRONMENT_SETUP,
|
|
InstallStage.INSTALLING_REQUIREMENTS,
|
|
InstallStage.INSTALLING_PYTORCH,
|
|
InstallStage.INSTALLING_COMFYUI_REQUIREMENTS,
|
|
InstallStage.INSTALLING_MANAGER_REQUIREMENTS,
|
|
InstallStage.MIGRATING_CUSTOM_NODES
|
|
]
|
|
return (
|
|
installStage.value !== null &&
|
|
installationStages.includes(installStage.value)
|
|
)
|
|
})
|
|
|
|
const displayTitle = computed(() => {
|
|
if (isError.value) {
|
|
return t('serverStart.errorMessage')
|
|
}
|
|
if (isInstallationStage.value) {
|
|
return t('serverStart.installation.title')
|
|
}
|
|
return t('serverStart.title')
|
|
})
|
|
|
|
const displayStatusText = computed(() => {
|
|
if (isError.value && electronVersion.value) {
|
|
return `v${electronVersion.value}`
|
|
}
|
|
return currentStatusLabel.value
|
|
})
|
|
|
|
const updateProgress = ({ status: newStatus }: { status: ProgressStatus }) => {
|
|
status.value = newStatus
|
|
|
|
// Make critical error screen more obvious.
|
|
if (newStatus === ProgressStatus.ERROR) terminalVisible.value = false
|
|
}
|
|
|
|
const terminalCreated = (
|
|
{ terminal, useAutoSize }: ReturnType<typeof useTerminal>,
|
|
root: Ref<HTMLElement | undefined>
|
|
) => {
|
|
xterm = terminal
|
|
|
|
useAutoSize({ root, autoRows: true, autoCols: true })
|
|
electron.onLogMessage((message: string) => {
|
|
terminal.write(message)
|
|
})
|
|
|
|
terminal.options.cursorBlink = false
|
|
terminal.options.disableStdin = true
|
|
terminal.options.cursorInactiveStyle = 'block'
|
|
}
|
|
|
|
const troubleshoot = () => electron.startTroubleshooting()
|
|
const reportIssue = () => {
|
|
window.open('https://forum.comfy.org/c/v1-feedback/', '_blank')
|
|
}
|
|
const openLogs = () => electron.openLogsFolder()
|
|
|
|
let cleanupInstallStageListener: (() => void) | undefined
|
|
|
|
onMounted(async () => {
|
|
electron.sendReady()
|
|
electron.onProgressUpdate(updateProgress)
|
|
cleanupInstallStageListener =
|
|
electron.InstallStage.onUpdate(updateInstallStage)
|
|
|
|
const stageInfo = await electron.InstallStage.getCurrent()
|
|
updateInstallStage(stageInfo)
|
|
electronVersion.value = await electron.getElectronVersion()
|
|
})
|
|
|
|
onUnmounted(() => {
|
|
xterm?.dispose()
|
|
cleanupInstallStageListener?.()
|
|
})
|
|
</script>
|
|
|
|
<style scoped>
|
|
/* Hide the xterm scrollbar completely */
|
|
:deep(.p-terminal) .xterm-viewport {
|
|
overflow: hidden !important;
|
|
}
|
|
</style>
|