diff --git a/Dockerfile b/Dockerfile index 51bb27b..2713828 100644 --- a/Dockerfile +++ b/Dockerfile @@ -8,19 +8,17 @@ COPY webapp/yarn.lock . COPY webapp/package.json . RUN yarn install --network-timeout 1000000000 COPY webapp/ . -RUN yarn build -#Remove node_modules, need to keep the geppetto client -RUN rm -Rf node_modules +RUN yarn build && rm -Rf node_modules ### -FROM jupyter/base-notebook:hub-1.5.0 +FROM quay.io/jupyter/base-notebook:latest ENV NB_UID=jovyan ENV FOLDER=nwb-explorer USER root RUN jupyter labextension disable @jupyterlab/hub-extension RUN apt-get update -qq &&\ - apt-get install python3-tk vim nano unzip git g++ -qq - + apt-get install python3-tk vim nano unzip git g++ -qq\ + && rm -rf /var/lib/apt/lists USER $NB_UID COPY --chown=1000:1000 requirements.txt . RUN --mount=type=cache,target=/root/.cache python -m pip install --upgrade pip &&\ @@ -34,23 +32,15 @@ WORKDIR $FOLDER RUN mkdir workspace - -# Temporary fix for deprecated api usage on some requirement -RUN pip install setuptools==45 - - - # RUN --mount=type=cache,target=/root/.cache python -m pip install --upgrade pip &&\ # python utilities/install.py --npm-skip - -RUN rm -rf /var/lib/apt/lists +USER root # sym link workspace pvc to $FOLDER RUN mkdir -p /opt/workspace RUN mkdir -p /opt/home # clean workspace from tests RUN rm -Rf workspace/* -RUN chown $NB_UID app.log RUN chown $NB_UID /opt/workspace RUN chown $NB_UID /opt/home RUN ln -s /opt/workspace ./workspace diff --git a/Dockerfile_dev b/Dockerfile_dev deleted file mode 100644 index eb7585d..0000000 --- a/Dockerfile_dev +++ /dev/null @@ -1,28 +0,0 @@ -FROM metacell/jupyter-neuron:development -ARG BUILD_DEV -ARG DEV_BRANCH - -ENV FOLDER=nwb-explorer -ENV DEV=--dev - -USER root -RUN apt-get update -qq &&\ - apt-get install python3-tk vim nano unzip -qq -RUN npm i -g npm@6 - -RUN chown -R 1000:100 $HOME/.npm -USER $NB_UID - -RUN jupyter labextension disable @jupyterlab/hub-extension - -COPY --chown=1000:1000 . ${FOLDER} - -RUN python $FOLDER/utilities/install.py ${BUILD_DEV:+$DEV} ${DEV_BRANCH:+--branch=$DEV_BRANCH} -RUN mv $FOLDER/webapp/node_modules/@geppettoengine . -RUN rm -Rf $FOLDER/webapp/node_modules/* -RUN mv @geppettoengine $FOLDER/webapp/node_modules -WORKDIR $HOME/$FOLDER - -EXPOSE 8000 - -CMD ./NWBE \ No newline at end of file diff --git a/README.md b/README.md index 41694e6..aa8c5fb 100644 --- a/README.md +++ b/README.md @@ -23,8 +23,8 @@ Alternatively, to see a working demo of nwb explorer without a local setup see t Below you will find the software you need to install to use nwb explorer (and the versions we used): * Git (2+). -* Node (10+) and npm (6+). -* Python 3 (3.7+), pip (20+) +* Node (20+) and npm (7+). +* Python 3 (3.10+), pip (20+) #### Python Dependencies diff --git a/node_modules/.yarn-integrity b/node_modules/.yarn-integrity deleted file mode 100644 index f498cf6..0000000 --- a/node_modules/.yarn-integrity +++ /dev/null @@ -1,12 +0,0 @@ -{ - "systemParams": "linux-x64-93", - "modulesFolders": [ - "node_modules" - ], - "flags": [], - "linkedModules": [], - "topLevelPatterns": [], - "lockfileEntries": {}, - "files": [], - "artifacts": {} -} \ No newline at end of file diff --git a/nwb_explorer/api.py b/nwb_explorer/api.py index 51a43e0..dc4e6be 100644 --- a/nwb_explorer/api.py +++ b/nwb_explorer/api.py @@ -20,6 +20,7 @@ def create_notebook(filename): from nbformat.v4.nbbase import new_notebook from nbformat import sign import codecs + logging.info("Creating notebook {}".format(filename)) directory = os.path.dirname(filename) if not os.path.exists(directory): @@ -81,7 +82,6 @@ def image(handler: IPythonHandler, clientId: str, name: str, interface: str, pro @get('/notebook') def new_notebook(handler: IPythonHandler, path): - if not os.path.exists(path): - logging.info("Creating notebook {}".format(path)) + if not os.path.exists(os.path.join('workspace', path)): create_notebook(path) handler.redirect('notebooks/' + path) diff --git a/requirements.txt b/requirements.txt index db3be1f..a149c7d 100644 --- a/requirements.txt +++ b/requirements.txt @@ -4,10 +4,12 @@ jupyter-core<6.0.0 # jupyterhub==4.0.2 jupyterthemes==0.20.0 nbclient==0.10.0 +notebook==6.5.7 jupyter_geppetto==1.1.5 pynwb==2.8.3 nwbwidgets==0.11.3 -nwbinspector==0.6.0 +hdmf-zarr==0.10.0 +nwbinspector==0.6.1 quantities pyecore==0.15.2 pygeppetto==0.9.0 @@ -24,7 +26,7 @@ ipyvolume==0.6.2 # ipywidgets>=8.0.0 plotly==5.13.1 tqdm>=4.36.0 -zarr +zarr==2.18.4 tifffile ndx-spectrum ndx-icephys-meta diff --git a/webapp/Main.js b/webapp/Main.js index 05f307c..5bcae08 100644 --- a/webapp/Main.js +++ b/webapp/Main.js @@ -3,15 +3,15 @@ global.GEPPETTO_CONFIGURATION = require('./GeppettoConfiguration.json'); const { initGeppetto } = require('@metacell/geppetto-meta-client/GEPPETTO'); import { LoadingSpinner } from '@metacell/geppetto-meta-client/components'; import ErrorDialog from './components/reduxconnect/ErrorDialogContainer'; - +import CssBaseline from '@mui/material/CssBaseline'; require('babel-polyfill'); const { Provider } = require('react-redux'); -const configureStore = require('./redux/store').default; +const store = require('./redux/store').store; -const ReactDOM = require('react-dom'); +const { createRoot } = require('react-dom/client'); const React = require('react'); -const { MuiThemeProvider } = require('@material-ui/core/styles'); +const { ThemeProvider } = require('@mui/material/styles'); const Utils = require('./Utils').default; @@ -21,15 +21,15 @@ const App = require('./components/reduxconnect/AppContainer').default; const nwbFileService = require('./services/NWBFileService').default; import { loadNWBFile, clearModel } from './redux/actions/nwbfile'; -initGeppetto(true); +initGeppetto(true, false); // MUI theming const theme = require('./theme').default; window.updateFile = nwbFileService.setNWBFileUrl; -const store = configureStore(); -import './styles/main.less'; +import '@metacell/geppetto-meta-client/common/layout/styles/dark.css'; +import './styles/nwb.css'; (function init () { @@ -67,15 +67,16 @@ import './styles/main.less'; window.load = loadFromEvent; - - ReactDOM.render( - + const container = document.getElementById("mainContainer"); + const root = createRoot(container); // createRoot(container!) if you use TypeScript + root.render( + + - , - document.getElementById('mainContainer'), + ); }()); diff --git a/webapp/Utils.js b/webapp/Utils.js index c333dff..a3fbb5a 100644 --- a/webapp/Utils.js +++ b/webapp/Utils.js @@ -3,7 +3,7 @@ import { execPythonMessage, evalPythonMessage, } from '@metacell/geppetto-meta-client/communication/geppettoJupyter/GeppettoJupyterUtils'; -import { teal, deepOrange, lightGreen, purple, amber, cyan, brown, lime, pink, yellow, indigo, red, lightBlue, orange, green, blueGrey, } from '@material-ui/core/colors'; +import { teal, deepOrange, lightGreen, purple, amber, cyan, brown, lime, pink, yellow, indigo, red, lightBlue, orange, green, blueGrey, } from '@mui/material/colors'; const Utils = { diff --git a/webapp/components/AddPlotMenu.js b/webapp/components/AddPlotMenu.js index d645f4e..0704998 100644 --- a/webapp/components/AddPlotMenu.js +++ b/webapp/components/AddPlotMenu.js @@ -1,7 +1,6 @@ import React, { Component } from 'react'; -import Menu from '@material-ui/core/Menu'; -import Popover from '@material-ui/core/Popover'; -import MenuItem from '@material-ui/core/MenuItem'; +import Menu from '@mui/material/Menu'; +import MenuItem from '@mui/material/MenuItem'; const anchor = { origin: { diff --git a/webapp/components/CustomIconComponent.js b/webapp/components/CustomIconComponent.js index b275e1b..339d29b 100644 --- a/webapp/components/CustomIconComponent.js +++ b/webapp/components/CustomIconComponent.js @@ -1,5 +1,5 @@ import React from 'react'; -import IconButton from '@material-ui/core/IconButton'; +import IconButton from '@mui/material/IconButton'; import { isString } from '../Utils'; const IconComponent = ({ action, color, tooltip, Icon, }) => ( @@ -8,7 +8,7 @@ const IconComponent = ({ action, color, tooltip, Icon, }) => ( className="list-icon" title={tooltip} onClick={action} - > + size="large"> ); diff --git a/webapp/components/Dialog.js b/webapp/components/Dialog.js index af89213..0eb6667 100644 --- a/webapp/components/Dialog.js +++ b/webapp/components/Dialog.js @@ -1,39 +1,38 @@ import React from 'react'; -import Button from '@material-ui/core/Button'; -import MuiDialog from '@material-ui/core/Dialog'; -import DialogActions from '@material-ui/core/DialogActions'; -import DialogContent from '@material-ui/core/DialogContent'; -import Typography from '@material-ui/core/Typography'; -import DialogTitle from '@material-ui/core/DialogTitle'; -import Paper from '@material-ui/core/Paper'; -import Grid from '@material-ui/core/Grid'; -import Box from '@material-ui/core/Box'; -import Link from '@material-ui/core/Link'; -import { withStyles } from '@material-ui/core/styles'; -import { fontColor } from '../theme'; +import Button from '@mui/material/Button'; +import MuiDialog from '@mui/material/Dialog'; +import DialogActions from '@mui/material/DialogActions'; +import DialogContent from '@mui/material/DialogContent'; +import Typography from '@mui/material/Typography'; +import DialogTitle from '@mui/material/DialogTitle'; +import Paper from '@mui/material/Paper'; +import Grid from '@mui/material/Grid2'; +import Box from '@mui/material/Box'; +import Link from '@mui/material/Link'; import logo_nwb_explorer from '../resources/logos/nwb-explorer.png'; import logo_metacell from '../resources/logos/metacell_logo.png'; import logo_osb_colour from '../resources/logos/osblogofull.png'; import { NWBE_WEBSITE } from '../constants'; -const styles = theme => ({ +const styles = { paper: { backgroundColor: '#4a4a4a', textAlign: 'center', - padding: theme.spacing(2) + padding: 2, + '& .MuiTypography-root': { color: "var(--font-color)", }, }, -}); +}; -const AboutContent = withStyles(styles)(({ classes }) => ( +const AboutContent = () => ( - + - + - + Powered by @@ -44,17 +43,17 @@ const AboutContent = withStyles(styles)(({ classes }) => ( - NWB Explorer v0.7.0 + NWB Explorer v0.7.0 - + NWB Explorer is a web application that can be used by scientists to read, visualize and explore the content of NWB:N 2 files. - + Want to know more? Go to our {' '} website @@ -63,7 +62,7 @@ const AboutContent = withStyles(styles)(({ classes }) => ( - + NWB Explorer is being developed in collaboration with: @@ -73,7 +72,7 @@ const AboutContent = withStyles(styles)(({ classes }) => ( -)); +); export default function Dialog ({ open, title, message, handleClose, }) { return ( diff --git a/webapp/components/ErrorDialog.js b/webapp/components/ErrorDialog.js index 7df339c..f4bc1aa 100644 --- a/webapp/components/ErrorDialog.js +++ b/webapp/components/ErrorDialog.js @@ -1,10 +1,10 @@ import React from "react"; -import Button from "@material-ui/core/Button"; -import Dialog from "@material-ui/core/Dialog"; -import Alert from "@material-ui/lab/Alert"; -import DialogActions from "@material-ui/core/DialogActions"; -import DialogContent from "@material-ui/core/DialogContent"; -import DialogTitle from "@material-ui/core/DialogTitle"; +import Button from "@mui/material/Button"; +import Dialog from "@mui/material/Dialog"; +import Alert from '@mui/material/Alert'; +import DialogActions from "@mui/material/DialogActions"; +import DialogContent from "@mui/material/DialogContent"; +import DialogTitle from "@mui/material/DialogTitle"; export default ({ error, startRecoveryFromError }) => { let title = "An error occurred"; diff --git a/webapp/components/FileSampleSelector.js b/webapp/components/FileSampleSelector.js index a9edb67..ade4cc6 100644 --- a/webapp/components/FileSampleSelector.js +++ b/webapp/components/FileSampleSelector.js @@ -1,5 +1,5 @@ import React from 'react'; -import { Box, Button, Typography, FormControl, Select, MenuItem, Grid, } from '@material-ui/core'; +import { Box, Button, Typography, FormControl, Select, MenuItem, Grid2 as Grid, } from '@mui/material'; const SAMPLE_LINK_FERGUSON = 'https://github.com/OpenSourceBrain/NWBShowcase/raw/master/FergusonEtAl2015/FergusonEtAl2015.nwb'; const SAMPLE_LINK_FERGUSON_2 = 'https://github.com/OpenSourceBrain/NWBShowcase/raw/master/FergusonEtAl2015/FergusonEtAl2015_PYR2.nwb'; @@ -63,6 +63,7 @@ export default class FileSampleSelector extends React.Component { className="button badge-button" name="ferguson" displayEmpty + variant="outlined" inputProps={{ 'aria-label': 'ferguson' }} > @@ -85,6 +86,7 @@ export default class FileSampleSelector extends React.Component { className="button badge-button" name="ferguson" displayEmpty + variant="outlined" inputProps={{ 'aria-label': 'ferguson' }} > diff --git a/webapp/components/FileUrlSelector.js b/webapp/components/FileUrlSelector.js index 2d369c6..2af5a4c 100644 --- a/webapp/components/FileUrlSelector.js +++ b/webapp/components/FileUrlSelector.js @@ -1,8 +1,8 @@ import React from 'react'; -import TextField from '@material-ui/core/TextField'; -import Box from '@material-ui/core/Box'; -import Button from '@material-ui/core/Button'; -import Typography from '@material-ui/core/Typography'; +import TextField from '@mui/material/TextField'; +import Box from '@mui/material/Box'; +import Button from '@mui/material/Button'; +import Typography from '@mui/material/Typography'; export default class FileUrlSelector extends React.Component { constructor (props) { @@ -28,7 +28,7 @@ export default class FileUrlSelector extends React.Component { render () { return (
- What file do you wish to load? + What file do you wish to load? this.updateInputValue(evt)} />