mirror of
https://github.com/Comfy-Org/ComfyUI_frontend.git
synced 2026-05-05 05:32:02 +00:00
Add search settings feature (#362)
* Add setting searchbox ui * Basic search * Remove first divider * Keep group label on search result * No result placeholder * Prevent no result flash * i18n * Disable category nav when searching
This commit is contained in:
@@ -1,26 +1,49 @@
|
||||
<template>
|
||||
<div class="settings-container">
|
||||
<div class="settings-sidebar">
|
||||
<SettingSearchBox
|
||||
class="settings-search-box"
|
||||
v-model:modelValue="searchQuery"
|
||||
@search="handleSearch"
|
||||
/>
|
||||
<Listbox
|
||||
v-model="activeCategory"
|
||||
:options="categories"
|
||||
optionLabel="label"
|
||||
scrollHeight="100%"
|
||||
:disabled="inSearch"
|
||||
:pt="{ root: { class: 'border-none' } }"
|
||||
/>
|
||||
</div>
|
||||
<Divider layout="vertical" />
|
||||
<div class="settings-content" v-if="activeCategory">
|
||||
<Tabs :value="activeCategory.label">
|
||||
<TabPanels>
|
||||
<div class="settings-content">
|
||||
<Tabs :value="tabValue">
|
||||
<TabPanels class="settings-tab-panels">
|
||||
<TabPanel key="search-results" value="Search Results">
|
||||
<div v-if="searchResults.length > 0">
|
||||
<SettingGroup
|
||||
v-for="(group, i) in searchResults"
|
||||
:key="group.label"
|
||||
:divider="i !== 0"
|
||||
:group="group"
|
||||
/>
|
||||
</div>
|
||||
<NoResultsPlaceholder
|
||||
v-else
|
||||
icon="pi pi-search"
|
||||
:title="$t('noResultsFound')"
|
||||
:message="$t('searchFailedMessage')"
|
||||
/>
|
||||
</TabPanel>
|
||||
<TabPanel
|
||||
v-for="category in categories"
|
||||
:key="category.key"
|
||||
:value="category.label"
|
||||
>
|
||||
<SettingGroup
|
||||
v-for="group in sortedGroups(category)"
|
||||
v-for="(group, i) in sortedGroups(category)"
|
||||
:key="group.label"
|
||||
:divider="i !== 0"
|
||||
:group="{
|
||||
label: group.label,
|
||||
settings: flattenTree<SettingParams>(group)
|
||||
@@ -43,15 +66,22 @@ import Divider from 'primevue/divider'
|
||||
import { SettingTreeNode, useSettingStore } from '@/stores/settingStore'
|
||||
import { SettingParams } from '@/types/settingTypes'
|
||||
import SettingGroup from './setting/SettingGroup.vue'
|
||||
import SettingSearchBox from './setting/SettingSearchBox.vue'
|
||||
import NoResultsPlaceholder from '@/components/common/NoResultsPlaceholder.vue'
|
||||
import { flattenTree } from '@/utils/treeUtil'
|
||||
|
||||
interface ISettingGroup {
|
||||
label: string
|
||||
settings: SettingParams[]
|
||||
}
|
||||
|
||||
const settingStore = useSettingStore()
|
||||
const settingRoot = computed<SettingTreeNode>(() => settingStore.settingTree)
|
||||
const categories = computed<SettingTreeNode[]>(
|
||||
() => settingRoot.value.children || []
|
||||
)
|
||||
|
||||
const activeCategory = ref<SettingTreeNode | null>(null)
|
||||
const searchResults = ref<ISettingGroup[]>([])
|
||||
|
||||
watch(activeCategory, (newCategory, oldCategory) => {
|
||||
if (newCategory === null) {
|
||||
@@ -68,6 +98,48 @@ const sortedGroups = (category: SettingTreeNode) => {
|
||||
a.label.localeCompare(b.label)
|
||||
)
|
||||
}
|
||||
|
||||
const searchQuery = ref<string>('')
|
||||
const searchInProgress = ref<boolean>(false)
|
||||
watch(searchQuery, () => (searchInProgress.value = true))
|
||||
|
||||
const handleSearch = (query: string) => {
|
||||
if (!query) {
|
||||
searchResults.value = []
|
||||
return
|
||||
}
|
||||
|
||||
const allSettings = flattenTree<SettingParams>(settingRoot.value)
|
||||
const filteredSettings = allSettings.filter(
|
||||
(setting) =>
|
||||
setting.id.toLowerCase().includes(query.toLowerCase()) ||
|
||||
setting.name.toLowerCase().includes(query.toLowerCase())
|
||||
)
|
||||
|
||||
const groupedSettings: { [key: string]: SettingParams[] } = {}
|
||||
filteredSettings.forEach((setting) => {
|
||||
const groupLabel = setting.id.split('.')[1]
|
||||
if (!groupedSettings[groupLabel]) {
|
||||
groupedSettings[groupLabel] = []
|
||||
}
|
||||
groupedSettings[groupLabel].push(setting)
|
||||
})
|
||||
|
||||
searchResults.value = Object.entries(groupedSettings).map(
|
||||
([label, settings]) => ({
|
||||
label,
|
||||
settings
|
||||
})
|
||||
)
|
||||
searchInProgress.value = false
|
||||
}
|
||||
|
||||
const inSearch = computed(
|
||||
() => searchQuery.value.length > 0 && !searchInProgress.value
|
||||
)
|
||||
const tabValue = computed(() =>
|
||||
inSearch.value ? 'Search Results' : activeCategory.value?.label
|
||||
)
|
||||
</script>
|
||||
|
||||
<style>
|
||||
@@ -75,6 +147,10 @@ const sortedGroups = (category: SettingTreeNode) => {
|
||||
.border-none {
|
||||
border: none !important;
|
||||
}
|
||||
|
||||
.settings-tab-panels {
|
||||
padding-top: 0px !important;
|
||||
}
|
||||
</style>
|
||||
|
||||
<style scoped>
|
||||
@@ -95,6 +171,11 @@ const sortedGroups = (category: SettingTreeNode) => {
|
||||
padding: 10px;
|
||||
}
|
||||
|
||||
.settings-search-box {
|
||||
width: 100%;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.settings-content {
|
||||
flex-grow: 1;
|
||||
overflow-y: auto;
|
||||
|
||||
Reference in New Issue
Block a user