mirror of
https://github.com/bitburner-official/bitburner-src.git
synced 2026-04-26 11:10:58 +02:00
Active Scripts
This commit is contained in:
@@ -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>;
|
||||
|
||||
@@ -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>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -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}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -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}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -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>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user