Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
c6f1c68
feat: Adds basic example of curated results table.
neomorphic Nov 26, 2024
939b2ff
feat: Adds Curated Results section to help.
neomorphic Dec 3, 2024
b51686a
feat: Adds API endpoint fetch to CuratedResults.
neomorphic Dec 4, 2024
f489f26
feat: Fixes up curated matches processing.
neomorphic Dec 10, 2024
8df3ec9
feat: Places curated matches in a collapsible element
neomorphic Dec 11, 2024
81dcfbb
feat: adds pagination to the curate matches table.
neomorphic Dec 11, 2024
0004e2d
feat: curated matches sets page size to 5
neomorphic Dec 11, 2024
f0a346d
fix: removes card border around curated matches error
neomorphic Dec 17, 2024
02557e0
fix: Changes title of curated matches container.
neomorphic Dec 17, 2024
604d0ef
fix: Constrains maximum width of search results.
neomorphic Dec 17, 2024
9060790
feat: Adds "search" link to Neuron type/instance
neomorphic Dec 17, 2024
e75f4d8
fix: Removes collapse box around computed matches.
neomorphic Dec 17, 2024
60579bb
feat: Adds "Source" column to curated results.
neomorphic Jan 7, 2025
7e436f2
fix: sets default to 2 items per page for curated results.
neomorphic Jan 7, 2025
9f24128
fix: Changes 'Search' button to 'Query' button.
neomorphic Jan 7, 2025
b54e4e8
fix: hides pagination when curated results <= 2.
neomorphic Jan 7, 2025
d494009
testing: fix SearchInput tests after button name change
neomorphic Jan 8, 2025
b0ee4fc
feat: Adds EM annotations to curated matches table
neomorphic Jan 15, 2025
d9d1026
fix: reduce allowed search term length to 2 from 3
neomorphic Jan 15, 2025
d882022
fix: Adds a wildcard to the end of all curated cell_types
neomorphic Feb 27, 2025
d523bf2
fix: Adds addWildCard attribute to curated matches
neomorphic Feb 27, 2025
67f0604
fix: removes incorrect "Additional matches ...." message
neomorphic Mar 3, 2025
0d7a077
fix: Moves curated matches pagination to table bottom.
neomorphic Mar 12, 2025
d267c7d
fix: Makes curated match count bold to highlight it.
neomorphic Mar 12, 2025
f36bfe7
added help text for curated matches from Geoffrey
krokicki Apr 3, 2025
5b4c29e
updated paper reference
krokicki Apr 3, 2025
7cd4b37
updated search examples to include more curated matches
krokicki Apr 3, 2025
0c182aa
fix: restore bodyID string parsing broken during rebase
neomorphic Apr 14, 2026
3bb4238
feat: add @fortawesome/free-solid-svg-icons dependency
neomorphic Apr 14, 2026
3d5734d
feat: make line name a link to search page in LineMeta
neomorphic Apr 17, 2026
59614a2
chore: bump version to 3.5.0 and add 3.4.0 release notes
neomorphic Apr 17, 2026
83f31d8
docs: add 3.5.0 release notes
neomorphic Apr 17, 2026
a7b6041
fix: scroll to hash anchor on mount instead of page top
neomorphic Apr 17, 2026
0de5732
chore: Updated release notes to remove unnecessary details
neomorphic Apr 17, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 42 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 3 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
{
"name": "neuronbridge",
"version": "3.4.0",
"version": "3.5.0",
"private": true,
"dependencies": {
"@ant-design/icons": "^5.1.4",
"@babel/eslint-parser": "^7.22.7",
"@fortawesome/fontawesome-svg-core": "^6.4.0",
"@fortawesome/free-brands-svg-icons": "^6.4.0",
"@fortawesome/free-solid-svg-icons": "^7.2.0",
"@fortawesome/pro-regular-svg-icons": "^6.4.0",
"@fortawesome/pro-solid-svg-icons": "^6.7.1",
"@fortawesome/react-fontawesome": "^0.2.0",
"@testing-library/cypress": "^10.0.1",
"@testing-library/jest-dom": "^5.16.5",
Expand Down
41 changes: 41 additions & 0 deletions public/RELEASENOTES.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,44 @@
## VERSION 3.5.0 - 2026-04-17

### Major Features

- **Curated Matches of Split-GAL4 Lines to Cell Types**: Search results now include a curated matches section that displays expert-annotated associations between Split-GAL4 lines and cell types
- Results are shown in a collapsible, paginated table with confidence level (Confident/Candidate), anatomical region, and source columns
- Curated matches appear above computed matches with a bookmark indicator when results are available
- See the [Curated Results section of the help page](/help#curated_results) for details on confidence levels and data sources.

- **Line Name Links**: Line names in search result metadata are now clickable links that navigate to a new search for that line

### UI/UX Improvements

- **Updated Search Examples**: The example search terms have been refreshed to showcase curated matches functionality
- **Help Documentation**: Added a new help section explaining the curated matches feature

---

## VERSION 3.4.0 - 2026-04-17

### Major Features

- **Aligned Volume Download for Custom Searches**: Custom search results now include a download link for the aligned volume, making it easier to retrieve aligned data for further analysis
- The "View in 3D" button is now available for custom uploads when an aligned volume exists

- **Searched Libraries Display**: The Color Depth Search step now shows which libraries were searched along with result counts, providing better visibility into search coverage

### UI/UX Improvements

- **External Links Open in New Tabs**: All links to external sources now open in a new tab, preventing users from losing their place on the site

### Bug Fixes & Improvements

- **Search & Navigation**:
- Improved search result filtering and duplicate removal logic
- Fixed external EM links to use id instead of library
- Fixed the "View" button to be clickable anywhere on the button area
- Updated search examples for accuracy

---

## VERSION 3.3.1 - 2024-09-22

### Major Features
Expand Down
8 changes: 8 additions & 0 deletions src/App.css
Original file line number Diff line number Diff line change
Expand Up @@ -74,3 +74,11 @@ body {
list-style: none;
padding: 0;
}

/* hides the anchor offset on any page that needs it */
.anchorOffset {
display: block;
position: relative;
top: -80px;
visibility: hidden;
}
83 changes: 83 additions & 0 deletions src/components/CuratedResults.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
import PropTypes from "prop-types";
import { Table, Typography } from "antd";
import { Link } from "react-router-dom";

const { Paragraph } = Typography;

const columns = [
{
title: "Line Name",
dataIndex: "name",
key: "name",
render: (name) => <Link to={`/search?q=${name}`}>{name}</Link>,
},
{
title: "Confidence",
dataIndex: "confidence",
key: "confidence",
},
{
title: "Anatomical Region",
dataIndex: "anatomicalRegion",
key: "anatomicalRegion",
},
{
title: "Source",
dataIndex: "source",
key: "source",
},
{
title: "Cell Type / Neuron ID",
dataIndex: "matched",
key: "matched",
// if the match is a cell type, then we add a wildcard to the search
// to get all the sub cell types.
render: (matched, row) => <Link to={`/search?q=${matched}${row.addWildard}`}>{matched}</Link>,
},
];

export default function CuratedResults({ results, loadError }) {
// if we didn't find anything, then don't display anything.
if (results.length === 0) {
return null;
}

let pagination = {
position: ["bottomLeft"],
pageSizeOptions: ["2", "5", "10", "15", "20"],
defaultPageSize: 2,
showSizeChanger: true,
showQuickJumper: true
};

if (results.length < 3) {
pagination = false;
}

if (loadError) {
return (
<>
<Paragraph type="danger">
There was a problem retrieving the curated matches.
</Paragraph>
<Paragraph>Reloading the page may resolve the issue.</Paragraph>
<Paragraph>
If this problem persists, please contact us at{" "}
<a href="mailto:neuronbridge@janelia.hhmi.org">
neuronbridge@janelia.hhmi.org
</a>
. Please provide the search term used and any other relevant details.
</Paragraph>
</>
);
}

return (
<Table columns={columns} dataSource={results} pagination={pagination} />
);
}

CuratedResults.propTypes = {
results: PropTypes.arrayOf(PropTypes.object).isRequired,
loadError: PropTypes.bool.isRequired,
};
11 changes: 9 additions & 2 deletions src/components/Help/HelpButton.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,17 @@ import { AppContext } from "../../containers/AppContext";
export default function HelpButton({target, text, onClick}) {
const { appState, setAppState } = useContext(AppContext);

const handleHelp = () => {
const handleHelp = (event) => {
// call the onClick callback if it is provided
if (onClick) {
onClick();
onClick(event);
}
// Toggle help if the button is clicked again
if (appState.helpTarget === target) {
setAppState({ ...appState, showHelp: !appState.showHelp });
return;
}
// Show help for the target
setAppState({ ...appState, showHelp: true, helpTarget: target });
}

Expand Down
52 changes: 37 additions & 15 deletions src/components/Help/HelpContents.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -34,29 +34,24 @@ export default function HelpContents({ scroll }) {
SearchInput: useRef(),
UploadAlignment: useRef(),
UploadSearch: useRef(),
CuratedResults: useRef(),
};

// use Effect to scroll to target set in the appState?
useEffect(() => {
if (scroll) {
if (refLookup[appState.helpTarget]) {
if (refLookup[appState.helpTarget].current) {
helpContentRef.current.parentElement.scrollTop =
refLookup[appState.helpTarget].current.offsetTop - 60;
refLookup[appState.helpTarget].current.classList.add("highlighted");
window.setTimeout(() => {
if (
refLookup[appState.helpTarget] &&
refLookup[appState.helpTarget].current
) {
refLookup[appState.helpTarget].current.classList.remove(
"highlighted"
);
}
}, 3000);
const observer = new IntersectionObserver(([entry]) => {
if (entry.isIntersecting) {
refLookup[appState.helpTarget].current.scrollIntoView({ behavior: "instant" });
observer.disconnect();
}
});
observer.observe(helpContentRef.current);
return () => {
observer.disconnect();
}
}
return () => {};
}, [appState.helpTarget, refLookup, scroll]);

const handleResultsPerLine = (count) => {
Expand Down Expand Up @@ -325,6 +320,33 @@ export default function HelpContents({ scroll }) {
</p>
</div>
<Divider />
<a
ref={refLookup.CuratedResults}
className="anchorOffset"
id="curated_results"
href="#curated_results"
>
#curated_results
</a>
<Title level={3}>Curated Results</Title>
<p>
Curated results are based on human evaluations of EM cell types labeled in LM images of split-GAL4 lines. In general they should be more accurate than the average NeuronBridge image search hit. The name of the primary person evaluating the cell type is listed.
</p>
<p>
Curated results come from two sources:
<ul>
<li>Annotations generated as part of split-GAL4 publications, and included with releases posted to <a href="https://splitgal4.janelia.org">https://splitgal4.janelia.org</a>.</li>
<li>Scoring of PatchPerPixMatch EM search results for a subset of the cell type lines published in <a href="https://doi.org/10.7554/elife.98405.3">Meissner et al., 2025</a>. These scores and additional details may be published in a forthcoming standalone paper or addendum to the above paper.</li>
</ul>

Results have one of three confidence levels:
<ul>
<li>Confident: &gt;95% confidence, based on detailed examination of all potential associations, similar to criteria for publication.</li>
<li>Probable: 70-95% confidence, an association that seems correct but has not been as fully validated.</li>
<li>Candidate: 30-70% confidence, where more work is needed for validation and there are often multiple candidates.</li>
</ul>
</p>
<Divider />
<a
ref={refLookup.UploadAlignment}
className="anchorOffset"
Expand Down
7 changes: 1 addition & 6 deletions src/components/HelpPage.css
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,4 @@
}
}

.anchorOffset {
display: block;
position: relative;
top: -80px;
visibility: hidden;
}

4 changes: 2 additions & 2 deletions src/components/LineMeta.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ export default function LineMeta({ attributes, compact, fromSearch }) {
return (
<p>
<b>Line Name: </b>
<span>{publishedName}</span>
<Link to={`/search?q=${publishedName}`}>{publishedName}</Link>
</p>
);
}
Expand All @@ -64,7 +64,7 @@ export default function LineMeta({ attributes, compact, fromSearch }) {
<Col md={24} lg={12}>
<p>
<b>Line Name: </b>
<span>{publishedName}</span>
<Link to={`/search?q=${publishedName}`}>{publishedName}</Link>
</p>
{attributes.normalizedScore ? (
<p>
Expand Down
2 changes: 1 addition & 1 deletion src/components/References.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -188,7 +188,7 @@ export default function References() {

<dt>Raw (uncurated) Split-GAL4 Lines</dt>
<dd>
<a href="https://doi.org/10.1101/2024.01.09.574419" target="_blank" rel="noopener noreferrer">Meissner et al., 2024 <FontAwesomeIcon icon={faExternalLink} size="xs" /></a>
<a href="https://doi.org/10.7554/elife.98405.3" target="_blank" rel="noopener noreferrer">Meissner et al., 2025 <FontAwesomeIcon icon={faExternalLink} size="xs" /></a>
</dd>

<dt>FlyWire</dt>
Expand Down
8 changes: 8 additions & 0 deletions src/components/ScrollToTopOnMount.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,14 @@ import { useEffect } from "react";

function ScrollToTopOnMount() {
useEffect(() => {
const { hash } = window.location;
if (hash) {
const element = document.getElementById(hash.slice(1));
if (element) {
element.scrollIntoView();
return;
}
}
window.scrollTo(0, 0);
}, []);

Expand Down
6 changes: 3 additions & 3 deletions src/components/Search.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,14 +24,14 @@ function Search() {
if (!searchTerm) {
return;
}
if (searchTerm.length < 3) {
if (searchTerm.length < 2) {
message.error({
duration: 0,
content: "Searches must have a minimum of 3 characters.",
content: "Searches must have a minimum of 2 characters.",
key: "searchminimum",
onClick: () => message.destroy("searchminimum"),
});
setResults({ error: "Searches must have a minimum of 3 characters." });
setResults({ error: "Searches must have a minimum of 2 characters." });
return;
}
if (searchTerm.match(/\*(\*|\.)\*/)) {
Expand Down
Loading
Loading