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