add sequence log settings

pull/550/head
gabrielburnworth 2017-12-01 20:47:57 -08:00
parent 7c91e51bc6
commit d6993516e4
6 changed files with 133 additions and 18 deletions

View File

@ -251,6 +251,15 @@ export namespace ToolTips {
// Logs
export const LOGS =
`View and filter log messages.`;
export const SEQUENCE_LOG_BEGIN =
`Send a log message upon the start of sequence execution.`;
export const SEQUENCE_LOG_STEP =
`Send a log message for each sequence step.`;
export const SEQUENCE_LOG_END =
`Send a log message upon the end of sequence execution.`;
}
export namespace Content {

View File

@ -509,6 +509,25 @@ ul {
margin-right: 0;
}
}
.settings-menu-button {
float: right;
margin-left: 1rem;
margin-top: 0.25rem;
}
}
.logs-settings-menu {
label {
margin-top: 7px;
}
.saucer {
float: left;
margin-right: 10px;
}
.pt-popover-target {
display: inline;
margin-left: 1rem;
}
}
.logs-table {

View File

@ -1,14 +1,23 @@
const mockDevice = {
updateConfig: jest.fn(() => { return Promise.resolve(); }),
};
jest.mock("../../device", () => ({
getDevice: () => (mockDevice)
}));
jest.mock("react-redux", () => ({
connect: jest.fn()
}));
import * as React from "react";
import { mount } from "enzyme";
import { Logs, LogsFilterMenu } from "../index";
import { Logs, LogsFilterMenu, LogsSettingsMenu } from "../index";
import { ToolTips } from "../../constants";
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 { ConfigurationName } from "farmbot";
describe("<Logs />", () => {
function fakeLogs(): TaggedLog[] {
@ -41,7 +50,7 @@ describe("<Logs />", () => {
}
it("renders", () => {
const wrapper = mount(<Logs logs={fakeLogs()} />);
const wrapper = mount(<Logs logs={fakeLogs()} bot={bot} />);
["Logs", ToolTips.LOGS, "Type", "Message", "Time", "Info",
"Fake log message 1", "Success", "Fake log message 2"]
.map(string =>
@ -52,7 +61,7 @@ describe("<Logs />", () => {
});
it("filters logs", () => {
const wrapper = mount(<Logs logs={fakeLogs()} />);
const wrapper = mount(<Logs logs={fakeLogs()} bot={bot} />);
wrapper.setState({ info: false });
expect(wrapper.text()).not.toContain("Fake log message 1");
const filterBtn = wrapper.find("button").first();
@ -66,7 +75,7 @@ describe("<Logs />", () => {
logs[1].body.meta.x = 0;
logs[1].body.meta.y = 1;
logs[1].body.meta.z = 2;
const wrapper = mount(<Logs logs={logs} />);
const wrapper = mount(<Logs logs={logs} bot={bot} />);
expect(wrapper.text()).toContain("Unknown");
expect(wrapper.text()).toContain("0, 1, 2");
});
@ -94,3 +103,24 @@ describe("<LogsFilterMenu />", () => {
expect(toggle).toHaveBeenCalledWith("success");
});
});
describe("<LogsSettingsMenu />", () => {
it("renders", () => {
const wrapper = mount(<LogsSettingsMenu {...bot} />);
["begin", "steps", "complete"].map(string =>
expect(wrapper.text().toLowerCase()).toContain(string));
});
function testSettingToggle(setting: ConfigurationName, position: number) {
it("toggles setting", () => {
bot.hardware.configuration[setting] = false;
const wrapper = mount(<LogsSettingsMenu {...bot} />);
wrapper.find("button").at(position).simulate("click");
expect(mockDevice.updateConfig)
.toHaveBeenCalledWith({ [setting]: true });
});
}
testSettingToggle("sequence_init_log", 0);
testSettingToggle("sequence_body_log", 1);
testSettingToggle("sequence_complete_log", 2);
});

View File

@ -1,14 +1,20 @@
import * as React from "react";
import * as moment from "moment";
import { connect } from "react-redux";
import { Col, Row, Page, ToolTip } from "../ui";
import { Col, Row, Page, ToolTip, Help } from "../ui";
import { mapStateToProps } from "./state_to_props";
import { t } from "i18next";
import { Popover, Position } from "@blueprintjs/core";
import * as _ from "lodash";
import { LogsTableProps, LogsState, LogsFilterMenuProps, LogsProps } from "./interfaces";
import {
LogsTableProps, LogsState, LogsFilterMenuProps, LogsProps
} from "./interfaces";
import { ToolTips } from "../constants";
import { TaggedLog } from "../resources/tagged_resources";
import { ToggleButton } from "../controls/toggle_button";
import { noop } from "lodash";
import { updateConfig } from "../devices/actions";
import { BotState } from "../devices/interfaces";
export const formatLogTime = (created_at: number) =>
moment.unix(created_at).local().format("MMM D, h:mma");
@ -63,14 +69,13 @@ const LogsRow = (tlog: TaggedLog, state: LogsState) => {
export const LogsFilterMenu = (props: LogsFilterMenuProps) => {
const btnColor = (x: keyof LogsState) => props.state[x] ? "green" : "red";
return <div>
return <div className={"logs-settings-menu"}>
{Object.keys(props.state)
.filter(x => { if (!(x == "autoscroll")) { return x; } })
.map((logType: keyof LogsState) => {
return <fieldset key={logType}>
<label style={{ marginTop: "7px" }}>
<div className={`saucer ${logType}`}
style={{ float: "left", marginRight: "10px" }} />
<label>
<div className={`saucer ${logType}`} />
{_.startCase(logType)}
</label>
<button
@ -81,6 +86,47 @@ export const LogsFilterMenu = (props: LogsFilterMenuProps) => {
</div>;
};
export const LogsSettingsMenu = (bot: BotState) => {
const {
sequence_init_log, sequence_body_log, sequence_complete_log
} = bot.hardware.configuration;
return <div className={"logs-settings-menu"}>
{t("Create logs for sequence:")}
<fieldset>
<label>
{t("Begin")}
</label>
<Help text={t(ToolTips.SEQUENCE_LOG_BEGIN)} />
<ToggleButton toggleValue={sequence_init_log}
toggleAction={() => {
updateConfig({ sequence_init_log: !sequence_init_log })(noop);
}} />
</fieldset>
<fieldset>
<label>
{t("Steps")}
</label>
<Help text={t(ToolTips.SEQUENCE_LOG_STEP)} />
<ToggleButton toggleValue={sequence_body_log}
toggleAction={() => {
updateConfig({ sequence_body_log: !sequence_body_log })(noop);
}} />
</fieldset>
<fieldset>
<label>
{t("Complete")}
</label>
<Help text={t(ToolTips.SEQUENCE_LOG_END)} />
<ToggleButton toggleValue={sequence_complete_log}
toggleAction={() => {
updateConfig({
sequence_complete_log: !sequence_complete_log
})(noop);
}} />
</fieldset>
</div>;
};
@connect(mapStateToProps)
export class Logs extends React.Component<LogsProps, Partial<LogsState>> {
@ -117,12 +163,20 @@ export class Logs extends React.Component<LogsProps, Partial<LogsState>> {
<ToolTip helpText={ToolTips.LOGS} />
</Col>
<Col xs={1}>
<Popover position={Position.BOTTOM_RIGHT}>
<button className={`fb-button ${filterBtnColor}`}>
{this.filterActive ? t("Filters active") : t("filter")}
</button>
<LogsFilterMenu toggle={this.toggle} state={this.state} />
</Popover>
<div className={"settings-menu-button"}>
<Popover position={Position.BOTTOM_RIGHT}>
<i className="fa fa-gear" />
<LogsSettingsMenu {...this.props.bot} />
</Popover>
</div>
<div className={"settings-menu-button"}>
<Popover position={Position.BOTTOM_RIGHT}>
<button className={`fb-button ${filterBtnColor}`}>
{this.filterActive ? t("Filters active") : t("filter")}
</button>
<LogsFilterMenu toggle={this.toggle} state={this.state} />
</Popover>
</div>
</Col>
</Row>
<Row>

View File

@ -1,7 +1,9 @@
import { TaggedLog } from "../resources/tagged_resources";
import { BotState } from "../devices/interfaces";
export interface LogsProps {
logs: TaggedLog[]
logs: TaggedLog[];
bot: BotState;
}
export interface Filters {

View File

@ -9,7 +9,8 @@ export function mapStateToProps(props: Everything): LogsProps {
logs: _(selectAllLogs(props.resources.index))
.sortBy("body.created_at")
.reverse()
.value()
.value(),
bot: props.bot
};
}