Files
ComfyUI_frontend/src/App.vue
Benjamin Lu dd89b74ca5 fix: wait for settings before cloud desktop promo (#10526)
this fixes two issues, setting store race did not await load, and it
only cleared shown on clear not on show

## Summary

Wait for settings to load before deciding whether to show the one-time
macOS desktop cloud promo so the persisted dismissal state is respected
on launch.

## Changes

- **What**: Await `settingStore.load()` before checking
`Comfy.Desktop.CloudNotificationShown`, keep the promo gated to macOS
desktop, and persist the shown flag before awaiting dialog close.
- **Dependencies**: None

## Review Focus

- Launch-time settings race for `Comfy.Desktop.CloudNotificationShown`
- One-time modal behavior if the app closes before the dialog is
dismissed
- Regression coverage in `src/App.test.ts`

## Screenshots (if applicable)

- N/A

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-10526-fix-wait-for-settings-before-cloud-desktop-promo-32e6d73d365081939fc3ca5b4346b873)
by [Unito](https://www.unito.io)

---------

Co-authored-by: Alexander Brown <drjkl@comfy.org>
2026-03-26 22:31:31 -07:00

132 lines
4.0 KiB
Vue

<template>
<router-view />
<GlobalDialog />
<BlockUI full-screen :blocked="isLoading" />
</template>
<script setup lang="ts">
import { captureException } from '@sentry/vue'
import BlockUI from 'primevue/blockui'
import { computed, onMounted, watch } from 'vue'
import GlobalDialog from '@/components/dialog/GlobalDialog.vue'
import config from '@/config'
import { isDesktop } from '@/platform/distribution/types'
import { app } from '@/scripts/app'
import { useWorkspaceStore } from '@/stores/workspaceStore'
import { electronAPI } from '@/utils/envUtil'
import { parsePreloadError } from '@/utils/preloadErrorUtil'
import { useConflictDetection } from '@/workbench/extensions/manager/composables/useConflictDetection'
const workspaceStore = useWorkspaceStore()
app.extensionManager = useWorkspaceStore()
const conflictDetection = useConflictDetection()
const isLoading = computed<boolean>(() => workspaceStore.spinner)
watch(
isLoading,
(loading, prevLoading) => {
if (prevLoading && !loading) {
document.getElementById('splash-loader')?.remove()
}
},
{ flush: 'post' }
)
const showContextMenu = (event: MouseEvent) => {
const { target } = event
switch (true) {
case target instanceof HTMLTextAreaElement:
case target instanceof HTMLInputElement && target.type === 'text':
// TODO: Context input menu explicitly for text input
electronAPI()?.showContextMenu({ type: 'text' })
return
}
}
function handleResourceError(url: string, tagName: string) {
console.error('[resource:loadError]', { url, tagName })
if (__DISTRIBUTION__ === 'cloud') {
captureException(new Error(`Resource load failed: ${url}`), {
tags: {
error_type: 'resource_load_error',
tag_name: tagName
}
})
}
}
onMounted(() => {
window['__COMFYUI_FRONTEND_VERSION__'] = config.app_version
if (isDesktop) {
document.addEventListener('contextmenu', showContextMenu)
}
// Handle preload errors that occur during dynamic imports (e.g., stale chunks after deployment)
// See: https://vite.dev/guide/build#load-error-handling
window.addEventListener('vite:preloadError', (event) => {
event.preventDefault()
const info = parsePreloadError(event.payload)
console.error('[vite:preloadError]', {
url: info.url,
fileType: info.fileType,
chunkName: info.chunkName,
message: info.message
})
if (__DISTRIBUTION__ === 'cloud') {
captureException(event.payload, {
tags: {
error_type: 'vite_preload_error',
file_type: info.fileType,
chunk_name: info.chunkName ?? undefined
},
contexts: {
preload: {
url: info.url,
fileType: info.fileType,
chunkName: info.chunkName
}
}
})
}
// Disabled: Third-party custom node extensions frequently trigger this toast
// (e.g., bare "vue" imports, wrong relative paths to scripts/app.js, missing
// core dependencies). These are plugin bugs, not ComfyUI core failures, but
// the generic error message alarms users and offers no actionable guidance.
// The console.error above still logs the details for developers to debug.
// useToastStore().add({
// severity: 'error',
// summary: t('g.preloadErrorTitle'),
// detail: t('g.preloadError'),
// life: 10000
// })
})
// Capture resource load failures (CSS, scripts) in non-localhost distributions
if (__DISTRIBUTION__ !== 'localhost') {
window.addEventListener(
'error',
(event) => {
const target = event.target
if (target instanceof HTMLScriptElement) {
handleResourceError(target.src, 'script')
} else if (
target instanceof HTMLLinkElement &&
target.rel === 'stylesheet'
) {
handleResourceError(target.href, 'link')
}
},
true
)
}
// Initialize conflict detection in background
// This runs async and doesn't block UI setup
void conflictDetection.initializeConflictDetection()
})
</script>