Farmbot-Web-App/frontend/nav/ticker_list.tsx

100 lines
3.5 KiB
TypeScript

import * as React from "react";
import { Collapse } from "@blueprintjs/core";
import { Markdown } from "../ui/index";
import { TickerListProps } from "./interfaces";
import { formatLogTime } from "../logs/index";
import { safeNumericSetting } from "../session";
import { ErrorBoundary } from "../error_boundary";
import { ALLOWED_MESSAGE_TYPES, TaggedLog, SpecialStatus } from "farmbot";
import { filterByVerbosity } from "../logs/components/logs_table";
import { isNumber } from "lodash";
import { GetWebAppConfigValue } from "../config_storage/actions";
import { Link } from "../link";
import { MessageType } from "../sequences/interfaces";
import { t } from "../i18next_wrapper";
import { TimeSettings } from "../interfaces";
/** Get current verbosity filter level for a message type from WebAppConfig. */
const getFilterLevel = (getConfigValue: GetWebAppConfigValue) =>
(type: ALLOWED_MESSAGE_TYPES): number => {
const filterLevel =
getConfigValue(safeNumericSetting(type + "_log"));
return isNumber(filterLevel) ? filterLevel : 1;
};
/** Generate a fallback TaggedLog to display in the first line of the ticker. */
const generateFallbackLog = (uuid: string, message: string): TaggedLog => {
return {
kind: "Log",
uuid,
specialStatus: SpecialStatus.SAVED,
body: {
message,
type: MessageType.debug,
verbosity: -1,
channels: [], created_at: NaN
}
};
};
/** Choose the log to display in the first line of the ticker. */
const getfirstTickerLog = (getConfigValue: GetWebAppConfigValue) =>
(logs: TaggedLog[]): TaggedLog => {
if (logs.length == 0) {
return generateFallbackLog("no_logs_yet", t("No logs yet."));
} else {
const filteredLogs =
filterByVerbosity(getFilterLevel(getConfigValue), logs);
if (filteredLogs.length > 0) {
return filteredLogs[0];
} else {
return generateFallbackLog("no_logs_to_display",
t("No logs to display. Visit Logs page to view filters."));
}
}
};
/** Format a single log for display in the ticker. */
const Ticker = (log: TaggedLog, timeSettings: TimeSettings) => {
const { message, type, created_at } = log.body;
const time = created_at ? formatLogTime(created_at, timeSettings) : "";
return <div key={log.uuid} className="status-ticker-wrapper">
<div className={`saucer ${type}`} />
<label className="status-ticker-message">
<Markdown>
{message.replace(/\s+/g, " ") || t("Loading")}
</Markdown>
</label>
<label className="status-ticker-created-at">
{t(time)}
</label>
</div>;
};
/** The logs ticker, with closed/open views, and a link to the Logs page. */
export const TickerList = (props: TickerListProps) => {
return <ErrorBoundary>
<div className="ticker-list" onClick={props.toggle("tickerListOpen")}>
<div className="first-ticker">
{Ticker(getfirstTickerLog(props.getConfigValue)(props.logs),
props.timeSettings)}
</div>
<Collapse isOpen={props.tickerListOpen}>
{filterByVerbosity(getFilterLevel(props.getConfigValue), props.logs)
// Don't use first log again since it's already displayed in first row
.filter((_, index) => index !== 0)
.map((log: TaggedLog) => Ticker(log, props.timeSettings))}
</Collapse>
<Collapse isOpen={props.tickerListOpen}>
<Link to={"/app/logs"}>
<div className="logs-page-link">
<label>
{t("Filter logs")}
</label>
</div>
</Link>
</Collapse>
</div>
</ErrorBoundary>;
};