Compare commits

...

22 Commits

Author SHA1 Message Date
snomiao
aa2fa05887 Add dependency-cruiser configuration and graph
- Add dependency-cruiser config for analyzing dependencies
- Generate dependency graph visualization
- Update package dependencies

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-09-15 09:43:02 +00:00
snomiao
883400ec77 fix-vue-tsc 2025-09-15 08:15:48 +00:00
snomiao
5d082b7f37 refactor litegraph to solve circular dep 2025-09-15 08:01:39 +00:00
snomiao
768e49bfdd Merge branch 'main' into sno-fix-playwright-babel-config 2025-09-15 06:58:58 +00:00
snomiao
5b034a97bf fix(.gitignore): update core dump entry to remove leading dot for proper ignoring 2025-09-13 17:15:52 +00:00
snomiao
a9a17cc5c8 fix(api.ts): correct globalThis reference for location to ensure compatibility across environments 2025-09-13 17:15:34 +00:00
snomiao
40a13ea1cf fix(api.ts): correct globalThis reference for location to ensure compatibility across environments 2025-09-13 17:10:37 +00:00
snomiao
414935594c chore: update import statements to use 'type' for type-only imports for better clarity and performance
refactor(collect-i18n-node-defs): clean up comments for clarity on API endpoint behavior
2025-09-13 14:41:40 +00:00
snomiao
7d28bb6919 [refactor] Add type imports across codebase for verbatim module syntax
- Update all Vue components to use type imports
- Update all TypeScript files to use type imports
- Update test files to use type imports
- Ensure compliance with TypeScript verbatim module syntax

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-09-13 14:12:33 +00:00
snomiao
84fe17e7da [fix] Enable verbatim module syntax in TypeScript configuration 2025-09-13 13:18:04 +00:00
snomiao
f4c157d3c8 restore 2025-09-13 11:49:30 +00:00
snomiao
76bd481666 Merge branch 'sno-fix-playwright-babel-config' of github.com:Comfy-Org/ComfyUI_frontend into sno-fix-playwright-babel-config 2025-09-13 10:52:27 +00:00
snomiao
74af367810 no-mock-object_info 2025-09-13 10:46:55 +00:00
GitHub Action
35e56a441c [auto-fix] Apply ESLint and Prettier fixes 2025-09-13 10:27:34 +00:00
snomiao
0ae6e26052 [fix] Update Playwright and knip configurations
- Fix ComfyPage imports and exports in browser tests
- Update knip config to properly handle Playwright fixtures

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-09-13 09:47:58 +00:00
snomiao
7306c6f04f fix: Improve i18n collection script setup
- Move setup-browser-globals import to top to fix location undefined error
- Skip user setup for i18n tests to avoid duplicate user conflicts
- Run i18n tests serially with workers=1 to prevent race conditions
- Add unique test-based usernames for better test isolation
2025-09-13 09:24:20 +00:00
snomiao
ead43312f8 feat: Add Happy DOM location mocking for Playwright tests
- Enhanced setup-browser-globals.js with configurable URL and full location mock
- Created LocationMock helper class for dynamic location mocking in tests
- Integrated LocationMock into ComfyPage fixture with optional setup
- Added example test file demonstrating location mock usage
- Support for mocking location.assign, location.replace, and location.reload methods
2025-09-13 09:14:55 +00:00
snomiao
29d22454f4 Merge branch 'main' into sno-fix-playwright-babel-config 2025-09-13 18:09:53 +09:00
snomiao
f697717b4d feat(collect-i18n-node-defs): add mock for object_info API endpoint to allow script execution without backend
fix(collect-i18n-node-defs): create empty locale files if no node definitions are collected to prevent build failures
2025-09-13 07:48:52 +00:00
snomiao
4ea2987502 fix: Convert babel plugin to CommonJS format for Playwright compatibility
- Renamed babel-plugin-stub-vue-imports.js to .cjs extension
- Changed from ES module exports to CommonJS module.exports
- Updated playwright.i18n.config.ts to use correct file path with __dirname
- Added import.meta.url handling for ES module compatibility

This fixes the module resolution errors when running pnpm collect-i18n
2025-09-12 08:47:43 +00:00
snomiao
6c5f17a0aa chore(i18n.yaml): update job condition to include sno-fix-playwright- branches for locale updates 2025-09-12 08:26:50 +00:00
snomiao
540b6f3d26 fix: Add babel configuration for Playwright to handle TypeScript declare fields
- Configure babel plugins for TypeScript with allowDeclareFields option
- Add module resolver for @ alias to src directory
- Create custom babel plugin to stub Vue/CSS imports
- Add browser globals polyfill using happy-dom for Node.js context
- Update playwright.i18n.config.ts with babel configuration

This enables collect-i18n tests to run with proper TypeScript and module transformations.
2025-09-12 08:16:37 +00:00
245 changed files with 46473 additions and 1205 deletions

395
.dependency-cruiser.cjs Normal file
View File

