mirror of
https://github.com/Comfy-Org/ComfyUI_frontend.git
synced 2026-04-28 10:12:11 +00:00
[Electron] ComfyUI Desktop install wizard (#1503)
* Basic prototype * Welcome screen animation * nit * Refactor structure * Fix mocking * Add tooltips * i18n * Add next button * nit * Stepper navigate * Extract * More i18n * More i18n * Polish MigrationPicker * Polish settings step * Add more i18n * nit * nit
This commit is contained in:
136
src/components/install/MigrationPicker.vue
Normal file
136
src/components/install/MigrationPicker.vue
Normal file
@@ -0,0 +1,136 @@
|
||||
<template>
|
||||
<div class="flex flex-col gap-6 w-[600px]">
|
||||
<!-- Source Location Section -->
|
||||
<div class="flex flex-col gap-4">
|
||||
<h2 class="text-2xl font-semibold text-neutral-100">
|
||||
{{ $t('install.migrateFromExistingInstallation') }}
|
||||
</h2>
|
||||
|
||||
<p class="text-neutral-400 my-0">
|
||||
{{ $t('install.migrationSourcePathDescription') }}
|
||||
</p>
|
||||
|
||||
<div class="flex gap-2">
|
||||
<InputText
|
||||
v-model="sourcePath"
|
||||
placeholder="Select existing ComfyUI installation (optional)"
|
||||
class="flex-1"
|
||||
:class="{ 'p-invalid': pathError }"
|
||||
@change="validateSource"
|
||||
/>
|
||||
<Button icon="pi pi-folder" @click="browsePath" class="w-12" />
|
||||
</div>
|
||||
|
||||
<Message v-if="pathError" severity="error">
|
||||
{{ pathError }}
|
||||
</Message>
|
||||
</div>
|
||||
|
||||
<!-- Migration Options -->
|
||||
<div
|
||||
v-if="isValidSource"
|
||||
class="flex flex-col gap-4 bg-neutral-800 p-4 rounded-lg"
|
||||
>
|
||||
<h3 class="text-lg mt-0 font-medium text-neutral-100">
|
||||
{{ $t('install.selectItemsToMigrate') }}
|
||||
</h3>
|
||||
|
||||
<div class="flex flex-col gap-3">
|
||||
<div
|
||||
v-for="item in migrationItems"
|
||||
:key="item.id"
|
||||
class="flex items-center gap-3 p-2 hover:bg-neutral-700 rounded"
|
||||
@click="item.selected = !item.selected"
|
||||
>
|
||||
<Checkbox
|
||||
v-model="item.selected"
|
||||
:inputId="item.id"
|
||||
:binary="true"
|
||||
@click.stop
|
||||
/>
|
||||
<div>
|
||||
<label :for="item.id" class="text-neutral-200 font-medium">
|
||||
{{ item.label }}
|
||||
</label>
|
||||
<p class="text-sm text-neutral-400 my-1">
|
||||
{{ item.description }}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Skip Migration -->
|
||||
<div v-else class="text-neutral-400 italic">
|
||||
{{ $t('install.migrationOptional') }}
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, computed, onMounted, watchEffect } from 'vue'
|
||||
import { electronAPI } from '@/utils/envUtil'
|
||||
import InputText from 'primevue/inputtext'
|
||||
import Button from 'primevue/button'
|
||||
import Checkbox from 'primevue/checkbox'
|
||||
import Message from 'primevue/message'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
|
||||
const { t } = useI18n()
|
||||
|
||||
const electron = electronAPI() as any
|
||||
|
||||
const sourcePath = defineModel<string>('sourcePath', { required: false })
|
||||
const migrationItemIds = defineModel<string[]>('migrationItemIds', {
|
||||
required: false
|
||||
})
|
||||
|
||||
const migrationItems = ref([])
|
||||
const pathError = ref('')
|
||||
const isValidSource = computed(
|
||||
() => sourcePath.value !== '' && pathError.value === ''
|
||||
)
|
||||
|
||||
const validateSource = async () => {
|
||||
if (!sourcePath.value) {
|
||||
pathError.value = ''
|
||||
return
|
||||
}
|
||||
|
||||
try {
|
||||
pathError.value = ''
|
||||
const validation = await electron.validateComfyUISource(sourcePath.value)
|
||||
|
||||
if (!validation.isValid) pathError.value = validation.error
|
||||
} catch (error) {
|
||||
console.error(error)
|
||||
pathError.value = t('install.pathValidationFailed')
|
||||
}
|
||||
}
|
||||
|
||||
const browsePath = async () => {
|
||||
try {
|
||||
const result = await electron.showDirectoryPicker()
|
||||
if (result) {
|
||||
sourcePath.value = result
|
||||
await validateSource()
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(error)
|
||||
pathError.value = t('install.failedToSelectDirectory')
|
||||
}
|
||||
}
|
||||
|
||||
onMounted(async () => {
|
||||
migrationItems.value = (await electron.migrationItems()).map((item) => ({
|
||||
...item,
|
||||
selected: true
|
||||
}))
|
||||
})
|
||||
|
||||
watchEffect(() => {
|
||||
migrationItemIds.value = migrationItems.value
|
||||
.filter((item) => item.selected)
|
||||
.map((item) => item.id)
|
||||
})
|
||||
</script>
|
||||
Reference in New Issue
Block a user