mirror of
https://github.com/Comfy-Org/ComfyUI_frontend.git
synced 2026-07-09 16:48:06 +00:00
Compare commits
6 Commits
feat/creat
...
agent/upgr
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1b0d458f36 | ||
|
|
96ec732104 | ||
|
|
134e27cca1 | ||
|
|
f1761a41fe | ||
|
|
68c2c9f0f5 | ||
|
|
fc3a945003 |
@@ -77,7 +77,6 @@ const preview: Preview = {
|
||||
{ value: 'light', icon: 'sun', title: 'Light' },
|
||||
{ value: 'dark', icon: 'moon', title: 'Dark' }
|
||||
],
|
||||
showName: true,
|
||||
dynamicTitle: true
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,32 +1,30 @@
|
||||
import { beforeEach, describe, expect, it, vi } from 'vitest'
|
||||
import { ref } from 'vue'
|
||||
|
||||
const { mockTerminal, MockTerminal, mockFitAddon, MockFitAddon } = vi.hoisted(
|
||||
() => {
|
||||
const mockTerminal = {
|
||||
loadAddon: vi.fn(),
|
||||
attachCustomKeyEventHandler: vi.fn(),
|
||||
open: vi.fn(),
|
||||
dispose: vi.fn(),
|
||||
hasSelection: vi.fn<[], boolean>(),
|
||||
resize: vi.fn(),
|
||||
cols: 80,
|
||||
rows: 24
|
||||
}
|
||||
const MockTerminal = vi.fn(function () {
|
||||
return mockTerminal
|
||||
})
|
||||
|
||||
const mockFitAddon = {
|
||||
proposeDimensions: vi.fn().mockReturnValue({ cols: 80, rows: 24 })
|
||||
}
|
||||
const MockFitAddon = vi.fn(function () {
|
||||
return mockFitAddon
|
||||
})
|
||||
|
||||
return { mockTerminal, MockTerminal, mockFitAddon, MockFitAddon }
|
||||
const { mockTerminal, MockTerminal, MockFitAddon } = vi.hoisted(() => {
|
||||
const mockTerminal = {
|
||||
loadAddon: vi.fn(),
|
||||
attachCustomKeyEventHandler: vi.fn(),
|
||||
open: vi.fn(),
|
||||
dispose: vi.fn(),
|
||||
hasSelection: vi.fn<() => boolean>(),
|
||||
resize: vi.fn(),
|
||||
cols: 80,
|
||||
rows: 24
|
||||
}
|
||||
)
|
||||
const MockTerminal = vi.fn(function () {
|
||||
return mockTerminal
|
||||
})
|
||||
|
||||
const mockFitAddon = {
|
||||
proposeDimensions: vi.fn().mockReturnValue({ cols: 80, rows: 24 })
|
||||
}
|
||||
const MockFitAddon = vi.fn(function () {
|
||||
return mockFitAddon
|
||||
})
|
||||
|
||||
return { mockTerminal, MockTerminal, MockFitAddon }
|
||||
})
|
||||
|
||||
vi.mock('@xterm/xterm', () => ({ Terminal: MockTerminal }))
|
||||
vi.mock('@xterm/addon-fit', () => ({ FitAddon: MockFitAddon }))
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { beforeEach, describe, expect, it, vi } from 'vitest'
|
||||
|
||||
const { mockSerialize, MockSerializeAddon } = vi.hoisted(() => {
|
||||
const mockSerialize = vi.fn<[], string>()
|
||||
const mockSerialize = vi.fn<() => string>()
|
||||
const MockSerializeAddon = vi.fn(function () {
|
||||
return { serialize: mockSerialize }
|
||||
})
|
||||
@@ -18,7 +18,6 @@ vi.mock('@xterm/addon-serialize', () => ({
|
||||
SerializeAddon: MockSerializeAddon
|
||||
}))
|
||||
|
||||
import type { Terminal } from '@xterm/xterm'
|
||||
import { withSetup } from '@/test/withSetup'
|
||||
import { useTerminalBuffer } from '@/composables/bottomPanelTabs/useTerminalBuffer'
|
||||
|
||||
@@ -33,7 +32,7 @@ describe('useTerminalBuffer', () => {
|
||||
mockSerialize.mockReturnValue('hello world')
|
||||
const { copyTo } = withSetup(() => useTerminalBuffer())
|
||||
const mockWrite = vi.fn()
|
||||
copyTo({ write: mockWrite } as Pick<Terminal, 'write'>)
|
||||
copyTo({ write: mockWrite })
|
||||
expect(mockWrite).toHaveBeenCalledWith('hello world')
|
||||
})
|
||||
|
||||
@@ -41,7 +40,7 @@ describe('useTerminalBuffer', () => {
|
||||
mockSerialize.mockReturnValue('')
|
||||
const { copyTo } = withSetup(() => useTerminalBuffer())
|
||||
const mockWrite = vi.fn()
|
||||
copyTo({ write: mockWrite } as Pick<Terminal, 'write'>)
|
||||
copyTo({ write: mockWrite })
|
||||
expect(mockWrite).toHaveBeenCalledWith('')
|
||||
})
|
||||
})
|
||||
|
||||
@@ -6,7 +6,7 @@ export function useTerminalBuffer() {
|
||||
const serializeAddon = new SerializeAddon()
|
||||
const terminal = markRaw(new Terminal({ convertEol: true }))
|
||||
|
||||
const copyTo = (destinationTerminal: Terminal) => {
|
||||
const copyTo = (destinationTerminal: Pick<Terminal, 'write'>) => {
|
||||
destinationTerminal.write(serializeAddon.serialize())
|
||||
}
|
||||
|
||||
|
||||
@@ -27,10 +27,14 @@ describe('getDialog', () => {
|
||||
|
||||
it('returns a deep clone — mutations do not affect the original', () => {
|
||||
const result = getDialog('reinstallVenv')
|
||||
const originalFirstLabel = DESKTOP_DIALOGS.reinstallVenv.buttons[0].label
|
||||
result.buttons[0].label = 'Mutated'
|
||||
expect(DESKTOP_DIALOGS.reinstallVenv.buttons[0].label).toBe(
|
||||
originalFirstLabel
|
||||
const originalButtonCount = DESKTOP_DIALOGS.reinstallVenv.buttons.length
|
||||
result.buttons.push({
|
||||
label: 'Mutated',
|
||||
action: 'cancel',
|
||||
returnValue: 'mutated'
|
||||
})
|
||||
expect(DESKTOP_DIALOGS.reinstallVenv.buttons).toHaveLength(
|
||||
originalButtonCount
|
||||
)
|
||||
})
|
||||
|
||||
|
||||
@@ -3,11 +3,11 @@ import { beforeEach, describe, expect, it, vi } from 'vitest'
|
||||
const { mockElectron } = vi.hoisted(() => ({
|
||||
mockElectron: {
|
||||
setBasePath: vi.fn(),
|
||||
reinstall: vi.fn<[], Promise<void>>().mockResolvedValue(undefined),
|
||||
reinstall: vi.fn<() => Promise<void>>().mockResolvedValue(undefined),
|
||||
uv: {
|
||||
installRequirements: vi.fn<[], Promise<void>>(),
|
||||
clearCache: vi.fn<[], Promise<void>>().mockResolvedValue(undefined),
|
||||
resetVenv: vi.fn<[], Promise<void>>().mockResolvedValue(undefined)
|
||||
installRequirements: vi.fn<() => Promise<void>>(),
|
||||
clearCache: vi.fn<() => Promise<void>>().mockResolvedValue(undefined),
|
||||
resetVenv: vi.fn<() => Promise<void>>().mockResolvedValue(undefined)
|
||||
}
|
||||
}
|
||||
}))
|
||||
@@ -48,24 +48,24 @@ describe('desktopMaintenanceTasks', () => {
|
||||
})
|
||||
|
||||
describe('URL-opening tasks', () => {
|
||||
it('git execute opens the git download page', () => {
|
||||
findTask('git').execute()
|
||||
it('git execute opens the git download page', async () => {
|
||||
expect(await findTask('git').execute()).toBe(true)
|
||||
expect(window.open).toHaveBeenCalledWith(
|
||||
'https://git-scm.com/downloads/',
|
||||
'_blank'
|
||||
)
|
||||
})
|
||||
|
||||
it('uv execute opens the uv installation page', () => {
|
||||
findTask('uv').execute()
|
||||
it('uv execute opens the uv installation page', async () => {
|
||||
expect(await findTask('uv').execute()).toBe(true)
|
||||
expect(window.open).toHaveBeenCalledWith(
|
||||
'https://docs.astral.sh/uv/getting-started/installation/',
|
||||
'_blank'
|
||||
)
|
||||
})
|
||||
|
||||
it('vcRedist execute opens the VC++ redistributable download', () => {
|
||||
findTask('vcRedist').execute()
|
||||
it('vcRedist execute opens the VC++ redistributable download', async () => {
|
||||
expect(await findTask('vcRedist').execute()).toBe(true)
|
||||
expect(window.open).toHaveBeenCalledWith(
|
||||
'https://aka.ms/vs/17/release/vc_redist.x64.exe',
|
||||
'_blank'
|
||||
|
||||
@@ -3,7 +3,7 @@ import { beforeEach, describe, expect, it, vi } from 'vitest'
|
||||
const { mockElectron } = vi.hoisted(() => ({
|
||||
mockElectron: {
|
||||
NetWork: {
|
||||
canAccessUrl: vi.fn<[url: string], Promise<boolean>>()
|
||||
canAccessUrl: vi.fn<(url: string) => Promise<boolean>>()
|
||||
}
|
||||
}
|
||||
}))
|
||||
|
||||
@@ -1,11 +1,15 @@
|
||||
import type { ElectronAPI } from '@comfyorg/comfyui-electron-types'
|
||||
|
||||
type ElectronWindow = typeof window & {
|
||||
electronAPI: ElectronAPI
|
||||
}
|
||||
|
||||
export function isElectron() {
|
||||
return 'electronAPI' in window && window.electronAPI !== undefined
|
||||
}
|
||||
|
||||
export function electronAPI() {
|
||||
return (window as any).electronAPI as ElectronAPI
|
||||
return (window as ElectronWindow).electronAPI
|
||||
}
|
||||
|
||||
export function isNativeWindow() {
|
||||
|
||||
@@ -2,11 +2,38 @@
|
||||
import type { Meta, StoryObj } from '@storybook/vue3'
|
||||
import type { ElectronAPI } from '@comfyorg/comfyui-electron-types'
|
||||
import { nextTick, provide } from 'vue'
|
||||
import type { ElectronWindow } from '@/utils/envUtil'
|
||||
import { createMemoryHistory, createRouter } from 'vue-router'
|
||||
|
||||
import InstallView from './InstallView.vue'
|
||||
|
||||
type InstallViewElectronAPI = {
|
||||
getPlatform: ElectronAPI['getPlatform']
|
||||
Config: {
|
||||
getDetectedGpu: ElectronAPI['Config']['getDetectedGpu']
|
||||
}
|
||||
Events: {
|
||||
trackEvent: ElectronAPI['Events']['trackEvent']
|
||||
}
|
||||
installComfyUI: ElectronAPI['installComfyUI']
|
||||
changeTheme: ElectronAPI['changeTheme']
|
||||
getSystemPaths: ElectronAPI['getSystemPaths']
|
||||
validateInstallPath: ElectronAPI['validateInstallPath']
|
||||
validateComfyUISource: ElectronAPI['validateComfyUISource']
|
||||
showDirectoryPicker: ElectronAPI['showDirectoryPicker']
|
||||
}
|
||||
|
||||
type InstallViewElectronWindow = Window & {
|
||||
electronAPI?: InstallViewElectronAPI
|
||||
}
|
||||
|
||||
const installViewElectronAPI = () => {
|
||||
const api = (window as InstallViewElectronWindow).electronAPI
|
||||
if (!api) {
|
||||
throw new Error('InstallView story electronAPI was not initialized')
|
||||
}
|
||||
return api
|
||||
}
|
||||
|
||||
// Create a mock router for stories
|
||||
const createMockRouter = () =>
|
||||
createRouter({
|
||||
@@ -44,7 +71,7 @@ const meta: Meta<typeof InstallView> = {
|
||||
const router = createMockRouter()
|
||||
|
||||
// Mock electron API
|
||||
;(window as ElectronWindow).electronAPI = {
|
||||
;(window as InstallViewElectronWindow).electronAPI = {
|
||||
getPlatform: () => 'darwin',
|
||||
Config: {
|
||||
getDetectedGpu: () => Promise.resolve('mps')
|
||||
@@ -61,6 +88,8 @@ const meta: Meta<typeof InstallView> = {
|
||||
changeTheme: (_theme: Parameters<ElectronAPI['changeTheme']>[0]) => {},
|
||||
getSystemPaths: () =>
|
||||
Promise.resolve({
|
||||
appData: '/Users/username/Library/Application Support/ComfyUI',
|
||||
appPath: '/Applications/ComfyUI.app',
|
||||
defaultInstallPath: '/Users/username/ComfyUI'
|
||||
}),
|
||||
validateInstallPath: () =>
|
||||
@@ -247,8 +276,8 @@ export const DesktopSettings: Story = {
|
||||
export const WindowsPlatform: Story = {
|
||||
render: () => {
|
||||
// Override the platform to Windows
|
||||
;(window as ElectronWindow).electronAPI.getPlatform = () => 'win32'
|
||||
;(window as ElectronWindow).electronAPI.Config.getDetectedGpu = () =>
|
||||
installViewElectronAPI().getPlatform = () => 'win32'
|
||||
installViewElectronAPI().Config.getDetectedGpu = () =>
|
||||
Promise.resolve('nvidia')
|
||||
|
||||
return {
|
||||
@@ -266,8 +295,8 @@ export const MacOSPlatform: Story = {
|
||||
name: 'macOS Platform',
|
||||
render: () => {
|
||||
// Override the platform to macOS
|
||||
;(window as ElectronWindow).electronAPI.getPlatform = () => 'darwin'
|
||||
;(window as ElectronWindow).electronAPI.Config.getDetectedGpu = () =>
|
||||
installViewElectronAPI().getPlatform = () => 'darwin'
|
||||
installViewElectronAPI().Config.getDetectedGpu = () =>
|
||||
Promise.resolve('mps')
|
||||
|
||||
return {
|
||||
@@ -334,7 +363,7 @@ export const ManualInstall: Story = {
|
||||
export const ErrorState: Story = {
|
||||
render: () => {
|
||||
// Override validation to return an error
|
||||
;(window as ElectronWindow).electronAPI.validateInstallPath = () =>
|
||||
installViewElectronAPI().validateInstallPath = () =>
|
||||
Promise.resolve({
|
||||
isValid: false,
|
||||
exists: false,
|
||||
@@ -382,7 +411,7 @@ export const ErrorState: Story = {
|
||||
export const WarningState: Story = {
|
||||
render: () => {
|
||||
// Override validation to return a warning about non-default drive
|
||||
;(window as ElectronWindow).electronAPI.validateInstallPath = () =>
|
||||
installViewElectronAPI().validateInstallPath = () =>
|
||||
Promise.resolve({
|
||||
isValid: true,
|
||||
exists: false,
|
||||
|
||||
@@ -6,7 +6,14 @@
|
||||
"paths": {
|
||||
"@/*": ["./src/*"],
|
||||
"@frontend-locales/*": ["../../src/locales/*"]
|
||||
}
|
||||
},
|
||||
"types": [
|
||||
"vite/client",
|
||||
"node",
|
||||
"vitest/globals",
|
||||
"@webgpu/types",
|
||||
"@testing-library/jest-dom/vitest"
|
||||
]
|
||||
},
|
||||
"include": [
|
||||
".storybook/**/*",
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
"./css/*": "./src/css/*"
|
||||
},
|
||||
"scripts": {
|
||||
"typecheck": "tsc --noEmit"
|
||||
"typecheck": "node ./node_modules/typescript-7/bin/tsc --noEmit"
|
||||
},
|
||||
"dependencies": {
|
||||
"@iconify-json/lucide": "catalog:",
|
||||
@@ -19,6 +19,7 @@
|
||||
},
|
||||
"devDependencies": {
|
||||
"tailwindcss": "catalog:",
|
||||
"typescript": "catalog:"
|
||||
"typescript": "catalog:",
|
||||
"typescript-7": "catalog:"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
},
|
||||
"scripts": {
|
||||
"test": "vitest run --config ./vitest.config.ts",
|
||||
"typecheck": "tsc --noEmit"
|
||||
"typecheck": "node ./node_modules/typescript-7/bin/tsc --noEmit"
|
||||
},
|
||||
"dependencies": {
|
||||
"zod": "catalog:",
|
||||
@@ -19,6 +19,7 @@
|
||||
},
|
||||
"devDependencies": {
|
||||
"typescript": "catalog:",
|
||||
"typescript-7": "catalog:",
|
||||
"vitest": "catalog:"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,13 +11,14 @@
|
||||
"./piiUtil": "./src/piiUtil.ts"
|
||||
},
|
||||
"scripts": {
|
||||
"typecheck": "tsc --noEmit"
|
||||
"typecheck": "node ./node_modules/typescript-7/bin/tsc --noEmit"
|
||||
},
|
||||
"dependencies": {
|
||||
"axios": "catalog:",
|
||||
"dompurify": "catalog:"
|
||||
},
|
||||
"devDependencies": {
|
||||
"typescript": "catalog:"
|
||||
"typescript": "catalog:",
|
||||
"typescript-7": "catalog:"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,13 +4,14 @@ import { createPostHogBeforeSend } from './piiUtil'
|
||||
|
||||
describe('createPostHogBeforeSend', () => {
|
||||
const beforeSend = createPostHogBeforeSend()
|
||||
type BeforeSendEvent = NonNullable<Parameters<typeof beforeSend>[0]>
|
||||
|
||||
it('returns null for null input', () => {
|
||||
expect(beforeSend(null)).toBeNull()
|
||||
})
|
||||
|
||||
it('strips all PII keys from properties, $set, and $set_once', () => {
|
||||
const event = {
|
||||
const event: BeforeSendEvent = {
|
||||
properties: {
|
||||
email: 'a@example.com',
|
||||
prompt: 'hello',
|
||||
@@ -48,7 +49,9 @@ describe('createPostHogBeforeSend', () => {
|
||||
})
|
||||
|
||||
it('handles missing property bags gracefully', () => {
|
||||
const event = { properties: { email: 'a@example.com', safe: true } }
|
||||
const event: BeforeSendEvent = {
|
||||
properties: { email: 'a@example.com', safe: true }
|
||||
}
|
||||
const result = beforeSend(event)!
|
||||
expect(result.properties).not.toHaveProperty('email')
|
||||
expect(result.properties).toHaveProperty('safe', true)
|
||||
|
||||
@@ -9,13 +9,14 @@
|
||||
".": "./src/index.ts"
|
||||
},
|
||||
"scripts": {
|
||||
"typecheck": "tsc --noEmit"
|
||||
"typecheck": "node ./node_modules/typescript-7/bin/tsc --noEmit"
|
||||
},
|
||||
"dependencies": {
|
||||
"clsx": "^2.1.1",
|
||||
"tailwind-merge": "^2.2.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"typescript": "catalog:"
|
||||
"typescript": "catalog:",
|
||||
"typescript-7": "catalog:"
|
||||
}
|
||||
}
|
||||
|
||||
818
pnpm-lock.yaml
generated
818
pnpm-lock.yaml
generated
File diff suppressed because it is too large
Load Diff
@@ -125,7 +125,8 @@ catalog:
|
||||
tsx: ^4.15.6
|
||||
tw-animate-css: ^1.3.8
|
||||
typegpu: ^0.8.2
|
||||
typescript: ^5.9.3
|
||||
typescript: ^6.0.3
|
||||
typescript-7: npm:typescript@^7.0.2
|
||||
typescript-eslint: ^8.60.0
|
||||
unplugin-icons: ^22.5.0
|
||||
unplugin-typegpu: 0.8.0
|
||||
@@ -174,3 +175,26 @@ overrides:
|
||||
minimatch@^9.0.0: ^9.0.7
|
||||
minimatch@^10.0.0: ^10.2.3
|
||||
ajv@^8.0.0: ^8.18.0
|
||||
|
||||
minimumReleaseAgeExclude:
|
||||
- '@typescript/typescript-aix-ppc64@7.0.2'
|
||||
- '@typescript/typescript-darwin-arm64@7.0.2'
|
||||
- '@typescript/typescript-darwin-x64@7.0.2'
|
||||
- '@typescript/typescript-freebsd-arm64@7.0.2'
|
||||
- '@typescript/typescript-freebsd-x64@7.0.2'
|
||||
- '@typescript/typescript-linux-arm64@7.0.2'
|
||||
- '@typescript/typescript-linux-arm@7.0.2'
|
||||
- '@typescript/typescript-linux-loong64@7.0.2'
|
||||
- '@typescript/typescript-linux-mips64el@7.0.2'
|
||||
- '@typescript/typescript-linux-ppc64@7.0.2'
|
||||
- '@typescript/typescript-linux-riscv64@7.0.2'
|
||||
- '@typescript/typescript-linux-s390x@7.0.2'
|
||||
- '@typescript/typescript-linux-x64@7.0.2'
|
||||
- '@typescript/typescript-netbsd-arm64@7.0.2'
|
||||
- '@typescript/typescript-netbsd-x64@7.0.2'
|
||||
- '@typescript/typescript-openbsd-arm64@7.0.2'
|
||||
- '@typescript/typescript-openbsd-x64@7.0.2'
|
||||
- '@typescript/typescript-sunos-x64@7.0.2'
|
||||
- '@typescript/typescript-win32-arm64@7.0.2'
|
||||
- '@typescript/typescript-win32-x64@7.0.2'
|
||||
- typescript@7.0.2
|
||||
|
||||
@@ -207,7 +207,8 @@ export function useGPUResources() {
|
||||
async function initTypeGPU(): Promise<void> {
|
||||
if (store.tgpuRoot) {
|
||||
/* c8 ignore start */
|
||||
device = store.tgpuRoot.device
|
||||
// typegpu's GPUDevice type can lag @webgpu/types; the runtime object is still a browser GPUDevice.
|
||||
device = store.tgpuRoot.device as GPUDevice
|
||||
return
|
||||
/* c8 ignore stop */
|
||||
}
|
||||
@@ -215,7 +216,7 @@ export function useGPUResources() {
|
||||
/* c8 ignore start — requires functional WebGPU hardware */
|
||||
const root = await tgpu.init()
|
||||
store.tgpuRoot = root
|
||||
device = root.device
|
||||
device = root.device as GPUDevice
|
||||
console.warn('✅ TypeGPU initialized! Root:', root)
|
||||
console.warn('Device info:', root.device.limits)
|
||||
/* c8 ignore stop */
|
||||
|
||||
Reference in New Issue
Block a user