mirror of
https://github.com/Comfy-Org/ComfyUI_frontend.git
synced 2026-02-04 15:10:06 +00:00
use update service
This commit is contained in:
23
src/App.vue
23
src/App.vue
@@ -17,7 +17,6 @@ import { computed, onMounted } from 'vue'
|
||||
import GlobalDialog from '@/components/dialog/GlobalDialog.vue'
|
||||
import config from '@/config'
|
||||
import { t } from '@/i18n'
|
||||
import { useSettingStore } from '@/platform/settings/settingStore'
|
||||
import { useWorkflowStore } from '@/platform/workflow/management/stores/workflowStore'
|
||||
import { app } from '@/scripts/app'
|
||||
import { useDialogService } from '@/services/dialogService'
|
||||
@@ -48,7 +47,7 @@ const showContextMenu = (event: MouseEvent) => {
|
||||
}
|
||||
}
|
||||
|
||||
onMounted(async () => {
|
||||
onMounted(() => {
|
||||
window['__COMFYUI_FRONTEND_VERSION__'] = config.app_version
|
||||
|
||||
if (isElectron()) {
|
||||
@@ -78,25 +77,5 @@ onMounted(async () => {
|
||||
// Initialize conflict detection in background
|
||||
// This runs async and doesn't block UI setup
|
||||
void conflictDetection.initializeConflictDetection()
|
||||
|
||||
// Show cloud notification for macOS desktop users (one-time)
|
||||
// Delayed to ensure it appears after workflow loading (missing models dialog, etc.)
|
||||
if (isElectron()) {
|
||||
const isMacOS = navigator.platform.toLowerCase().includes('mac')
|
||||
if (isMacOS) {
|
||||
const settingStore = useSettingStore()
|
||||
const hasShownNotification = settingStore.get(
|
||||
'Comfy.Desktop.CloudNotificationShown'
|
||||
)
|
||||
|
||||
if (!hasShownNotification) {
|
||||
// Delay to show after initial workflow loading completes
|
||||
setTimeout(async () => {
|
||||
dialogService.showCloudNotification()
|
||||
await settingStore.set('Comfy.Desktop.CloudNotificationShown', true)
|
||||
}, 2000)
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import tgpu from 'typegpu'
|
||||
import typegpu from 'typegpu'
|
||||
import * as d from 'typegpu/data'
|
||||
import { BrushUniforms } from './gpuSchema'
|
||||
|
||||
@@ -38,7 +38,7 @@ fn vs(
|
||||
}
|
||||
`
|
||||
|
||||
export const brushVertex = tgpu.resolve({
|
||||
export const brushVertex = typegpu.resolve({
|
||||
template: brushVertexTemplate,
|
||||
externals: {
|
||||
BrushUniforms,
|
||||
@@ -75,7 +75,7 @@ fn fs(v: VertexOutput) -> @location(0) vec4<f32> {
|
||||
}
|
||||
`
|
||||
|
||||
export const brushFragment = tgpu.resolve({
|
||||
export const brushFragment = typegpu.resolve({
|
||||
template: brushFragmentTemplate,
|
||||
externals: {
|
||||
VertexOutput,
|
||||
@@ -100,7 +100,7 @@ const blitShaderTemplate = `
|
||||
}
|
||||
`
|
||||
|
||||
export const blitShader = tgpu.resolve({
|
||||
export const blitShader = typegpu.resolve({
|
||||
template: blitShaderTemplate,
|
||||
externals: {}
|
||||
})
|
||||
@@ -123,7 +123,7 @@ const compositeShaderTemplate = `
|
||||
}
|
||||
`
|
||||
|
||||
export const compositeShader = tgpu.resolve({
|
||||
export const compositeShader = typegpu.resolve({
|
||||
template: compositeShaderTemplate,
|
||||
externals: {
|
||||
BrushUniforms
|
||||
@@ -165,7 +165,7 @@ fn main(@builtin(global_invocation_id) id: vec3<u32>) {
|
||||
}
|
||||
`
|
||||
|
||||
export const readbackShader = tgpu.resolve({
|
||||
export const readbackShader = typegpu.resolve({
|
||||
template: readbackShaderTemplate,
|
||||
externals: {}
|
||||
})
|
||||
|
||||
@@ -296,7 +296,7 @@ export const CORE_SETTINGS: SettingParams[] = [
|
||||
{
|
||||
id: 'Comfy.Desktop.CloudNotificationShown',
|
||||
name: 'Cloud notification shown',
|
||||
type: 'boolean',
|
||||
type: 'hidden',
|
||||
defaultValue: false
|
||||
},
|
||||
{
|
||||
|
||||
@@ -45,6 +45,7 @@ function onChange(
|
||||
export const useSettingStore = defineStore('setting', () => {
|
||||
const settingValues = ref<Record<string, any>>({})
|
||||
const settingsById = ref<Record<string, SettingParams>>({})
|
||||
const isInitialized = ref(false)
|
||||
|
||||
/**
|
||||
* Check if a setting's value exists, i.e. if the user has set it manually.
|
||||
@@ -196,6 +197,7 @@ export const useSettingStore = defineStore('setting', () => {
|
||||
|
||||
// Migrate old zoom threshold setting to new font size setting
|
||||
await migrateZoomThresholdToFontSize()
|
||||
isInitialized.value = true
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -240,6 +242,7 @@ export const useSettingStore = defineStore('setting', () => {
|
||||
return {
|
||||
settingValues,
|
||||
settingsById,
|
||||
isInitialized,
|
||||
addSetting,
|
||||
loadSettingValues,
|
||||
set,
|
||||
|
||||
71
src/platform/updates/common/cloudNotificationStore.ts
Normal file
71
src/platform/updates/common/cloudNotificationStore.ts
Normal file
@@ -0,0 +1,71 @@
|
||||
import { until } from '@vueuse/core'
|
||||
import { defineStore } from 'pinia'
|
||||
import { computed, ref } from 'vue'
|
||||
|
||||
import { useSettingStore } from '@/platform/settings/settingStore'
|
||||
import { useSystemStatsStore } from '@/stores/systemStatsStore'
|
||||
import { isElectron } from '@/utils/envUtil'
|
||||
|
||||
export const useCloudNotificationStore = defineStore(
|
||||
'cloudNotification',
|
||||
() => {
|
||||
const settingStore = useSettingStore()
|
||||
const systemStatsStore = useSystemStatsStore()
|
||||
|
||||
const isReady = ref(false)
|
||||
const hasShownThisSession = ref(false)
|
||||
// Temporary override so developers can test the dialog in non-mac/non-desktop envs
|
||||
const devOverrideEnabled = import.meta.env.DEV
|
||||
|
||||
async function initialize() {
|
||||
if (isReady.value) return
|
||||
await until(settingStore.isInitialized)
|
||||
await until(systemStatsStore.isInitialized)
|
||||
isReady.value = true
|
||||
}
|
||||
|
||||
const isEligiblePlatform = computed(() => {
|
||||
if (!isReady.value) return false
|
||||
if (devOverrideEnabled) return true
|
||||
if (!isElectron()) return false
|
||||
|
||||
const osString =
|
||||
systemStatsStore.systemStats?.system?.os?.toLowerCase() ?? ''
|
||||
const platformString =
|
||||
typeof navigator === 'undefined' ? '' : navigator.platform.toLowerCase()
|
||||
|
||||
return (
|
||||
osString.includes('darwin') ||
|
||||
osString.includes('mac') ||
|
||||
platformString.includes('mac')
|
||||
)
|
||||
})
|
||||
|
||||
const hasSeenNotification = computed(() => {
|
||||
if (!isReady.value) return true
|
||||
return !!settingStore.get('Comfy.Desktop.CloudNotificationShown')
|
||||
})
|
||||
|
||||
const shouldShowNotification = computed(() => {
|
||||
if (!isReady.value) return false
|
||||
if (!isEligiblePlatform.value) return false
|
||||
|
||||
return !hasSeenNotification.value && !hasShownThisSession.value
|
||||
})
|
||||
|
||||
function markSessionShown() {
|
||||
hasShownThisSession.value = true
|
||||
}
|
||||
|
||||
async function persistNotificationShown() {
|
||||
await settingStore.set('Comfy.Desktop.CloudNotificationShown', true)
|
||||
}
|
||||
|
||||
return {
|
||||
initialize,
|
||||
shouldShowNotification,
|
||||
markSessionShown,
|
||||
persistNotificationShown
|
||||
}
|
||||
}
|
||||
)
|
||||
@@ -0,0 +1,42 @@
|
||||
<template>
|
||||
<span class="sr-only" aria-hidden="true" />
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { onBeforeUnmount, onMounted, watch } from 'vue'
|
||||
import type { WatchStopHandle } from 'vue'
|
||||
|
||||
import { useCloudNotificationStore } from '@/platform/updates/common/cloudNotificationStore'
|
||||
import { useDialogService } from '@/services/dialogService'
|
||||
|
||||
const dialogService = useDialogService()
|
||||
const cloudNotificationStore = useCloudNotificationStore()
|
||||
|
||||
let stopWatcher: WatchStopHandle | null = null
|
||||
|
||||
onMounted(async () => {
|
||||
await cloudNotificationStore.initialize()
|
||||
|
||||
stopWatcher = watch(
|
||||
() => cloudNotificationStore.shouldShowNotification,
|
||||
(shouldShow) => {
|
||||
if (shouldShow) {
|
||||
cloudNotificationStore.markSessionShown()
|
||||
dialogService.showCloudNotification()
|
||||
|
||||
void cloudNotificationStore
|
||||
.persistNotificationShown()
|
||||
.catch((error) => {
|
||||
console.error('[CloudNotification] Failed to persist flag', error)
|
||||
})
|
||||
}
|
||||
},
|
||||
{ immediate: true }
|
||||
)
|
||||
})
|
||||
|
||||
onBeforeUnmount(() => {
|
||||
stopWatcher?.()
|
||||
stopWatcher = null
|
||||
})
|
||||
</script>
|
||||
@@ -3,11 +3,17 @@ import type { useSettingStore } from '@/platform/settings/settingStore'
|
||||
let pendingCallbacks: Array<() => Promise<void>> = []
|
||||
let isNewUserDetermined = false
|
||||
let isNewUserCached: boolean | null = null
|
||||
// Temporary override to always treat dev builds as "new user" for local testing
|
||||
const devForceNewUser = import.meta.env.DEV
|
||||
|
||||
export const newUserService = () => {
|
||||
function checkIsNewUser(
|
||||
settingStore: ReturnType<typeof useSettingStore>
|
||||
): boolean {
|
||||
if (devForceNewUser) {
|
||||
return true
|
||||
}
|
||||
|
||||
const isNewUserSettings =
|
||||
Object.keys(settingStore.settingValues).length === 0 ||
|
||||
!settingStore.get('Comfy.TutorialCompleted')
|
||||
@@ -41,6 +47,16 @@ export const newUserService = () => {
|
||||
isNewUserCached = checkIsNewUser(settingStore)
|
||||
isNewUserDetermined = true
|
||||
|
||||
if (devForceNewUser) {
|
||||
localStorage.removeItem('workflow')
|
||||
localStorage.removeItem('Comfy.PreviousWorkflow')
|
||||
try {
|
||||
await settingStore.set('Comfy.TutorialCompleted', false)
|
||||
} catch (error) {
|
||||
console.error('[newUserService] Failed to reset tutorial flag', error)
|
||||
}
|
||||
}
|
||||
|
||||
if (!isNewUserCached) {
|
||||
pendingCallbacks = []
|
||||
return
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
<GlobalToast />
|
||||
<RerouteMigrationToast />
|
||||
<VueNodesMigrationToast />
|
||||
<CloudNotificationOrchestrator />
|
||||
<UnloadWindowConfirmDialog v-if="!isElectron()" />
|
||||
<MenuHamburger />
|
||||
</template>
|
||||
@@ -56,6 +57,7 @@ import { useSettingStore } from '@/platform/settings/settingStore'
|
||||
import { useTelemetry } from '@/platform/telemetry'
|
||||
import { useFrontendVersionMismatchWarning } from '@/platform/updates/common/useFrontendVersionMismatchWarning'
|
||||
import { useVersionCompatibilityStore } from '@/platform/updates/common/versionCompatibilityStore'
|
||||
import CloudNotificationOrchestrator from '@/platform/updates/components/CloudNotificationOrchestrator.vue'
|
||||
import { useCanvasStore } from '@/renderer/core/canvas/canvasStore'
|
||||
import type { StatusWsMessageStatus } from '@/schemas/apiSchema'
|
||||
import { api } from '@/scripts/api'
|
||||
|
||||
Reference in New Issue
Block a user