Skip to content

Commit 9fff3dc

Browse files
authored
Merge pull request #126 from NeuroJSON/dev-fan
Improve 2D plot UX, external API routing, and state handling
2 parents 99be7a9 + c450eb4 commit 9fff3dc

9 files changed

Lines changed: 275 additions & 134 deletions

File tree

backend/src/controllers/couchdb.controller.js

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
const axios = require("axios");
2-
const COUCHDB_BASE_URL =
3-
process.env.COUCHDB_BASE_URL ||
4-
"https://cors.redoc.ly/https://neurojson.io:7777";
5-
2+
// const COUCHDB_BASE_URL =
3+
// process.env.COUCHDB_BASE_URL ||
4+
// "https://cors.redoc.ly/https://neurojson.io:7777";
5+
const COUCHDB_BASE_URL = "https://neurojson.io:7777";
66
// get all dbs list (registry)
77
const getDbList = async (req, res) => {
88
try {

backend/src/routes/dbs.routes.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ router.get("/", getDbList);
1616
router.get("/stats", getDbStats);
1717

1818
// cross-database search
19-
router.get("/search", searchAllDatabases);
19+
router.post("/search", searchAllDatabases);
2020

2121
// Specific database routes
2222
router.get("/:dbName", getDbInfo);

src/components/User/Dashboard/DatasetOrganizer/utils/plannerHelpers.ts

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -858,7 +858,14 @@ export const buildBidsPlan = async (
858858
}
859859

860860
// Preserve raw YAML string for saving
861-
const planYamlStr = raw.startsWith("```") ? planYaml._raw ?? raw : raw;
861+
// const planYamlStr = raw.startsWith("```") ? planYaml._raw ?? raw : raw;
862+
// Preserve raw YAML string for saving — strip markdown fences if present (mirrors planner.py Step 3)
863+
let planYamlStr = raw.trim();
864+
if (planYamlStr.startsWith("```yaml")) planYamlStr = planYamlStr.slice(7);
865+
else if (planYamlStr.startsWith("```"))
866+
planYamlStr = planYamlStr.split("\n").slice(1).join("\n");
867+
if (planYamlStr.endsWith("```")) planYamlStr = planYamlStr.slice(0, -3);
868+
planYamlStr = planYamlStr.trim();
862869

863870
log("✓ BIDSPlan complete");
864871
return {

src/pages/UpdatedDatasetDetailPage.tsx

Lines changed: 55 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,7 @@ import {
6868
fetchDbInfoByDatasetId,
6969
} from "redux/neurojson/neurojson.action";
7070
import { NeurojsonSelector } from "redux/neurojson/neurojson.selector";
71+
import { resetDocument } from "redux/neurojson/neurojson.slice";
7172
// import { NeurojsonService } from "services/neurojson.service";
7273
import RoutesEnum from "types/routes.enum";
7374

@@ -262,7 +263,7 @@ const UpdatedDatasetDetailPage: React.FC = () => {
262263
const [searchParams, setSearchParams] = useSearchParams();
263264
const focus = searchParams.get("focus") || undefined; // get highlight from url
264265
const rev = searchParams.get("rev") || undefined; // get revision from url
265-
266+
const [chart2DPreviewPath, setChart2DPreviewPath] = useState<string>("");
266267
const [externalLinks, setExternalLinks] = useState<ExternalDataLink[]>([]);
267268
const [internalLinks, setInternalLinks] = useState<InternalDataLink[]>([]);
268269
const [isInternalExpanded, setIsInternalExpanded] = useState(true);
@@ -284,6 +285,14 @@ const UpdatedDatasetDetailPage: React.FC = () => {
284285
? rawSummary
285286
: Object.values(rawSummary).filter(Boolean).join("\n\n");
286287
const readme = datasetDocument?.["README"] ?? "";
288+
289+
useEffect(() => {
290+
window.__clear2DPath = () => setChart2DPreviewPath("");
291+
return () => {
292+
delete window.__clear2DPath;
293+
};
294+
}, []);
295+
287296
const handleSelectRevision = (newRev?: string | null) => {
288297
setSearchParams((prev) => {
289298
const p = new URLSearchParams(prev); // copy of the query url
@@ -335,7 +344,7 @@ const UpdatedDatasetDetailPage: React.FC = () => {
335344
: "Unknown Size";
336345

337346
const parts = currentPath.split("/");
338-
const subpath = parts.slice(-3).join("/");
347+
const subpath = parts.slice(-6).join("/");
339348
const label = parentKey || "ExternalData";
340349

341350
links.push({
@@ -478,6 +487,12 @@ const UpdatedDatasetDetailPage: React.FC = () => {
478487
};
479488
}, []);
480489

490+
// clean old dataset detail and metadata panel(include rev)
491+
useEffect(() => {
492+
dispatch(resetDocument()); // clear redux state
493+
setRevsList([]); // clear local state
494+
}, [dbName, docId, dispatch]);
495+
481496
useEffect(() => {
482497
if (!dbName || !docId) return;
483498

@@ -493,10 +508,10 @@ const UpdatedDatasetDetailPage: React.FC = () => {
493508
const fromDoc = Array.isArray(datasetDocument?._revs_info)
494509
? (datasetDocument._revs_info as { rev: string }[])
495510
: [];
496-
if (fromDoc.length && revsList.length === 0) {
497-
setRevsList(fromDoc);
511+
if (fromDoc.length > 0) {
512+
setRevsList(fromDoc); // only update when we have revisions
498513
}
499-
}, [datasetDocument, revsList.length]);
514+
}, [datasetDocument]);
500515

501516
useEffect(() => {
502517
if (datasetDocument) {
@@ -625,7 +640,9 @@ const UpdatedDatasetDetailPage: React.FC = () => {
625640
const handlePreview = (
626641
dataOrUrl: string | any,
627642
idx: number,
628-
isInternal: boolean = false
643+
isInternal: boolean = false,
644+
previewPath: string = "",
645+
displayNumber?: number
629646
) => {
630647
// console.log(
631648
// "🟢 Preview button clicked for:",
@@ -635,6 +652,9 @@ const UpdatedDatasetDetailPage: React.FC = () => {
635652
// "Is Internal:",
636653
// isInternal
637654
// );
655+
setChart2DPreviewPath(
656+
displayNumber ? `[${displayNumber}] ${previewPath}` : previewPath
657+
);
638658

639659
// Clear any stale preview type from last run
640660
delete (window as any).__previewType;
@@ -783,14 +803,14 @@ const UpdatedDatasetDetailPage: React.FC = () => {
783803
// Try internal data first
784804
const internal = internalMap.get(previewPath);
785805
if (internal) {
786-
handlePreview(internal.data, internal.index, true);
806+
handlePreview(internal.data, internal.index, true, previewPath);
787807
return;
788808
}
789809

790810
// Then try external data by JSON path
791811
const external = linkMap.get(previewPath);
792812
if (external) {
793-
handlePreview(external.url, external.index, false);
813+
handlePreview(external.url, external.index, false, previewPath);
794814
}
795815
}, [
796816
datasetDocument,
@@ -1324,7 +1344,12 @@ const UpdatedDatasetDetailPage: React.FC = () => {
13241344
},
13251345
}}
13261346
onClick={() =>
1327-
handlePreview(link.data, link.index, true)
1347+
handlePreview(
1348+
link.data,
1349+
link.index,
1350+
true,
1351+
link.path
1352+
)
13281353
}
13291354
>
13301355
Preview
@@ -1463,7 +1488,7 @@ const UpdatedDatasetDetailPage: React.FC = () => {
14631488
}}
14641489
title={link.name}
14651490
>
1466-
{link.name}
1491+
{index + 1}. {link.name}
14671492
</Typography>
14681493
<Box sx={{ display: "flex", flexShrink: 0, gap: 1 }}>
14691494
<Button
@@ -1500,7 +1525,13 @@ const UpdatedDatasetDetailPage: React.FC = () => {
15001525
},
15011526
}}
15021527
onClick={() =>
1503-
handlePreview(link.url, link.index, false)
1528+
handlePreview(
1529+
link.url,
1530+
link.index,
1531+
false,
1532+
link.path,
1533+
index + 1
1534+
)
15041535
}
15051536
>
15061537
Preview
@@ -1563,12 +1594,24 @@ const UpdatedDatasetDetailPage: React.FC = () => {
15631594
</Box>
15641595
</Box>
15651596

1597+
{chart2DPreviewPath && (
1598+
<Typography
1599+
sx={{
1600+
mt: 2,
1601+
mb: 0.5,
1602+
fontSize: "0.85rem",
1603+
color: Colors.lightBlue,
1604+
}}
1605+
>
1606+
Previewing: {chart2DPreviewPath}
1607+
</Typography>
1608+
)}
15661609
<div
15671610
id="chartpanel"
15681611
style={{
15691612
display: "none",
15701613
marginTop: "16px",
1571-
background: Colors.darkGray,
1614+
background: Colors.lightGray,
15721615
color: Colors.black,
15731616
padding: "12px",
15741617
borderRadius: "8px",

src/redux/neurojson/neurojson.action.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ export const loadPaginatedData = createAsyncThunk(
4545
return rejectWithValue("No more data to load.");
4646
}
4747

48-
response.rows = response.rows.map((row) => ({
48+
response.rows = response.rows.map((row: any) => ({
4949
...row,
5050
dbName,
5151
}));

src/redux/neurojson/neurojson.slice.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,10 @@ const neurojsonSlice = createSlice({
4343
setLoading: (state, action: PayloadAction<boolean>) => {
4444
state.loading = action.payload;
4545
},
46+
resetDocument: (state) => {
47+
state.selectedDocument = null;
48+
state.datasetViewInfo = null;
49+
},
4650
},
4751
extraReducers: (builder) => {
4852
builder
@@ -169,6 +173,6 @@ const neurojsonSlice = createSlice({
169173
},
170174
});
171175

172-
export const { resetData, setLoading } = neurojsonSlice.actions;
176+
export const { resetData, setLoading, resetDocument } = neurojsonSlice.actions;
173177

174178
export default neurojsonSlice.reducer;

src/services/instance.ts

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,19 @@
11
import axios, { AxiosInstance, AxiosRequestConfig, AxiosResponse } from "axios";
22

3-
// export const baseURL =
4-
// process.env.REACT_APP_BACK_URL ??
5-
// "https://cors.redoc.ly/https://neurojson.io:7777";
3+
// ==========not mapping neurojson.org and CouchDB requests to backend api yet==============
4+
// const needsCorsProxy =
5+
// process.env.REACT_APP_USE_CORS === "true" ||
6+
// process.env.NODE_ENV === "development";
67

7-
const needsCorsProxy =
8-
process.env.REACT_APP_USE_CORS === "true" ||
9-
process.env.NODE_ENV === "development";
8+
// const backendURL = "https://neurojson.io:7777";
109

11-
const backendURL = "https://neurojson.io:7777";
10+
// export const baseURL = needsCorsProxy
11+
// ? `https://cors.redoc.ly/${backendURL}`
12+
// : backendURL;
13+
//==========================================================================================
1214

13-
export const baseURL = needsCorsProxy
14-
? `https://cors.redoc.ly/${backendURL}`
15-
: backendURL;
15+
export const baseURL =
16+
process.env.REACT_APP_API_URL || "http://localhost:5000/api/v1";
1617

1718
export const api: AxiosInstance = axios.create({
1819
baseURL,

0 commit comments

Comments
 (0)