tools fixes and refactoring
parent
fa56cc137b
commit
f165cd19b0
|
@ -836,6 +836,7 @@ ul {
|
|||
}
|
||||
}
|
||||
|
||||
.tools-widget,
|
||||
.toolbay-widget {
|
||||
.fa-gear {
|
||||
color: $dark_gray;
|
||||
|
@ -844,6 +845,9 @@ ul {
|
|||
.del-button {
|
||||
margin-top: 0.5rem;
|
||||
}
|
||||
.fb-button {
|
||||
margin-left: 1rem;
|
||||
}
|
||||
}
|
||||
|
||||
.toolbay-slot-menu {
|
||||
|
|
|
@ -3,26 +3,26 @@ jest.mock("react-redux", () => ({
|
|||
}));
|
||||
|
||||
import * as React from "react";
|
||||
import { mount } from "enzyme";
|
||||
import { mount, shallow } from "enzyme";
|
||||
import { Tools } from "../index";
|
||||
import { Props } from "../interfaces";
|
||||
import { fakeToolSlot, fakeTool } from "../../__test_support__/fake_state/resources";
|
||||
import {
|
||||
fakeToolSlot, fakeTool
|
||||
} from "../../__test_support__/fake_state/resources";
|
||||
|
||||
describe("<Tools />", () => {
|
||||
function fakeProps(): Props {
|
||||
return {
|
||||
toolSlots: [],
|
||||
tools: [fakeTool()],
|
||||
getToolSlots: () => [fakeToolSlot()],
|
||||
getToolOptions: () => [],
|
||||
getChosenToolOption: () => { return { label: "None", value: "" }; },
|
||||
getToolByToolSlotUUID: () => fakeTool(),
|
||||
changeToolSlot: jest.fn(),
|
||||
isActive: () => true,
|
||||
dispatch: jest.fn(),
|
||||
botPosition: { x: undefined, y: undefined, z: undefined }
|
||||
};
|
||||
}
|
||||
const fakeProps = (): Props => ({
|
||||
toolSlots: [],
|
||||
tools: [fakeTool()],
|
||||
getToolSlots: () => [fakeToolSlot()],
|
||||
getToolOptions: () => [],
|
||||
getChosenToolOption: () => ({ label: "None", value: "" }),
|
||||
getToolByToolSlotUUID: fakeTool,
|
||||
changeToolSlot: jest.fn(),
|
||||
isActive: () => true,
|
||||
dispatch: jest.fn(),
|
||||
botPosition: { x: undefined, y: undefined, z: undefined }
|
||||
});
|
||||
|
||||
it("renders", () => {
|
||||
const wrapper = mount(<Tools {...fakeProps()} />);
|
||||
|
@ -36,4 +36,17 @@ describe("<Tools />", () => {
|
|||
"Fooactive"];
|
||||
strings.map(string => expect(txt).toContain(string));
|
||||
});
|
||||
|
||||
it("shows forms", () => {
|
||||
const wrapper = shallow(<Tools {...fakeProps()} />);
|
||||
expect(wrapper.find("ToolList").length).toEqual(1);
|
||||
expect(wrapper.find("ToolBayList").length).toEqual(1);
|
||||
expect(wrapper.find("ToolForm").length).toEqual(0);
|
||||
expect(wrapper.find("ToolBayForm").length).toEqual(0);
|
||||
wrapper.setState({ editingBays: true, editingTools: true });
|
||||
expect(wrapper.find("ToolList").length).toEqual(0);
|
||||
expect(wrapper.find("ToolBayList").length).toEqual(0);
|
||||
expect(wrapper.find("ToolForm").length).toEqual(1);
|
||||
expect(wrapper.find("ToolBayForm").length).toEqual(1);
|
||||
});
|
||||
});
|
||||
|
|
|
@ -0,0 +1,30 @@
|
|||
jest.mock("../../api/crud", () => ({ edit: jest.fn() }));
|
||||
|
||||
import { mapStateToProps } from "../state_to_props";
|
||||
import { fakeState } from "../../__test_support__/fake_state";
|
||||
import { NULL_CHOICE } from "../../ui";
|
||||
import { fakeToolSlot } from "../../__test_support__/fake_state/resources";
|
||||
import { edit } from "../../api/crud";
|
||||
|
||||
describe("mapStateToProps()", () => {
|
||||
it("getChosenToolOption()", () => {
|
||||
const props = mapStateToProps(fakeState());
|
||||
const result = props.getChosenToolOption(undefined);
|
||||
expect(result).toEqual(NULL_CHOICE);
|
||||
});
|
||||
|
||||
it("changeToolSlot(): no tool_id", () => {
|
||||
const props = mapStateToProps(fakeState());
|
||||
const tool = fakeToolSlot();
|
||||
props.changeToolSlot(tool, jest.fn())({ label: "", value: "" });
|
||||
// tslint:disable-next-line:no-null-keyword
|
||||
expect(edit).toHaveBeenCalledWith(tool, { tool_id: null });
|
||||
});
|
||||
|
||||
it("changeToolSlot(): tool_id", () => {
|
||||
const props = mapStateToProps(fakeState());
|
||||
const tool = fakeToolSlot();
|
||||
props.changeToolSlot(tool, jest.fn())({ label: "", value: 1 });
|
||||
expect(edit).toHaveBeenCalledWith(tool, { tool_id: 1 });
|
||||
});
|
||||
});
|
|
@ -1,12 +1,20 @@
|
|||
jest.mock("../../../api/crud", () => ({
|
||||
init: jest.fn(),
|
||||
saveAll: jest.fn(),
|
||||
destroy: jest.fn(),
|
||||
edit: jest.fn(),
|
||||
}));
|
||||
|
||||
import * as React from "react";
|
||||
import { ToolForm } from "../tool_form";
|
||||
import { mount } from "enzyme";
|
||||
import { mount, shallow } from "enzyme";
|
||||
import { fakeTool } from "../../../__test_support__/fake_state/resources";
|
||||
import { ToolFormProps } from "../../interfaces";
|
||||
import { ToolListAndFormProps } from "../../interfaces";
|
||||
import { clickButton } from "../../../__test_support__/helpers";
|
||||
import { init, saveAll, destroy, edit } from "../../../api/crud";
|
||||
|
||||
describe("<ToolForm/>", () => {
|
||||
function fakeProps(): ToolFormProps {
|
||||
function fakeProps(): ToolListAndFormProps {
|
||||
return {
|
||||
dispatch: jest.fn(),
|
||||
toggle: jest.fn(),
|
||||
|
@ -21,11 +29,34 @@ describe("<ToolForm/>", () => {
|
|||
expect(wrapper.find("input").length).toEqual(p.tools.length);
|
||||
});
|
||||
|
||||
it("saves tools", () => {
|
||||
const wrapper = mount(<ToolForm {...fakeProps()} />);
|
||||
clickButton(wrapper, 1, "saved", { partial_match: true });
|
||||
expect(saveAll).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
it("adds new tool", () => {
|
||||
const wrapper = mount(<ToolForm {...fakeProps()} />);
|
||||
expect(wrapper.props().tools.length).toEqual(2);
|
||||
clickButton(wrapper, 2, "");
|
||||
expect(init).toHaveBeenCalledWith(expect.objectContaining({
|
||||
body: { name: "Tool 3" }
|
||||
}));
|
||||
});
|
||||
|
||||
it("adds stock tools", () => {
|
||||
const p = fakeProps();
|
||||
const wrapper = mount(<ToolForm {...p} />);
|
||||
const wrapper = mount(<ToolForm {...fakeProps()} />);
|
||||
clickButton(wrapper, 3, "stock tools");
|
||||
expect(p.dispatch).toHaveBeenCalledTimes(6);
|
||||
expect(init).toHaveBeenCalledTimes(6);
|
||||
});
|
||||
|
||||
it("changes tool name", () => {
|
||||
const p = fakeProps();
|
||||
const wrapper = shallow(<ToolForm {...p} />);
|
||||
wrapper.find("BlurableInput").first().simulate("commit", {
|
||||
currentTarget: { value: "New Tool Name" }
|
||||
});
|
||||
expect(edit).toHaveBeenCalledWith(p.tools[0], { name: "New Tool Name" });
|
||||
});
|
||||
|
||||
it("has red delete button", () => {
|
||||
|
@ -36,6 +67,15 @@ describe("<ToolForm/>", () => {
|
|||
expect(delBtn.hasClass("red")).toBeTruthy();
|
||||
});
|
||||
|
||||
it("deletes tool", () => {
|
||||
const p = fakeProps();
|
||||
p.isActive = () => false;
|
||||
const wrapper = mount(<ToolForm {...p} />);
|
||||
const delBtn = wrapper.find("button").last();
|
||||
delBtn.simulate("click");
|
||||
expect(destroy).toHaveBeenCalledWith(p.tools[1].uuid);
|
||||
});
|
||||
|
||||
it("has gray delete button", () => {
|
||||
const p = fakeProps();
|
||||
p.isActive = () => true;
|
||||
|
|
|
@ -3,25 +3,22 @@ import { ToolList } from "../tool_list";
|
|||
import { mount } from "enzyme";
|
||||
import { mapStateToProps } from "../../state_to_props";
|
||||
import { fakeState } from "../../../__test_support__/fake_state";
|
||||
import { ToolListAndFormProps } from "../../interfaces";
|
||||
|
||||
describe("<ToolList />", () => {
|
||||
function bootstrapTest() {
|
||||
const state = fakeState();
|
||||
const toggle = jest.fn();
|
||||
const props = mapStateToProps(state);
|
||||
const fakeProps = (): ToolListAndFormProps => {
|
||||
const props = mapStateToProps(fakeState());
|
||||
return {
|
||||
state,
|
||||
toggle,
|
||||
props,
|
||||
component: mount(<ToolList dispatch={state.dispatch}
|
||||
tools={props.tools}
|
||||
toggle={toggle}
|
||||
isActive={props.isActive} />)
|
||||
dispatch: jest.fn(),
|
||||
tools: props.tools,
|
||||
toggle: jest.fn(),
|
||||
isActive: props.isActive,
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
it("renders tool names and statuses", () => {
|
||||
const test = bootstrapTest();
|
||||
expect(test.component.text()).toContain("Trench Digging Toolactive");
|
||||
expect(test.component.text()).toContain("Berry Picking Toolinactive");
|
||||
const wrapper = mount(<ToolList {...fakeProps()} />);
|
||||
expect(wrapper.text()).toContain("Trench Digging Toolactive");
|
||||
expect(wrapper.text()).toContain("Berry Picking Toolinactive");
|
||||
});
|
||||
});
|
||||
|
|
|
@ -0,0 +1,25 @@
|
|||
jest.mock("../../../api/crud", () => ({ destroy: jest.fn() }));
|
||||
|
||||
import * as React from "react";
|
||||
import { ToolSlotRowProps, ToolSlotRow } from "../tool_slot_row";
|
||||
import { mount } from "enzyme";
|
||||
import { destroy } from "../../../api/crud";
|
||||
import { fakeToolSlot } from "../../../__test_support__/fake_state/resources";
|
||||
|
||||
describe("<ToolSlotRow />", () => {
|
||||
const fakeProps = (): ToolSlotRowProps => ({
|
||||
dispatch: jest.fn(),
|
||||
slot: fakeToolSlot(),
|
||||
botPosition: { x: undefined, y: undefined, z: undefined },
|
||||
toolOptions: [],
|
||||
chosenToolOption: { label: "", value: "" },
|
||||
onToolSlotChange: jest.fn(),
|
||||
});
|
||||
|
||||
it("deletes slot", () => {
|
||||
const p = fakeProps();
|
||||
const wrapper = mount(<ToolSlotRow {...p} />);
|
||||
wrapper.find("button").last().simulate("click");
|
||||
expect(destroy).toHaveBeenCalledWith(p.slot.uuid);
|
||||
});
|
||||
});
|
|
@ -1,37 +1,50 @@
|
|||
jest.mock("../../../api/crud", () => ({
|
||||
init: jest.fn(),
|
||||
saveAll: jest.fn(),
|
||||
}));
|
||||
|
||||
import * as React from "react";
|
||||
import { ToolBayForm } from "../toolbay_form";
|
||||
import { mount } from "enzyme";
|
||||
import { mapStateToProps } from "../../state_to_props";
|
||||
import { fakeState } from "../../../__test_support__/fake_state";
|
||||
import { ToolBayFormProps } from "../../interfaces";
|
||||
import { clickButton } from "../../../__test_support__/helpers";
|
||||
import { saveAll, init } from "../../../api/crud";
|
||||
import { emptyToolSlot } from "../empty_tool_slot";
|
||||
|
||||
describe("<ToolBayForm/>", () => {
|
||||
function bootstrapTest() {
|
||||
const state = fakeState();
|
||||
const toggle = jest.fn();
|
||||
const props = mapStateToProps(state);
|
||||
const dispatch = jest.fn();
|
||||
const fakeProps = (): ToolBayFormProps => {
|
||||
const props = mapStateToProps(fakeState());
|
||||
return {
|
||||
state,
|
||||
toggle,
|
||||
props,
|
||||
dispatch,
|
||||
component: mount(<ToolBayForm
|
||||
toggle={toggle}
|
||||
dispatch={dispatch}
|
||||
toolSlots={props.toolSlots}
|
||||
getToolSlots={props.getToolSlots}
|
||||
getChosenToolOption={props.getChosenToolOption}
|
||||
getToolOptions={props.getToolOptions}
|
||||
changeToolSlot={props.changeToolSlot}
|
||||
botPosition={{ x: 1, y: 2, z: 3 }} />)
|
||||
toggle: jest.fn(),
|
||||
dispatch: jest.fn(),
|
||||
toolSlots: props.toolSlots,
|
||||
getToolSlots: props.getToolSlots,
|
||||
getChosenToolOption: props.getChosenToolOption,
|
||||
getToolOptions: props.getToolOptions,
|
||||
changeToolSlot: props.changeToolSlot,
|
||||
botPosition: { x: 1, y: 2, z: 3 },
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
it("renders ToolSlot", () => {
|
||||
const test = bootstrapTest();
|
||||
const inputs = test.component.find("input");
|
||||
const wrapper = mount(<ToolBayForm {...fakeProps()} />);
|
||||
const inputs = wrapper.find("input");
|
||||
expect(inputs.length).toEqual(3);
|
||||
expect(test.component.text()).toContain("Trench Digging Tool");
|
||||
expect(wrapper.text()).toContain("Trench Digging Tool");
|
||||
[0, 1, 2].map(i => expect(inputs.at(i).props().value).toEqual("10"));
|
||||
});
|
||||
|
||||
it("saves tool slots", () => {
|
||||
const wrapper = mount(<ToolBayForm {...fakeProps()} />);
|
||||
clickButton(wrapper, 1, "saved", { partial_match: true });
|
||||
expect(saveAll).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
it("adds new tool slot", () => {
|
||||
const wrapper = mount(<ToolBayForm {...fakeProps()} />);
|
||||
clickButton(wrapper, 2, "");
|
||||
expect(init).toHaveBeenCalledWith(emptyToolSlot());
|
||||
});
|
||||
});
|
||||
|
|
|
@ -3,24 +3,20 @@ import { ToolBayList } from "../toolbay_list";
|
|||
import { mount } from "enzyme";
|
||||
import { mapStateToProps } from "../../state_to_props";
|
||||
import { fakeState } from "../../../__test_support__/fake_state";
|
||||
import { ToolBayListProps } from "../../interfaces";
|
||||
|
||||
describe("<ToolBayList />", () => {
|
||||
function bootstrapTest() {
|
||||
const state = fakeState();
|
||||
const toggle = jest.fn();
|
||||
const props = mapStateToProps(state);
|
||||
const fakeProps = (): ToolBayListProps => {
|
||||
const props = mapStateToProps(fakeState());
|
||||
return {
|
||||
state,
|
||||
toggle,
|
||||
props,
|
||||
component: mount(<ToolBayList dispatch={state.dispatch}
|
||||
getToolByToolSlotUUID={props.getToolByToolSlotUUID}
|
||||
getToolSlots={props.getToolSlots}
|
||||
toggle={toggle} />)
|
||||
getToolByToolSlotUUID: props.getToolByToolSlotUUID,
|
||||
getToolSlots: props.getToolSlots,
|
||||
toggle: jest.fn(),
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
it("renders", () => {
|
||||
const test = bootstrapTest();
|
||||
expect(test.component.text()).toContain("1101010Trench Digging Tool");
|
||||
const wrapper = mount(<ToolBayList {...fakeProps()} />);
|
||||
expect(wrapper.text()).toContain("1101010Trench Digging Tool");
|
||||
});
|
||||
});
|
||||
|
|
|
@ -0,0 +1,25 @@
|
|||
jest.mock("../../../api/crud", () => ({ edit: jest.fn() }));
|
||||
|
||||
import * as React from "react";
|
||||
import { shallow } from "enzyme";
|
||||
import { ToolBayNumberCol, TBNumColProps } from "../toolbay_number_column";
|
||||
import { edit } from "../../../api/crud";
|
||||
import { fakeToolSlot } from "../../../__test_support__/fake_state/resources";
|
||||
|
||||
describe("<ToolBayNumberCol />", () => {
|
||||
const fakeProps = (): TBNumColProps => ({
|
||||
axis: "x",
|
||||
value: 0,
|
||||
dispatch: jest.fn(),
|
||||
slot: fakeToolSlot(),
|
||||
});
|
||||
|
||||
it("edits value", () => {
|
||||
const p = fakeProps();
|
||||
const wrapper = shallow(<ToolBayNumberCol {...p} />);
|
||||
wrapper.find("BlurableInput").simulate("commit", {
|
||||
currentTarget: { value: "1.23" }
|
||||
});
|
||||
expect(edit).toHaveBeenCalledWith(p.slot, { x: 1.23 });
|
||||
});
|
||||
});
|
|
@ -1,5 +1,5 @@
|
|||
import * as React from "react";
|
||||
import { ToolFormProps } from "../interfaces";
|
||||
import { ToolListAndFormProps } from "../interfaces";
|
||||
import { t } from "i18next";
|
||||
import {
|
||||
Row,
|
||||
|
@ -9,30 +9,25 @@ import {
|
|||
WidgetHeader,
|
||||
BlurableInput,
|
||||
SaveBtn
|
||||
} from "../../ui/index";
|
||||
} from "../../ui";
|
||||
import { getArrayStatus } from "../../resources/tagged_resources";
|
||||
import { edit, destroy, init, saveAll } from "../../api/crud";
|
||||
import { ToolTips } from "../../constants";
|
||||
import { TaggedTool, SpecialStatus } from "farmbot";
|
||||
|
||||
export class ToolForm extends React.Component<ToolFormProps, {}> {
|
||||
taggedTool = (name: string): TaggedTool => {
|
||||
return {
|
||||
uuid: "ERROR: GENERATED BY REDUCER - UUID SHOULD BE UNSEEN",
|
||||
specialStatus: SpecialStatus.SAVED,
|
||||
kind: "Tool",
|
||||
body: { name }
|
||||
};
|
||||
}
|
||||
export class ToolForm extends React.Component<ToolListAndFormProps, {}> {
|
||||
taggedTool = (name: string): TaggedTool => ({
|
||||
uuid: "ERROR: GENERATED BY REDUCER - UUID SHOULD BE UNSEEN",
|
||||
specialStatus: SpecialStatus.SAVED,
|
||||
kind: "Tool",
|
||||
body: { name }
|
||||
});
|
||||
|
||||
emptyTool = (): TaggedTool => {
|
||||
return this.taggedTool(t("Tool ") + (this.props.tools.length + 1));
|
||||
}
|
||||
emptyTool = (): TaggedTool =>
|
||||
this.taggedTool(t("Tool ") + (this.props.tools.length + 1))
|
||||
|
||||
stockTools = (dispatch: Function) => {
|
||||
const newTool = (name: string) => {
|
||||
dispatch(init(this.taggedTool(name)));
|
||||
};
|
||||
const newTool = (name: string) => dispatch(init(this.taggedTool(name)));
|
||||
|
||||
newTool(t("Seeder"));
|
||||
newTool(t("Watering Nozzle"));
|
||||
|
@ -42,34 +37,59 @@ export class ToolForm extends React.Component<ToolFormProps, {}> {
|
|||
newTool(t("Seed Tray"));
|
||||
}
|
||||
|
||||
render() {
|
||||
const toggle = () => this.props.toggle();
|
||||
const { dispatch, tools, isActive } = this.props;
|
||||
HeaderButtons = () => {
|
||||
const { dispatch, tools, toggle } = this.props;
|
||||
const specialStatus = getArrayStatus(tools);
|
||||
return <Widget>
|
||||
return <div>
|
||||
<button
|
||||
className="fb-button gray"
|
||||
onClick={toggle}
|
||||
disabled={!!specialStatus}>
|
||||
{t("Back")}
|
||||
</button>
|
||||
<SaveBtn
|
||||
status={specialStatus}
|
||||
onClick={() => dispatch(saveAll(tools, toggle))} />
|
||||
<button
|
||||
className="fb-button green"
|
||||
onClick={() => dispatch(init(this.emptyTool()))}>
|
||||
<i className="fa fa-plus" />
|
||||
</button>
|
||||
<button
|
||||
className="fb-button green"
|
||||
onClick={() => this.stockTools(dispatch)}>
|
||||
<i className="fa fa-plus" style={{ marginRight: "0.5rem" }} />
|
||||
{t("Stock Tools")}
|
||||
</button>
|
||||
</div>;
|
||||
}
|
||||
|
||||
ToolForm = (tool: TaggedTool, index: number) => {
|
||||
const { dispatch, isActive } = this.props;
|
||||
const inSlotClass = isActive(tool) ? "pseudo-disabled" : "";
|
||||
return <Row key={index}>
|
||||
<Col xs={10}>
|
||||
<BlurableInput
|
||||
id={(tool.body.id || "Error getting ID").toString()}
|
||||
value={tool.body.name || "Error getting Name"}
|
||||
onCommit={e =>
|
||||
dispatch(edit(tool, { name: e.currentTarget.value }))} />
|
||||
</Col>
|
||||
<Col xs={2}>
|
||||
<button
|
||||
className={`fb-button red ${inSlotClass} del-button`}
|
||||
title={isActive(tool) ? t("in slot") : ""}
|
||||
onClick={() => dispatch(destroy(tool.uuid))}>
|
||||
<i className="fa fa-times"></i>
|
||||
</button>
|
||||
</Col>
|
||||
</Row>;
|
||||
}
|
||||
|
||||
render() {
|
||||
return <Widget className="tools-widget">
|
||||
<WidgetHeader helpText={ToolTips.TOOL_LIST} title="Tools">
|
||||
<button
|
||||
className="fb-button gray"
|
||||
onClick={() => { toggle(); }}
|
||||
hidden={!!specialStatus}>
|
||||
{t("Back")}
|
||||
</button>
|
||||
<SaveBtn
|
||||
status={specialStatus}
|
||||
onClick={() => {
|
||||
dispatch(saveAll(tools, () => { toggle(); }));
|
||||
}} />
|
||||
<button
|
||||
className="fb-button green"
|
||||
onClick={() => { dispatch(init(this.emptyTool())); }}>
|
||||
<i className="fa fa-plus" />
|
||||
</button>
|
||||
<button
|
||||
className="fb-button green"
|
||||
onClick={() => { this.stockTools(dispatch); }}>
|
||||
<i className="fa fa-plus" style={{ marginRight: "0.5rem" }} />
|
||||
{t("Stock Tools")}
|
||||
</button>
|
||||
<this.HeaderButtons />
|
||||
</WidgetHeader>
|
||||
<WidgetBody>
|
||||
<Row>
|
||||
|
@ -77,27 +97,7 @@ export class ToolForm extends React.Component<ToolFormProps, {}> {
|
|||
<label>{t("Tool Name")}</label>
|
||||
</Col>
|
||||
</Row>
|
||||
{tools.map((tool: TaggedTool, index: number) => {
|
||||
const inSlotClass = isActive(tool) ? "pseudo-disabled" : "";
|
||||
return <Row key={index}>
|
||||
<Col xs={10}>
|
||||
<BlurableInput
|
||||
id={(tool.body.id || "Error getting ID").toString()}
|
||||
value={tool.body.name || "Error getting Name"}
|
||||
onCommit={(e) => {
|
||||
dispatch(edit(tool, { name: e.currentTarget.value }));
|
||||
}} />
|
||||
</Col>
|
||||
<Col xs={2}>
|
||||
<button
|
||||
className={`fb-button red ${inSlotClass}`}
|
||||
title={isActive(tool) ? t("in slot") : ""}
|
||||
onClick={() => { dispatch(destroy(tool.uuid)); }}>
|
||||
<i className="fa fa-times"></i>
|
||||
</button>
|
||||
</Col>
|
||||
</Row>;
|
||||
})}
|
||||
{this.props.tools.map(this.ToolForm)}
|
||||
</WidgetBody>
|
||||
</Widget>;
|
||||
}
|
||||
|
|
|
@ -1,14 +1,30 @@
|
|||
import * as React from "react";
|
||||
import { Row, Col, Widget, WidgetBody, WidgetHeader } from "../../ui/index";
|
||||
import { Row, Col, Widget, WidgetBody, WidgetHeader } from "../../ui";
|
||||
import { t } from "i18next";
|
||||
import { ToolListProps } from "../interfaces";
|
||||
import { ToolListAndFormProps } from "../interfaces";
|
||||
import { TaggedTool } from "farmbot";
|
||||
import { ToolTips } from "../../constants";
|
||||
|
||||
export class ToolList extends React.Component<ToolListProps, {}> {
|
||||
enum ColWidth {
|
||||
toolName = 8,
|
||||
status = 4,
|
||||
}
|
||||
|
||||
export class ToolList extends React.Component<ToolListAndFormProps, {}> {
|
||||
|
||||
ToolListItem = (tool: TaggedTool) => {
|
||||
return <Row key={tool.uuid}>
|
||||
<Col xs={ColWidth.toolName}>
|
||||
{tool.body.name || "Name not found"}
|
||||
</Col>
|
||||
<Col xs={ColWidth.status}>
|
||||
{this.props.isActive(tool) ? t("active") : t("inactive")}
|
||||
</Col>
|
||||
</Row>;
|
||||
}
|
||||
|
||||
render() {
|
||||
const toggle = () => this.props.toggle();
|
||||
const { tools } = this.props;
|
||||
const { tools, toggle } = this.props;
|
||||
|
||||
return <Widget>
|
||||
<WidgetHeader helpText={ToolTips.TOOL_LIST} title={t("Tools")}>
|
||||
|
@ -20,23 +36,14 @@ export class ToolList extends React.Component<ToolListProps, {}> {
|
|||
</WidgetHeader>
|
||||
<WidgetBody>
|
||||
<Row>
|
||||
<Col xs={8}>
|
||||
<Col xs={ColWidth.toolName}>
|
||||
<label>{t("Tool Name")}</label>
|
||||
</Col>
|
||||
<Col xs={4}>
|
||||
<Col xs={ColWidth.status}>
|
||||
<label>{t("Status")}</label>
|
||||
</Col>
|
||||
</Row>
|
||||
{tools.map((tool: TaggedTool) => {
|
||||
return <Row key={tool.uuid}>
|
||||
<Col xs={8}>
|
||||
{tool.body.name || "Name not found"}
|
||||
</Col>
|
||||
<Col xs={4}>
|
||||
{this.props.isActive(tool) ? t("active") : t("inactive")}
|
||||
</Col>
|
||||
</Row>;
|
||||
})}
|
||||
{tools.map(this.ToolListItem)}
|
||||
</WidgetBody>
|
||||
</Widget>;
|
||||
}
|
||||
|
|
|
@ -7,7 +7,7 @@ import { destroy } from "../../api/crud";
|
|||
import { Xyz } from "../../devices/interfaces";
|
||||
import { ToolBayNumberCol } from "./toolbay_number_column";
|
||||
|
||||
interface ToolSlotRowProps {
|
||||
export interface ToolSlotRowProps {
|
||||
dispatch: Function;
|
||||
slot: TaggedToolSlotPointer;
|
||||
botPosition: Record<"x" | "y" | "z", number | undefined>;
|
||||
|
@ -22,7 +22,7 @@ interface ToolSlotRowProps {
|
|||
type Axis = Xyz & keyof (TaggedToolSlotPointer["body"]);
|
||||
const axes: Axis[] = ["x", "y", "z"];
|
||||
|
||||
export function ToolSlotRow(p: ToolSlotRowProps) {
|
||||
export function ToolSlotRow(props: ToolSlotRowProps) {
|
||||
const {
|
||||
dispatch,
|
||||
slot,
|
||||
|
@ -30,7 +30,7 @@ export function ToolSlotRow(p: ToolSlotRowProps) {
|
|||
toolOptions,
|
||||
onToolSlotChange,
|
||||
chosenToolOption
|
||||
} = p;
|
||||
} = props;
|
||||
|
||||
return <Row>
|
||||
<Col xs={1}>
|
||||
|
@ -42,12 +42,10 @@ export function ToolSlotRow(p: ToolSlotRowProps) {
|
|||
botPosition={botPosition} />
|
||||
</Popover>
|
||||
</Col>
|
||||
{
|
||||
axes
|
||||
.map(axis => ({ axis, dispatch, slot, value: (slot.body[axis] || 0) }))
|
||||
.map((props) =>
|
||||
<ToolBayNumberCol key={slot.uuid + props.axis} {...props} />)
|
||||
}
|
||||
{axes
|
||||
.map(axis => ({ axis, dispatch, slot, value: (slot.body[axis] || 0) }))
|
||||
.map(axisProps =>
|
||||
<ToolBayNumberCol key={slot.uuid + axisProps.axis} {...axisProps} />)}
|
||||
<Col xs={4}>
|
||||
<FBSelect
|
||||
list={toolOptions}
|
||||
|
|
|
@ -5,7 +5,7 @@ import {
|
|||
WidgetBody,
|
||||
WidgetHeader,
|
||||
SaveBtn,
|
||||
} from "../../ui/index";
|
||||
} from "../../ui";
|
||||
import { t } from "i18next";
|
||||
import {
|
||||
getArrayStatus
|
||||
|
@ -19,42 +19,48 @@ import { TaggedToolSlotPointer } from "farmbot";
|
|||
|
||||
export class ToolBayForm extends React.Component<ToolBayFormProps, {}> {
|
||||
|
||||
render() {
|
||||
const { toggle, dispatch, toolSlots, botPosition } = this.props;
|
||||
HeaderButtons = () => {
|
||||
const { toggle, dispatch, toolSlots } = this.props;
|
||||
const toolSlotStatus = getArrayStatus(toolSlots);
|
||||
return <div>
|
||||
<button
|
||||
className="gray fb-button"
|
||||
disabled={!!toolSlotStatus}
|
||||
onClick={toggle}>
|
||||
{t("Back")}
|
||||
</button>
|
||||
<SaveBtn
|
||||
status={toolSlotStatus}
|
||||
onClick={() => dispatch(saveAll(toolSlots, toggle))} />
|
||||
<button
|
||||
className="green fb-button"
|
||||
onClick={() => dispatch(init(emptyToolSlot()))}>
|
||||
<i className="fa fa-plus" />
|
||||
</button>
|
||||
</div>;
|
||||
}
|
||||
|
||||
ToolbayForm = (slot: TaggedToolSlotPointer) => {
|
||||
const { dispatch, botPosition } = this.props;
|
||||
return <ToolSlotRow
|
||||
key={slot.uuid}
|
||||
dispatch={dispatch}
|
||||
slot={slot}
|
||||
botPosition={botPosition}
|
||||
toolOptions={this.props.getToolOptions()}
|
||||
onToolSlotChange={this.props.changeToolSlot(slot, this.props.dispatch)}
|
||||
chosenToolOption={this.props.getChosenToolOption(slot.uuid)} />;
|
||||
}
|
||||
|
||||
render() {
|
||||
return <div className={"toolbay-widget"}>
|
||||
<Widget>
|
||||
<WidgetHeader helpText={ToolTips.TOOLBAY_LIST} title={t("Tool Slots")}>
|
||||
<button
|
||||
className="gray fb-button"
|
||||
hidden={!!toolSlotStatus}
|
||||
onClick={() => { toggle(); }}>
|
||||
{t("Back")}
|
||||
</button>
|
||||
<SaveBtn
|
||||
status={toolSlotStatus}
|
||||
onClick={() => {
|
||||
dispatch(saveAll(toolSlots, () => { toggle(); }));
|
||||
}} />
|
||||
<button
|
||||
className="green fb-button"
|
||||
onClick={() => { dispatch(init(emptyToolSlot())); }}>
|
||||
<i className="fa fa-plus" />
|
||||
</button>
|
||||
<this.HeaderButtons />
|
||||
</WidgetHeader>
|
||||
<WidgetBody>
|
||||
<ToolBayHeader />
|
||||
{this.props.getToolSlots().map(
|
||||
(slot: TaggedToolSlotPointer) => {
|
||||
return <ToolSlotRow
|
||||
key={slot.uuid}
|
||||
dispatch={dispatch}
|
||||
slot={slot}
|
||||
botPosition={botPosition}
|
||||
toolOptions={this.props.getToolOptions()}
|
||||
onToolSlotChange={this.props.changeToolSlot(slot, this.props.dispatch)}
|
||||
chosenToolOption={this.props.getChosenToolOption(slot.uuid)} />;
|
||||
})}
|
||||
{this.props.getToolSlots().map(this.ToolbayForm)}
|
||||
</WidgetBody>
|
||||
</Widget>
|
||||
</div>;
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
import * as React from "react";
|
||||
import { Col, Row } from "../../ui/index";
|
||||
import { Col, Row } from "../../ui";
|
||||
import { t } from "i18next";
|
||||
|
||||
export function ToolBayHeader(_: {}) {
|
||||
export function ToolBayHeader() {
|
||||
return <Row>
|
||||
<Col xs={1}>
|
||||
<label>{t("Slot")}</label>
|
||||
|
|
|
@ -1,41 +1,40 @@
|
|||
import * as React from "react";
|
||||
import { t } from "i18next";
|
||||
import { Row, Col, Widget, WidgetBody, WidgetHeader } from "../../ui/index";
|
||||
import { Row, Col, Widget, WidgetBody, WidgetHeader } from "../../ui";
|
||||
import { ToolBayListProps } from "../interfaces";
|
||||
import { TaggedToolSlotPointer } from "farmbot";
|
||||
import { ToolBayHeader } from "./toolbay_header";
|
||||
import { ToolTips } from "../../constants";
|
||||
|
||||
export class ToolBayList extends React.Component<ToolBayListProps, {}> {
|
||||
render() {
|
||||
const toggle = () => this.props.toggle();
|
||||
const { getToolSlots, getToolByToolSlotUUID } = this.props;
|
||||
|
||||
ToolSlotListItem = (slot: TaggedToolSlotPointer, index: number) => {
|
||||
const { getToolByToolSlotUUID } = this.props;
|
||||
const tool = getToolByToolSlotUUID(slot.uuid);
|
||||
const name = (tool && tool.body.name) || t("None");
|
||||
return <Row key={slot.uuid}>
|
||||
<Col xs={1}><label>{index + 1}</label></Col>
|
||||
<Col xs={2}>{slot.body.x}</Col>
|
||||
<Col xs={2}>{slot.body.y}</Col>
|
||||
<Col xs={2}>{slot.body.z}</Col>
|
||||
<Col xs={4}>{name}</Col>
|
||||
</Row>;
|
||||
}
|
||||
|
||||
render() {
|
||||
return <Widget>
|
||||
<WidgetHeader helpText={ToolTips.TOOLBAY_LIST} title={t("ToolBay ") + "1"}>
|
||||
<WidgetHeader
|
||||
helpText={ToolTips.TOOLBAY_LIST}
|
||||
title={t("ToolBay ") + "1"}>
|
||||
<button
|
||||
className="gray fb-button"
|
||||
onClick={toggle}>
|
||||
onClick={this.props.toggle}>
|
||||
{t("Edit")}
|
||||
</button>
|
||||
</WidgetHeader>
|
||||
<WidgetBody>
|
||||
<ToolBayHeader />
|
||||
{getToolSlots().map((slot: TaggedToolSlotPointer, index: number) => {
|
||||
const tool = getToolByToolSlotUUID(slot.uuid);
|
||||
const name = (tool && tool.body.name) || t("None");
|
||||
return <Row key={slot.uuid}>
|
||||
<Col xs={1}>
|
||||
<label>{index + 1}</label>
|
||||
</Col>
|
||||
<Col xs={2}>{slot.body.x}</Col>
|
||||
<Col xs={2}>{slot.body.y}</Col>
|
||||
<Col xs={2}>{slot.body.z}</Col>
|
||||
<Col xs={4}>
|
||||
{name}
|
||||
</Col>
|
||||
</Row>;
|
||||
})}
|
||||
{this.props.getToolSlots().map(this.ToolSlotListItem)}
|
||||
</WidgetBody>
|
||||
</Widget>;
|
||||
}
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
import * as React from "react";
|
||||
import { TaggedToolSlotPointer } from "farmbot";
|
||||
import { Col, BlurableInput } from "../../ui/index";
|
||||
import { Col, BlurableInput } from "../../ui";
|
||||
import { edit } from "../../api/crud";
|
||||
|
||||
interface NumColProps {
|
||||
export interface TBNumColProps {
|
||||
axis: "x" | "y" | "z";
|
||||
value: number;
|
||||
dispatch: Function;
|
||||
|
@ -11,13 +11,13 @@ interface NumColProps {
|
|||
}
|
||||
|
||||
/** Used to display and edit the X/Y/Z numeric values in the tool bay form. */
|
||||
export function ToolBayNumberCol({ axis, value, dispatch, slot }: NumColProps) {
|
||||
export function ToolBayNumberCol(props: TBNumColProps) {
|
||||
const { axis, value, dispatch, slot } = props;
|
||||
return <Col xs={2}>
|
||||
<BlurableInput
|
||||
value={value.toString()}
|
||||
onCommit={(e) => {
|
||||
dispatch(edit(slot, { [axis]: parseFloat(e.currentTarget.value) }));
|
||||
}}
|
||||
onCommit={e =>
|
||||
dispatch(edit(slot, { [axis]: parseFloat(e.currentTarget.value) }))}
|
||||
type="number" />
|
||||
</Col>;
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import * as React from "react";
|
||||
import { t } from "i18next";
|
||||
import { FBSelect, DropDownItem } from "../../ui/index";
|
||||
import { FBSelect, DropDownItem } from "../../ui";
|
||||
import { TaggedToolSlotPointer } from "farmbot";
|
||||
import { edit } from "../../api/crud";
|
||||
import { isNumber } from "lodash";
|
||||
|
|
|
@ -7,9 +7,8 @@ import { edit } from "../../api/crud";
|
|||
import { SlotDirectionSelect } from "./toolbay_slot_direction_selection";
|
||||
import { ToolPulloutDirection } from "farmbot/dist/resources/api_resources";
|
||||
|
||||
const positionIsDefined = (position: BotPosition): boolean => {
|
||||
return isNumber(position.x) && isNumber(position.y) && isNumber(position.z);
|
||||
};
|
||||
const positionIsDefined = (position: BotPosition): boolean =>
|
||||
isNumber(position.x) && isNumber(position.y) && isNumber(position.z);
|
||||
|
||||
const useCurrentPosition = (
|
||||
dispatch: Function, slot: TaggedToolSlotPointer, position: BotPosition) => {
|
||||
|
@ -18,21 +17,16 @@ const useCurrentPosition = (
|
|||
}
|
||||
};
|
||||
|
||||
const positionButtonTitle = (position: BotPosition): string => {
|
||||
if (positionIsDefined(position)) {
|
||||
return `(${position.x}, ${position.y}, ${position.z})`;
|
||||
} else {
|
||||
return t("(unknown)");
|
||||
}
|
||||
};
|
||||
const positionButtonTitle = (position: BotPosition): string =>
|
||||
positionIsDefined(position)
|
||||
? `(${position.x}, ${position.y}, ${position.z})`
|
||||
: t("(unknown)");
|
||||
|
||||
const changePulloutDirection =
|
||||
(dispatch: Function, slot: TaggedToolSlotPointer) => () => {
|
||||
const newDirection = (
|
||||
old: ToolPulloutDirection | undefined): ToolPulloutDirection => {
|
||||
if (isNumber(old) && old < 4) { return old + 1; }
|
||||
return ToolPulloutDirection.NONE;
|
||||
};
|
||||
const newDirection =
|
||||
(old: ToolPulloutDirection | undefined): ToolPulloutDirection =>
|
||||
isNumber(old) && old < 4 ? old + 1 : ToolPulloutDirection.NONE;
|
||||
dispatch(edit(slot,
|
||||
{ pullout_direction: newDirection(slot.body.pullout_direction) }));
|
||||
};
|
||||
|
@ -61,29 +55,22 @@ export const SlotMenu = (props: SlotMenuProps) => {
|
|||
<label>
|
||||
{t("Change slot direction")}
|
||||
</label>
|
||||
<i className={"direction-icon " +
|
||||
directionIconClass(pullout_direction)}
|
||||
onClick={
|
||||
changePulloutDirection(dispatch, slot)} />
|
||||
<i className={"direction-icon " + directionIconClass(pullout_direction)}
|
||||
onClick={changePulloutDirection(dispatch, slot)} />
|
||||
<SlotDirectionSelect
|
||||
key={pullout_direction}
|
||||
dispatch={dispatch}
|
||||
slot={slot} />
|
||||
</fieldset>
|
||||
<fieldset>
|
||||
<label>
|
||||
{t("Use current location")}
|
||||
</label>
|
||||
<label>{t("Use current location")}</label>
|
||||
<button
|
||||
className="blue fb-button"
|
||||
title={positionButtonTitle(botPosition)}
|
||||
onClick={() =>
|
||||
useCurrentPosition(dispatch, slot, botPosition)}>
|
||||
onClick={() => useCurrentPosition(dispatch, slot, botPosition)}>
|
||||
<i className="fa fa-crosshairs" />
|
||||
</button>
|
||||
<p>
|
||||
{positionButtonTitle(botPosition)}
|
||||
</p>
|
||||
<p>{positionButtonTitle(botPosition)}</p>
|
||||
</fieldset>
|
||||
</div>;
|
||||
};
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import * as React from "react";
|
||||
import { connect } from "react-redux";
|
||||
import { ToolsState, Props } from "./interfaces";
|
||||
import { Col, Row, Page } from "../ui/index";
|
||||
import { Col, Row, Page } from "../ui";
|
||||
import { ToolBayList, ToolBayForm, ToolList, ToolForm } from "./components";
|
||||
import { mapStateToProps } from "./state_to_props";
|
||||
|
||||
|
@ -13,19 +13,11 @@ export class Tools extends React.Component<Props, Partial<ToolsState>> {
|
|||
() => this.setState({ [name]: !this.state[name] });
|
||||
|
||||
render() {
|
||||
const isEditingBays = this.state.editingBays;
|
||||
const isEditingTools = this.state.editingTools;
|
||||
return <Page className="tools">
|
||||
<Row>
|
||||
<Col sm={7}>
|
||||
{!isEditingBays &&
|
||||
<ToolBayList
|
||||
toggle={this.toggle("editingBays")}
|
||||
dispatch={this.props.dispatch}
|
||||
getToolByToolSlotUUID={this.props.getToolByToolSlotUUID}
|
||||
getToolSlots={this.props.getToolSlots} />}
|
||||
{isEditingBays &&
|
||||
<ToolBayForm
|
||||
{this.state.editingBays
|
||||
? <ToolBayForm
|
||||
toggle={this.toggle("editingBays")}
|
||||
dispatch={this.props.dispatch}
|
||||
botPosition={this.props.botPosition}
|
||||
|
@ -33,17 +25,20 @@ export class Tools extends React.Component<Props, Partial<ToolsState>> {
|
|||
getToolSlots={this.props.getToolSlots}
|
||||
getChosenToolOption={this.props.getChosenToolOption}
|
||||
getToolOptions={this.props.getToolOptions}
|
||||
changeToolSlot={this.props.changeToolSlot} />}
|
||||
changeToolSlot={this.props.changeToolSlot} />
|
||||
: <ToolBayList
|
||||
toggle={this.toggle("editingBays")}
|
||||
getToolByToolSlotUUID={this.props.getToolByToolSlotUUID}
|
||||
getToolSlots={this.props.getToolSlots} />}
|
||||
</Col>
|
||||
<Col sm={5}>
|
||||
{!isEditingTools &&
|
||||
<ToolList
|
||||
{this.state.editingTools
|
||||
? <ToolForm
|
||||
isActive={this.props.isActive}
|
||||
toggle={this.toggle("editingTools")}
|
||||
dispatch={this.props.dispatch}
|
||||
tools={this.props.tools} />}
|
||||
{isEditingTools &&
|
||||
<ToolForm
|
||||
tools={this.props.tools} />
|
||||
: <ToolList
|
||||
isActive={this.props.isActive}
|
||||
toggle={this.toggle("editingTools")}
|
||||
dispatch={this.props.dispatch}
|
||||
|
|
|
@ -14,7 +14,7 @@ export interface Props {
|
|||
toolSlots: TaggedToolSlotPointer[];
|
||||
tools: TaggedTool[];
|
||||
getToolOptions(): DropDownItem[];
|
||||
getChosenToolOption(toolSlotUuid: string): DropDownItem;
|
||||
getChosenToolOption(toolSlotUuid: string | undefined): DropDownItem;
|
||||
getToolByToolSlotUUID(uuid: string): TaggedTool | undefined;
|
||||
getToolSlots(): TaggedToolSlotPointer[];
|
||||
dispatch: Function;
|
||||
|
@ -30,7 +30,6 @@ export interface Tool {
|
|||
}
|
||||
|
||||
export interface ToolBayListProps {
|
||||
dispatch: Function;
|
||||
toggle(): void;
|
||||
getToolByToolSlotUUID(uuid: string): TaggedTool | undefined;
|
||||
getToolSlots(): TaggedToolSlotPointer[];
|
||||
|
@ -42,19 +41,12 @@ export interface ToolBayFormProps {
|
|||
botPosition: BotPosition;
|
||||
toggle(): void;
|
||||
getToolOptions(): DropDownItem[];
|
||||
getChosenToolOption(uuid: string): DropDownItem;
|
||||
getChosenToolOption(uuid: string | undefined): DropDownItem;
|
||||
getToolSlots(): TaggedToolSlotPointer[];
|
||||
changeToolSlot(t: TaggedToolSlotPointer, dispatch: Function): (d: DropDownItem) => void;
|
||||
}
|
||||
|
||||
export interface ToolListProps {
|
||||
tools: TaggedTool[];
|
||||
dispatch: Function;
|
||||
toggle(): void;
|
||||
isActive(tool: TaggedTool): boolean;
|
||||
}
|
||||
|
||||
export interface ToolFormProps {
|
||||
export interface ToolListAndFormProps {
|
||||
dispatch: Function;
|
||||
tools: TaggedTool[];
|
||||
toggle(): void;
|
||||
|
|
|
@ -10,7 +10,7 @@ import {
|
|||
isTaggedTool,
|
||||
} from "../resources/tagged_resources";
|
||||
import { edit } from "../api/crud";
|
||||
import { DropDownItem, NULL_CHOICE } from "../ui/index";
|
||||
import { DropDownItem, NULL_CHOICE } from "../ui";
|
||||
import { validBotLocationData } from "../util";
|
||||
import { TaggedTool, TaggedToolSlotPointer } from "farmbot";
|
||||
|
||||
|
@ -44,11 +44,9 @@ export function mapStateToProps(props: Everything): Props {
|
|||
* and in an <FBSelect /> compatible format. */
|
||||
const getChosenToolOption = (toolSlotUUID: string | undefined) => {
|
||||
const chosenTool = toolSlotUUID && getToolByToolSlotUUID(toolSlotUUID);
|
||||
if (chosenTool && isTaggedTool(chosenTool) && chosenTool.body.id) {
|
||||
return { label: chosenTool.body.name || "untitled", value: chosenTool.uuid };
|
||||
} else {
|
||||
return NULL_CHOICE;
|
||||
}
|
||||
return (chosenTool && isTaggedTool(chosenTool) && chosenTool.body.id)
|
||||
? { label: chosenTool.body.name || "untitled", value: chosenTool.uuid }
|
||||
: NULL_CHOICE;
|
||||
};
|
||||
|
||||
const changeToolSlot = (t: TaggedToolSlotPointer,
|
||||
|
@ -62,6 +60,9 @@ export function mapStateToProps(props: Everything): Props {
|
|||
dispatch(edit(t, { tool_id }));
|
||||
};
|
||||
|
||||
const botPosition =
|
||||
validBotLocationData(props.bot.hardware.location_data).position;
|
||||
|
||||
return {
|
||||
toolSlots,
|
||||
tools,
|
||||
|
@ -72,7 +73,7 @@ export function mapStateToProps(props: Everything): Props {
|
|||
changeToolSlot,
|
||||
isActive,
|
||||
dispatch: _.noop,
|
||||
botPosition: validBotLocationData(props.bot.hardware.location_data).position
|
||||
botPosition,
|
||||
};
|
||||
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue