Devex: Linter updates (#7309)

## Summary

Updates for the linter/formatter deps, turning on some more rules.

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-7309-WIP-Linter-updates-2c56d73d36508101b3ece6bcaf7e5212)
by [Unito](https://www.unito.io)

---------

Co-authored-by: GitHub Action <action@github.com>
Co-authored-by: Christian Byrne <cbyrne@comfy.org>
This commit is contained in:
Alexander Brown
2025-12-10 11:08:47 -08:00
committed by GitHub
parent b52b2bbc30
commit 72b5444d5a
62 changed files with 1331 additions and 766 deletions

View File

@@ -13,14 +13,37 @@
"src/types/generatedManagerTypes.ts",
"src/types/vue-shim.d.ts"
],
"plugins": [
"eslint",
"import",
"oxc",
"typescript",
"unicorn",
"vitest",
"vue"
],
"rules": {
"no-async-promise-executor": "off",
"no-control-regex": "off",
"no-eval": "off",
"no-redeclare": "error",
"no-self-assign": "allow",
"no-unused-expressions": "off",
"no-unused-private-class-members": "off",
"no-useless-rename": "off",
"import/default": "error",
"import/export": "error",
"import/namespace": "error",
"import/no-duplicates": "error",
"import/consistent-type-specifier-style": [
"error",
"prefer-top-level"
],
"jest/expect-expect": "off",
"jest/no-conditional-expect": "off",
"jest/no-disabled-tests": "off",
"jest/no-standalone-expect": "off",
"jest/valid-title": "off",
"typescript/no-this-alias": "off",
"typescript/no-unnecessary-parameter-property-assignment": "off",
"typescript/no-unsafe-declaration-merging": "off",
@@ -39,6 +62,7 @@
"typescript/restrict-template-expressions": "off",
"typescript/unbound-method": "off",
"typescript/no-floating-promises": "error",
"vue/no-import-compiler-macros": "error"
"vue/no-import-compiler-macros": "error",
"vue/no-dupe-keys": "error"
}
}

View File

