Merge remote-tracking branch 'origin/main' into bl-semantic-jellyfish

# Conflicts:
#	src/components/TopMenuSection.vue
#	src/components/queue/job/QueueJobItem.vue
This commit is contained in:
Benjamin Lu
2025-12-08 18:37:05 -08:00
88 changed files with 1258 additions and 310 deletions

View File

@@ -115,6 +115,7 @@ const cancelJobTooltipConfig = computed(() =>
// Right side panel toggle
const { isOpen: isRightSidePanelOpen } = storeToRefs(rightSidePanelStore)
const rightSidePanelTooltipConfig = computed(() =>
buildTooltipConfig(t('rightSidePanel.togglePanel'))
)

View File

@@ -10,6 +10,7 @@
@click="$emit('showFilter', $event)"
/>
<InputText
ref="inputRef"
class="search-box-input w-full"
:model-value="modelValue"
:placeholder="placeholder"
@@ -48,6 +49,7 @@ import Button from 'primevue/button'
import IconField from 'primevue/iconfield'
import InputIcon from 'primevue/inputicon'
import InputText from 'primevue/inputtext'
import { ref } from 'vue'
import type { SearchFilter } from './SearchFilterChip.vue'
import SearchFilterChip from './SearchFilterChip.vue'
@@ -77,6 +79,14 @@ const emit = defineEmits<{
(e: 'removeFilter', filter: TFilter): void
}>()
const inputRef = ref()
defineExpose({
focus: () => {
inputRef.value?.$el?.focus()
}
})
const emitSearch = debounce((value: string) => {
emit('search', value, filters)
}, debounceTime)

View File

@@ -117,16 +117,7 @@ onBeforeUnmount(() => {
.scroll-container {
height: 100%;
overflow-y: auto;
/* Firefox */
scrollbar-width: none;
&::-webkit-scrollbar {
width: 1px;
}
&::-webkit-scrollbar-thumb {
background-color: transparent;
}
scrollbar-width: thin;
scrollbar-color: var(--dialog-surface) transparent;
}
</style>

View File

@@ -132,7 +132,7 @@ import { useCopy } from '@/composables/useCopy'
import { useGlobalLitegraph } from '@/composables/useGlobalLitegraph'
import { usePaste } from '@/composables/usePaste'
import { useVueFeatureFlags } from '@/composables/useVueFeatureFlags'
import { i18n, t } from '@/i18n'
import { mergeCustomNodesI18n, t } from '@/i18n'
import { LiteGraph } from '@/lib/litegraph/src/litegraph'
import { useLitegraphSettings } from '@/platform/settings/composables/useLitegraphSettings'
import { CORE_SETTINGS } from '@/platform/settings/constants/coreSettings'
@@ -391,9 +391,7 @@ useEventListener(
const loadCustomNodesI18n = async () => {
try {
const i18nData = await api.getCustomNodesI18n()
Object.entries(i18nData).forEach(([locale, message]) => {
i18n.global.mergeLocaleMessage(locale, message)
})
mergeCustomNodesI18n(i18nData)
} catch (error) {
console.error('Failed to load custom nodes i18n', error)
}

View File

@@ -36,12 +36,12 @@
</template>
<script setup lang="ts">
import { ref } from 'vue'
import { onBeforeUnmount, ref, watch } from 'vue'
import QueueJobItem from '@/components/queue/job/QueueJobItem.vue'
import type { JobGroup, JobListItem } from '@/composables/queue/useJobList'
defineProps<{ displayedJobGroups: JobGroup[] }>()
const props = defineProps<{ displayedJobGroups: JobGroup[] }>()
const emit = defineEmits<{
(e: 'cancelItem', item: JobListItem): void
@@ -89,4 +89,26 @@ const onDetailsLeave = (jobId: string) => {
hideTimer.value = null
}, 150)
}
const resetActiveDetails = () => {
clearHideTimer()
clearShowTimer()
activeDetailsId.value = null
}
watch(
() => props.displayedJobGroups,
(groups) => {
const activeId = activeDetailsId.value
if (!activeId) return
const hasActiveJob = groups.some((group) =>
group.items.some((item) => item.id === activeId)
)
if (!hasActiveJob) resetActiveDetails()
}
)
onBeforeUnmount(resetActiveDetails)
</script>

View File

@@ -361,7 +361,10 @@ const baseActions = computed<ActionConfig[]>(() => {
ariaLabel: t('g.delete'),
tooltip: deleteTooltipConfig.value,
isVisible: () => props.state === 'failed' && computedShowClear.value,
onClick: () => emit('delete')
onClick: () => {
onRowLeave()
emit('delete')
}
},
{
key: 'cancel-hover',
@@ -377,7 +380,10 @@ const baseActions = computed<ActionConfig[]>(() => {
props.state !== 'running' &&
props.state !== 'failed' &&
computedShowClear.value,
onClick: () => emit('cancel')
onClick: () => {
onRowLeave()
emit('cancel')
}
},
{
key: 'view',
@@ -401,7 +407,10 @@ const baseActions = computed<ActionConfig[]>(() => {
ariaLabel: t('g.cancel'),
tooltip: cancelTooltipConfig.value,
isVisible: () => props.state === 'running' && computedShowClear.value,
onClick: () => emit('cancel')
onClick: () => {
onRowLeave()
emit('cancel')
}
}
]
})

View File

@@ -21,6 +21,7 @@
</template>
<template #header>
<SearchBox
ref="searchBoxRef"
v-model:model-value="searchQuery"
class="model-lib-search-box p-2 2xl:p-4"
:placeholder="$t('g.searchModels') + '...'"
@@ -66,6 +67,7 @@ import { buildTree } from '@/utils/treeUtil'
const modelStore = useModelStore()
const modelToNodeStore = useModelToNodeStore()
const settingStore = useSettingStore()
const searchBoxRef = ref()
const searchQuery = ref<string>('')
const expandedKeys = ref<Record<string, boolean>>({})
const { expandNode, toggleNodeOnEvent } = useTreeExpansion(expandedKeys)
@@ -180,6 +182,7 @@ watch(
)
onMounted(async () => {
searchBoxRef.value?.focus()
if (settingStore.get('Comfy.ModelLibrary.AutoLoadAll')) {
await modelStore.loadModels()
}

View File

@@ -78,6 +78,7 @@
<template #header>
<div>
<SearchBox
ref="searchBoxRef"
v-model:model-value="searchQuery"
class="node-lib-search-box p-2 2xl:p-4"
:placeholder="$t('g.searchNodes') + '...'"
@@ -130,7 +131,7 @@ import Button from 'primevue/button'
import Divider from 'primevue/divider'
import Popover from 'primevue/popover'
import type { Ref } from 'vue'
import { computed, h, nextTick, ref, render } from 'vue'
import { computed, h, nextTick, onMounted, ref, render } from 'vue'
import SearchBox from '@/components/common/SearchBox.vue'
import type { SearchFilter } from '@/components/common/SearchFilterChip.vue'
@@ -171,6 +172,12 @@ const { expandNode, toggleNodeOnEvent } = useTreeExpansion(expandedKeys)
const nodeBookmarkTreeExplorerRef = ref<InstanceType<
typeof NodeBookmarkTreeExplorer
> | null>(null)
const searchBoxRef = ref()
onMounted(() => {
searchBoxRef.value?.focus()
})
const searchFilter = ref<InstanceType<typeof Popover> | null>(null)
const groupingPopover = ref<InstanceType<typeof Popover> | null>(null)
const sortingPopover = ref<InstanceType<typeof Popover> | null>(null)

View File

@@ -14,6 +14,7 @@
</template>
<template #header>
<SearchBox
ref="searchBoxRef"
v-model:model-value="searchQuery"
class="workflows-search-box p-2 2xl:p-4"
:placeholder="$t('g.searchWorkflows') + '...'"
@@ -158,6 +159,8 @@ const workflowTabsPosition = computed(() =>
settingStore.get('Comfy.Workflow.WorkflowTabsPosition')
)
const searchBoxRef = ref()
const searchQuery = ref('')
const isSearching = computed(() => searchQuery.value.length > 0)
const filteredWorkflows = ref<ComfyWorkflow[]>([])
@@ -295,6 +298,7 @@ const selectionKeys = computed(() => ({
const workflowBookmarkStore = useWorkflowBookmarkStore()
onMounted(async () => {
searchBoxRef.value?.focus()
await workflowBookmarkStore.loadBookmarks()
})
</script>

View File

@@ -162,7 +162,7 @@ const rightAreaClasses = computed(() => {
})
const contentContainerClasses = computed(() => {
return cn('min-h-0 px-6 pt-0 pb-10', 'overflow-y-auto scrollbar-hide')
return cn('min-h-0 px-6 pt-0 pb-10', 'overflow-y-auto')
})
const rightPanelClasses = computed(() => {