diff --git a/packages/web_ui/src/components/InstanceViewPage.jsx b/packages/web_ui/src/components/InstanceViewPage.jsx index e9bf72c9..c5a27cb5 100644 --- a/packages/web_ui/src/components/InstanceViewPage.jsx +++ b/packages/web_ui/src/components/InstanceViewPage.jsx @@ -9,7 +9,7 @@ import { useAccount } from "../model/account"; import ControlContext from "./ControlContext"; import PageLayout from "./PageLayout"; import InstanceConfigTree from "./InstanceConfigTree"; -import InstanceConsole from "./InstanceConsole"; +import LogConsole from "./LogConsole"; import InstanceRcon from "./InstanceRcon"; import AssignInstanceModal from "./AssignInstanceModal"; import StartStopInstanceButton from "./StartStopInstanceButton"; @@ -127,7 +127,7 @@ export default function InstanceViewPage(props) { account.hasAnyPermission("core.log.follow", "core.instance.send_rcon") && Console } - {account.hasPermission("core.log.follow") && } + {account.hasPermission("core.log.follow") && } { account.hasPermission("core.instance.send_rcon") && diff --git a/packages/web_ui/src/components/InstanceConsole.jsx b/packages/web_ui/src/components/LogConsole.jsx similarity index 88% rename from packages/web_ui/src/components/InstanceConsole.jsx rename to packages/web_ui/src/components/LogConsole.jsx index aa2d50ca..aa76c7a7 100644 --- a/packages/web_ui/src/components/InstanceConsole.jsx +++ b/packages/web_ui/src/components/LogConsole.jsx @@ -49,7 +49,7 @@ function formatLog(info, key) { return [{level}] {info.message}
; } -export default function InstanceConsole(props) { +export default function LogConsole(props) { let account = useAccount(); let control = useContext(ControlContext); let anchor = useRef(); @@ -57,16 +57,20 @@ export default function InstanceConsole(props) { let [lines, setLines] = useState([]); useEffect(() => { + let logFilter = { + all: props.all || false, + master: props.master || false, + slave_ids: props.slaves || [], + instance_ids: props.instances || [], + }; + // Scroll view to the anchor so it sticks to the bottom let parent = anchor.current.parentElement; parent.scrollTop = parent.scrollHeight - parent.clientHeight; if (account.hasPermission("core.log.query")) { libLink.messages.queryLog.send(control, { - all: false, - master: false, - slave_ids: [], - instance_ids: [props.id], + ...logFilter, max_level: null, limit: 400, order: "desc", @@ -85,11 +89,11 @@ export default function InstanceConsole(props) { )); } - control.onInstanceLog(props.id, logHandler); + control.onLog(logFilter, logHandler); return () => { - control.offInstanceLog(props.id, logHandler); + control.offLog(logFilter, logHandler); }; - }, [props.id]); + }, [props.all, props.master, props.slaves, props.instances]); return <> diff --git a/packages/web_ui/src/components/MasterPage.jsx b/packages/web_ui/src/components/MasterPage.jsx index 53c83877..088d347e 100644 --- a/packages/web_ui/src/components/MasterPage.jsx +++ b/packages/web_ui/src/components/MasterPage.jsx @@ -1,15 +1,23 @@ import React, { useContext } from "react"; +import { Typography } from "antd"; +import LogConsole from "./LogConsole"; import { useAccount } from "../model/account"; import MasterConfigTree from "./MasterConfigTree"; import PageLayout from "./PageLayout"; +const { Title } = Typography; + export default function SlavesPage() { let account = useAccount(); return

Master

+ {account.hasPermission("core.log.follow") && <> + Console + + } {account.hasPermission("core.master.get_config") && }
; }; diff --git a/packages/web_ui/src/components/SlaveViewPage.jsx b/packages/web_ui/src/components/SlaveViewPage.jsx index f4076073..c5a985bd 100644 --- a/packages/web_ui/src/components/SlaveViewPage.jsx +++ b/packages/web_ui/src/components/SlaveViewPage.jsx @@ -3,6 +3,7 @@ import { Descriptions, PageHeader, Spin, Typography } from "antd"; import { useParams } from "react-router-dom"; import InstanceList from "./InstanceList"; +import LogConsole from "./LogConsole"; import { useAccount } from "../model/account"; import { useInstanceList } from "../model/instance"; import { useSlave } from "../model/slave"; @@ -47,10 +48,13 @@ export default function SlaveViewPage(props) { {slave["agent"]} {slave["version"]} - {account.hasPermission("core.instance.list") && <> Instances } + {account.hasPermission("core.log.follow") && <> + Console + + } ; } diff --git a/packages/web_ui/src/index.jsx b/packages/web_ui/src/index.jsx index febfde98..ae2b6bbc 100644 --- a/packages/web_ui/src/index.jsx +++ b/packages/web_ui/src/index.jsx @@ -13,8 +13,9 @@ export { default as BaseConfigTree } from "./components/BaseConfigTree"; export { default as InstanceConfigTree } from "./components/InstanceConfigTree"; export { default as MasterConfigTree } from "./components/MasterConfigTree"; +export { default as LogConsole } from "./components/LogConsole"; + export { default as AssignInstanceModal } from "./components/AssignInstanceModal"; -export { default as InstanceConsole } from "./components/InstanceConsole"; export { default as InstanceList } from "./components/InstanceList"; export { default as InstanceRcon } from "./components/InstanceRcon"; diff --git a/packages/web_ui/src/util/websocket.jsx b/packages/web_ui/src/util/websocket.jsx index 18c54f1c..5473ad49 100644 --- a/packages/web_ui/src/util/websocket.jsx +++ b/packages/web_ui/src/util/websocket.jsx @@ -27,6 +27,22 @@ export class ControlConnector extends libLink.WebSocketClientConnector { } } +function logFilter({ all, master, slave_ids, instance_ids }, info) { + if (all) { + return true; + } + if (master && info.slave_id === undefined) { + return true; + } + if (info.slave_id && slave_ids.includes(info.slave_id)) { + return true; + } + if (info.instance_id && instance_ids.includes(info.instance_id)) { + return true; + } + return false; +} + /** * Handles running the control * @@ -70,7 +86,7 @@ export class Control extends libLink.Link { this.slaveUpdateHandlers = new Map(); this.instanceUpdateHandlers = new Map(); this.saveListUpdateHandlers = new Map(); - this.instanceLogHandlers = new Map(); + this.logHandlers = new Map(); this.connector.on("connect", data => { this.accountName = data.account.name; @@ -302,23 +318,20 @@ export class Control extends libLink.Link { async logMessageEventHandler(message) { let info = message.data.info; - if (info.instance_id !== undefined) { - let instanceHandlers = this.instanceLogHandlers.get(info.instance_id); - for (let handler of instanceHandlers || []) { - handler(info); + for (let [filter, handlers] of this.logHandlers) { + if (logFilter(filter, info)) { + for (let handler of handlers) { + handler(info); + } } } } - async onInstanceLog(id, handler) { - if (!Number.isInteger(id)) { - throw new Error("Invalid instance id"); - } - - let handlers = this.instanceLogHandlers.get(id); + async onLog(filter, handler) { + let handlers = this.logHandlers.get(filter); if (!handlers) { handlers = []; - this.instanceLogHandlers.set(id, handlers); + this.logHandlers.set(filter, handlers); } handlers.push(handler); @@ -328,15 +341,15 @@ export class Control extends libLink.Link { } } - async offInstanceLog(id, handler) { - let handlers = this.instanceLogHandlers.get(id); + async offLog(filter, handler) { + let handlers = this.logHandlers.get(filter); if (!handlers || !handlers.length) { - throw new Error(`No handlers for instance ${id} exist`); + throw new Error("No handlers for the given filter exists"); } let index = handlers.lastIndexOf(handler); if (index === -1) { - throw new Error(`Given handler is not registered for instance ${id}`); + throw new Error("Given handler is not registered for the filter"); } handlers.splice(index, 1); @@ -350,13 +363,29 @@ export class Control extends libLink.Link { return; } - await libLink.messages.setLogSubscriptions.send(this, { + let combinedFilter = { all: false, master: false, slave_ids: [], - instance_ids: [...this.instanceLogHandlers.keys()], - max_level: null, - }); + instance_ids: [], + }; + + for (let filter of this.logHandlers.keys()) { + if (filter.all) { combinedFilter.all = true; } + if (filter.master) { combinedFilter.master = true; } + for (let slaveId of filter.slave_ids || []) { + if (!combinedFilter.slave_ids.includes(slaveId)) { + combinedFilter.slave_ids.push(slaveId); + } + } + for (let instanceId of filter.instance_ids || []) { + if (!combinedFilter.instance_ids.includes(instanceId)) { + combinedFilter.instance_ids.push(instanceId); + } + } + } + + await libLink.messages.setLogSubscriptions.send(this, { ...combinedFilter, max_level: null }); } async debugWsMessageEventHandler(message) {