@@ -12,6 +12,9 @@
"declaration-property-value-no-unknown": [
true,
{
"typesSyntax": {
"radial-gradient()": "| <any-value>"
},
"ignoreProperties": {
"speak": ["none"],
"app-region": ["drag", "no-drag"],
@@ -56,10 +59,7 @@
"function-no-unknown": [
true,
{
"ignoreFunctions": [
"theme",
"v-bind"
]
"ignoreFunctions": ["theme", "v-bind"]
}
]
},

View File

@@ -135,7 +135,6 @@ export default defineConfig([
allowInterfaces: 'always'
}
],
'import-x/consistent-type-specifier-style': ['error', 'prefer-top-level'],
'import-x/no-useless-path-segments': 'error',
'import-x/no-relative-packages': 'error',
'unused-imports/no-unused-imports': 'error',
@@ -146,14 +145,13 @@ export default defineConfig([
'vue/multi-word-component-names': 'off', // TODO: fix
'vue/no-template-shadow': 'off', // TODO: fix
'vue/match-component-import-name': 'error',
/* Toggle on to do additional until we can clean up existing violations.
'vue/no-unused-emit-declarations': 'error',
'vue/no-unused-properties': 'error',
'vue/no-unused-refs': 'error',
'vue/no-use-v-else-with-v-for': 'error',
'vue/no-useless-mustaches': 'error',
'vue/no-useless-v-bind': 'error',
// */
'vue/one-component-per-file': 'off', // TODO: fix
'vue/no-unused-emit-declarations': 'error',
'vue/no-use-v-else-with-v-for': 'error',
'vue/one-component-per-file': 'error',
'vue/require-default-prop': 'off', // TODO: fix -- this one is very worthwhile
// Restrict deprecated PrimeVue components
'no-restricted-imports': [
@@ -297,5 +295,14 @@ export default defineConfig([
// Turn off ESLint rules that are already handled by oxlint
...oxlint.buildFromOxlintConfigFile(
path.resolve(import.meta.dirname, '.oxlintrc.json')
)
),
{
rules: {
'import-x/default': 'off',
'import-x/export': 'off',
'import-x/namespace': 'off',
'import-x/no-duplicates': 'off',
'import-x/consistent-type-specifier-style': 'off'
}
}
])

1648
pnpm-lock.yaml generated

File diff suppressed because it is too large Load Diff

View File

@@ -5,7 +5,7 @@ packages:
catalog:
'@alloc/quick-lru': ^5.2.0
'@comfyorg/comfyui-electron-types': 0.5.5
'@eslint/js': ^9.35.0
'@eslint/js': ^9.39.1
'@iconify-json/lucide': ^1.1.178
'@iconify/json': ^2.2.380
'@iconify/tailwind': ^1.1.3
@@ -17,7 +17,7 @@ catalog:
'@nx/vite': 21.4.1
'@pinia/testing': ^0.1.5
'@playwright/test': ^1.52.0
'@prettier/plugin-oxc': ^0.0.4
'@prettier/plugin-oxc': ^0.1.3
'@primeuix/forms': 0.0.2
'@primeuix/styled': 0.3.2
'@primeuix/utils': ^0.3.2
@@ -48,15 +48,15 @@ catalog:
axios: ^1.8.2
cross-env: ^10.1.0
dotenv: ^16.4.5
eslint: ^9.34.0
eslint: ^9.39.1
eslint-config-prettier: ^10.1.8
eslint-import-resolver-typescript: ^4.4.4
eslint-plugin-import-x: ^4.16.1
eslint-plugin-oxlint: 1.25.0
eslint-plugin-prettier: ^5.5.4
eslint-plugin-storybook: ^9.1.6
eslint-plugin-unused-imports: ^4.2.0
eslint-plugin-vue: ^10.4.0
eslint-plugin-storybook: ^9.1.16
eslint-plugin-unused-imports: ^4.3.0
eslint-plugin-vue: ^10.6.2
firebase: ^11.6.0
globals: ^15.9.0
happy-dom: ^15.11.0
@@ -64,29 +64,29 @@ catalog:
jiti: 2.4.2
jsdom: ^26.1.0
knip: ^5.62.0
lint-staged: ^15.2.7
lint-staged: ^15.5.2
markdown-table: ^3.0.4
mixpanel-browser: ^2.71.0
nx: 21.4.1
oxlint: ^1.25.0
oxlint-tsgolint: ^0.4.0
oxlint: ^1.32.0
oxlint-tsgolint: ^0.8.4
picocolors: ^1.1.1
pinia: ^2.1.7
postcss-html: ^1.8.0
prettier: ^3.6.2
prettier: ^3.7.4
pretty-bytes: ^7.1.0
primeicons: ^7.0.0
primevue: ^4.2.5
rollup-plugin-visualizer: ^6.0.4
storybook: ^9.1.6
stylelint: ^16.24.0
storybook: ^9.1.16
stylelint: ^16.26.1
tailwindcss: ^4.1.12
tailwindcss-primeui: ^0.6.1
tsx: ^4.15.6
tw-animate-css: ^1.3.8
typegpu: ^0.8.2
typescript: ^5.9.2
typescript-eslint: ^8.44.0
typescript: ^5.9.3
typescript-eslint: ^8.49.0
unplugin-icons: ^0.22.0
unplugin-typegpu: 0.8.0
unplugin-vue-components: ^0.28.0
@@ -100,7 +100,7 @@ catalog:
vue-eslint-parser: ^10.2.0
vue-i18n: ^9.14.3
vue-router: ^4.4.3
vue-tsc: ^3.0.7
vue-tsc: ^3.1.8
vuefire: ^3.2.1
yjs: ^13.6.27
zod: ^3.23.8

View File

@@ -55,7 +55,6 @@ import { normalizeI18nKey } from '@/utils/formatUtil'
const { t } = useI18n()
const { subcategories } = defineProps<{
commands: ComfyCommandImpl[]
subcategories: Record<string, ComfyCommandImpl[]>
}>()

View File

@@ -21,7 +21,7 @@
class="icon-[lucide--triangle-alert] text-warning-background"
/>
<span class="p-breadcrumb-item-label px-2">{{ item.label }}</span>
<Tag v-if="item.isBlueprint" :value="'Blueprint'" severity="primary" />
<Tag v-if="item.isBlueprint" value="Blueprint" severity="primary" />
<i v-if="isActive" class="pi pi-angle-down text-[10px]"></i>
</a>
<Menu

View File

@@ -41,7 +41,7 @@ const {
inputAttrs?: Record<string, string>
}>()
const emit = defineEmits(['update:modelValue', 'edit', 'cancel'])
const emit = defineEmits(['edit', 'cancel'])
const inputValue = ref<string>(modelValue)
const inputRef = ref<InstanceType<typeof InputText> | undefined>()
const isCanceling = ref(false)

View File

@@ -11,7 +11,6 @@ import InputText from 'primevue/inputtext'
const modelValue = defineModel<string>('modelValue')
defineProps<{
defaultValue?: string
label?: string
}>()

View File

@@ -5,7 +5,7 @@
icon="pi pi-exclamation-circle"
:title="title"
:message="error.exceptionMessage"
:text-class="'break-words max-w-[60vw]'"
text-class="break-words max-w-[60vw]"
/>
<template v-if="error.extensionFile">
<span>{{ t('errorDialog.extensionFileHint') }}:</span>

View File

@@ -465,9 +465,8 @@ onMounted(async () => {
await workflowPersistence.loadTemplateFromUrlIfPresent()
// Initialize release store to fetch releases from comfy-api (fire-and-forget)
const { useReleaseStore } = await import(
'@/platform/updates/common/releaseStore'
)
const { useReleaseStore } =
await import('@/platform/updates/common/releaseStore')
const releaseStore = useReleaseStore()
void releaseStore.initialize()

View File

@@ -37,7 +37,6 @@
</Button>
<Button
ref="zoomButton"
v-tooltip.top="t('zoomControls.label')"
severity="secondary"
:label="t('zoomControls.label')"
@@ -56,7 +55,6 @@
<div class="h-[27px] w-[1px] self-center bg-node-divider" />
<Button
ref="minimapButton"
v-tooltip.top="minimapTooltip"
severity="secondary"
:aria-label="minimapTooltip"

View File

@@ -2,7 +2,7 @@
<div>
<Popover
ref="popover"
:append-to="'body'"
append-to="body"
:auto-z-index="true"
:base-z-index="1000"
:dismissable="true"

View File

@@ -21,7 +21,6 @@ import { linkifyHtml, nl2br } from '@/utils/formatUtil'
const modelValue = defineModel<string>({ required: true })
const props = defineProps<{
widget?: object
nodeId: NodeId
}>()

View File

@@ -35,7 +35,6 @@
<div v-show="activeCategory" class="rounded-lg bg-smoke-700/30">
<SceneControls
v-if="showSceneControls"
ref="sceneControlsRef"
v-model:show-grid="sceneConfig!.showGrid"
v-model:background-color="sceneConfig!.backgroundColor"
v-model:background-image="sceneConfig!.backgroundImage"
@@ -46,28 +45,24 @@
<ModelControls
v-if="showModelControls"
ref="modelControlsRef"
v-model:material-mode="modelConfig!.materialMode"
v-model:up-direction="modelConfig!.upDirection"
/>
<CameraControls
v-if="showCameraControls"
ref="cameraControlsRef"
v-model:camera-type="cameraConfig!.cameraType"
v-model:fov="cameraConfig!.fov"
/>
<LightControls
v-if="showLightControls"
ref="lightControlsRef"
v-model:light-intensity="lightConfig!.intensity"
v-model:material-mode="modelConfig!.materialMode"
/>
<ExportControls
v-if="showExportControls"
ref="exportControlsRef"
@export-model="handleExportModel"
/>
</div>

View File

@@ -9,8 +9,7 @@
<span class="inline-flex items-center gap-2">
<span v-if="props.mode === 'allFailed'" class="inline-flex items-center">
<i
class="ml-1 icon-[lucide--circle-alert] block size-4 leading-none"
:class="'text-destructive-background'"
class="ml-1 icon-[lucide--circle-alert] block size-4 leading-none text-destructive-background"
/>
</span>

View File

@@ -64,8 +64,7 @@ export const RunningWithCurrent: Story = {
state: 'running',
title: 'Generating image',
progressTotalPercent: 66,
progressCurrentPercent: 10,
runningNodeName: 'KSampler'
progressCurrentPercent: 10
}
}

View File

@@ -225,7 +225,6 @@ const props = withDefaults(
showMenu?: boolean
progressTotalPercent?: number
progressCurrentPercent?: number
runningNodeName?: string
activeDetailsId?: string | null
}>(),
{

View File

@@ -7,7 +7,6 @@ import type { ClassValue } from '@/utils/tailwindUtil'
const props = defineProps<{
nodeTitle: string
widgetName: string
isShown?: boolean
isDraggable?: boolean
isPhysical?: boolean
class?: ClassValue

View File

@@ -49,7 +49,7 @@
auto-option-focus
force-selection
multiple
:option-label="'display_name'"
option-label="display_name"
@complete="search($event.query)"
@option-select="onAddNode($event.value)"
@focused-option-changed="setHoverSuggestion($event)"

View File

@@ -59,7 +59,6 @@ interface WorkflowOption {
}
const props = defineProps<{
class?: string
workflowOption: WorkflowOption
}>()

View File

@@ -14,6 +14,7 @@ import type { HTMLAttributes } from 'vue'
import { cn } from '@/utils/tailwindUtil'
const props = defineProps<
// eslint-disable-next-line vue/no-unused-properties
SliderRootProps & { class?: HTMLAttributes['class'] }
>()

View File

@@ -249,9 +249,7 @@ const link_bounding = new Rectangle()
* This class is in charge of rendering one graph inside a canvas. And provides all the interaction required.
* Valid callbacks are: onNodeSelected, onNodeDeselected, onShowNodePanel, onNodeDblClicked
*/
export class LGraphCanvas
implements CustomEventDispatcher<LGraphCanvasEventMap>
{
export class LGraphCanvas implements CustomEventDispatcher<LGraphCanvasEventMap> {
static DEFAULT_BACKGROUND_IMAGE =
'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGQAAABkCAIAAAD/gAIDAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAQBJREFUeNrs1rEKwjAUhlETUkj3vP9rdmr1Ysammk2w5wdxuLgcMHyptfawuZX4pJSWZTnfnu/lnIe/jNNxHHGNn//HNbbv+4dr6V+11uF527arU7+u63qfa/bnmh8sWLBgwYJlqRf8MEptXPBXJXa37BSl3ixYsGDBMliwFLyCV/DeLIMFCxYsWLBMwSt4Be/NggXLYMGCBUvBK3iNruC9WbBgwYJlsGApeAWv4L1ZBgsWLFiwYJmCV/AK3psFC5bBggULloJX8BpdwXuzYMGCBctgwVLwCl7Be7MMFixYsGDBsu8FH1FaSmExVfAxBa/gvVmwYMGCZbBg/W4vAQYA5tRF9QYlv/QAAAAASUVORK5CYII='

View File

@@ -2,9 +2,9 @@
* Temporary workaround until downstream consumers migrate to Map.
* A brittle wrapper with many flaws, but should be fine for simple maps using int indexes.
*/
export class MapProxyHandler<V>
implements ProxyHandler<Map<number | string, V>>
{
export class MapProxyHandler<V> implements ProxyHandler<
Map<number | string, V>
> {
getOwnPropertyDescriptor(
target: Map<number | string, V>,
p: string | symbol

View File

@@ -81,9 +81,9 @@ export interface CustomEventDispatcher<
* ```
*/
export class CustomEventTarget<
EventMap extends Record<Keys, unknown>,
Keys extends keyof EventMap & string = keyof EventMap & string
>
EventMap extends Record<Keys, unknown>,
Keys extends keyof EventMap & string = keyof EventMap & string
>
extends EventTarget
implements ICustomEventTarget<EventMap, Keys>
{

View File

@@ -380,8 +380,10 @@ interface IContextMenuBase {
}
/** ContextMenu */
export interface IContextMenuOptions<TValue = unknown, TExtra = unknown>
extends IContextMenuBase {
export interface IContextMenuOptions<
TValue = unknown,
TExtra = unknown
> extends IContextMenuBase {
ignore_item_callbacks?: boolean
parentMenu?: ContextMenu<TValue>
event?: MouseEvent
@@ -426,13 +428,15 @@ export interface IContextMenuValue<
): void | boolean | Promise<void | boolean>
}
interface IContextMenuSubmenu<TValue = unknown>
extends IContextMenuOptions<TValue> {
interface IContextMenuSubmenu<
TValue = unknown
> extends IContextMenuOptions<TValue> {
options: ConstructorParameters<typeof ContextMenu<TValue>>[0]
}
export interface ContextMenuDivElement<TValue = unknown>
extends HTMLDivElement {
export interface ContextMenuDivElement<
TValue = unknown
> extends HTMLDivElement {
value?: string | IContextMenuValue<TValue>
onclick_callback?: never
}

View File

@@ -30,8 +30,8 @@ import type { SubgraphInput } from './SubgraphInput'
import type { SubgraphOutput } from './SubgraphOutput'
export abstract class SubgraphIONodeBase<
TSlot extends SubgraphInput | SubgraphOutput
>
TSlot extends SubgraphInput | SubgraphOutput
>
implements Positionable, Hoverable, Serialisable<ExportedSubgraphIONode>
{
static margin = 10

View File

@@ -46,9 +46,7 @@ export interface CanvasPointerEvent extends PointerEvent, CanvasMouseEvent {}
/** MouseEvent with canvasX/Y and deltaX/Y properties */
interface CanvasMouseEvent
extends MouseEvent,
Readonly<CanvasPointerExtensions>,
LegacyMouseEvent {}
extends MouseEvent, Readonly<CanvasPointerExtensions>, LegacyMouseEvent {}
export type CanvasEventDetail =
| GenericEventDetail

View File

@@ -94,27 +94,32 @@ export interface INumericWidget extends IBaseWidget<number, 'number'> {
value: number
}
export interface ISliderWidget
extends IBaseWidget<number, 'slider', IWidgetSliderOptions> {
export interface ISliderWidget extends IBaseWidget<
number,
'slider',
IWidgetSliderOptions
> {
type: 'slider'
value: number
marker?: number
}
export interface IKnobWidget
extends IBaseWidget<number, 'knob', IWidgetKnobOptions> {
export interface IKnobWidget extends IBaseWidget<
number,
'knob',
IWidgetKnobOptions
> {
type: 'knob'
value: number
options: IWidgetKnobOptions
}
/** Avoids the type issues with the legacy IComboWidget type */
export interface IStringComboWidget
extends IBaseWidget<
string,
'combo',
RequiredProps<IWidgetOptions<string[]>, 'values'>
> {
export interface IStringComboWidget extends IBaseWidget<
string,
'combo',
RequiredProps<IWidgetOptions<string[]>, 'values'>
> {
type: 'combo'
value: string
}
@@ -125,25 +130,29 @@ type ComboWidgetValues =
| ((widget?: IComboWidget, node?: LGraphNode) => string[])
/** A combo-box widget (dropdown, select, etc) */
export interface IComboWidget
extends IBaseWidget<
string | number,
'combo',
RequiredProps<IWidgetOptions<ComboWidgetValues>, 'values'>
> {
export interface IComboWidget extends IBaseWidget<
string | number,
'combo',
RequiredProps<IWidgetOptions<ComboWidgetValues>, 'values'>
> {
type: 'combo'
value: string | number
}
/** A widget with a string value */
export interface IStringWidget
extends IBaseWidget<string, 'string' | 'text', IWidgetOptions<string[]>> {
export interface IStringWidget extends IBaseWidget<
string,
'string' | 'text',
IWidgetOptions<string[]>
> {
type: 'string' | 'text'
value: string
}
export interface IButtonWidget
extends IBaseWidget<string | undefined, 'button'> {
export interface IButtonWidget extends IBaseWidget<
string | undefined,
'button'
> {
type: 'button'
value: string | undefined
clicked: boolean
@@ -181,15 +190,19 @@ interface IImageWidget extends IBaseWidget<string, 'image'> {
}
/** Tree select widget for hierarchical selection */
export interface ITreeSelectWidget
extends IBaseWidget<string | string[], 'treeselect'> {
export interface ITreeSelectWidget extends IBaseWidget<
string | string[],
'treeselect'
> {
type: 'treeselect'
value: string | string[]
}
/** Multi-select widget for selecting multiple options */
export interface IMultiSelectWidget
extends IBaseWidget<string[], 'multiselect'> {
export interface IMultiSelectWidget extends IBaseWidget<
string[],
'multiselect'
> {
type: 'multiselect'
value: string[]
}
@@ -207,19 +220,20 @@ export interface IGalleriaWidget extends IBaseWidget<string[], 'galleria'> {
}
/** Image comparison widget for comparing two images side by side */
export interface IImageCompareWidget
extends IBaseWidget<string[], 'imagecompare'> {
export interface IImageCompareWidget extends IBaseWidget<
string[],
'imagecompare'
> {
type: 'imagecompare'
value: string[]
}
/** Select button widget for selecting from a group of buttons */
export interface ISelectButtonWidget
extends IBaseWidget<
string,
'selectbutton',
RequiredProps<IWidgetOptions<string[]>, 'values'>
> {
export interface ISelectButtonWidget extends IBaseWidget<
string,
'selectbutton',
RequiredProps<IWidgetOptions<string[]>, 'values'>
> {
type: 'selectbutton'
value: string
}
@@ -230,8 +244,11 @@ export interface ITextareaWidget extends IBaseWidget<string, 'textarea'> {
value: string
}
export interface IAssetWidget
extends IBaseWidget<string, 'asset', IWidgetOptions<string[]>> {
export interface IAssetWidget extends IBaseWidget<
string,
'asset',
IWidgetOptions<string[]>
> {
type: 'asset'
value: string
}

View File

@@ -33,9 +33,9 @@ export interface WidgetEventOptions {
canvas: LGraphCanvas
}
export abstract class BaseWidget<TWidget extends IBaseWidget = IBaseWidget>
implements IBaseWidget
{
export abstract class BaseWidget<
TWidget extends IBaseWidget = IBaseWidget
> implements IBaseWidget {
/** From node edge to widget edge */
static margin = 15
/** From widget edge to tip of arrow button */

View File

@@ -27,9 +27,8 @@ import { i18n } from './i18n'
import { isCloud } from '@/platform/distribution/types'
if (isCloud) {
const { loadRemoteConfig } = await import(
'@/platform/remoteConfig/remoteConfig'
)
const { loadRemoteConfig } =
await import('@/platform/remoteConfig/remoteConfig')
await loadRemoteConfig()
}

View File

@@ -85,7 +85,6 @@ import { OnCloseKey } from '@/types/widgetTypes'
const props = defineProps<{
nodeType?: string
inputName?: string
onSelect?: (asset: AssetItem) => void
onClose?: () => void
showLeftPanel?: boolean

View File

@@ -44,7 +44,6 @@ TODO: Extract checkbox pattern into reusable Checkbox component
<script setup lang="ts">
const { mediaTypeFilters } = defineProps<{
mediaTypeFilters: string[]
close: () => void
}>()
const emit = defineEmits<{

View File

@@ -6,7 +6,7 @@
<Popover
ref="popover"
:append-to="'body'"
append-to="body"
:auto-z-index="true"
:base-z-index="1000"
:dismissable="true"

View File

@@ -16,12 +16,11 @@ import { computed } from 'vue'
import { formatSize, getFilenameDetails } from '@/utils/formatUtil'
import type { AssetContext, AssetMeta } from '../schemas/mediaAssetSchema'
import type { AssetMeta } from '../schemas/mediaAssetSchema'
import MediaTitle from './MediaTitle.vue'
const { asset } = defineProps<{
asset: AssetMeta
context: AssetContext
}>()
const fileName = computed(() => {

View File

@@ -14,12 +14,11 @@ import { computed } from 'vue'
import { getFilenameDetails } from '@/utils/formatUtil'
import type { AssetContext, AssetMeta } from '../schemas/mediaAssetSchema'
import type { AssetMeta } from '../schemas/mediaAssetSchema'
import MediaTitle from './MediaTitle.vue'
const { asset } = defineProps<{
asset: AssetMeta
context: AssetContext
}>()
const fileName = computed(() => {

View File

@@ -13,12 +13,11 @@ import { computed } from 'vue'
import { formatSize, getFilenameDetails } from '@/utils/formatUtil'
import type { AssetContext, AssetMeta } from '../schemas/mediaAssetSchema'
import type { AssetMeta } from '../schemas/mediaAssetSchema'
import MediaTitle from './MediaTitle.vue'
const { asset } = defineProps<{
asset: AssetMeta
context: AssetContext
}>()
const fileName = computed(() => {

View File

@@ -5,7 +5,6 @@
@mouseleave="isHovered = false"
>
<video
ref="videoRef"
:controls="shouldShowControls"
preload="metadata"
autoplay
@@ -27,20 +26,17 @@
<script setup lang="ts">
import { computed, onMounted, ref, watch } from 'vue'
import type { AssetContext, AssetMeta } from '../schemas/mediaAssetSchema'
import type { AssetMeta } from '../schemas/mediaAssetSchema'
const { asset } = defineProps<{
asset: AssetMeta
context: AssetContext
}>()
const emit = defineEmits<{
play: [assetId: string]
videoPlayingStateChanged: [isPlaying: boolean]
videoControlsChanged: [showControls: boolean]
}>()
const videoRef = ref<HTMLVideoElement>()
const isHovered = ref(false)
const isPlaying = ref(false)

View File

@@ -14,9 +14,8 @@ export const cloudOnboardingRoutes: RouteRecordRaw[] = [
beforeEnter: async (to, _from, next) => {
// Only redirect if not explicitly switching accounts
if (!to.query.switchAccount) {
const { useCurrentUser } = await import(
'@/composables/auth/useCurrentUser'
)
const { useCurrentUser } =
await import('@/composables/auth/useCurrentUser')
const { isLoggedIn } = useCurrentUser()
if (isLoggedIn.value) {

View File

@@ -28,9 +28,7 @@ export const useSubscriptionDialog = () => {
key: DIALOG_KEY,
component: defineAsyncComponent(
() =>
import(
'@/platform/cloud/subscription/components/SubscriptionRequiredDialogContent.vue'
)
import('@/platform/cloud/subscription/components/SubscriptionRequiredDialogContent.vue')
),
props: {
onClose: hide

View File

@@ -100,9 +100,7 @@ export function useSettingUI(
},
component: defineAsyncComponent(
() =>
import(
'@/platform/cloud/subscription/components/SubscriptionPanel.vue'
)
import('@/platform/cloud/subscription/components/SubscriptionPanel.vue')
)
}

View File

@@ -181,7 +181,6 @@ import NodeWidgets from './NodeWidgets.vue'
interface LGraphNodeProps {
nodeData: VueNodeData
error?: string | null
zoomLevel?: number
}
const { nodeData, error = null } = defineProps<LGraphNodeProps>()

View File

@@ -1,3 +1,4 @@
/* eslint-disable vue/one-component-per-file */
import { mount } from '@vue/test-utils'
import { createPinia } from 'pinia'
import { describe, expect, it } from 'vitest'

View File

@@ -9,7 +9,6 @@ import type { SimplifiedWidget } from '@/types/simplifiedWidget'
const props = defineProps<{
widget: SimplifiedWidget<void>
nodeId: string
readonly?: boolean
}>()
const domEl = ref<HTMLElement>()

View File

@@ -14,7 +14,6 @@ import type { SimplifiedWidget } from '@/types/simplifiedWidget'
const props = defineProps<{
widget: SimplifiedWidget<void>
readonly?: boolean
}>()
const canvasEl = ref()

View File

@@ -92,7 +92,6 @@ import type { IBaseWidget } from '@/lib/litegraph/src/types/widgets'
import { useToastStore } from '@/platform/updates/common/toastStore'
import { app } from '@/scripts/app'
import { useAudioService } from '@/services/audioService'
import type { SimplifiedWidget } from '@/types/simplifiedWidget'
import { useAudioPlayback } from '../composables/audio/useAudioPlayback'
import { useAudioRecorder } from '../composables/audio/useAudioRecorder'
@@ -100,7 +99,6 @@ import { useAudioWaveform } from '../composables/audio/useAudioWaveform'
import { formatTime } from '../utils/audioUtils'
const props = defineProps<{
widget: SimplifiedWidget<string | number | undefined>
readonly?: boolean
nodeId: string
}>()

View File

@@ -82,7 +82,6 @@
<!-- Options Button -->
<div
v-if="showOptionsButton"
ref="optionsButtonRef"
role="button"
:tabindex="0"
:aria-label="$t('g.moreOptions')"
@@ -155,10 +154,8 @@ const { t } = useI18n()
const props = withDefaults(
defineProps<{
readonly?: boolean
hideWhenEmpty?: boolean
showOptionsButton?: boolean
modelValue?: string
nodeId?: string
audioUrl?: string
}>(),
@@ -170,7 +167,6 @@ const props = withDefaults(
// Refs
const audioRef = ref<HTMLAudioElement>()
const optionsMenu = ref()
const optionsButtonRef = ref<HTMLElement>()
const isPlaying = ref(false)
const isMuted = ref(false)
const volume = ref(1)

View File

@@ -9,7 +9,6 @@ import type { DropdownItem, SelectedKey } from './types'
interface Props {
isOpen?: boolean
placeholder?: string
files: File[]
items: DropdownItem[]
selected: Set<SelectedKey>
maxSelectable: number

View File

@@ -169,9 +169,8 @@ if (isCloud) {
// For root path, check actual user status to handle waitlisted users
if (!isElectron() && isLoggedIn && to.path === '/') {
// Import auth functions dynamically to avoid circular dependency
const { getSurveyCompletedStatus } = await import(
'@/platform/cloud/onboarding/auth'
)
const { getSurveyCompletedStatus } =
await import('@/platform/cloud/onboarding/auth')
try {
// Check user's actual status
const surveyCompleted = await getSurveyCompletedStatus()

View File

@@ -15,8 +15,9 @@ import type { InputSpec } from '@/schemas/nodeDef/nodeDefSchemaV2'
import { useDomWidgetStore } from '@/stores/domWidgetStore'
import { generateUUID } from '@/utils/formatUtil'
export interface BaseDOMWidget<V extends object | string = object | string>
extends IBaseWidget<V, string, DOMWidgetOptions<V>> {
export interface BaseDOMWidget<
V extends object | string = object | string
> extends IBaseWidget<V, string, DOMWidgetOptions<V>> {
// ICustomWidget properties
type: string
options: DOMWidgetOptions<V>
@@ -37,8 +38,10 @@ export interface BaseDOMWidget<V extends object | string = object | string>
/**
* A DOM widget that wraps a custom HTML element as a litegraph widget.
*/
export interface DOMWidget<T extends HTMLElement, V extends object | string>
extends BaseDOMWidget<V> {
export interface DOMWidget<
T extends HTMLElement,
V extends object | string
> extends BaseDOMWidget<V> {
element: T
/**
* @deprecated Legacy property used by some extensions for customtext
@@ -78,8 +81,9 @@ export interface ComponentWidget<
readonly props?: P
}
export interface DOMWidgetOptions<V extends object | string>
extends IWidgetOptions {
export interface DOMWidgetOptions<
V extends object | string
> extends IWidgetOptions {
/**
* Whether to render a placeholder rectangle when zoomed out.
*/
@@ -286,9 +290,9 @@ export class DOMWidgetImpl<T extends HTMLElement, V extends object | string>
}
export class ComponentWidgetImpl<
V extends object | string,
P extends ComponentWidgetCustomProps = ComponentWidgetCustomProps
>
V extends object | string,
P extends ComponentWidgetCustomProps = ComponentWidgetCustomProps
>
extends BaseDOMWidgetImpl<V>
implements ComponentWidget<V, P>
{

View File

@@ -535,9 +535,8 @@ export const useDialogService = () => {
return
}
const { useSubscriptionDialog } = await import(
'@/platform/cloud/subscription/composables/useSubscriptionDialog'
)
const { useSubscriptionDialog } =
await import('@/platform/cloud/subscription/composables/useSubscriptionDialog')
const { show } = useSubscriptionDialog()
show()
}

View File

@@ -5,8 +5,10 @@ import { computed, ref } from 'vue'
import { electronAPI, isElectron } from '@/utils/envUtil'
export interface ElectronDownload
extends Pick<DownloadState, 'url' | 'filename'> {
export interface ElectronDownload extends Pick<
DownloadState,
'url' | 'filename'
> {
progress?: number
savePath?: string
status?: DownloadStatus

View File

@@ -549,9 +549,8 @@ export function useConflictDetection() {
async function initializeConflictDetection(): Promise<void> {
try {
// Check if manager is new Manager before proceeding
const { useManagerState } = await import(
'@/workbench/extensions/manager/composables/useManagerState'
)
const { useManagerState } =
await import('@/workbench/extensions/manager/composables/useManagerState')
const managerState = useManagerState()
if (!managerState.isNewManagerUI.value) {

View File

@@ -61,13 +61,6 @@ describe('EssentialsPanel', () => {
const shortcutsList = wrapper.findComponent(ShortcutsList)
expect(shortcutsList.exists()).toBe(true)
// Should pass only essentials commands
const commands = shortcutsList.props('commands')
expect(commands).toHaveLength(3)
commands.forEach((cmd: ComfyCommandImpl) => {
expect(cmd.category).toBe('essentials')
})
})
it('should categorize commands into subcategories', () => {

View File

@@ -18,9 +18,8 @@ describe('useConflictAcknowledgment', () => {
describe('initial state loading', () => {
it('should load empty state when localStorage is empty', async () => {
vi.resetModules()
const { useConflictAcknowledgment } = await import(
'@/workbench/extensions/manager/composables/useConflictAcknowledgment'
)
const { useConflictAcknowledgment } =
await import('@/workbench/extensions/manager/composables/useConflictAcknowledgment')
const { acknowledgmentState } = useConflictAcknowledgment()
expect(acknowledgmentState.value).toEqual({
@@ -44,9 +43,8 @@ describe('useConflictAcknowledgment', () => {
// Need to import the module after localStorage is set
vi.resetModules()
const { useConflictAcknowledgment } = await import(
'@/workbench/extensions/manager/composables/useConflictAcknowledgment'
)
const { useConflictAcknowledgment } =
await import('@/workbench/extensions/manager/composables/useConflictAcknowledgment')
const { acknowledgmentState } = useConflictAcknowledgment()
expect(acknowledgmentState.value).toEqual({
@@ -60,9 +58,8 @@ describe('useConflictAcknowledgment', () => {
describe('dismissal functions', () => {
it('should mark conflicts as seen with unified function', async () => {
vi.resetModules()
const { useConflictAcknowledgment } = await import(
'@/workbench/extensions/manager/composables/useConflictAcknowledgment'
)
const { useConflictAcknowledgment } =
await import('@/workbench/extensions/manager/composables/useConflictAcknowledgment')
const { markConflictsAsSeen, acknowledgmentState } =
useConflictAcknowledgment()
@@ -73,9 +70,8 @@ describe('useConflictAcknowledgment', () => {
it('should dismiss red dot notification', async () => {
vi.resetModules()
const { useConflictAcknowledgment } = await import(
'@/workbench/extensions/manager/composables/useConflictAcknowledgment'
)
const { useConflictAcknowledgment } =
await import('@/workbench/extensions/manager/composables/useConflictAcknowledgment')
const { dismissRedDotNotification, acknowledgmentState } =
useConflictAcknowledgment()
@@ -86,9 +82,8 @@ describe('useConflictAcknowledgment', () => {
it('should dismiss warning banner', async () => {
vi.resetModules()
const { useConflictAcknowledgment } = await import(
'@/workbench/extensions/manager/composables/useConflictAcknowledgment'
)
const { useConflictAcknowledgment } =
await import('@/workbench/extensions/manager/composables/useConflictAcknowledgment')
const { dismissWarningBanner, acknowledgmentState } =
useConflictAcknowledgment()
@@ -99,9 +94,8 @@ describe('useConflictAcknowledgment', () => {
it('should mark all conflicts as seen', async () => {
vi.resetModules()
const { useConflictAcknowledgment } = await import(
'@/workbench/extensions/manager/composables/useConflictAcknowledgment'
)
const { useConflictAcknowledgment } =
await import('@/workbench/extensions/manager/composables/useConflictAcknowledgment')
const { markConflictsAsSeen, acknowledgmentState } =
useConflictAcknowledgment()
@@ -117,9 +111,8 @@ describe('useConflictAcknowledgment', () => {
it('should calculate shouldShowConflictModal correctly', async () => {
// Need fresh module import to ensure clean state
vi.resetModules()
const { useConflictAcknowledgment } = await import(
'@/workbench/extensions/manager/composables/useConflictAcknowledgment'
)
const { useConflictAcknowledgment } =
await import('@/workbench/extensions/manager/composables/useConflictAcknowledgment')
const { shouldShowConflictModal, markConflictsAsSeen } =
useConflictAcknowledgment()
@@ -131,9 +124,8 @@ describe('useConflictAcknowledgment', () => {
it('should calculate shouldShowRedDot correctly based on conflicts', async () => {
vi.resetModules()
const { useConflictAcknowledgment } = await import(
'@/workbench/extensions/manager/composables/useConflictAcknowledgment'
)
const { useConflictAcknowledgment } =
await import('@/workbench/extensions/manager/composables/useConflictAcknowledgment')
const { shouldShowRedDot, dismissRedDotNotification } =
useConflictAcknowledgment()
@@ -146,9 +138,8 @@ describe('useConflictAcknowledgment', () => {
it('should calculate shouldShowManagerBanner correctly', async () => {
vi.resetModules()
const { useConflictAcknowledgment } = await import(
'@/workbench/extensions/manager/composables/useConflictAcknowledgment'
)
const { useConflictAcknowledgment } =
await import('@/workbench/extensions/manager/composables/useConflictAcknowledgment')
const { shouldShowManagerBanner, dismissWarningBanner } =
useConflictAcknowledgment()
@@ -164,9 +155,8 @@ describe('useConflictAcknowledgment', () => {
it('should persist to localStorage automatically', async () => {
// Need fresh module import to ensure clean state
vi.resetModules()
const { useConflictAcknowledgment } = await import(
'@/workbench/extensions/manager/composables/useConflictAcknowledgment'
)
const { useConflictAcknowledgment } =
await import('@/workbench/extensions/manager/composables/useConflictAcknowledgment')
const { markConflictsAsSeen, dismissWarningBanner } =
useConflictAcknowledgment()

View File

@@ -153,9 +153,8 @@ vi.mock('@/platform/workflow/management/stores/workflowStore', () => ({
}))
}))
const { useMinimap } = await import(
'@/renderer/extensions/minimap/composables/useMinimap'
)
const { useMinimap } =
await import('@/renderer/extensions/minimap/composables/useMinimap')
const { api } = await import('@/scripts/api')
describe('useMinimap', () => {

View File

@@ -29,9 +29,8 @@ vi.mock('@/platform/telemetry', () => ({
}))
}))
const { useTemplateFiltering } = await import(
'@/composables/useTemplateFiltering'
)
const { useTemplateFiltering } =
await import('@/composables/useTemplateFiltering')
describe('useTemplateFiltering', () => {
beforeEach(() => {

View File

@@ -103,9 +103,8 @@ describe('useMinimapRenderer', () => {
})
it('should only render when redraw is needed', async () => {
const { renderMinimapToCanvas } = await import(
'@/renderer/extensions/minimap/minimapCanvasRenderer'
)
const { renderMinimapToCanvas } =
await import('@/renderer/extensions/minimap/minimapCanvasRenderer')
const canvasRef = ref(mockCanvas)
const graphRef = ref(mockGraph as any)
const boundsRef = ref({ minX: 0, minY: 0, width: 100, height: 100 })

View File

@@ -66,9 +66,8 @@ describe('useMinimapViewport', () => {
})
it('should calculate graph bounds from nodes', async () => {
const { calculateNodeBounds, enforceMinimumBounds } = await import(
'@/renderer/core/spatial/boundsCalculator'
)
const { calculateNodeBounds, enforceMinimumBounds } =
await import('@/renderer/core/spatial/boundsCalculator')
vi.mocked(calculateNodeBounds).mockReturnValue({
minX: 100,
@@ -93,9 +92,8 @@ describe('useMinimapViewport', () => {
})
it('should handle empty graph', async () => {
const { calculateNodeBounds } = await import(
'@/renderer/core/spatial/boundsCalculator'
)
const { calculateNodeBounds } =
await import('@/renderer/core/spatial/boundsCalculator')
vi.mocked(calculateNodeBounds).mockReturnValue(null)

View File

@@ -19,12 +19,10 @@ vi.mock('@/scripts/api', () => ({
}
}))
const { useWorkflowThumbnail } = await import(
'@/renderer/core/thumbnail/useWorkflowThumbnail'
)
const { createGraphThumbnail } = await import(
'@/renderer/core/thumbnail/graphThumbnailRenderer'
)
const { useWorkflowThumbnail } =
await import('@/renderer/core/thumbnail/useWorkflowThumbnail')
const { createGraphThumbnail } =
await import('@/renderer/core/thumbnail/graphThumbnailRenderer')
const { api } = await import('@/scripts/api')
describe('useWorkflowThumbnail', () => {

View File

@@ -62,9 +62,8 @@ describe('useReleaseStore', () => {
}
// Setup mock implementations
const { useReleaseService } = await import(
'@/platform/updates/common/releaseService'
)
const { useReleaseService } =
await import('@/platform/updates/common/releaseService')
const { useSettingStore } = await import('@/platform/settings/settingStore')
const { useSystemStatsStore } = await import('@/stores/systemStatsStore')
const { isElectron } = await import('@/utils/envUtil')

View File

@@ -287,9 +287,8 @@ describe('versionUtil', () => {
vi.resetModules()
// Import fresh module
const versionUtil = await import(
'@/workbench/extensions/manager/utils/versionUtil'
)
const versionUtil =
await import('@/workbench/extensions/manager/utils/versionUtil')
const version = versionUtil.getFrontendVersion()
expect(version).toBe('2.0.0')
@@ -322,9 +321,8 @@ describe('versionUtil', () => {
vi.resetModules()
// Import fresh module
const versionUtil = await import(
'@/workbench/extensions/manager/utils/versionUtil'
)
const versionUtil =
await import('@/workbench/extensions/manager/utils/versionUtil')
const version = versionUtil.getFrontendVersion()
expect(version).toBeUndefined()