log verbosity filters
parent
237ddb2651
commit
5f0055f084
|
@ -2,6 +2,28 @@ jest.mock("react-redux", () => ({
|
|||
connect: jest.fn()
|
||||
}));
|
||||
|
||||
const mockStorj: Dictionary<number | boolean> = {};
|
||||
|
||||
jest.mock("../../session", () => {
|
||||
return {
|
||||
Session: {
|
||||
getNum: (k: string) => {
|
||||
return mockStorj[k];
|
||||
},
|
||||
setNum: (k: string, v: number) => {
|
||||
mockStorj[k] = v;
|
||||
},
|
||||
getBool: (k: string) => {
|
||||
mockStorj[k] = !!mockStorj[k];
|
||||
return mockStorj[k];
|
||||
}
|
||||
},
|
||||
// tslint:disable-next-line:no-any
|
||||
safeNumericSetting: (x: any) => x
|
||||
|
||||
};
|
||||
});
|
||||
|
||||
import * as React from "react";
|
||||
import { mount } from "enzyme";
|
||||
import { Logs } from "../index";
|
||||
|
@ -10,6 +32,8 @@ import { TaggedLog, SpecialStatus } from "../../resources/tagged_resources";
|
|||
import { Log } from "../../interfaces";
|
||||
import { generateUuid } from "../../resources/util";
|
||||
import { bot } from "../../__test_support__/fake_state/bot";
|
||||
import { Dictionary } from "farmbot";
|
||||
import { NumericSetting } from "../../session_keys";
|
||||
|
||||
describe("<Logs />", () => {
|
||||
function fakeLogs(): TaggedLog[] {
|
||||
|
@ -48,13 +72,13 @@ describe("<Logs />", () => {
|
|||
.map(string =>
|
||||
expect(wrapper.text().toLowerCase()).toContain(string.toLowerCase()));
|
||||
const filterBtn = wrapper.find("button").first();
|
||||
expect(filterBtn.text().toLowerCase()).toEqual("filter");
|
||||
expect(filterBtn.hasClass("gray")).toBeTruthy();
|
||||
expect(filterBtn.text().toLowerCase()).toEqual("filters active");
|
||||
expect(filterBtn.hasClass("green")).toBeTruthy();
|
||||
});
|
||||
|
||||
it("filters logs", () => {
|
||||
const wrapper = mount(<Logs logs={fakeLogs()} bot={bot} />);
|
||||
wrapper.setState({ info: false });
|
||||
wrapper.setState({ info: 0 });
|
||||
expect(wrapper.text()).not.toContain("Fake log message 1");
|
||||
const filterBtn = wrapper.find("button").first();
|
||||
expect(filterBtn.text().toLowerCase()).toEqual("filters active");
|
||||
|
@ -74,8 +98,46 @@ describe("<Logs />", () => {
|
|||
|
||||
it("shows verbosity", () => {
|
||||
const logs = fakeLogs();
|
||||
logs[0].body.meta.verbosity = 999;
|
||||
logs[0].body.meta.verbosity = -999;
|
||||
const wrapper = mount(<Logs logs={logs} bot={bot} />);
|
||||
expect(wrapper.text()).toContain(999);
|
||||
expect(wrapper.text()).toContain(-999);
|
||||
});
|
||||
|
||||
it("loads filter setting", () => {
|
||||
mockStorj[NumericSetting.warnLog] = 3;
|
||||
const wrapper = mount(<Logs logs={fakeLogs()} bot={bot} />);
|
||||
expect(wrapper.state().warn).toEqual(3);
|
||||
});
|
||||
|
||||
it("shows overall filter status", () => {
|
||||
const wrapper = mount(<Logs logs={fakeLogs()} bot={bot} />);
|
||||
wrapper.setState({
|
||||
success: 3, busy: 3, warn: 3, error: 3, info: 3, fun: 3, debug: 3
|
||||
});
|
||||
const filterBtn = wrapper.find("button").first();
|
||||
expect(filterBtn.text().toLowerCase()).toEqual("filter");
|
||||
expect(filterBtn.hasClass("gray")).toBeTruthy();
|
||||
});
|
||||
|
||||
it("toggles filter", () => {
|
||||
mockStorj[NumericSetting.warnLog] = 3;
|
||||
const wrapper = mount(<Logs logs={fakeLogs()} bot={bot} />);
|
||||
// tslint:disable-next-line:no-any
|
||||
const instance = wrapper.instance() as any;
|
||||
expect(wrapper.state().warn).toEqual(3);
|
||||
instance.toggle("warn")();
|
||||
expect(wrapper.state().warn).toEqual(0);
|
||||
instance.toggle("warn")();
|
||||
expect(wrapper.state().warn).toEqual(1);
|
||||
});
|
||||
|
||||
it("sets filter", () => {
|
||||
mockStorj[NumericSetting.warnLog] = 3;
|
||||
const wrapper = mount(<Logs logs={fakeLogs()} bot={bot} />);
|
||||
// tslint:disable-next-line:no-any
|
||||
const instance = wrapper.instance() as any;
|
||||
expect(wrapper.state().warn).toEqual(3);
|
||||
instance.setFilterLevel("warn")(2);
|
||||
expect(wrapper.state().warn).toEqual(2);
|
||||
});
|
||||
});
|
||||
|
|
|
@ -4,23 +4,40 @@ import { LogsFilterMenu } from "../filter_menu";
|
|||
|
||||
describe("<LogsFilterMenu />", () => {
|
||||
const fakeState = {
|
||||
autoscroll: true, success: true, busy: true, warn: true,
|
||||
error: true, info: true, fun: true, debug: true
|
||||
autoscroll: true, success: 1, busy: 1, warn: 1,
|
||||
error: 1, info: 1, fun: 1, debug: 1
|
||||
};
|
||||
it("renders", () => {
|
||||
const wrapper = mount(
|
||||
<LogsFilterMenu toggle={jest.fn()} state={fakeState} />);
|
||||
<LogsFilterMenu
|
||||
toggle={jest.fn()} setFilterLevel={jest.fn()} state={fakeState} />);
|
||||
["success", "busy", "warn", "error", "info", "fun", "debug"]
|
||||
.map(string =>
|
||||
expect(wrapper.text().toLowerCase()).toContain(string.toLowerCase()));
|
||||
expect(wrapper.text().toLowerCase())
|
||||
.toContain(string.toLowerCase()));
|
||||
expect(wrapper.text()).not.toContain("autscroll");
|
||||
});
|
||||
|
||||
it("filters logs", () => {
|
||||
const toggle = jest.fn();
|
||||
const setFilterLevel = jest.fn();
|
||||
const wrapper = mount(
|
||||
<LogsFilterMenu toggle={(x) => () => toggle(x)} state={fakeState} />);
|
||||
<LogsFilterMenu
|
||||
toggle={(x) => () => toggle(x)}
|
||||
setFilterLevel={(x) => () => setFilterLevel(x)}
|
||||
state={fakeState} />);
|
||||
wrapper.find("button").first().simulate("click");
|
||||
expect(toggle).toHaveBeenCalledWith("success");
|
||||
});
|
||||
|
||||
it("shows filter status", () => {
|
||||
fakeState.debug = 3;
|
||||
fakeState.success = 0;
|
||||
const wrapper = mount(
|
||||
<LogsFilterMenu
|
||||
toggle={jest.fn()} setFilterLevel={jest.fn()} state={fakeState} />);
|
||||
const toggles = wrapper.find("button");
|
||||
expect(toggles.last().hasClass("green")).toBeTruthy();
|
||||
expect(toggles.first().hasClass("red")).toBeTruthy();
|
||||
});
|
||||
});
|
||||
|
|
|
@ -12,8 +12,13 @@ import { bot } from "../../../__test_support__/fake_state/bot";
|
|||
import { ConfigurationName } from "farmbot";
|
||||
|
||||
describe("<LogsSettingsMenu />", () => {
|
||||
beforeEach(() => {
|
||||
jest.clearAllMocks();
|
||||
});
|
||||
|
||||
it("renders", () => {
|
||||
const wrapper = mount(<LogsSettingsMenu {...bot} />);
|
||||
const wrapper = mount(<LogsSettingsMenu
|
||||
bot={bot} setFilterLevel={() => jest.fn()} />);
|
||||
["begin", "steps", "complete"].map(string =>
|
||||
expect(wrapper.text().toLowerCase()).toContain(string));
|
||||
});
|
||||
|
@ -21,7 +26,8 @@ describe("<LogsSettingsMenu />", () => {
|
|||
function testSettingToggle(setting: ConfigurationName, position: number) {
|
||||
it("toggles setting", () => {
|
||||
bot.hardware.configuration[setting] = false;
|
||||
const wrapper = mount(<LogsSettingsMenu {...bot} />);
|
||||
const wrapper = mount(<LogsSettingsMenu
|
||||
bot={bot} setFilterLevel={() => jest.fn()} />);
|
||||
wrapper.find("button").at(position).simulate("click");
|
||||
expect(mockDevice.updateConfig)
|
||||
.toHaveBeenCalledWith({ [setting]: true });
|
||||
|
@ -30,4 +36,6 @@ describe("<LogsSettingsMenu />", () => {
|
|||
testSettingToggle("sequence_init_log", 0);
|
||||
testSettingToggle("sequence_body_log", 1);
|
||||
testSettingToggle("sequence_complete_log", 2);
|
||||
testSettingToggle("firmware_output_log" as ConfigurationName, 3);
|
||||
testSettingToggle("firmware_input_log" as ConfigurationName, 4);
|
||||
});
|
||||
|
|
|
@ -1,9 +1,11 @@
|
|||
import * as React from "react";
|
||||
import { LogsFilterMenuProps, LogsState } from "../interfaces";
|
||||
import * as _ from "lodash";
|
||||
import { Slider } from "@blueprintjs/core";
|
||||
|
||||
export const LogsFilterMenu = (props: LogsFilterMenuProps) => {
|
||||
const btnColor = (x: keyof LogsState) => props.state[x] ? "green" : "red";
|
||||
const btnColor = (x: keyof LogsState) => props.state[x] != 0
|
||||
? "green" : "red";
|
||||
return <div className={"logs-settings-menu"}>
|
||||
{Object.keys(props.state)
|
||||
.filter(x => { if (!(x == "autoscroll")) { return x; } })
|
||||
|
@ -16,6 +18,9 @@ export const LogsFilterMenu = (props: LogsFilterMenuProps) => {
|
|||
<button
|
||||
className={"fb-button fb-toggle-button " + btnColor(logType)}
|
||||
onClick={props.toggle(logType)} />
|
||||
<Slider min={0} max={3} stepSize={1}
|
||||
onChange={props.setFilterLevel(logType)}
|
||||
value={props.state[logType] as number} />
|
||||
</fieldset>;
|
||||
})}
|
||||
</div>;
|
||||
|
|
|
@ -7,17 +7,19 @@ import * as _ from "lodash";
|
|||
|
||||
const LogsRow = (tlog: TaggedLog, state: LogsState) => {
|
||||
const log = tlog.body;
|
||||
const { x, y, z, verbosity } = log.meta;
|
||||
const time = formatLogTime(log.created_at);
|
||||
const type = (log.meta || {}).type;
|
||||
const filtered = state[type as keyof LogsState];
|
||||
const displayLog = _.isUndefined(filtered) || filtered;
|
||||
const { x, y, z } = log.meta;
|
||||
const filterLevel = state[type as keyof LogsState];
|
||||
const displayLog = verbosity
|
||||
? verbosity <= filterLevel
|
||||
: filterLevel != 0;
|
||||
return displayLog ?
|
||||
<tr key={tlog.uuid}>
|
||||
<td>
|
||||
<div className={`saucer ${type}`}>
|
||||
<p>
|
||||
{log.meta.verbosity}
|
||||
{verbosity}
|
||||
</p>
|
||||
</div>
|
||||
{_.startCase(type)}
|
||||
|
|
|
@ -1,16 +1,15 @@
|
|||
import * as React from "react";
|
||||
import { t } from "i18next";
|
||||
import { BotState } from "../../devices/interfaces";
|
||||
import { Help } from "../../ui/index";
|
||||
import { ToolTips } from "../../constants";
|
||||
import { ToggleButton } from "../../controls/toggle_button";
|
||||
import { updateConfig } from "../../devices/actions";
|
||||
import { noop } from "lodash";
|
||||
import { LogSettingProps } from "../interfaces";
|
||||
import { LogSettingProps, LogsSettingsMenuProps } from "../interfaces";
|
||||
import { ConfigurationName } from "farmbot";
|
||||
|
||||
const LogSetting = (props: LogSettingProps) => {
|
||||
const { label, setting, toolTip, value } = props;
|
||||
const { label, setting, toolTip, value, setFilterLevel } = props;
|
||||
return <fieldset>
|
||||
<label>
|
||||
{t(label)}
|
||||
|
@ -19,11 +18,29 @@ const LogSetting = (props: LogSettingProps) => {
|
|||
<ToggleButton toggleValue={value}
|
||||
toggleAction={() => {
|
||||
updateConfig({ [setting]: !value })(noop);
|
||||
if (!value === true) {
|
||||
switch (setting) {
|
||||
case "firmware_output_log" as ConfigurationName:
|
||||
case "firmware_input_log" as ConfigurationName:
|
||||
setFilterLevel("debug")(3);
|
||||
break;
|
||||
case "sequence_init_log":
|
||||
setFilterLevel("busy")(2);
|
||||
break;
|
||||
case "sequence_body_log":
|
||||
setFilterLevel("info")(2);
|
||||
break;
|
||||
case "sequence_complete_log":
|
||||
setFilterLevel("success")(2);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}} />
|
||||
</fieldset>;
|
||||
};
|
||||
|
||||
export const LogsSettingsMenu = (bot: BotState) => {
|
||||
export const LogsSettingsMenu = (props: LogsSettingsMenuProps) => {
|
||||
const { bot, setFilterLevel } = props;
|
||||
const { configuration } = bot.hardware;
|
||||
return <div className={"logs-settings-menu"}>
|
||||
{t("Create logs for sequence:")}
|
||||
|
@ -31,17 +48,20 @@ export const LogsSettingsMenu = (bot: BotState) => {
|
|||
label={"Begin"}
|
||||
setting={"sequence_init_log"}
|
||||
toolTip={ToolTips.SEQUENCE_LOG_BEGIN}
|
||||
value={configuration.sequence_init_log} />
|
||||
value={configuration.sequence_init_log}
|
||||
setFilterLevel={setFilterLevel} />
|
||||
<LogSetting
|
||||
label={"Steps"}
|
||||
setting={"sequence_body_log"}
|
||||
toolTip={ToolTips.SEQUENCE_LOG_STEP}
|
||||
value={configuration.sequence_body_log} />
|
||||
value={configuration.sequence_body_log}
|
||||
setFilterLevel={setFilterLevel} />
|
||||
<LogSetting
|
||||
label={"Complete"}
|
||||
setting={"sequence_complete_log"}
|
||||
toolTip={ToolTips.SEQUENCE_LOG_END}
|
||||
value={configuration.sequence_complete_log} />
|
||||
value={configuration.sequence_complete_log}
|
||||
setFilterLevel={setFilterLevel} />
|
||||
{t("Firmware Logs:")}
|
||||
{/*
|
||||
// TODO: remove type assertions when names are added to farmbot-js
|
||||
|
@ -50,11 +70,13 @@ export const LogsSettingsMenu = (bot: BotState) => {
|
|||
label={"Sent"}
|
||||
setting={"firmware_output_log" as ConfigurationName}
|
||||
toolTip={ToolTips.FIRMWARE_LOG_SENT}
|
||||
value={!!configuration["firmware_output_log" as ConfigurationName]} />
|
||||
value={!!configuration["firmware_output_log" as ConfigurationName]}
|
||||
setFilterLevel={setFilterLevel} />
|
||||
<LogSetting
|
||||
label={"Received"}
|
||||
setting={"firmware_input_log" as ConfigurationName}
|
||||
toolTip={ToolTips.FIRMWARE_LOG_RECEIVED}
|
||||
value={!!configuration["firmware_input_log" as ConfigurationName]} />
|
||||
value={!!configuration["firmware_input_log" as ConfigurationName]}
|
||||
setFilterLevel={setFilterLevel} />
|
||||
</div>;
|
||||
};
|
||||
|
|
|
@ -10,6 +10,9 @@ import { ToolTips } from "../constants";
|
|||
import { LogsSettingsMenu } from "./components/settings_menu";
|
||||
import { LogsFilterMenu } from "./components/filter_menu";
|
||||
import { LogsTable } from "./components/logs_table";
|
||||
import { Session, safeNumericSetting } from "../session";
|
||||
import { isUndefined } from "lodash";
|
||||
import { NumericSetting } from "../session_keys";
|
||||
|
||||
export const formatLogTime = (created_at: number) =>
|
||||
moment.unix(created_at).local().format("MMM D, h:mma");
|
||||
|
@ -17,43 +20,73 @@ export const formatLogTime = (created_at: number) =>
|
|||
@connect(mapStateToProps)
|
||||
export class Logs extends React.Component<LogsProps, Partial<LogsState>> {
|
||||
|
||||
initialize = (name: NumericSetting, defaultValue: number): number => {
|
||||
const currentValue = Session.getNum(safeNumericSetting(name));
|
||||
if (isUndefined(currentValue)) {
|
||||
Session.setNum(safeNumericSetting(name), defaultValue);
|
||||
return defaultValue;
|
||||
} else {
|
||||
return currentValue;
|
||||
}
|
||||
}
|
||||
|
||||
state: LogsState = {
|
||||
autoscroll: false,
|
||||
success: true,
|
||||
busy: true,
|
||||
warn: true,
|
||||
error: true,
|
||||
info: true,
|
||||
fun: true,
|
||||
debug: true,
|
||||
success: this.initialize(NumericSetting.successLog, 1),
|
||||
busy: this.initialize(NumericSetting.busyLog, 1),
|
||||
warn: this.initialize(NumericSetting.warnLog, 1),
|
||||
error: this.initialize(NumericSetting.errorLog, 1),
|
||||
info: this.initialize(NumericSetting.infoLog, 1),
|
||||
fun: this.initialize(NumericSetting.funLog, 1),
|
||||
debug: this.initialize(NumericSetting.debugLog, 1),
|
||||
};
|
||||
|
||||
toggle = (name: keyof LogsState) =>
|
||||
() => this.setState({ [name]: !this.state[name] });
|
||||
toggle = (name: keyof LogsState) => {
|
||||
switch (this.state[name]) {
|
||||
case 0:
|
||||
return () => {
|
||||
this.setState({ [name]: 1 });
|
||||
Session.setNum(safeNumericSetting(name + "Log"), 1);
|
||||
};
|
||||
default:
|
||||
return () => {
|
||||
this.setState({ [name]: 0 });
|
||||
Session.setNum(safeNumericSetting(name + "Log"), 0);
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
setFilterLevel = (name: keyof LogsState) => {
|
||||
return (value: number) => {
|
||||
this.setState({ [name]: value });
|
||||
Session.setNum(safeNumericSetting(name + "Log"), value);
|
||||
};
|
||||
};
|
||||
|
||||
get filterActive() {
|
||||
const filterKeys = Object.keys(this.state)
|
||||
.filter(x => !(x === "autoscroll"));
|
||||
const filterValues = filterKeys
|
||||
.map((key: keyof LogsState) => this.state[key]);
|
||||
return !filterValues.every(x => x);
|
||||
return !filterValues.every(x => x == 3);
|
||||
}
|
||||
|
||||
render() {
|
||||
const filterBtnColor = this.filterActive ? "green" : "gray";
|
||||
return <Page className="logs">
|
||||
<Row>
|
||||
<Col xs={11}>
|
||||
<Col xs={10}>
|
||||
<h3>
|
||||
<i>{t("Logs")}</i>
|
||||
</h3>
|
||||
<ToolTip helpText={ToolTips.LOGS} />
|
||||
</Col>
|
||||
<Col xs={1}>
|
||||
<Col xs={2}>
|
||||
<div className={"settings-menu-button"}>
|
||||
<Popover position={Position.BOTTOM_RIGHT}>
|
||||
<i className="fa fa-gear" />
|
||||
<LogsSettingsMenu {...this.props.bot} />
|
||||
<LogsSettingsMenu
|
||||
setFilterLevel={this.setFilterLevel} bot={this.props.bot} />
|
||||
</Popover>
|
||||
</div>
|
||||
<div className={"settings-menu-button"}>
|
||||
|
@ -61,7 +94,9 @@ export class Logs extends React.Component<LogsProps, Partial<LogsState>> {
|
|||
<button className={`fb-button ${filterBtnColor}`}>
|
||||
{this.filterActive ? t("Filters active") : t("filter")}
|
||||
</button>
|
||||
<LogsFilterMenu toggle={this.toggle} state={this.state} />
|
||||
<LogsFilterMenu
|
||||
toggle={this.toggle} state={this.state}
|
||||
setFilterLevel={this.setFilterLevel} />
|
||||
</Popover>
|
||||
</div>
|
||||
</Col>
|
||||
|
|
|
@ -8,13 +8,13 @@ export interface LogsProps {
|
|||
}
|
||||
|
||||
export interface Filters {
|
||||
success: boolean;
|
||||
busy: boolean;
|
||||
warn: boolean;
|
||||
error: boolean;
|
||||
info: boolean;
|
||||
fun: boolean;
|
||||
debug: boolean;
|
||||
success: number;
|
||||
busy: number;
|
||||
warn: number;
|
||||
error: number;
|
||||
info: number;
|
||||
fun: number;
|
||||
debug: number;
|
||||
}
|
||||
|
||||
export interface LogsState extends Filters {
|
||||
|
@ -27,15 +27,23 @@ export interface LogsTableProps {
|
|||
}
|
||||
|
||||
type ToggleEventHandler = (e: React.MouseEvent<HTMLButtonElement>) => void;
|
||||
type SetNumSetting = (property: keyof LogsState) => (value: number) => void;
|
||||
|
||||
export interface LogsFilterMenuProps {
|
||||
toggle: (property: keyof LogsState) => ToggleEventHandler;
|
||||
state: LogsState;
|
||||
setFilterLevel: SetNumSetting;
|
||||
}
|
||||
|
||||
export interface LogSettingProps {
|
||||
label: string;
|
||||
setting: ConfigurationName;
|
||||
toolTip: string;
|
||||
value: boolean | undefined;
|
||||
value: boolean | number | undefined;
|
||||
setFilterLevel: SetNumSetting;
|
||||
}
|
||||
|
||||
export interface LogsSettingsMenuProps {
|
||||
bot: BotState;
|
||||
setFilterLevel: SetNumSetting;
|
||||
}
|
||||
|
|
|
@ -1,8 +1,31 @@
|
|||
const mockStorj: Dictionary<number | boolean> = {};
|
||||
|
||||
jest.mock("../../session", () => {
|
||||
return {
|
||||
Session: {
|
||||
getNum: (k: string) => {
|
||||
return mockStorj[k];
|
||||
},
|
||||
setNum: (k: string, v: number) => {
|
||||
mockStorj[k] = v;
|
||||
},
|
||||
getBool: (k: string) => {
|
||||
mockStorj[k] = !!mockStorj[k];
|
||||
return mockStorj[k];
|
||||
}
|
||||
},
|
||||
// tslint:disable-next-line:no-any
|
||||
safeNumericSetting: (x: any) => x
|
||||
|
||||
};
|
||||
});
|
||||
|
||||
import * as React from "react";
|
||||
import { mount } from "enzyme";
|
||||
|
||||
import { TickerList } from "../ticker_list";
|
||||
import { Log } from "../../interfaces";
|
||||
import { Dictionary } from "farmbot";
|
||||
|
||||
describe("<TickerList />", () => {
|
||||
const log: Log = {
|
||||
|
@ -64,4 +87,16 @@ describe("<TickerList />", () => {
|
|||
expect(labels.at(3).text()).toContain(":50pm");
|
||||
expect(labels.at(4).text()).toEqual("Filter logs");
|
||||
});
|
||||
|
||||
it("all logs filtered out", () => {
|
||||
["success", "busy", "warn", "error", "info", "fun", "debug"]
|
||||
.map(logType => mockStorj[logType + "Log"] = 0);
|
||||
log.meta.verbosity = 1;
|
||||
const wrapper = mount(<TickerList
|
||||
logs={[log]} tickerListOpen={false} toggle={jest.fn()} />);
|
||||
const labels = wrapper.find("label");
|
||||
expect(labels.length).toEqual(2);
|
||||
expect(labels.at(0).text())
|
||||
.toContain("No logs to display. Visit Logs page to view filters.");
|
||||
});
|
||||
});
|
||||
|
|
|
@ -6,6 +6,44 @@ import { TickerListProps } from "./interfaces";
|
|||
import { Link } from "react-router";
|
||||
import { t } from "i18next";
|
||||
import { formatLogTime } from "../logs/index";
|
||||
import { Session, safeNumericSetting } from "../session";
|
||||
import { isNumber } from "lodash";
|
||||
|
||||
const logFilter = (log: Log): Log | undefined => {
|
||||
const type = (log.meta || {}).type;
|
||||
const { verbosity } = log.meta;
|
||||
const filterLevel = Session.getNum(safeNumericSetting(type + "Log"));
|
||||
const filterLevelCompare = isNumber(filterLevel) ? filterLevel : 1;
|
||||
const displayLog = verbosity
|
||||
? verbosity <= filterLevelCompare
|
||||
: filterLevel != 0;
|
||||
const whitelisted = !log.message.toLowerCase().includes("filtered");
|
||||
if (displayLog && whitelisted) {
|
||||
return log;
|
||||
}
|
||||
return;
|
||||
};
|
||||
|
||||
const getfirstTickerLog = (logs: Log[]): Log => {
|
||||
if (logs.length == 0) {
|
||||
return {
|
||||
message: "No logs yet.",
|
||||
meta: { type: "debug", verbosity: -1 },
|
||||
channels: [], created_at: NaN
|
||||
};
|
||||
} else {
|
||||
const filteredLogs = logs.filter(log => logFilter(log));
|
||||
if (filteredLogs.length > 0) {
|
||||
return filteredLogs[0];
|
||||
} else {
|
||||
return {
|
||||
message: "No logs to display. Visit Logs page to view filters.",
|
||||
meta: { type: "debug", verbosity: -1 },
|
||||
channels: [], created_at: NaN
|
||||
};
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const Ticker = (log: Log, index: number) => {
|
||||
const time = formatLogTime(log.created_at);
|
||||
|
@ -27,26 +65,19 @@ const Ticker = (log: Log, index: number) => {
|
|||
};
|
||||
|
||||
export let TickerList = (props: TickerListProps) => {
|
||||
const firstTicker: Log = props.logs.filter(
|
||||
log => !log.message.toLowerCase().includes("filtered"))[0];
|
||||
const noLogs: Log = {
|
||||
message: "No logs yet.", meta: { type: "debug" }, channels: [], created_at: NaN
|
||||
};
|
||||
return (
|
||||
<div
|
||||
className="ticker-list"
|
||||
onClick={props.toggle("tickerListOpen")} >
|
||||
<div className="first-ticker">
|
||||
{Ticker(firstTicker || noLogs, -1)}
|
||||
{Ticker(getfirstTickerLog(props.logs), -1)}
|
||||
</div>
|
||||
<Collapse isOpen={props.tickerListOpen}>
|
||||
{props
|
||||
.logs
|
||||
.filter((log, index) => index !== 0)
|
||||
.map((log: Log, index: number) => {
|
||||
const isFiltered = log.message.toLowerCase().includes("filtered");
|
||||
if (!isFiltered) { return Ticker(log, index); }
|
||||
})}
|
||||
.filter((log) => logFilter(log))
|
||||
.map((log: Log, index: number) => Ticker(log, index))}
|
||||
</Collapse>
|
||||
<Collapse isOpen={props.tickerListOpen}>
|
||||
<Link to={"/app/logs"}>
|
||||
|
|
|
@ -84,3 +84,15 @@ export function safeBooleanSettting(name: string): BooleanSetting {
|
|||
throw new Error(`Expected BooleanSetting but got '${name}'`);
|
||||
}
|
||||
}
|
||||
|
||||
const isNumericSetting =
|
||||
// tslint:disable-next-line:no-any
|
||||
(x: any): x is NumericSetting => !!NumericSetting[x];
|
||||
|
||||
export function safeNumericSetting(name: string): NumericSetting {
|
||||
if (isNumericSetting(name)) {
|
||||
return name;
|
||||
} else {
|
||||
throw new Error(`Expected NumericSetting but got '${name}'`);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -24,5 +24,12 @@ export enum BooleanSetting {
|
|||
|
||||
export enum NumericSetting {
|
||||
botOriginQuadrant = "botOriginQuadrant",
|
||||
zoomLevel = "zoomLevel"
|
||||
zoomLevel = "zoomLevel",
|
||||
successLog = "successLog",
|
||||
busyLog = "busyLog",
|
||||
warnLog = "warnLog",
|
||||
errorLog = "errorLog",
|
||||
infoLog = "infoLog",
|
||||
funLog = "funLog",
|
||||
debugLog = "debugLog"
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue