[Manager] Add filtering nodes/packs by 'Installed' or 'All' (#3031)

Co-authored-by: github-actions <github-actions@github.com>
This commit is contained in:
Christian Byrne
2025-03-13 17:39:27 -07:00
committed by GitHub
parent 0cfd6a487a
commit 8f8b5bdcf4
11 changed files with 86 additions and 23 deletions

View File

@@ -15,8 +15,7 @@
<ManagerNavSidebar
v-if="isSideNavOpen"
:tabs="tabs"
:selected-tab="selectedTab"
@update:selected-tab="handleTabSelection"
v-model:selectedTab="selectedTab"
/>
<div
class="flex-1 overflow-auto"
@@ -107,7 +106,8 @@
<script setup lang="ts">
import Button from 'primevue/button'
import ProgressSpinner from 'primevue/progressspinner'
import { computed, ref } from 'vue'
import { computed, ref, watchEffect } from 'vue'
import { useI18n } from 'vue-i18n'
import ContentDivider from '@/components/common/ContentDivider.vue'
import NoResultsPlaceholder from '@/components/common/NoResultsPlaceholder.vue'
@@ -118,12 +118,17 @@ import InfoPanelMultiItem from '@/components/dialog/content/manager/infoPanel/In
import PackCard from '@/components/dialog/content/manager/packCard/PackCard.vue'
import RegistrySearchBar from '@/components/dialog/content/manager/registrySearchBar/RegistrySearchBar.vue'
import { useResponsiveCollapse } from '@/composables/element/useResponsiveCollapse'
import { useInstalledPacks } from '@/composables/useInstalledPacks'
import { useRegistrySearch } from '@/composables/useRegistrySearch'
import { useComfyManagerStore } from '@/stores/comfyManagerStore'
import type { PackField, TabItem } from '@/types/comfyManagerTypes'
import { components } from '@/types/comfyRegistryTypes'
const DEFAULT_CARD_SIZE = 512
const { t } = useI18n()
const comfyManagerStore = useComfyManagerStore()
const {
isSmallScreen,
isOpen: isSideNavOpen,
@@ -132,14 +137,10 @@ const {
const hideSearchBar = computed(() => isSmallScreen.value && showInfoPanel.value)
const tabs = ref<TabItem[]>([
{ id: 'all', label: 'All', icon: 'pi-list' },
{ id: 'community', label: 'Community', icon: 'pi-globe' },
{ id: 'installed', label: 'Installed', icon: 'pi-box' }
{ id: 'all', label: t('g.all'), icon: 'pi-list' },
{ id: 'installed', label: t('g.installed'), icon: 'pi-box' }
])
const selectedTab = ref<TabItem>(tabs.value[0])
const handleTabSelection = (tab: TabItem) => {
selectedTab.value = tab
}
const { searchQuery, pageNumber, sortField, isLoading, error, searchResults } =
useRegistrySearch()
@@ -149,8 +150,27 @@ const isInitialLoad = computed(
() => searchResults.value.length === 0 && searchQuery.value === ''
)
const { getInstalledPacks } = useInstalledPacks()
const displayPacks = ref<components['schemas']['Node'][]>([])
const isEmptySearch = computed(() => searchQuery.value === '')
const getInstalledSearchResults = async () => {
if (isEmptySearch.value) return getInstalledPacks()
return searchResults.value.filter((pack) =>
comfyManagerStore.installedPacksIds.has(pack.name)
)
}
watchEffect(async () => {
if (selectedTab.value.id === 'installed') {
displayPacks.value = await getInstalledSearchResults()
} else {
displayPacks.value = searchResults.value
}
})
const resultsWithKeys = computed(() =>
searchResults.value.map((item) => ({
displayPacks.value.map((item) => ({
...item,
key: item.id || item.name
}))

View File

@@ -4,17 +4,16 @@
>
<ScrollPanel class="w-80 mt-7">
<Listbox
:model-value="selectedTab"
v-model="selectedTab"
:options="tabs"
optionLabel="label"
listStyle="max-height:unset"
class="w-full border-0 bg-transparent"
:pt="{
root: { class: 'w-full border-0 bg-transparent' },
list: { class: 'p-5' },
option: { class: 'px-8 py-3 text-lg rounded-xl' },
optionGroup: { class: 'p-0 text-left text-inherit' }
}"
@update:model-value="handleTabSelection"
>
<template #option="slotProps">
<div class="text-left flex items-center">
@@ -37,14 +36,7 @@ import type { TabItem } from '@/types/comfyManagerTypes'
defineProps<{
tabs: TabItem[]
selectedTab: TabItem
}>()
const emit = defineEmits<{
'update:selectedTab': [value: TabItem]
}>()
const handleTabSelection = (tab: TabItem) => {
emit('update:selectedTab', tab)
}
const selectedTab = defineModel<TabItem>('selectedTab')
</script>

View File

@@ -0,0 +1,39 @@
import { chunk } from 'lodash'
import { onUnmounted } from 'vue'
import { useComfyManagerStore } from '@/stores/comfyManagerStore'
import { useComfyRegistryStore } from '@/stores/comfyRegistryStore'
import { components } from '@/types/comfyRegistryTypes'
const MAX_SIMULTANEOUS_REQUESTS = 8
export const useInstalledPacks = () => {
const comfyManagerStore = useComfyManagerStore()
const { getPackById, cancelRequests } = useComfyRegistryStore()
const getInstalledIdsChunks = () =>
chunk(
Array.from(comfyManagerStore.installedPacksIds),
MAX_SIMULTANEOUS_REQUESTS
)
const getInstalledPacks = async () => {
const packs: components['schemas']['Node'][] = []
for (const packIdsChunk of getInstalledIdsChunks()) {
const requests = packIdsChunk.map((id) => getPackById(id))
const responses = await Promise.all(requests)
responses.forEach((pack) => {
if (pack) packs.push(pack)
})
}
return packs
}
onUnmounted(() => {
cancelRequests()
})
return {
getInstalledPacks
}
}

View File

@@ -58,7 +58,6 @@ export function useRegistrySearch() {
onUnmounted(() => {
debouncedSearch.cancel() // Cancel debounced searches
registryStore.cancelRequests() // Cancel in-flight requests
registryStore.clearCache() // Clear cached responses
})
return {

View File

@@ -92,7 +92,9 @@
"category": "Category",
"sort": "Sort",
"filter": "Filter",
"apply": "Apply"
"apply": "Apply",
"enabled": "Enabled",
"installed": "Installed"
},
"manager": {
"title": "Custom Nodes Manager",

View File

@@ -144,6 +144,7 @@
"download": "Télécharger",
"empty": "Vide",
"enableAll": "Activer tout",
"enabled": "Activé",
"error": "Erreur",
"experimental": "BETA",
"export": "Exportation",
@@ -158,6 +159,7 @@
"import": "Importer",
"insert": "Insérer",
"install": "Installer",
"installed": "Installé",
"installing": "Installation",
"keybinding": "Raccourci clavier",
"loadAllFolders": "Charger tous les dossiers",

View File

@@ -144,6 +144,7 @@
"download": "ダウンロード",
"empty": "空",
"enableAll": "すべて有効にする",
"enabled": "有効",
"error": "エラー",
"experimental": "ベータ",
"export": "エクスポート",
@@ -158,6 +159,7 @@
"import": "インポート",
"insert": "挿入",
"install": "インストール",
"installed": "インストール済み",
"installing": "インストール中",
"keybinding": "キーバインディング",
"loadAllFolders": "すべてのフォルダーを読み込む",

View File

@@ -144,6 +144,7 @@
"download": "다운로드",
"empty": "비어 있음",
"enableAll": "모두 활성화",
"enabled": "활성화됨",
"error": "오류",
"experimental": "베타",
"export": "내보내기",
@@ -158,6 +159,7 @@
"import": "가져오기",
"insert": "삽입",
"install": "설치",
"installed": "설치됨",
"installing": "설치 중",
"keybinding": "키 바인딩",
"loadAllFolders": "모든 폴더 로드",

View File

@@ -144,6 +144,7 @@
"download": "Скачать",
"empty": "Пусто",
"enableAll": "Включить все",
"enabled": "Включено",
"error": "Ошибка",
"experimental": "БЕТА",
"export": "Экспорт",
@@ -158,6 +159,7 @@
"import": "Импорт",
"insert": "Вставить",
"install": "Установить",
"installed": "Установлено",
"installing": "Установка",
"keybinding": "Привязка клавиш",
"loadAllFolders": "Загрузить все папки",

View File

@@ -144,6 +144,7 @@
"download": "下载",
"empty": "空",
"enableAll": "启用全部",
"enabled": "已启用",
"error": "错误",
"experimental": "测试版",
"export": "导出",
@@ -158,6 +159,7 @@
"import": "导入",
"insert": "插入",
"install": "安装",
"installed": "已安装",
"installing": "正在安装",
"keybinding": "按键绑定",
"loadAllFolders": "加载所有文件夹",

View File

@@ -138,6 +138,7 @@ export const useComfyManagerStore = defineStore('comfyManager', () => {
// Installed packs state
installedPacks,
installedPacksIds,
isPackInstalled: isInstalledPackId,
isPackEnabled: isEnabledPackId,