Skip to content

First iteration of a PyNM GUI for easy feature extraction and visualization #361

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 35 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
c2462e5
Set up development environment
toni-neurosc Sep 19, 2024
2cda2cb
Fixed run_flask
Jul 10, 2024
82f2d0c
Update to React 19, add ESLint, add code-workspace
toni-neurosc Jul 11, 2024
d7bf811
Add PyWebView window API, create basic app UI, add Zustand stores, ad…
toni-neurosc Jul 22, 2024
80de293
Remove fontsource import
toni-neurosc Jul 23, 2024
c62e967
add required dependencies
timonmerk Jul 24, 2024
6028787
Move the PyWebView window API into the window class file
toni-neurosc Jul 23, 2024
af6274d
Tweak CSS reset
toni-neurosc Jul 23, 2024
cb3f5e6
Change toml to tomllib (python 3.11 required)
toni-neurosc Jul 25, 2024
2c70947
Change from Flask to FastAPI, add loggers
toni-neurosc Jul 31, 2024
c67a421
Add websockets with FastAPI, defer imports, fix Graph component
toni-neurosc Jul 31, 2024
5c57007
Fix HMR, socket connection
toni-neurosc Aug 1, 2024
f1357d9
Added Text_field.jsx
Jul 12, 2024
18bd936
Add dropdown component
Jul 26, 2024
5aee283
Add Accordion component
Jul 29, 2024
2692fec
Changed accordion to collapsible box
Jul 29, 2024
add0cc7
fixed CollapsibleBox, used useEffect, removed <input>
elizaveta-terek Jul 29, 2024
d452508
Simplify component imports
toni-neurosc Jul 30, 2024
5678b9d
Fix CollapsibleBox component
toni-neurosc Jul 30, 2024
5b0cd0a
Upload static files, fix signals for posix os in app_manager
toni-neurosc Aug 1, 2024
aff7b95
fix subprocess.Popen for MacOS
toni-neurosc Aug 1, 2024
f78302a
Improve sidebar
toni-neurosc Aug 1, 2024
97799aa
Layout redesign: new App bar, and other improvements (#356)
toni-neurosc Aug 30, 2024
ced0bad
Fix about modal
toni-neurosc Aug 30, 2024
91c588b
Add backend stream init and frontend setup page (#358)
timonmerk Sep 18, 2024
ffbac39
add backend stream run process
timonmerk Sep 20, 2024
998dbef
fix imports
toni-neurosc Sep 20, 2024
44fd4c5
fix additional imports
timonmerk Sep 20, 2024
d3f5401
add debugging file and fix another import
timonmerk Sep 20, 2024
50e3527
WIP calling run function and setting up websocket connetion
timonmerk Sep 22, 2024
1296a81
Liz gui (#360)
elizaveta-terek Sep 22, 2024
b770784
async run function gets now called but websocket connection needs to …
timonmerk Sep 22, 2024
b137462
add cbor
timonmerk Sep 22, 2024
0ee03ed
fix installation version
timonmerk Oct 2, 2024
dfbdc79
remove vite proxy
timonmerk Oct 4, 2024
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
15 changes: 13 additions & 2 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -191,6 +191,17 @@ out_per
# Profiler files
/*.prof
/profiling/*

# Test output
test_data/
# various lock files
package-lock.json
package-lock.json.bak
uv.lock
# temporarily ignore the frontend build
/gui_dev/dist
/gui/frontend
# Node modules
gui_dev/node_modules/*
test/data/*

# LSL log file
lsllog.txt
21 changes: 21 additions & 0 deletions gui_dev/.eslintrc.cjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
module.exports = {
root: true,
env: { browser: true, es2020: true },
extends: [
'eslint:recommended',
'plugin:react/recommended',
'plugin:react/jsx-runtime',
'plugin:react-hooks/recommended',
],
ignorePatterns: ['dist', '.eslintrc.cjs'],
parserOptions: { ecmaVersion: 'latest', sourceType: 'module' },
settings: { react: { version: '18.2' } },
plugins: ['react-refresh'],
rules: {
'react/jsx-no-target-blank': 'off',
'react-refresh/only-export-components': [
'warn',
{ allowConstantExport: true },
],
},
}
3 changes: 3 additions & 0 deletions gui_dev/.gitattributes
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
*.lockb binary diff=lockb
*.lockb diff=lockb
*.lockb textconv=bun
17 changes: 17 additions & 0 deletions gui_dev/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*
lerna-debug.log*

# JS
node_modules
dist
dist-ssr
*.local

# Dev-scripts
gui_startup.py
Binary file added gui_dev/bun.lockb
Binary file not shown.
51 changes: 51 additions & 0 deletions gui_dev/eslint.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import globals from "globals";
import js from "@eslint/js";
import jsdoc from "eslint-plugin-jsdoc";
import react from "eslint-plugin-react";
import reactHooks from "eslint-plugin-react-hooks";
import reactRefresh from "eslint-plugin-react-refresh";
import reactCompiler from "eslint-plugin-react-compiler";
import babelParser from "@babel/eslint-parser";

export default [
js.configs.recommended,
jsdoc.configs["flat/recommended-typescript-flavor"],
{ files: ["**/*.{js,mjs,cjs,jsx}"] },
{ languageOptions: { parserOptions: { ecmaFeatures: { jsx: true } } } },
{ languageOptions: { globals: globals.browser } },
{
files: ["**/*.{js,jsx,mjs,cjs,ts,tsx}"],
plugins: {
jsdoc,
react,
reactHooks,
"react-refresh": reactRefresh,
"react-compiler": reactCompiler,
},
languageOptions: {
ecmaVersion: "latest",
sourceType: "module",
parser: babelParser,
parserOptions: {
requireConfigFile: false,
babelOptions: {
babelrc: false,
configFile: false,
presets: ["@babel/preset-env", "@babel/preset-react"],
},
ecmaFeatures: {
jsx: true,
},
},
},
rules: {
"react/jsx-uses-react": "error",
"react/jsx-uses-vars": "error",
},
settings: {
react: {
version: "19",
},
},
},
];
13 changes: 13 additions & 0 deletions gui_dev/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<link rel="icon" type="image/svg+xml" href="/charite.svg" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>PyNeuromodulation</title>
</head>
<body>
<div id="root"></div>
<script type="module" src="/src/main.jsx"></script>
</body>
</html>
13 changes: 13 additions & 0 deletions gui_dev/jsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
{
"compilerOptions": {
"baseUrl": "./",
"target": "ES6",
"checkJs": true,
"module": "ES6",
"moduleResolution": "node",
"paths": {
"@/*": ["./src/*"]
},
"jsx": "react-jsx"
}
}
43 changes: 43 additions & 0 deletions gui_dev/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
{
"license": "MIT",
"type": "module",
"private": true,
"scripts": {
"dev": "vite",
"build": "vite build",
"lint": "eslint . --ext js,jsx --report-unused-disable-directives --max-warnings 0",
"preview": "vite preview"
},
"dependencies": {
"@emotion/react": "^11.13.3",
"@emotion/styled": "^11.13.0",
"@mui/icons-material": "latest",
"@mui/material": "latest",
"immer": "^10.1.1",
"plotly.js-basic-dist-min": "^2.35.2",
"react": "next",
"react-dom": "next",
"react-icons": "^5.3.0",
"react-router-dom": "^6.26.2",
"zustand": "next"
},
"devDependencies": {
"@babel/core": "^7.25.2",
"@babel/eslint-parser": "^7.25.1",
"@babel/preset-env": "^7.25.4",
"@babel/preset-react": "^7.24.7",
"@eslint/compat": "^1.1.1",
"@vitejs/plugin-react": "^4.3.2",
"@welldone-software/why-did-you-render": "^8.0.3",
"babel-plugin-react-compiler": "latest",
"eslint": "^9.11.1",
"eslint-config-prettier": "^9.1.0",
"eslint-plugin-jsdoc": "^50.3.1",
"eslint-plugin-react": "^7.37.1",
"eslint-plugin-react-compiler": "latest",
"eslint-plugin-react-hooks": "^4.6.2",
"eslint-plugin-react-refresh": "^0.4.12",
"prettier": "^3.3.3",
"vite": "^5.4.8"
}
}
16 changes: 16 additions & 0 deletions gui_dev/public/charite.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
9 changes: 9 additions & 0 deletions gui_dev/scripts/wdyr.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import React from "react";
import whyDidYouRender from "@welldone-software/why-did-you-render";
if (process.env.NODE_ENV === "development") {
whyDidYouRender(React, {
trackAllPureComponents: true,
logOnDifferentValues: true,
collapseGroups: false,
});
}
90 changes: 90 additions & 0 deletions gui_dev/src/App.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
import { useEffect } from "react";
import {
useSocketStore,
useFetchSettings,
useInitPyWebView,
useFetchAppInfo,
} from "@/stores";
import {
BrowserRouter as Router,
Route,
Routes,
Navigate,
} from "react-router-dom";
import { Box, Stack, ThemeProvider } from "@mui/material";
import CssBaseline from "@mui/material/CssBaseline";
import { AppBar, StatusBar } from "@/components";
import {
Dashboard,
SourceSelection,
Channels,
Settings,
Decoding,
} from "@/pages";
import { theme } from "./theme";
import { StreamSelector } from "@/pages/SourceSelection/StreamSelector";
import { FileSelector } from "@/pages/SourceSelection/FileSelector";

/**
*
* @returns {JSX.Element} The rendered App component
*/
export const App = () => {
// Get settings from backend on start-up and check for PyWebView
const initPyWebView = useInitPyWebView();
const fetchSettingsWithDelay = useFetchSettings();
const fetchAppInfo = useFetchAppInfo();

useEffect(() => {
fetchSettingsWithDelay();
initPyWebView();
fetchAppInfo();
}, [fetchSettingsWithDelay, initPyWebView, fetchAppInfo]);

// Connect to web-socket
const connectSocket = useSocketStore((state) => state.connectSocket);
const disconnectSocket = useSocketStore((state) => state.disconnectSocket);

useEffect(() => {
console.log("Connecting socket from App component...");
connectSocket();
return () => {
console.log("Disconnecting socket from App component...");
disconnectSocket();
};
}, [connectSocket, disconnectSocket]);

return (
<ThemeProvider theme={theme}>
<CssBaseline />
<Router>
<Stack height="100vh" width="100vw" overflow="hidden">
<AppBar />
<Box
sx={{
height: "100%",
overflow: "auto",
width: "100%",
p: 0,
m: 0,
}}
>
<Routes>
<Route index element={<Navigate to="/source" replace />} />
<Route path="source" element={<SourceSelection />}>
<Route index element={<Navigate to="/source/file" replace />} />
<Route path="file" element={<FileSelector />} />
<Route path="lsl" element={<StreamSelector />} />
</Route>
<Route path="channels" element={<Channels />} />
<Route path="settings" element={<Settings />} />
<Route path="dashboard" element={<Dashboard />} />
<Route path="decoding" element={<Decoding />} />
</Routes>
</Box>
<StatusBar />
</Stack>
</Router>
</ThemeProvider>
);
};
Binary file not shown.
Binary file not shown.
Loading
Loading