Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Electron] Add basic welcome screen #1491

Merged
merged 10 commits into from
Nov 10, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
9 changes: 4 additions & 5 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
"type": "module",
"scripts": {
"dev": "vite",
"dev:electron": "vite --config vite.electron.config.mts",
"build": "npm run typecheck && vite build",
"deploy": "npm run build && node scripts/deploy.js",
"release": "node scripts/release.js",
Expand All @@ -26,7 +27,6 @@
"devDependencies": {
"@babel/core": "^7.24.7",
"@babel/preset-env": "^7.22.20",
"@comfyorg/comfyui-electron-types": "^0.2.9",
"@eslint/js": "^9.8.0",
"@iconify/json": "^2.2.245",
"@pinia/testing": "^0.1.5",
Expand Down Expand Up @@ -71,6 +71,7 @@
},
"dependencies": {
"@atlaskit/pragmatic-drag-and-drop": "^1.3.1",
"@comfyorg/comfyui-electron-types": "^0.2.10",
"@comfyorg/litegraph": "^0.8.24",
"@primevue/themes": "^4.0.5",
"@vueuse/core": "^11.0.0",
Expand Down
66 changes: 66 additions & 0 deletions src/components/common/LogTerminal.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
<!-- A simple read-only terminal component that displays logs. -->
<template>
<div class="p-terminal rounded-none h-full w-full">
<ScrollPanel class="h-full w-full" ref="scrollPanelRef">
<pre class="px-4 whitespace-pre-wrap">{{ log }}</pre>
</ScrollPanel>
</div>
</template>

<script setup lang="ts">
import ScrollPanel from 'primevue/scrollpanel'
import { onBeforeUnmount, onMounted, ref, watch } from 'vue'

const props = defineProps<{
fetchLogs: () => Promise<string>
fetchInterval: number
}>()

const log = ref<string>('')
const scrollPanelRef = ref<InstanceType<typeof ScrollPanel> | null>(null)
/**
* Whether the user has scrolled to the bottom of the terminal.
* This is used to prevent the terminal from scrolling to the bottom
* when new logs are fetched.
*/
const scrolledToBottom = ref(false)

let intervalId: number = 0

onMounted(async () => {
const element = scrollPanelRef.value?.$el
const scrollContainer = element?.querySelector('.p-scrollpanel-content')

if (scrollContainer) {
scrollContainer.addEventListener('scroll', () => {
scrolledToBottom.value =
scrollContainer.scrollTop + scrollContainer.clientHeight ===
scrollContainer.scrollHeight
})
}

const scrollToBottom = () => {
if (scrollContainer) {
scrollContainer.scrollTop = scrollContainer.scrollHeight
}
}

watch(log, () => {
if (scrolledToBottom.value) {
scrollToBottom()
}
})

const fetchLogs = async () => {
log.value = await props.fetchLogs()
}

await fetchLogs()
scrollToBottom()
intervalId = window.setInterval(fetchLogs, props.fetchInterval)
})

onBeforeUnmount(() => {
window.clearInterval(intervalId)
})
</script>
47 changes: 47 additions & 0 deletions src/components/install/WelcomeScreen.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
<template>
<div class="flex flex-col items-center justify-center gap-8 p-8">
<!-- Header -->
<h1 class="text-4xl font-bold text-neutral-100">Welcome to ComfyUI</h1>

<!-- Get Started Button -->
<Button
label="Get Started"
icon="pi pi-arrow-right"
iconPos="right"
size="large"
@click="$emit('start')"
class="p-4 text-lg"
/>

<!-- Installation Steps -->
<div class="w-[600px]">
<Steps :model="installSteps" :readonly="true" />
</div>
</div>
</template>

<script setup lang="ts">
import Steps from 'primevue/steps'
import Button from 'primevue/button'

const installSteps = [
{
label: 'Install Location',
icon: 'pi pi-folder'
},
{
label: 'Migration',
icon: 'pi pi-download'
},
{
label: 'Desktop Settings',
icon: 'pi pi-desktop'
},
{
label: 'Review',
icon: 'pi pi-check'
}
]

defineEmits(['start'])
</script>
13 changes: 13 additions & 0 deletions src/router.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,19 @@ const router = createRouter({
next('/')
}
}
},
{
path: 'install',
name: 'InstallView',
component: () => import('@/views/InstallView.vue'),
beforeEnter: async (to, from, next) => {
// Only allow access to this page in electron environment
if (isElectron()) {
next()
} else {
next('/')
}
}
}
]
}
Expand Down
2 changes: 2 additions & 0 deletions src/scripts/app.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1784,6 +1784,8 @@ export class ComfyApp {
*/
async setup(canvasEl: HTMLCanvasElement) {
this.canvasEl = canvasEl
// Show menu container for GraphView.
this.ui.menuContainer.style.display = 'block'
await this.#setUser()

this.resizeCanvas()
Expand Down
2 changes: 2 additions & 0 deletions src/scripts/ui.ts
Original file line number Diff line number Diff line change
Expand Up @@ -636,6 +636,8 @@ export class ComfyUI {
}
})
]) as HTMLDivElement
// Hide by default on construction so it does not interfere with other views.
this.menuContainer.style.display = 'none'

