mirror of
https://github.com/jupyterhub/jupyterhub.git
synced 2025-10-18 15:33:02 +00:00
jsx: update and address eslint
add script to top-level package.json to run eslint in subdir
This commit is contained in:
@@ -1,7 +1,6 @@
|
||||
import React, { act } from "react";
|
||||
import "@testing-library/jest-dom";
|
||||
import { render, screen, fireEvent } from "@testing-library/react";
|
||||
import userEvent from "@testing-library/user-event";
|
||||
import { Provider, useDispatch, useSelector } from "react-redux";
|
||||
import { createStore } from "redux";
|
||||
import { HashRouter } from "react-router";
|
||||
|
@@ -179,6 +179,7 @@ GroupEdit.propTypes = {
|
||||
removeFromGroup: PropTypes.func,
|
||||
deleteGroup: PropTypes.func,
|
||||
updateGroups: PropTypes.func,
|
||||
updateProp: PropTypes.func,
|
||||
validateUser: PropTypes.func,
|
||||
};
|
||||
|
||||
|
@@ -3,6 +3,7 @@ import { useSelector, useDispatch } from "react-redux";
|
||||
import { debounce } from "lodash";
|
||||
import PropTypes from "prop-types";
|
||||
import ErrorAlert from "../../util/error";
|
||||
import { User, Server } from "../../util/jhapiUtil";
|
||||
|
||||
import {
|
||||
Button,
|
||||
@@ -209,6 +210,15 @@ const ServerDashboard = (props) => {
|
||||
);
|
||||
};
|
||||
|
||||
ServerButton.propTypes = {
|
||||
server: Server,
|
||||
user: User,
|
||||
action: PropTypes.string,
|
||||
name: PropTypes.string,
|
||||
variant: PropTypes.string,
|
||||
extraClass: PropTypes.string,
|
||||
};
|
||||
|
||||
const StopServerButton = ({ server, user }) => {
|
||||
if (!server.ready) {
|
||||
return null;
|
||||
@@ -222,6 +232,12 @@ const ServerDashboard = (props) => {
|
||||
extraClass: "stop-button",
|
||||
});
|
||||
};
|
||||
|
||||
StopServerButton.propTypes = {
|
||||
server: Server,
|
||||
user: User,
|
||||
};
|
||||
|
||||
const DeleteServerButton = ({ server, user }) => {
|
||||
if (!server.name) {
|
||||
// It's not possible to delete unnamed servers
|
||||
@@ -240,6 +256,11 @@ const ServerDashboard = (props) => {
|
||||
});
|
||||
};
|
||||
|
||||
DeleteServerButton.propTypes = {
|
||||
server: Server,
|
||||
user: User,
|
||||
};
|
||||
|
||||
const StartServerButton = ({ server, user }) => {
|
||||
if (server.ready) {
|
||||
return null;
|
||||
@@ -254,6 +275,11 @@ const ServerDashboard = (props) => {
|
||||
});
|
||||
};
|
||||
|
||||
StartServerButton.propTypes = {
|
||||
server: Server,
|
||||
user: User,
|
||||
};
|
||||
|
||||
const SpawnPageButton = ({ server, user }) => {
|
||||
if (server.ready) {
|
||||
return null;
|
||||
@@ -271,6 +297,11 @@ const ServerDashboard = (props) => {
|
||||
);
|
||||
};
|
||||
|
||||
SpawnPageButton.propTypes = {
|
||||
server: Server,
|
||||
user: User,
|
||||
};
|
||||
|
||||
const AccessServerButton = ({ server }) => {
|
||||
if (!server.ready) {
|
||||
return null;
|
||||
@@ -283,6 +314,9 @@ const ServerDashboard = (props) => {
|
||||
</a>
|
||||
);
|
||||
};
|
||||
AccessServerButton.propTypes = {
|
||||
server: Server,
|
||||
};
|
||||
|
||||
const EditUserButton = ({ user }) => {
|
||||
return (
|
||||
@@ -303,10 +337,17 @@ const ServerDashboard = (props) => {
|
||||
);
|
||||
};
|
||||
|
||||
const ServerRowTable = ({ data }) => {
|
||||
EditUserButton.propTypes = {
|
||||
user: User,
|
||||
};
|
||||
|
||||
const ServerRowTable = ({ data, exclude }) => {
|
||||
const sortedData = Object.keys(data)
|
||||
.sort()
|
||||
.reduce(function (result, key) {
|
||||
if (exclude && exclude.includes(key)) {
|
||||
return result;
|
||||
}
|
||||
let value = data[key];
|
||||
switch (key) {
|
||||
case "last_activity":
|
||||
@@ -346,88 +387,101 @@ const ServerDashboard = (props) => {
|
||||
);
|
||||
};
|
||||
|
||||
const serverRow = (user, server) => {
|
||||
const { servers, ...userNoServers } = user;
|
||||
ServerRowTable.propTypes = {
|
||||
data: Server,
|
||||
exclude: PropTypes.arrayOf(PropTypes.string),
|
||||
};
|
||||
|
||||
const ServerRow = ({ user, server }) => {
|
||||
const serverNameDash = server.name ? `-${server.name}` : "";
|
||||
const userServerName = user.name + serverNameDash;
|
||||
const open = collapseStates[userServerName] || false;
|
||||
return [
|
||||
<tr
|
||||
key={`${userServerName}-row`}
|
||||
data-testid={`user-row-${userServerName}`}
|
||||
className="user-row"
|
||||
>
|
||||
<td data-testid="user-row-name">
|
||||
<span>
|
||||
<Button
|
||||
onClick={() =>
|
||||
setCollapseStates({
|
||||
...collapseStates,
|
||||
[userServerName]: !open,
|
||||
})
|
||||
}
|
||||
aria-controls={`${userServerName}-collapse`}
|
||||
aria-expanded={open}
|
||||
data-testid={`${userServerName}-collapse-button`}
|
||||
variant={open ? "secondary" : "primary"}
|
||||
size="sm"
|
||||
>
|
||||
<span className="fa fa-caret-down"></span>
|
||||
</Button>{" "}
|
||||
</span>
|
||||
<span data-testid={`user-name-div-${userServerName}`}>
|
||||
{user.name}
|
||||
</span>
|
||||
</td>
|
||||
<td data-testid="user-row-admin">{user.admin ? "admin" : ""}</td>
|
||||
|
||||
<td data-testid="user-row-server">
|
||||
<p className="text-secondary">{server.name}</p>
|
||||
</td>
|
||||
<td data-testid="user-row-last-activity">
|
||||
{server.last_activity ? timeSince(server.last_activity) : "Never"}
|
||||
</td>
|
||||
<td data-testid="user-row-server-activity" className="actions">
|
||||
<StartServerButton server={server} user={user} />
|
||||
<StopServerButton server={server} user={user} />
|
||||
<DeleteServerButton server={server} user={user} />
|
||||
<AccessServerButton server={server} />
|
||||
<SpawnPageButton server={server} user={user} />
|
||||
<EditUserButton user={user} />
|
||||
</td>
|
||||
</tr>,
|
||||
<tr key={`${userServerName}-detail`}>
|
||||
<td
|
||||
colSpan={6}
|
||||
style={{ padding: 0 }}
|
||||
data-testid={`${userServerName}-td`}
|
||||
return (
|
||||
<Fragment key={`${userServerName}-row`}>
|
||||
<tr
|
||||
key={`${userServerName}-row`}
|
||||
data-testid={`user-row-${userServerName}`}
|
||||
className="user-row"
|
||||
>
|
||||
<Collapse in={open} data-testid={`${userServerName}-collapse`}>
|
||||
<CardGroup
|
||||
id={`${userServerName}-card-group`}
|
||||
style={{ width: "100%", margin: "0 auto", float: "none" }}
|
||||
>
|
||||
<Card style={{ width: "100%", padding: 3, margin: "0 auto" }}>
|
||||
<Card.Title>User</Card.Title>
|
||||
<ServerRowTable data={userNoServers} />
|
||||
</Card>
|
||||
<Card style={{ width: "100%", padding: 3, margin: "0 auto" }}>
|
||||
<Card.Title>Server</Card.Title>
|
||||
<ServerRowTable data={server} />
|
||||
</Card>
|
||||
</CardGroup>
|
||||
</Collapse>
|
||||
</td>
|
||||
</tr>,
|
||||
];
|
||||
<td data-testid="user-row-name">
|
||||
<span>
|
||||
<Button
|
||||
onClick={() =>
|
||||
setCollapseStates({
|
||||
...collapseStates,
|
||||
[userServerName]: !open,
|
||||
})
|
||||
}
|
||||
aria-controls={`${userServerName}-collapse`}
|
||||
aria-expanded={open}
|
||||
data-testid={`${userServerName}-collapse-button`}
|
||||
variant={open ? "secondary" : "primary"}
|
||||
size="sm"
|
||||
>
|
||||
<span className="fa fa-caret-down"></span>
|
||||
</Button>{" "}
|
||||
</span>
|
||||
<span data-testid={`user-name-div-${userServerName}`}>
|
||||
{user.name}
|
||||
</span>
|
||||
</td>
|
||||
<td data-testid="user-row-admin">{user.admin ? "admin" : ""}</td>
|
||||
|
||||
<td data-testid="user-row-server">
|
||||
<p className="text-secondary">{server.name}</p>
|
||||
</td>
|
||||
<td data-testid="user-row-last-activity">
|
||||
{server.last_activity ? timeSince(server.last_activity) : "Never"}
|
||||
</td>
|
||||
<td data-testid="user-row-server-activity" className="actions">
|
||||
<StartServerButton server={server} user={user} />
|
||||
<StopServerButton server={server} user={user} />
|
||||
<DeleteServerButton server={server} user={user} />
|
||||
<AccessServerButton server={server} />
|
||||
<SpawnPageButton server={server} user={user} />
|
||||
<EditUserButton user={user} />
|
||||
</td>
|
||||
</tr>
|
||||
<tr key={`${userServerName}-detail`}>
|
||||
<td
|
||||
colSpan={6}
|
||||
style={{ padding: 0 }}
|
||||
data-testid={`${userServerName}-td`}
|
||||
>
|
||||
<Collapse in={open} data-testid={`${userServerName}-collapse`}>
|
||||
<CardGroup
|
||||
id={`${userServerName}-card-group`}
|
||||
style={{ width: "100%", margin: "0 auto", float: "none" }}
|
||||
>
|
||||
<Card style={{ width: "100%", padding: 3, margin: "0 auto" }}>
|
||||
<Card.Title>User</Card.Title>
|
||||
<ServerRowTable data={user} exclude={["server", "servers"]} />
|
||||
</Card>
|
||||
<Card style={{ width: "100%", padding: 3, margin: "0 auto" }}>
|
||||
<Card.Title>Server</Card.Title>
|
||||
<ServerRowTable data={server} />
|
||||
</Card>
|
||||
</CardGroup>
|
||||
</Collapse>
|
||||
</td>
|
||||
</tr>
|
||||
</Fragment>
|
||||
);
|
||||
};
|
||||
|
||||
let servers = user_data.flatMap((user) => {
|
||||
let userServers = Object.values({
|
||||
ServerRow.propTypes = {
|
||||
user: User,
|
||||
server: Server,
|
||||
};
|
||||
|
||||
const serverRows = user_data.flatMap((user) => {
|
||||
const userServers = Object.values({
|
||||
// eslint-disable-next-line react/prop-types
|
||||
"": user.server || {},
|
||||
// eslint-disable-next-line react/prop-types
|
||||
...(user.servers || {}),
|
||||
});
|
||||
return userServers.map((server) => [user, server]);
|
||||
return userServers.map((server) => ServerRow({ user, server }));
|
||||
});
|
||||
|
||||
return (
|
||||
@@ -583,7 +637,7 @@ const ServerDashboard = (props) => {
|
||||
</Button>
|
||||
</td>
|
||||
</tr>
|
||||
{servers.flatMap(([user, server]) => serverRow(user, server))}
|
||||
{serverRows}
|
||||
</tbody>
|
||||
</table>
|
||||
<PaginationFooter
|
||||
@@ -607,7 +661,7 @@ const ServerDashboard = (props) => {
|
||||
};
|
||||
|
||||
ServerDashboard.propTypes = {
|
||||
user_data: PropTypes.array,
|
||||
user_data: PropTypes.arrayOf(User),
|
||||
updateUsers: PropTypes.func,
|
||||
shutdownHub: PropTypes.func,
|
||||
startServer: PropTypes.func,
|
||||
|
Reference in New Issue
Block a user