Fix /jsx with prettifier

This commit is contained in:
Nathan Barber
2021-04-08 15:50:54 -04:00
parent 89a430cc13
commit c7dcb4db85
12 changed files with 4883 additions and 4125 deletions

View File

@@ -225,4 +225,4 @@ jobs:
cd jsx && yarn && yarn test cd jsx && yarn && yarn test
- name: Submit codecov report - name: Submit codecov report
run: | run: |
codecov codecov

View File

@@ -1 +1,2 @@
share/jupyterhub/templates/ share/jupyterhub/templates/
share/jupyterhub/static/js/admin-react.js

View File

@@ -1,41 +1,33 @@
{ {
"extends": [ "extends": ["plugin:react/recommended"],
"plugin:react/recommended" "parserOptions": {
], "ecmaVersion": 6,
"parserOptions": { "sourceType": "module",
"ecmaVersion": 6, "ecmaFeatures": {
"sourceType": "module", "jsx": true
"ecmaFeatures": { }
"jsx": true },
} "settings": {
}, "react": {
"settings": { "version": "detect"
"react": { }
"version": "detect" },
} "plugins": ["eslint-plugin-react", "prettier"],
}, "env": {
"plugins": [ "es6": true,
"eslint-plugin-react", "browser": true
"prettier" },
], "rules": {
"env": { "semi": "off",
"es6": true, "quotes": "off",
"browser": true "prettier/prettier": "warn"
}, },
"rules": { "overrides": [
"semi": "off", {
"quotes": "off", "files": ["**/*.test.js", "**/*.test.jsx"],
"prettier/prettier": "warn" "env": {
}, "jest": true
"overrides": [ }
{ }
"files": [ ]
"**/*.test.js", }
"**/*.test.jsx"
],
"env": {
"jest": true
}
}
]
}

2
jsx/.gitignore vendored
View File

@@ -1,2 +1,2 @@
node_modules node_modules
build/admin-react.js build/admin-react.js

View File

@@ -1,12 +1,14 @@
# Jupyterhub Admin Dashboard - React Variant # Jupyterhub Admin Dashboard - React Variant
This repository contains current updates to the Jupyterhub Admin Dashboard service,
reducing the complexity from a mass of templated HTML to a simple React web application.
This will integrate with Jupyterhub, speeding up client interactions while simplifying the
admin dashboard codebase.
### Build Commands This repository contains current updates to the Jupyterhub Admin Dashboard service,
- `yarn build`: Installs all dependencies and bundles the application reducing the complexity from a mass of templated HTML to a simple React web application.
- `yarn hot`: Bundles the application and runs a mock (serverless) version on port 8000 This will integrate with Jupyterhub, speeding up client interactions while simplifying the
- `yarn lint`: Lints JSX with ESLint admin dashboard codebase.
- `yarn lint --fix`: Lints and fixes errors JSX with ESLint / formats with Prettier
- `yarn place`: Copies the transpiled React bundle to /share/jupyterhub/static/js/admin-react.js for use. ### Build Commands
- `yarn build`: Installs all dependencies and bundles the application
- `yarn hot`: Bundles the application and runs a mock (serverless) version on port 8000
- `yarn lint`: Lints JSX with ESLint
- `yarn lint --fix`: Lints and fixes errors JSX with ESLint / formats with Prettier
- `yarn place`: Copies the transpiled React bundle to /share/jupyterhub/static/js/admin-react.js for use.

View File

@@ -1,6 +1,6 @@
<!DOCTYPE html> <!DOCTYPE html>
<head></head> <head></head>
<body> <body>
<div id="admin-react-hook"></div> <div id="admin-react-hook"></div>
<script src="admin-react.js"></script> <script src="admin-react.js"></script>
</body> </body>

View File

