Active Scripts

This commit is contained in:
Olivier Gagnon
2021-09-18 00:16:02 -04:00
parent 907314e76b
commit 1996deaf0a
17 changed files with 289 additions and 189 deletions
@@ -10,6 +10,7 @@ import { ServerAccordions } from "./ServerAccordions";
import { WorkerScript } from "../../Netscript/WorkerScript";
import Typography from "@mui/material/Typography";
import TextField from "@mui/material/TextField";
type IProps = {
workerScripts: Map<number, WorkerScript>;
+17 -13
View File
@@ -5,10 +5,14 @@
import * as React from "react";
import Typography from "@mui/material/Typography";
import Accordion from "@mui/material/Accordion";
import AccordionSummary from "@mui/material/AccordionSummary";
import AccordionDetails from "@mui/material/AccordionDetails";
import ExpandMoreIcon from "@mui/icons-material/ExpandMore";
import ListItemButton from "@mui/material/ListItemButton";
import ListItemText from "@mui/material/ListItemText";
import Paper from "@mui/material/Paper";
import Collapse from "@mui/material/Collapse";
import ExpandMore from "@mui/icons-material/ExpandMore";
import ExpandLess from "@mui/icons-material/ExpandLess";
import { ServerAccordionContent } from "./ServerAccordionContent";
import { BaseServer } from "../../Server/BaseServer";
@@ -22,6 +26,7 @@ type IProps = {
};
export function ServerAccordion(props: IProps): React.ReactElement {
const [open, setOpen] = React.useState(false);
const server = props.server;
// Accordion's header text
@@ -38,15 +43,14 @@ export function ServerAccordion(props: IProps): React.ReactElement {
const headerTxt = `${paddedName} ${createProgressBarText(barOptions)}`;
return (
<Accordion TransitionProps={{ unmountOnExit: true }}>
<AccordionSummary expandIcon={<ExpandMoreIcon />}>
<Typography style={{ whiteSpace: "pre-wrap" }} color="primary">
{headerTxt}
</Typography>
</AccordionSummary>
<AccordionDetails>
<>
<ListItemButton onClick={() => setOpen((old) => !old)} component={Paper}>
<ListItemText primary={<Typography style={{ whiteSpace: "pre-wrap" }}>{headerTxt}</Typography>} />
{open ? <ExpandLess color="primary" /> : <ExpandMore color="primary" />}
</ListItemButton>
<Collapse in={open} timeout={0} unmountOnExit>
<ServerAccordionContent workerScripts={props.workerScripts} />
</AccordionDetails>
</Accordion>
</Collapse>
</>
);
}
+27 -52
View File
@@ -2,6 +2,10 @@ import React, { useState } from "react";
import { WorkerScript } from "../../Netscript/WorkerScript";
import { WorkerScriptAccordion } from "./WorkerScriptAccordion";
import { AccordionButton } from "../React/AccordionButton";
import Paper from "@mui/material/Paper";
import List from "@mui/material/List";
import TablePagination from "@mui/material/TablePagination";
import { TablePaginationActionsAll } from "../React/TablePaginationActionsAll";
const pageSize = 20;
@@ -10,63 +14,34 @@ interface IProps {
}
export function ServerAccordionContent(props: IProps): React.ReactElement {
if (props.workerScripts.length > pageSize) {
return <ServerAccordionContentPaginated workerScripts={props.workerScripts} />;
}
return (
<ul>
{props.workerScripts.map((ws) => {
return <WorkerScriptAccordion key={`${ws.name}_${ws.args}`} workerScript={ws} />;
})}
</ul>
);
}
export function ServerAccordionContentPaginated(props: IProps): React.ReactElement {
const [page, setPage] = useState(0);
const scripts: React.ReactElement[] = [];
const maxPage = Math.ceil(props.workerScripts.length / pageSize);
const maxScript = Math.min((page + 1) * pageSize, props.workerScripts.length);
for (let i = page * pageSize; i < maxScript; i++) {
const ws = props.workerScripts[i];
scripts.push(<WorkerScriptAccordion key={`${ws.name}_${ws.args}`} workerScript={ws} />);
}
const [rowsPerPage, setRowsPerPage] = useState(10);
const handleChangePage = (event: unknown, newPage: number) => {
setPage(newPage);
};
function capPage(page: number): number {
if (page < 0) {
page = 0;
}
if (maxPage - 1 < page) {
page = maxPage - 1;
}
return page;
}
// in case we're on an invalid page number because scripts were killed.
const capped = capPage(page);
if (capped !== page) setPage(capped);
function changePage(n: number): void {
setPage((newPage) => {
newPage += n;
newPage = Math.round(newPage);
return capPage(newPage);
});
}
const handleChangeRowsPerPage = (event: React.ChangeEvent<HTMLInputElement>) => {
setRowsPerPage(parseInt(event.target.value, 10));
setPage(0);
};
return (
<>
<ul>{scripts}</ul>
<AccordionButton onClick={() => changePage(-1e99)} text="<<" />
<AccordionButton onClick={() => changePage(-1)} text="<" />
<span className="text">
{page + 1} / {maxPage}
</span>
<AccordionButton onClick={() => changePage(1)} text=">" />
<AccordionButton onClick={() => changePage(1e99)} text=">>" />
<List>
{props.workerScripts.slice(page * rowsPerPage, page * rowsPerPage + rowsPerPage).map((ws) => (
<WorkerScriptAccordion key={`${ws.name}_${ws.args}`} workerScript={ws} />
))}
</List>
<TablePagination
rowsPerPageOptions={[10, 15, 20]}
component="div"
count={props.workerScripts.length}
rowsPerPage={rowsPerPage}
page={page}
onPageChange={handleChangePage}
onRowsPerPageChange={handleChangeRowsPerPage}
ActionsComponent={TablePaginationActionsAll}
/>
</>
);
}
+57 -7
View File
@@ -6,10 +6,16 @@ import React, { useState, useEffect } from "react";
import { ServerAccordion } from "./ServerAccordion";
import TextField from "@mui/material/TextField";
import Typography from "@mui/material/Typography";
import Paper from "@mui/material/Paper";
import List from "@mui/material/List";
import TablePagination from "@mui/material/TablePagination";
import { WorkerScript } from "../../Netscript/WorkerScript";
import { WorkerScriptStartStopEventEmitter } from "../../Netscript/WorkerScriptStartStopEventEmitter";
import { getServer } from "../../Server/ServerHelpers";
import { BaseServer } from "../../Server/BaseServer";
import { TablePaginationActionsAll } from "../React/TablePaginationActionsAll";
// Map of server hostname -> all workerscripts on that server for all active scripts
interface IServerData {
@@ -32,6 +38,9 @@ type IState = {
const subscriberId = "ActiveScriptsUI";
export function ServerAccordions(props: IProps): React.ReactElement {
const [filter, setFilter] = useState("");
const [page, setPage] = useState(0);
const [rowsPerPage, setRowsPerPage] = useState(10);
const setRerender = useState(false)[1];
function rerender(): void {
setRerender((old) => !old);
@@ -45,6 +54,20 @@ export function ServerAccordions(props: IProps): React.ReactElement {
return () => WorkerScriptStartStopEventEmitter.removeSubscriber(subscriberId);
}, []);
const handleChangePage = (event: unknown, newPage: number) => {
setPage(newPage);
};
const handleChangeRowsPerPage = (event: React.ChangeEvent<HTMLInputElement>) => {
setRowsPerPage(parseInt(event.target.value, 10));
setPage(0);
};
function handleFilterChange(event: React.ChangeEvent<HTMLInputElement>): void {
setFilter(event.target.value);
setPage(0);
}
const serverToScriptMap: IServerToScriptsMap = {};
for (const ws of props.workerScripts.values()) {
const server = getServer(ws.serverIp);
@@ -65,13 +88,40 @@ export function ServerAccordions(props: IProps): React.ReactElement {
if (data !== undefined) data.workerScripts.push(ws);
}
const filtered = Object.values(serverToScriptMap).filter((data) => data && data.server.hostname.includes(filter));
return (
<ul className="active-scripts-list" id="active-scripts-list">
{Object.values(serverToScriptMap).map((data) => {
return (
data && <ServerAccordion key={data.server.hostname} server={data.server} workerScripts={data.workerScripts} />
);
})}
</ul>
<>
<TextField
value={filter}
onChange={handleFilterChange}
color="primary"
autoFocus
variant="standard"
InputProps={{
startAdornment: <Typography m={1}>Filter:</Typography>,
spellCheck: false,
}}
/>
<List>
{filtered.slice(page * rowsPerPage, page * rowsPerPage + rowsPerPage).map((data) => {
return (
data && (
<ServerAccordion key={data.server.hostname} server={data.server} workerScripts={data.workerScripts} />
)
);
})}
</List>
<TablePagination
rowsPerPageOptions={[10, 15, 20]}
component="div"
count={filtered.length}
rowsPerPage={rowsPerPage}
page={page}
onPageChange={handleChangePage}
onRowsPerPageChange={handleChangeRowsPerPage}
ActionsComponent={TablePaginationActionsAll}
/>
</>
);
}
+45 -33
View File
@@ -7,6 +7,8 @@ import * as React from "react";
import { numeralWrapper } from "../numeralFormat";
import Button from "@mui/material/Button";
import Box from "@mui/material/Box";
import Paper from "@mui/material/Paper";
import Typography from "@mui/material/Typography";
import Accordion from "@mui/material/Accordion";
import AccordionSummary from "@mui/material/AccordionSummary";
@@ -15,6 +17,12 @@ import ExpandMoreIcon from "@mui/icons-material/ExpandMore";
import { AccordionButton } from "../React/AccordionButton";
import IconButton from "@mui/material/IconButton";
import DeleteIcon from "@mui/icons-material/Delete";
import ListItemButton from "@mui/material/ListItemButton";
import ListItemText from "@mui/material/ListItemText";
import Collapse from "@mui/material/Collapse";
import ExpandMore from "@mui/icons-material/ExpandMore";
import ExpandLess from "@mui/icons-material/ExpandLess";
import { killWorkerScript } from "../../Netscript/killWorkerScript";
import { WorkerScript } from "../../Netscript/WorkerScript";
@@ -30,6 +38,7 @@ type IProps = {
};
export function WorkerScriptAccordion(props: IProps): React.ReactElement {
const [open, setOpen] = React.useState(false);
const workerScript = props.workerScript;
const scriptRef = workerScript.scriptRef;
@@ -48,39 +57,42 @@ export function WorkerScriptAccordion(props: IProps): React.ReactElement {
const offlineEps = scriptRef.offlineExpGained / scriptRef.offlineRunningTime;
return (
<Accordion TransitionProps={{ unmountOnExit: true }}>
<AccordionSummary expandIcon={<ExpandMoreIcon />}>
<Typography color="primary">{props.workerScript.name}</Typography>
</AccordionSummary>
<AccordionDetails>
<pre>Threads: {numeralWrapper.formatThreads(props.workerScript.scriptRef.threads)}</pre>
<pre>Args: {arrayToString(props.workerScript.args)}</pre>
<pre>Online Time: {convertTimeMsToTimeElapsedString(scriptRef.onlineRunningTime * 1e3)}</pre>
<pre>Offline Time: {convertTimeMsToTimeElapsedString(scriptRef.offlineRunningTime * 1e3)}</pre>
<pre>
Total online production: <Money money={scriptRef.onlineMoneyMade} />
</pre>
<pre>{Array(26).join(" ") + numeralWrapper.formatExp(scriptRef.onlineExpGained) + " hacking exp"}</pre>
<pre>
Online production rate: <Money money={onlineMps} /> / second
</pre>
<pre>{Array(25).join(" ") + numeralWrapper.formatExp(onlineEps) + " hacking exp / second"}</pre>
<pre>
Total offline production: <Money money={scriptRef.offlineMoneyMade} />
</pre>
<pre>{Array(27).join(" ") + numeralWrapper.formatExp(scriptRef.offlineExpGained) + " hacking exp"}</pre>
<pre>
Offline production rate: <Money money={offlineMps} /> / second
</pre>
<pre>{Array(26).join(" ") + numeralWrapper.formatExp(offlineEps) + " hacking exp / second"}</pre>
<>
<ListItemButton onClick={() => setOpen((old) => !old)} component={Paper}>
<ListItemText primary={<Typography style={{ whiteSpace: "pre-wrap" }}>{props.workerScript.name}</Typography>} />
{open ? <ExpandLess /> : <ExpandMore />}
</ListItemButton>
<Collapse in={open} timeout={0} unmountOnExit>
<Box m={3}>
<pre>Threads: {numeralWrapper.formatThreads(props.workerScript.scriptRef.threads)}</pre>
<pre>Args: {arrayToString(props.workerScript.args)}</pre>
<pre>Online Time: {convertTimeMsToTimeElapsedString(scriptRef.onlineRunningTime * 1e3)}</pre>
<pre>Offline Time: {convertTimeMsToTimeElapsedString(scriptRef.offlineRunningTime * 1e3)}</pre>
<pre>
Total online production: <Money money={scriptRef.onlineMoneyMade} />
</pre>
<pre>{Array(26).join(" ") + numeralWrapper.formatExp(scriptRef.onlineExpGained) + " hacking exp"}</pre>
<pre>
Online production rate: <Money money={onlineMps} /> / second
</pre>
<pre>{Array(25).join(" ") + numeralWrapper.formatExp(onlineEps) + " hacking exp / second"}</pre>
<pre>
Total offline production: <Money money={scriptRef.offlineMoneyMade} />
</pre>
<pre>{Array(27).join(" ") + numeralWrapper.formatExp(scriptRef.offlineExpGained) + " hacking exp"}</pre>
<pre>
Offline production rate: <Money money={offlineMps} /> / second
</pre>
<pre>{Array(26).join(" ") + numeralWrapper.formatExp(offlineEps) + " hacking exp / second"}</pre>
<Button onClick={logClickHandler}>
<Typography>Log</Typography>
</Button>
<IconButton onClick={killScriptClickHandler}>
<DeleteIcon color="error" />
</IconButton>
</AccordionDetails>
</Accordion>
<Button onClick={logClickHandler}>
<Typography>Log</Typography>
</Button>
<IconButton onClick={killScriptClickHandler}>
<DeleteIcon color="error" />
</IconButton>
</Box>
</Collapse>
</>
);
}