this.restoreMenuPosition = dragElement(this.menuContainer, this.settings)

Expand Down
2 changes: 1 addition & 1 deletion src/utils/envUtil.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,5 @@ export function isElectron() {
}

export function electronAPI() {
return window['electronAPI'] as ElectronAPI
return (window as any)['electronAPI'] as ElectronAPI
}
11 changes: 11 additions & 0 deletions src/views/InstallView.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<template>
<div
class="font-sans flex flex-col justify-center items-center h-screen m-0 text-neutral-300 bg-neutral-900 dark-theme pointer-events-auto"
>
<WelcomeScreen />
</div>
</template>

<script setup lang="ts">
import WelcomeScreen from '@/components/install/WelcomeScreen.vue'
</script>
43 changes: 35 additions & 8 deletions src/views/ServerStartView.vue
Original file line number Diff line number Diff line change
@@ -1,17 +1,44 @@
<!-- This is a dummy page built for electron app only. -->
<!-- Replace this page with the electron side logic on installation & log streaming. -->
<template>
<div
class="absolute inset-0 flex flex-col items-center justify-center h-screen bg-surface-0"
class="font-sans flex flex-col justify-center items-center h-screen m-0 text-neutral-300 bg-neutral-900 dark-theme pointer-events-auto"
>
<ProgressSpinner class="w-16 h-16 mb-4" />
<div class="text-xl">{{ $t('loading') }}{{ counter }}</div>
<h2 class="text-2xl font-bold">{{ ProgressMessages[status] }}</h2>
<LogTerminal :fetch-logs="fetchLogs" :fetch-interval="500" />
</div>
</template>

<script setup lang="ts">
import ProgressSpinner from 'primevue/progressspinner'
import { useInterval } from '@vueuse/core'
import { ref, onMounted } from 'vue'
import LogTerminal from '@/components/common/LogTerminal.vue'
import {
ProgressStatus,
ProgressMessages
} from '@comfyorg/comfyui-electron-types'
import { electronAPI as getElectronAPI } from '@/utils/envUtil'

const counter = useInterval(1000)
const electronAPI = getElectronAPI()

const status = ref<ProgressStatus>(ProgressStatus.INITIAL_STATE)
const logs = ref<string[]>([])

const updateProgress = ({ status: newStatus }: { status: ProgressStatus }) => {
status.value = newStatus
logs.value = [] // Clear logs when status changes
}

const addLogMessage = (message: string) => {
logs.value = [...logs.value, message]
}

const fetchLogs = async () => {
return logs.value.join('\n')
}

onMounted(() => {
electronAPI.sendReady()
electronAPI.onProgressUpdate(updateProgress)
electronAPI.onLogMessage((message: string) => {
addLogMessage(message)
})
})
</script>
33 changes: 33 additions & 0 deletions vite.electron.config.mts
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import { defineConfig, Plugin } from 'vite'
import { mergeConfig } from 'vite'
import type { UserConfig } from 'vitest/config'
import baseConfig from './vite.config.mts'
import type { ElectronAPI } from '@comfyorg/comfyui-electron-types'

const electronAPIMock: Partial<ElectronAPI> = {
sendReady: () => {},
onShowSelectDirectory: () => {},
onFirstTimeSetupComplete: () => {},
onProgressUpdate: () => {},
onLogMessage: () => {},
isFirstTimeSetup: () => Promise.resolve(true)
}

const mockElectronAPI: Plugin = {
name: 'mock-electron-api',
transformIndexHtml() {
return [
{
tag: 'script',
children: `window.electronAPI = ${JSON.stringify(electronAPIMock)};`
}
]
}
}

export default mergeConfig(
baseConfig as unknown as UserConfig,
defineConfig({
plugins: [mockElectronAPI]
})
)
Loading