[Refactor] Move tree logic to setting composable (#3491)

This commit is contained in:
Chenlei Hu
2025-04-17 16:34:42 -04:00
committed by GitHub
parent dacb59f5d3
commit 2f77d74891
5 changed files with 57 additions and 64 deletions

View File

@@ -10,7 +10,7 @@
/>
<Listbox
v-model="activeCategory"
:options="categories"
:options="allCategories"
option-label="translatedLabel"
scroll-height="100%"
:option-disabled="
@@ -73,12 +73,12 @@ import Listbox from 'primevue/listbox'
import ScrollPanel from 'primevue/scrollpanel'
import TabPanels from 'primevue/tabpanels'
import Tabs from 'primevue/tabs'
import { computed, defineAsyncComponent, onMounted, watch } from 'vue'
import { computed, defineAsyncComponent, watch } from 'vue'
import SearchBox from '@/components/common/SearchBox.vue'
import { useSettingSearch } from '@/composables/setting/useSettingSearch'
import { useSettingUI } from '@/composables/setting/useSettingUI'
import { SettingTreeNode, useSettingStore } from '@/stores/settingStore'
import { SettingTreeNode } from '@/stores/settingStore'
import { ISettingGroup, SettingParams } from '@/types/settingTypes'
import { flattenTree } from '@/utils/treeUtil'
@@ -103,13 +103,7 @@ const ServerConfigPanel = defineAsyncComponent(
() => import('./setting/ServerConfigPanel.vue')
)
const settingStore = useSettingStore()
const settingRoot = computed<SettingTreeNode>(() => settingStore.settingTree)
const settingCategories = computed<SettingTreeNode[]>(
() => settingRoot.value.children ?? []
)
const { activeCategory, getDefaultCategory, createTranslatedCategories } =
const { activeCategory, defaultCategory, allCategories, settingCategories } =
useSettingUI(defaultPanel)
const {
@@ -121,16 +115,6 @@ const {
getSearchResults
} = useSettingSearch()
// Create categories with translated labels
const categories = computed<SettingTreeNode[]>(() =>
createTranslatedCategories(settingCategories.value)
)
// Initialize active category on mount
onMounted(() => {
activeCategory.value = getDefaultCategory(categories.value)
})
// Sort groups for a category
const sortedGroups = (category: SettingTreeNode): ISettingGroup[] => {
return [...(category.children ?? [])]
@@ -142,8 +126,8 @@ const sortedGroups = (category: SettingTreeNode): ISettingGroup[] => {
}
const handleSearch = (query: string) => {
handleSearchBase(query, settingRoot.value)
activeCategory.value = query ? null : getDefaultCategory(categories.value)
handleSearchBase(query)
activeCategory.value = query ? null : defaultCategory.value
}
// Get search results

View File

@@ -8,7 +8,6 @@ import {
} from '@/stores/settingStore'
import { ISettingGroup, SettingParams } from '@/types/settingTypes'
import { normalizeI18nKey } from '@/utils/formatUtil'
import { flattenTree } from '@/utils/treeUtil'
export function useSettingSearch() {
const settingStore = useSettingStore()
@@ -45,14 +44,14 @@ export function useSettingSearch() {
/**
* Handle search functionality
*/
const handleSearch = (query: string, settingRoot: SettingTreeNode) => {
const handleSearch = (query: string) => {
if (!query) {
filteredSettingIds.value = []
return
}
const queryLower = query.toLocaleLowerCase()
const allSettings = flattenTree<SettingParams>(settingRoot)
const allSettings = Object.values(settingStore.settingsById)
const filteredSettings = allSettings.filter((setting) => {
const idLower = setting.id.toLowerCase()
const nameLower = setting.name.toLowerCase()

View File

@@ -1,16 +1,45 @@
import { computed, ref } from 'vue'
import { computed, onMounted, ref } from 'vue'
import { useI18n } from 'vue-i18n'
import { SettingTreeNode } from '@/stores/settingStore'
import { SettingTreeNode, useSettingStore } from '@/stores/settingStore'
import type { SettingParams } from '@/types/settingTypes'
import { isElectron } from '@/utils/envUtil'
import { normalizeI18nKey } from '@/utils/formatUtil'
import { buildTree } from '@/utils/treeUtil'
export function useSettingUI(
defaultPanel?: 'about' | 'keybinding' | 'extension' | 'server-config'
) {
const { t } = useI18n()
const settingStore = useSettingStore()
const activeCategory = ref<SettingTreeNode | null>(null)
const settingRoot = computed<SettingTreeNode>(() => {
const root = buildTree(
Object.values(settingStore.settingsById).filter(
(setting: SettingParams) => setting.type !== 'hidden'
),
(setting: SettingParams) => setting.category || setting.id.split('.')
)
const floatingSettings = (root.children ?? []).filter((node) => node.leaf)
if (floatingSettings.length) {
root.children = (root.children ?? []).filter((node) => !node.leaf)
root.children.push({
key: 'Other',
label: 'Other',
leaf: false,
children: floatingSettings
})
}
return root
})
const settingCategories = computed<SettingTreeNode[]>(
() => settingRoot.value.children ?? []
)
// Define panel nodes
const aboutPanelNode: SettingTreeNode = {
key: 'about',
@@ -44,20 +73,21 @@ export function useSettingUI(
})
/**
* Get the default category to show when the dialog is opened.
* The default category to show when the dialog is opened.
*/
const getDefaultCategory = (categories: SettingTreeNode[]) => {
const defaultCategory = computed<SettingTreeNode>(() => {
return defaultPanel
? categories.find((x) => x.key === defaultPanel) ?? categories[0]
: categories[0]
}
? settingCategories.value.find((x) => x.key === defaultPanel) ??
settingCategories.value[0]
: settingCategories.value[0]
})
/**
* Create translated categories with labels
* Translated all categories with labels
*/
const createTranslatedCategories = (settingCategories: SettingTreeNode[]) => {
const translatedCategories = computed<SettingTreeNode[]>(() => {
return [
...settingCategories,
...settingCategories.value,
keybindingPanelNode,
extensionPanelNode,
...serverConfigPanelNodeList.value,
@@ -69,11 +99,16 @@ export function useSettingUI(
node.label
)
}))
}
})
onMounted(() => {
activeCategory.value = defaultCategory.value
})
return {
activeCategory,
getDefaultCategory,
createTranslatedCategories
defaultCategory,
allCategories: translatedCategories,
settingCategories
}
}

View File

@@ -1,13 +1,12 @@
import _ from 'lodash'
import { defineStore } from 'pinia'
import { computed, ref } from 'vue'
import { ref } from 'vue'
import type { Settings } from '@/schemas/apiSchema'
import { api } from '@/scripts/api'
import { app } from '@/scripts/app'
import type { SettingParams } from '@/types/settingTypes'
import type { TreeNode } from '@/types/treeExplorerTypes'
import { buildTree } from '@/utils/treeUtil'
export const getSettingInfo = (setting: SettingParams) => {
const parts = setting.category || setting.id.split('.')
@@ -38,28 +37,6 @@ export const useSettingStore = defineStore('setting', () => {
const settingValues = ref<Record<string, any>>({})
const settingsById = ref<Record<string, SettingParams>>({})
const settingTree = computed<SettingTreeNode>(() => {
const root = buildTree(
Object.values(settingsById.value).filter(
(setting: SettingParams) => setting.type !== 'hidden'
),
(setting: SettingParams) => setting.category || setting.id.split('.')
)
const floatingSettings = (root.children ?? []).filter((node) => node.leaf)
if (floatingSettings.length) {
root.children = (root.children ?? []).filter((node) => !node.leaf)
root.children.push({
key: 'Other',
label: 'Other',
leaf: false,
children: floatingSettings
})
}
return root
})
/**
* Check if a setting's value exists, i.e. if the user has set it manually.
* @param key - The key of the setting to check.
@@ -150,7 +127,6 @@ export const useSettingStore = defineStore('setting', () => {
return {
settingValues,
settingsById,
settingTree,
addSetting,
loadSettingValues,
set,

View File

@@ -37,7 +37,6 @@ describe('useSettingStore', () => {
it('should initialize with empty settings', () => {
expect(store.settingValues).toEqual({})
expect(store.settingsById).toEqual({})
expect(store.settingTree.children).toEqual([])
})
describe('loadSettingValues', () => {