@@ -0,0 +1,395 @@
/** @type {import('dependency-cruiser').IConfiguration} */
module.exports = {
forbidden: [
{
name: 'no-circular',
severity: 'warn',
comment:
'This dependency is part of a circular relationship. You might want to revise ' +
'your solution (i.e. use dependency inversion, make sure the modules have a single responsibility) ',
from: {},
to: {
circular: true
}
},
{
name: 'no-orphans',
comment:
"This is an orphan module - it's likely not used (anymore?). Either use it or " +
"remove it. If it's logical this module is an orphan (i.e. it's a config file), " +
"add an exception for it in your dependency-cruiser configuration. By default " +
"this rule does not scrutinize dot-files (e.g. .eslintrc.js), TypeScript declaration " +
"files (.d.ts), tsconfig.json and some of the babel and webpack configs.",
severity: 'warn',
from: {
orphan: true,
pathNot: [
'(^|/)[.][^/]+[.](?:js|cjs|mjs|ts|cts|mts|json)$', // dot files
'[.]d[.]ts$', // TypeScript declaration files
'(^|/)tsconfig[.]json$', // TypeScript config
'(^|/)(?:babel|webpack)[.]config[.](?:js|cjs|mjs|ts|cts|mts|json)$' // other configs
]
},
to: {},
},
{
name: 'no-deprecated-core',
comment:
'A module depends on a node core module that has been deprecated. Find an alternative - these are ' +
"bound to exist - node doesn't deprecate lightly.",
severity: 'warn',
from: {},
to: {
dependencyTypes: [
'core'
],
path: [
'^v8/tools/codemap$',
'^v8/tools/consarray$',
'^v8/tools/csvparser$',
'^v8/tools/logreader$',
'^v8/tools/profile_view$',
'^v8/tools/profile$',
'^v8/tools/SourceMap$',
'^v8/tools/splaytree$',
'^v8/tools/tickprocessor-driver$',
'^v8/tools/tickprocessor$',
'^node-inspect/lib/_inspect$',
'^node-inspect/lib/internal/inspect_client$',
'^node-inspect/lib/internal/inspect_repl$',
'^async_hooks$',
'^punycode$',
'^domain$',
'^constants$',
'^sys$',
'^_linklist$',
'^_stream_wrap$'
],
}
},
{
name: 'not-to-deprecated',
comment:
'This module uses a (version of an) npm module that has been deprecated. Either upgrade to a later ' +
'version of that module, or find an alternative. Deprecated modules are a security risk.',
severity: 'warn',
from: {},
to: {
dependencyTypes: [
'deprecated'
]
}
},
{
name: 'no-non-package-json',
severity: 'error',
comment:
"This module depends on an npm package that isn't in the 'dependencies' section of your package.json. " +
"That's problematic as the package either (1) won't be available on live (2 - worse) will be " +
"available on live with an non-guaranteed version. Fix it by adding the package to the dependencies " +
"in your package.json.",
from: {},
to: {
dependencyTypes: [
'npm-no-pkg',
'npm-unknown'
]
}
},
{
name: 'not-to-unresolvable',
comment:
"This module depends on a module that cannot be found ('resolved to disk'). If it's an npm " +
'module: add it to your package.json. In all other cases you likely already know what to do.',
severity: 'error',
from: {},
to: {
couldNotResolve: true
}
},
{
name: 'no-duplicate-dep-types',
comment:
"Likely this module depends on an external ('npm') package that occurs more than once " +
"in your package.json i.e. bot as a devDependencies and in dependencies. This will cause " +
"maintenance problems later on.",
severity: 'warn',
from: {},
to: {
moreThanOneDependencyType: true,
// as it's pretty common to have a type import be a type only import
// _and_ (e.g.) a devDependency - don't consider type-only dependency
// types for this rule
dependencyTypesNot: ["type-only"]
}
},
/* rules you might want to tweak for your specific situation: */
{
name: 'not-to-spec',
comment:
'This module depends on a spec (test) file. The sole responsibility of a spec file is to test code. ' +
"If there's something in a spec that's of use to other modules, it doesn't have that single " +
'responsibility anymore. Factor it out into (e.g.) a separate utility/ helper or a mock.',
severity: 'error',
from: {},
to: {
path: '[.](?:spec|test)[.](?:js|mjs|cjs|jsx|ts|mts|cts|tsx)$'
}
},
{
name: 'not-to-dev-dep',
severity: 'error',
comment:
"This module depends on an npm package from the 'devDependencies' section of your " +
'package.json. It looks like something that ships to production, though. To prevent problems ' +
"with npm packages that aren't there on production declare it (only!) in the 'dependencies'" +
'section of your package.json. If this module is development only - add it to the ' +
'from.pathNot re of the not-to-dev-dep rule in the dependency-cruiser configuration',
from: {
path: '^(src)',
pathNot: '[.](?:spec|test)[.](?:js|mjs|cjs|jsx|ts|mts|cts|tsx)$'
},
to: {
dependencyTypes: [
'npm-dev',
],
// type only dependencies are not a problem as they don't end up in the
// production code or are ignored by the runtime.
dependencyTypesNot: [
'type-only'
],
pathNot: [
'node_modules/@types/'
]
}
},
{
name: 'optional-deps-used',
severity: 'info',
comment:
"This module depends on an npm package that is declared as an optional dependency " +
"in your package.json. As this makes sense in limited situations only, it's flagged here. " +
"If you're using an optional dependency here by design - add an exception to your" +
"dependency-cruiser configuration.",
from: {},
to: {
dependencyTypes: [
'npm-optional'
]
}
},
{
name: 'peer-deps-used',
comment:
"This module depends on an npm package that is declared as a peer dependency " +
"in your package.json. This makes sense if your package is e.g. a plugin, but in " +
"other cases - maybe not so much. If the use of a peer dependency is intentional " +
"add an exception to your dependency-cruiser configuration.",
severity: 'warn',
from: {},
to: {
dependencyTypes: [
'npm-peer'
]
}
}
],
options: {
/* Which modules not to follow further when encountered */
doNotFollow: {
/* path: an array of regular expressions in strings to match against */
path: ['node_modules']
},
/* Which modules to exclude */
// exclude : {
// /* path: an array of regular expressions in strings to match against */
// path: '',
// },
/* Which modules to exclusively include (array of regular expressions in strings)
dependency-cruiser will skip everything not matching this pattern
*/
// includeOnly : [''],
/* List of module systems to cruise.
When left out dependency-cruiser will fall back to the list of _all_
module systems it knows of. It's the default because it's the safe option
It might come at a performance penalty, though.
moduleSystems: ['amd', 'cjs', 'es6', 'tsd']
As in practice only commonjs ('cjs') and ecmascript modules ('es6')
are widely used, you can limit the moduleSystems to those.
*/
// moduleSystems: ['cjs', 'es6'],
/*
false: don't look at JSDoc imports (the default)
true: dependency-cruiser will detect dependencies in JSDoc-style
import statements. Implies "parser": "tsc", so the dependency-cruiser
will use the typescript parser for JavaScript files.
For this to work the typescript compiler will need to be installed in the
same spot as you're running dependency-cruiser from.
*/
// detectJSDocImports: true,
/* prefix for links in html and svg output (e.g. 'https://github.com/you/yourrepo/blob/main/'
to open it on your online repo or `vscode://file/${process.cwd()}/` to
open it in visual studio code),
*/
// prefix: `vscode://file/${process.cwd()}/`,
/* false (the default): ignore dependencies that only exist before typescript-to-javascript compilation
true: also detect dependencies that only exist before typescript-to-javascript compilation
"specify": for each dependency identify whether it only exists before compilation or also after
*/
tsPreCompilationDeps: true,
/* list of extensions to scan that aren't javascript or compile-to-javascript.
Empty by default. Only put extensions in here that you want to take into
account that are _not_ parsable.
*/
// extraExtensionsToScan: [".json", ".jpg", ".png", ".svg", ".webp"],
/* if true combines the package.jsons found from the module up to the base
folder the cruise is initiated from. Useful for how (some) mono-repos
manage dependencies & dependency definitions.
*/
// combinedDependencies: false,
/* if true leave symlinks untouched, otherwise use the realpath */
// preserveSymlinks: false,
/* TypeScript project file ('tsconfig.json') to use for
(1) compilation and
(2) resolution (e.g. with the paths property)
The (optional) fileName attribute specifies which file to take (relative to
dependency-cruiser's current working directory). When not provided
defaults to './tsconfig.json'.
*/
tsConfig: {
fileName: 'tsconfig.json'
},
/* Webpack configuration to use to get resolve options from.
The (optional) fileName attribute specifies which file to take (relative
to dependency-cruiser's current working directory. When not provided defaults
to './webpack.conf.js'.
The (optional) `env` and `arguments` attributes contain the parameters
to be passed if your webpack config is a function and takes them (see
webpack documentation for details)
*/
// webpackConfig: {
// fileName: 'webpack.config.js',
// env: {},
// arguments: {}
// },
/* Babel config ('.babelrc', '.babelrc.json', '.babelrc.json5', ...) to use
for compilation
*/
// babelConfig: {
// fileName: '.babelrc',
// },
/* List of strings you have in use in addition to cjs/ es6 requires
& imports to declare module dependencies. Use this e.g. if you've
re-declared require, use a require-wrapper or use window.require as
a hack.
*/
// exoticRequireStrings: [],
/* options to pass on to enhanced-resolve, the package dependency-cruiser
uses to resolve module references to disk. The values below should be
suitable for most situations
If you use webpack: you can also set these in webpack.conf.js. The set
there will override the ones specified here.
*/
enhancedResolveOptions: {
/* What to consider as an 'exports' field in package.jsons */
exportsFields: ["exports"],
/* List of conditions to check for in the exports field.
Only works when the 'exportsFields' array is non-empty.
*/
conditionNames: ["import", "require", "node", "default", "types"],
/* The extensions, by default are the same as the ones dependency-cruiser
can access (run `npx depcruise --info` to see which ones that are in
_your_ environment). If that list is larger than you need you can pass
the extensions you actually use (e.g. [".js", ".jsx"]). This can speed
up module resolution, which is the most expensive step.
*/
// extensions: [".js", ".jsx", ".ts", ".tsx", ".d.ts"],
/* What to consider a 'main' field in package.json */
mainFields: ["module", "main", "types", "typings"],
/* A list of alias fields in package.jsons
See [this specification](https://github.com/defunctzombie/package-browser-field-spec) and
the webpack [resolve.alias](https://webpack.js.org/configuration/resolve/#resolvealiasfields)
documentation.
Defaults to an empty array (= don't use alias fields).
*/
// aliasFields: ["browser"],
},
/* skipAnalysisNotInRules will make dependency-cruiser execute
analysis strictly necessary for checking the rule set only.
See https://github.com/sverweij/dependency-cruiser/blob/main/doc/options-reference.md#skipanalysisnotinrules
for details
*/
skipAnalysisNotInRules: true,
reporterOptions: {
dot: {
/* pattern of modules that can be consolidated in the detailed
graphical dependency graph. The default pattern in this configuration
collapses everything in node_modules to one folder deep so you see
the external modules, but their innards.
*/
collapsePattern: 'node_modules/(?:@[^/]+/[^/]+|[^/]+)',
/* Options to tweak the appearance of your graph.See
https://github.com/sverweij/dependency-cruiser/blob/main/doc/options-reference.md#reporteroptions
for details and some examples. If you don't specify a theme
dependency-cruiser falls back to a built-in one.
*/
// theme: {
// graph: {
// /* splines: "ortho" gives straight lines, but is slow on big graphs
// splines: "true" gives bezier curves (fast, not as nice as ortho)
// */
// splines: "true"
// },
// }
},
archi: {
/* pattern of modules that can be consolidated in the high level
graphical dependency graph. If you use the high level graphical
dependency graph reporter (`archi`) you probably want to tweak
this collapsePattern to your situation.
*/
collapsePattern: '^(?:packages|src|lib(s?)|app(s?)|bin|test(s?)|spec(s?))/[^/]+|node_modules/(?:@[^/]+/[^/]+|[^/]+)',
/* Options to tweak the appearance of your graph. If you don't specify a
theme for 'archi' dependency-cruiser will use the one specified in the
dot section above and otherwise use the default one.
*/
// theme: { },
},
"text": {
"highlightFocused": true
},
}
}
};
// generated: dependency-cruiser@17.0.1 on 2025-09-15T09:33:27.618Z

View File

@@ -7,11 +7,10 @@ on:
pull_request:
branches: [ main ]
types: [opened, synchronize, reopened]
jobs:
update-locales:
# Branch detection: Only run for manual dispatch or version-bump-* branches from main repo
if: github.event_name == 'workflow_dispatch' || (github.event.pull_request.head.repo.full_name == github.repository && startsWith(github.head_ref, 'version-bump-'))
if: github.event_name == 'workflow_dispatch' || (github.event.pull_request.head.repo.full_name == github.repository && (startsWith(github.head_ref, 'version-bump-') || startsWith(github.head_ref, 'sno-fix-playwright-')))
runs-on: ubuntu-latest
steps:
- uses: Comfy-Org/ComfyUI_frontend_setup_action@v3

2
.gitignore vendored
View File

@@ -73,7 +73,7 @@ templates_repo/
vite.config.mts.timestamp-*.mjs
# Linux core dumps
./core
core
*storybook.log
storybook-static

View File

@@ -0,0 +1,32 @@
module.exports = function(babel) {
const { types: t } = babel;
return {
visitor: {
ImportDeclaration(path) {
const source = path.node.source.value;
// Handle Vue files
if (source.endsWith('.vue')) {
const specifiers = path.node.specifiers;
if (specifiers.length > 0 && specifiers[0].type === 'ImportDefaultSpecifier') {
const name = specifiers[0].local.name;
// Replace with a variable declaration
path.replaceWith(
t.variableDeclaration('const', [
t.variableDeclarator(
t.identifier(name),
t.objectExpression([])
)
])
);
}
}
// Handle CSS files - just remove the import
else if (source.endsWith('.css') || source.endsWith('.scss') || source.endsWith('.less')) {
path.remove();
}
}
}
};
};

24
babel.config.json Normal file
View File

@@ -0,0 +1,24 @@
{
"presets": [
"@babel/preset-env",
[
"@babel/preset-typescript",
{
"allowDeclareFields": true,
"onlyRemoveTypeImports": true
}
]
],
"plugins": [
[
"babel-plugin-module-resolver",
{
"root": ["./"],
"alias": {
"@": "./src"
}
}
],
"@vue/babel-plugin-jsx"
]
}

View File

