From 5984585d6d6fa175292194567576ab15832244a2 Mon Sep 17 00:00:00 2001 From: kartik Date: Tue, 4 Aug 2026 13:19:00 +0530 Subject: [PATCH 1/4] drop duplicated database details --- frontend/components/ChatBox.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/components/ChatBox.tsx b/frontend/components/ChatBox.tsx index 944bcf7..61e4999 100644 --- a/frontend/components/ChatBox.tsx +++ b/frontend/components/ChatBox.tsx @@ -126,7 +126,7 @@ export const ChatBox: React.FC = ({ const db_link = `[Database](/search/${bmId})`; const replacementString = `**${bmId}** -- ${ai_link}  |  ${db_link}`; */ const db_link = `[Database Details](/search/${bmId})`; - const replacementString = `**${bmId}** || ${db_link}`; + const replacementString = `**${bmId}**`; const idRegex = new RegExp(`(? Date: Tue, 4 Aug 2026 13:35:00 +0530 Subject: [PATCH 2/4] make text inside results selectable --- frontend/app/search/page.tsx | 141 ++++++++++++++++++----------------- 1 file changed, 73 insertions(+), 68 deletions(-) diff --git a/frontend/app/search/page.tsx b/frontend/app/search/page.tsx index b3e1184..9a6e161 100644 --- a/frontend/app/search/page.tsx +++ b/frontend/app/search/page.tsx @@ -1,6 +1,7 @@ "use client"; import { useState } from "react"; +import { useRouter } from "next/navigation"; import { Search, Filter, @@ -33,7 +34,6 @@ import { CollapsibleContent, CollapsibleTrigger, } from "@/components/ui/collapsible"; -import Link from "next/link"; import { cn } from "@/lib/utils"; import { SignInOutButton } from "@/components/sign-in-out-button"; @@ -84,6 +84,7 @@ const defaultFilters: SearchFilters = { }; export default function BiomodelSearchPage() { + const router = useRouter(); const [filters, setFilters] = useState(defaultFilters); const [results, setResults] = useState([]); @@ -167,8 +168,8 @@ export default function BiomodelSearchPage() { Biomodel Database Search

- Search and explore biomodels from the VCell database with advanced - filtering options. + Search and explore biomodels from the VCell database with + advanced filtering options.

@@ -460,78 +461,82 @@ export default function BiomodelSearchPage() {
{results.map((model) => ( - { + const selection = window.getSelection(); + if (selection && selection.toString().length > 0) { + return; + } + router.push(`/search/${model.bmId}`); + }} + className="group shadow-sm border-slate-200 hover:border-blue-300 hover:shadow-md transition-all cursor-pointer" > - - -
-
- {model.privacy === 1 ? ( - - ) : ( - - )} + +
+
+ {model.privacy === 1 ? ( + + ) : ( + + )} +
+
+
+

+ {model.name} +

+
-
-
-

- {model.name} -

- -
-

- {model.annot || "No description available."} -

+

+ {model.annot || "No description available."} +

-
- - - {model.ownerName} - - - - {formatDate(model.savedDate)} - - - - {model.simulations} simulation - {model.simulations === 1 ? "" : "s"} - - - - {model.bmId} +
+ + + {model.ownerName} + + + + {formatDate(model.savedDate)} + + + + {model.simulations} simulation + {model.simulations === 1 ? "" : "s"} + + + + {model.bmId} + +
+ + {model.groupUsers.length > 0 && ( +
+ + Shared with: + {model.groupUsers.map((user, index) => ( + + {user} + + ))}
- - {model.groupUsers.length > 0 && ( -
- - Shared with: - - {model.groupUsers.map((user, index) => ( - - {user} - - ))} -
- )} -
+ )}
- - - +
+ + ))}
From 2ff78a713e428cf5d8aee7a8281390b1cea71c50 Mon Sep 17 00:00:00 2001 From: kartik Date: Tue, 4 Aug 2026 13:39:00 +0530 Subject: [PATCH 3/4] improve visibility of inactive tab on search page --- frontend/app/search/[bmid]/page.tsx | 33 ++++++++++++++++++++++------- 1 file changed, 25 insertions(+), 8 deletions(-) diff --git a/frontend/app/search/[bmid]/page.tsx b/frontend/app/search/[bmid]/page.tsx index f589cce..cecdbbd 100644 --- a/frontend/app/search/[bmid]/page.tsx +++ b/frontend/app/search/[bmid]/page.tsx @@ -216,7 +216,10 @@ export default function BiomodelDetailPage() { return (
- +
@@ -286,13 +289,23 @@ export default function BiomodelDetailPage() {
- + - + Overview - + AI Analysis @@ -332,7 +345,7 @@ export default function BiomodelDetailPage() {
- + {/* Applications Section */} @@ -347,7 +360,9 @@ export default function BiomodelDetailPage() {
    {data.applications?.map((app) => { - const encodedAppName = encodeURIComponent(app.name || ""); + const encodedAppName = encodeURIComponent( + app.name || "", + ); const bnglUrl = `https://vcell.cam.uchc.edu/api/v0/biomodel/${data.bmKey}/biomodel.bngl?appname=${encodedAppName}`; const sbmlUrl = `https://vcell.cam.uchc.edu/api/v0/biomodel/${data.bmKey}/biomodel.sbml?appname=${encodedAppName}`; return ( @@ -389,7 +404,7 @@ export default function BiomodelDetailPage() {
- + {/* Simulations Section */} @@ -440,7 +455,9 @@ export default function BiomodelDetailPage() {
  • {ov.name} ({ov.type}):{" "} - {ov.values ? ov.values.join(", ") : "No values"} + {ov.values + ? ov.values.join(", ") + : "No values"} {" "} (Cardinality: {ov.cardinality})
  • From 33114a56464b6a809d13d8541d76519a00913573 Mon Sep 17 00:00:00 2001 From: kartik Date: Tue, 4 Aug 2026 13:45:00 +0530 Subject: [PATCH 4/4] persist search filters and results across navigation --- frontend/app/search/page.tsx | 32 +++++++++++++++++++++++++++++++- 1 file changed, 31 insertions(+), 1 deletion(-) diff --git a/frontend/app/search/page.tsx b/frontend/app/search/page.tsx index 9a6e161..ab5313e 100644 --- a/frontend/app/search/page.tsx +++ b/frontend/app/search/page.tsx @@ -1,6 +1,6 @@ "use client"; -import { useState } from "react"; +import { useEffect, useRef, useState } from "react"; import { useRouter } from "next/navigation"; import { Search, @@ -83,6 +83,8 @@ const defaultFilters: SearchFilters = { orderBy: "date_desc", }; +const SEARCH_STATE_KEY = "vcell-search-state"; + export default function BiomodelSearchPage() { const router = useRouter(); const [filters, setFilters] = useState(defaultFilters); @@ -91,6 +93,34 @@ export default function BiomodelSearchPage() { const [isLoading, setIsLoading] = useState(false); const [hasSearched, setHasSearched] = useState(false); const [isAdvancedSearchOpen, setIsAdvancedSearchOpen] = useState(false); + const isHydrated = useRef(false); + + // Restore filters/results saved before navigating away (e.g. to a result's detail page) + useEffect(() => { + try { + const saved = sessionStorage.getItem(SEARCH_STATE_KEY); + if (saved) { + const parsed = JSON.parse(saved); + if (parsed.filters) setFilters(parsed.filters); + if (parsed.results) setResults(parsed.results); + if (typeof parsed.hasSearched === "boolean") + setHasSearched(parsed.hasSearched); + if (typeof parsed.isAdvancedSearchOpen === "boolean") + setIsAdvancedSearchOpen(parsed.isAdvancedSearchOpen); + } + } catch { + // ignore malformed/unavailable storage + } + isHydrated.current = true; + }, []); + + useEffect(() => { + if (!isHydrated.current) return; + sessionStorage.setItem( + SEARCH_STATE_KEY, + JSON.stringify({ filters, results, hasSearched, isAdvancedSearchOpen }), + ); + }, [filters, results, hasSearched, isAdvancedSearchOpen]); const handleSearch = async () => { setIsLoading(true);