Skip to content

Commit f8eafb7

Browse files
RenjiYuuseiCodFrm
andauthored
✨ Global search (#662)
* Refines and expands Vietnamese locale Improves existing Vietnamese translations for better consistency, clarity, and natural phrasing. Adds numerous new translation keys to provide comprehensive localization for recently introduced features and UI elements. * Adds global search to the script list Enables users to filter scripts by name, metadata, or their entire source code. Introduces a search input with debounce for better performance and a scope selector to toggle between title-only and full-content search. Lazy-loads and caches script source code on demand when performing full-content searches, improving responsiveness and reducing unnecessary network requests. This enhances script discoverability and management within the options interface. * lint-fix * 全局代码搜索 * 恢复style --------- Co-authored-by: 王一之 <yz@ggnb.top>
1 parent 6847a59 commit f8eafb7

4 files changed

Lines changed: 89 additions & 15 deletions

File tree

src/locales/en-US/translation.json

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -451,5 +451,7 @@
451451
"light": "Light",
452452
"dark": "Dark",
453453
"individual_edit": "Individual Edit",
454-
"batch_edit": "Batch Edit"
454+
"batch_edit": "Batch Edit",
455+
"script_code": "Script Code",
456+
"enter_search_value": "Enter {{search}} to search"
455457
}

src/locales/zh-CN/translation.json

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -451,5 +451,7 @@
451451
"light": "亮色模式",
452452
"dark": "暗色模式",
453453
"individual_edit": "单独编辑",
454-
"batch_edit": "批量编辑"
454+
"batch_edit": "批量编辑",
455+
"script_code": "脚本代码",
456+
"enter_search_value": "请输入 {{search}} 进行搜索"
455457
}

src/pages/options/routes/ScriptList.tsx

Lines changed: 63 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,7 @@ import {
8282
updateEnableStatus,
8383
synchronizeClient,
8484
batchDeleteScript,
85+
requestScriptCode,
8586
} from "@App/pages/store/features/script";
8687
import { ValueClient } from "@App/app/service/service_worker/client";
8788
import { loadScriptFavicons } from "@App/pages/store/utils";
@@ -203,6 +204,8 @@ const EnableSwitch = React.memo(
203204
);
204205
EnableSwitch.displayName = "EnableSwitch";
205206

