From e6638a65179615b78df2d6dfc643b010966bd6f7 Mon Sep 17 00:00:00 2001 From: Dave Date: Mon, 16 Feb 2026 19:53:31 +0000 Subject: [PATCH] Clean up previous project display --- frontend/src/App.tsx | 95 +++++++++++++++++++++++++++----------- frontend/src/api/client.ts | 7 +++ server/src/http/project.rs | 7 +++ server/src/io/fs.rs | 15 ++++++ 4 files changed, 96 insertions(+), 28 deletions(-) diff --git a/frontend/src/App.tsx b/frontend/src/App.tsx index 2a599a4..878e6eb 100644 --- a/frontend/src/App.tsx +++ b/frontend/src/App.tsx @@ -28,15 +28,18 @@ function renderHighlightedMatch(text: string, query: string) { if (!query) return text; let qIndex = 0; const lowerQuery = query.toLowerCase(); - return text.split("").map((char, index) => { + const counts = new Map(); + return text.split("").map((char) => { const isMatch = qIndex < lowerQuery.length && char.toLowerCase() === lowerQuery[qIndex]; if (isMatch) { qIndex += 1; } + const count = counts.get(char) ?? 0; + counts.set(char, count + 1); return ( {char} @@ -53,7 +56,6 @@ function App() { const [knownProjects, setKnownProjects] = React.useState([]); const [homeDir, setHomeDir] = React.useState(null); - const [suggestion, setSuggestion] = React.useState(null); const [suggestionTail, setSuggestionTail] = React.useState(""); const [completionError, setCompletionError] = React.useState( null, @@ -99,7 +101,6 @@ function App() { async function computeSuggestion() { setCompletionError(null); - setSuggestion(null); setSuggestionTail(""); setMatchList([]); setSelectedMatch(0); @@ -174,13 +175,11 @@ function App() { React.useEffect(() => { if (matchList.length === 0) { - setSuggestion(null); setSuggestionTail(""); return; } const index = Math.min(selectedMatch, matchList.length - 1); const next = matchList[index]; - setSuggestion(next.path); const trimmed = pathInput.trim(); if (next.path.startsWith(trimmed)) { setSuggestionTail(next.path.slice(trimmed.length)); @@ -247,27 +246,68 @@ function App() { Recent projects
    - {knownProjects.map((project) => ( -
  • - -
  • - ))} + {knownProjects.map((project) => { + const displayName = + project.split("/").filter(Boolean).pop() ?? project; + return ( +
  • +
    + + +
    +
  • + ); + })}
)} @@ -326,7 +366,6 @@ function App() { event.preventDefault(); setMatchList([]); setSelectedMatch(0); - setSuggestion(null); setSuggestionTail(""); setCompletionError(null); } else if (event.key === "Enter") { diff --git a/frontend/src/api/client.ts b/frontend/src/api/client.ts index 117aa04..8f0378a 100644 --- a/frontend/src/api/client.ts +++ b/frontend/src/api/client.ts @@ -89,6 +89,13 @@ export const api = { getKnownProjects(baseUrl?: string) { return requestJson("/projects", {}, baseUrl); }, + forgetKnownProject(path: string, baseUrl?: string) { + return requestJson( + "/projects/forget", + { method: "POST", body: JSON.stringify({ path }) }, + baseUrl, + ); + }, openProject(path: string, baseUrl?: string) { return requestJson( "/project", diff --git a/server/src/http/project.rs b/server/src/http/project.rs index 5ec575d..eb04a70 100644 --- a/server/src/http/project.rs +++ b/server/src/http/project.rs @@ -54,4 +54,11 @@ impl ProjectApi { let projects = fs::get_known_projects(self.ctx.store.as_ref()).map_err(bad_request)?; Ok(Json(projects)) } + + /// Forget a known project path. + #[oai(path = "/projects/forget", method = "post")] + async fn forget_known_project(&self, payload: Json) -> OpenApiResult> { + fs::forget_known_project(payload.0.path, self.ctx.store.as_ref()).map_err(bad_request)?; + Ok(Json(true)) + } } diff --git a/server/src/io/fs.rs b/server/src/io/fs.rs index 2761b03..b6d4479 100644 --- a/server/src/io/fs.rs +++ b/server/src/io/fs.rs @@ -126,6 +126,21 @@ pub fn get_known_projects(store: &dyn StoreOps) -> Result, String> { Ok(projects) } +pub fn forget_known_project(path: String, store: &dyn StoreOps) -> Result<(), String> { + let mut known_projects = get_known_projects(store)?; + let original_len = known_projects.len(); + + known_projects.retain(|p| p != &path); + + if known_projects.len() == original_len { + return Ok(()); + } + + store.set(KEY_KNOWN_PROJECTS, json!(known_projects)); + store.save()?; + Ok(()) +} + pub fn get_model_preference(store: &dyn StoreOps) -> Result, String> { if let Some(model) = store .get(KEY_SELECTED_MODEL)