tools panel updates

pull/1730/head
gabrielburnworth 2020-03-13 14:09:46 -07:00
parent b1c2b36a37
commit ec878e0dae
21 changed files with 263 additions and 190 deletions

View File

@ -640,6 +640,9 @@
.add-tool-panel-content,
.edit-tool-panel-content {
max-height: calc(100vh - 14rem);
overflow-y: auto;
overflow-x: hidden;
button {
display: block;
margin-left: auto;
@ -687,6 +690,7 @@
}
}
button {
margin-bottom: 2rem;
.fa-plus {
margin-right: 0.5rem;
}

View File

@ -26,9 +26,6 @@ const NO_TMC = ["arduino", "farmduino", "farmduino_k14"];
export const isTMCBoard = (firmwareHardware: FirmwareHardware | undefined) =>
!firmwareHardware || !NO_TMC.includes(firmwareHardware);
export const isExpressBoard = (firmwareHardware: FirmwareHardware | undefined) =>
!!(firmwareHardware && EXPRESS_BOARDS.includes(firmwareHardware));
export const hasButtons = (firmwareHardware: FirmwareHardware | undefined) =>
!firmwareHardware || !NO_BUTTONS.includes(firmwareHardware);

View File

@ -6,6 +6,7 @@ import { Color } from "../../../../../ui/index";
import {
fakeMapTransformProps,
} from "../../../../../__test_support__/map_transform_props";
import { svgMount } from "../../../../../__test_support__/svg_mount";
describe("<BotFigure/>", () => {
const fakeProps = (): BotFigureProps => ({
@ -35,7 +36,7 @@ describe("<BotFigure/>", () => {
p.mapTransformProps.quadrant = quadrant;
p.mapTransformProps.xySwap = xySwap;
p.figureName = figureName;
const result = shallow<BotFigure>(<BotFigure {...p} />);
const result = svgMount(<BotFigure {...p} />);
const expectedGantryProps = expect.objectContaining({
id: "gantry",
@ -65,7 +66,7 @@ describe("<BotFigure/>", () => {
const p = fakeProps();
p.mapTransformProps.quadrant = 2;
p.position = { x: 100, y: 200, z: 0 };
const result = shallow<BotFigure>(<BotFigure {...p} />);
const result = svgMount(<BotFigure {...p} />);
const gantry = result.find("#gantry");
expect(gantry.length).toEqual(1);
expect(gantry.props().x).toEqual(90);
@ -77,7 +78,7 @@ describe("<BotFigure/>", () => {
it("changes color on e-stop", () => {
const p = fakeProps();
p.eStopStatus = true;
const wrapper = shallow<BotFigure>(<BotFigure {...p} />);
const wrapper = svgMount(<BotFigure {...p} />);
expect(wrapper.find("#gantry").props().fill).toEqual(Color.virtualRed);
});
@ -118,7 +119,7 @@ describe("<BotFigure/>", () => {
it("shows mounted tool", () => {
const p = fakeProps();
p.mountedToolName = "Seeder";
const wrapper = shallow<BotFigure>(<BotFigure {...p} />);
const wrapper = svgMount(<BotFigure {...p} />);
expect(wrapper.find("#UTM-wrapper").find("#mounted-tool").length)
.toEqual(1);
});

View File

@ -303,7 +303,6 @@ describe("<ToolSlotSVG />", () => {
const fakeProps = (): ToolSlotSVGProps => ({
toolSlot: fakeToolSlot(),
toolName: "seeder",
renderRotation: false,
xySwap: false,
quadrant: 2,
});

View File

@ -341,13 +341,12 @@ const SeedTrough = (props: ToolGraphicProps) => {
export interface ToolSlotSVGProps {
toolSlot: TaggedToolSlotPointer;
toolName: string | undefined;
renderRotation: boolean;
xySwap?: boolean;
quadrant?: BotOriginQuadrant;
}
export const ToolSlotSVG = (props: ToolSlotSVGProps) => {
const xySwap = props.renderRotation ? !!props.xySwap : false;
const xySwap = !!props.xySwap;
const toolProps = {
x: 0, y: 0,
hovered: false,
@ -355,13 +354,11 @@ export const ToolSlotSVG = (props: ToolSlotSVGProps) => {
uuid: props.toolSlot.uuid,
xySwap,
};
const pulloutDirection = props.renderRotation
? props.toolSlot.body.pullout_direction
: ToolPulloutDirection.POSITIVE_X;
const quadrant = props.renderRotation && props.quadrant ? props.quadrant : 2;
const viewBox = props.renderRotation ? "-25 0 50 1" : "-25 0 50 1";
const pulloutDirection = props.toolSlot.body.pullout_direction
|| ToolPulloutDirection.POSITIVE_X;
const quadrant = props.quadrant || 2;
return props.toolSlot.body.gantry_mounted
? <svg width="3rem" height="3rem" viewBox={viewBox}>
? <svg width="3rem" height="3rem" viewBox={"-25 0 50 1"}>
<GantryToolSlot x={0} y={0} xySwap={xySwap} />
{props.toolSlot.body.tool_id &&
<Tool tool={reduceToolName(props.toolName)} toolProps={toolProps} />}
@ -369,7 +366,7 @@ export const ToolSlotSVG = (props: ToolSlotSVGProps) => {
: <svg width="3rem" height="3rem" viewBox={`-50 0 100 1`}>
{props.toolSlot.body.pullout_direction &&
<ToolbaySlot
id={props.toolSlot.body.id}
id={-(props.toolSlot.body.id || 1)}
x={0}
y={0}
pulloutDirection={pulloutDirection}

View File

@ -51,7 +51,7 @@ export const ToolSlotPoint = (props: TSPProps) => {
onClick={() => history.push(`/app/designer/tool-slots/${id}`)}>
{pullout_direction && !gantry_mounted &&
<ToolbaySlot
id={-(id || 1)}
id={id}
x={qx}
y={qy}
pulloutDirection={pullout_direction}

View File

@ -21,7 +21,8 @@ import { init, save, edit, destroy } from "../../../api/crud";
import { history } from "../../../history";
import { SpecialStatus } from "farmbot";
import { ToolPulloutDirection } from "farmbot/dist/resources/api_resources";
import { AddToolSlotProps, mapStateToPropsAdd } from "../map_to_props_add_edit";
import { mapStateToPropsAdd } from "../state_to_props";
import { AddToolSlotProps } from "../interfaces";
describe("<AddToolSlot />", () => {
const fakeProps = (): AddToolSlotProps => ({
@ -39,7 +40,7 @@ describe("<AddToolSlot />", () => {
it("renders", () => {
const wrapper = mount(<AddToolSlot {...fakeProps()} />);
["add new slot", "x (mm)", "y (mm)", "z (mm)", "tool or seed container",
"change direction", "gantry-mounted",
"direction", "gantry-mounted",
].map(string => expect(wrapper.text().toLowerCase()).toContain(string));
expect(init).toHaveBeenCalledWith("Point", {
pointer_type: "ToolSlot", name: "Slot", radius: 0, meta: {},

View File

@ -4,14 +4,13 @@ jest.mock("../../../history", () => ({ history: { push: jest.fn() } }));
import * as React from "react";
import { mount, shallow } from "enzyme";
import {
RawAddTool as AddTool, AddToolProps, mapStateToProps,
} from "../add_tool";
import { RawAddTool as AddTool, mapStateToProps } from "../add_tool";
import { fakeState } from "../../../__test_support__/fake_state";
import { SaveBtn } from "../../../ui";
import { initSave } from "../../../api/crud";
import { history } from "../../../history";
import { FirmwareHardware } from "farmbot";
import { AddToolProps } from "../interfaces";
describe("<AddTool />", () => {
const fakeProps = (): AddToolProps => ({
@ -90,6 +89,22 @@ describe("<AddTool />", () => {
wrapper.find("input").last().simulate("change");
expect(wrapper.state().toAdd).toEqual(["Seed Trough 2"]);
});
it("disables when all already added", () => {
const p = fakeProps();
p.firmwareHardware = "express_k10";
p.existingToolNames = ["Seed Trough 1", "Seed Trough 2"];
const wrapper = mount<AddTool>(<AddTool {...p} />);
expect(wrapper.find("button").last().hasClass("pseudo-disabled"))
.toBeTruthy();
});
it("hides when none firmware is selected", () => {
const p = fakeProps();
p.firmwareHardware = "none";
const wrapper = mount<AddTool>(<AddTool {...p} />);
expect(wrapper.find(".add-stock-tools").props().hidden).toBeTruthy();
});
});
describe("mapStateToProps()", () => {

View File

@ -18,10 +18,9 @@ import {
buildResourceIndex,
} from "../../../__test_support__/resource_index_builder";
import { destroy, edit, save } from "../../../api/crud";
import {
EditToolSlotProps, mapStateToPropsEdit,
} from "../map_to_props_add_edit";
import { mapStateToPropsEdit } from "../state_to_props";
import { SlotEditRows } from "../tool_slot_edit_components";
import { EditToolSlotProps } from "../interfaces";
describe("<EditToolSlot />", () => {
const fakeProps = (): EditToolSlotProps => ({
@ -46,7 +45,7 @@ describe("<EditToolSlot />", () => {
p.findToolSlot = () => fakeToolSlot();
const wrapper = mount(<EditToolSlot {...p} />);
["edit slot", "x (mm)", "y (mm)", "z (mm)", "tool or seed container",
"change direction", "gantry-mounted",
"direction", "gantry-mounted",
].map(string => expect(wrapper.text().toLowerCase()).toContain(string));
});

View File

@ -13,9 +13,11 @@ jest.mock("../../../history", () => ({
import * as React from "react";
import { mount, shallow } from "enzyme";
import {
RawEditTool as EditTool, EditToolProps, mapStateToProps, isActive,
RawEditTool as EditTool, mapStateToProps, isActive,
} from "../edit_tool";
import { fakeTool, fakeToolSlot } from "../../../__test_support__/fake_state/resources";
import {
fakeTool, fakeToolSlot,
} from "../../../__test_support__/fake_state/resources";
import { fakeState } from "../../../__test_support__/fake_state";
import {
buildResourceIndex, fakeDevice,
@ -24,6 +26,7 @@ import { SaveBtn } from "../../../ui";
import { history } from "../../../history";
import { edit, destroy } from "../../../api/crud";
import { clickButton } from "../../../__test_support__/helpers";
import { EditToolProps } from "../interfaces";
describe("<EditTool />", () => {
beforeEach(() => {

View File

@ -14,22 +14,20 @@ jest.mock("../../../device", () => ({ getDevice: () => mockDevice }));
import * as React from "react";
import { mount, shallow } from "enzyme";
import {
RawTools as Tools, ToolsProps, mapStateToProps,
RawTools as Tools,
ToolSlotInventoryItem, ToolSlotInventoryItemProps,
} from "../index";
import {
fakeTool, fakeToolSlot, fakeSensor,
} from "../../../__test_support__/fake_state/resources";
import { history } from "../../../history";
import { fakeState } from "../../../__test_support__/fake_state";
import {
buildResourceIndex, fakeDevice,
} from "../../../__test_support__/resource_index_builder";
import { fakeDevice } from "../../../__test_support__/resource_index_builder";
import { bot } from "../../../__test_support__/fake_state/bot";
import { error } from "../../../toast/toast";
import { Content, Actions } from "../../../constants";
import { edit, save } from "../../../api/crud";
import { ToolSelection } from "../tool_slot_edit_components";
import { ToolsProps } from "../interfaces";
describe("<Tools />", () => {
const fakeProps = (): ToolsProps => ({
@ -43,6 +41,8 @@ describe("<Tools />", () => {
hoveredToolSlot: undefined,
firmwareHardware: undefined,
isActive: jest.fn(),
xySwap: false,
quadrant: 2,
});
it("renders with no tools", () => {
@ -225,6 +225,8 @@ describe("<ToolSlotInventoryItem />", () => {
hovered: false,
dispatch: jest.fn(),
isActive: jest.fn(),
xySwap: false,
quadrant: 2,
});
it("changes tool", () => {
@ -242,14 +244,3 @@ describe("<ToolSlotInventoryItem />", () => {
expect(e.stopPropagation).toHaveBeenCalled();
});
});
describe("mapStateToProps()", () => {
it("returns props", () => {
const state = fakeState();
const tool = fakeTool();
tool.body.id = 1;
state.resources = buildResourceIndex([tool, fakeDevice()]);
const props = mapStateToProps(state);
expect(props.findTool(tool.body.id)).toEqual(tool);
});
});

View File

@ -0,0 +1,31 @@
import { fakeState } from "../../../__test_support__/fake_state";
import {
fakeWebAppConfig, fakeTool,
} from "../../../__test_support__/fake_state/resources";
import {
buildResourceIndex, fakeDevice,
} from "../../../__test_support__/resource_index_builder";
import { mapStateToProps } from "../state_to_props";
describe("mapStateToProps()", () => {
it("returns props", () => {
const state = fakeState();
const webAppConfig = fakeWebAppConfig();
webAppConfig.body.bot_origin_quadrant = 1;
state.resources = buildResourceIndex([fakeDevice(), webAppConfig]);
const props = mapStateToProps(state);
expect(props.quadrant).toEqual(1);
});
it("returns props: incorrect quadrant", () => {
const state = fakeState();
const tool = fakeTool();
tool.body.id = 1;
const webAppConfig = fakeWebAppConfig();
webAppConfig.body.bot_origin_quadrant = 10;
state.resources = buildResourceIndex([tool, fakeDevice(), webAppConfig]);
const props = mapStateToProps(state);
expect(props.findTool(tool.body.id)).toEqual(tool);
expect(props.quadrant).toEqual(2);
});
});

View File

@ -7,8 +7,11 @@ import {
SlotLocationInputRow, SlotLocationInputRowProps,
ToolSelection, ToolSelectionProps, SlotEditRows, SlotEditRowsProps,
} from "../tool_slot_edit_components";
import { fakeTool, fakeToolSlot } from "../../../__test_support__/fake_state/resources";
import {
fakeTool, fakeToolSlot,
} from "../../../__test_support__/fake_state/resources";
import { FBSelect, NULL_CHOICE } from "../../../ui";
import { ToolPulloutDirection } from "farmbot/dist/resources/api_resources";
describe("<GantryMountedInput />", () => {
const fakeProps = (): GantryMountedInputProps => ({
@ -35,9 +38,18 @@ describe("<SlotDirectionInputRow />", () => {
onChange: jest.fn(),
});
it("renders", () => {
const wrapper = mount(<SlotDirectionInputRow {...fakeProps()} />);
expect(wrapper.text().toLowerCase()).toContain("change direction");
it.each<[ToolPulloutDirection, string]>([
[ToolPulloutDirection.NONE, "fa-dot-circle-o"],
[ToolPulloutDirection.POSITIVE_X, "fa-arrow-circle-right"],
[ToolPulloutDirection.NEGATIVE_X, "fa-arrow-circle-left"],
[ToolPulloutDirection.POSITIVE_Y, "fa-arrow-circle-up"],
[ToolPulloutDirection.NEGATIVE_Y, "fa-arrow-circle-down"],
])("renders: direction %s", (toolPulloutDirection, expected) => {
const p = fakeProps();
p.toolPulloutDirection = toolPulloutDirection;
const wrapper = mount(<SlotDirectionInputRow {...p} />);
expect(wrapper.text().toLowerCase()).toContain("direction");
expect(wrapper.find("i").first().hasClass(expected)).toBeTruthy();
});
it("changes value by click", () => {
@ -47,6 +59,14 @@ describe("<SlotDirectionInputRow />", () => {
expect(p.onChange).toHaveBeenCalledWith({ pullout_direction: 1 });
});
it("changes value by click: handles rollover", () => {
const p = fakeProps();
p.toolPulloutDirection = ToolPulloutDirection.NEGATIVE_Y;
const wrapper = shallow(<SlotDirectionInputRow {...p} />);
wrapper.find("i").first().simulate("click");
expect(p.onChange).toHaveBeenCalledWith({ pullout_direction: 0 });
});
it("changes value by selection", () => {
const p = fakeProps();
const wrapper = shallow(<SlotDirectionInputRow {...p} />);
@ -72,7 +92,8 @@ describe("<ToolSelection />", () => {
it("handles missing tool data", () => {
const p = fakeProps();
p.filterSelectedTool = true;
p.filterActiveTools = false;
p.filterSelectedTool = false;
const tool = fakeTool();
tool.body.name = undefined;
tool.body.id = undefined;
@ -111,7 +132,7 @@ describe("<ToolInputRow />", () => {
tools: [],
selectedTool: undefined,
onChange: jest.fn(),
isExpress: false,
noUTM: false,
isActive: jest.fn(),
});
@ -129,7 +150,7 @@ describe("<ToolInputRow />", () => {
it("renders for express bots", () => {
const p = fakeProps();
p.isExpress = true;
p.noUTM = true;
const wrapper = mount(<ToolInputRow {...p} />);
expect(wrapper.text().toLowerCase()).toContain("seed container");
});
@ -196,7 +217,7 @@ describe("<SlotEditRows />", () => {
tool: undefined,
botPosition: { x: undefined, y: undefined, z: undefined },
updateToolSlot: jest.fn(),
isExpress: false,
noUTM: false,
xySwap: false,
quadrant: 2,
isActive: () => false,

View File

@ -6,7 +6,7 @@ import {
import { Everything } from "../../interfaces";
import { t } from "../../i18next_wrapper";
import { SaveBtn } from "../../ui";
import { SpecialStatus, FirmwareHardware } from "farmbot";
import { SpecialStatus } from "farmbot";
import { initSave } from "../../api/crud";
import { Panel } from "../panel_header";
import { history } from "../../history";
@ -17,17 +17,7 @@ import {
} from "../../devices/components/firmware_hardware_support";
import { getFbosConfig } from "../../resources/getters";
import { ToolSVG } from "../map/layers/tool_slots/tool_graphics";
export interface AddToolProps {
dispatch: Function;
existingToolNames: string[];
firmwareHardware: FirmwareHardware | undefined;
}
export interface AddToolState {
toolName: string;
toAdd: string[];
}
import { AddToolProps, AddToolState } from "./interfaces";
export const mapStateToProps = (props: Everything): AddToolProps => ({
dispatch: props.dispatch,
@ -107,8 +97,10 @@ export class RawAddTool extends React.Component<AddToolProps, AddToolState> {
</div>;
}
AddStockTools = () =>
<div className="add-stock-tools">
AddStockTools = () => {
const add = this.state.toAdd.filter(this.filterExisting);
return <div className="add-stock-tools"
hidden={this.props.firmwareHardware == "none"}>
<label>{t("stock names")}</label>
<ul>
{this.stockToolNames().map(n =>
@ -118,17 +110,17 @@ export class RawAddTool extends React.Component<AddToolProps, AddToolState> {
</li>)}
</ul>
<button
className="fb-button green"
title={t("add selected stock names")}
className={`fb-button green ${add.length > 0 ? "" : "pseudo-disabled"}`}
title={add.length > 0 ? t("Add selected") : t("None to add")}
onClick={() => {
this.state.toAdd.filter(this.filterExisting)
.map(n => this.newTool(n));
add.map(n => this.newTool(n));
history.push("/app/designer/tools");
}}>
<i className="fa fa-plus" />
{t("selected")}
</button>
</div>
</div>;
}
render() {
const panelName = "add-tool";

View File

@ -11,15 +11,9 @@ import { Panel } from "../panel_header";
import { ToolPulloutDirection } from "farmbot/dist/resources/api_resources";
import { history } from "../../history";
import { SlotEditRows } from "./tool_slot_edit_components";
import { UUID } from "../../resources/interfaces";
import {
isExpressBoard,
} from "../../devices/components/firmware_hardware_support";
import { AddToolSlotProps, mapStateToPropsAdd } from "./map_to_props_add_edit";
export interface AddToolSlotState {
uuid: UUID | undefined;
}
import { hasUTM } from "../../devices/components/firmware_hardware_support";
import { mapStateToPropsAdd } from "./state_to_props";
import { AddToolSlotState, AddToolSlotProps } from "./interfaces";
export class RawAddToolSlot
extends React.Component<AddToolSlotProps, AddToolSlotState> {
@ -30,7 +24,7 @@ export class RawAddToolSlot
pointer_type: "ToolSlot", name: t("Slot"), radius: 0, meta: {},
x: 0, y: 0, z: 0, tool_id: undefined,
pullout_direction: ToolPulloutDirection.NONE,
gantry_mounted: isExpressBoard(this.props.firmwareHardware) ? true : false,
gantry_mounted: !hasUTM(this.props.firmwareHardware) ? true : false,
});
this.setState({ uuid: action.payload.uuid });
this.props.dispatch(action);
@ -74,7 +68,7 @@ export class RawAddToolSlot
<DesignerPanelContent panelName={panelName}>
{this.toolSlot
? <SlotEditRows
isExpress={isExpressBoard(this.props.firmwareHardware)}
noUTM={!hasUTM(this.props.firmwareHardware)}
toolSlot={this.toolSlot}
tools={this.props.tools}
tool={this.tool}

View File

@ -16,22 +16,12 @@ import { history } from "../../history";
import { Panel } from "../panel_header";
import { ToolSVG } from "../map/layers/tool_slots/tool_graphics";
import { error } from "../../toast/toast";
import { EditToolProps, EditToolState } from "./interfaces";
export const isActive = (toolSlots: TaggedToolSlotPointer[]) =>
(toolId: number | undefined) =>
!!(toolId && toolSlots.map(x => x.body.tool_id).includes(toolId));
export interface EditToolProps {
findTool(id: string): TaggedTool | undefined;
dispatch: Function;
mountedToolId: number | undefined;
isActive(id: number | undefined): boolean;
}
export interface EditToolState {
toolName: string;
}
export const mapStateToProps = (props: Everything): EditToolProps => ({
findTool: (id: string) =>
maybeFindToolById(props.resources.index, parseInt(id)),

View File

@ -11,10 +11,9 @@ import { history } from "../../history";
import { Panel } from "../panel_header";
import { SlotEditRows } from "./tool_slot_edit_components";
import { moveAbs } from "../../devices/actions";
import {
isExpressBoard,
} from "../../devices/components/firmware_hardware_support";
import { EditToolSlotProps, mapStateToPropsEdit } from "./map_to_props_add_edit";
import { hasUTM } from "../../devices/components/firmware_hardware_support";
import { mapStateToPropsEdit } from "./state_to_props";
import { EditToolSlotProps } from "./interfaces";
export class RawEditToolSlot extends React.Component<EditToolSlotProps> {
@ -44,7 +43,7 @@ export class RawEditToolSlot extends React.Component<EditToolSlotProps> {
{toolSlot
? <div className={"edit-tool-slot-content-wrapper"}>
<SlotEditRows
isExpress={isExpressBoard(this.props.firmwareHardware)}
noUTM={!hasUTM(this.props.firmwareHardware)}
toolSlot={toolSlot}
tools={this.props.tools}
tool={this.tool}

View File

@ -3,21 +3,12 @@ import { connect } from "react-redux";
import {
DesignerPanel, DesignerPanelTop, DesignerPanelContent,
} from "../designer_panel";
import { Everything } from "../../interfaces";
import { DesignerNavTabs, Panel, TAB_COLOR } from "../panel_header";
import {
EmptyStateWrapper, EmptyStateGraphic,
} from "../../ui/empty_state_wrapper";
import { t } from "../../i18next_wrapper";
import {
TaggedTool, TaggedToolSlotPointer, TaggedDevice, TaggedSensor,
FirmwareHardware,
} from "farmbot";
import {
selectAllTools, selectAllToolSlotPointers, getDeviceAccountSettings,
maybeFindToolById,
selectAllSensors,
} from "../../resources/selectors";
import { TaggedTool, TaggedToolSlotPointer, TaggedSensor } from "farmbot";
import { Content } from "../../constants";
import { history } from "../../history";
import { Row, Col, Help } from "../../ui";
@ -26,47 +17,15 @@ import { Link } from "../../link";
import { edit, save } from "../../api/crud";
import { readPin } from "../../devices/actions";
import { isBotOnlineFromState } from "../../devices/must_be_online";
import { BotState } from "../../devices/interfaces";
import {
setToolHover, ToolSlotSVG, ToolSVG,
} from "../map/layers/tool_slots/tool_graphics";
import { ToolSelection } from "./tool_slot_edit_components";
import { error } from "../../toast/toast";
import {
isExpressBoard, getFwHardwareValue,
} from "../../devices/components/firmware_hardware_support";
import { getFbosConfig } from "../../resources/getters";
import { isActive } from "./edit_tool";
export interface ToolsProps {
tools: TaggedTool[];
toolSlots: TaggedToolSlotPointer[];
dispatch: Function;
findTool(id: number): TaggedTool | undefined;
device: TaggedDevice;
sensors: TaggedSensor[];
bot: BotState;
hoveredToolSlot: string | undefined;
firmwareHardware: FirmwareHardware | undefined;
isActive(id: number | undefined): boolean;
}
export interface ToolsState {
searchTerm: string;
}
export const mapStateToProps = (props: Everything): ToolsProps => ({
tools: selectAllTools(props.resources.index),
toolSlots: selectAllToolSlotPointers(props.resources.index),
dispatch: props.dispatch,
findTool: (id: number) => maybeFindToolById(props.resources.index, id),
device: getDeviceAccountSettings(props.resources.index),
sensors: selectAllSensors(props.resources.index),
bot: props.bot,
hoveredToolSlot: props.resources.consumers.farm_designer.hoveredToolSlot,
firmwareHardware: getFwHardwareValue(getFbosConfig(props.resources.index)),
isActive: isActive(selectAllToolSlotPointers(props.resources.index)),
});
import { hasUTM } from "../../devices/components/firmware_hardware_support";
import { ToolsProps, ToolsState } from "./interfaces";
import { mapStateToProps } from "./state_to_props";
import { BotOriginQuadrant } from "../interfaces";
const toolStatus = (value: number | undefined): string => {
switch (value) {
@ -112,7 +71,7 @@ export class RawTools extends React.Component<ToolsProps, ToolsState> {
get botOnline() { return isBotOnlineFromState(this.props.bot); }
get isExpress() { return isExpressBoard(this.props.firmwareHardware); }
get noUTM() { return !hasUTM(this.props.firmwareHardware); }
MountedToolInfo = () =>
<div className="mounted-tool">
@ -165,7 +124,9 @@ export class RawTools extends React.Component<ToolsProps, ToolsState> {
dispatch={this.props.dispatch}
toolSlot={toolSlot}
isActive={this.props.isActive}
tools={this.props.tools} />)}
tools={this.props.tools}
xySwap={this.props.xySwap}
quadrant={this.props.quadrant} />)}
</div>
Tools = () =>
@ -192,16 +153,16 @@ export class RawTools extends React.Component<ToolsProps, ToolsState> {
get strings() {
return {
placeholder: this.isExpress
placeholder: this.noUTM
? t("Search your seed containers...")
: t("Search your tools..."),
titleText: this.isExpress
titleText: this.noUTM
? t("Add a seed container")
: t("Add a tool or seed container"),
emptyStateText: this.isExpress
emptyStateText: this.noUTM
? Content.NO_SEED_CONTAINERS
: Content.NO_TOOLS,
tools: this.isExpress
tools: this.noUTM
? t("seed containers")
: t("tools and seed containers"),
toolSlots: t("slots"),
@ -228,8 +189,7 @@ export class RawTools extends React.Component<ToolsProps, ToolsState> {
title={this.strings.titleText}
text={this.strings.emptyStateText}
colorScheme={"tools"}>
{!this.isExpress &&
<this.MountedToolInfo />}
{!this.noUTM && <this.MountedToolInfo />}
<this.ToolSlots />
<this.Tools />
</EmptyStateWrapper>
@ -244,6 +204,8 @@ export interface ToolSlotInventoryItemProps {
hovered: boolean;
dispatch: Function;
isActive(id: number | undefined): boolean;
xySwap: boolean;
quadrant: BotOriginQuadrant;
}
export const ToolSlotInventoryItem = (props: ToolSlotInventoryItemProps) => {
@ -260,7 +222,7 @@ export const ToolSlotInventoryItem = (props: ToolSlotInventoryItemProps) => {
<ToolSlotSVG
toolSlot={props.toolSlot}
toolName={tool_id ? toolName : "Empty"}
renderRotation={false} />
xySwap={props.xySwap} quadrant={props.quadrant} />
</Col>
<Col xs={6}>
<div className={"tool-selection-wrapper"}

View File

@ -0,0 +1,71 @@
import { UUID } from "../../resources/interfaces";
import {
FirmwareHardware, TaggedTool, TaggedToolSlotPointer,
TaggedDevice, TaggedSensor,
} from "farmbot";
import { BotOriginQuadrant } from "../interfaces";
import { BotState, BotPosition } from "../../devices/interfaces";
export interface AddToolSlotState {
uuid: UUID | undefined;
}
export interface AddToolProps {
dispatch: Function;
existingToolNames: string[];
firmwareHardware: FirmwareHardware | undefined;
}
export interface AddToolState {
toolName: string;
toAdd: string[];
}
export interface EditToolProps {
findTool(id: string): TaggedTool | undefined;
dispatch: Function;
mountedToolId: number | undefined;
isActive(id: number | undefined): boolean;
}
export interface EditToolState {
toolName: string;
}
export interface ToolsProps {
tools: TaggedTool[];
toolSlots: TaggedToolSlotPointer[];
dispatch: Function;
findTool(id: number): TaggedTool | undefined;
device: TaggedDevice;
sensors: TaggedSensor[];
bot: BotState;
hoveredToolSlot: string | undefined;
firmwareHardware: FirmwareHardware | undefined;
xySwap: boolean;
quadrant: BotOriginQuadrant;
isActive(id: number | undefined): boolean;
}
export interface ToolsState {
searchTerm: string;
}
export interface AddEditToolSlotPropsBase {
tools: TaggedTool[];
dispatch: Function;
botPosition: BotPosition;
findTool(id: number): TaggedTool | undefined;
firmwareHardware: FirmwareHardware | undefined;
xySwap: boolean;
quadrant: BotOriginQuadrant;
isActive(id: number | undefined): boolean;
}
export interface AddToolSlotProps extends AddEditToolSlotPropsBase {
findToolSlot(uuid: UUID | undefined): TaggedToolSlotPointer | undefined;
}
export interface EditToolSlotProps extends AddEditToolSlotPropsBase {
findToolSlot(id: string): TaggedToolSlotPointer | undefined;
}

View File

@ -1,10 +1,10 @@
import { Everything } from "../../interfaces";
import { TaggedTool, TaggedToolSlotPointer, FirmwareHardware } from "farmbot";
import {
selectAllTools, maybeFindToolById, maybeGetToolSlot, maybeFindToolSlotById,
selectAllToolSlotPointers,
getDeviceAccountSettings,
selectAllSensors,
} from "../../resources/selectors";
import { BotPosition } from "../../devices/interfaces";
import { validBotLocationData } from "../../util";
import { UUID } from "../../resources/interfaces";
import {
@ -13,21 +13,35 @@ import {
import { getFbosConfig } from "../../resources/getters";
import { getWebAppConfigValue } from "../../config_storage/actions";
import { BooleanSetting, NumericSetting } from "../../session_keys";
import { BotOriginQuadrant, isBotOriginQuadrant } from "../interfaces";
import { isBotOriginQuadrant } from "../interfaces";
import { isActive } from "./edit_tool";
import {
AddEditToolSlotPropsBase, AddToolSlotProps, EditToolSlotProps, ToolsProps,
} from "./interfaces";
export interface AddEditToolSlotPropsBase {
tools: TaggedTool[];
dispatch: Function;
botPosition: BotPosition;
findTool(id: number): TaggedTool | undefined;
firmwareHardware: FirmwareHardware | undefined;
xySwap: boolean;
quadrant: BotOriginQuadrant;
isActive(id: number | undefined): boolean;
}
export const mapStateToProps = (props: Everything): ToolsProps => {
const getWebAppConfig = getWebAppConfigValue(() => props);
const xySwap = !!getWebAppConfig(BooleanSetting.xy_swap);
const rawQuadrant = getWebAppConfig(NumericSetting.bot_origin_quadrant);
const quadrant = isBotOriginQuadrant(rawQuadrant) ? rawQuadrant : 2;
return {
tools: selectAllTools(props.resources.index),
toolSlots: selectAllToolSlotPointers(props.resources.index),
dispatch: props.dispatch,
findTool: (id: number) => maybeFindToolById(props.resources.index, id),
device: getDeviceAccountSettings(props.resources.index),
sensors: selectAllSensors(props.resources.index),
bot: props.bot,
hoveredToolSlot: props.resources.consumers.farm_designer.hoveredToolSlot,
firmwareHardware: getFwHardwareValue(getFbosConfig(props.resources.index)),
isActive: isActive(selectAllToolSlotPointers(props.resources.index)),
xySwap,
quadrant,
};
};
export const mapStateToPropsBase = (props: Everything): AddEditToolSlotPropsBase => {
export const mapStateToPropsAddEditBase = (props: Everything):
AddEditToolSlotPropsBase => {
const getWebAppConfig = getWebAppConfigValue(() => props);
const xySwap = !!getWebAppConfig(BooleanSetting.xy_swap);
const rawQuadrant = getWebAppConfig(NumericSetting.bot_origin_quadrant);
@ -44,24 +58,16 @@ export const mapStateToPropsBase = (props: Everything): AddEditToolSlotPropsBase
};
};
export interface AddToolSlotProps extends AddEditToolSlotPropsBase {
findToolSlot(uuid: UUID | undefined): TaggedToolSlotPointer | undefined;
}
export const mapStateToPropsAdd = (props: Everything): AddToolSlotProps => {
const mapStateToProps = mapStateToPropsBase(props) as AddToolSlotProps;
mapStateToProps.findToolSlot = (uuid: UUID | undefined) =>
const stateToProps = mapStateToPropsAddEditBase(props) as AddToolSlotProps;
stateToProps.findToolSlot = (uuid: UUID | undefined) =>
maybeGetToolSlot(props.resources.index, uuid);
return mapStateToProps;
return stateToProps;
};
export interface EditToolSlotProps extends AddEditToolSlotPropsBase {
findToolSlot(id: string): TaggedToolSlotPointer | undefined;
}
export const mapStateToPropsEdit = (props: Everything): EditToolSlotProps => {
const mapStateToProps = mapStateToPropsBase(props) as EditToolSlotProps;
mapStateToProps.findToolSlot = (id: string) =>
const stateToProps = mapStateToPropsAddEditBase(props) as EditToolSlotProps;
stateToProps.findToolSlot = (id: string) =>
maybeFindToolSlotById(props.resources.index, parseInt(id));
return mapStateToProps;
return stateToProps;
};

View File

@ -8,8 +8,8 @@ import { BotPosition } from "../../devices/interfaces";
import { ToolPulloutDirection } from "farmbot/dist/resources/api_resources";
import { Popover } from "@blueprintjs/core";
import { ToolSlotSVG } from "../map/layers/tool_slots/tool_graphics";
import { BotOriginQuadrant } from "../interfaces";
import { isNumber } from "lodash";
import { BotOriginQuadrant } from "../interfaces";
export interface GantryMountedInputProps {
gantryMounted: boolean;
@ -32,7 +32,7 @@ export interface SlotDirectionInputRowProps {
export const SlotDirectionInputRow = (props: SlotDirectionInputRowProps) =>
<fieldset className="tool-slot-direction-input">
<label>
{t("Change direction")}
{t("Direction")}
</label>
<i className={"direction-icon "
+ directionIconClass(props.toolPulloutDirection)}
@ -81,7 +81,7 @@ export interface ToolInputRowProps {
tools: TaggedTool[];
selectedTool: TaggedTool | undefined;
onChange(update: { tool_id: number }): void;
isExpress: boolean;
noUTM: boolean;
isActive(id: number | undefined): boolean;
}
@ -90,7 +90,7 @@ export const ToolInputRow = (props: ToolInputRowProps) =>
<Row>
<Col xs={12}>
<label>
{props.isExpress
{props.noUTM
? t("Seed Container")
: t("Tool or Seed Container")}
</label>
@ -155,7 +155,7 @@ export interface SlotEditRowsProps {
tool: TaggedTool | undefined;
botPosition: BotPosition;
updateToolSlot(update: Partial<TaggedToolSlotPointer["body"]>): void;
isExpress: boolean;
noUTM: boolean;
xySwap: boolean;
quadrant: BotOriginQuadrant;
isActive(id: number | undefined): boolean;
@ -165,14 +165,14 @@ export const SlotEditRows = (props: SlotEditRowsProps) =>
<div className="tool-slot-edit-rows">
<ToolSlotSVG toolSlot={props.toolSlot}
toolName={props.tool ? props.tool.body.name : "Empty"}
renderRotation={true} xySwap={props.xySwap} quadrant={props.quadrant} />
xySwap={props.xySwap} quadrant={props.quadrant} />
<SlotLocationInputRow
slotLocation={props.toolSlot.body}
gantryMounted={props.toolSlot.body.gantry_mounted}
botPosition={props.botPosition}
onChange={props.updateToolSlot} />
<ToolInputRow
isExpress={props.isExpress}
noUTM={props.noUTM}
tools={props.tools}
selectedTool={props.tool}
isActive={props.isActive}
@ -181,7 +181,7 @@ export const SlotEditRows = (props: SlotEditRowsProps) =>
<SlotDirectionInputRow
toolPulloutDirection={props.toolSlot.body.pullout_direction}
onChange={props.updateToolSlot} />}
{!props.isExpress &&
{!props.noUTM &&
<GantryMountedInput
gantryMounted={props.toolSlot.body.gantry_mounted}
onChange={props.updateToolSlot} />}