From 689f43334273608089904f61c0d38312ef454695 Mon Sep 17 00:00:00 2001 From: elainefan331 Date: Wed, 22 Oct 2025 17:54:44 -0400 Subject: [PATCH 1/2] feat: enhance highlightkeyword to check secondary fields when visible fields don't match --- src/components/SearchPage/DatasetCard.tsx | 120 ++++++++++++++++++++-- src/pages/DatasetDetailPage.tsx | 2 +- 2 files changed, 111 insertions(+), 11 deletions(-) diff --git a/src/components/SearchPage/DatasetCard.tsx b/src/components/SearchPage/DatasetCard.tsx index 110b6fc..19fb758 100644 --- a/src/components/SearchPage/DatasetCard.tsx +++ b/src/components/SearchPage/DatasetCard.tsx @@ -1,6 +1,7 @@ import { Typography, Card, CardContent, Stack, Chip } from "@mui/material"; import { Colors } from "design/theme"; import React from "react"; +import { useMemo } from "react"; import { Link } from "react-router-dom"; import RoutesEnum from "types/routes.enum"; @@ -17,7 +18,9 @@ interface DatasetCardProps { info?: { Authors?: string[]; DatasetDOI?: string; + [k: string]: any; }; + [k: string]: any; }; }; index: number; @@ -25,6 +28,63 @@ interface DatasetCardProps { keyword?: string; // for keyword highlight } +/** ---------- utility helpers ---------- **/ +const normalize = (s: string) => + s + ?.replace(/[\u2018\u2019\u2032]/g, "'") // curly → straight + ?.replace(/[\u201C\u201D\u2033]/g, '"') ?? // curly → straight + ""; + +const containsKeyword = (text?: string, kw?: string) => { + if (!text || !kw) return false; + const t = normalize(text).toLowerCase(); + const k = normalize(kw).toLowerCase(); + return t.includes(k); +}; + +/** Find a short snippet in secondary fields if not already visible */ +function findMatchSnippet( + v: any, + kw?: string +): { label: string; html: string } | null { + if (!kw) return null; + + // Which fields to scan (can add/remove fields here) + const CANDIDATE_FIELDS: Array<[string, (v: any) => string | undefined]> = [ + ["Acknowledgements", (v) => v?.info?.Acknowledgements], + [ + "Funding", + (v) => + Array.isArray(v?.info?.Funding) + ? v.info.Funding.join(" ") + : v?.info?.Funding, + ], + ["ReferencesAndLinks", (v) => v?.info?.ReferencesAndLinks], + ]; + + const k = normalize(kw).toLowerCase(); + + for (const [label, getter] of CANDIDATE_FIELDS) { + const raw = getter(v); // v = parsedJson.value + if (!raw) continue; + const text = normalize(String(raw)); + const i = text.toLowerCase().indexOf(k); // k is the lowercase version of keyword + if (i >= 0) { + const start = Math.max(0, i - 40); + const end = Math.min(text.length, i + k.length + 40); + const before = text.slice(start, i); + const hit = text.slice(i, i + k.length); + const after = text.slice(i + k.length, end); + const html = `${ + start > 0 ? "…" : "" + }${before}${hit}${after}${end < text.length ? "…" : ""}`; + return { label, html }; + } + } + return null; +} +/** ---------- end of helpers ---------- **/ + const DatasetCard: React.FC = ({ dbname, dsname, @@ -40,7 +100,29 @@ const DatasetCard: React.FC = ({ const rawDOI = info?.DatasetDOI?.replace(/^doi:/, ""); const doiLink = rawDOI ? `https://doi.org/${rawDOI}` : null; - // keyword hightlight functional component + // precompute what’s visible & whether it already contains the keyword + const authorsJoined = Array.isArray(info?.Authors) + ? info!.Authors.join(", ") + : typeof info?.Authors === "string" + ? info!.Authors + : ""; + + const visibleHasKeyword = useMemo( + () => + containsKeyword(name, keyword) || + containsKeyword(readme, keyword) || + containsKeyword(authorsJoined, keyword), + [name, readme, authorsJoined, keyword] + ); + + // If not visible, produce a one-line snippet from other fields (for non-visible fields) + const snippet = useMemo( + () => + !visibleHasKeyword ? findMatchSnippet(parsedJson.value, keyword) : null, + [parsedJson.value, keyword, visibleHasKeyword] + ); + + // keyword hightlight functional component (only for visible fields) const highlightKeyword = (text: string, keyword?: string) => { if (!keyword || !text?.toLowerCase().includes(keyword.toLowerCase())) { return text; @@ -99,7 +181,10 @@ const DatasetCard: React.FC = ({ {highlightKeyword(name || "Untitled Dataset", keyword)} - Database: {dbname}   |   Dataset: {dsname} + {/* Database: {dbname}   |   Dataset: {dsname} */} + Database: {highlightKeyword(dbname, keyword)} + {" "}  |  {" "} + Dataset: {highlightKeyword(dsname, keyword)} @@ -168,20 +253,35 @@ const DatasetCard: React.FC = ({ {info?.Authors && ( Authors:{" "} - {highlightKeyword( - Array.isArray(info.Authors) - ? info.Authors.join(", ") - : typeof info.Authors === "string" - ? info.Authors - : "N/A", - keyword - )} + {highlightKeyword(authorsJoined || "N/A", keyword)} )} )} + {/* show why it matched if not visible in main fields */} + {snippet && ( + + + only + dangerouslySetInnerHTML={{ __html: snippet.html }} + /> + + )} + {doiLink && ( diff --git a/src/pages/DatasetDetailPage.tsx b/src/pages/DatasetDetailPage.tsx index 0999906..c1b5c89 100644 --- a/src/pages/DatasetDetailPage.tsx +++ b/src/pages/DatasetDetailPage.tsx @@ -305,7 +305,7 @@ const DatasetDetailPage: React.FC = () => { useEffect(() => { if (datasetDocument) { // ✅ Extract External Data & Assign `index` - console.log("datasetDocument", datasetDocument); + // console.log("datasetDocument", datasetDocument); const links = extractDataLinks(datasetDocument, "").map( (link, index) => ({ ...link, From 7bc8fc0e62abe36755cb4becd029812a3928dad8 Mon Sep 17 00:00:00 2001 From: elainefan331 Date: Thu, 23 Oct 2025 10:36:19 -0400 Subject: [PATCH 2/2] feat: display readme as summary when ai summary is unavailable --- src/pages/UpdatedDatasetDetailPage.tsx | 26 +++++++++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) diff --git a/src/pages/UpdatedDatasetDetailPage.tsx b/src/pages/UpdatedDatasetDetailPage.tsx index a56e0d0..ee24bd0 100644 --- a/src/pages/UpdatedDatasetDetailPage.tsx +++ b/src/pages/UpdatedDatasetDetailPage.tsx @@ -93,6 +93,7 @@ const UpdatedDatasetDetailPage: React.FC = () => { const [copiedKey, setCopiedKey] = useState(null); const copyTimer = useRef(null); const aiSummary = datasetDocument?.[".datainfo"]?.AISummary ?? ""; + const readme = datasetDocument?.["README"] ?? ""; const handleSelectRevision = (newRev?: string | null) => { setSearchParams((prev) => { const p = new URLSearchParams(prev); // copy of the query url @@ -808,7 +809,7 @@ const UpdatedDatasetDetailPage: React.FC = () => { )} {/* ai summary */} - {aiSummary && ( + {aiSummary ? ( <> { + ) : readme ? ( + <> + + + Summary + + + + + + ) : ( + "" )}