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})
  • diff --git a/frontend/app/search/page.tsx b/frontend/app/search/page.tsx index b3e1184..ab5313e 100644 --- a/frontend/app/search/page.tsx +++ b/frontend/app/search/page.tsx @@ -1,6 +1,7 @@ "use client"; -import { useState } from "react"; +import { useEffect, useRef, 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"; @@ -83,13 +83,44 @@ 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); const [results, setResults] = useState([]); 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); @@ -167,8 +198,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 +491,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} - - ))} -
    - )} -
    + )}
    - - - +
    + + ))}
    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(`(?