mirror of
https://github.com/Comfy-Org/ComfyUI_frontend.git
synced 2026-03-15 01:48:06 +00:00
Compare commits
31 Commits
node-group
...
changelog-
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
11c46ea62d | ||
|
|
86789ceb9d | ||
|
|
1a4e77a3ab | ||
|
|
de570712df | ||
|
|
44612e8f97 | ||
|
|
3df911c1bf | ||
|
|
af26b9ad6d | ||
|
|
d503873980 | ||
|
|
842a9f74fc | ||
|
|
29551a36b3 | ||
|
|
d6e5c8950c | ||
|
|
ad1c1ce9c2 | ||
|
|
cb9d2c6bae | ||
|
|
7fd41eeaba | ||
|
|
79fee6ac72 | ||
|
|
edd58cd153 | ||
|
|
e153508955 | ||
|
|
237fca0bf1 | ||
|
|
65542b885a | ||
|
|
f739f704af | ||
|
|
37abdbe35d | ||
|
|
ff445f5c95 | ||
|
|
84b652a281 | ||
|
|
184291d21b | ||
|
|
d7fb25a36a | ||
|
|
c039a60fcc | ||
|
|
3b6108c26e | ||
|
|
49bb247526 | ||
|
|
dd005f5fa5 | ||
|
|
bf90b458d3 | ||
|
|
7e78c5b1dc |
43
.cusorrules
Normal file
43
.cusorrules
Normal file
@@ -0,0 +1,43 @@
|
||||
// Vue 3 Composition API .cursorrules
|
||||
|
||||
// Vue 3 Composition API best practices
|
||||
const vue3CompositionApiBestPractices = [
|
||||
"Use setup() function for component logic",
|
||||
"Utilize ref and reactive for reactive state",
|
||||
"Implement computed properties with computed()",
|
||||
"Use watch and watchEffect for side effects",
|
||||
"Implement lifecycle hooks with onMounted, onUpdated, etc.",
|
||||
"Utilize provide/inject for dependency injection",
|
||||
]
|
||||
|
||||
// Folder structure
|
||||
const folderStructure = `
|
||||
src/
|
||||
components/
|
||||
constants/
|
||||
hooks/
|
||||
views/
|
||||
stores/
|
||||
services/
|
||||
App.vue
|
||||
main.ts
|
||||
`;
|
||||
|
||||
// Tailwind CSS best practices
|
||||
const tailwindCssBestPractices = [
|
||||
"Use Tailwind CSS for styling",
|
||||
"Implement responsive design with Tailwind CSS",
|
||||
]
|
||||
|
||||
// Additional instructions
|
||||
const additionalInstructions = `
|
||||
1. Leverage VueUse functions for performance-enhancing styles
|
||||
2. Use lodash for utility functions
|
||||
3. Use TypeScript for type safety
|
||||
4. Implement proper props and emits definitions
|
||||
5. Utilize Vue 3's Teleport component when needed
|
||||
6. Use Suspense for async components
|
||||
7. Implement proper error handling
|
||||
8. Follow Vue 3 style guide and naming conventions
|
||||
9. Use Vite for fast development and building
|
||||
`;
|
||||
5
.github/workflows/i18n-node-defs.yaml
vendored
5
.github/workflows/i18n-node-defs.yaml
vendored
@@ -42,6 +42,7 @@ jobs:
|
||||
Automated PR to update locales for node definitions
|
||||
|
||||
This PR was created automatically by the frontend update workflow.
|
||||
branch: update-locales-node-defs-{{ github.event.inputs.trigger_type }}-{{ github.run_id }}
|
||||
branch: update-locales-node-defs-${{ github.event.inputs.trigger_type }}-${{ github.run_id }}
|
||||
base: main
|
||||
labels: dependencies
|
||||
labels: dependencies
|
||||
path: ComfyUI_frontend
|
||||
37
browser_tests/assets/collapsed_multiline.json
Normal file
37
browser_tests/assets/collapsed_multiline.json
Normal file
@@ -0,0 +1,37 @@
|
||||
{
|
||||
"last_node_id": 1,
|
||||
"last_link_id": 0,
|
||||
"nodes": [
|
||||
{
|
||||
"id": 1,
|
||||
"type": "CLIPTextEncode",
|
||||
"pos": [20, 50],
|
||||
"size": [400, 200],
|
||||
"flags": { "collapsed": true },
|
||||
"order": 0,
|
||||
"mode": 0,
|
||||
"inputs": [
|
||||
{
|
||||
"name": "clip",
|
||||
"type": "CLIP",
|
||||
"link": null,
|
||||
"localized_name": "clip"
|
||||
}
|
||||
],
|
||||
"outputs": [
|
||||
{
|
||||
"name": "CONDITIONING",
|
||||
"type": "CONDITIONING",
|
||||
"links": null,
|
||||
"localized_name": "CONDITIONING"
|
||||
}
|
||||
],
|
||||
"properties": {},
|
||||
"widgets_values": ["Should not be displayed."]
|
||||
}
|
||||
],
|
||||
"links": [],
|
||||
"groups": [],
|
||||
"config": {},
|
||||
"version": 0.4
|
||||
}
|
||||
BIN
browser_tests/assets/image32x32.webp
Normal file
BIN
browser_tests/assets/image32x32.webp
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 488 B |
BIN
browser_tests/assets/image64x64.webp
Normal file
BIN
browser_tests/assets/image64x64.webp
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.3 KiB |
27
browser_tests/domWidget.spec.ts
Normal file
27
browser_tests/domWidget.spec.ts
Normal file
@@ -0,0 +1,27 @@
|
||||
import { expect } from '@playwright/test'
|
||||
|
||||
import { comfyPageFixture as test } from './fixtures/ComfyPage'
|
||||
|
||||
test.describe('DOM Widget', () => {
|
||||
test('Collapsed multiline textarea is not visible', async ({ comfyPage }) => {
|
||||
await comfyPage.loadWorkflow('collapsed_multiline')
|
||||
|
||||
expect(comfyPage.page.locator('.comfy-multiline-input')).not.toBeVisible()
|
||||
})
|
||||
|
||||
test('Multiline textarea correctly collapses', async ({ comfyPage }) => {
|
||||
const multilineTextAreas = comfyPage.page.locator('.comfy-multiline-input')
|
||||
const firstMultiline = multilineTextAreas.first()
|
||||
const lastMultiline = multilineTextAreas.last()
|
||||
|
||||
await expect(firstMultiline).toBeVisible()
|
||||
await expect(lastMultiline).toBeVisible()
|
||||
|
||||
const nodes = await comfyPage.getNodeRefsByType('CLIPTextEncode')
|
||||
for (const node of nodes) {
|
||||
await node.click('collapse')
|
||||
}
|
||||
await expect(firstMultiline).not.toBeVisible()
|
||||
await expect(lastMultiline).not.toBeVisible()
|
||||
})
|
||||
})
|
||||
@@ -194,6 +194,10 @@ export class QueueSidebarTab extends SidebarTab {
|
||||
return this.root.locator('.no-results-placeholder')
|
||||
}
|
||||
|
||||
get galleryImage() {
|
||||
return this.page.locator('.galleria-image')
|
||||
}
|
||||
|
||||
private getToggleExpandButton(isExpanded: boolean) {
|
||||
const iconSelector = isExpanded ? '.pi-image' : '.pi-images'
|
||||
return this.root.locator(`.toggle-expanded-button ${iconSelector}`)
|
||||
@@ -256,14 +260,24 @@ export class QueueSidebarTab extends SidebarTab {
|
||||
|
||||
async openTaskPreview(taskIndex: number) {
|
||||
const previewButton = this.getTaskPreviewButton(taskIndex)
|
||||
await previewButton.hover()
|
||||
await previewButton.click()
|
||||
return this.getGalleryImage(taskIndex).waitFor({ state: 'visible' })
|
||||
return this.galleryImage.waitFor({ state: 'visible' })
|
||||
}
|
||||
|
||||
getGalleryImage(galleryItemIndex: number) {
|
||||
// Aria labels of Galleria items are 1-based indices
|
||||
const galleryLabel = `${galleryItemIndex + 1}`
|
||||
return this.page.getByLabel(galleryLabel).locator('.galleria-image')
|
||||
getGalleryImage(imageFilename: string) {
|
||||
return this.galleryImage.and(this.page.getByAltText(imageFilename))
|
||||
}
|
||||
|
||||
getTaskImage(imageFilename: string) {
|
||||
return this.tasks.getByAltText(imageFilename)
|
||||
}
|
||||
|
||||
/** Trigger the queue store and tasks to update */
|
||||
async triggerTasksUpdate() {
|
||||
await this.page.evaluate(() => {
|
||||
window['app']['api'].dispatchCustomEvent('status', {
|
||||
exec_info: { queue_remaining: 0 }
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -132,11 +132,12 @@ export default class TaskHistory {
|
||||
private addTask(task: HistoryTaskItem) {
|
||||
setPromptId(task)
|
||||
setQueueIndex(task)
|
||||
this.tasks.push(task)
|
||||
this.tasks.unshift(task) // Tasks are added to the front of the queue
|
||||
}
|
||||
|
||||
clearTasks() {
|
||||
clearTasks(): this {
|
||||
this.tasks = []
|
||||
return this
|
||||
}
|
||||
|
||||
withTask(
|
||||
@@ -155,7 +156,7 @@ export default class TaskHistory {
|
||||
/** Repeats the last task in the task history a specified number of times. */
|
||||
repeat(n: number): this {
|
||||
for (let i = 0; i < n; i++)
|
||||
this.addTask(structuredClone(this.tasks.at(-1)) as HistoryTaskItem)
|
||||
this.addTask(structuredClone(this.tasks.at(0)) as HistoryTaskItem)
|
||||
return this
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,9 +1,6 @@
|
||||
import { expect, mergeTests } from '@playwright/test'
|
||||
import { expect } from '@playwright/test'
|
||||
|
||||
import { comfyPageFixture } from './fixtures/ComfyPage'
|
||||
import { webSocketFixture } from './fixtures/ws'
|
||||
|
||||
const test = mergeTests(comfyPageFixture, webSocketFixture)
|
||||
import { comfyPageFixture as test } from './fixtures/ComfyPage'
|
||||
|
||||
test.describe('Menu', () => {
|
||||
test.beforeEach(async ({ comfyPage }) => {
|
||||
@@ -948,66 +945,61 @@ test.describe.skip('Queue sidebar', () => {
|
||||
})
|
||||
|
||||
test.describe('Gallery', () => {
|
||||
const firstImage = 'example.webp'
|
||||
const secondImage = 'image32x32.webp'
|
||||
|
||||
test.beforeEach(async ({ comfyPage }) => {
|
||||
await comfyPage
|
||||
.setupHistory()
|
||||
.withTask(['example.webp'])
|
||||
.repeat(1)
|
||||
.withTask([secondImage])
|
||||
.withTask([firstImage])
|
||||
.setupRoutes()
|
||||
await comfyPage.menu.queueTab.open()
|
||||
await comfyPage.menu.queueTab.waitForTasks()
|
||||
await comfyPage.menu.queueTab.openTaskPreview(0)
|
||||
})
|
||||
|
||||
test('displays gallery image after opening task preview', async ({
|
||||
comfyPage
|
||||
}) => {
|
||||
await comfyPage.menu.queueTab.openTaskPreview(0)
|
||||
expect(comfyPage.menu.queueTab.getGalleryImage(0)).toBeVisible()
|
||||
await comfyPage.nextFrame()
|
||||
expect(comfyPage.menu.queueTab.getGalleryImage(firstImage)).toBeVisible()
|
||||
})
|
||||
|
||||
test('should maintain active gallery item when new tasks are added', async ({
|
||||
comfyPage,
|
||||
ws
|
||||
test('maintains active gallery item when new tasks are added', async ({
|
||||
comfyPage
|
||||
}) => {
|
||||
const initialIndex = 0
|
||||
await comfyPage.menu.queueTab.openTaskPreview(initialIndex)
|
||||
|
||||
// Add a new task while the gallery is still open
|
||||
comfyPage.setupHistory().withTask(['example.webp'])
|
||||
await ws.trigger({
|
||||
type: 'status',
|
||||
data: {
|
||||
status: { exec_info: { queue_remaining: 0 } }
|
||||
}
|
||||
})
|
||||
await comfyPage.menu.queueTab.waitForTasks()
|
||||
|
||||
// The index of all tasks increments when a new task is prepended
|
||||
const expectIndex = initialIndex + 1
|
||||
expect(comfyPage.menu.queueTab.getGalleryImage(expectIndex)).toBeVisible()
|
||||
const newImage = 'image64x64.webp'
|
||||
comfyPage.setupHistory().withTask([newImage])
|
||||
await comfyPage.menu.queueTab.triggerTasksUpdate()
|
||||
await comfyPage.page.waitForTimeout(500)
|
||||
const newTask = comfyPage.menu.queueTab.tasks.getByAltText(newImage)
|
||||
await newTask.waitFor({ state: 'visible' })
|
||||
// The active gallery item should still be the initial image
|
||||
expect(comfyPage.menu.queueTab.getGalleryImage(firstImage)).toBeVisible()
|
||||
})
|
||||
|
||||
test.describe('Gallery navigation', () => {
|
||||
const paths: {
|
||||
description: string
|
||||
path: ('Right' | 'Left')[]
|
||||
expectIndex: number
|
||||
end: string
|
||||
}[] = [
|
||||
{ description: 'Right', path: ['Right'], expectIndex: 1 },
|
||||
{ description: 'Left', path: ['Right', 'Left'], expectIndex: 0 },
|
||||
{ description: 'Right wrap', path: ['Right', 'Right'], expectIndex: 0 },
|
||||
{ description: 'Left wrap', path: ['Left'], expectIndex: 1 }
|
||||
{ description: 'Right', path: ['Right'], end: secondImage },
|
||||
{ description: 'Left', path: ['Right', 'Left'], end: firstImage },
|
||||
{ description: 'Left wrap', path: ['Left'], end: secondImage },
|
||||
{ description: 'Right wrap', path: ['Right', 'Right'], end: firstImage }
|
||||
]
|
||||
|
||||
paths.forEach(({ description, path, expectIndex }) => {
|
||||
paths.forEach(({ description, path, end }) => {
|
||||
test(`can navigate gallery ${description}`, async ({ comfyPage }) => {
|
||||
await comfyPage.menu.queueTab.openTaskPreview(0)
|
||||
for (const direction of path)
|
||||
await comfyPage.page.keyboard.press(`Arrow${direction}`)
|
||||
|
||||
expect(
|
||||
comfyPage.menu.queueTab.getGalleryImage(expectIndex)
|
||||
).toBeVisible()
|
||||
await comfyPage.page.keyboard.press(`Arrow${direction}`, {
|
||||
delay: 256
|
||||
})
|
||||
await comfyPage.nextFrame()
|
||||
expect(comfyPage.menu.queueTab.getGalleryImage(end)).toBeVisible()
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
13
package-lock.json
generated
13
package-lock.json
generated
@@ -1,16 +1,16 @@
|
||||
{
|
||||
"name": "@comfyorg/comfyui-frontend",
|
||||
"version": "1.7.10",
|
||||
"version": "1.7.14",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "@comfyorg/comfyui-frontend",
|
||||
"version": "1.7.10",
|
||||
"version": "1.7.14",
|
||||
"license": "GPL-3.0-only",
|
||||
"dependencies": {
|
||||
"@atlaskit/pragmatic-drag-and-drop": "^1.3.1",
|
||||
"@comfyorg/comfyui-electron-types": "^0.4.7",
|
||||
"@comfyorg/comfyui-electron-types": "^0.4.10",
|
||||
"@comfyorg/litegraph": "^0.8.60",
|
||||
"@primevue/themes": "^4.0.5",
|
||||
"@sentry/vue": "^8.48.0",
|
||||
@@ -1936,10 +1936,9 @@
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/@comfyorg/comfyui-electron-types": {
|
||||
"version": "0.4.7",
|
||||
"resolved": "https://registry.npmjs.org/@comfyorg/comfyui-electron-types/-/comfyui-electron-types-0.4.7.tgz",
|
||||
"integrity": "sha512-APC3C4VZOo9W6h0xiAGxnsU9iNp3T8rN9w/5KmOCI0GUoKtKg5U2OaicTmnMwcDSQe5Jxflmej53GyJ1nH9oRw==",
|
||||
"license": "GPL-3.0-only"
|
||||
"version": "0.4.10",
|
||||
"resolved": "https://registry.npmjs.org/@comfyorg/comfyui-electron-types/-/comfyui-electron-types-0.4.10.tgz",
|
||||
"integrity": "sha512-UWBgyuWeV7vussYZVUYhCe0jj+XbIq2nglrCUy6IgFgXp9pbE8Ktg5D36WxE0RWj6SvVXErlCL9wWnMktaRbCA=="
|
||||
},
|
||||
"node_modules/@comfyorg/litegraph": {
|
||||
"version": "0.8.60",
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@comfyorg/comfyui-frontend",
|
||||
"private": true,
|
||||
"version": "1.7.10",
|
||||
"version": "1.7.14",
|
||||
"type": "module",
|
||||
"repository": "https://github.com/Comfy-Org/ComfyUI_frontend",
|
||||
"homepage": "https://comfy.org",
|
||||
@@ -83,7 +83,7 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@atlaskit/pragmatic-drag-and-drop": "^1.3.1",
|
||||
"@comfyorg/comfyui-electron-types": "^0.4.7",
|
||||
"@comfyorg/comfyui-electron-types": "^0.4.10",
|
||||
"@comfyorg/litegraph": "^0.8.60",
|
||||
"@primevue/themes": "^4.0.5",
|
||||
"@sentry/vue": "^8.48.0",
|
||||
|
||||
1
src/assets/changelog.json
Normal file
1
src/assets/changelog.json
Normal file
@@ -0,0 +1 @@
|
||||
{"last_node_id":16,"last_link_id":10,"nodes":[{"id":16,"type":"MarkdownNote","pos":[630,60],"size":[930,945],"flags":{},"order":0,"mode":0,"inputs":[],"outputs":[],"title":"Changelog","properties":{},"widgets_values":["# v0.3.11 (Pre-release)\n\n## What's Changed\n\n* Nvidia Cosmos 7B and 14B: text to video and image to video diffusion model support.\n <iframe width=\"560\" height=\"315\" src=\"https://www.youtube.com/watch?v=-OCwHBur0FM\" frameborder=\"0\" allowfullscreen></iframe>\n\n\n* New sampler: res_multistep\n* ckpt/pt/etc.. files are now always loaded safely on pytorch 2.4 and above.\n* Fix some cases of ancestral samplers not being deterministic.\n* Support ascend npu by @ji-huazhong [#5436](https://github.com/comfyanonymous/ComfyUI/pull/5436)\n* Add option to log non-error output to stdout by @webfiltered [#6243](https://github.com/comfyanonymous/ComfyUI/pull/6243)\n* serve workflow templates from custom_nodes by @bezo97 [#6193](https://github.com/comfyanonymous/ComfyUI/pull/6193)\n* Remove duplicate calls to INPUT_TYPES by @catboxanon [#6249](https://github.com/comfyanonymous/ComfyUI/pull/6249)\n* Fix Hook Keyframe 'guarantee_steps' behavior and add 'sigmas' by @Kosinkadink [#6273](https://github.com/comfyanonymous/ComfyUI/pull/6273)\n* Add kl_optimal scheduler by @blepping [#6206](https://github.com/comfyanonymous/ComfyUI/pull/6206)\n* (fix): \"verbose\" argument by @bigcat88 [#6289](https://github.com/comfyanonymous/ComfyUI/pull/6289)\n* Fix custom node type-hinting examples by @webfiltered [#6281](https://github.com/comfyanonymous/ComfyUI/pull/6281)\n* Add missing model_options param to finalize_default_conds call by @Kosinkadink [#6296](https://github.com/comfyanonymous/ComfyUI/pull/6296)\n* Fix unknown scheduler error handling in calculate_sigmas function by @blepping [#6280](https://github.com/comfyanonymous/ComfyUI/pull/6280)\n* Fix temporal tiling for Tiled VAE decoder, remove redundant tiles. by @kvochko [#6306](https://github.com/comfyanonymous/ComfyUI/pull/6306)\n* Update web content to release v1.6.14 by @huchenlei [#6312](https://github.com/comfyanonymous/ComfyUI/pull/6312)\n* add fov and mask for load 3d node by @jtydhr88 [#6308](https://github.com/comfyanonymous/ComfyUI/pull/6308)\n* Update web content to release v1.6.15 by @huchenlei [#6324](https://github.com/comfyanonymous/ComfyUI/pull/6324)\n* Update web content to release v1.6.16 by @huchenlei [#6335](https://github.com/comfyanonymous/ComfyUI/pull/6335)\n* Update web content to release v1.6.17 by @huchenlei [#6337](https://github.com/comfyanonymous/ComfyUI/pull/6337)\n* Add update-frontend github action by @huchenlei [#6336](https://github.com/comfyanonymous/ComfyUI/pull/6336)\n* Update CODEOWNERS by @yoland68 [#6338](https://github.com/comfyanonymous/ComfyUI/pull/6338)\n* In inner_sample, change \"sigmas\" to \"sample_sigmas\" by @Kosinkadink [#6360](https://github.com/comfyanonymous/ComfyUI/pull/6360)\n* Frontend Update: v1.6.18 by @huchenlei [#6368](https://github.com/comfyanonymous/ComfyUI/pull/6368)\n* Document get_attr and get_model_object by @huchenlei [#6357](https://github.com/comfyanonymous/ComfyUI/pull/6357)\n* fixed: robust loading \\`comfy.settings.json\\` by @ltdrdata [#6383](https://github.com/comfyanonymous/ComfyUI/pull/6383)\n* Add pyproject.toml by @huchenlei [#6386](https://github.com/comfyanonymous/ComfyUI/pull/6386)\n* Hooks Part 2 - TransformerOptionsHook and AdditionalModelsHook by @Kosinkadink [#6377](https://github.com/comfyanonymous/ComfyUI/pull/6377)\n* Merge ruff.toml into pyproject.toml by @huchenlei [#6431](https://github.com/comfyanonymous/ComfyUI/pull/6431)\n* (fix): load_extra_path_config: relative path not converted to a full path by @bigcat88 [#6395](https://github.com/comfyanonymous/ComfyUI/pull/6395)\n* Rewrite res_multistep sampler and implement res_multistep_cfg_pp sampler by @pamparamm [#6462](https://github.com/comfyanonymous/ComfyUI/pull/6462)\n* Add SetFirstSigma node by @catboxanon [#6459](https://github.com/comfyanonymous/ComfyUI/pull/6459)\n\n**Full Changelog**: [\\`v0.3.10...v0.3.11\\`](https://github.com/comfyanonymous/ComfyUI/compare/v0.3.10...v0.3.11)\n\n----\n\n> To disable showing changelog on new releases, go the the Changelog section in settings\n"],"color":"#222","bgcolor":"#000"}],"links":[],"groups":[],"config":{},"extra":{"ds":{"scale":1.503752370924104,"offset":[-489.9627968865069,158.59081129748483]}},"version":0.4}
|
||||
@@ -20,11 +20,16 @@ const terminalCreated = (
|
||||
let offData: IDisposable
|
||||
let offOutput: () => void
|
||||
|
||||
useAutoSize(root, true, true, () => {
|
||||
// If we aren't visible, don't resize
|
||||
if (!terminal.element?.offsetParent) return
|
||||
useAutoSize({
|
||||
root,
|
||||
autoRows: true,
|
||||
autoCols: true,
|
||||
onResize: () => {
|
||||
// If we aren't visible, don't resize
|
||||
if (!terminal.element?.offsetParent) return
|
||||
|
||||
terminalApi.resize(terminal.cols, terminal.rows)
|
||||
terminalApi.resize(terminal.cols, terminal.rows)
|
||||
}
|
||||
})
|
||||
|
||||
onMounted(async () => {
|
||||
|
||||
@@ -29,7 +29,12 @@ const terminalCreated = (
|
||||
{ terminal, useAutoSize }: ReturnType<typeof useTerminal>,
|
||||
root: Ref<HTMLElement>
|
||||
) => {
|
||||
useAutoSize(root, true, false)
|
||||
// `autoCols` is false because we don't want the progress bar in the terminal
|
||||
// to render incorrectly as the progress bar is rendered based on the
|
||||
// server's terminal size.
|
||||
// Apply a min cols of 80 for colab environments
|
||||
// See https://github.com/comfyanonymous/ComfyUI/issues/6396
|
||||
useAutoSize({ root, autoRows: true, autoCols: false, minCols: 80 })
|
||||
|
||||
const update = (entries: Array<LogEntry>, size?: TerminalSize) => {
|
||||
if (size) {
|
||||
|
||||
@@ -13,11 +13,16 @@
|
||||
import { onBeforeUnmount, onMounted } from 'vue'
|
||||
|
||||
import { useSettingStore } from '@/stores/settingStore'
|
||||
import { useWorkflowStore } from '@/stores/workflowStore'
|
||||
|
||||
const settingStore = useSettingStore()
|
||||
const workflowStore = useWorkflowStore()
|
||||
|
||||
const handleBeforeUnload = (event: BeforeUnloadEvent) => {
|
||||
if (settingStore.get('Comfy.Window.UnloadConfirmation')) {
|
||||
if (
|
||||
settingStore.get('Comfy.Window.UnloadConfirmation') &&
|
||||
workflowStore.modifiedWorkflows.length > 0
|
||||
) {
|
||||
event.preventDefault()
|
||||
return true
|
||||
}
|
||||
|
||||
@@ -30,6 +30,7 @@
|
||||
v-if="sendReportOpen"
|
||||
error-type="graphExecutionError"
|
||||
:extra-fields="[stackTraceField]"
|
||||
:tags="{ exceptionMessage: props.error.exception_message }"
|
||||
/>
|
||||
<div class="action-container">
|
||||
<FindIssueButton
|
||||
|
||||
@@ -75,9 +75,12 @@ const props = defineProps<{
|
||||
errorType: string
|
||||
defaultFields?: DefaultField[]
|
||||
extraFields?: ReportField[]
|
||||
tags?: Record<string, string>
|
||||
}>()
|
||||
const { defaultFields = ['Workflow', 'Logs', 'SystemStats', 'Settings'] } =
|
||||
props
|
||||
const {
|
||||
defaultFields = ['Workflow', 'Logs', 'SystemStats', 'Settings'],
|
||||
tags = {}
|
||||
} = props
|
||||
|
||||
const { t } = useI18n()
|
||||
const toast = useToast()
|
||||
@@ -168,7 +171,8 @@ const createCaptureContext = async (): Promise<CaptureContext> => {
|
||||
user: getUserInfo(),
|
||||
level: 'error',
|
||||
tags: {
|
||||
errorType: props.errorType
|
||||
errorType: props.errorType,
|
||||
...tags
|
||||
},
|
||||
extra: {
|
||||
...createFeedback(),
|
||||
|
||||
@@ -43,6 +43,7 @@ import {
|
||||
} from '@comfyorg/litegraph'
|
||||
import { computed, onMounted, ref, watch, watchEffect } from 'vue'
|
||||
|
||||
import changelog from '@/assets/changelog.json'
|
||||
import LiteGraphCanvasSplitterOverlay from '@/components/LiteGraphCanvasSplitterOverlay.vue'
|
||||
import BottomPanel from '@/components/bottomPanel/BottomPanel.vue'
|
||||
import GraphCanvasMenu from '@/components/graph/GraphCanvasMenu.vue'
|
||||
@@ -56,6 +57,7 @@ import { CORE_SETTINGS } from '@/constants/coreSettings'
|
||||
import { usePragmaticDroppable } from '@/hooks/dndHooks'
|
||||
import { api } from '@/scripts/api'
|
||||
import { app as comfyApp } from '@/scripts/app'
|
||||
import { app } from '@/scripts/app'
|
||||
import { ChangeTracker } from '@/scripts/changeTracker'
|
||||
import { getStorageValue, setStorageValue } from '@/scripts/utils'
|
||||
import { IS_CONTROL_WIDGET, updateControlWidgetLabel } from '@/scripts/widgets'
|
||||
@@ -75,6 +77,7 @@ import { useWorkflowStore } from '@/stores/workflowStore'
|
||||
import { useColorPaletteStore } from '@/stores/workspace/colorPaletteStore'
|
||||
import { useWorkspaceStore } from '@/stores/workspaceStore'
|
||||
import type { RenderedTreeExplorerNode } from '@/types/treeExplorerTypes'
|
||||
import { getComfyVersion, isVersionLessThan } from '@/utils/envUtil'
|
||||
|
||||
const emit = defineEmits(['ready'])
|
||||
const canvasRef = ref<HTMLCanvasElement | null>(null)
|
||||
@@ -278,6 +281,35 @@ const persistCurrentWorkflow = () => {
|
||||
}
|
||||
}
|
||||
|
||||
const stopWatchChangeLog = watch(
|
||||
() => workflowStore.activeWorkflow,
|
||||
async () => {
|
||||
if (!comfyAppReady.value) return
|
||||
if (!changelog || settingStore.get('Comfy.ShowChangeLog') === false) {
|
||||
stopWatchChangeLog()
|
||||
return
|
||||
}
|
||||
|
||||
const workflow = workflowStore.activeWorkflow
|
||||
const activeState = workflow?.activeState
|
||||
const comfyVersion = getComfyVersion() // TODO: initialize/fetch somewhere else
|
||||
if (!workflow || !activeState || !comfyVersion) return
|
||||
|
||||
// Just checking if workflow temporary is not enough bc of Duplicate feature
|
||||
const isBlank = !workflow.isPersisted && activeState.nodes?.length === 0
|
||||
if (!isBlank) return
|
||||
|
||||
const lastShown = settingStore.get('Comfy.LastChangelogVersion')
|
||||
const isSeen = lastShown && !isVersionLessThan(lastShown, comfyVersion)
|
||||
if (!isSeen) {
|
||||
app.loadGraphData(changelog)
|
||||
settingStore.set('Comfy.LastChangelogVersion', comfyVersion)
|
||||
}
|
||||
|
||||
stopWatchChangeLog()
|
||||
}
|
||||
)
|
||||
|
||||
watchEffect(() => {
|
||||
if (workflowStore.activeWorkflow) {
|
||||
const workflow = workflowStore.activeWorkflow
|
||||
|
||||
@@ -72,14 +72,6 @@
|
||||
'install.settings.dataCollectionDialog.collect.userJourneyEvents'
|
||||
)
|
||||
}}
|
||||
<span
|
||||
class="pi pi-info-circle text-neutral-400"
|
||||
v-tooltip="
|
||||
$t(
|
||||
'install.settings.dataCollectionDialog.collect.userJourneyTooltip'
|
||||
)
|
||||
"
|
||||
/>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
@@ -116,6 +108,16 @@
|
||||
}}
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<div class="mt-4">
|
||||
<a
|
||||
href="https://comfy.org/privacy"
|
||||
target="_blank"
|
||||
class="text-blue-400 hover:text-blue-300 underline"
|
||||
>
|
||||
{{ $t('install.settings.dataCollectionDialog.viewFullPolicy') }}
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</Dialog>
|
||||
</div>
|
||||
|
||||
@@ -159,8 +159,8 @@ const pickGpu = (value: typeof selected.value) => {
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="postcss">
|
||||
:root {
|
||||
<style scoped>
|
||||
.p-tag {
|
||||
--p-tag-gap: 0.5rem;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<template>
|
||||
<teleport :to="teleportTarget">
|
||||
<nav :class="'side-tool-bar-container' + (isSmall ? ' small-sidebar' : '')">
|
||||
<nav class="side-tool-bar-container" :class="{ 'small-sidebar': isSmall }">
|
||||
<SidebarIcon
|
||||
v-for="tab in tabs"
|
||||
:key="tab.id"
|
||||
@@ -69,17 +69,6 @@ const getTabTooltipSuffix = (tab: SidebarTabExtension) => {
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
:root {
|
||||
--sidebar-width: 4rem;
|
||||
--sidebar-icon-size: 1.5rem;
|
||||
}
|
||||
:root .small-sidebar {
|
||||
--sidebar-width: 2.5rem;
|
||||
--sidebar-icon-size: 1rem;
|
||||
}
|
||||
</style>
|
||||
|
||||
<style scoped>
|
||||
.side-tool-bar-container {
|
||||
display: flex;
|
||||
@@ -94,6 +83,14 @@ const getTabTooltipSuffix = (tab: SidebarTabExtension) => {
|
||||
background-color: var(--comfy-menu-secondary-bg);
|
||||
color: var(--fg-color);
|
||||
box-shadow: var(--bar-shadow);
|
||||
|
||||
--sidebar-width: 4rem;
|
||||
--sidebar-icon-size: 1.5rem;
|
||||
}
|
||||
|
||||
.side-tool-bar-container.small-sidebar {
|
||||
--sidebar-width: 2.5rem;
|
||||
--sidebar-icon-size: 1rem;
|
||||
}
|
||||
|
||||
.side-tool-bar-end {
|
||||
|
||||
@@ -99,7 +99,7 @@ import type { MenuItem } from 'primevue/menuitem'
|
||||
import ProgressSpinner from 'primevue/progressspinner'
|
||||
import { useConfirm } from 'primevue/useconfirm'
|
||||
import { useToast } from 'primevue/usetoast'
|
||||
import { computed, onMounted, onUnmounted, ref, shallowRef, watch } from 'vue'
|
||||
import { computed, ref, shallowRef, watch } from 'vue'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
|
||||
import NoResultsPlaceholder from '@/components/common/NoResultsPlaceholder.vue'
|
||||
@@ -194,10 +194,6 @@ const confirmRemoveAll = (event: Event) => {
|
||||
})
|
||||
}
|
||||
|
||||
const onStatus = async () => {
|
||||
await queueStore.update()
|
||||
}
|
||||
|
||||
const menu = ref(null)
|
||||
const menuTargetTask = ref<TaskItemImpl | null>(null)
|
||||
const menuTargetNode = ref<ComfyNode | null>(null)
|
||||
@@ -267,13 +263,4 @@ watch(allTasks, () => {
|
||||
const newIndex = galleryActiveIndex.value + lengthChange
|
||||
galleryActiveIndex.value = Math.max(0, newIndex)
|
||||
})
|
||||
|
||||
onMounted(() => {
|
||||
api.addEventListener('status', onStatus)
|
||||
queueStore.update()
|
||||
})
|
||||
|
||||
onUnmounted(() => {
|
||||
api.removeEventListener('status', onStatus)
|
||||
})
|
||||
</script>
|
||||
|
||||
@@ -230,7 +230,8 @@ export const CORE_SETTINGS: SettingParams[] = [
|
||||
id: 'Comfy.Window.UnloadConfirmation',
|
||||
name: 'Show confirmation when closing window',
|
||||
type: 'boolean',
|
||||
defaultValue: false
|
||||
defaultValue: true,
|
||||
versionModified: '1.7.12'
|
||||
},
|
||||
{
|
||||
id: 'Comfy.TreeExplorer.ItemPadding',
|
||||
@@ -707,5 +708,20 @@ export const CORE_SETTINGS: SettingParams[] = [
|
||||
defaultValue: 'after',
|
||||
options: ['before', 'after'],
|
||||
versionModified: '1.6.10'
|
||||
},
|
||||
{
|
||||
id: 'Comfy.ShowChangeLog',
|
||||
category: ['Comfy', 'Changelog'],
|
||||
name: 'Show changelog on new release',
|
||||
type: 'boolean',
|
||||
defaultValue: true,
|
||||
versionAdded: '1.7.15'
|
||||
},
|
||||
{
|
||||
id: 'Comfy.LastChangelogVersion',
|
||||
name: 'Last shown changelog version',
|
||||
type: 'hidden',
|
||||
defaultValue: '0.0.0',
|
||||
versionAdded: '1.7.15'
|
||||
}
|
||||
]
|
||||
|
||||
@@ -181,6 +181,16 @@ import { electronAPI as getElectronAPI, isElectron } from '@/utils/envUtil'
|
||||
}
|
||||
],
|
||||
|
||||
keybindings: [
|
||||
{
|
||||
commandId: 'Workspace.CloseWorkflow',
|
||||
combo: {
|
||||
key: 'w',
|
||||
ctrl: true
|
||||
}
|
||||
}
|
||||
],
|
||||
|
||||
aboutPageBadges: [
|
||||
{
|
||||
label: 'ComfyUI_desktop v' + desktopAppVersion,
|
||||
|
||||
@@ -1,7 +1,10 @@
|
||||
import { debounce } from 'lodash'
|
||||
|
||||
import { api } from '../../scripts/api'
|
||||
import { app } from '../../scripts/app'
|
||||
import { ComfyApp } from '../../scripts/app'
|
||||
import { $el, ComfyDialog } from '../../scripts/ui'
|
||||
import { getStorageValue, setStorageValue } from '../../scripts/utils'
|
||||
import { ClipspaceDialog } from './clipspace'
|
||||
import { MaskEditorDialogOld } from './maskEditorOld'
|
||||
|
||||
@@ -262,15 +265,15 @@ var styles = `
|
||||
}
|
||||
#maskEditor_toolPanel {
|
||||
height: 100%;
|
||||
width: var(--sidebar-width);
|
||||
width: 4rem;
|
||||
z-index: 8888;
|
||||
background: var(--comfy-menu-bg);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
.maskEditor_toolPanelContainer {
|
||||
width: var(--sidebar-width);
|
||||
height: var(--sidebar-width);
|
||||
width: 4rem;
|
||||
height: 4rem;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
@@ -331,7 +334,7 @@ var styles = `
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
#maskEditor_pointerZone {
|
||||
width: calc(100% - var(--sidebar-width) - 220px);
|
||||
width: calc(100% - 4rem - 220px);
|
||||
height: 100%;
|
||||
}
|
||||
#maskEditor_uiContainer {
|
||||
@@ -703,8 +706,8 @@ var styles = `
|
||||
}
|
||||
|
||||
.maskEditor_toolPanelZoomIndicator {
|
||||
width: var(--sidebar-width);
|
||||
height: var(--sidebar-width);
|
||||
width: 4rem;
|
||||
height: 4rem;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
@@ -776,10 +779,37 @@ interface Offset {
|
||||
}
|
||||
|
||||
export interface Brush {
|
||||
type: BrushShape
|
||||
size: number
|
||||
opacity: number
|
||||
hardness: number
|
||||
type: BrushShape
|
||||
smoothingPrecision: number
|
||||
}
|
||||
|
||||
const saveBrushToCache = debounce(function (key: string, brush: Brush): void {
|
||||
try {
|
||||
const brushString = JSON.stringify(brush)
|
||||
setStorageValue(key, brushString)
|
||||
} catch (error) {
|
||||
console.error('Failed to save brush to cache:', error)
|
||||
}
|
||||
}, 300)
|
||||
|
||||
function loadBrushFromCache(key: string): Brush | null {
|
||||
try {
|
||||
const brushString = getStorageValue(key)
|
||||
if (brushString) {
|
||||
const brush = JSON.parse(brushString) as Brush
|
||||
console.log('Loaded brush from cache:', brush)
|
||||
return brush
|
||||
} else {
|
||||
console.log('No brush found in cache.')
|
||||
return null
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Failed to load brush from cache:', error)
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
type Callback = (data?: any) => void
|
||||
@@ -1952,12 +1982,19 @@ class BrushTool {
|
||||
'Comfy.MaskEditor.BrushAdjustmentSpeed'
|
||||
)
|
||||
|
||||
this.brushSettings = {
|
||||
size: 10,
|
||||
opacity: 100,
|
||||
hardness: 1,
|
||||
type: BrushShape.Arc
|
||||
const cachedBrushSettings = loadBrushFromCache('maskeditor_brush_settings')
|
||||
if (cachedBrushSettings) {
|
||||
this.brushSettings = cachedBrushSettings
|
||||
} else {
|
||||
this.brushSettings = {
|
||||
type: BrushShape.Arc,
|
||||
size: 10,
|
||||
opacity: 0.7,
|
||||
hardness: 1,
|
||||
smoothingPrecision: 10
|
||||
}
|
||||
}
|
||||
|
||||
this.maskBlendMode = MaskBlendMode.Black
|
||||
}
|
||||
|
||||
@@ -2016,6 +2053,10 @@ class BrushTool {
|
||||
'brushType',
|
||||
async () => this.brushSettings.type
|
||||
)
|
||||
this.messageBroker.createPullTopic(
|
||||
'brushSmoothingPrecision',
|
||||
async () => this.brushSettings.smoothingPrecision
|
||||
)
|
||||
this.messageBroker.createPullTopic(
|
||||
'maskBlendMode',
|
||||
async () => this.maskBlendMode
|
||||
@@ -2143,7 +2184,7 @@ class BrushTool {
|
||||
}
|
||||
|
||||
const distanceBetweenPoints =
|
||||
(this.brushSettings.size / this.smoothingPrecision) * 6
|
||||
(this.brushSettings.size / this.brushSettings.smoothingPrecision) * 6
|
||||
const stepNr = Math.ceil(totalLength / distanceBetweenPoints)
|
||||
|
||||
let interpolatedPoints = points
|
||||
@@ -2190,7 +2231,7 @@ class BrushTool {
|
||||
const brush_size = await this.messageBroker.pull('brushSize')
|
||||
const distance = Math.sqrt((p2.x - p1.x) ** 2 + (p2.y - p1.y) ** 2)
|
||||
const steps = Math.ceil(
|
||||
distance / ((brush_size / this.smoothingPrecision) * 4)
|
||||
distance / ((brush_size / this.brushSettings.smoothingPrecision) * 4)
|
||||
) // Adjust for smoother lines
|
||||
const interpolatedOpacity =
|
||||
1 / (1 + Math.exp(-6 * (this.brushSettings.opacity - 0.5))) -
|
||||
@@ -2545,23 +2586,27 @@ class BrushTool {
|
||||
|
||||
private setBrushSize(size: number) {
|
||||
this.brushSettings.size = size
|
||||
saveBrushToCache('maskeditor_brush_settings', this.brushSettings)
|
||||
}
|
||||
|
||||
private setBrushOpacity(opacity: number) {
|
||||
this.brushSettings.opacity = opacity
|
||||
saveBrushToCache('maskeditor_brush_settings', this.brushSettings)
|
||||
}
|
||||
|
||||
private setBrushHardness(hardness: number) {
|
||||
this.brushSettings.hardness = hardness
|
||||
saveBrushToCache('maskeditor_brush_settings', this.brushSettings)
|
||||
}
|
||||
|
||||
private setBrushType(type: BrushShape) {
|
||||
this.brushSettings.type = type
|
||||
saveBrushToCache('maskeditor_brush_settings', this.brushSettings)
|
||||
}
|
||||
|
||||
private setBrushSmoothingPrecision(precision: number) {
|
||||
//console.log('precision', precision)
|
||||
this.smoothingPrecision = precision
|
||||
this.brushSettings.smoothingPrecision = precision
|
||||
saveBrushToCache('maskeditor_brush_settings', this.brushSettings)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2825,7 +2870,6 @@ class UIManager {
|
||||
const circle_shape = document.createElement('div')
|
||||
circle_shape.id = 'maskEditor_sidePanelBrushShapeCircle'
|
||||
circle_shape.classList.add(shapeColor)
|
||||
circle_shape.style.background = 'var(--p-button-text-primary-color)'
|
||||
circle_shape.addEventListener('click', () => {
|
||||
this.messageBroker.publish('setBrushShape', BrushShape.Arc)
|
||||
this.setBrushBorderRadius()
|
||||
@@ -2836,7 +2880,6 @@ class UIManager {
|
||||
const square_shape = document.createElement('div')
|
||||
square_shape.id = 'maskEditor_sidePanelBrushShapeSquare'
|
||||
square_shape.classList.add(shapeColor)
|
||||
square_shape.style.background = ''
|
||||
square_shape.addEventListener('click', () => {
|
||||
this.messageBroker.publish('setBrushShape', BrushShape.Rect)
|
||||
this.setBrushBorderRadius()
|
||||
@@ -2844,6 +2887,16 @@ class UIManager {
|
||||
circle_shape.style.background = ''
|
||||
})
|
||||
|
||||
if (
|
||||
(await this.messageBroker.pull('brushSettings')).type === BrushShape.Arc
|
||||
) {
|
||||
circle_shape.style.background = 'var(--p-button-text-primary-color)'
|
||||
square_shape.style.background = ''
|
||||
} else {
|
||||
circle_shape.style.background = ''
|
||||
square_shape.style.background = 'var(--p-button-text-primary-color)'
|
||||
}
|
||||
|
||||
brush_shape_container.appendChild(circle_shape)
|
||||
brush_shape_container.appendChild(square_shape)
|
||||
|
||||
@@ -2855,7 +2908,7 @@ class UIManager {
|
||||
1,
|
||||
100,
|
||||
1,
|
||||
10,
|
||||
(await this.messageBroker.pull('brushSettings')).size,
|
||||
(event, value) => {
|
||||
this.messageBroker.publish('setBrushSize', parseInt(value))
|
||||
this.updateBrushPreview()
|
||||
@@ -2868,7 +2921,7 @@ class UIManager {
|
||||
0,
|
||||
1,
|
||||
0.01,
|
||||
0.7,
|
||||
(await this.messageBroker.pull('brushSettings')).opacity,
|
||||
(event, value) => {
|
||||
this.messageBroker.publish('setBrushOpacity', parseFloat(value))
|
||||
this.updateBrushPreview()
|
||||
@@ -2881,7 +2934,7 @@ class UIManager {
|
||||
0,
|
||||
1,
|
||||
0.01,
|
||||
1,
|
||||
(await this.messageBroker.pull('brushSettings')).hardness,
|
||||
(event, value) => {
|
||||
this.messageBroker.publish('setBrushHardness', parseFloat(value))
|
||||
this.updateBrushPreview()
|
||||
@@ -2894,7 +2947,7 @@ class UIManager {
|
||||
1,
|
||||
100,
|
||||
1,
|
||||
10,
|
||||
(await this.messageBroker.pull('brushSettings')).smoothingPrecision,
|
||||
(event, value) => {
|
||||
this.messageBroker.publish(
|
||||
'setBrushSmoothingPrecision',
|
||||
@@ -2903,7 +2956,31 @@ class UIManager {
|
||||
}
|
||||
)
|
||||
|
||||
const resetBrushSettingsButton = document.createElement('button')
|
||||
resetBrushSettingsButton.id = 'resetBrushSettingsButton'
|
||||
resetBrushSettingsButton.innerText = 'Reset to Default'
|
||||
|
||||
resetBrushSettingsButton.addEventListener('click', () => {
|
||||
this.messageBroker.publish('setBrushShape', BrushShape.Arc)
|
||||
this.messageBroker.publish('setBrushSize', 10)
|
||||
this.messageBroker.publish('setBrushOpacity', 0.7)
|
||||
this.messageBroker.publish('setBrushHardness', 1)
|
||||
this.messageBroker.publish('setBrushSmoothingPrecision', 10)
|
||||
|
||||
circle_shape.style.background = 'var(--p-button-text-primary-color)'
|
||||
square_shape.style.background = ''
|
||||
|
||||
thicknesSliderObj.slider.value = '10'
|
||||
opacitySliderObj.slider.value = '0.7'
|
||||
hardnessSliderObj.slider.value = '1'
|
||||
brushSmoothingPrecisionSliderObj.slider.value = '10'
|
||||
|
||||
this.setBrushBorderRadius()
|
||||
this.updateBrushPreview()
|
||||
})
|
||||
|
||||
brush_settings_container.appendChild(brush_settings_title)
|
||||
brush_settings_container.appendChild(resetBrushSettingsButton)
|
||||
brush_settings_container.appendChild(brush_shape_outer_container)
|
||||
brush_settings_container.appendChild(thicknesSliderObj.container)
|
||||
brush_settings_container.appendChild(opacitySliderObj.container)
|
||||
|
||||
@@ -36,12 +36,21 @@ export function useTerminal(element: Ref<HTMLElement>) {
|
||||
|
||||
return {
|
||||
terminal,
|
||||
useAutoSize(
|
||||
root: Ref<HTMLElement>,
|
||||
autoRows: boolean = true,
|
||||
autoCols: boolean = true,
|
||||
useAutoSize({
|
||||
root,
|
||||
autoRows = true,
|
||||
autoCols = true,
|
||||
minCols = Number.NEGATIVE_INFINITY,
|
||||
minRows = Number.NEGATIVE_INFINITY,
|
||||
onResize
|
||||
}: {
|
||||
root: Ref<HTMLElement>
|
||||
autoRows?: boolean
|
||||
autoCols?: boolean
|
||||
minCols?: number
|
||||
minRows?: number
|
||||
onResize?: () => void
|
||||
) {
|
||||
}) {
|
||||
const ensureValidRows = (rows: number | undefined) => {
|
||||
if (rows == null || isNaN(rows)) {
|
||||
return root.value?.clientHeight / 20
|
||||
@@ -61,8 +70,14 @@ export function useTerminal(element: Ref<HTMLElement>) {
|
||||
const dims = fitAddon.proposeDimensions()
|
||||
// Sometimes propose returns NaN, so we may need to estimate.
|
||||
terminal.resize(
|
||||
autoCols ? ensureValidCols(dims?.cols) : terminal.cols,
|
||||
autoRows ? ensureValidRows(dims?.rows) : terminal.rows
|
||||
Math.max(
|
||||
autoCols ? ensureValidCols(dims?.cols) : terminal.cols,
|
||||
minCols
|
||||
),
|
||||
Math.max(
|
||||
autoRows ? ensureValidRows(dims?.rows) : terminal.rows,
|
||||
minRows
|
||||
)
|
||||
)
|
||||
onResize?.()
|
||||
}
|
||||
|
||||
@@ -70,7 +70,9 @@
|
||||
"keybinding": "Keybinding",
|
||||
"upload": "Upload",
|
||||
"export": "Export",
|
||||
"workflow": "Workflow"
|
||||
"workflow": "Workflow",
|
||||
"success": "Success",
|
||||
"ok": "OK"
|
||||
},
|
||||
"issueReport": {
|
||||
"submitErrorReport": "Submit Error Report (Optional)",
|
||||
@@ -151,7 +153,7 @@
|
||||
"appDataLocationTooltip": "ComfyUI's app data directory. Stores:\n- Logs\n- Server configs",
|
||||
"appPathLocationTooltip": "ComfyUI's app asset directory. Stores the ComfyUI code and assets",
|
||||
"migrateFromExistingInstallation": "Migrate from Existing Installation",
|
||||
"migrationSourcePathDescription": "If you have an existing ComfyUI installation, we can copy/link your existing user files and models to the new installation.",
|
||||
"migrationSourcePathDescription": "If you have an existing ComfyUI installation, we can copy/link your existing user files and models to the new installation. Your existing ComfyUI installation will not be affected.",
|
||||
"selectItemsToMigrate": "Select Items to Migrate",
|
||||
"migrationOptional": "Migration is optional. If you don't have an existing installation, you can skip this step.",
|
||||
"desktopAppSettings": "Desktop App Settings",
|
||||
@@ -182,6 +184,8 @@
|
||||
"settings": {
|
||||
"autoUpdate": "Automatic Updates",
|
||||
"allowMetrics": "Usage Metrics",
|
||||
"errorUpdatingConsent": "Error Updating Consent",
|
||||
"errorUpdatingConsentDetail": "Failed to update metrics consent settings",
|
||||
"autoUpdateDescription": "Automatically download updates when they become available. You will be notified before updates are installed.",
|
||||
"allowMetricsDescription": "Help improve ComfyUI by sending anonymous usage metrics. No personal information or workflow content will be collected.",
|
||||
"learnMoreAboutData": "Learn more about data collection",
|
||||
@@ -192,19 +196,25 @@
|
||||
"collect": {
|
||||
"errorReports": "Error message and stack trace",
|
||||
"systemInfo": "Hardware, OS type, and app version",
|
||||
"userJourneyEvents": "User journey events",
|
||||
"userJourneyTooltip": "User journey events are used to track the user's journey through the app installation process. The event collection ends on the first successful ComfyUI workflow run."
|
||||
"userJourneyEvents": "User journey events"
|
||||
},
|
||||
"doNotCollect": {
|
||||
"personalInformation": "Personal information",
|
||||
"fileSystemInformation": "File system information",
|
||||
"workflowContents": "Workflow contents",
|
||||
"customNodeConfigurations": "Custom node configurations"
|
||||
}
|
||||
},
|
||||
"viewFullPolicy": "View full policy"
|
||||
}
|
||||
},
|
||||
"customNodes": "Custom Nodes",
|
||||
"customNodesDescription": "Reinstall custom nodes from existing ComfyUI installations."
|
||||
"customNodesDescription": "Reinstall custom nodes from existing ComfyUI installations.",
|
||||
"helpImprove": "Please help improve ComfyUI",
|
||||
"moreInfo": "For more info, please read our",
|
||||
"privacyPolicy": "privacy policy",
|
||||
"metricsEnabled": "Metrics Enabled",
|
||||
"metricsDisabled": "Metrics Disabled",
|
||||
"updateConsent": "You previously opted in to reporting crashes. We are now tracking event-based metrics to help identify bugs and improve the app. No personal identifiable information is collected."
|
||||
},
|
||||
"serverStart": {
|
||||
"reinstall": "Reinstall",
|
||||
@@ -600,6 +610,7 @@
|
||||
"combine": "combine",
|
||||
"cond single": "cond single",
|
||||
"controlnet": "controlnet",
|
||||
"inpaint": "inpaint",
|
||||
"scheduling": "scheduling",
|
||||
"create": "create",
|
||||
"mask": "mask",
|
||||
@@ -619,7 +630,6 @@
|
||||
"batch": "batch",
|
||||
"video_models": "video_models",
|
||||
"upscaling": "upscaling",
|
||||
"inpaint": "inpaint",
|
||||
"instructpix2pix": "instructpix2pix",
|
||||
"compositing": "compositing",
|
||||
"samplers": "samplers",
|
||||
|
||||
@@ -177,7 +177,7 @@
|
||||
},
|
||||
"CLIPLoader": {
|
||||
"display_name": "Load CLIP",
|
||||
"description": "[Recipes]\n\nstable_diffusion: clip-l\nstable_cascade: clip-g\nsd3: t5 / clip-g / clip-l\nstable_audio: t5\nmochi: t5",
|
||||
"description": "[Recipes]\n\nstable_diffusion: clip-l\nstable_cascade: clip-g\nsd3: t5 / clip-g / clip-l\nstable_audio: t5\nmochi: t5\ncosmos: old t5 xxl",
|
||||
"inputs": {
|
||||
"clip_name": {
|
||||
"name": "clip_name"
|
||||
@@ -862,6 +862,32 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"CosmosImageToVideoLatent": {
|
||||
"display_name": "CosmosImageToVideoLatent",
|
||||
"inputs": {
|
||||
"vae": {
|
||||
"name": "vae"
|
||||
},
|
||||
"width": {
|
||||
"name": "width"
|
||||
},
|
||||
"height": {
|
||||
"name": "height"
|
||||
},
|
||||
"length": {
|
||||
"name": "length"
|
||||
},
|
||||
"batch_size": {
|
||||
"name": "batch_size"
|
||||
},
|
||||
"start_image": {
|
||||
"name": "start_image"
|
||||
},
|
||||
"end_image": {
|
||||
"name": "end_image"
|
||||
}
|
||||
}
|
||||
},
|
||||
"CreateHookKeyframe": {
|
||||
"display_name": "Create Hook Keyframe",
|
||||
"inputs": {
|
||||
@@ -1230,6 +1256,23 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"EmptyCosmosLatentVideo": {
|
||||
"display_name": "EmptyCosmosLatentVideo",
|
||||
"inputs": {
|
||||
"width": {
|
||||
"name": "width"
|
||||
},
|
||||
"height": {
|
||||
"name": "height"
|
||||
},
|
||||
"length": {
|
||||
"name": "length"
|
||||
},
|
||||
"batch_size": {
|
||||
"name": "batch_size"
|
||||
}
|
||||
}
|
||||
},
|
||||
"EmptyHunyuanLatentVideo": {
|
||||
"display_name": "EmptyHunyuanLatentVideo",
|
||||
"inputs": {
|
||||
@@ -4745,6 +4788,17 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"SetFirstSigma": {
|
||||
"display_name": "SetFirstSigma",
|
||||
"inputs": {
|
||||
"sigmas": {
|
||||
"name": "sigmas"
|
||||
},
|
||||
"sigma": {
|
||||
"name": "sigma"
|
||||
}
|
||||
}
|
||||
},
|
||||
"SetHookKeyframes": {
|
||||
"display_name": "Set Hook Keyframes",
|
||||
"inputs": {
|
||||
|
||||
@@ -107,6 +107,7 @@
|
||||
"noTasksFound": "Aucune tâche trouvée",
|
||||
"noTasksFoundMessage": "Il n'y a pas de tâches dans la file d'attente.",
|
||||
"noWorkflowsFound": "Aucun flux de travail trouvé.",
|
||||
"ok": "OK",
|
||||
"openNewIssue": "Ouvrir un nouveau problème",
|
||||
"overwrite": "Écraser",
|
||||
"reconnected": "Reconnecté",
|
||||
@@ -129,6 +130,7 @@
|
||||
"searchWorkflows": "Rechercher des flux de travail",
|
||||
"settings": "Paramètres",
|
||||
"showReport": "Afficher le rapport",
|
||||
"success": "Succès",
|
||||
"systemInfo": "Informations système",
|
||||
"terminal": "Terminal",
|
||||
"upload": "Téléverser",
|
||||
@@ -186,6 +188,7 @@
|
||||
"selectGpu": "Sélectionnez le GPU",
|
||||
"selectGpuDescription": "Sélectionnez le type de GPU que vous avez"
|
||||
},
|
||||
"helpImprove": "Veuillez aider à améliorer ComfyUI",
|
||||
"installLocation": "Emplacement d'installation",
|
||||
"installLocationDescription": "Sélectionnez le répertoire pour les données utilisateur de ComfyUI. Un environnement python sera installé à l'emplacement sélectionné. Veuillez vous assurer que le disque sélectionné a suffisamment d'espace (~15GB) restant.",
|
||||
"installLocationTooltip": "Répertoire des données utilisateur de ComfyUI. Stocke :\n- Environnement Python\n- Modèles\n- Nœuds personnalisés\n",
|
||||
@@ -197,13 +200,17 @@
|
||||
"title": "Configuration manuelle",
|
||||
"virtualEnvironmentPath": "Chemin de l'environnement virtuel"
|
||||
},
|
||||
"metricsDisabled": "Métriques désactivées",
|
||||
"metricsEnabled": "Métriques activées",
|
||||
"migrateFromExistingInstallation": "Migrer à partir d'une installation existante",
|
||||
"migration": "Migration",
|
||||
"migrationOptional": "La migration est facultative. Si vous n'avez pas d'installation existante, vous pouvez sauter cette étape.",
|
||||
"migrationSourcePathDescription": "Si vous avez une installation existante de ComfyUI, nous pouvons copier/lier vos fichiers utilisateur et modèles existants à la nouvelle installation.",
|
||||
"migrationSourcePathDescription": "Si vous avez une installation existante de ComfyUI, nous pouvons copier/lier vos fichiers utilisateur et modèles existants à la nouvelle installation. Votre installation existante de ComfyUI ne sera pas affectée.",
|
||||
"moreInfo": "Pour plus d'informations, veuillez lire notre",
|
||||
"parentMissing": "Le chemin n'existe pas - créez d'abord le répertoire contenant",
|
||||
"pathExists": "Le répertoire existe déjà - veuillez vous assurer que vous avez sauvegardé toutes les données",
|
||||
"pathValidationFailed": "Échec de la validation du chemin",
|
||||
"privacyPolicy": "politique de confidentialité",
|
||||
"selectItemsToMigrate": "Sélectionnez les éléments à migrer",
|
||||
"settings": {
|
||||
"allowMetrics": "Métriques d'utilisation",
|
||||
@@ -214,8 +221,7 @@
|
||||
"collect": {
|
||||
"errorReports": "Message d'erreur et trace de la pile",
|
||||
"systemInfo": "Matériel, type de système d'exploitation et version de l'application",
|
||||
"userJourneyEvents": "Événements du parcours utilisateur",
|
||||
"userJourneyTooltip": "Les événements du parcours utilisateur sont utilisés pour suivre le parcours de l'utilisateur lors du processus d'installation de l'application. La collecte d'événements se termine lors de la première exécution réussie du flux de travail ComfyUI."
|
||||
"userJourneyEvents": "Événements du parcours utilisateur"
|
||||
},
|
||||
"doNotCollect": {
|
||||
"customNodeConfigurations": "Configurations de nœud personnalisées",
|
||||
@@ -224,13 +230,17 @@
|
||||
"workflowContents": "Contenus du flux de travail"
|
||||
},
|
||||
"title": "À propos de la collecte de données",
|
||||
"viewFullPolicy": "Voir la politique complète",
|
||||
"whatWeCollect": "Ce que nous collectons :",
|
||||
"whatWeDoNotCollect": "Ce que nous ne collectons pas :"
|
||||
},
|
||||
"errorUpdatingConsent": "Erreur de mise à jour du consentement",
|
||||
"errorUpdatingConsentDetail": "Échec de la mise à jour des paramètres de consentement aux métriques",
|
||||
"learnMoreAboutData": "En savoir plus sur la collecte de données"
|
||||
},
|
||||
"systemLocations": "Emplacements système",
|
||||
"unhandledError": "Erreur inconnue"
|
||||
"unhandledError": "Erreur inconnue",
|
||||
"updateConsent": "Vous avez précédemment accepté de signaler les plantages. Nous suivons maintenant des métriques basées sur les événements pour aider à identifier les bugs et améliorer l'application. Aucune information personnelle identifiable n'est collectée."
|
||||
},
|
||||
"issueReport": {
|
||||
"contactFollowUp": "Contactez-moi pour un suivi",
|
||||
|
||||
@@ -113,7 +113,7 @@
|
||||
}
|
||||
},
|
||||
"CLIPLoader": {
|
||||
"description": "[Recettes]\n\nstable_diffusion: clip-l\nstable_cascade: clip-g\nsd3: t5 / clip-g / clip-l\nstable_audio: t5\nmochi: t5",
|
||||
"description": "[Recettes]\n\nstable_diffusion: clip-l\nstable_cascade: clip-g\nsd3: t5 / clip-g / clip-l\nstable_audio: t5\nmochi: t5\ncosmos: old t5 xxl",
|
||||
"display_name": "Charger CLIP",
|
||||
"inputs": {
|
||||
"clip_name": {
|
||||
@@ -862,6 +862,32 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"CosmosImageToVideoLatent": {
|
||||
"display_name": "CosmosImageVersVidéoLatent",
|
||||
"inputs": {
|
||||
"batch_size": {
|
||||
"name": "taille_du_lot"
|
||||
},
|
||||
"end_image": {
|
||||
"name": "image_de_fin"
|
||||
},
|
||||
"height": {
|
||||
"name": "hauteur"
|
||||
},
|
||||
"length": {
|
||||
"name": "longueur"
|
||||
},
|
||||
"start_image": {
|
||||
"name": "image_de_départ"
|
||||
},
|
||||
"vae": {
|
||||
"name": "vae"
|
||||
},
|
||||
"width": {
|
||||
"name": "largeur"
|
||||
}
|
||||
}
|
||||
},
|
||||
"CreateHookKeyframe": {
|
||||
"display_name": "Créer une image clé de crochet",
|
||||
"inputs": {
|
||||
@@ -1230,6 +1256,23 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"EmptyCosmosLatentVideo": {
|
||||
"display_name": "VidéoLatenteCosmosVide",
|
||||
"inputs": {
|
||||
"batch_size": {
|
||||
"name": "taille_du_lot"
|
||||
},
|
||||
"height": {
|
||||
"name": "hauteur"
|
||||
},
|
||||
"length": {
|
||||
"name": "longueur"
|
||||
},
|
||||
"width": {
|
||||
"name": "largeur"
|
||||
}
|
||||
}
|
||||
},
|
||||
"EmptyHunyuanLatentVideo": {
|
||||
"display_name": "EmptyHunyuanLatentVideo",
|
||||
"inputs": {
|
||||
@@ -4825,6 +4868,17 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"SetFirstSigma": {
|
||||
"display_name": "DéfinirPremierSigma",
|
||||
"inputs": {
|
||||
"sigma": {
|
||||
"name": "sigma"
|
||||
},
|
||||
"sigmas": {
|
||||
"name": "sigmas"
|
||||
}
|
||||
}
|
||||
},
|
||||
"SetHookKeyframes": {
|
||||
"display_name": "Définir les Images Clés de Crochet",
|
||||
"inputs": {
|
||||
|
||||
@@ -107,6 +107,7 @@
|
||||
"noTasksFound": "タスクが見つかりません",
|
||||
"noTasksFoundMessage": "キューにタスクがありません。",
|
||||
"noWorkflowsFound": "ワークフローが見つかりません。",
|
||||
"ok": "OK",
|
||||
"openNewIssue": "新しい問題を開く",
|
||||
"overwrite": "上書き",
|
||||
"reconnected": "再接続されました",
|
||||
@@ -129,6 +130,7 @@
|
||||
"searchWorkflows": "ワークフローを検索",
|
||||
"settings": "設定",
|
||||
"showReport": "レポートを表示",
|
||||
"success": "成功",
|
||||
"systemInfo": "システム情報",
|
||||
"terminal": "ターミナル",
|
||||
"upload": "アップロード",
|
||||
@@ -186,6 +188,7 @@
|
||||
"selectGpu": "GPUを選択",
|
||||
"selectGpuDescription": "所有しているGPUのタイプを選択してください"
|
||||
},
|
||||
"helpImprove": "ComfyUIの改善にご協力ください",
|
||||
"installLocation": "インストール先",
|
||||
"installLocationDescription": "ComfyUIのユーザーデータを保存するディレクトリを選択してください。Python環境が選択した場所にインストールされます。選択したディスクに約15GBの空き容量が必要です。",
|
||||
"installLocationTooltip": "ComfyUIのユーザーデータディレクトリ。保存内容:\n- Python環境\n- モデル\n- カスタムノード\n",
|
||||
@@ -197,13 +200,17 @@
|
||||
"title": "マニュアル設定",
|
||||
"virtualEnvironmentPath": "仮想環境のパス"
|
||||
},
|
||||
"metricsDisabled": "メトリクス無効",
|
||||
"metricsEnabled": "メトリクス有効",
|
||||
"migrateFromExistingInstallation": "既存のインストールから移行",
|
||||
"migration": "移行",
|
||||
"migrationOptional": "移行は任意です。既存のインストールがない場合、このステップをスキップできます。",
|
||||
"migrationSourcePathDescription": "既存のComfyUIインストールがある場合、既存のユーザーファイルやモデルを新しいインストールにコピー/リンクできます。",
|
||||
"migrationSourcePathDescription": "既存のComfyUIインストールがある場合、既存のユーザーファイルとモデルを新しいインストールにコピー/リンクすることができます。既存のComfyUIインストールは影響を受けません。",
|
||||
"moreInfo": "詳細は、私たちの",
|
||||
"parentMissing": "パスが存在しません - 最初に含まれるディレクトリを作成してください",
|
||||
"pathExists": "ディレクトリはすでに存在します - すべてのデータをバックアップしたことを確認してください",
|
||||
"pathValidationFailed": "パスの検証に失敗しました",
|
||||
"privacyPolicy": "プライバシーポリシー",
|
||||
"selectItemsToMigrate": "移行する項目を選択",
|
||||
"settings": {
|
||||
"allowMetrics": "使用状況のメトリクス",
|
||||
@@ -214,8 +221,7 @@
|
||||
"collect": {
|
||||
"errorReports": "エラーメッセージとスタックトレース",
|
||||
"systemInfo": "ハードウェア、OSタイプ、アプリバージョン",
|
||||
"userJourneyEvents": "ユーザージャーニーイベント",
|
||||
"userJourneyTooltip": "ユーザージャーニーイベントは、アプリのインストールプロセスを通じてユーザーの旅を追跡するために使用されます。イベントの収集は、最初の成功したComfyUIワークフローの実行で終了します。"
|
||||
"userJourneyEvents": "ユーザージャーニーイベント"
|
||||
},
|
||||
"doNotCollect": {
|
||||
"customNodeConfigurations": "カスタムノードの設定",
|
||||
@@ -224,13 +230,17 @@
|
||||
"workflowContents": "ワークフローの内容"
|
||||
},
|
||||
"title": "データ収集について",
|
||||
"viewFullPolicy": "完全なポリシーを見る",
|
||||
"whatWeCollect": "収集内容:",
|
||||
"whatWeDoNotCollect": "収集しない内容:"
|
||||
},
|
||||
"errorUpdatingConsent": "同意の更新エラー",
|
||||
"errorUpdatingConsentDetail": "メトリクスの同意設定の更新に失敗しました",
|
||||
"learnMoreAboutData": "データ収集の詳細を見る"
|
||||
},
|
||||
"systemLocations": "システムの場所",
|
||||
"unhandledError": "未知のエラー"
|
||||
"unhandledError": "未知のエラー",
|
||||
"updateConsent": "以前はクラッシュの報告に同意していました。現在、バグの特定とアプリの改善を助けるためにイベントベースのメトリクスを追跡しています。個人を特定できる情報は収集されません。"
|
||||
},
|
||||
"issueReport": {
|
||||
"contactFollowUp": "フォローアップのために私に連絡する",
|
||||
|
||||
@@ -113,7 +113,7 @@
|
||||
}
|
||||
},
|
||||
"CLIPLoader": {
|
||||
"description": "[レシピ]\n\nstable_diffusion: clip-l\nstable_cascade: clip-g\nsd3: t5 / clip-g / clip-l\nstable_audio: t5\nmochi: t5",
|
||||
"description": "[レシピ]\n\nstable_diffusion: clip-l\nstable_cascade: clip-g\nsd3: t5 / clip-g / clip-l\nstable_audio: t5\nmochi: t5\ncosmos: old t5 xxl",
|
||||
"display_name": "CLIPを読み込む",
|
||||
"inputs": {
|
||||
"clip_name": {
|
||||
@@ -862,6 +862,32 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"CosmosImageToVideoLatent": {
|
||||
"display_name": "CosmosImageToVideoLatent",
|
||||
"inputs": {
|
||||
"batch_size": {
|
||||
"name": "バッチサイズ"
|
||||
},
|
||||
"end_image": {
|
||||
"name": "終了画像"
|
||||
},
|
||||
"height": {
|
||||
"name": "高さ"
|
||||
},
|
||||
"length": {
|
||||
"name": "長さ"
|
||||
},
|
||||
"start_image": {
|
||||
"name": "開始画像"
|
||||
},
|
||||
"vae": {
|
||||
"name": "vae"
|
||||
},
|
||||
"width": {
|
||||
"name": "幅"
|
||||
}
|
||||
}
|
||||
},
|
||||
"CreateHookKeyframe": {
|
||||
"display_name": "フックキーフレームを作成",
|
||||
"inputs": {
|
||||
@@ -1230,6 +1256,23 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"EmptyCosmosLatentVideo": {
|
||||
"display_name": "EmptyCosmosLatentVideo",
|
||||
"inputs": {
|
||||
"batch_size": {
|
||||
"name": "バッチサイズ"
|
||||
},
|
||||
"height": {
|
||||
"name": "高さ"
|
||||
},
|
||||
"length": {
|
||||
"name": "長さ"
|
||||
},
|
||||
"width": {
|
||||
"name": "幅"
|
||||
}
|
||||
}
|
||||
},
|
||||
"EmptyHunyuanLatentVideo": {
|
||||
"display_name": "EmptyHunyuanLatentVideo",
|
||||
"inputs": {
|
||||
@@ -4825,6 +4868,17 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"SetFirstSigma": {
|
||||
"display_name": "SetFirstSigma",
|
||||
"inputs": {
|
||||
"sigma": {
|
||||
"name": "シグマ"
|
||||
},
|
||||
"sigmas": {
|
||||
"name": "シグマ"
|
||||
}
|
||||
}
|
||||
},
|
||||
"SetHookKeyframes": {
|
||||
"display_name": "フックキーフレームを設定",
|
||||
"inputs": {
|
||||
|
||||
@@ -107,6 +107,7 @@
|
||||
"noTasksFound": "작업을 찾을 수 없습니다.",
|
||||
"noTasksFoundMessage": "대기열에 작업이 없습니다.",
|
||||
"noWorkflowsFound": "워크플로를 찾을 수 없습니다.",
|
||||
"ok": "확인",
|
||||
"openNewIssue": "새 문제 열기",
|
||||
"overwrite": "덮어쓰기",
|
||||
"reconnected": "재연결됨",
|
||||
@@ -129,6 +130,7 @@
|
||||
"searchWorkflows": "워크플로 검색",
|
||||
"settings": "설정",
|
||||
"showReport": "보고서 보기",
|
||||
"success": "성공",
|
||||
"systemInfo": "시스템 정보",
|
||||
"terminal": "터미널",
|
||||
"upload": "업로드",
|
||||
@@ -186,6 +188,7 @@
|
||||
"selectGpu": "GPU 선택",
|
||||
"selectGpuDescription": "소유한 GPU 유형을 선택하세요"
|
||||
},
|
||||
"helpImprove": "ComfyUI 개선에 도움을 주세요",
|
||||
"installLocation": "설치 위치",
|
||||
"installLocationDescription": "ComfyUI의 사용자 데이터 디렉토리를 선택하십시오. 선택한 위치에 Python 환경이 설치됩니다. 선택한 디스크에 충분한 공간(~15GB)이 남아 있는지 확인하십시오.",
|
||||
"installLocationTooltip": "ComfyUI의 사용자 데이터 디렉토리. 저장소:\n- Python 환경\n- 모델\n- 사용자 정의 노드\n",
|
||||
@@ -197,13 +200,17 @@
|
||||
"title": "수동 구성",
|
||||
"virtualEnvironmentPath": "가상 환경 경로"
|
||||
},
|
||||
"metricsDisabled": "메트릭스 비활성화",
|
||||
"metricsEnabled": "메트릭스 활성화",
|
||||
"migrateFromExistingInstallation": "기존 설치에서 마이그레이션",
|
||||
"migration": "마이그레이션",
|
||||
"migrationOptional": "마이그레이션은 선택 사항입니다. 기존에 설치된 것이 없다면, 이 단계를 건너뛸 수 있습니다.",
|
||||
"migrationSourcePathDescription": "기존에 설치된 ComfyUI가 있는 경우, 기존 사용자 파일과 모델을 새 설치에 복사하거나 링크할 수 있습니다",
|
||||
"migrationSourcePathDescription": "기존의 ComfyUI 설치가 있으면, 기존 사용자 파일과 모델을 새 설치로 복사/링크할 수 있습니다. 기존의 ComfyUI 설치는 영향을 받지 않습니다.",
|
||||
"moreInfo": "자세한 정보는 우리의",
|
||||
"parentMissing": "경로가 존재하지 않습니다 - 먼저 포함하는 디렉토리를 생성하세요",
|
||||
"pathExists": "디렉토리가 이미 존재합니다 - 모든 데이터를 백업했는지 확인해 주세요",
|
||||
"pathValidationFailed": "경로 유효성 검사 실패",
|
||||
"privacyPolicy": "개인정보 보호정책",
|
||||
"selectItemsToMigrate": "마이그레이션 항목 선택",
|
||||
"settings": {
|
||||
"allowMetrics": "사용 통계",
|
||||
@@ -214,8 +221,7 @@
|
||||
"collect": {
|
||||
"errorReports": "오류 메시지 및 스택 추적",
|
||||
"systemInfo": "하드웨어, OS 유형, 앱 버전",
|
||||
"userJourneyEvents": "사용자 여정 이벤트",
|
||||
"userJourneyTooltip": "사용자 여정 이벤트는 앱 설치 과정을 통한 사용자의 여정을 추적하는 데 사용됩니다. 이벤트 수집은 첫 번째 성공적인 ComfyUI 워크플로우 실행에서 종료됩니다."
|
||||
"userJourneyEvents": "사용자 여정 이벤트"
|
||||
},
|
||||
"doNotCollect": {
|
||||
"customNodeConfigurations": "사용자 정의 노드 구성",
|
||||
@@ -224,13 +230,17 @@
|
||||
"workflowContents": "워크플로우 내용"
|
||||
},
|
||||
"title": "데이터 수집 안내",
|
||||
"viewFullPolicy": "전체 정책 보기",
|
||||
"whatWeCollect": "수집하는 정보:",
|
||||
"whatWeDoNotCollect": "수집하지 않는 정보:"
|
||||
},
|
||||
"errorUpdatingConsent": "동의 업데이트 오류",
|
||||
"errorUpdatingConsentDetail": "메트릭스 동의 설정 업데이트에 실패했습니다",
|
||||
"learnMoreAboutData": "데이터 수집에 대해 더 알아보기"
|
||||
},
|
||||
"systemLocations": "시스템 위치",
|
||||
"unhandledError": "알 수 없는 오류"
|
||||
"unhandledError": "알 수 없는 오류",
|
||||
"updateConsent": "당신은 이전에 충돌 보고에 동의했습니다. 이제 버그를 식별하고 앱을 개선하기 위해 이벤트 기반 메트릭스를 추적하고 있습니다. 개인 식별 정보는 수집하지 않습니다."
|
||||
},
|
||||
"issueReport": {
|
||||
"contactFollowUp": "추적 조사를 위해 연락해 주세요",
|
||||
|
||||
@@ -113,7 +113,7 @@
|
||||
}
|
||||
},
|
||||
"CLIPLoader": {
|
||||
"description": "[조합법]\n\nstable_diffusion: clip-l\nstable_cascade: clip-g\nsd3: t5 / clip-g / clip-l\nstable_audio: t5\nmochi: t5",
|
||||
"description": "[조합법]\n\nstable_diffusion: clip-l\nstable_cascade: clip-g\nsd3: t5 / clip-g / clip-l\nstable_audio: t5\nmochi: t5\ncosmos: old t5 xxl",
|
||||
"display_name": "CLIP 로드",
|
||||
"inputs": {
|
||||
"clip_name": {
|
||||
@@ -862,6 +862,32 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"CosmosImageToVideoLatent": {
|
||||
"display_name": "CosmosImageToVideoLatent",
|
||||
"inputs": {
|
||||
"batch_size": {
|
||||
"name": "배치 크기"
|
||||
},
|
||||
"end_image": {
|
||||
"name": "끝 이미지"
|
||||
},
|
||||
"height": {
|
||||
"name": "높이"
|
||||
},
|
||||
"length": {
|
||||
"name": "길이"
|
||||
},
|
||||
"start_image": {
|
||||
"name": "시작 이미지"
|
||||
},
|
||||
"vae": {
|
||||
"name": "vae"
|
||||
},
|
||||
"width": {
|
||||
"name": "너비"
|
||||
}
|
||||
}
|
||||
},
|
||||
"CreateHookKeyframe": {
|
||||
"display_name": "후크 키프레임 생성",
|
||||
"inputs": {
|
||||
@@ -1230,6 +1256,23 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"EmptyCosmosLatentVideo": {
|
||||
"display_name": "EmptyCosmosLatentVideo",
|
||||
"inputs": {
|
||||
"batch_size": {
|
||||
"name": "배치 크기"
|
||||
},
|
||||
"height": {
|
||||
"name": "높이"
|
||||
},
|
||||
"length": {
|
||||
"name": "길이"
|
||||
},
|
||||
"width": {
|
||||
"name": "너비"
|
||||
}
|
||||
}
|
||||
},
|
||||
"EmptyHunyuanLatentVideo": {
|
||||
"display_name": "빈 잠재 비디오 (Hunyuan)",
|
||||
"inputs": {
|
||||
@@ -4825,6 +4868,17 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"SetFirstSigma": {
|
||||
"display_name": "SetFirstSigma",
|
||||
"inputs": {
|
||||
"sigma": {
|
||||
"name": "시그마"
|
||||
},
|
||||
"sigmas": {
|
||||
"name": "시그마들"
|
||||
}
|
||||
}
|
||||
},
|
||||
"SetHookKeyframes": {
|
||||
"display_name": "후크 키프레임 설정",
|
||||
"inputs": {
|
||||
|
||||
@@ -107,6 +107,7 @@
|
||||
"noTasksFound": "Задачи не найдены",
|
||||
"noTasksFoundMessage": "В очереди нет задач.",
|
||||
"noWorkflowsFound": "Рабочие процессы не найдены.",
|
||||
"ok": "ОК",
|
||||
"openNewIssue": "Открыть новую проблему",
|
||||
"overwrite": "Перезаписать",
|
||||
"reconnected": "Переподключено",
|
||||
@@ -129,6 +130,7 @@
|
||||
"searchWorkflows": "Поиск рабочих процессов",
|
||||
"settings": "Настройки",
|
||||
"showReport": "Показать отчет",
|
||||
"success": "Успех",
|
||||
"systemInfo": "Информация о системе",
|
||||
"terminal": "Терминал",
|
||||
"upload": "Загрузить",
|
||||
@@ -186,6 +188,7 @@
|
||||
"selectGpu": "Выберите GPU",
|
||||
"selectGpuDescription": "Выберите тип GPU, который у вас есть"
|
||||
},
|
||||
"helpImprove": "Пожалуйста, помогите улучшить ComfyUI",
|
||||
"installLocation": "Место установки",
|
||||
"installLocationDescription": "Выберите директорию для пользовательских данных ComfyUI. В выбранном месте будет установлена среда Python. Пожалуйста, убедитесь, что на выбранном диске достаточно места (~15 ГБ).",
|
||||
"installLocationTooltip": "Директория пользовательских данных ComfyUI. Хранит:\n- Среда Python\n- Модели\n- Пользовательские узлы\n",
|
||||
@@ -197,13 +200,17 @@
|
||||
"title": "Ручная Конфигурация",
|
||||
"virtualEnvironmentPath": "Путь виртуального окружения"
|
||||
},
|
||||
"metricsDisabled": "Метрики отключены",
|
||||
"metricsEnabled": "Метрики включены",
|
||||
"migrateFromExistingInstallation": "Миграция из существующей установки",
|
||||
"migration": "Миграция",
|
||||
"migrationOptional": "Миграция является необязательной. Если у вас нет существующей установки, вы можете пропустить этот шаг.",
|
||||
"migrationSourcePathDescription": "Если у вас есть существующая установка ComfyUI, мы можем скопировать/связать ваши существующие пользовательские файлы и модели в новую установку.",
|
||||
"migrationSourcePathDescription": "Если у вас уже есть установка ComfyUI, мы можем скопировать/связать ваши существующие пользовательские файлы и модели с новой установкой. Ваша существующая установка ComfyUI не будет затронута.",
|
||||
"moreInfo": "Для получения дополнительной информации, пожалуйста, прочтите нашу",
|
||||
"parentMissing": "Путь не существует - сначала создайте родительский каталог",
|
||||
"pathExists": "Директория уже существует - пожалуйста, убедитесь, что вы сделали резервное копирование всех данных",
|
||||
"pathValidationFailed": "Не удалось проверить путь",
|
||||
"privacyPolicy": "политику конфиденциальности",
|
||||
"selectItemsToMigrate": "Выберите элементы для миграции",
|
||||
"settings": {
|
||||
"allowMetrics": "Метрики использования",
|
||||
@@ -214,8 +221,7 @@
|
||||
"collect": {
|
||||
"errorReports": "Сообщение об ошибке и трассировка стека",
|
||||
"systemInfo": "Аппаратное обеспечение, тип ОС и версия приложения",
|
||||
"userJourneyEvents": "События пользовательского пути",
|
||||
"userJourneyTooltip": "События пользовательского пути используются для отслеживания пути пользователя в процессе установки приложения. Сбор событий заканчивается после первого успешного запуска рабочего процесса ComfyUI."
|
||||
"userJourneyEvents": "События пользовательского пути"
|
||||
},
|
||||
"doNotCollect": {
|
||||
"customNodeConfigurations": "Пользовательские конфигурации узлов",
|
||||
@@ -224,13 +230,17 @@
|
||||
"workflowContents": "Содержание рабочего процесса"
|
||||
},
|
||||
"title": "О сборе данных",
|
||||
"viewFullPolicy": "Просмотреть политику полностью",
|
||||
"whatWeCollect": "Что мы собираем:",
|
||||
"whatWeDoNotCollect": "Что мы не собираем:"
|
||||
},
|
||||
"errorUpdatingConsent": "Ошибка обновления согласия",
|
||||
"errorUpdatingConsentDetail": "Не удалось обновить настройки согласия на метрики",
|
||||
"learnMoreAboutData": "Узнать больше о сборе данных"
|
||||
},
|
||||
"systemLocations": "Системные места",
|
||||
"unhandledError": "Неизвестная ошибка"
|
||||
"unhandledError": "Неизвестная ошибка",
|
||||
"updateConsent": "Вы ранее согласились на отчетность об ошибках. Теперь мы отслеживаем событийные метрики, чтобы помочь выявить ошибки и улучшить приложение. Личная идентифицируемая информация не собирается."
|
||||
},
|
||||
"issueReport": {
|
||||
"contactFollowUp": "Свяжитесь со мной для уточнения",
|
||||
|
||||
@@ -113,7 +113,7 @@
|
||||
}
|
||||
},
|
||||
"CLIPLoader": {
|
||||
"description": "[Рецепты]\n\nstable_diffusion: clip-l\nstable_cascade: clip-g\nsd3: t5 / clip-g / clip-l\nstable_audio: t5\nmochi: t5",
|
||||
"description": "[Рецепты]\n\nstable_diffusion: clip-l\nstable_cascade: clip-g\nsd3: t5 / clip-g / clip-l\nstable_audio: t5\nmochi: t5\ncosmos: old t5 xxl",
|
||||
"display_name": "Загрузить CLIP",
|
||||
"inputs": {
|
||||
"clip_name": {
|
||||
@@ -862,6 +862,32 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"CosmosImageToVideoLatent": {
|
||||
"display_name": "CosmosImageToVideoLatent",
|
||||
"inputs": {
|
||||
"batch_size": {
|
||||
"name": "размер_пакета"
|
||||
},
|
||||
"end_image": {
|
||||
"name": "конечное_изображение"
|
||||
},
|
||||
"height": {
|
||||
"name": "высота"
|
||||
},
|
||||
"length": {
|
||||
"name": "длина"
|
||||
},
|
||||
"start_image": {
|
||||
"name": "начальное_изображение"
|
||||
},
|
||||
"vae": {
|
||||
"name": "vae"
|
||||
},
|
||||
"width": {
|
||||
"name": "ширина"
|
||||
}
|
||||
}
|
||||
},
|
||||
"CreateHookKeyframe": {
|
||||
"display_name": "Создать ключевой кадр хука",
|
||||
"inputs": {
|
||||
@@ -1230,6 +1256,23 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"EmptyCosmosLatentVideo": {
|
||||
"display_name": "EmptyCosmosLatentVideo",
|
||||
"inputs": {
|
||||
"batch_size": {
|
||||
"name": "размер_пакета"
|
||||
},
|
||||
"height": {
|
||||
"name": "высота"
|
||||
},
|
||||
"length": {
|
||||
"name": "длина"
|
||||
},
|
||||
"width": {
|
||||
"name": "ширина"
|
||||
}
|
||||
}
|
||||
},
|
||||
"EmptyHunyuanLatentVideo": {
|
||||
"display_name": "ПустойHunyuanLatentVideo",
|
||||
"inputs": {
|
||||
@@ -4825,6 +4868,17 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"SetFirstSigma": {
|
||||
"display_name": "SetFirstSigma",
|
||||
"inputs": {
|
||||
"sigma": {
|
||||
"name": "сигма"
|
||||
},
|
||||
"sigmas": {
|
||||
"name": "сигмы"
|
||||
}
|
||||
}
|
||||
},
|
||||
"SetHookKeyframes": {
|
||||
"display_name": "Установить ключевые кадры хука",
|
||||
"inputs": {
|
||||
|
||||
@@ -107,6 +107,7 @@
|
||||
"noTasksFound": "未找到任务",
|
||||
"noTasksFoundMessage": "队列中没有任务。",
|
||||
"noWorkflowsFound": "未找到工作流。",
|
||||
"ok": "确定",
|
||||
"openNewIssue": "打开新问题",
|
||||
"overwrite": "覆盖",
|
||||
"reconnected": "已重新连接",
|
||||
@@ -129,6 +130,7 @@
|
||||
"searchWorkflows": "搜索工作流",
|
||||
"settings": "设置",
|
||||
"showReport": "显示报告",
|
||||
"success": "成功",
|
||||
"systemInfo": "系统信息",
|
||||
"terminal": "终端",
|
||||
"upload": "上传",
|
||||
@@ -186,6 +188,7 @@
|
||||
"selectGpu": "选择 GPU",
|
||||
"selectGpuDescription": "选择你拥有的 GPU 类型"
|
||||
},
|
||||
"helpImprove": "请帮助我们改进ComfyUI",
|
||||
"installLocation": "安装位置",
|
||||
"installLocationDescription": "选择 ComfyUI 用户数据的存放目录。将安装一个 Python 环境到所选位置。请确保所选磁盘有足够的空间(约 15GB)。",
|
||||
"installLocationTooltip": "ComfyUI 的用户数据目录。存储:\n- Python 环境\n- 模型\n- 自定义节点\n",
|
||||
@@ -197,13 +200,17 @@
|
||||
"title": "手动配置",
|
||||
"virtualEnvironmentPath": "虚拟环境路径"
|
||||
},
|
||||
"metricsDisabled": "禁用度量",
|
||||
"metricsEnabled": "启用度量",
|
||||
"migrateFromExistingInstallation": "从现有安装迁移",
|
||||
"migration": "迁移",
|
||||
"migrationOptional": "迁移是可选的。如果您之前没有安装过 ComfyUI,可以跳过此步骤。",
|
||||
"migrationSourcePathDescription": "如果您有可用的 ComfyUI,我们可以将您的现有用户文件和模型复制/链接到新安装。",
|
||||
"migrationSourcePathDescription": "如果您已有现有的ComfyUI安装,我们可以复制/链接您现有的用户文件和模型到新的安装。您现有的ComfyUI安装将不会受到影响。",
|
||||
"moreInfo": "有关更多信息,请阅读我们的",
|
||||
"parentMissing": "路径不存在 - 请先创建包含该路径的目录",
|
||||
"pathExists": "目录已存在 - 请确保您已备份全部数据",
|
||||
"pathValidationFailed": "路径验证失败",
|
||||
"privacyPolicy": "隐私政策",
|
||||
"selectItemsToMigrate": "选择要迁移的项目",
|
||||
"settings": {
|
||||
"allowMetrics": "使用情况指标",
|
||||
@@ -214,8 +221,7 @@
|
||||
"collect": {
|
||||
"errorReports": "错误报告和堆栈跟踪",
|
||||
"systemInfo": "硬件,操作系统类型和应用版本",
|
||||
"userJourneyEvents": "用户旅程事件",
|
||||
"userJourneyTooltip": "用户旅程事件用于跟踪用户通过应用安装过程的旅程。事件收集在第一次成功运行ComfyUI工作流后结束。"
|
||||
"userJourneyEvents": "用户旅程事件"
|
||||
},
|
||||
"doNotCollect": {
|
||||
"customNodeConfigurations": "自定义节点配置",
|
||||
@@ -224,13 +230,17 @@
|
||||
"workflowContents": "工作流内容"
|
||||
},
|
||||
"title": "关于数据收集",
|
||||
"viewFullPolicy": "查看完整政策",
|
||||
"whatWeCollect": "我们收集的内容:",
|
||||
"whatWeDoNotCollect": "我们不收集的内容:"
|
||||
},
|
||||
"errorUpdatingConsent": "更新同意错误",
|
||||
"errorUpdatingConsentDetail": "无法更新度量同意设置",
|
||||
"learnMoreAboutData": "了解更多关于数据收集的信息"
|
||||
},
|
||||
"systemLocations": "系统位置",
|
||||
"unhandledError": "未知错误"
|
||||
"unhandledError": "未知错误",
|
||||
"updateConsent": "您之前选择了报告崩溃。我们现在正在跟踪基于事件的度量,以帮助识别错误并改进应用程序。我们不收集任何个人可识别信息。"
|
||||
},
|
||||
"issueReport": {
|
||||
"contactFollowUp": "跟进联系我",
|
||||
|
||||
@@ -113,7 +113,7 @@
|
||||
}
|
||||
},
|
||||
"CLIPLoader": {
|
||||
"description": "[配方]\n\nStable Diffusion:clip-l\nStable Cascade:clip-g\nSD3:t5 / clip-g / clip-l\nStable Audio:t5\nMochi:t5",
|
||||
"description": "[配方]\n\nStable Diffusion:clip-l\nStable Cascade:clip-g\nSD3:t5 / clip-g / clip-l\nStable Audio:t5\nMochi:t5\ncosmos:old t5 xxl",
|
||||
"display_name": "加载CLIP",
|
||||
"inputs": {
|
||||
"clip_name": {
|
||||
@@ -862,6 +862,32 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"CosmosImageToVideoLatent": {
|
||||
"display_name": "Cosmos图像到视频潜在",
|
||||
"inputs": {
|
||||
"batch_size": {
|
||||
"name": "批量大小"
|
||||
},
|
||||
"end_image": {
|
||||
"name": "结束图像"
|
||||
},
|
||||
"height": {
|
||||
"name": "高度"
|
||||
},
|
||||
"length": {
|
||||
"name": "长度"
|
||||
},
|
||||
"start_image": {
|
||||
"name": "开始图像"
|
||||
},
|
||||
"vae": {
|
||||
"name": "vae"
|
||||
},
|
||||
"width": {
|
||||
"name": "宽度"
|
||||
}
|
||||
}
|
||||
},
|
||||
"CreateHookKeyframe": {
|
||||
"display_name": "创建约束关键帧",
|
||||
"inputs": {
|
||||
@@ -1230,6 +1256,23 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"EmptyCosmosLatentVideo": {
|
||||
"display_name": "空的Cosmos潜在视频",
|
||||
"inputs": {
|
||||
"batch_size": {
|
||||
"name": "批量大小"
|
||||
},
|
||||
"height": {
|
||||
"name": "高度"
|
||||
},
|
||||
"length": {
|
||||
"name": "长度"
|
||||
},
|
||||
"width": {
|
||||
"name": "宽度"
|
||||
}
|
||||
}
|
||||
},
|
||||
"EmptyHunyuanLatentVideo": {
|
||||
"display_name": "空Latent视频(混元)",
|
||||
"inputs": {
|
||||
@@ -4825,6 +4868,17 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"SetFirstSigma": {
|
||||
"display_name": "设置第一个Sigma",
|
||||
"inputs": {
|
||||
"sigma": {
|
||||
"name": "sigma"
|
||||
},
|
||||
"sigmas": {
|
||||
"name": "sigmas"
|
||||
}
|
||||
}
|
||||
},
|
||||
"SetHookKeyframes": {
|
||||
"display_name": "设置约束关键帧",
|
||||
"inputs": {
|
||||
|
||||
@@ -92,6 +92,18 @@ const router = createRouter({
|
||||
name: 'ManualConfigurationView',
|
||||
component: () => import('@/views/ManualConfigurationView.vue'),
|
||||
beforeEnter: guardElectronAccess
|
||||
},
|
||||
{
|
||||
path: '/metrics-consent',
|
||||
name: 'MetricsConsentView',
|
||||
component: () => import('@/views/MetricsConsentView.vue'),
|
||||
beforeEnter: guardElectronAccess
|
||||
},
|
||||
{
|
||||
path: 'desktop-start',
|
||||
name: 'DesktopStartView',
|
||||
component: () => import('@/views/DesktopStartView.vue'),
|
||||
beforeEnter: guardElectronAccess
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -417,6 +417,12 @@ LGraphNode.prototype.addDOMWidget = function <
|
||||
element.dataset.collapsed = this.flags?.collapsed ? 'true' : 'false'
|
||||
}
|
||||
|
||||
const { onConfigure } = this
|
||||
this.onConfigure = function () {
|
||||
onConfigure?.apply(this, arguments)
|
||||
element.dataset.collapsed = this.flags?.collapsed ? 'true' : 'false'
|
||||
}
|
||||
|
||||
const onRemoved = this.onRemoved
|
||||
this.onRemoved = function () {
|
||||
element.remove()
|
||||
|
||||
@@ -3,6 +3,8 @@ import {
|
||||
ElectronContextMenuOptions
|
||||
} from '@comfyorg/comfyui-electron-types'
|
||||
|
||||
import { useSystemStatsStore } from '@/stores/systemStatsStore'
|
||||
|
||||
export function isElectron() {
|
||||
return 'electronAPI' in window && window.electronAPI !== undefined
|
||||
}
|
||||
@@ -14,3 +16,34 @@ export function electronAPI() {
|
||||
export function showNativeMenu(options?: ElectronContextMenuOptions) {
|
||||
electronAPI()?.showContextMenu(options)
|
||||
}
|
||||
|
||||
const normalizeVersion = (version: string) => {
|
||||
return version
|
||||
.split('.')
|
||||
.map(Number)
|
||||
.filter((n): n is number => !Number.isNaN(n))
|
||||
}
|
||||
|
||||
export function isVersionLessThan(versionA: string, versionB: string) {
|
||||
versionA ??= '0.0.0'
|
||||
versionB ??= '0.0.0'
|
||||
|
||||
const normalizedA = normalizeVersion(versionA)
|
||||
const normalizedB = normalizeVersion(versionB)
|
||||
|
||||
for (let i = 0; i < Math.max(normalizedA.length, normalizedB.length); i++) {
|
||||
const a = normalizedA[i] ?? 0
|
||||
const b = normalizedB[i] ?? 0
|
||||
if (a < b) return true
|
||||
if (a > b) return false
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
export function getComfyVersion() {
|
||||
if (isElectron()) return electronAPI().getComfyUIVersion()
|
||||
const store = useSystemStatsStore()
|
||||
store.fetchSystemStats()
|
||||
return store.systemStats?.system?.comfyui_version ?? ''
|
||||
}
|
||||
|
||||
13
src/views/DesktopStartView.vue
Normal file
13
src/views/DesktopStartView.vue
Normal file
@@ -0,0 +1,13 @@
|
||||
<template>
|
||||
<BaseViewTemplate dark>
|
||||
<div class="max-w-screen-sm w-screen p-8">
|
||||
<ProgressBar mode="indeterminate" />
|
||||
</div>
|
||||
</BaseViewTemplate>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import ProgressBar from 'primevue/progressbar'
|
||||
|
||||
import BaseViewTemplate from './templates/BaseViewTemplate.vue'
|
||||
</script>
|
||||
@@ -55,6 +55,7 @@ const toast = useToast()
|
||||
const settingStore = useSettingStore()
|
||||
const executionStore = useExecutionStore()
|
||||
const colorPaletteStore = useColorPaletteStore()
|
||||
const queueStore = useQueueStore()
|
||||
|
||||
watch(
|
||||
() => colorPaletteStore.completedActivePalette,
|
||||
@@ -76,6 +77,29 @@ watch(
|
||||
{ immediate: true }
|
||||
)
|
||||
|
||||
if (isElectron()) {
|
||||
watch(
|
||||
() => queueStore.tasks,
|
||||
(newTasks, oldTasks) => {
|
||||
// Report tasks that previously running but are now completed (i.e. in history)
|
||||
const oldRunningTaskIds = new Set(
|
||||
oldTasks.filter((task) => task.isRunning).map((task) => task.promptId)
|
||||
)
|
||||
newTasks
|
||||
.filter(
|
||||
(task) => oldRunningTaskIds.has(task.promptId) && task.isHistory
|
||||
)
|
||||
.forEach((task) => {
|
||||
electronAPI().Events.incrementUserProperty(
|
||||
`execution:${task.displayStatus.toLowerCase()}`,
|
||||
1
|
||||
)
|
||||
})
|
||||
},
|
||||
{ deep: true }
|
||||
)
|
||||
}
|
||||
|
||||
watchEffect(() => {
|
||||
const fontSize = settingStore.get('Comfy.TextareaWidget.FontSize')
|
||||
document.documentElement.style.setProperty(
|
||||
@@ -110,9 +134,7 @@ watchEffect(() => {
|
||||
})
|
||||
|
||||
watchEffect(() => {
|
||||
useQueueStore().maxHistoryItems = settingStore.get(
|
||||
'Comfy.Queue.MaxHistoryItems'
|
||||
)
|
||||
queueStore.maxHistoryItems = settingStore.get('Comfy.Queue.MaxHistoryItems')
|
||||
})
|
||||
|
||||
const init = () => {
|
||||
@@ -126,8 +148,9 @@ const init = () => {
|
||||
}
|
||||
|
||||
const queuePendingTaskCountStore = useQueuePendingTaskCountStore()
|
||||
const onStatus = (e: CustomEvent<StatusWsMessageStatus>) => {
|
||||
const onStatus = async (e: CustomEvent<StatusWsMessageStatus>) => {
|
||||
queuePendingTaskCountStore.update(e)
|
||||
await queueStore.update()
|
||||
}
|
||||
|
||||
const reconnectingMessage: ToastMessageOptions = {
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
<Stepper
|
||||
class="h-full p-8 2xl:p-16"
|
||||
value="0"
|
||||
@update:value="setHighestStep"
|
||||
@update:value="handleStepChange"
|
||||
>
|
||||
<StepList class="select-none">
|
||||
<Step value="0">
|
||||
@@ -137,6 +137,14 @@ const allowMetrics = ref(true)
|
||||
/** Forces each install step to be visited at least once. */
|
||||
const highestStep = ref(0)
|
||||
|
||||
const handleStepChange = (value: string | number) => {
|
||||
setHighestStep(value)
|
||||
|
||||
electronAPI().Events.trackEvent('install_stepper_change', {
|
||||
step: value
|
||||
})
|
||||
}
|
||||
|
||||
const setHighestStep = (value: string | number) => {
|
||||
const int = typeof value === 'number' ? value : parseInt(value, 10)
|
||||
if (!isNaN(int) && int > highestStep.value) highestStep.value = int
|
||||
@@ -167,12 +175,18 @@ onMounted(async () => {
|
||||
if (!electron) return
|
||||
|
||||
const detectedGpu = await electron.Config.getDetectedGpu()
|
||||
if (detectedGpu === 'mps' || detectedGpu === 'nvidia')
|
||||
if (detectedGpu === 'mps' || detectedGpu === 'nvidia') {
|
||||
device.value = detectedGpu
|
||||
}
|
||||
|
||||
electronAPI().Events.trackEvent('install_stepper_change', {
|
||||
step: '0',
|
||||
gpu: detectedGpu
|
||||
})
|
||||
})
|
||||
</script>
|
||||
|
||||
<style lang="postcss" scoped>
|
||||
<style scoped>
|
||||
:deep(.p-steppanel) {
|
||||
@apply bg-transparent;
|
||||
}
|
||||
|
||||
@@ -75,8 +75,8 @@ onMounted(async () => {
|
||||
})
|
||||
</script>
|
||||
|
||||
<style>
|
||||
:root {
|
||||
<style scoped>
|
||||
.p-tag {
|
||||
--p-tag-gap: 0.5rem;
|
||||
}
|
||||
|
||||
|
||||
83
src/views/MetricsConsentView.vue
Normal file
83
src/views/MetricsConsentView.vue
Normal file
@@ -0,0 +1,83 @@
|
||||
<template>
|
||||
<BaseViewTemplate dark>
|
||||
<div class="h-full p-8 2xl:p-16 flex flex-col items-center justify-center">
|
||||
<div
|
||||
class="bg-neutral-800 rounded-lg shadow-lg p-6 w-full max-w-[600px] flex flex-col gap-6"
|
||||
>
|
||||
<h2 class="text-3xl font-semibold text-neutral-100">
|
||||
{{ $t('install.helpImprove') }}
|
||||
</h2>
|
||||
<p class="text-neutral-400">
|
||||
{{ $t('install.updateConsent') }}
|
||||
</p>
|
||||
<p class="text-neutral-400">
|
||||
{{ $t('install.moreInfo') }}
|
||||
<a
|
||||
href="https://comfy.org/privacy"
|
||||
target="_blank"
|
||||
class="text-blue-400 hover:text-blue-300 underline"
|
||||
>
|
||||
{{ $t('install.privacyPolicy') }} </a
|
||||
>.
|
||||
</p>
|
||||
<div class="flex items-center gap-4">
|
||||
<ToggleSwitch
|
||||
v-model="allowMetrics"
|
||||
aria-describedby="metricsDescription"
|
||||
/>
|
||||
<span id="metricsDescription" class="text-neutral-100">
|
||||
{{
|
||||
allowMetrics
|
||||
? $t('install.metricsEnabled')
|
||||
: $t('install.metricsDisabled')
|
||||
}}
|
||||
</span>
|
||||
</div>
|
||||
<div class="flex pt-6 justify-end">
|
||||
<Button
|
||||
:label="$t('g.ok')"
|
||||
icon="pi pi-check"
|
||||
:loading="isUpdating"
|
||||
iconPos="right"
|
||||
@click="updateConsent"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</BaseViewTemplate>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import Button from 'primevue/button'
|
||||
import ToggleSwitch from 'primevue/toggleswitch'
|
||||
import { useToast } from 'primevue/usetoast'
|
||||
import { ref } from 'vue'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
import { useRouter } from 'vue-router'
|
||||
|
||||
import { electronAPI } from '@/utils/envUtil'
|
||||
|
||||
const toast = useToast()
|
||||
const { t } = useI18n()
|
||||
|
||||
const allowMetrics = ref(true)
|
||||
const router = useRouter()
|
||||
const isUpdating = ref(false)
|
||||
|
||||
const updateConsent = async () => {
|
||||
isUpdating.value = true
|
||||
try {
|
||||
await electronAPI().setMetricsConsent(allowMetrics.value)
|
||||
} catch (error) {
|
||||
toast.add({
|
||||
severity: 'error',
|
||||
summary: t('install.errorUpdatingConsent'),
|
||||
detail: t('install.errorUpdatingConsentDetail'),
|
||||
life: 3000
|
||||
})
|
||||
} finally {
|
||||
isUpdating.value = false
|
||||
}
|
||||
router.push('/')
|
||||
}
|
||||
</script>
|
||||
@@ -78,7 +78,7 @@ const continueToInstall = () => {
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
<style scoped>
|
||||
.sad-container {
|
||||
@apply grid items-center justify-evenly;
|
||||
grid-template-columns: 25rem 1fr;
|
||||
|
||||
@@ -78,7 +78,7 @@ const terminalCreated = (
|
||||
) => {
|
||||
xterm = terminal
|
||||
|
||||
useAutoSize(root, true, true)
|
||||
useAutoSize({ root, autoRows: true, autoCols: true })
|
||||
electron.onLogMessage((message: string) => {
|
||||
terminal.write(message)
|
||||
})
|
||||
|
||||
@@ -28,7 +28,7 @@ import { electronAPI, isElectron } from '@/utils/envUtil'
|
||||
|
||||
const props = withDefaults(
|
||||
defineProps<{
|
||||
dark: boolean
|
||||
dark?: boolean
|
||||
}>(),
|
||||
{
|
||||
dark: false
|
||||
|
||||
@@ -57,8 +57,18 @@ const mockElectronAPI: Plugin = {
|
||||
changeTheme: () => {},
|
||||
Config: {
|
||||
setWindowStyle: () => {},
|
||||
getWindowStyle: () => Promise.resolve('default')
|
||||
}
|
||||
getWindowStyle: () => Promise.resolve('default'),
|
||||
getDetectedGpu: () => Promise.resolve('nvidia')
|
||||
},
|
||||
Events: {
|
||||
trackEvent: (event_name, event_data) => {
|
||||
console.log('trackEvent', event_name, event_data)
|
||||
},
|
||||
incrementUserProperty: (property, value) => {
|
||||
console.log('incrementUserProperty', property, value)
|
||||
}
|
||||
},
|
||||
setMetricsConsent: (consent) => {}
|
||||
};`
|
||||
}
|
||||
]
|
||||
|
||||
Reference in New Issue
Block a user