@@ -10,6 +10,7 @@ import type { KeyCombo } from '../../src/schemas/keyBindingSchema'
import type { useWorkspaceStore } from '../../src/stores/workspaceStore'
import { NodeBadgeMode } from '../../src/types/nodeSource'
import { ComfyActionbar } from '../helpers/actionbar'
import { LocationMock } from '../helpers/locationMock'
import { ComfyTemplates } from '../helpers/templates'
import { ComfyMouse } from './ComfyMouse'
import { VueNodeHelpers } from './VueNodeHelpers'
@@ -145,6 +146,7 @@ export class ComfyPage {
public readonly templates: ComfyTemplates
public readonly settingDialog: SettingDialog
public readonly confirmDialog: ConfirmDialog
public readonly locationMock: LocationMock
public readonly vueNodes: VueNodeHelpers
/** Worker index to test user ID */
@@ -174,6 +176,7 @@ export class ComfyPage {
this.templates = new ComfyTemplates(page)
this.settingDialog = new SettingDialog(page, this)
this.confirmDialog = new ConfirmDialog(page)
this.locationMock = new LocationMock(page)
this.vueNodes = new VueNodeHelpers(page)
}
@@ -275,11 +278,20 @@ export class ComfyPage {
async setup({
clearStorage = true,
mockReleases = true
mockReleases = true,
mockLocation = false
}: {
clearStorage?: boolean
mockReleases?: boolean
mockLocation?: boolean | Parameters<LocationMock['setupLocationMock']>[0]
} = {}) {
// Setup location mock if requested
if (mockLocation) {
const config =
typeof mockLocation === 'boolean' ? undefined : mockLocation
await this.locationMock.setupLocationMock(config)
}
await this.goto()
// Mock release endpoint to prevent changelog popups
@@ -1636,28 +1648,39 @@ export const comfyPageFixture = base.extend<{
comfyPage: async ({ page, request }, use, testInfo) => {
const comfyPage = new ComfyPage(page, request)
const { parallelIndex } = testInfo
const username = `playwright-test-${parallelIndex}`
const userId = await comfyPage.setupUser(username)
comfyPage.userIds[parallelIndex] = userId
const { parallelIndex, workerIndex, title } = testInfo
// Skip user setup for i18n collection tests
const isI18nTest = testInfo.file?.includes('collect-i18n')
let userId: string | undefined
if (!isI18nTest) {
// Use a combination of workerIndex and test title hash for unique usernames
const testHash = title.replace(/[^a-zA-Z0-9]/g, '').substring(0, 8)
const username = `playwright-test-${workerIndex}-${testHash}`
userId = await comfyPage.setupUser(username)
comfyPage.userIds[parallelIndex] = userId!
}
try {
await comfyPage.setupSettings({
'Comfy.UseNewMenu': 'Disabled',
// Hide canvas menu/info/selection toolbox by default.
'Comfy.Graph.CanvasInfo': false,
'Comfy.Graph.CanvasMenu': false,
'Comfy.Canvas.SelectionToolbox': false,
// Hide all badges by default.
'Comfy.NodeBadge.NodeIdBadgeMode': NodeBadgeMode.None,
'Comfy.NodeBadge.NodeSourceBadgeMode': NodeBadgeMode.None,
// Disable tooltips by default to avoid flakiness.
'Comfy.EnableTooltips': false,
'Comfy.userId': userId,
// Set tutorial completed to true to avoid loading the tutorial workflow.
'Comfy.TutorialCompleted': true,
'Comfy.SnapToGrid.GridSize': testComfySnapToGridGridSize
})
if (!isI18nTest && userId) {
await comfyPage.setupSettings({
'Comfy.UseNewMenu': 'Disabled',
// Hide canvas menu/info/selection toolbox by default.
'Comfy.Graph.CanvasInfo': false,
'Comfy.Graph.CanvasMenu': false,
'Comfy.Canvas.SelectionToolbox': false,
// Hide all badges by default.
'Comfy.NodeBadge.NodeIdBadgeMode': NodeBadgeMode.None,
'Comfy.NodeBadge.NodeSourceBadgeMode': NodeBadgeMode.None,
// Disable tooltips by default to avoid flakiness.
'Comfy.EnableTooltips': false,
'Comfy.userId': userId,
// Set tutorial completed to true to avoid loading the tutorial workflow.
'Comfy.TutorialCompleted': true,
'Comfy.SnapToGrid.GridSize': testComfySnapToGridGridSize
})
}
} catch (e) {
console.error(e)
}
@@ -1676,6 +1699,7 @@ const makeMatcher = function <T>(
type: string
) {
return async function (
this: any,
node: NodeReference,
options?: { timeout?: number; intervals?: number[] }
) {

View File

@@ -0,0 +1,144 @@
import type { Page } from '@playwright/test'
/**
* Mock location object for testing navigation and URL manipulation
*/
export class LocationMock {
constructor(private page: Page) {}
/**
* Mock the location object in the page context
* @param mockConfig Configuration for the mock location
*/
async setupLocationMock(mockConfig?: {
href?: string
origin?: string
pathname?: string
search?: string
hash?: string
hostname?: string
port?: string
protocol?: string
}) {
await this.page.addInitScript((config) => {
const defaultUrl = config?.href || window.location.href
const url = new URL(defaultUrl)
// Create a mock location object
const mockLocation = {
href: config?.href || url.href,
origin: config?.origin || url.origin,
protocol: config?.protocol || url.protocol,
host: url.host,
hostname: config?.hostname || url.hostname,
port: config?.port || url.port,
pathname: config?.pathname || url.pathname,
search: config?.search || url.search,
hash: config?.hash || url.hash,
assign: (newUrl: string) => {
console.log(`[Mock] location.assign called with: ${newUrl}`)
mockLocation.href = newUrl
// Trigger navigation event if needed
window.dispatchEvent(new Event('popstate'))
},
replace: (newUrl: string) => {
console.log(`[Mock] location.replace called with: ${newUrl}`)
mockLocation.href = newUrl
// Trigger navigation event if needed
window.dispatchEvent(new Event('popstate'))
},
reload: () => {
console.log('[Mock] location.reload called')
// Trigger reload event if needed
window.dispatchEvent(new Event('beforeunload'))
},
toString: () => mockLocation.href
}
// Override window.location
Object.defineProperty(window, 'location', {
value: mockLocation,
writable: true,
configurable: true
})
// Also override document.location
Object.defineProperty(document, 'location', {
value: mockLocation,
writable: true,
configurable: true
})
}, mockConfig)
}
/**
* Update the mock location during test execution
*/
async updateLocation(
updates: Partial<{
href: string
pathname: string
search: string
hash: string
}>
) {
await this.page.evaluate((updates) => {
const location = window.location as any
Object.keys(updates).forEach((key) => {
if (location[key] !== undefined) {
location[key] = updates[key as keyof typeof updates]
}
})
}, updates)
}
/**
* Get the current mock location values
*/
async getLocation() {
return await this.page.evaluate(() => {
const loc = window.location
return {
href: loc.href,
origin: loc.origin,
protocol: loc.protocol,
host: loc.host,
hostname: loc.hostname,
port: loc.port,
pathname: loc.pathname,
search: loc.search,
hash: loc.hash
}
})
}
/**
* Simulate navigation to a new URL
*/
async navigateTo(url: string) {
await this.page.evaluate((url) => {
const location = window.location as any
location.assign(url)
}, url)
}
/**
* Simulate location.replace
*/
async replaceTo(url: string) {
await this.page.evaluate((url) => {
const location = window.location as any
location.replace(url)
}, url)
}
/**
* Simulate location.reload
*/
async reload() {
await this.page.evaluate(() => {
const location = window.location as any
location.reload()
})
}
}

View File

@@ -0,0 +1,103 @@
import { expect } from '@playwright/test'
import { comfyPageFixture as test } from './fixtures/ComfyPage'
import { LocationMock } from './helpers/locationMock'
test.describe('Location Mock Example', () => {
test('should mock location object', async ({ page, comfyPage }) => {
const locationMock = new LocationMock(page)
// Setup location mock before navigating to the page
await locationMock.setupLocationMock({
href: 'http://example.com/test',
pathname: '/test',
search: '?query=value',
hash: '#section'
})
// Navigate to your app
await comfyPage.goto()
// Verify the mock is working
const location = await locationMock.getLocation()
expect(location.pathname).toBe('/test')
expect(location.search).toBe('?query=value')
expect(location.hash).toBe('#section')
// Test navigation
await locationMock.navigateTo('http://example.com/new-page')
const newLocation = await locationMock.getLocation()
expect(newLocation.href).toBe('http://example.com/new-page')
// Test updating specific properties
await locationMock.updateLocation({
pathname: '/updated-path',
search: '?new=param'
})
const updatedLocation = await locationMock.getLocation()
expect(updatedLocation.pathname).toBe('/updated-path')
expect(updatedLocation.search).toBe('?new=param')
})
test('should handle location methods', async ({ page, comfyPage }) => {
const locationMock = new LocationMock(page)
await locationMock.setupLocationMock({
href: 'http://localhost:5173/'
})
await comfyPage.goto()
// Test location.assign
await page.evaluate(() => {
window.location.assign('/new-route')
})
// Check console for mock output
const consoleMessages: string[] = []
page.on('console', (msg) => {
if (msg.text().includes('[Mock]')) {
consoleMessages.push(msg.text())
}
})
await locationMock.navigateTo('/another-route')
await locationMock.replaceTo('/replaced-route')
await locationMock.reload()
// Verify mock methods were called
expect(
consoleMessages.some((msg) => msg.includes('location.assign'))
).toBeTruthy()
expect(
consoleMessages.some((msg) => msg.includes('location.replace'))
).toBeTruthy()
expect(
consoleMessages.some((msg) => msg.includes('location.reload'))
).toBeTruthy()
})
test('should work with Happy DOM globals', async ({ page, comfyPage }) => {
// Set environment variable for Happy DOM URL
process.env.HAPPY_DOM_URL = 'http://custom-domain.com/'
const locationMock = new LocationMock(page)
await locationMock.setupLocationMock()
await comfyPage.goto()
// Verify location is mocked correctly
const location = await page.evaluate(() => ({
href: window.location.href,
origin: window.location.origin,
canAssign: typeof window.location.assign === 'function',
canReplace: typeof window.location.replace === 'function',
canReload: typeof window.location.reload === 'function'
}))
expect(location.canAssign).toBeTruthy()
expect(location.canReplace).toBeTruthy()
expect(location.canReload).toBeTruthy()
})
})

View File

@@ -1,5 +1,5 @@
import path from 'path'
import { Plugin } from 'vite'
import { type Plugin } from 'vite'
interface ShimResult {
code: string

View File

@@ -1,7 +1,7 @@
import glob from 'fast-glob'
import fs from 'fs-extra'
import { dirname, join } from 'node:path'
import { HtmlTagDescriptor, Plugin, normalizePath } from 'vite'
import { type HtmlTagDescriptor, type Plugin, normalizePath } from 'vite'
interface ImportMapSource {
name: string

39351
dependency-graph.svg Normal file

File diff suppressed because it is too large Load Diff

After

Width:  |  Height:  |  Size: 4.1 MiB

View File

@@ -18,7 +18,16 @@ const config: KnipConfig = {
'@primeuix/utils',
'@primevue/icons',
// Dev
'@trivago/prettier-plugin-sort-imports'
'@trivago/prettier-plugin-sort-imports',
// Babel dependencies used in playwright.i18n.config.ts
'@babel/plugin-transform-modules-commonjs',
'@babel/plugin-transform-typescript',
'babel-helper-vue-jsx-merge-props',
'babel-plugin-syntax-jsx',
'babel-plugin-transform-import-ignore',
'babel-plugin-transform-vue-jsx',
'babel-preset-env',
'babel-preset-typescript-vue3'
],
ignore: [
// Auto generated manager types

View File

@@ -32,12 +32,17 @@
"knip": "knip --cache",
"knip:no-cache": "knip",
"locale": "lobe-i18n locale",
"collect-i18n": "npx playwright test --config=playwright.i18n.config.ts",
"collect-i18n": "playwright test --config=playwright.i18n.config.ts",
"json-schema": "tsx scripts/generate-json-schema.ts",
"storybook": "nx storybook -p 6006",
"build-storybook": "storybook build"
},
"devDependencies": {
"@babel/core": "^7.28.4",
"@babel/plugin-transform-modules-commonjs": "^7.27.1",
"@babel/plugin-transform-typescript": "^7.28.0",
"@babel/preset-env": "^7.28.3",
"@babel/preset-typescript": "^7.27.1",
"@eslint/js": "^9.8.0",
"@iconify-json/lucide": "^1.2.66",
"@iconify/tailwind": "^1.2.0",
@@ -62,7 +67,16 @@
"@vitejs/plugin-vue": "^5.1.4",
"@vitest/coverage-v8": "^3.2.4",
"@vitest/ui": "^3.0.0",
"@vue/babel-plugin-jsx": "^1.5.0",
"@vue/test-utils": "^2.4.6",
"babel-helper-vue-jsx-merge-props": "^2.0.3",
"babel-plugin-module-resolver": "^5.0.2",
"babel-plugin-syntax-jsx": "^6.18.0",
"babel-plugin-transform-import-ignore": "^1.1.0",
"babel-plugin-transform-vue-jsx": "^3.7.0",
"babel-preset-env": "^1.7.0",
"babel-preset-typescript-vue3": "^2.1.1",
"dependency-cruiser": "^17.0.1",
"eslint": "^9.34.0",
"eslint-config-prettier": "^10.1.2",
"eslint-plugin-prettier": "^5.2.6",

View File

@@ -1,6 +1,10 @@
import { defineConfig } from '@playwright/test'
import path from 'path'
import { fileURLToPath } from 'url'
export default defineConfig({
const __dirname = path.dirname(fileURLToPath(import.meta.url))
const config: any = defineConfig({
testDir: './scripts',
use: {
baseURL: 'http://localhost:5173',
@@ -8,5 +12,41 @@ export default defineConfig({
},
reporter: 'list',
timeout: 60000,
testMatch: /collect-i18n-.*\.ts/
workers: 1, // Run tests serially to avoid duplicate user creation
testMatch: /collect-i18n-.*\.ts/,
// Start dev server before running tests
webServer: {
command: 'pnpm dev',
url: 'http://localhost:5173',
reuseExistingServer: true,
timeout: 60000
}
})
// Configure babel plugins for TypeScript with declare fields and module resolution
config['@playwright/test'] = {
babelPlugins: [
// Stub Vue and CSS imports first to prevent parsing errors
[path.join(__dirname, 'babel-plugin-stub-vue-imports.cjs')],
// Module resolver to handle @ alias
[
'babel-plugin-module-resolver',
{
root: ['./'],
alias: {
'@': './src'
}
}
],
// Then TypeScript transformation with declare field support
[
'@babel/plugin-transform-typescript',
{
allowDeclareFields: true,
onlyRemoveTypeImports: true
}
]
]
}
export default config

1833
pnpm-lock.yaml generated

File diff suppressed because it is too large Load Diff

View File

@@ -6,6 +6,7 @@ import { SERVER_CONFIG_ITEMS } from '../src/constants/serverConfig'
import type { ComfyCommandImpl } from '../src/stores/commandStore'
import type { FormItem, SettingParams } from '../src/types/settingTypes'
import { formatCamelCase, normalizeI18nKey } from '../src/utils/formatUtil'
import './setup-browser-globals.js'
const localePath = './src/locales/en/main.json'
const commandsPath = './src/locales/en/commands.json'
@@ -47,15 +48,28 @@ test('collect-i18n-general', async ({ comfyPage }) => {
Array.from(allLabels).map((label) => [normalizeI18nKey(label), label])
)
const allCommandsLocale = Object.fromEntries(
commands.map((command) => [
// Load existing commands to preserve Desktop commands
const existingCommands = JSON.parse(fs.readFileSync(commandsPath, 'utf-8'))
// Filter out Desktop commands from existing commands
const desktopCommands = Object.fromEntries(
Object.entries(existingCommands).filter(([key]) =>
key.startsWith('Comfy-Desktop')
)
)
const allCommandsLocale = Object.fromEntries([
// Keep Desktop commands that aren't in the current collection
...Object.entries(desktopCommands),
// Add/update commands from current collection
...commands.map((command) => [
normalizeI18nKey(command.id),
{
label: command.label,
tooltip: command.tooltip
}
])
)
])
// Settings
const settings = await comfyPage.page.evaluate(() => {
@@ -78,8 +92,21 @@ test('collect-i18n-general', async ({ comfyPage }) => {
}))
})
const allSettingsLocale = Object.fromEntries(
settings.map((setting) => [
// Load existing settings to preserve Desktop settings
const existingSettings = JSON.parse(fs.readFileSync(settingsPath, 'utf-8'))
// Filter out Desktop settings from existing settings
const desktopSettings = Object.fromEntries(
Object.entries(existingSettings).filter(([key]) =>
key.startsWith('Comfy-Desktop')
)
)
const allSettingsLocale = Object.fromEntries([
// Keep Desktop settings that aren't in the current collection
...Object.entries(desktopSettings),
// Add/update settings from current collection
...settings.map((setting) => [
normalizeI18nKey(setting.id),
{
name: setting.name,
@@ -98,7 +125,7 @@ test('collect-i18n-general', async ({ comfyPage }) => {
: undefined
}
])
)
])
const allSettingCategoriesLocale = Object.fromEntries(
settings

View File

@@ -1,3 +1,4 @@
// Setup browser globals before any other imports that might use them
import * as fs from 'fs'
import { comfyPageFixture as test } from '../browser_tests/fixtures/ComfyPage'
@@ -5,18 +6,21 @@ import type { ComfyNodeDef } from '../src/schemas/nodeDefSchema'
import type { ComfyApi } from '../src/scripts/api'
import { ComfyNodeDefImpl } from '../src/stores/nodeDefStore'
import { normalizeI18nKey } from '../src/utils/formatUtil'
import './setup-browser-globals.js'
const localePath = './src/locales/en/main.json'
const nodeDefsPath = './src/locales/en/nodeDefs.json'
test('collect-i18n-node-defs', async ({ comfyPage }) => {
// Mock view route
comfyPage.page.route('**/view**', async (route) => {
await comfyPage.page.route('**/view**', async (route) => {
await route.fulfill({
body: JSON.stringify({})
})
})
// Note: Don't mock the object_info API endpoint - let it hit the actual backend
const nodeDefs: ComfyNodeDefImpl[] = (
Object.values(
await comfyPage.page.evaluate(async () => {
@@ -31,6 +35,27 @@ test('collect-i18n-node-defs', async ({ comfyPage }) => {
console.log(`Collected ${nodeDefs.length} node definitions`)
// If no node definitions were collected (e.g., running without backend),
// create empty locale files to avoid build failures
if (nodeDefs.length === 0) {
console.warn('No node definitions found - creating empty locale files')
const locale = JSON.parse(fs.readFileSync(localePath, 'utf-8'))
fs.writeFileSync(
localePath,
JSON.stringify(
{
...locale,
dataTypes: {},
nodeCategories: {}
},
null,
2
)
)
fs.writeFileSync(nodeDefsPath, JSON.stringify({}, null, 2))
return
}
const allDataTypesLocale = Object.fromEntries(
nodeDefs
.flatMap((nodeDef) => {

View File

@@ -0,0 +1,98 @@
// Polyfill browser globals for Node.js context during test imports
import { Window } from 'happy-dom'
// Define build-time constants
if (typeof globalThis.__USE_PROD_CONFIG__ === 'undefined') {
globalThis.__USE_PROD_CONFIG__ = false
}
// Create a happy-dom window instance with configurable URL
const defaultUrl =
(typeof globalThis.process !== 'undefined' &&
globalThis.process.env?.HAPPY_DOM_URL) ||
'http://localhost:5173/'
const window = new Window({
url: defaultUrl,
width: 1024,
height: 768
})
// Mock location with additional properties for testing
const mockLocation = {
...window.location,
href: defaultUrl,
origin: new URL(defaultUrl).origin,
protocol: new URL(defaultUrl).protocol,
host: new URL(defaultUrl).host,
hostname: new URL(defaultUrl).hostname,
port: new URL(defaultUrl).port,
pathname: new URL(defaultUrl).pathname,
search: new URL(defaultUrl).search,
hash: new URL(defaultUrl).hash,
assign: (url) => {
console.log(`[Mock] location.assign called with: ${url}`)
mockLocation.href = url
},
replace: (url) => {
console.log(`[Mock] location.replace called with: ${url}`)
mockLocation.href = url
},
reload: () => {
console.log('[Mock] location.reload called')
}
}
// Expose DOM globals (only set if not already defined)
if (!globalThis.window) globalThis.window = window
if (!globalThis.document) globalThis.document = window.document
if (!globalThis.location) globalThis.location = mockLocation
if (!globalThis.navigator) {
try {
globalThis.navigator = window.navigator
} catch (e) {
// navigator might be read-only in some environments
}
}
if (!globalThis.HTMLElement) globalThis.HTMLElement = window.HTMLElement
if (!globalThis.Element) globalThis.Element = window.Element
if (!globalThis.Node) globalThis.Node = window.Node
if (!globalThis.NodeList) globalThis.NodeList = window.NodeList
if (!globalThis.DOMParser) globalThis.DOMParser = window.DOMParser
if (!globalThis.XMLSerializer) globalThis.XMLSerializer = window.XMLSerializer
if (!globalThis.localStorage) globalThis.localStorage = window.localStorage
if (!globalThis.sessionStorage)
globalThis.sessionStorage = window.sessionStorage
if (!globalThis.CustomEvent) globalThis.CustomEvent = window.CustomEvent
if (!globalThis.Event) globalThis.Event = window.Event
if (!globalThis.MouseEvent) globalThis.MouseEvent = window.MouseEvent
if (!globalThis.KeyboardEvent) globalThis.KeyboardEvent = window.KeyboardEvent
if (!globalThis.getComputedStyle)
globalThis.getComputedStyle = window.getComputedStyle
if (!globalThis.requestAnimationFrame)
globalThis.requestAnimationFrame = window.requestAnimationFrame
if (!globalThis.cancelAnimationFrame)
globalThis.cancelAnimationFrame = window.cancelAnimationFrame
// Add ResizeObserver polyfill
if (!globalThis.ResizeObserver) {
globalThis.ResizeObserver = class ResizeObserver {
constructor(callback) {
this.callback = callback
}
observe() {}
unobserve() {}
disconnect() {}
}
}
// Add IntersectionObserver polyfill
if (!globalThis.IntersectionObserver) {
globalThis.IntersectionObserver = class IntersectionObserver {
constructor(callback) {
this.callback = callback
}
observe() {}
unobserve() {}
disconnect() {}
}
}

130
scripts/verbatim.mjs Normal file
View File

@@ -0,0 +1,130 @@
#!/usr/bin/env bun
import fs from 'fs/promises';
import path from 'path';
import { fileURLToPath } from 'url';
// const __dirname = path.dirname(fileURLToPath(import.meta.url));
const __dirname = process.cwd()
// Parse the tsc.log file to get all errors
async function parseErrors(file) {
const logContent = await fs.readFile(file, 'utf-8');
const lines = logContent.split('\n').filter(line => line.includes('error TS1484'));
const errors = [];
for (const line of lines) {
// Match the format: filepath(line,col): error TS1484: 'TypeName' is a type
// Note: Some lines may have a number prefix followed by →
const match = line.match(/(?:\d+→)?(.+?)\((\d+),(\d+)\): error TS1484: '(.+?)' is a type/);
if (match) {
const [, filePath, lineNum, colNum, typeName] = match;
errors.push({
filePath: path.join(__dirname, filePath.trim()),
lineNum: parseInt(lineNum),
colNum: parseInt(colNum),
typeName
});
}
}
return errors;
}
// Group errors by file
function groupByFile(errors) {
const grouped = {};
for (const error of errors) {
if (!grouped[error.filePath]) {
grouped[error.filePath] = [];
}
grouped[error.filePath].push(error);
}
return grouped;
}
// Process a single file
async function processFile(filePath, errors) {
try {
const content = await fs.readFile(filePath, 'utf-8');
const lines = content.split('\n');
// Sort errors by line and column in reverse order to avoid position shifts
errors.sort((a, b) => {
if (a.lineNum !== b.lineNum) {
return b.lineNum - a.lineNum;
}
return b.colNum - a.colNum;
});
// Process each error
for (const error of errors) {
const lineIndex = error.lineNum - 1;
const line = lines[lineIndex];
if (!line) continue;
// Skip if already has 'type' keyword before this position
const beforePos = line.substring(0, error.colNum - 1);
if (beforePos.includes('import type') || beforePos.endsWith('{ type ') || beforePos.endsWith(', type ')) {
continue;
}
// Insert "type " at the exact column position (column is 1-based)
const insertPos = error.colNum - 1;
lines[lineIndex] = line.substring(0, insertPos) + 'type ' + line.substring(insertPos);
}
await fs.writeFile(filePath, lines.join('\n'));
console.log(`✓ Fixed ${errors.length} type imports in ${path.relative(__dirname, filePath)}`);
return true;
} catch (error) {
console.error(`✗ Error processing ${filePath}:`, error.message);
return false;
}
}
// Main function
async function main() {
console.log('🔧 Fixing TypeScript type-only imports...\n');
const logFile = path.join(__dirname, 'tsc.log');
if (!await fs.readFile(logFile, 'utf-8').catch(() => null)) {
console.error('Unable to read tsc.log');
console.error('Run this command to generate type errors and rerun this script again:');
console.error('pnpm typecheck > tsc.log');
return;
}
console.log('Parsing tsc.log for type import errors...\n');
const errors = await parseErrors(logFile);
console.log(`Found ${errors.length} type import errors\n`);
const grouped = groupByFile(errors);
const files = Object.keys(grouped);
console.log(`Processing ${files.length} files...\n`);
let successCount = 0;
let failCount = 0;
for (const filePath of files) {
const success = await processFile(filePath, grouped[filePath]);
if (success) {
successCount++;
} else {
failCount++;
}
}
console.log('\n📊 Summary:');
console.log(`✓ Successfully processed: ${successCount} files`);
if (failCount > 0) {
console.log(`✗ Failed to process: ${failCount} files`);
}
console.log('\n✨ Refactoring complete!');
console.log('Run "pnpm typecheck" to verify the fixes.');
}
// Run the script
main().catch(console.error);

View File

@@ -21,7 +21,7 @@
<script setup lang="ts">
import Button from 'primevue/button'
import { CSSProperties, computed, watchEffect } from 'vue'
import { type CSSProperties, computed, watchEffect } from 'vue'
import { app } from '@/scripts/app'
import { useSettingStore } from '@/stores/settingStore'

View File

@@ -22,7 +22,15 @@ import {
} from '@vueuse/core'
import { clamp } from 'es-toolkit/compat'
import Panel from 'primevue/panel'
import { Ref, computed, inject, nextTick, onMounted, ref, watch } from 'vue'
import {
type Ref,
computed,
inject,
nextTick,
onMounted,
ref,
watch
} from 'vue'
import { useSettingStore } from '@/stores/settingStore'

View File

@@ -7,7 +7,7 @@
</template>
<script setup lang="ts">
import { Ref, onUnmounted, ref } from 'vue'
import { type Ref, onUnmounted, ref } from 'vue'
import { useTerminal } from '@/composables/bottomPanelTabs/useTerminal'

View File

@@ -3,8 +3,8 @@
</template>
<script setup lang="ts">
import { IDisposable } from '@xterm/xterm'
import { Ref, onMounted, onUnmounted } from 'vue'
import { type IDisposable } from '@xterm/xterm'
import { type Ref, onMounted, onUnmounted } from 'vue'
import type { useTerminal } from '@/composables/bottomPanelTabs/useTerminal'
import { electronAPI } from '@/utils/envUtil'

View File

@@ -15,10 +15,14 @@
import { until } from '@vueuse/core'
import { storeToRefs } from 'pinia'
import ProgressSpinner from 'primevue/progressspinner'
import { Ref, onMounted, onUnmounted, ref } from 'vue'
import { type Ref, onMounted, onUnmounted, ref } from 'vue'
import type { useTerminal } from '@/composables/bottomPanelTabs/useTerminal'
import { LogEntry, LogsWsMessage, TerminalSize } from '@/schemas/apiSchema'
import {
type LogEntry,
type LogsWsMessage,
type TerminalSize
} from '@/schemas/apiSchema'
import { api } from '@/scripts/api'
import { useExecutionStore } from '@/stores/executionStore'

View File

@@ -47,7 +47,8 @@
<script setup lang="ts">
import InputText from 'primevue/inputtext'
import Menu, { MenuState } from 'primevue/menu'
import Menu from 'primevue/menu'
import type { MenuState } from 'primevue/menu'
import type { MenuItem } from 'primevue/menuitem'
import Tag from 'primevue/tag'
import { computed, nextTick, ref } from 'vue'

View File

@@ -17,7 +17,7 @@
<script setup lang="ts">
import { onBeforeUnmount } from 'vue'
import { CustomExtension, VueExtension } from '@/types/extensionTypes'
import { type CustomExtension, type VueExtension } from '@/types/extensionTypes'
const props = defineProps<{
extension: VueExtension | CustomExtension

View File

@@ -44,7 +44,7 @@ import FormRadioGroup from '@/components/common/FormRadioGroup.vue'
import InputKnob from '@/components/common/InputKnob.vue'
import InputSlider from '@/components/common/InputSlider.vue'
import UrlInput from '@/components/common/UrlInput.vue'
import { FormItem } from '@/types/settingTypes'
import { type FormItem } from '@/types/settingTypes'
const formValue = defineModel<any>('formValue')
const props = defineProps<{

View File

@@ -32,7 +32,7 @@
import Button from 'primevue/button'
import ProgressSpinner from 'primevue/progressspinner'
import { PrimeVueSeverity } from '@/types/primeVueTypes'
import { type PrimeVueSeverity } from '@/types/primeVueTypes'
const {
disabled,

View File

@@ -11,7 +11,7 @@ import EditableText from '@/components/common/EditableText.vue'
import TreeExplorerTreeNode from '@/components/common/TreeExplorerTreeNode.vue'
import {
InjectKeyHandleEditLabelFunction,
RenderedTreeExplorerNode
type RenderedTreeExplorerNode
} from '@/types/treeExplorerTypes'
// Create a mock i18n instance

View File

@@ -69,8 +69,8 @@ import SearchBox from '@/components/common/SearchBox.vue'
import { useFirebaseAuthActions } from '@/composables/auth/useFirebaseAuthActions'
import { useSettingSearch } from '@/composables/setting/useSettingSearch'
import { useSettingUI } from '@/composables/setting/useSettingUI'
import { SettingTreeNode } from '@/stores/settingStore'
import { ISettingGroup, SettingParams } from '@/types/settingTypes'
import { type SettingTreeNode } from '@/stores/settingStore'
import { type ISettingGroup, type SettingParams } from '@/types/settingTypes'
import { flattenTree } from '@/utils/treeUtil'
import ColorPaletteMessage from './setting/ColorPaletteMessage.vue'

View File

@@ -148,7 +148,7 @@ import { useI18n } from 'vue-i18n'
import { useFirebaseAuthActions } from '@/composables/auth/useFirebaseAuthActions'
import { COMFY_PLATFORM_BASE_URL } from '@/config/comfyApi'
import { SignInData, SignUpData } from '@/schemas/signInSchema'
import { type SignInData, type SignUpData } from '@/schemas/signInSchema'
import { isInChina } from '@/utils/networkUtil'
import ApiKeyForm from './signin/ApiKeyForm.vue'

View File

@@ -17,7 +17,7 @@
</template>
<script setup lang="ts">
import { Form, FormSubmitEvent } from '@primevue/forms'
import { Form, type FormSubmitEvent } from '@primevue/forms'
import { zodResolver } from '@primevue/forms/resolvers/zod'
import Button from 'primevue/button'
import { ref } from 'vue'

View File

@@ -160,7 +160,7 @@ import { useComfyManagerStore } from '@/stores/comfyManagerStore'
import { useComfyRegistryStore } from '@/stores/comfyRegistryStore'
import type { TabItem } from '@/types/comfyManagerTypes'
import { ManagerTab } from '@/types/comfyManagerTypes'
import { components } from '@/types/comfyRegistryTypes'
import { type components } from '@/types/comfyRegistryTypes'
const { initialTab } = defineProps<{
initialTab?: ManagerTab

View File

@@ -170,8 +170,8 @@ import { useI18n } from 'vue-i18n'
import ContentDivider from '@/components/common/ContentDivider.vue'
import { useConflictDetection } from '@/composables/useConflictDetection'
import {
ConflictDetail,
ConflictDetectionResult
type ConflictDetail,
type ConflictDetectionResult
} from '@/types/conflictDetectionTypes'
import { getConflictMessage } from '@/utils/conflictMessageUtil'

View File

@@ -19,7 +19,7 @@
import Message from 'primevue/message'
import { computed, inject } from 'vue'
import { components } from '@/types/comfyRegistryTypes'
import { type components } from '@/types/comfyRegistryTypes'
import { ImportFailedKey } from '@/types/importFailedTypes'
type PackVersionStatus = components['schemas']['NodeVersionStatus']

View File

@@ -93,8 +93,8 @@ import VerifiedIcon from '@/components/icons/VerifiedIcon.vue'
import { useConflictDetection } from '@/composables/useConflictDetection'
import { useComfyRegistryService } from '@/services/comfyRegistryService'
import { useComfyManagerStore } from '@/stores/comfyManagerStore'
import { components } from '@/types/comfyRegistryTypes'
import { components as ManagerComponents } from '@/types/generatedManagerTypes'
import { type components } from '@/types/comfyRegistryTypes'
import { type components as ManagerComponents } from '@/types/generatedManagerTypes'
import { getJoinedConflictMessages } from '@/utils/conflictMessageUtil'
import { isSemVer } from '@/utils/formatUtil'

View File

@@ -39,7 +39,7 @@ import { useDialogService } from '@/services/dialogService'
import { useComfyManagerStore } from '@/stores/comfyManagerStore'
import { useConflictDetectionStore } from '@/stores/conflictDetectionStore'
import type { components } from '@/types/comfyRegistryTypes'
import { components as ManagerComponents } from '@/types/generatedManagerTypes'
import { type components as ManagerComponents } from '@/types/generatedManagerTypes'
const TOGGLE_DEBOUNCE_MS = 256

View File

@@ -31,13 +31,13 @@ import { useConflictDetection } from '@/composables/useConflictDetection'
import { t } from '@/i18n'
import { useDialogService } from '@/services/dialogService'
import { useComfyManagerStore } from '@/stores/comfyManagerStore'
import { ButtonSize } from '@/types/buttonTypes'
import { type ButtonSize } from '@/types/buttonTypes'
import type { components } from '@/types/comfyRegistryTypes'
import {
type ConflictDetail,
ConflictDetectionResult
type ConflictDetectionResult
} from '@/types/conflictDetectionTypes'
import { components as ManagerComponents } from '@/types/generatedManagerTypes'
import { type components as ManagerComponents } from '@/types/generatedManagerTypes'
type NodePack = components['schemas']['Node']

View File

@@ -17,9 +17,9 @@
<script setup lang="ts">
import IconTextButton from '@/components/button/IconTextButton.vue'
import { useComfyManagerStore } from '@/stores/comfyManagerStore'
import { ButtonSize } from '@/types/buttonTypes'
import { type ButtonSize } from '@/types/buttonTypes'
import type { components } from '@/types/comfyRegistryTypes'
import { components as ManagerComponents } from '@/types/generatedManagerTypes'
import { type components as ManagerComponents } from '@/types/generatedManagerTypes'
type NodePack = components['schemas']['Node']

View File

@@ -75,7 +75,7 @@ import { useImportFailedDetection } from '@/composables/useImportFailedDetection
import { useComfyManagerStore } from '@/stores/comfyManagerStore'
import { useConflictDetectionStore } from '@/stores/conflictDetectionStore'
import { IsInstallingKey } from '@/types/comfyManagerTypes'
import { components } from '@/types/comfyRegistryTypes'
import { type components } from '@/types/comfyRegistryTypes'
import type { ConflictDetectionResult } from '@/types/conflictDetectionTypes'
import { ImportFailedKey } from '@/types/importFailedTypes'

View File

@@ -50,7 +50,7 @@ import PackUninstallButton from '@/components/dialog/content/manager/button/Pack
import PackIcon from '@/components/dialog/content/manager/packIcon/PackIcon.vue'
import { useConflictDetection } from '@/composables/useConflictDetection'
import { useComfyManagerStore } from '@/stores/comfyManagerStore'
import { components } from '@/types/comfyRegistryTypes'
import { type components } from '@/types/comfyRegistryTypes'
import type { ConflictDetail } from '@/types/conflictDetectionTypes'
import { ImportFailedKey } from '@/types/importFailedTypes'

View File

@@ -67,7 +67,7 @@ import { usePacksSelection } from '@/composables/nodePack/usePacksSelection'
import { usePacksStatus } from '@/composables/nodePack/usePacksStatus'
import { useConflictDetection } from '@/composables/useConflictDetection'
import { useComfyRegistryStore } from '@/stores/comfyRegistryStore'
import { components } from '@/types/comfyRegistryTypes'
import { type components } from '@/types/comfyRegistryTypes'
import type { ConflictDetail } from '@/types/conflictDetectionTypes'
import { ImportFailedKey } from '@/types/importFailedTypes'

View File

@@ -48,7 +48,7 @@ import { computed, inject, ref, watchEffect } from 'vue'
import DescriptionTabPanel from '@/components/dialog/content/manager/infoPanel/tabs/DescriptionTabPanel.vue'
import NodesTabPanel from '@/components/dialog/content/manager/infoPanel/tabs/NodesTabPanel.vue'
import WarningTabPanel from '@/components/dialog/content/manager/infoPanel/tabs/WarningTabPanel.vue'
import { components } from '@/types/comfyRegistryTypes'
import { type components } from '@/types/comfyRegistryTypes'
import type { ConflictDetectionResult } from '@/types/conflictDetectionTypes'
import { ImportFailedKey } from '@/types/importFailedTypes'

View File

@@ -3,7 +3,7 @@ import { describe, expect, it } from 'vitest'
import { createI18n } from 'vue-i18n'
import enMessages from '@/locales/en/main.json' with { type: 'json' }
import { components } from '@/types/comfyRegistryTypes'
import { type components } from '@/types/comfyRegistryTypes'
import DescriptionTabPanel from './DescriptionTabPanel.vue'

View File

@@ -29,7 +29,7 @@ import { useI18n } from 'vue-i18n'
import InfoTextSection, {
type TextSection
} from '@/components/dialog/content/manager/infoPanel/InfoTextSection.vue'
import { components } from '@/types/comfyRegistryTypes'
import { type components } from '@/types/comfyRegistryTypes'
import { isValidUrl } from '@/utils/formatUtil'
const { t } = useI18n()

View File

@@ -34,7 +34,7 @@ import { computed, ref, shallowRef, useId } from 'vue'
import NoResultsPlaceholder from '@/components/common/NoResultsPlaceholder.vue'
import NodePreview from '@/components/node/NodePreview.vue'
import { useComfyRegistryStore } from '@/stores/comfyRegistryStore'
import { components, operations } from '@/types/comfyRegistryTypes'
import { type components, type operations } from '@/types/comfyRegistryTypes'
import { registryToFrontendV2NodeDef } from '@/utils/mapperUtil'
type ListComfyNodesResponse =

View File

@@ -29,8 +29,8 @@ import { computed } from 'vue'
import { useImportFailedDetection } from '@/composables/useImportFailedDetection'
import { t } from '@/i18n'
import { components } from '@/types/comfyRegistryTypes'
import { ConflictDetectionResult } from '@/types/conflictDetectionTypes'
import { type components } from '@/types/comfyRegistryTypes'
import { type ConflictDetectionResult } from '@/types/conflictDetectionTypes'
import { getConflictMessage } from '@/utils/conflictMessageUtil'
const { nodePack, conflictResult } = defineProps<{

View File

@@ -37,7 +37,7 @@
<script setup lang="ts">
import { computed, ref } from 'vue'
import { components } from '@/types/comfyRegistryTypes'
import { type components } from '@/types/comfyRegistryTypes'
const DEFAULT_BANNER = '/assets/images/fallback-gradient-avatar.svg'

View File

@@ -37,7 +37,7 @@
<script setup lang="ts">
import { computed, ref } from 'vue'
import { components } from '@/types/comfyRegistryTypes'
import { type components } from '@/types/comfyRegistryTypes'
const DEFAULT_BANNER = '/assets/images/fallback-gradient-avatar.svg'

View File

@@ -19,7 +19,7 @@
<script setup lang="ts">
import PackIcon from '@/components/dialog/content/manager/packIcon/PackIcon.vue'
import { components } from '@/types/comfyRegistryTypes'
import { type components } from '@/types/comfyRegistryTypes'
const {
nodePacks,

View File

@@ -63,7 +63,7 @@
<script setup lang="ts">
import { stubTrue } from 'es-toolkit/compat'
import AutoComplete, {
AutoCompleteOptionSelectEvent
type AutoCompleteOptionSelectEvent
} from 'primevue/autocomplete'
import { computed } from 'vue'
import { useI18n } from 'vue-i18n'
@@ -77,7 +77,7 @@ import {
type SearchOption,
SortableAlgoliaField
} from '@/types/comfyManagerTypes'
import { components } from '@/types/comfyRegistryTypes'
import { type components } from '@/types/comfyRegistryTypes'
import type {
QuerySuggestion,
SearchMode,

View File

@@ -20,7 +20,7 @@
import Divider from 'primevue/divider'
import SettingItem from '@/components/dialog/content/setting/SettingItem.vue'
import { SettingParams } from '@/types/settingTypes'
import { type SettingParams } from '@/types/settingTypes'
import { normalizeI18nKey } from '@/utils/formatUtil'
defineProps<{

View File

@@ -17,7 +17,7 @@
<script setup lang="ts">
import NoResultsPlaceholder from '@/components/common/NoResultsPlaceholder.vue'
import { ISettingGroup } from '@/types/settingTypes'
import { type ISettingGroup } from '@/types/settingTypes'
import SettingGroup from './SettingGroup.vue'

View File

@@ -97,7 +97,7 @@ import ProgressSpinner from 'primevue/progressspinner'
import { computed, ref } from 'vue'
import {
AuditLog,
type AuditLog,
EventType,
useCustomerEventsService
} from '@/services/customerEventsService'

View File

@@ -79,7 +79,7 @@
</template>
<script setup lang="ts">
import { Form, FormSubmitEvent } from '@primevue/forms'
import { Form, type FormSubmitEvent } from '@primevue/forms'
import { zodResolver } from '@primevue/forms/resolvers/zod'
import Button from 'primevue/button'
import InputText from 'primevue/inputtext'

View File

@@ -71,7 +71,7 @@
</template>
<script setup lang="ts">
import { Form, FormSubmitEvent } from '@primevue/forms'
import { Form, type FormSubmitEvent } from '@primevue/forms'
import { zodResolver } from '@primevue/forms/resolvers/zod'
import Button from 'primevue/button'
import InputText from 'primevue/inputtext'

View File

@@ -59,7 +59,7 @@
</template>
<script setup lang="ts">
import { Form, FormField, FormSubmitEvent } from '@primevue/forms'
import { Form, FormField, type FormSubmitEvent } from '@primevue/forms'
import { zodResolver } from '@primevue/forms/resolvers/zod'
import Button from 'primevue/button'
import Checkbox from 'primevue/checkbox'

View File

@@ -135,7 +135,7 @@
</template>
<script setup lang="ts">
import { Button, InputNumber, InputNumberInputEvent } from 'primevue'
import { Button, InputNumber, type InputNumberInputEvent } from 'primevue'
import { computed, nextTick, ref, watch } from 'vue'
import { useI18n } from 'vue-i18n'

View File

@@ -50,7 +50,7 @@
<script setup lang="ts">
import Button from 'primevue/button'
import SelectButton from 'primevue/selectbutton'
import { Raw, computed, ref, watch } from 'vue'
import { type Raw, computed, ref, watch } from 'vue'
import { useI18n } from 'vue-i18n'
import type {

View File

@@ -20,7 +20,7 @@ import { computed } from 'vue'
import { useI18n } from 'vue-i18n'
import { useSelectionState } from '@/composables/graph/useSelectionState'
import { Positionable } from '@/lib/litegraph/src/interfaces'
import { type Positionable } from '@/lib/litegraph/src/interfaces'
import { useCommandStore } from '@/stores/commandStore'
const { t } = useI18n()

View File

@@ -17,7 +17,7 @@
import Button from 'primevue/button'
import { st } from '@/i18n'
import { ComfyCommand, useCommandStore } from '@/stores/commandStore'
import { type ComfyCommand, useCommandStore } from '@/stores/commandStore'
import { normalizeI18nKey } from '@/utils/formatUtil'
defineProps<{

View File

@@ -56,7 +56,7 @@ import { computed, nextTick, ref, watch } from 'vue'
import CopyButton from '@/components/graph/widgets/chatHistory/CopyButton.vue'
import ResponseBlurb from '@/components/graph/widgets/chatHistory/ResponseBlurb.vue'
import { ComponentWidget } from '@/scripts/domWidget'
import { type ComponentWidget } from '@/scripts/domWidget'
import { linkifyHtml, nl2br } from '@/utils/formatUtil'
const { widget, history = '[]' } = defineProps<{

View File

@@ -19,13 +19,20 @@
<script setup lang="ts">
import { useElementBounding, useEventListener } from '@vueuse/core'
import { CSSProperties, computed, nextTick, onMounted, ref, watch } from 'vue'
import {
type CSSProperties,
computed,
nextTick,
onMounted,
ref,
watch
} from 'vue'
import { useAbsolutePosition } from '@/composables/element/useAbsolutePosition'
import { useDomClipping } from '@/composables/element/useDomClipping'
import { useCanvasStore } from '@/renderer/core/canvas/canvasStore'
import { isComponentWidget, isDOMWidget } from '@/scripts/domWidget'
import { DomWidgetState } from '@/stores/domWidgetStore'
import type { DomWidgetState } from '@/stores/domWidgetStore'
import { useSettingStore } from '@/stores/settingStore'
const { widgetState } = defineProps<{

View File

@@ -15,7 +15,7 @@
import Skeleton from 'primevue/skeleton'
import { computed, onMounted, ref, watch } from 'vue'
import { NodeId } from '@/lib/litegraph/src/litegraph'
import { type NodeId } from '@/lib/litegraph/src/litegraph'
import { useExecutionStore } from '@/stores/executionStore'
import { linkifyHtml, nl2br } from '@/utils/formatUtil'

View File

@@ -101,9 +101,8 @@
<script setup lang="ts">
import Button from 'primevue/button'
import MultiSelect, {
MultiSelectPassThroughMethodOptions
} from 'primevue/multiselect'
import MultiSelect from 'primevue/multiselect'
import type { MultiSelectPassThroughMethodOptions } from 'primevue/multiselect'
import { computed } from 'vue'
import SearchBox from '@/components/input/SearchBox.vue'

View File

@@ -53,7 +53,8 @@
</template>
<script setup lang="ts">
import Select, { SelectPassThroughMethodOptions } from 'primevue/select'
import Select from 'primevue/select'
import type { SelectPassThroughMethodOptions } from 'primevue/select'
import { computed } from 'vue'
import { cn } from '@/utils/tailwindUtil'

View File

@@ -35,15 +35,19 @@
<script setup lang="ts">
import {
TorchDeviceType,
type TorchDeviceType,
TorchMirrorUrl
} from '@comfyorg/comfyui-electron-types'
import Divider from 'primevue/divider'
import Panel from 'primevue/panel'
import { ModelRef, computed, onMounted, ref } from 'vue'
import { type ModelRef, computed, onMounted, ref } from 'vue'
import MirrorItem from '@/components/install/mirror/MirrorItem.vue'
import { PYPI_MIRROR, PYTHON_MIRROR, UVMirror } from '@/constants/uvMirrors'
import {
PYPI_MIRROR,
PYTHON_MIRROR,
type UVMirror
} from '@/constants/uvMirrors'
import { t } from '@/i18n'
import { isInChina } from '@/utils/networkUtil'
import { ValidationState, mergeValidationStates } from '@/utils/validationUtil'

View File

@@ -23,7 +23,7 @@
import { computed, onMounted, ref, watch } from 'vue'
import UrlInput from '@/components/common/UrlInput.vue'
import { UVMirror } from '@/constants/uvMirrors'
import { type UVMirror } from '@/constants/uvMirrors'
import { normalizeI18nKey } from '@/utils/formatUtil'
import { checkMirrorReachable } from '@/utils/networkUtil'
import { ValidationState } from '@/utils/validationUtil'

View File

@@ -96,10 +96,10 @@ import RecordingControls from '@/components/load3d/controls/RecordingControls.vu
import ViewerControls from '@/components/load3d/controls/ViewerControls.vue'
import Load3dUtils from '@/extensions/core/load3d/Load3dUtils'
import {
CameraType,
Load3DNodeType,
MaterialMode,
UpDirection
type CameraType,
type Load3DNodeType,
type MaterialMode,
type UpDirection
} from '@/extensions/core/load3d/interfaces'
import type { CustomInputSpec } from '@/schemas/nodeDef/nodeDefSchemaV2'
import type { ComponentWidget } from '@/scripts/domWidget'

View File

@@ -94,11 +94,11 @@ import Load3DControls from '@/components/load3d/Load3DControls.vue'
import RecordingControls from '@/components/load3d/controls/RecordingControls.vue'
import Load3dUtils from '@/extensions/core/load3d/Load3dUtils'
import {
AnimationItem,
CameraType,
Load3DAnimationNodeType,
MaterialMode,
UpDirection
type AnimationItem,
type CameraType,
type Load3DAnimationNodeType,
type MaterialMode,
type UpDirection
} from '@/extensions/core/load3d/interfaces'
import type { CustomInputSpec } from '@/schemas/nodeDef/nodeDefSchemaV2'
import type { ComponentWidget } from '@/scripts/domWidget'

View File

@@ -29,11 +29,11 @@ import { ref, watch } from 'vue'
import Load3DScene from '@/components/load3d/Load3DScene.vue'
import Load3dAnimation from '@/extensions/core/load3d/Load3dAnimation'
import {
CameraType,
MaterialMode,
UpDirection
type CameraType,
type MaterialMode,
type UpDirection
} from '@/extensions/core/load3d/interfaces'
import { CustomInputSpec } from '@/schemas/nodeDef/nodeDefSchemaV2'
import { type CustomInputSpec } from '@/schemas/nodeDef/nodeDefSchemaV2'
const props = defineProps<{
node: any

View File

@@ -100,9 +100,9 @@ import LightControls from '@/components/load3d/controls/LightControls.vue'
import ModelControls from '@/components/load3d/controls/ModelControls.vue'
import SceneControls from '@/components/load3d/controls/SceneControls.vue'
import {
CameraType,
MaterialMode,
UpDirection
type CameraType,
type MaterialMode,
type UpDirection
} from '@/extensions/core/load3d/interfaces'
import { t } from '@/i18n'
import type { CustomInputSpec } from '@/schemas/nodeDef/nodeDefSchemaV2'

View File

@@ -11,9 +11,9 @@ import LoadingOverlay from '@/components/load3d/LoadingOverlay.vue'
import Load3d from '@/extensions/core/load3d/Load3d'
import Load3dAnimation from '@/extensions/core/load3d/Load3dAnimation'
import {
CameraType,
MaterialMode,
UpDirection
type CameraType,
type MaterialMode,
type UpDirection
} from '@/extensions/core/load3d/interfaces'
import { t } from '@/i18n'
import { LGraphNode } from '@/lib/litegraph/src/litegraph'

View File

@@ -40,7 +40,7 @@ import Button from 'primevue/button'
import Slider from 'primevue/slider'
import { computed, onMounted, onUnmounted, ref, watch } from 'vue'
import { CameraType } from '@/extensions/core/load3d/interfaces'
import { type CameraType } from '@/extensions/core/load3d/interfaces'
import { t } from '@/i18n'
const vTooltip = Tooltip

View File

@@ -99,7 +99,10 @@ import Button from 'primevue/button'
import Slider from 'primevue/slider'
import { computed, onMounted, onUnmounted, ref, watch } from 'vue'
import { MaterialMode, UpDirection } from '@/extensions/core/load3d/interfaces'
import {
type MaterialMode,
type UpDirection
} from '@/extensions/core/load3d/interfaces'
import { t } from '@/i18n'
import type { CustomInputSpec } from '@/schemas/nodeDef/nodeDefSchemaV2'

View File

@@ -23,7 +23,7 @@ import Select from 'primevue/select'
import Slider from 'primevue/slider'
import { computed } from 'vue'
import { CameraType } from '@/extensions/core/load3d/interfaces'
import { type CameraType } from '@/extensions/core/load3d/interfaces'
import { t } from '@/i18n'
const cameras = [

View File

@@ -26,7 +26,10 @@
import Select from 'primevue/select'
import { computed } from 'vue'
import { MaterialMode, UpDirection } from '@/extensions/core/load3d/interfaces'
import {
type MaterialMode,
type UpDirection
} from '@/extensions/core/load3d/interfaces'
import { t } from '@/i18n'
const upDirection = defineModel<UpDirection>('upDirection')

View File

@@ -47,7 +47,7 @@ import { computed, ref } from 'vue'
import { useMaintenanceTaskStore } from '@/stores/maintenanceTaskStore'
import type { MaintenanceTask } from '@/types/desktop/maintenanceTypes'
import { PrimeVueSeverity } from '@/types/primeVueTypes'
import { type PrimeVueSeverity } from '@/types/primeVueTypes'
import { useMinLoadingDurationRef } from '@/utils/refUtil'
import TaskListStatusIcon from './TaskListStatusIcon.vue'

View File

@@ -8,7 +8,7 @@
<script setup lang="ts">
import { PrimeIcons } from '@primevue/core/api'
import ProgressSpinner from 'primevue/progressspinner'
import { MaybeRef, computed } from 'vue'
import { type MaybeRef, computed } from 'vue'
import { t } from '@/i18n'

View File

@@ -12,7 +12,7 @@
<script setup lang="ts">
import { Terminal } from '@xterm/xterm'
import Drawer from 'primevue/drawer'
import { Ref, onMounted } from 'vue'
import { type Ref, onMounted } from 'vue'
import BaseTerminal from '@/components/bottomPanel/tabs/terminal/BaseTerminal.vue'
import type { useTerminal } from '@/composables/bottomPanelTabs/useTerminal'

View File

@@ -38,11 +38,11 @@ import { storeToRefs } from 'pinia'
import Dialog from 'primevue/dialog'
import { computed, ref, toRaw, watch, watchEffect } from 'vue'
import { Point } from '@/lib/litegraph/src/interfaces'
import { type Point } from '@/lib/litegraph/src/interfaces'
import {
LGraphNode,
LiteGraph,
LiteGraphCanvasEvent
type LiteGraphCanvasEvent
} from '@/lib/litegraph/src/litegraph'
import type { CanvasPointerEvent } from '@/lib/litegraph/src/types/events'
import { useCanvasStore } from '@/renderer/core/canvas/canvasStore'
@@ -52,7 +52,7 @@ import { useSettingStore } from '@/stores/settingStore'
import { useWorkflowStore } from '@/stores/workflowStore'
import { useSearchBoxStore } from '@/stores/workspace/searchBoxStore'
import { LinkReleaseTriggerAction } from '@/types/searchBoxTypes'
import { FuseFilterWithValue } from '@/utils/fuseUtil'
import { type FuseFilterWithValue } from '@/utils/fuseUtil'
import NodeSearchBox from './NodeSearchBox.vue'

View File

@@ -28,7 +28,7 @@ import SelectButton from 'primevue/selectbutton'
import { computed, onMounted, ref } from 'vue'
import { ComfyNodeDefImpl, useNodeDefStore } from '@/stores/nodeDefStore'
import { FuseFilter, FuseFilterWithValue } from '@/utils/fuseUtil'
import { FuseFilter, type FuseFilterWithValue } from '@/utils/fuseUtil'
const filters = computed(() => nodeDefStore.nodeSearchService.nodeFilters)
const selectedFilter = ref<FuseFilter<ComfyNodeDefImpl, string>>()

View File

@@ -129,10 +129,10 @@ import { storeToRefs } from 'pinia'
import Button from 'primevue/button'
import Divider from 'primevue/divider'
import Popover from 'primevue/popover'
import { Ref, computed, h, nextTick, ref, render } from 'vue'
import { type Ref, computed, h, nextTick, ref, render } from 'vue'
import SearchBox from '@/components/common/SearchBox.vue'
import { SearchFilter } from '@/components/common/SearchFilterChip.vue'
import { type SearchFilter } from '@/components/common/SearchFilterChip.vue'
import TreeExplorer from '@/components/common/TreeExplorer.vue'
import NodePreview from '@/components/node/NodePreview.vue'
import NodeSearchFilter from '@/components/searchbox/NodeSearchFilter.vue'
@@ -156,7 +156,7 @@ import type {
} from '@/types/nodeOrganizationTypes'
import type { TreeNode } from '@/types/treeExplorerTypes'
import type { TreeExplorerNode } from '@/types/treeExplorerTypes'
import { FuseFilterWithValue } from '@/utils/fuseUtil'
import { type FuseFilterWithValue } from '@/utils/fuseUtil'
import NodeBookmarkTreeExplorer from './nodeLibrary/NodeBookmarkTreeExplorer.vue'

View File

@@ -104,7 +104,7 @@ import { useI18n } from 'vue-i18n'
import NoResultsPlaceholder from '@/components/common/NoResultsPlaceholder.vue'
import VirtualGrid from '@/components/common/VirtualGrid.vue'
import { ComfyNode } from '@/schemas/comfyWorkflowSchema'
import { type ComfyNode } from '@/schemas/comfyWorkflowSchema'
import { api } from '@/scripts/api'
import { app } from '@/scripts/app'
import { useLitegraphService } from '@/services/litegraphService'

View File

@@ -150,7 +150,7 @@ import {
import { ComfyWorkflow } from '@/stores/workflowStore'
import { useWorkspaceStore } from '@/stores/workspaceStore'
import type { TreeNode } from '@/types/treeExplorerTypes'
import { TreeExplorerNode } from '@/types/treeExplorerTypes'
import { type TreeExplorerNode } from '@/types/treeExplorerTypes'
import { appendJsonExt } from '@/utils/formatUtil'
import { buildTree, sortedTree } from '@/utils/treeUtil'

View File

@@ -21,7 +21,7 @@
<script setup lang="ts">
import {
CSSProperties,
type CSSProperties,
computed,
nextTick,
onMounted,
@@ -32,7 +32,7 @@ import {
import TreeExplorerTreeNode from '@/components/common/TreeExplorerTreeNode.vue'
import { ComfyModelDef } from '@/stores/modelStore'
import { useSettingStore } from '@/stores/settingStore'
import { RenderedTreeExplorerNode } from '@/types/treeExplorerTypes'
import { type RenderedTreeExplorerNode } from '@/types/treeExplorerTypes'
import ModelPreview from './ModelPreview.vue'

View File

@@ -72,7 +72,7 @@ import ContextMenu from 'primevue/contextmenu'
import type { MenuItem } from 'primevue/menuitem'
import Tag from 'primevue/tag'
import {
CSSProperties,
type CSSProperties,
computed,
nextTick,
onMounted,
@@ -87,7 +87,7 @@ import { useNodeBookmarkStore } from '@/stores/nodeBookmarkStore'
import { ComfyNodeDefImpl } from '@/stores/nodeDefStore'
import { useSettingStore } from '@/stores/settingStore'
import { useSubgraphStore } from '@/stores/subgraphStore'
import { RenderedTreeExplorerNode } from '@/types/treeExplorerTypes'
import { type RenderedTreeExplorerNode } from '@/types/treeExplorerTypes'
const { t } = useI18n()

View File

@@ -78,7 +78,7 @@ import Button from 'primevue/button'
import Tag from 'primevue/tag'
import { computed, onMounted, onUnmounted, ref } from 'vue'
import { ComfyNode } from '@/schemas/comfyWorkflowSchema'
import { type ComfyNode } from '@/schemas/comfyWorkflowSchema'
import { api } from '@/scripts/api'
import { useLitegraphService } from '@/services/litegraphService'
import { TaskItemDisplayStatus, type TaskItemImpl } from '@/stores/queueStore'

View File

@@ -3,7 +3,7 @@ import { describe, expect, it, vi } from 'vitest'
import { ref } from 'vue'
import TemplateWorkflowCard from '@/components/templates/TemplateWorkflowCard.vue'
import { TemplateInfo } from '@/types/workflowTemplateTypes'
import { type TemplateInfo } from '@/types/workflowTemplateTypes'
vi.mock('@/components/templates/thumbnails/AudioThumbnail.vue', () => ({
default: {

View File

@@ -87,7 +87,7 @@ import CompareSliderThumbnail from '@/components/templates/thumbnails/CompareSli
import DefaultThumbnail from '@/components/templates/thumbnails/DefaultThumbnail.vue'
import HoverDissolveThumbnail from '@/components/templates/thumbnails/HoverDissolveThumbnail.vue'
import { useTemplateWorkflows } from '@/composables/useTemplateWorkflows'
import { TemplateInfo } from '@/types/workflowTemplateTypes'
import { type TemplateInfo } from '@/types/workflowTemplateTypes'
const UPSCALE_ZOOM_SCALE = 16 // for upscale templates, exaggerate the hover zoom
const DEFAULT_ZOOM_SCALE = 5

View File

@@ -3,7 +3,7 @@ import { describe, expect, it, vi } from 'vitest'
import { createI18n } from 'vue-i18n'
import TemplateWorkflowView from '@/components/templates/TemplateWorkflowView.vue'
import { TemplateInfo } from '@/types/workflowTemplateTypes'
import { type TemplateInfo } from '@/types/workflowTemplateTypes'
vi.mock('primevue/dataview', () => ({
default: {

View File

@@ -143,7 +143,7 @@ import SingleSelect from '@/components/input/SingleSelect.vue'
import BaseModalLayout from '@/components/widget/layout/BaseModalLayout.vue'
import LeftSidePanel from '@/components/widget/panel/LeftSidePanel.vue'
import RightSidePanel from '@/components/widget/panel/RightSidePanel.vue'
import { NavGroupData, NavItemData } from '@/types/navTypes'
import { type NavGroupData, type NavItemData } from '@/types/navTypes'
import { OnCloseKey } from '@/types/widgetTypes'
import { createGridStyle } from '@/utils/gridUtil'

View File

@@ -3,7 +3,7 @@
</template>
<script setup lang="ts">
import { NavItemData } from '@/types/navTypes'
import { type NavItemData } from '@/types/navTypes'
defineProps<{
icon: NavItemData['icon']

View File

@@ -18,7 +18,7 @@
</template>
<script setup lang="ts">
import { NavItemData } from '@/types/navTypes'
import { type NavItemData } from '@/types/navTypes'
import NavIcon from './NavIcon.vue'

View File

@@ -40,7 +40,7 @@ import { computed } from 'vue'
import NavItem from '@/components/widget/nav/NavItem.vue'
import NavTitle from '@/components/widget/nav/NavTitle.vue'
import { NavGroupData, NavItemData } from '@/types/navTypes'
import { type NavGroupData, type NavItemData } from '@/types/navTypes'
import PanelHeader from './PanelHeader.vue'

View File

@@ -3,7 +3,7 @@ import { useI18n } from 'vue-i18n'
import EssentialsPanel from '@/components/bottomPanel/tabs/shortcuts/EssentialsPanel.vue'
import ViewControlsPanel from '@/components/bottomPanel/tabs/shortcuts/ViewControlsPanel.vue'
import { BottomPanelExtension } from '@/types/extensionTypes'
import { type BottomPanelExtension } from '@/types/extensionTypes'
export const useShortcutsTab = (): BottomPanelExtension[] => {
const { t } = useI18n()

View File

@@ -2,7 +2,7 @@ import { FitAddon } from '@xterm/addon-fit'
import { Terminal } from '@xterm/xterm'
import '@xterm/xterm/css/xterm.css'
import { debounce } from 'es-toolkit/compat'
import { Ref, markRaw, onMounted, onUnmounted } from 'vue'
import { type Ref, markRaw, onMounted, onUnmounted } from 'vue'
export function useTerminal(element: Ref<HTMLElement | undefined>) {
const fitAddon = new FitAddon()

View File

@@ -3,7 +3,7 @@ import { useI18n } from 'vue-i18n'
import CommandTerminal from '@/components/bottomPanel/tabs/terminal/CommandTerminal.vue'
import LogsTerminal from '@/components/bottomPanel/tabs/terminal/LogsTerminal.vue'
import { BottomPanelExtension } from '@/types/extensionTypes'
import { type BottomPanelExtension } from '@/types/extensionTypes'
export const useLogsTerminalTab = (): BottomPanelExtension => {
const { t } = useI18n()

View File

@@ -1,7 +1,7 @@
import {
LGraphEventMode,
LGraphNode,
Positionable,
type Positionable,
Reroute
} from '@/lib/litegraph/src/litegraph'
import { useCanvasStore } from '@/renderer/core/canvas/canvasStore'

View File

@@ -1,4 +1,4 @@
import { CSSProperties, ref, watch } from 'vue'
import { type CSSProperties, ref, watch } from 'vue'
import { useCanvasPositionConversion } from '@/composables/element/useCanvasPositionConversion'
import type { Size, Vector2 } from '@/lib/litegraph/src/litegraph'

Some files were not shown because too many files have changed in this diff Show More