Skip to content

Commit 033d4fe

Browse files
SimplyLizclaude
andcommitted
Make genome selector the start page and always accessible from sidebar
- Remove auto-redirect from / to last genome; always land on /genomes - Remove auto-redirect in GenomeSelectorPage that bounced back to /g/:id when only one genome existed (prevented users from importing new genomes) - Sidebar: always show Genomes link, fetch genomes list on mount so the link is available even when navigating directly to /g/:id Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent 8525bc6 commit 033d4fe

6 files changed

Lines changed: 47 additions & 39 deletions

File tree

frontend/src/App.js

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,10 +12,6 @@ import { SimulationPage } from "./pages/SimulationPage";
1212
import { GeneAnalysisPage } from "./pages/GeneAnalysisPage";
1313
import { CellForgePage } from "./pages/CellForgePage";
1414
function RedirectToLastGenome() {
15-
const lastId = localStorage.getItem("biolab_last_genome");
16-
if (lastId) {
17-
return _jsx(Navigate, { to: `/g/${lastId}`, replace: true });
18-
}
1915
return _jsx(Navigate, { to: "/genomes", replace: true });
2016
}
2117
export function App() {

frontend/src/App.tsx

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,10 +12,6 @@ import { GeneAnalysisPage } from "./pages/GeneAnalysisPage";
1212
import { CellForgePage } from "./pages/CellForgePage";
1313

1414
function RedirectToLastGenome() {
15-
const lastId = localStorage.getItem("biolab_last_genome");
16-
if (lastId) {
17-
return <Navigate to={`/g/${lastId}`} replace />;
18-
}
1915
return <Navigate to="/genomes" replace />;
2016
}
2117

frontend/src/components/Sidebar.js

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2+
import { useEffect, useCallback } from "react";
23
import { NavLink, useParams } from "react-router-dom";
34
import { useGeneStore } from "../store";
5+
const API = `${location.protocol}//${location.host}/api/v1`;
46
const NAV_ITEMS = [
57
{
68
path: "",
@@ -36,8 +38,23 @@ const NAV_ITEMS = [
3638
export function Sidebar() {
3739
const { genomeId } = useParams();
3840
const genomes = useGeneStore((s) => s.genomes);
41+
const setGenomes = useGeneStore((s) => s.setGenomes);
3942
const activeGenomeId = useGeneStore((s) => s.activeGenomeId);
43+
const fetchGenomes = useCallback(async () => {
44+
try {
45+
const res = await fetch(`${API}/genomes`);
46+
if (res.ok) {
47+
const data = await res.json();
48+
setGenomes(data);
49+
}
50+
}
51+
catch { /* silent */ }
52+
}, [setGenomes]);
53+
useEffect(() => {
54+
if (genomes.length === 0)
55+
fetchGenomes();
56+
}, [genomes.length, fetchGenomes]);
4057
const basePath = genomeId ? `/g/${genomeId}` : activeGenomeId ? `/g/${activeGenomeId}` : "";
4158
return (_jsxs("nav", { className: "sidebar", children: [_jsx("div", { className: "sidebar-logo", children: _jsxs(NavLink, { to: "/", className: "sidebar-logo-link", children: [_jsx("span", { className: "logo-gene", children: "G" }), _jsx("span", { className: "logo-life", children: "L" })] }) }), _jsx("div", { className: "sidebar-nav", children: basePath &&
42-
NAV_ITEMS.map((item) => (_jsxs(NavLink, { to: `${basePath}${item.path}`, end: item.path === "", className: ({ isActive }) => `sidebar-item ${isActive ? "sidebar-item-active" : ""}`, title: item.label, children: [_jsx("span", { className: "sidebar-icon", children: item.icon }), _jsx("span", { className: "sidebar-label", children: item.label })] }, item.path))) }), _jsx("div", { className: "sidebar-footer", children: genomes.length > 0 && (_jsxs(NavLink, { to: "/genomes", className: "sidebar-item sidebar-genome-picker", title: "Switch Genome", children: [_jsx("span", { className: "sidebar-icon", children: _jsxs("svg", { width: "20", height: "20", viewBox: "0 0 20 20", fill: "none", stroke: "currentColor", strokeWidth: "1.5", children: [_jsx("path", { d: "M3 7l7-5 7 5-7 5z" }), _jsx("path", { d: "M3 13l7 5 7-5" }), _jsx("path", { d: "M3 10l7 5 7-5" })] }) }), _jsx("span", { className: "sidebar-label", children: "Genomes" })] })) })] }));
59+
NAV_ITEMS.map((item) => (_jsxs(NavLink, { to: `${basePath}${item.path}`, end: item.path === "", className: ({ isActive }) => `sidebar-item ${isActive ? "sidebar-item-active" : ""}`, title: item.label, children: [_jsx("span", { className: "sidebar-icon", children: item.icon }), _jsx("span", { className: "sidebar-label", children: item.label })] }, item.path))) }), _jsx("div", { className: "sidebar-footer", children: _jsxs(NavLink, { to: "/genomes", className: "sidebar-item sidebar-genome-picker", title: "Switch Genome", children: [_jsx("span", { className: "sidebar-icon", children: _jsxs("svg", { width: "20", height: "20", viewBox: "0 0 20 20", fill: "none", stroke: "currentColor", strokeWidth: "1.5", children: [_jsx("path", { d: "M3 7l7-5 7 5-7 5z" }), _jsx("path", { d: "M3 13l7 5 7-5" }), _jsx("path", { d: "M3 10l7 5 7-5" })] }) }), _jsx("span", { className: "sidebar-label", children: "Genomes" })] }) })] }));
4360
}

