Skip to content

Commit 8e6aaee

Browse files
authored
fix(webui): unify search input clear behavior (AstrBotDevs#6017)
* fix(webui): unify search input clear behavior * fix: centralize search input normalization
1 parent 6da59cf commit 8e6aaee

11 files changed

Lines changed: 61 additions & 22 deletions

File tree

dashboard/src/components/extension/componentPanel/components/CommandFilters.vue

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
<script setup lang="ts">
22
import { computed } from 'vue';
33
import { useModuleI18n } from '@/i18n/composables';
4+
import { normalizeTextInput } from '@/utils/inputValue';
45
56
const { tm } = useModuleI18n('features/command');
67
@@ -52,6 +53,7 @@ const statusItems = [
5253
{ title: tm('filters.disabled'), value: 'disabled' },
5354
{ title: tm('filters.conflict'), value: 'conflict' }
5455
];
56+
5557
</script>
5658

5759
<template>
@@ -108,10 +110,11 @@ const statusItems = [
108110
<div style="min-width: 200px; max-width: 350px; flex: 1; border: 1px solid #B9B9B9; border-radius: 16px;">
109111
<v-text-field
110112
:model-value="searchQuery"
111-
@update:model-value="emit('update:searchQuery', $event)"
113+
@update:model-value="emit('update:searchQuery', normalizeTextInput($event))"
112114
density="compact"
113115
:label="tm('search.placeholder')"
114116
prepend-inner-icon="mdi-magnify"
117+
clearable
115118
variant="solo-filled"
116119
flat
117120
hide-details

dashboard/src/components/extension/componentPanel/composables/useCommandFilters.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
*/
44
import { ref, computed, type Ref } from 'vue';
55
import type { CommandItem, FilterState } from '../types';
6+
import { normalizeTextInput } from '@/utils/inputValue';
67

78
export function useCommandFilters(commands: Ref<CommandItem[]>) {
89
// 过滤状态
@@ -95,7 +96,7 @@ export function useCommandFilters(commands: Ref<CommandItem[]>) {
9596
* 过滤后的指令列表(支持层级结构)
9697
*/
9798
const filteredCommands = computed(() => {
98-
const query = searchQuery.value.toLowerCase();
99+
const query = normalizeTextInput(searchQuery.value).toLowerCase();
99100
const conflictCmds: CommandItem[] = [];
100101
const normalCmds: CommandItem[] = [];
101102

@@ -184,4 +185,3 @@ export function useCommandFilters(commands: Ref<CommandItem[]>) {
184185
isGroupExpanded
185186
};
186187
}
187-

dashboard/src/components/extension/componentPanel/index.vue

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
import { computed, onActivated, onMounted, ref, watch} from 'vue';
1616
import axios from 'axios';
1717
import { useModuleI18n } from '@/i18n/composables';
18+
import { normalizeTextInput } from '@/utils/inputValue';
1819
1920
// Composables
2021
import { useComponentData } from './composables/useComponentData';
@@ -83,7 +84,7 @@ const {
8384
} = useCommandActions(toast, () => fetchCommands(tm('messages.loadFailed')));
8485
8586
const filteredTools = computed(() => {
86-
const query = toolSearch.value.trim().toLowerCase();
87+
const query = normalizeTextInput(toolSearch.value).trim().toLowerCase();
8788
if (!query) return tools.value;
8889
return tools.value.filter(tool =>
8990
tool.name?.toLowerCase().includes(query) ||
@@ -253,7 +254,8 @@ watch(viewMode, async (mode) => {
253254
<div class="d-flex flex-wrap align-center ga-3 mb-4">
254255
<div style="min-width: 240px; max-width: 380px; flex: 1;">
255256
<v-text-field
256-
v-model="toolSearch"
257+
:model-value="toolSearch"
258+
@update:model-value="toolSearch = normalizeTextInput($event)"
257259
prepend-inner-icon="mdi-magnify"
258260
:label="tmTool('functionTools.search')"
259261
variant="outlined"

dashboard/src/components/provider/ProviderModelsPanel.vue

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
v-model="modelSearchProxy"
88
density="compact"
99
prepend-inner-icon="mdi-magnify"
10+
clearable
1011
hide-details
1112
variant="solo-filled"
1213
flat
@@ -161,6 +162,7 @@
161162

162163
<script setup>
163164
import { computed } from 'vue'
165+
import { normalizeTextInput } from '@/utils/inputValue'
164166
165167
const props = defineProps({
166168
entries: {
@@ -222,7 +224,7 @@ const emit = defineEmits([
222224
223225
const modelSearchProxy = computed({
224226
get: () => props.modelSearch,
225-
set: (val) => emit('update:modelSearch', val)
227+
set: (val) => emit('update:modelSearch', normalizeTextInput(val))
226228
})
227229
228230
const isProviderTesting = (providerId) => props.testingProviders.includes(providerId)

dashboard/src/composables/useProviderSources.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import { ref, computed, onMounted, nextTick, watch } from 'vue'
22
import axios from 'axios'
33
import { getProviderIcon } from '@/utils/providerUtils'
44
import { askForConfirmation as askForConfirmationDialog, useConfirmDialog } from '@/utils/confirmDialog'
5+
import { normalizeTextInput } from '@/utils/inputValue'
56

67
export interface UseProviderSourcesOptions {
78
defaultTab?: string
@@ -157,7 +158,7 @@ export function useProviderSources(options: UseProviderSourcesOptions) {
157158
})
158159

159160
const filteredMergedModelEntries = computed(() => {
160-
const term = modelSearch.value.trim().toLowerCase()
161+
const term = normalizeTextInput(modelSearch.value).trim().toLowerCase()
161162
if (!term) return mergedModelEntries.value
162163

163164
return mergedModelEntries.value.filter((entry: any) => {

dashboard/src/utils/inputValue.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
export const normalizeTextInput = (value: unknown): string =>
2+
typeof value === 'string' ? value : '';

dashboard/src/views/ConfigPage.vue

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,11 @@
1313
</v-select>
1414
<v-text-field
1515
class="config-search-input"
16-
v-model="configSearchKeyword"
16+
:model-value="configSearchKeyword"
17+
@update:model-value="onConfigSearchInput"
1718
prepend-inner-icon="mdi-magnify"
1819
:label="tm('search.placeholder')"
20+
clearable
1921
hide-details
2022
density="compact"
2123
rounded="md"
@@ -211,6 +213,7 @@ import {
211213
useConfirmDialog
212214
} from '@/utils/confirmDialog';
213215
import UnsavedChangesConfirmDialog from '@/components/config/UnsavedChangesConfirmDialog.vue';
216+
import { normalizeTextInput } from '@/utils/inputValue';
214217
215218
export default {
216219
name: 'ConfigPage',
@@ -419,6 +422,9 @@ export default {
419422
420423
},
421424
methods: {
425+
onConfigSearchInput(value) {
426+
this.configSearchKeyword = normalizeTextInput(value);
427+
},
422428
extractConfigTypeFromHash(hash) {
423429
const rawHash = String(hash || '');
424430
const lastHashIndex = rawHash.lastIndexOf('#');

dashboard/src/views/alkaid/KnowledgeBase.vue

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -353,10 +353,11 @@
353353
<v-window-item value="search">
354354
<div class="search-container pa-4">
355355
<v-form @submit.prevent="searchKnowledgeBase" class="d-flex align-center">
356-
<v-text-field v-model="searchQuery" :label="tm('search.queryLabel')"
356+
<v-text-field :model-value="searchQuery"
357+
@update:model-value="onSearchQueryInput" :label="tm('search.queryLabel')"
357358
append-icon="mdi-magnify" variant="outlined" class="flex-grow-1 me-2"
358359
@click:append="searchKnowledgeBase" @keyup.enter="searchKnowledgeBase"
359-
:placeholder="tm('search.queryPlaceholder')" hide-details></v-text-field>
360+
:placeholder="tm('search.queryPlaceholder')" hide-details clearable></v-text-field>
360361

361362
<v-select v-model="topK" :items="[3, 5, 10, 20]"
362363
:label="tm('search.resultCountLabel')" variant="outlined"
@@ -434,6 +435,7 @@
434435
import axios from 'axios';
435436
import ConsoleDisplayer from '@/components/shared/ConsoleDisplayer.vue';
436437
import { useModuleI18n } from '@/i18n/composables';
438+
import { normalizeTextInput } from '@/utils/inputValue';
437439
438440
export default {
439441
name: 'KnowledgeBase',
@@ -580,6 +582,9 @@ export default {
580582
this.getProviderList();
581583
},
582584
methods: {
585+
onSearchQueryInput(value) {
586+
this.searchQuery = normalizeTextInput(value);
587+
},
583588
getSelectedGitHubProxy() {
584589
if (typeof window === "undefined" || !window.localStorage) return "";
585590
return localStorage.getItem("githubProxyRadioValue") === "1"
@@ -903,7 +908,8 @@ export default {
903908
},
904909
905910
searchKnowledgeBase() {
906-
if (!this.searchQuery.trim()) {
911+
const query = normalizeTextInput(this.searchQuery).trim();
912+
if (!query) {
907913
this.showSnackbar(this.tm('messages.pleaseEnterSearchContent'), 'warning');
908914
return;
909915
}
@@ -914,7 +920,7 @@ export default {
914920
axios.get(`/api/plug/alkaid/kb/collection/search`, {
915921
params: {
916922
collection_name: this.currentKB.collection_name,
917-
query: this.searchQuery,
923+
query,
918924
top_k: this.topK
919925
}
920926
})

dashboard/src/views/alkaid/LongTermMemory.vue

Lines changed: 19 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -37,10 +37,12 @@
3737
<h3>{{ tm('search.title') }}</h3>
3838
<v-card variant="outlined" class="mt-2 pa-3">
3939
<div>
40-
<v-text-field v-model="searchMemoryUserId" :label="tm('search.userIdLabel')" variant="outlined" density="compact" hide-details
41-
class="mb-2"></v-text-field>
42-
<v-text-field v-model="searchQuery" :label="tm('search.queryLabel')" variant="outlined" density="compact" hide-details
43-
@keyup.enter="searchMemory" class="mb-2"></v-text-field>
40+
<v-text-field :model-value="searchMemoryUserId"
41+
@update:model-value="onSearchMemoryUserIdInput" :label="tm('search.userIdLabel')" variant="outlined" density="compact" hide-details
42+
class="mb-2" clearable></v-text-field>
43+
<v-text-field :model-value="searchQuery"
44+
@update:model-value="onSearchQueryInput" :label="tm('search.queryLabel')" variant="outlined" density="compact" hide-details
45+
@keyup.enter="searchMemory" class="mb-2" clearable></v-text-field>
4446
<v-btn color="info" @click="searchMemory" :loading="isSearching" variant="tonal">
4547
<v-icon start>mdi-text-search</v-icon>
4648
{{ tm('search.searchButton') }}
@@ -254,6 +256,7 @@
254256
import axios from 'axios';
255257
// import * as d3 from "d3"; // npm install d3
256258
import { useModuleI18n } from '@/i18n/composables';
259+
import { normalizeTextInput } from '@/utils/inputValue';
257260
258261
export default {
259262
name: 'LongTermMemory',
@@ -336,9 +339,16 @@ export default {
336339
this.searchResults = [];
337340
},
338341
methods: {
342+
onSearchMemoryUserIdInput(value) {
343+
this.searchMemoryUserId = normalizeTextInput(value);
344+
},
345+
onSearchQueryInput(value) {
346+
this.searchQuery = normalizeTextInput(value);
347+
},
339348
// 添加搜索记忆方法
340349
searchMemory() {
341-
if (!this.searchQuery.trim()) {
350+
const query = normalizeTextInput(this.searchQuery).trim();
351+
if (!query) {
342352
this.$toast.warning(this.tm('messages.searchQueryRequired'));
343353
return;
344354
}
@@ -349,12 +359,13 @@ export default {
349359
350360
// 构建查询参数
351361
const params = {
352-
query: this.searchQuery
362+
query
353363
};
354364
355365
// 如果有选择用户ID,也加入查询参数
356-
if (this.searchMemoryUserId) {
357-
params.user_id = this.searchMemoryUserId;
366+
const normalizedUserId = normalizeTextInput(this.searchMemoryUserId).trim();
367+
if (normalizedUserId) {
368+
params.user_id = normalizedUserId;
358369
}
359370
360371
axios.get('/api/plug/alkaid/ltm/graph/search', { params })

dashboard/src/views/extension/InstalledPluginsTab.vue

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import PluginSortControl from "@/components/extension/PluginSortControl.vue";
33
import ExtensionCard from "@/components/shared/ExtensionCard.vue";
44
import StyledMenu from "@/components/shared/StyledMenu.vue";
55
import defaultPluginIcon from "@/assets/images/plugin_icon.png";
6+
import { normalizeTextInput } from "@/utils/inputValue";
67
78
const props = defineProps({
89
state: {
@@ -164,10 +165,12 @@ const {
164165

165166
<div class="d-flex align-center flex-wrap ml-auto" style="gap: 8px">
166167
<v-text-field
167-
v-model="pluginSearch"
168+
:model-value="pluginSearch"
169+
@update:model-value="pluginSearch = normalizeTextInput($event)"
168170
density="compact"
169171
:label="tm('search.placeholder')"
170172
prepend-inner-icon="mdi-magnify"
173+
clearable
171174
variant="solo-filled"
172175
flat
173176
hide-details

0 commit comments

Comments
 (0)