import React, { useEffect, useContext, useRef, useState, ReactElement } from "react";
import { Typography } from "antd";
import * as lib from "@clusterio/lib";
import { useAccount } from "../model/account";
import ControlContext from "./ControlContext";
const { Paragraph } = Typography;
type Parsed = {
format: string;
type: string;
level: string;
time: string;
file: string;
action: string;
message: string;
};
function formatParsedOutput(parsed: Parsed, key: number) {
let time: ReactElement|string = "";
if (parsed.format === "seconds") {
time = {parsed.time.padStart(8)} ;
} else if (parsed.format === "date") {
time = {parsed.time} ;
}
let info: ReactElement|string = "";
if (parsed.type === "log") {
let level: ReactElement|string = parsed.level;
if (level === "Script") {
level = {level};
} else if (level === "Verbose") {
level = {level};
} else if (level === "Info") {
level = {level};
} else if (parsed.level === "Warning") {
level = {level};
} else if (parsed.level === "Error") {
level = {level};
}
info = <>{level} {parsed.file}: >;
} else if (parsed.type === "action") {
info = <>[{parsed.action}] >;
}
return {time}{info}{parsed.message}
;
}
type Info = {
level: string;
message: string;
parsed?: Parsed;
};
function formatLog(info: Info, key: number): ReactElement {
if (info.level === "server" && info.parsed) {
return formatParsedOutput(info.parsed, key);
}
let level = {info.level};
return [{level}] {info.message}
;
}
type LogConsoleProps = {
all?: boolean;
controller?: boolean;
hosts?: number[];
instances?: number[];
};
export default function LogConsole(props: LogConsoleProps) {
let account = useAccount();
let control = useContext(ControlContext);
let anchor = useRef();
let [pastLines, setPastLines] = useState([{"Loading past entries..."}
]);
let [lines, setLines] = useState([]);
useEffect(() => {
let logFilter = {
all: props.all || false,
controller: props.controller || false,
hostIds: props.hosts || [],
instanceIds: 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")) {
setPastLines([{"Loading past entries..."}
]);
control.send(new lib.LogQueryRequest(
logFilter.all,
logFilter.controller,
logFilter.hostIds,
logFilter.instanceIds,
undefined,
400,
"desc",
)).then(result => {
setPastLines(result.log.map((info, index) => formatLog(info as Info, -index - 1)).reverse());
}).catch(err => {
setPastLines([{`Error loading log: ${err.message}`}
]);
});
} else {
setPastLines([]);
}
function logHandler(info: Info) {
setLines(currentLines => currentLines.concat(
[formatLog(info, currentLines.length)]
));
}
control.onLog(logFilter, logHandler);
return () => {
control.offLog(logFilter, logHandler);
};
}, [props.all, props.controller, (props.hosts || []).join(), (props.instances || []).join()]);
return <>
{pastLines}
{lines}
>;
}