mirror of
https://github.com/jupyterhub/jupyterhub.git
synced 2025-10-12 12:33:02 +00:00
Admin missing features
This commit is contained in:
@@ -115,6 +115,14 @@ const ServerDashboard = (props) => {
|
|||||||
testid="admin-sort"
|
testid="admin-sort"
|
||||||
/>
|
/>
|
||||||
</th>
|
</th>
|
||||||
|
<th id="user-header">
|
||||||
|
Server{" "}
|
||||||
|
<SortHandler
|
||||||
|
sorts={{ asc: usernameAsc, desc: usernameDesc }}
|
||||||
|
callback={(method) => setSortMethod(() => method)}
|
||||||
|
testid="user-sort"
|
||||||
|
/>
|
||||||
|
</th>
|
||||||
<th id="last-activity-header">
|
<th id="last-activity-header">
|
||||||
Last Activity{" "}
|
Last Activity{" "}
|
||||||
<SortHandler
|
<SortHandler
|
||||||
@@ -227,88 +235,134 @@ const ServerDashboard = (props) => {
|
|||||||
</Button>
|
</Button>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
{user_data.map((e, i) => (
|
{user_data.flatMap((e, i) => {
|
||||||
<tr key={i + "row"} className="user-row">
|
let userServers = Object.values({
|
||||||
<td data-testid="user-row-name">{e.name}</td>
|
"": e.server,
|
||||||
<td data-testid="user-row-admin">{e.admin ? "admin" : ""}</td>
|
...(e.servers || {}),
|
||||||
<td data-testid="user-row-last-activity">
|
});
|
||||||
{e.last_activity ? timeSince(e.last_activity) : "Never"}
|
return userServers.map((server) => {
|
||||||
</td>
|
return (
|
||||||
<td data-testid="user-row-server-activity">
|
<tr key={i + "row"} className="user-row">
|
||||||
{e.server != null ? (
|
{!(server || {}).name && (
|
||||||
// Stop Single-user server
|
<td
|
||||||
<button
|
data-testid="user-row-name"
|
||||||
className="btn btn-danger btn-xs stop-button"
|
rowspan={userServers.length}
|
||||||
onClick={() =>
|
>
|
||||||
stopServer(e.name)
|
{e.name}
|
||||||
.then((res) => {
|
</td>
|
||||||
if (res.status < 300) {
|
)}
|
||||||
updateUsers(...slice)
|
{!(server || {}).name && (
|
||||||
.then((data) => {
|
<td
|
||||||
dispatchPageUpdate(data, page);
|
data-testid="user-row-admin"
|
||||||
})
|
rowspan={userServers.length}
|
||||||
.catch(() =>
|
>
|
||||||
setErrorAlert(`Failed to update users list.`)
|
{e.admin ? "admin" : ""}
|
||||||
);
|
</td>
|
||||||
} else {
|
)}
|
||||||
setErrorAlert(`Failed to stop server.`);
|
|
||||||
}
|
<td data-testid="user-row-name">
|
||||||
return res;
|
{(server || {}).name || "[MAIN]"}
|
||||||
|
</td>
|
||||||
|
<td data-testid="user-row-last-activity">
|
||||||
|
{(server || {}).last_activity
|
||||||
|
? timeSince(server.last_activity)
|
||||||
|
: "Never"}
|
||||||
|
</td>
|
||||||
|
<td data-testid="user-row-server-activity">
|
||||||
|
{server != null ? (
|
||||||
|
// Stop Single-user server
|
||||||
|
<button
|
||||||
|
className="btn btn-danger btn-xs stop-button"
|
||||||
|
onClick={() =>
|
||||||
|
stopServer(e.name, server.name)
|
||||||
|
.then((res) => {
|
||||||
|
if (res.status < 300) {
|
||||||
|
updateUsers(...slice)
|
||||||
|
.then((data) => {
|
||||||
|
dispatchPageUpdate(data, page);
|
||||||
|
})
|
||||||
|
.catch(() =>
|
||||||
|
setErrorAlert(
|
||||||
|
`Failed to update users list.`
|
||||||
|
)
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
setErrorAlert(`Failed to stop server.`);
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
})
|
||||||
|
.catch(() =>
|
||||||
|
setErrorAlert(`Failed to stop server.`)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
>
|
||||||
|
Stop Server
|
||||||
|
</button>
|
||||||
|
) : (
|
||||||
|
// Start Single-user server
|
||||||
|
<button
|
||||||
|
className="btn btn-primary btn-xs start-button"
|
||||||
|
onClick={() =>
|
||||||
|
startServer(e.name, (server || {}).name)
|
||||||
|
.then((res) => {
|
||||||
|
if (res.status < 300) {
|
||||||
|
updateUsers(...slice)
|
||||||
|
.then((data) => {
|
||||||
|
dispatchPageUpdate(data, page);
|
||||||
|
})
|
||||||
|
.catch(() =>
|
||||||
|
setErrorAlert(
|
||||||
|
`Failed to update users list.`
|
||||||
|
)
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
setErrorAlert(`Failed to start server.`);
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
})
|
||||||
|
.catch(() => {
|
||||||
|
setErrorAlert(`Failed to start server.`);
|
||||||
|
})
|
||||||
|
}
|
||||||
|
>
|
||||||
|
Start Server
|
||||||
|
</button>
|
||||||
|
)}
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
{/* Edit User */}
|
||||||
|
<button
|
||||||
|
className="btn btn-primary btn-xs"
|
||||||
|
style={{ marginRight: 20 }}
|
||||||
|
onClick={() =>
|
||||||
|
history.push({
|
||||||
|
pathname: "/edit-user",
|
||||||
|
state: {
|
||||||
|
username: e.name,
|
||||||
|
has_admin: e.admin,
|
||||||
|
},
|
||||||
})
|
})
|
||||||
.catch(() => setErrorAlert(`Failed to stop server.`))
|
}
|
||||||
}
|
>
|
||||||
>
|
edit user
|
||||||
Stop Server
|
</button>
|
||||||
</button>
|
<a
|
||||||
) : (
|
href={`/user/${e.name}${
|
||||||
// Start Single-user server
|
server && server.name && "/" + server.name
|
||||||
<button
|
}`}
|
||||||
className="btn btn-primary btn-xs start-button"
|
>
|
||||||
onClick={() =>
|
<button
|
||||||
startServer(e.name)
|
className="btn btn-primary btn-xs"
|
||||||
.then((res) => {
|
style={{ marginRight: 20 }}
|
||||||
if (res.status < 300) {
|
>
|
||||||
updateUsers(...slice)
|
Access Server
|
||||||
.then((data) => {
|
</button>
|
||||||
dispatchPageUpdate(data, page);
|
</a>
|
||||||
})
|
</td>
|
||||||
.catch(() =>
|
</tr>
|
||||||
setErrorAlert(`Failed to update users list.`)
|
);
|
||||||
);
|
});
|
||||||
} else {
|
})}
|
||||||
setErrorAlert(`Failed to start server.`);
|
|
||||||
}
|
|
||||||
return res;
|
|
||||||
})
|
|
||||||
.catch(() => {
|
|
||||||
setErrorAlert(`Failed to start server.`);
|
|
||||||
})
|
|
||||||
}
|
|
||||||
>
|
|
||||||
Start Server
|
|
||||||
</button>
|
|
||||||
)}
|
|
||||||
</td>
|
|
||||||
<td>
|
|
||||||
{/* Edit User */}
|
|
||||||
<button
|
|
||||||
className="btn btn-primary btn-xs"
|
|
||||||
style={{ marginRight: 20 }}
|
|
||||||
onClick={() =>
|
|
||||||
history.push({
|
|
||||||
pathname: "/edit-user",
|
|
||||||
state: {
|
|
||||||
username: e.name,
|
|
||||||
has_admin: e.admin,
|
|
||||||
},
|
|
||||||
})
|
|
||||||
}
|
|
||||||
>
|
|
||||||
edit user
|
|
||||||
</button>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
))}
|
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
<PaginationFooter
|
<PaginationFooter
|
||||||
|
@@ -11,8 +11,8 @@ const withAPI = withProps(() => ({
|
|||||||
(data) => data.json()
|
(data) => data.json()
|
||||||
),
|
),
|
||||||
shutdownHub: () => jhapiRequest("/shutdown", "POST"),
|
shutdownHub: () => jhapiRequest("/shutdown", "POST"),
|
||||||
startServer: (name) => jhapiRequest("/users/" + name + "/server", "POST"),
|
startServer: (name, serverName = "") => jhapiRequest("/users/" + name + "/servers/" + (serverName || ""), "POST"),
|
||||||
stopServer: (name) => jhapiRequest("/users/" + name + "/server", "DELETE"),
|
stopServer: (name, serverName = "") => jhapiRequest("/users/" + name + "/servers/" + (serverName || ""), "DELETE"),
|
||||||
startAll: (names) =>
|
startAll: (names) =>
|
||||||
names.map((e) => jhapiRequest("/users/" + e + "/server", "POST")),
|
names.map((e) => jhapiRequest("/users/" + e + "/server", "POST")),
|
||||||
stopAll: (names) =>
|
stopAll: (names) =>
|
||||||
|
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user