frontend/src/components/Sidebar.tsx

Lines changed: 29 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
1+
import { useEffect, useCallback } from "react";
12
import { NavLink, useParams } from "react-router-dom";
23
import { useGeneStore } from "../store";
34

5+
const API = `${location.protocol}//${location.host}/api/v1`;
6+
47
const NAV_ITEMS = [
58
{
69
path: "",
@@ -74,8 +77,24 @@ const NAV_ITEMS = [
7477
export function Sidebar() {
7578
const { genomeId } = useParams();
7679
const genomes = useGeneStore((s) => s.genomes);
80+
const setGenomes = useGeneStore((s) => s.setGenomes);
7781
const activeGenomeId = useGeneStore((s) => s.activeGenomeId);
7882

83+
// Fetch genomes list so the switcher link is always available
84+
const fetchGenomes = useCallback(async () => {
85+
try {
86+
const res = await fetch(`${API}/genomes`);
87+
if (res.ok) {
88+
const data = await res.json();
89+
setGenomes(data);
90+
}
91+
} catch { /* silent */ }
92+
}, [setGenomes]);
93+
94+
useEffect(() => {
95+
if (genomes.length === 0) fetchGenomes();
96+
}, [genomes.length, fetchGenomes]);
97+
7998
const basePath = genomeId ? `/g/${genomeId}` : activeGenomeId ? `/g/${activeGenomeId}` : "";
8099

81100
return (
@@ -106,18 +125,16 @@ export function Sidebar() {
106125
</div>
107126

108127
<div className="sidebar-footer">
109-
{genomes.length > 0 && (
110-
<NavLink to="/genomes" className="sidebar-item sidebar-genome-picker" title="Switch Genome">
111-
<span className="sidebar-icon">
112-
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" stroke="currentColor" strokeWidth="1.5">
113-
<path d="M3 7l7-5 7 5-7 5z" />
114-
<path d="M3 13l7 5 7-5" />
115-
<path d="M3 10l7 5 7-5" />
116-
</svg>
117-
</span>
118-
<span className="sidebar-label">Genomes</span>
119-
</NavLink>
120-
)}
128+
<NavLink to="/genomes" className="sidebar-item sidebar-genome-picker" title="Switch Genome">
129+
<span className="sidebar-icon">
130+
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" stroke="currentColor" strokeWidth="1.5">
131+
<path d="M3 7l7-5 7 5-7 5z" />
132+
<path d="M3 13l7 5 7-5" />
133+
<path d="M3 10l7 5 7-5" />
134+
</svg>
135+
</span>
136+
<span className="sidebar-label">Genomes</span>
137+
</NavLink>
121138
</div>
122139
</nav>
123140
);

frontend/src/pages/GenomeSelectorPage.js

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -14,15 +14,6 @@ export function GenomeSelectorPage() {
1414
useEffect(() => {
1515
fetchGenomes();
1616
}, [fetchGenomes]);
17-
// If only one genome and coming from /, auto-redirect
18-
useEffect(() => {
19-
if (genomes.length === 1) {
20-
const lastId = localStorage.getItem("biolab_last_genome");
21-
if (lastId) {
22-
navigate(`/g/${lastId}`, { replace: true });
23-
}
24-
}
25-
}, [genomes, navigate]);
2617
const handleSearch = useCallback((query) => {
2718
setSearchQuery(query);
2819
setError(null);

frontend/src/pages/GenomeSelectorPage.tsx

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -24,15 +24,6 @@ export function GenomeSelectorPage() {
2424
fetchGenomes();
2525
}, [fetchGenomes]);
2626

27-
// If only one genome and coming from /, auto-redirect
28-
useEffect(() => {
29-
if (genomes.length === 1) {
30-
const lastId = localStorage.getItem("biolab_last_genome");
31-
if (lastId) {
32-
navigate(`/g/${lastId}`, { replace: true });
33-
}
34-
}
35-
}, [genomes, navigate]);
3627

3728
const handleSearch = useCallback(
3829
(query: string) => {

0 commit comments

Comments
 (0)