207+
type SearchType = "auto" | "name" | "script_code";
208+
206209
function ScriptList() {
207210
const [userConfig, setUserConfig] = useState<{
208211
script: Script;
@@ -298,35 +301,84 @@ function ScriptList() {
298301
sorter: (a, b) => a.name.localeCompare(b.name),
299302
filterIcon: <IconSearch />,
300303
filterDropdown: ({ filterKeys, setFilterKeys, confirm }: any) => {
304+
if (!filterKeys.length) {
305+
filterKeys = [{ type: "auto", value: "" }];
306+
}
301307
return (
302-
<div className="arco-table-custom-filter">
308+
<div className="arco-table-custom-filter flex flex-row gap-2">
309+
<Select
310+
className="flex-1"
311+
triggerProps={{ autoAlignPopupWidth: false, autoAlignPopupMinWidth: true, position: "bl" }}
312+
size="small"
313+
value={filterKeys[0].type || "auto"}
314+
onChange={(value) => {
315+
filterKeys[0].type = value;
316+
setFilterKeys([...filterKeys]);
317+
}}
318+
>
319+
<Select.Option value="auto">{t("auto")}</Select.Option>
320+
<Select.Option value="name">{t("name")}</Select.Option>
321+
<Select.Option value="script_code">{t("script_code")}</Select.Option>
322+
</Select>
303323
<Input.Search
304324
ref={inputRef}
325+
size="small"
305326
searchButton
306-
placeholder={t("enter_script_name")!}
307-
value={filterKeys[0] || ""}
327+
style={{ minWidth: 240 }}
328+
placeholder={
329+
t("enter_search_value", {
330+
search: filterKeys[0].type == "auto" ? `${t("name")}/${t("script_code")}` : t(""),
331+
})!
332+
}
333+
value={filterKeys[0].value || ""}
308334
onChange={(value) => {
309-
setFilterKeys(value ? [value] : []);
335+
filterKeys[0].value = value;
336+
setFilterKeys([...filterKeys]);
310337
}}
311338
onSearch={() => {
312-
confirm();
339+
confirm!();
313340
}}
314341
/>
315342
</div>
316343
);
317344
},
318-
onFilter: (value: string, row) => {
319-
if (!value) {
345+
onFilter: (value: { type: SearchType; value: string }, row) => {
346+
if (!value || !value.value) {
320347
return true;
321348
}
322-
value = value.toLocaleLowerCase();
349+
const keyword = value.value.toLocaleLowerCase();
323350
row.name = row.name.toLocaleLowerCase();
324351
const i18n = i18nName(row).toLocaleLowerCase();
325352
// 空格分开关键字搜索
326-
const keys = value.split(" ");
353+
const keys = keyword.split(" ");
354+
const searchName = (keyword: string) => {
355+
return row.name.includes(keyword) || i18n.includes(keyword);
356+
};
357+
const searchCode = (keyword: string) => {
358+
if (!row.code) {
359+
// 没有code,请求一下code
360+
dispatch(requestScriptCode(row.uuid));
361+
return false;
362+
}
363+
return row.code.includes(keyword);
364+
};
327365
for (const key of keys) {
328-
if (row.name.includes(key) || i18n.includes(key)) {
329-
return true;
366+
switch (value.type) {
367+
case "auto":
368+
if (searchName(key) || searchCode(key)) {
369+
return true;
370+
}
371+
break;
372+
case "script_code":
373+
if (searchCode(key)) {
374+
return true;
375+
}
376+
break;
377+
case "name":
378+
if (searchName(key)) {
379+
return true;
380+
}
381+
break;
330382
}
331383
}
332384
return false;
@@ -545,7 +597,6 @@ function ScriptList() {
545597
scriptClient
546598
.requestCheckUpdate(script.uuid)
547599
.then((res) => {
548-
console.log("res", res);
549600
if (res) {
550601
Message.warning({
551602
id: "checkupdate",

src/pages/store/features/script.ts

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,18 @@ export const requestDeleteScript = createAsyncThunk("script/deleteScript", async
4848
return await scriptClient.delete(uuid);
4949
});
5050

51+
export const requestScriptCode = createAsyncThunk("script/requestScriptCode", async (uuid: string, { getState }) => {
52+
const state = getState() as { script: { scripts: ScriptLoading[] } };
53+
const script = state.script.scripts.find((s) => s.uuid === uuid);
54+
55+
// 如果已经有代码了,直接返回
56+
if (script?.code !== undefined) {
57+
return { code: script.code };
58+
}
59+
60+
return await scriptClient.getCode(uuid);
61+
});
62+
5163
export type ScriptLoading = Script & {
5264
enableLoading?: boolean;
5365
actionLoading?: boolean;
@@ -56,6 +68,7 @@ export type ScriptLoading = Script & {
5668
website?: string;
5769
icon?: string;
5870
}[];
71+
code?: string; // 用于搜索的脚本代码
5972
};
6073

6174
const updateScript = (scripts: ScriptLoading[], uuid: string, update: (s: ScriptLoading) => void) => {
@@ -171,7 +184,13 @@ export const scriptSlice = createAppSlice({
171184
)
172185
.addCase(requestStopScript.fulfilled, (state, action) =>
173186
updateScript(state.scripts, action.meta.arg, (s) => (s.actionLoading = false))
174-
);
187+
)
188+
//处理请求脚本代码
189+
.addCase(requestScriptCode.fulfilled, (state, action) => {
190+
updateScript(state.scripts, action.meta.arg, (s) => {
191+
s.code = action.payload?.code.toLocaleLowerCase();
192+
});
193+
});
175194
},
176195
selectors: {
177196
selectScripts: (state) => state.scripts,

0 commit comments

Comments
 (0)