From f0e82b79b0b19880f8d5c10b26f05c52aa783ab0 Mon Sep 17 00:00:00 2001 From: wtlin1228 Date: Sun, 6 Oct 2024 04:14:18 +0800 Subject: [PATCH] feat: support two search mode --- crates/api_server/src/main.rs | 41 ++++++++++++++++++----- web/src/search/api.ts | 13 ++++--- web/src/search/components/SearchInput.tsx | 20 +++++++++-- web/src/search/components/TreeView.tsx | 7 +++- web/src/search/index.tsx | 7 ++-- 5 files changed, 69 insertions(+), 19 deletions(-) diff --git a/crates/api_server/src/main.rs b/crates/api_server/src/main.rs index ed8c053..a4ba979 100644 --- a/crates/api_server/src/main.rs +++ b/crates/api_server/src/main.rs @@ -5,7 +5,7 @@ use dt_core::{ portable::Portable, tracker::{DependencyTracker, TraceTarget}, }; -use serde::Serialize; +use serde::{Deserialize, Serialize}; use std::{ collections::{HashMap, HashSet}, fs::File, @@ -32,19 +32,40 @@ struct SearchResponse { trace_result: HashMap>>>>, } -#[get("/search/{search}")] +#[derive(Deserialize)] +struct Info { + q: String, + exact_match: bool, +} + +#[get("/search")] async fn search( data: web::Data, - path: web::Path, + info: web::Query, ) -> Result> { - let search = path.into_inner(); + let search = &info.q; + let exact_match = info.exact_match; - // TODO: deal with search mode let mut matched_i18n_keys: Vec = Vec::new(); - for (i18n_key, translation) in data.translation_json.iter() { - if translation == &search { - matched_i18n_keys.push(i18n_key.to_owned()); + match exact_match { + true => { + for (i18n_key, translation) in data.translation_json.iter() { + if translation == search { + matched_i18n_keys.push(i18n_key.to_owned()); + } + } } + false => { + for (i18n_key, translation) in data.translation_json.iter() { + if translation.contains(search) { + matched_i18n_keys.push(i18n_key.to_owned()); + } + } + } + } + + if matched_i18n_keys.len() == 0 { + return Err(error::ErrorNotFound(format!("No result for {}", search))); } let mut dependency_tracker = DependencyTracker::new(&data.used_by_graph, true); @@ -122,7 +143,9 @@ async fn search( #[actix_web::main] async fn main() -> std::io::Result<()> { // TODO: get portable path from args - let mut file = File::open("")?; + // let mut file = File::open("")?; + let mut file = + File::open("/Users/linweitang/rust/js-symbol-dependency-tracker/outputs/naopleon-06.json")?; let mut exported = String::new(); file.read_to_string(&mut exported)?; let portable = Portable::import(&exported).unwrap(); diff --git a/web/src/search/api.ts b/web/src/search/api.ts index 9b23770..3f90644 100644 --- a/web/src/search/api.ts +++ b/web/src/search/api.ts @@ -6,8 +6,13 @@ export type SearchResult = { trace_result: TraceResult; }; -export async function getSearchResult(search: string): Promise { - const url = `http://127.0.0.1:8080/search/${encodeURIComponent(search)}`; +export async function getSearchResult( + search: string, + exactMatch: boolean +): Promise { + const url = `http://127.0.0.1:8080/search?q=${encodeURIComponent( + search + )}&exact_match=${exactMatch}`; if (search === "demo") { return mockedSearchResult; @@ -25,8 +30,6 @@ export async function getSearchResult(search: string): Promise { return data; } catch (error) { // Handle and re-throw the error so React Query can capture it - throw new Error( - `Failed to fetch search results: ${(error as Error).message}` - ); + throw new Error((error as Error).message); } } diff --git a/web/src/search/components/SearchInput.tsx b/web/src/search/components/SearchInput.tsx index e2d9596..1472ce0 100644 --- a/web/src/search/components/SearchInput.tsx +++ b/web/src/search/components/SearchInput.tsx @@ -3,13 +3,19 @@ import Paper from "@mui/material/Paper"; import InputBase from "@mui/material/InputBase"; import IconButton from "@mui/material/IconButton"; import SearchIcon from "@mui/icons-material/Search"; +import BlurOffIcon from "@mui/icons-material/BlurOff"; +import BlurOnIcon from "@mui/icons-material/BlurOn"; export function CustomizedInputBase({ handleSearch, isSearching, + exactMatch, + setExactMatch, }: { handleSearch: (search: string) => void; isSearching: boolean; + exactMatch: boolean; + setExactMatch: (b: boolean) => void; }) { const inputRef = React.useRef(); @@ -34,8 +40,8 @@ export function CustomizedInputBase({ @@ -55,6 +61,16 @@ export function CustomizedInputBase({ > + { + setExactMatch(!exactMatch); + }} + > + {exactMatch ? : } + ); } diff --git a/web/src/search/components/TreeView.tsx b/web/src/search/components/TreeView.tsx index 7d7fa3d..b45a19d 100644 --- a/web/src/search/components/TreeView.tsx +++ b/web/src/search/components/TreeView.tsx @@ -84,7 +84,12 @@ export const TreeView = React.memo(function TreeView({ data: SearchResult; }) { return ( - + {Object.entries(data.trace_result).map( ([i18nKey, urlToTraceTargets]) => ( diff --git a/web/src/search/index.tsx b/web/src/search/index.tsx index 2a082db..d984299 100644 --- a/web/src/search/index.tsx +++ b/web/src/search/index.tsx @@ -7,9 +7,10 @@ import { getSearchResult } from "./api"; export const Search = () => { const [search, setSearch] = React.useState(); + const [exactMatch, setExactMatch] = React.useState(true); const { isPending, isLoading, isError, data, error } = useQuery({ - queryKey: ["search", search], - queryFn: () => getSearchResult(search!), + queryKey: ["search", search, exactMatch], + queryFn: () => getSearchResult(search!, exactMatch), enabled: search !== undefined, staleTime: 5 * 1000, retry: false, @@ -34,6 +35,8 @@ export const Search = () => { setSearch(search); }} isSearching={isLoading} + exactMatch={exactMatch} + setExactMatch={setExactMatch} /> {isPending ? (