From d8581c1ad1952a0d59afbb1f6869c9b06b745073 Mon Sep 17 00:00:00 2001
From: "Toni M. Brotons" <10654467+toni-neurosc@users.noreply.github.com>
Date: Mon, 25 Nov 2024 13:24:27 +0100
Subject: [PATCH] Add Folder selection to FileBrowser component
---
gui_dev/package.json | 36 +++++++--------
.../components/FileBrowser/FileBrowser.jsx | 45 +++++++++++++------
.../components/FileBrowser/QuickAccess.jsx | 1 -
.../pages/SourceSelection/FileSelector.jsx | 35 ++++++++++++---
py_neuromodulation/gui/backend/app_backend.py | 1 -
5 files changed, 78 insertions(+), 40 deletions(-)
diff --git a/gui_dev/package.json b/gui_dev/package.json
index 2850e8bf..0e31e9cc 100644
--- a/gui_dev/package.json
+++ b/gui_dev/package.json
@@ -9,34 +9,34 @@
"preview": "vite preview"
},
"dependencies": {
- "@emotion/react": "^11.13.3",
- "@emotion/styled": "^11.13.0",
- "@mui/icons-material": "latest",
- "@mui/material": "latest",
+ "@emotion/react": "^11.13.5",
+ "@emotion/styled": "^11.13.5",
+ "@mui/icons-material": "^6.1.8",
+ "@mui/material": "^6.1.8",
"immer": "^10.1.1",
"plotly.js-basic-dist-min": "^2.35.2",
"react": "next",
"react-dom": "next",
- "react-router-dom": "^6.26.2",
- "zustand": "latest"
+ "react-router-dom": "^7.0.1",
+ "zustand": "^5.0.1"
},
"devDependencies": {
- "@babel/core": "^7.25.7",
- "@babel/eslint-parser": "^7.25.7",
- "@babel/preset-env": "^7.25.7",
- "@babel/preset-react": "^7.25.7",
- "@eslint/compat": "^1.2.0",
- "@vitejs/plugin-react": "^4.3.2",
+ "@babel/core": "^7.26.0",
+ "@babel/eslint-parser": "^7.25.9",
+ "@babel/preset-env": "^7.26.0",
+ "@babel/preset-react": "^7.25.9",
+ "@eslint/compat": "^1.2.3",
+ "@vitejs/plugin-react": "^4.3.3",
"@welldone-software/why-did-you-render": "^8.0.3",
"babel-plugin-react-compiler": "latest",
- "eslint": "^9.12.0",
+ "eslint": "^9.15.0",
"eslint-config-prettier": "^9.1.0",
- "eslint-plugin-jsdoc": "^50.3.1",
- "eslint-plugin-react": "^7.37.1",
+ "eslint-plugin-jsdoc": "^50.5.0",
+ "eslint-plugin-react": "^7.37.2",
"eslint-plugin-react-compiler": "latest",
- "eslint-plugin-react-hooks": "^4.6.2",
- "eslint-plugin-react-refresh": "^0.4.12",
+ "eslint-plugin-react-hooks": "^5.0.0",
+ "eslint-plugin-react-refresh": "^0.4.14",
"prettier": "^3.3.3",
- "vite": "^5.4.8"
+ "vite": "^5.4.11"
}
}
diff --git a/gui_dev/src/components/FileBrowser/FileBrowser.jsx b/gui_dev/src/components/FileBrowser/FileBrowser.jsx
index 3c50c6b0..a902a931 100644
--- a/gui_dev/src/components/FileBrowser/FileBrowser.jsx
+++ b/gui_dev/src/components/FileBrowser/FileBrowser.jsx
@@ -1,6 +1,7 @@
import { useReducer, useEffect } from "react";
import {
Box,
+ Button,
Paper,
Typography,
TextField,
@@ -14,6 +15,7 @@ import {
TableSortLabel,
Modal,
Select,
+ Stack,
FormControl,
InputLabel,
Snackbar,
@@ -89,8 +91,10 @@ const columns = [
export const FileBrowser = ({
isModal = false,
directory = null,
+ onlyDirectories = false,
+ allowedExtensions = ALLOWED_EXTENSIONS,
onClose,
- onFileSelect,
+ onSelect,
}) => {
const [state, dispatch] = useReducer(reducer, initialState);
@@ -141,11 +145,16 @@ export const FileBrowser = ({
const fetchFiles = async (path) => {
try {
- const files = await fileManager.getFiles({
+ let files = await fileManager.getFiles({
path,
- allowedExtensions: ALLOWED_EXTENSIONS.join(","),
+ allowedExtensions: allowedExtensions.join(","),
showHidden: state.showHiddenFiles,
});
+
+ if (onlyDirectories) {
+ files = files.filter((file) => file.is_directory);
+ }
+
dispatch({
type: "SET_FILES",
payload: files.map((file) => ({
@@ -164,13 +173,13 @@ export const FileBrowser = ({
}
};
- const handleFileClick = (file) => {
+ const handleRowClick = (file) => {
if (file.is_directory) {
dispatch({ type: "SET_CURRENT_PATH", payload: file.path });
} else if (
ALLOWED_EXTENSIONS.some((ext) => file.name.toLowerCase().endsWith(ext))
) {
- onFileSelect(file);
+ onSelect(file);
}
};
@@ -272,9 +281,9 @@ export const FileBrowser = ({
};
const FileBrowserContent = (
-
-
-
+
+
+
{state.drives.length > 1 && (
Drive
@@ -333,7 +342,7 @@ export const FileBrowser = ({
{" "}
-
+
handleFileClick(file)}
+ onClick={() => handleRowClick(file)}
sx={{ cursor: "pointer" }}
>
{columns.map((column) => (
@@ -399,13 +406,25 @@ export const FileBrowser = ({
+
+
+ {onlyDirectories && (
+
+ )}
+
+
dispatch({ type: "SET_ERROR", payload: "" })}
message={state.error}
/>
-
+
);
return isModal ? (
diff --git a/gui_dev/src/components/FileBrowser/QuickAccess.jsx b/gui_dev/src/components/FileBrowser/QuickAccess.jsx
index 47dfaa34..f5778060 100644
--- a/gui_dev/src/components/FileBrowser/QuickAccess.jsx
+++ b/gui_dev/src/components/FileBrowser/QuickAccess.jsx
@@ -57,7 +57,6 @@ export const QuickAccessSidebar = ({ onItemClick }) => {
flexGrow: 1,
display: "flex",
flexDirection: "column",
- maxHeight: 400,
overflowX: "hidden",
overflowY: "auto",
scrollbarWidth: "thin",
diff --git a/gui_dev/src/pages/SourceSelection/FileSelector.jsx b/gui_dev/src/pages/SourceSelection/FileSelector.jsx
index c5f149d8..39eaa592 100644
--- a/gui_dev/src/pages/SourceSelection/FileSelector.jsx
+++ b/gui_dev/src/pages/SourceSelection/FileSelector.jsx
@@ -23,15 +23,12 @@ export const FileSelector = () => {
const [isSelecting, setIsSelecting] = useState(false);
const [showFileBrowser, setShowFileBrowser] = useState(false);
+ const [showFolderBrowser, setShowFolderBrowser] = useState(false);
useEffect(() => {
setSourceType("lsl");
}, []);
- const handleSelectFile = () => {
- setShowFileBrowser(true);
- };
-
const handleFileSelect = (file) => {
setIsSelecting(true);
@@ -50,11 +47,17 @@ export const FileSelector = () => {
}
};
+ const handleFolderSelect = (folder) => {
+ setShowFolderBrowser(false);
+ };
+
return (
+
{streamSetupMessage && (
{
isModal={true}
directory={fileBrowserDirRef.current}
onClose={() => setShowFileBrowser(false)}
- onFileSelect={handleFileSelect}
+ onSelect={handleFileSelect}
+ />
+ )}
+ {showFolderBrowser && (
+ setShowFolderBrowser(false)}
+ onSelect={handleFolderSelect}
+ onlyDirectories={true}
/>
)}
diff --git a/py_neuromodulation/gui/backend/app_backend.py b/py_neuromodulation/gui/backend/app_backend.py
index abbccfee..9847baf4 100644
--- a/py_neuromodulation/gui/backend/app_backend.py
+++ b/py_neuromodulation/gui/backend/app_backend.py
@@ -12,7 +12,6 @@
Query,
WebSocket,
)
-from fastapi.responses import FileResponse
from fastapi.staticfiles import StaticFiles
from fastapi.middleware.cors import CORSMiddleware
from pydantic import ValidationError