nits and test fixes

This commit is contained in:
Austin Mroz
2026-01-13 15:52:16 -08:00
parent 56df4c5874
commit 9b198dfce7
3 changed files with 27 additions and 22 deletions

View File

@@ -44,7 +44,7 @@ export class ComfyNodeSearchBox {
'.comfy-vue-node-search-container input[type="text"]' '.comfy-vue-node-search-container input[type="text"]'
) )
this.dropdown = page.locator( this.dropdown = page.locator(
'.comfy-vue-node-search-container .p-autocomplete-list' '.comfy-vue-node-search-container .comfy-autocomplete-list'
) )
this.filterSelectionPanel = new ComfyNodeSearchFilterSelectionPanel(page) this.filterSelectionPanel = new ComfyNodeSearchFilterSelectionPanel(page)
} }
@@ -61,7 +61,7 @@ export class ComfyNodeSearchBox {
await this.input.fill(nodeName) await this.input.fill(nodeName)
await this.dropdown.waitFor({ state: 'visible' }) await this.dropdown.waitFor({ state: 'visible' })
await this.dropdown await this.dropdown
.locator('li') .locator('.option-container')
.nth(options?.suggestionIndex || 0) .nth(options?.suggestionIndex || 0)
.click() .click()
} }

View File

@@ -61,24 +61,32 @@
ref="inputRef" ref="inputRef"
v-model="currentQuery" v-model="currentQuery"
class="text-base h-5 bg-transparent border-0 focus:outline-0 flex-1" class="text-base h-5 bg-transparent border-0 focus:outline-0 flex-1"
type="text"
autofocus autofocus
:placeholder="t('g.searchNodes') + '...'" :placeholder="t('g.searchNodes') + '...'"
@keydown.enter.prevent="onAddNode(hoveredSuggestion)" @keydown.enter.prevent="onAddNode(hoveredSuggestion)"
@keydown.down.prevent="updateIndexBy(1)"
@keydown.up.prevent="updateIndexBy(-1)"
/> />
</div> </div>
<div <div
v-bind="containerProps" v-bind="containerProps"
class="bg-comfy-menu-bg p-1 rounded-lg border-border-subtle border max-h-150" class="bg-comfy-menu-bg p-1 rounded-lg border-border-subtle border max-h-150"
> >
<div v-bind="wrapperProps"> <div v-bind="wrapperProps" class="comfy-autocomplete-list">
<NodeSearchItem <NodeSearchItem
v-for="{ data: option, index } in virtualList" v-for="{ data: option, index } in virtualList"
:key="index" :key="index"
class="hover:bg-secondary-background-hover p-1 rounded-sm" :class="
cn(
'p-1 rounded-sm',
hoveredIndex === index && 'bg-secondary-background-hover'
)
"
:node-def="option" :node-def="option"
:current-query="debouncedQuery" :current-query="debouncedQuery"
@click="onAddNode(option)" @click="onAddNode(option)"
@pointerover="setHoverSuggestion(index)" @pointerover="hoveredIndex = index"
/> />
</div> </div>
<div <div
@@ -93,9 +101,8 @@
<script setup lang="ts"> <script setup lang="ts">
import { refDebounced, useVirtualList } from '@vueuse/core' import { refDebounced, useVirtualList } from '@vueuse/core'
import { debounce } from 'es-toolkit/compat'
import Dialog from 'primevue/dialog' import Dialog from 'primevue/dialog'
import { computed, nextTick, ref, useTemplateRef } from 'vue' import { computed, nextTick, ref, useTemplateRef, watchEffect } from 'vue'
import { useI18n } from 'vue-i18n' import { useI18n } from 'vue-i18n'
import NodePreview from '@/components/node/NodePreview.vue' import NodePreview from '@/components/node/NodePreview.vue'
@@ -107,6 +114,7 @@ import { useTelemetry } from '@/platform/telemetry'
import type { ComfyNodeDefImpl } from '@/stores/nodeDefStore' import type { ComfyNodeDefImpl } from '@/stores/nodeDefStore'
import { useNodeDefStore, useNodeFrequencyStore } from '@/stores/nodeDefStore' import { useNodeDefStore, useNodeFrequencyStore } from '@/stores/nodeDefStore'
import type { FuseFilterWithValue } from '@/utils/fuseUtil' import type { FuseFilterWithValue } from '@/utils/fuseUtil'
import { cn } from '@/utils/tailwindUtil'
import SearchFilterChip from '../common/SearchFilterChip.vue' import SearchFilterChip from '../common/SearchFilterChip.vue'
@@ -124,7 +132,6 @@ const { filters, searchLimit = 64 } = defineProps<{
}>() }>()
const nodeSearchFilterVisible = ref(false) const nodeSearchFilterVisible = ref(false)
const hoveredSuggestion = ref<ComfyNodeDefImpl>()
const currentQuery = ref('') const currentQuery = ref('')
const debouncedQuery = refDebounced(currentQuery, 100, { maxWait: 400 }) const debouncedQuery = refDebounced(currentQuery, 100, { maxWait: 400 })
const inputRef = useTemplateRef('inputRef') const inputRef = useTemplateRef('inputRef')
@@ -132,20 +139,17 @@ const inputRef = useTemplateRef('inputRef')
const nodeDefStore = useNodeDefStore() const nodeDefStore = useNodeDefStore()
const nodeFrequencyStore = useNodeFrequencyStore() const nodeFrequencyStore = useNodeFrequencyStore()
// Debounced search tracking (500ms as per implementation plan) watchEffect(() => {
const debouncedTrackSearch = debounce((query: string) => { const query = debouncedQuery.value
if (query.trim()) { if (query.trim()) {
telemetry?.trackNodeSearch({ query }) telemetry?.trackNodeSearch({ query })
} }
}, 500) })
const suggestions = computed(() => { const suggestions = computed(() => {
const query = debouncedQuery.value const query = debouncedQuery.value
const queryIsEmpty = query === '' && filters.length === 0 const queryIsEmpty = query === '' && filters.length === 0
// Track search queries with debounce
debouncedTrackSearch(query)
return queryIsEmpty return queryIsEmpty
? nodeFrequencyStore.topNodeDefs ? nodeFrequencyStore.topNodeDefs
: [ : [
@@ -188,12 +192,14 @@ const onRemoveFilter = async (
emit('removeFilter', filterAndValue) emit('removeFilter', filterAndValue)
inputRef.value?.focus() inputRef.value?.focus()
} }
const setHoverSuggestion = (index: number) => { const hoveredIndex = ref<number>()
if (index === -1) { const hoveredSuggestion = computed(() =>
hoveredSuggestion.value = undefined hoveredIndex.value ? suggestions.value[hoveredIndex.value] : undefined
return )
} function updateIndexBy(delta: number) {
const value = suggestions.value[index] hoveredIndex.value = Math.max(
hoveredSuggestion.value = value 0,
Math.min(suggestions.value.length, (hoveredIndex.value ?? 0) + delta)
)
} }
</script> </script>

View File

@@ -12,7 +12,6 @@
mask: { class: 'node-search-box-dialog-mask' }, mask: { class: 'node-search-box-dialog-mask' },
transition: { transition: {
enterFromClass: 'opacity-0', enterFromClass: 'opacity-0',
// 100ms is the duration of the transition in the dialog component
enterActiveClass: 'transition-all duration-20 ease-out', enterActiveClass: 'transition-all duration-20 ease-out',
leaveActiveClass: 'transition-all duration-20 ease-in', leaveActiveClass: 'transition-all duration-20 ease-in',
leaveToClass: 'opacity-0 scale-75' leaveToClass: 'opacity-0 scale-75'