mirror of
https://github.com/Comfy-Org/ComfyUI_frontend.git
synced 2026-01-31 21:39:54 +00:00
## Summary Backporting #5292 to core/1.27 branch to fix desktop installation and startup UX issues. ## What's Changed This is a manual backport of commitb0f81b2245which reworks the desktop install and startup user experience. ### Merge Conflicts Resolved The automatic backport failed with conflicts in: - `src/components/install/GpuPicker.vue` - Resolved by keeping the changes made in the PR - `src/components/install/MirrorsConfiguration.vue` - Resolved by keeping the file deletion from the PR - `src/components/install/mirror/MirrorItem.vue` - Resolved by combination merge (all changes) - `src/views/ServerStartView.vue` - Resolved by combination merge (all changes) ## Original PR - PR: #5292 - Commit:b0f81b2245- Title: Rework desktop install / startup UX ┆Issue is synchronized with this [Notion page](https://www.notion.so/PR-5756-Backport-1-27-Rework-desktop-install-startup-UX-5292-2786d73d365081668f4dc16694c51185) by [Unito](https://www.unito.io)
211 lines
6.1 KiB
Vue
211 lines
6.1 KiB
Vue
<template>
|
|
<BaseViewTemplate dark>
|
|
<!-- Fixed height container with flexbox layout for proper content management -->
|
|
<div class="w-full h-full flex flex-col">
|
|
<Stepper
|
|
v-model:value="currentStep"
|
|
class="flex flex-col h-full"
|
|
@update:value="handleStepChange"
|
|
>
|
|
<!-- Main content area that grows to fill available space -->
|
|
<StepPanels
|
|
class="flex-1 overflow-auto"
|
|
:style="{ scrollbarGutter: 'stable' }"
|
|
>
|
|
<StepPanel value="1" class="flex">
|
|
<GpuPicker v-model:device="device" />
|
|
</StepPanel>
|
|
<StepPanel value="2">
|
|
<InstallLocationPicker
|
|
v-model:install-path="installPath"
|
|
v-model:path-error="pathError"
|
|
v-model:migration-source-path="migrationSourcePath"
|
|
v-model:migration-item-ids="migrationItemIds"
|
|
v-model:python-mirror="pythonMirror"
|
|
v-model:pypi-mirror="pypiMirror"
|
|
v-model:torch-mirror="torchMirror"
|
|
:device="device"
|
|
/>
|
|
</StepPanel>
|
|
<StepPanel value="3">
|
|
<DesktopSettingsConfiguration
|
|
v-model:auto-update="autoUpdate"
|
|
v-model:allow-metrics="allowMetrics"
|
|
/>
|
|
</StepPanel>
|
|
</StepPanels>
|
|
|
|
<!-- Install footer with navigation -->
|
|
<InstallFooter
|
|
class="w-full max-w-2xl my-6 mx-auto"
|
|
:current-step
|
|
:can-proceed
|
|
:disable-location-step="noGpu"
|
|
:disable-migration-step="noGpu || hasError || highestStep < 2"
|
|
:disable-settings-step="noGpu || hasError || highestStep < 3"
|
|
@previous="goToPreviousStep"
|
|
@next="goToNextStep"
|
|
@install="install"
|
|
/>
|
|
</Stepper>
|
|
</div>
|
|
</BaseViewTemplate>
|
|
</template>
|
|
|
|
<script setup lang="ts">
|
|
import type {
|
|
InstallOptions,
|
|
TorchDeviceType
|
|
} from '@comfyorg/comfyui-electron-types'
|
|
import StepPanel from 'primevue/steppanel'
|
|
import StepPanels from 'primevue/steppanels'
|
|
import Stepper from 'primevue/stepper'
|
|
import { computed, onMounted, ref, toRaw } from 'vue'
|
|
import { useRouter } from 'vue-router'
|
|
|
|
import DesktopSettingsConfiguration from '@/components/install/DesktopSettingsConfiguration.vue'
|
|
import GpuPicker from '@/components/install/GpuPicker.vue'
|
|
import InstallFooter from '@/components/install/InstallFooter.vue'
|
|
import InstallLocationPicker from '@/components/install/InstallLocationPicker.vue'
|
|
import { electronAPI } from '@/utils/envUtil'
|
|
import BaseViewTemplate from '@/views/templates/BaseViewTemplate.vue'
|
|
|
|
const device = ref<TorchDeviceType | null>(null)
|
|
|
|
const installPath = ref('')
|
|
const pathError = ref('')
|
|
|
|
const migrationSourcePath = ref('')
|
|
const migrationItemIds = ref<string[]>([])
|
|
|
|
const autoUpdate = ref(true)
|
|
const allowMetrics = ref(true)
|
|
const pythonMirror = ref('')
|
|
const pypiMirror = ref('')
|
|
const torchMirror = ref('')
|
|
|
|
/** Current step in the stepper */
|
|
const currentStep = ref('1')
|
|
|
|
/** Forces each install step to be visited at least once. */
|
|
const highestStep = ref(0)
|
|
|
|
const handleStepChange = (value: string | number) => {
|
|
setHighestStep(value)
|
|
|
|
electronAPI().Events.trackEvent('install_stepper_change', {
|
|
step: value
|
|
})
|
|
}
|
|
|
|
const setHighestStep = (value: string | number) => {
|
|
const int = typeof value === 'number' ? value : parseInt(value, 10)
|
|
if (!isNaN(int) && int > highestStep.value) highestStep.value = int
|
|
}
|
|
|
|
const hasError = computed(() => pathError.value !== '')
|
|
const noGpu = computed(() => typeof device.value !== 'string')
|
|
|
|
// Computed property to determine if user can proceed to next step
|
|
const regex = /^Insufficient space - minimum free space: \d+ GB$/
|
|
|
|
const canProceed = computed(() => {
|
|
switch (currentStep.value) {
|
|
case '1':
|
|
return typeof device.value === 'string'
|
|
case '2':
|
|
return pathError.value === '' || regex.test(pathError.value)
|
|
case '3':
|
|
return !hasError.value
|
|
default:
|
|
return false
|
|
}
|
|
})
|
|
|
|
// Navigation methods
|
|
const goToNextStep = () => {
|
|
const nextStep = (parseInt(currentStep.value) + 1).toString()
|
|
currentStep.value = nextStep
|
|
setHighestStep(nextStep)
|
|
electronAPI().Events.trackEvent('install_stepper_change', {
|
|
step: nextStep
|
|
})
|
|
}
|
|
|
|
const goToPreviousStep = () => {
|
|
const prevStep = (parseInt(currentStep.value) - 1).toString()
|
|
currentStep.value = prevStep
|
|
electronAPI().Events.trackEvent('install_stepper_change', {
|
|
step: prevStep
|
|
})
|
|
}
|
|
|
|
const electron = electronAPI()
|
|
const router = useRouter()
|
|
const install = async () => {
|
|
const options: InstallOptions = {
|
|
installPath: installPath.value,
|
|
autoUpdate: autoUpdate.value,
|
|
allowMetrics: allowMetrics.value,
|
|
migrationSourcePath: migrationSourcePath.value,
|
|
migrationItemIds: toRaw(migrationItemIds.value),
|
|
pythonMirror: pythonMirror.value,
|
|
pypiMirror: pypiMirror.value,
|
|
torchMirror: torchMirror.value,
|
|
// @ts-expect-error fixme ts strict error
|
|
device: device.value
|
|
}
|
|
electron.installComfyUI(options)
|
|
|
|
const nextPage =
|
|
options.device === 'unsupported' ? '/manual-configuration' : '/server-start'
|
|
await router.push(nextPage)
|
|
}
|
|
|
|
onMounted(async () => {
|
|
if (!electron) return
|
|
|
|
const detectedGpu = await electron.Config.getDetectedGpu()
|
|
if (detectedGpu === 'mps' || detectedGpu === 'nvidia') {
|
|
device.value = detectedGpu
|
|
}
|
|
|
|
electronAPI().Events.trackEvent('install_stepper_change', {
|
|
step: currentStep.value,
|
|
gpu: detectedGpu
|
|
})
|
|
})
|
|
</script>
|
|
|
|
<style scoped>
|
|
@reference '../assets/css/style.css';
|
|
|
|
:deep(.p-steppanel) {
|
|
@apply mt-8 flex justify-center bg-transparent;
|
|
}
|
|
|
|
/* Remove default padding/margin from StepPanels to make scrollbar flush */
|
|
:deep(.p-steppanels) {
|
|
@apply p-0 m-0;
|
|
}
|
|
|
|
/* Ensure StepPanel content container has no top/bottom padding */
|
|
:deep(.p-steppanel-content) {
|
|
@apply p-0;
|
|
}
|
|
|
|
/* Custom overlay scrollbar for WebKit browsers (Electron, Chrome) */
|
|
:deep(.p-steppanels::-webkit-scrollbar) {
|
|
@apply w-4;
|
|
}
|
|
|
|
:deep(.p-steppanels::-webkit-scrollbar-track) {
|
|
@apply bg-transparent;
|
|
}
|
|
|
|
:deep(.p-steppanels::-webkit-scrollbar-thumb) {
|
|
@apply bg-white/20 rounded-lg border-[4px] border-transparent;
|
|
background-clip: content-box;
|
|
}
|
|
</style>
|