mirror of
https://github.com/Comfy-Org/ComfyUI_frontend.git
synced 2026-02-04 07:00:23 +00:00
## Summary
This PR removes unsafe type assertions ("as unknown as Type") from test
files and improves type safety across the codebase.
### Key Changes
#### Type Safety Improvements
- Removed all instances of "as unknown as" patterns from test files
- Used proper factory functions from litegraphTestUtils instead of
custom mocks
- Made incomplete mocks explicit using Partial<T> types
- Fixed DialogStore mocking with proper interface exports
- Improved type safety with satisfies operator where applicable
#### App Parameter Removal
- **Removed the unused `app` parameter from all ComfyExtension interface
methods**
- The app parameter was always undefined at runtime as it was never
passed from invokeExtensions
- Affected methods: init, setup, addCustomNodeDefs,
beforeRegisterNodeDef, beforeRegisterVueAppNodeDefs,
registerCustomNodes, loadedGraphNode, nodeCreated, beforeConfigureGraph,
afterConfigureGraph
##### Breaking Change Analysis
Verified via Sourcegraph that this is NOT a breaking change:
- Searched all 10 affected methods across GitHub repositories
- Only one external repository
([drawthingsai/draw-things-comfyui](https://github.com/drawthingsai/draw-things-comfyui))
declares the app parameter in their extension methods
- That repository never actually uses the app parameter (just declares
it in the function signature)
- All other repositories already omit the app parameter
- Search queries used:
- [init method
search](https://sourcegraph.com/search?q=context:global+repo:%5Egithub%5C.com/.*+lang:typescript+%22init%28app%22+-repo:Comfy-Org/ComfyUI_frontend&patternType=standard)
- [setup method
search](https://sourcegraph.com/search?q=context:global+repo:%5Egithub%5C.com/.*+lang:typescript+%22setup%28app%22+-repo:Comfy-Org/ComfyUI_frontend&patternType=standard)
- Similar searches for all 10 methods confirmed no usage
### Files Changed
Test files:
-
src/components/settings/widgets/__tests__/WidgetInputNumberInput.test.ts
- src/services/keybindingService.escape.test.ts
- src/services/keybindingService.forwarding.test.ts
- src/utils/__tests__/newUserService.test.ts →
src/utils/__tests__/useNewUserService.test.ts
- src/services/jobOutputCache.test.ts
-
src/renderer/extensions/vueNodes/widgets/composables/useRemoteWidget.test.ts
-
src/renderer/extensions/vueNodes/widgets/composables/useIntWidget.test.ts
-
src/renderer/extensions/vueNodes/widgets/composables/useFloatWidget.test.ts
Source files:
- src/types/comfy.ts - Removed app parameter from ComfyExtension
interface
- src/services/extensionService.ts - Improved type safety with
FunctionPropertyNames helper
- src/scripts/metadata/isobmff.ts - Fixed extractJson return type per
review
- src/extensions/core/*.ts - Updated extension implementations
- src/scripts/app.ts - Updated app initialization
### Testing
- All existing tests pass
- Type checking passes
- ESLint/oxlint checks pass
- No breaking changes for external repositories
Part of the "Road to No Explicit Any" initiative.
### Previous PRs in this series:
- Part 2: #7401
- Part 3: #7935
- Part 4: #7970
- Part 5: #8064
- Part 6: #8083
- Part 7: #8092
- Part 8 Group 1: #8253
- Part 8 Group 2: #8258
- Part 8 Group 3: #8304
- Part 8 Group 4: #8314
- Part 8 Group 5: #8329
- Part 8 Group 6: #8344 (this PR)
203 lines
5.2 KiB
TypeScript
203 lines
5.2 KiB
TypeScript
import { app } from '../../scripts/app'
|
|
import { ComfyApp } from '../../scripts/app'
|
|
import { $el, ComfyDialog } from '../../scripts/ui'
|
|
|
|
export class ClipspaceDialog extends ComfyDialog {
|
|
static items: Array<
|
|
HTMLButtonElement & {
|
|
contextPredicate?: () => boolean
|
|
}
|
|
> = []
|
|
static instance: ClipspaceDialog | null = null
|
|
|
|
static registerButton(
|
|
name: string,
|
|
contextPredicate: () => boolean,
|
|
callback: () => void
|
|
) {
|
|
const item = $el('button', {
|
|
type: 'button',
|
|
textContent: name,
|
|
contextPredicate: contextPredicate,
|
|
onclick: callback
|
|
})
|
|
|
|
ClipspaceDialog.items.push(item)
|
|
}
|
|
|
|
static invalidatePreview() {
|
|
if (
|
|
ComfyApp.clipspace &&
|
|
ComfyApp.clipspace.imgs &&
|
|
ComfyApp.clipspace.imgs.length > 0
|
|
) {
|
|
const img_preview = document.getElementById(
|
|
'clipspace_preview'
|
|
) as HTMLImageElement
|
|
if (img_preview) {
|
|
img_preview.src =
|
|
ComfyApp.clipspace.imgs[ComfyApp.clipspace['selectedIndex']].src
|
|
img_preview.style.maxHeight = '100%'
|
|
img_preview.style.maxWidth = '100%'
|
|
}
|
|
}
|
|
}
|
|
|
|
static invalidate() {
|
|
if (ClipspaceDialog.instance) {
|
|
const self = ClipspaceDialog.instance
|
|
// allow reconstruct controls when copying from non-image to image content.
|
|
const imgSettings = self.createImgSettings()
|
|
const children = $el('div.comfy-modal-content', [
|
|
...(imgSettings ? [imgSettings] : []),
|
|
...self.createButtons()
|
|
])
|
|
|
|
if (self.element) {
|
|
// update
|
|
if (self.element.firstChild) {
|
|
self.element.removeChild(self.element.firstChild)
|
|
}
|
|
self.element.appendChild(children)
|
|
} else {
|
|
// new
|
|
self.element = $el('div.comfy-modal', { parent: document.body }, [
|
|
children
|
|
])
|
|
}
|
|
|
|
if (self.element.children[0].children.length <= 1) {
|
|
self.element.children[0].appendChild(
|
|
$el('p', {}, [
|
|
'Unable to find the features to edit content of a format stored in the current Clipspace.'
|
|
])
|
|
)
|
|
}
|
|
|
|
ClipspaceDialog.invalidatePreview()
|
|
}
|
|
}
|
|
|
|
constructor() {
|
|
super()
|
|
}
|
|
|
|
override createButtons() {
|
|
const buttons = []
|
|
|
|
for (let idx in ClipspaceDialog.items) {
|
|
const item = ClipspaceDialog.items[idx]
|
|
if (!item.contextPredicate || item.contextPredicate())
|
|
buttons.push(ClipspaceDialog.items[idx])
|
|
}
|
|
|
|
buttons.push(
|
|
$el('button', {
|
|
type: 'button',
|
|
textContent: 'Close',
|
|
onclick: () => {
|
|
this.close()
|
|
}
|
|
})
|
|
)
|
|
|
|
return buttons
|
|
}
|
|
|
|
createImgSettings(): HTMLTableElement | null {
|
|
if (ComfyApp.clipspace?.imgs) {
|
|
const combo_items = []
|
|
const imgs = ComfyApp.clipspace.imgs
|
|
|
|
for (let i = 0; i < imgs.length; i++) {
|
|
combo_items.push($el('option', { value: i }, [`${i}`]))
|
|
}
|
|
|
|
const combo1 = $el(
|
|
'select',
|
|
{
|
|
id: 'clipspace_img_selector',
|
|
onchange: (event: Event) => {
|
|
if (event.target && ComfyApp.clipspace) {
|
|
ComfyApp.clipspace['selectedIndex'] = (
|
|
event.target as HTMLSelectElement
|
|
).selectedIndex
|
|
ClipspaceDialog.invalidatePreview()
|
|
}
|
|
}
|
|
},
|
|
combo_items
|
|
)
|
|
|
|
const row1 = $el('tr', {}, [
|
|
$el('td', {}, [$el('font', { color: 'white' }, ['Select Image'])]),
|
|
$el('td', {}, [combo1])
|
|
])
|
|
|
|
const combo2 = $el(
|
|
'select',
|
|
{
|
|
id: 'clipspace_img_paste_mode',
|
|
onchange: (event: Event) => {
|
|
if (event.target && ComfyApp.clipspace) {
|
|
ComfyApp.clipspace['img_paste_mode'] = (
|
|
event.target as HTMLSelectElement
|
|
).value
|
|
}
|
|
}
|
|
},
|
|
[
|
|
$el('option', { value: 'selected' }, 'selected'),
|
|
$el('option', { value: 'all' }, 'all')
|
|
]
|
|
) as HTMLSelectElement
|
|
combo2.value = ComfyApp.clipspace['img_paste_mode']
|
|
|
|
const row2 = $el('tr', {}, [
|
|
$el('td', {}, [$el('font', { color: 'white' }, ['Paste Mode'])]),
|
|
$el('td', {}, [combo2])
|
|
])
|
|
|
|
const td = $el(
|
|
'td',
|
|
{ align: 'center', width: '100px', height: '100px', colSpan: '2' },
|
|
[$el('img', { id: 'clipspace_preview', ondragstart: () => false }, [])]
|
|
)
|
|
|
|
const row3 = $el('tr', {}, [td])
|
|
|
|
return $el('table', {}, [row1, row2, row3])
|
|
} else {
|
|
return null
|
|
}
|
|
}
|
|
|
|
createImgPreview(): HTMLImageElement | null {
|
|
if (ComfyApp.clipspace?.imgs) {
|
|
return $el('img', { id: 'clipspace_preview', ondragstart: () => false })
|
|
} else return null
|
|
}
|
|
|
|
override show() {
|
|
ClipspaceDialog.invalidate()
|
|
|
|
this.element.style.display = 'block'
|
|
}
|
|
}
|
|
|
|
app.registerExtension({
|
|
name: 'Comfy.Clipspace',
|
|
init() {
|
|
app.openClipspace = function () {
|
|
if (!ClipspaceDialog.instance) {
|
|
ClipspaceDialog.instance = new ClipspaceDialog()
|
|
ComfyApp.clipspace_invalidate_handler = ClipspaceDialog.invalidate
|
|
}
|
|
|
|
if (ComfyApp.clipspace) {
|
|
ClipspaceDialog.instance.show()
|
|
} else app.ui.dialog.show('Clipspace is Empty!')
|
|
}
|
|
}
|
|
})
|