@@ -17,7 +17,7 @@ import EditUser from "./components/EditUser/EditUser";
import "./style/root.css"; import "./style/root.css";
const store = createStore(reducers, initialState) const store = createStore(reducers, initialState);
const App = (props) => { const App = (props) => {
useEffect(() => { useEffect(() => {

View File

@@ -1,40 +1,40 @@
@import url(../../style/root.css); @import url(../../style/root.css);
.multi-container { .multi-container {
width: 100%; width: 100%;
position: relative; position: relative;
padding: 5px; padding: 5px;
overflow-x: scroll; overflow-x: scroll;
} }
.multi-container div { .multi-container div {
display: inline-block; display: inline-block;
} }
.multi-container .item { .multi-container .item {
padding: 3px; padding: 3px;
padding-left: 6px; padding-left: 6px;
padding-right: 6px; padding-right: 6px;
border-radius: 3px; border-radius: 3px;
font-size: 14px; font-size: 14px;
margin-left: 4px; margin-left: 4px;
margin-right: 4px; margin-right: 4px;
transition: 30ms ease-in all; transition: 30ms ease-in all;
cursor: pointer; cursor: pointer;
user-select: none; user-select: none;
border: solid 1px #dfdfdf; border: solid 1px #dfdfdf;
} }
.multi-container .item.unselected { .multi-container .item.unselected {
background-color: #f7f7f7; background-color: #f7f7f7;
color: #777; color: #777;
} }
.multi-container .item.selected { .multi-container .item.selected {
background-color: orange; background-color: orange;
color: white; color: white;
} }
.multi-container .item:hover { .multi-container .item:hover {
opacity: 0.7; opacity: 0.7;
} }

View File

@@ -1,32 +1,32 @@
@import url(../../style/root.css); @import url(../../style/root.css);
.server-dashboard-container { .server-dashboard-container {
padding-right: 15px; padding-right: 15px;
padding-left: 15px; padding-left: 15px;
margin-right: auto; margin-right: auto;
margin-left: auto; margin-left: auto;
} }
.server-dashboard-container .add-users-button { .server-dashboard-container .add-users-button {
border: 1px solid #ddd; border: 1px solid #ddd;
} }
.server-dashboard-container tbody { .server-dashboard-container tbody {
color: #626262; color: #626262;
} }
.admin-table-head { .admin-table-head {
user-select: none; user-select: none;
} }
.sort-icon { .sort-icon {
display: inline-block; display: inline-block;
top: .125em; top: 0.125em;
position: relative; position: relative;
user-select: none; user-select: none;
cursor: pointer; cursor: pointer;
} }
tr.noborder > td { tr.noborder > td {
border: none !important; border: none !important;
} }

View File

@@ -1,35 +1,35 @@
:root { :root {
--red: #d7191e; --red: #d7191e;
--orange: #f1ad4e; --orange: #f1ad4e;
--blue: #2e7ab6; --blue: #2e7ab6;
--white: #ffffff; --white: #ffffff;
--gray: #f7f7f; --gray: #f7f7f;
} }
/* Color Classes */ /* Color Classes */
.red { .red {
background-color: var(--red); background-color: var(--red);
} }
.orange { .orange {
background-color: var(--orange); background-color: var(--orange);
} }
.blue { .blue {
background-color: var(--blue); background-color: var(--blue);
} }
.white { .white {
background-color: var(--white); background-color: var(--white);
} }
/* Resets */ /* Resets */
.resets .modal { .resets .modal {
display: block; display: block;
visibility: visible; visibility: visible;
z-index: 2000 z-index: 2000;
} }
/* Global Util Classes */ /* Global Util Classes */
.adjacent-span-spacing { .adjacent-span-spacing {
margin-right: 5px; margin-right: 5px;
margin-left: 5px; margin-left: 5px;
} }

View File

@@ -1,66 +1,97 @@
const webpack = require("webpack") const webpack = require("webpack");
const path = require("path") const path = require("path");
const express = require("express") const express = require("express");
module.exports = { module.exports = {
entry: path.resolve(__dirname, "src", "App.jsx"), entry: path.resolve(__dirname, "src", "App.jsx"),
mode: "development", mode: "development",
module: { module: {
rules: [ rules: [
{ {
test: /\.(js|jsx)/, test: /\.(js|jsx)/,
exclude: /node_modules/, exclude: /node_modules/,
use: "babel-loader", use: "babel-loader",
}, },
{ {
test: /\.(css)/, test: /\.(css)/,
exclude: /node_modules/, exclude: /node_modules/,
use: ["style-loader", "css-loader"] use: ["style-loader", "css-loader"],
}, },
{ {
test: /\.(png|jpe?g|gif|svg|woff2?|ttf)$/i, test: /\.(png|jpe?g|gif|svg|woff2?|ttf)$/i,
exclude: /node_modules/, exclude: /node_modules/,
use: "file-loader" use: "file-loader",
} },
]
},
output: {
publicPath: "/",
filename: "admin-react.js",
path: path.resolve(__dirname, "build"),
},
resolve: {
extensions: [".css", ".js", ".jsx"]
},
plugins: [
new webpack.HotModuleReplacementPlugin
], ],
devServer: { },
contentBase: path.resolve(__dirname, "build"), output: {
port: 9000, publicPath: "/",
before: (app, server) => { filename: "admin-react.js",
var user_data = JSON.parse('[{"kind":"user","name":"foo","admin":true,"groups":[],"server":"/user/foo/","pending":null,"created":"2020-12-07T18:46:27.112695Z","last_activity":"2020-12-07T21:00:33.336354Z","servers":{"":{"name":"","last_activity":"2020-12-07T20:58:02.437408Z","started":"2020-12-07T20:58:01.508266Z","pending":null,"ready":true,"state":{"pid":28085},"url":"/user/foo/","user_options":{},"progress_url":"/hub/api/users/foo/server/progress"}}},{"kind":"user","name":"bar","admin":false,"groups":[],"server":null,"pending":null,"created":"2020-12-07T18:46:27.115528Z","last_activity":"2020-12-07T20:43:51.013613Z","servers":{}}]') path: path.resolve(__dirname, "build"),
var group_data = JSON.parse('[{"kind":"group","name":"testgroup","users":[]}, {"kind":"group","name":"testgroup2","users":["foo", "bar"]}]') },
app.use(express.json()) resolve: {
extensions: [".css", ".js", ".jsx"],
},
plugins: [new webpack.HotModuleReplacementPlugin()],
devServer: {
contentBase: path.resolve(__dirname, "build"),
port: 9000,
before: (app, server) => {
var user_data = JSON.parse(
'[{"kind":"user","name":"foo","admin":true,"groups":[],"server":"/user/foo/","pending":null,"created":"2020-12-07T18:46:27.112695Z","last_activity":"2020-12-07T21:00:33.336354Z","servers":{"":{"name":"","last_activity":"2020-12-07T20:58:02.437408Z","started":"2020-12-07T20:58:01.508266Z","pending":null,"ready":true,"state":{"pid":28085},"url":"/user/foo/","user_options":{},"progress_url":"/hub/api/users/foo/server/progress"}}},{"kind":"user","name":"bar","admin":false,"groups":[],"server":null,"pending":null,"created":"2020-12-07T18:46:27.115528Z","last_activity":"2020-12-07T20:43:51.013613Z","servers":{}}]'
);
var group_data = JSON.parse(
'[{"kind":"group","name":"testgroup","users":[]}, {"kind":"group","name":"testgroup2","users":["foo", "bar"]}]'
);
app.use(express.json());
// get user_data // get user_data
app.get("/hub/api/users", (req, res) => { res.set("Content-Type", "application/json").send(JSON.stringify(user_data)) }) app.get("/hub/api/users", (req, res) => {
// get group_data res
app.get("/hub/api/groups", (req, res) => { res.set("Content-Type", "application/json").send(JSON.stringify(group_data)) }) .set("Content-Type", "application/json")
// add users to group .send(JSON.stringify(user_data));
app.post("/hub/api/groups/*/users", (req, res) => { console.log(req.url, req.body); res.status(200).end() }) });
// remove users from group // get group_data
app.delete("/hub/api/groups/*", (req, res) => { console.log(req.url, req.body); res.status(200).end() }) app.get("/hub/api/groups", (req, res) => {
// add users res
app.post("/hub/api/users", (req, res) => { console.log(req.url, req.body); res.status(200).end() }) .set("Content-Type", "application/json")
// delete user .send(JSON.stringify(group_data));
app.delete("/hub/api/users", (req, res) => { console.log(req.url, req.body); res.status(200).end() }) });
// start user server // add users to group
app.post("/hub/api/users/*/server", (req, res) => { console.log(req.url, req.body); res.status(200).end() }) app.post("/hub/api/groups/*/users", (req, res) => {
// stop user server console.log(req.url, req.body);
app.delete("/hub/api/users/*/server", (req, res) => { console.log(req.url, req.body); res.status(200).end() }) res.status(200).end();
// shutdown hub });
app.post("/hub/api/shutdown", (req, res) => { console.log(req.url, req.body); res.status(200).end() }) // remove users from group
} app.delete("/hub/api/groups/*", (req, res) => {
} console.log(req.url, req.body);
} res.status(200).end();
});
// add users
app.post("/hub/api/users", (req, res) => {
console.log(req.url, req.body);
res.status(200).end();
});
// delete user
app.delete("/hub/api/users", (req, res) => {
console.log(req.url, req.body);
res.status(200).end();
});
// start user server
app.post("/hub/api/users/*/server", (req, res) => {
console.log(req.url, req.body);
res.status(200).end();
});
// stop user server
app.delete("/hub/api/users/*/server", (req, res) => {
console.log(req.url, req.body);
res.status(200).end();
});
// shutdown hub
app.post("/hub/api/shutdown", (req, res) => {
console.log(req.url, req.body);
res.status(200).end();
});
},
},
};

File diff suppressed because one or more lines are too long