cleanup and refactoring
parent
9d7833b71c
commit
781ac33b10
|
@ -26,6 +26,7 @@ module CeleryScript
|
|||
FRIENDLY_ERRORS = {
|
||||
nothing: {
|
||||
write_pin: "You must select a Peripheral in the Control Peripheral step.",
|
||||
toggle_pin: "You must select a Peripheral in the Toggle Peripheral step.",
|
||||
variable_declaration: MISSING_VAR,
|
||||
parameter_declaration: MISSING_PARAM,
|
||||
read_pin: "You must select a Sensor in the Read Sensor step.",
|
||||
|
|
|
@ -300,7 +300,9 @@ export namespace ToolTips {
|
|||
trim(`Power cycle FarmBot's onboard computer or microcontroller.`);
|
||||
|
||||
export const SET_SERVO_ANGLE =
|
||||
trim(`Move a servo to the provided angle.`);
|
||||
trim(`Move a servo to the provided angle. An angle of 90 degrees
|
||||
corresponds to the servo midpoint (or, for a continuous rotation
|
||||
servo, no movement).`);
|
||||
|
||||
export const TOGGLE_PIN =
|
||||
trim(`Toggle a digital pin on or off.`);
|
||||
|
|
|
@ -23,6 +23,12 @@
|
|||
margin-left: 1rem;
|
||||
box-shadow: none;
|
||||
}
|
||||
input[type="radio"] {
|
||||
margin-right: 0.25rem;
|
||||
margin-bottom: 0.25rem;
|
||||
margin-top: 0;
|
||||
vertical-align: middle;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -107,7 +113,7 @@
|
|||
background: $blue;
|
||||
}
|
||||
&.toggle-pin-step {
|
||||
background: $yellow;
|
||||
background: $orange;
|
||||
}
|
||||
&.set-zero-step {
|
||||
background: $blue;
|
||||
|
@ -124,6 +130,12 @@
|
|||
&.system-action-step {
|
||||
background: $brown;
|
||||
}
|
||||
&.emergency-stop-step {
|
||||
background: $brown;
|
||||
}
|
||||
&.reboot-step {
|
||||
background: $brown;
|
||||
}
|
||||
&.unknown-step {
|
||||
background: $gray;
|
||||
}
|
||||
|
@ -221,7 +233,7 @@
|
|||
background: $light_blue;
|
||||
}
|
||||
&.toggle-pin-step {
|
||||
background: $light_yellow;
|
||||
background: $light_orange;
|
||||
}
|
||||
&.set-zero-step {
|
||||
background: $light_blue;
|
||||
|
@ -238,6 +250,12 @@
|
|||
&.system-action-step {
|
||||
background: $light_brown;
|
||||
}
|
||||
&.emergency-stop-step {
|
||||
background: $light_brown;
|
||||
}
|
||||
&.reboot-step {
|
||||
background: $light_brown;
|
||||
}
|
||||
&.unknown-step {
|
||||
background: $light_gray;
|
||||
}
|
||||
|
|
|
@ -6,7 +6,7 @@ jest.mock("../../draggable/actions", () => ({
|
|||
stepGet: jest.fn(() => () => mockStepGetResult),
|
||||
}));
|
||||
|
||||
import { FolderNode } from "../constants";
|
||||
import { FolderNode } from "../interfaces";
|
||||
import { ingest } from "../data_transfer";
|
||||
import {
|
||||
collapseAll,
|
||||
|
@ -240,11 +240,11 @@ describe("deleteFolder", () => {
|
|||
|
||||
describe("updateSearchTerm", () => {
|
||||
it("updates a search term", () => {
|
||||
const argss =
|
||||
const args =
|
||||
(payload: string | undefined) => ({ type: "FOLDER_SEARCH", payload });
|
||||
[undefined, "foo"].map(term => {
|
||||
updateSearchTerm(term);
|
||||
expect(store.dispatch).toHaveBeenCalledWith(argss(term));
|
||||
expect(store.dispatch).toHaveBeenCalledWith(args(term));
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -35,7 +35,7 @@ import {
|
|||
FolderNameInputProps,
|
||||
FolderNodeMedial,
|
||||
FolderNodeTerminal,
|
||||
} from "../constants";
|
||||
} from "../interfaces";
|
||||
import {
|
||||
updateSearchTerm, toggleAll, moveSequence, dropSequence,
|
||||
sequenceEditMaybeSave,
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { FolderNode } from "../constants";
|
||||
import { FolderNode } from "../interfaces";
|
||||
import { ingest } from "../data_transfer";
|
||||
import { climb } from "../climb";
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import { TEST_GRAPH } from "./actions_test";
|
||||
import { searchFolderTree, FolderSearchProps } from "../search_folder_tree";
|
||||
import { TaggedResource } from "farmbot";
|
||||
import { FolderUnion } from "../constants";
|
||||
import { FolderUnion } from "../interfaces";
|
||||
|
||||
describe("searchFolderTree", () => {
|
||||
const searchFor = (input: string) => searchFolderTree({
|
||||
|
@ -19,7 +19,7 @@ describe("searchFolderTree", () => {
|
|||
expect(before).toEqual(after); // Prevent mutation of original data.
|
||||
});
|
||||
|
||||
it("finds an `inital` folder", () => {
|
||||
it("finds an `initial` folder", () => {
|
||||
const results = searchFor("one").map(x => x.name);
|
||||
expect(results.length).toEqual(1);
|
||||
expect(results).toContain("One");
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { RootFolderNode as Tree } from "./constants";
|
||||
import { RootFolderNode as Tree } from "./interfaces";
|
||||
import { cloneAndClimb } from "./climb";
|
||||
import { Color, SpecialStatus, TaggedSequence } from "farmbot";
|
||||
import { store } from "../redux/store";
|
||||
|
|
|
@ -1,4 +1,6 @@
|
|||
import { RootFolderNode, FolderUnion, FolderNodeMedial, FolderNodeInitial } from "./constants";
|
||||
import {
|
||||
RootFolderNode, FolderUnion, FolderNodeMedial, FolderNodeInitial
|
||||
} from "./interfaces";
|
||||
import { defensiveClone } from "../util";
|
||||
|
||||
interface TreeClimberState {
|
||||
|
|
|
@ -20,7 +20,7 @@ import {
|
|||
FolderButtonClusterProps,
|
||||
FolderNameInputProps,
|
||||
SequenceDropAreaState,
|
||||
} from "./constants";
|
||||
} from "./interfaces";
|
||||
import {
|
||||
createFolder,
|
||||
deleteFolder,
|
||||
|
|
|
@ -4,7 +4,7 @@ import {
|
|||
FolderNodeTerminal,
|
||||
RootFolderNode,
|
||||
FolderMeta,
|
||||
} from "./constants";
|
||||
} from "./interfaces";
|
||||
import { sortBy } from "lodash";
|
||||
|
||||
type FoldersIndexedByParentId = Record<number, FolderNode[]>;
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { FolderProps } from "./constants";
|
||||
import { FolderProps } from "./interfaces";
|
||||
import { selectAllSequences } from "../resources/selectors";
|
||||
import { TaggedSequence } from "farmbot";
|
||||
import { resourceUsageList } from "../resources/in_use";
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import { TaggedResource, TaggedSequence } from "farmbot";
|
||||
import { RootFolderNode, FolderUnion } from "./constants";
|
||||
import { RootFolderNode, FolderUnion } from "./interfaces";
|
||||
|
||||
export interface FolderSearchProps {
|
||||
references: Record<string, TaggedResource | undefined>;
|
||||
|
|
|
@ -14,7 +14,7 @@ import { HelpState } from "../help/reducer";
|
|||
import { UsageIndex } from "./in_use";
|
||||
import { SequenceMeta } from "./sequence_meta";
|
||||
import { AlertReducerState } from "../messages/interfaces";
|
||||
import { RootFolderNode, FolderMeta } from "../folders/constants";
|
||||
import { RootFolderNode, FolderMeta } from "../folders/interfaces";
|
||||
|
||||
export type UUID = string;
|
||||
export type VariableNameSet = Record<string, SequenceMeta | undefined>;
|
||||
|
|
|
@ -33,7 +33,9 @@ import { get } from "lodash";
|
|||
import { Actions } from "../constants";
|
||||
import { getFbosConfig } from "./getters";
|
||||
import { ingest, PARENTLESS as NO_PARENT } from "../folders/data_transfer";
|
||||
import { FolderNode, FolderMeta, FolderNodeTerminal, FolderNodeMedial } from "../folders/constants";
|
||||
import {
|
||||
FolderNode, FolderMeta, FolderNodeTerminal, FolderNodeMedial
|
||||
} from "../folders/interfaces";
|
||||
import { climb } from "../folders/climb";
|
||||
|
||||
export function findByUuid(index: ResourceIndex, uuid: string): TaggedResource {
|
||||
|
|
|
@ -52,7 +52,7 @@ export function StepButtonCluster(props: StepButtonProps) {
|
|||
step={{
|
||||
kind: "toggle_pin",
|
||||
args: {
|
||||
pin_number: 4
|
||||
pin_number: NOTHING_SELECTED
|
||||
}
|
||||
}}
|
||||
color="orange">
|
||||
|
|
|
@ -97,61 +97,6 @@ describe("renderCeleryNode()", () => {
|
|||
}
|
||||
|
||||
const TEST_DATA: TestData[] = [
|
||||
{
|
||||
expected: "MarkPlantasx = 300",
|
||||
node: {
|
||||
kind: "resource_update",
|
||||
args: {
|
||||
resource_id: 23,
|
||||
resource_type: "Plant",
|
||||
label: "x",
|
||||
value: 300
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
expected: "System",
|
||||
node: {
|
||||
kind: "check_updates",
|
||||
args: {
|
||||
package: "farmbot_os"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
expected: "System",
|
||||
node: {
|
||||
kind: "factory_reset",
|
||||
args: {
|
||||
package: "farmbot_os"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
expected: "Unlocking a device requires user intervention",
|
||||
node: {
|
||||
kind: "emergency_lock",
|
||||
args: {}
|
||||
}
|
||||
},
|
||||
{
|
||||
expected: "Unable to properly display this step",
|
||||
node: {
|
||||
kind: "power_off",
|
||||
args: {}
|
||||
}
|
||||
},
|
||||
{
|
||||
expected: "Unable to properly display this step",
|
||||
node: { kind: "read_status", args: {} }
|
||||
},
|
||||
{
|
||||
expected: "",
|
||||
node: {
|
||||
kind: "install_first_party_farmware",
|
||||
args: {}
|
||||
}
|
||||
},
|
||||
{
|
||||
node: {
|
||||
kind: "_if",
|
||||
|
@ -166,31 +111,13 @@ describe("renderCeleryNode()", () => {
|
|||
expected: "Then Execute"
|
||||
},
|
||||
{
|
||||
node: {
|
||||
kind: "execute_script",
|
||||
args: { label: "farmware-to-execute" }
|
||||
},
|
||||
node: { kind: "execute_script", args: { label: "farmware-to-execute" } },
|
||||
expected: "Manual Input"
|
||||
},
|
||||
{
|
||||
node: {
|
||||
kind: "execute",
|
||||
args: {
|
||||
sequence_id: 0
|
||||
}
|
||||
},
|
||||
node: { kind: "execute", args: { sequence_id: 0 } },
|
||||
expected: "Select a sequence"
|
||||
},
|
||||
{
|
||||
node: {
|
||||
kind: "find_home",
|
||||
args: {
|
||||
speed: 100,
|
||||
axis: "all"
|
||||
}
|
||||
},
|
||||
expected: "Find x"
|
||||
},
|
||||
{
|
||||
node: {
|
||||
kind: "move_absolute",
|
||||
|
@ -213,40 +140,37 @@ describe("renderCeleryNode()", () => {
|
|||
expected: "Message"
|
||||
},
|
||||
{
|
||||
node: {
|
||||
kind: "take_photo",
|
||||
args: {}
|
||||
},
|
||||
node: { kind: "take_photo", args: {} },
|
||||
expected: "Photo"
|
||||
},
|
||||
{
|
||||
node: {
|
||||
kind: "wait",
|
||||
args: {
|
||||
milliseconds: 100
|
||||
}
|
||||
},
|
||||
node: { kind: "wait", args: { milliseconds: 100 } },
|
||||
expected: "milliseconds"
|
||||
},
|
||||
{
|
||||
node: {
|
||||
kind: "set_servo_angle",
|
||||
kind: "resource_update",
|
||||
args: {
|
||||
pin_number: 4,
|
||||
pin_value: 90,
|
||||
resource_id: 23,
|
||||
resource_type: "Plant",
|
||||
label: "x",
|
||||
value: 300
|
||||
}
|
||||
},
|
||||
expected: "MarkPlantasx = 300"
|
||||
},
|
||||
{
|
||||
node: { kind: "set_servo_angle", args: { pin_number: 4, pin_value: 90, } },
|
||||
expected: "Servo"
|
||||
},
|
||||
{
|
||||
node: {
|
||||
kind: "toggle_pin",
|
||||
args: {
|
||||
pin_number: 13
|
||||
}
|
||||
},
|
||||
node: { kind: "toggle_pin", args: { pin_number: 13 } },
|
||||
expected: "Pin"
|
||||
},
|
||||
{
|
||||
node: { kind: "find_home", args: { speed: 100, axis: "all" } },
|
||||
expected: "Find x"
|
||||
},
|
||||
{
|
||||
node: { kind: "zero", args: { axis: "all" } },
|
||||
expected: "Zero x"
|
||||
|
@ -259,52 +183,36 @@ describe("renderCeleryNode()", () => {
|
|||
node: { kind: "home", args: { axis: "all", speed: 100, } },
|
||||
expected: "Home x"
|
||||
},
|
||||
{
|
||||
node: { kind: "reboot", args: { package: "farmbot_os" } },
|
||||
expected: "System"
|
||||
},
|
||||
{
|
||||
node: {
|
||||
kind: "check_updates", args: { package: "farmbot_os" }
|
||||
},
|
||||
expected: "System"
|
||||
},
|
||||
{
|
||||
node: {
|
||||
kind: "factory_reset", args: { package: "farmbot_os" }
|
||||
},
|
||||
expected: "System"
|
||||
},
|
||||
{
|
||||
node: {
|
||||
kind: "sync",
|
||||
args: {}
|
||||
},
|
||||
expected: ""
|
||||
},
|
||||
{
|
||||
node: {
|
||||
kind: "dump_info",
|
||||
args: {}
|
||||
},
|
||||
expected: ""
|
||||
},
|
||||
{
|
||||
node: {
|
||||
kind: "power_off",
|
||||
args: {}
|
||||
},
|
||||
expected: ""
|
||||
},
|
||||
{
|
||||
node: {
|
||||
kind: "read_status",
|
||||
args: {}
|
||||
},
|
||||
expected: ""
|
||||
},
|
||||
{
|
||||
node: { kind: "emergency_lock", args: {} },
|
||||
expected: "Unlocking a device requires user intervention"
|
||||
},
|
||||
{
|
||||
node: { kind: "reboot", args: { package: "farmbot_os" } },
|
||||
expected: "entire system"
|
||||
},
|
||||
{
|
||||
node: { kind: "check_updates", args: { package: "farmbot_os" } },
|
||||
expected: "System"
|
||||
},
|
||||
{
|
||||
node: { kind: "factory_reset", args: { package: "farmbot_os" } },
|
||||
expected: "System"
|
||||
},
|
||||
{
|
||||
node: { kind: "sync", args: {} },
|
||||
expected: ""
|
||||
},
|
||||
{
|
||||
node: { kind: "dump_info", args: {} },
|
||||
expected: ""
|
||||
},
|
||||
{
|
||||
node: { kind: "power_off", args: {} },
|
||||
expected: ""
|
||||
},
|
||||
{
|
||||
node: { kind: "read_status", args: {} },
|
||||
expected: ""
|
||||
},
|
||||
{
|
||||
|
@ -312,19 +220,12 @@ describe("renderCeleryNode()", () => {
|
|||
expected: ""
|
||||
},
|
||||
{
|
||||
node: {
|
||||
kind: "install_first_party_farmware", args: {}
|
||||
},
|
||||
node: { kind: "install_first_party_farmware", args: {} },
|
||||
expected: ""
|
||||
},
|
||||
{
|
||||
node: {
|
||||
kind: "unknown",
|
||||
args: {
|
||||
unknown: 0
|
||||
}
|
||||
// tslint:disable-next-line:no-any
|
||||
} as any,
|
||||
// tslint:disable-next-line: no-any
|
||||
node: { kind: "unknown", args: { unknown: 0 } } as any,
|
||||
expected: "unknown"
|
||||
},
|
||||
];
|
||||
|
|
|
@ -1,13 +1,12 @@
|
|||
jest.mock("../../api/crud", () => {
|
||||
return { editStep: jest.fn() };
|
||||
});
|
||||
import { TileReboot, editTheRebootStep, rebootExecutor, MultiChoiceRadio } from "../step_tiles/tile_reboot";
|
||||
import { render, mount } from "enzyme";
|
||||
jest.mock("../../../api/crud", () => ({ editStep: jest.fn() }));
|
||||
|
||||
import { TileReboot, editTheRebootStep, rebootExecutor } from "../tile_reboot";
|
||||
import { render } from "enzyme";
|
||||
import React from "react";
|
||||
import { StepParams } from "../interfaces";
|
||||
import { fakeSequence } from "../../__test_support__/fake_state/resources";
|
||||
import { buildResourceIndex } from "../../__test_support__/resource_index_builder";
|
||||
import { editStep } from "../../api/crud";
|
||||
import { StepParams } from "../../interfaces";
|
||||
import { fakeSequence } from "../../../__test_support__/fake_state/resources";
|
||||
import { buildResourceIndex } from "../../../__test_support__/resource_index_builder";
|
||||
import { editStep } from "../../../api/crud";
|
||||
import { Reboot } from "farmbot";
|
||||
|
||||
const fakeProps = (): StepParams => {
|
||||
|
@ -66,21 +65,3 @@ describe("<TileReboot/>", () => {
|
|||
expect(step.args.package).toBe("arduino_firmware");
|
||||
});
|
||||
});
|
||||
|
||||
describe("MultiChoiceRadio", () => {
|
||||
it("triggers callbacks", () => {
|
||||
const PACKAGE_CHOICES = {
|
||||
"a": "1",
|
||||
"b": "2"
|
||||
};
|
||||
const onChange = jest.fn();
|
||||
const el = mount(<MultiChoiceRadio
|
||||
uuid={"WHATEVER"}
|
||||
choices={PACKAGE_CHOICES}
|
||||
currentChoice={"a"}
|
||||
onChange={onChange} />);
|
||||
const radio = el.find("input[type='radio']").first();
|
||||
radio.simulate("change", "a");
|
||||
expect(onChange).toHaveBeenCalledWith("a");
|
||||
});
|
||||
});
|
|
@ -1,7 +1,9 @@
|
|||
jest.mock("../../../api/crud", () => ({ editStep: jest.fn() }));
|
||||
|
||||
import * as React from "react";
|
||||
import { TileSetServoAngle, pinNumberChanger, createServoEditFn, ServoPinSelection } from "../tile_set_servo_angle";
|
||||
import {
|
||||
TileSetServoAngle, pinNumberChanger, createServoEditFn, ServoPinSelection
|
||||
} from "../tile_set_servo_angle";
|
||||
import { mount } from "enzyme";
|
||||
import { fakeSequence } from "../../../__test_support__/fake_state/resources";
|
||||
import { SetServoAngle } from "farmbot";
|
||||
|
@ -33,8 +35,8 @@ describe("<TileSetServoAngle/>", () => {
|
|||
const inputs = block.find("input");
|
||||
const labels = block.find("label");
|
||||
const stepArgs = props.currentStep.args as SetServoAngle["args"];
|
||||
expect(inputs.length).toEqual(4);
|
||||
expect(labels.length).toEqual(4);
|
||||
expect(inputs.length).toEqual(6);
|
||||
expect(labels.length).toEqual(6);
|
||||
expect(inputs.first().props().placeholder).toEqual("Control Servo");
|
||||
expect(labels.at(0).text()).toContain("Servo angle (0-180)");
|
||||
expect(inputs.at(1).props().value).toEqual(stepArgs.pin_value);
|
||||
|
@ -53,7 +55,7 @@ describe("<TileSetServoAngle/>", () => {
|
|||
});
|
||||
});
|
||||
|
||||
it("dissallows named_pins", () => {
|
||||
it("disallows named_pins", () => {
|
||||
const p = fakeProps();
|
||||
const step = p.currentStep;
|
||||
if (step.kind === "set_servo_angle") {
|
||||
|
|
|
@ -157,10 +157,11 @@ export function renderCeleryNode(props: StepParams) {
|
|||
case "home": return <TileMoveHome {...props} />;
|
||||
case "reboot": return <TileReboot {...props} />;
|
||||
case "emergency_lock": return <TileEmergencyStop {...props} />;
|
||||
case "install_first_party_farmware": return <TileSystemAction {...props} />;
|
||||
case "assertion": return <TileAssertion {...props} />;
|
||||
case "check_updates":
|
||||
case "factory_reset":
|
||||
case "sync": case "dump_info": case "power_off": case "read_status":
|
||||
case "emergency_unlock": case "install_first_party_farmware":
|
||||
return <TileSystemAction {...props} />;
|
||||
case "check_updates": case "factory_reset":
|
||||
return <TileFirmwareAction {...props} />;
|
||||
default:
|
||||
return <TileUnknown {...props} />;
|
||||
|
|
|
@ -4,7 +4,7 @@ import { ToolTips, Content } from "../../constants";
|
|||
import {
|
||||
StepWrapper, StepHeader, StepContent, conflictsString, StepWarning
|
||||
} from "../step_ui/index";
|
||||
import { StepRadio } from "../step_ui/step_radio";
|
||||
import { AxisStepRadio } from "../step_ui/step_radio";
|
||||
import { t } from "../../i18next_wrapper";
|
||||
import { Xyz, Calibrate, TaggedSequence } from "farmbot";
|
||||
import { some } from "lodash";
|
||||
|
@ -81,7 +81,7 @@ class InnerTileCalibrate extends React.Component<CalibrateParams, {}> {
|
|||
conflicts={this.settingConflicts} />}
|
||||
</StepHeader>
|
||||
<StepContent className={className}>
|
||||
<StepRadio
|
||||
<AxisStepRadio
|
||||
currentSequence={currentSequence}
|
||||
currentStep={currentStep}
|
||||
dispatch={dispatch}
|
||||
|
|
|
@ -7,7 +7,7 @@ import { t } from "../../i18next_wrapper";
|
|||
|
||||
export function TileEmergencyStop(props: StepParams) {
|
||||
const { dispatch, currentStep, index, currentSequence } = props;
|
||||
const className = "take-photo-step";
|
||||
const className = "emergency-stop-step";
|
||||
return <StepWrapper>
|
||||
<StepHeader
|
||||
className={className}
|
||||
|
|
|
@ -7,7 +7,7 @@ import {
|
|||
StepWrapper, StepHeader, StepContent, StepWarning, conflictsString
|
||||
} from "../step_ui/index";
|
||||
import { some } from "lodash";
|
||||
import { StepRadio } from "../step_ui/step_radio";
|
||||
import { AxisStepRadio } from "../step_ui/step_radio";
|
||||
import { t } from "../../i18next_wrapper";
|
||||
|
||||
export function TileFindHome(props: StepParams) {
|
||||
|
@ -80,7 +80,7 @@ class InnerFindHome extends React.Component<FindHomeParams, {}> {
|
|||
conflicts={this.settingConflicts} />}
|
||||
</StepHeader>
|
||||
<StepContent className={className}>
|
||||
<StepRadio
|
||||
<AxisStepRadio
|
||||
currentSequence={currentSequence}
|
||||
currentStep={currentStep}
|
||||
dispatch={dispatch}
|
||||
|
|
|
@ -2,10 +2,11 @@ import * as React from "react";
|
|||
import { StepParams } from "../interfaces";
|
||||
import { ToolTips } from "../../constants";
|
||||
import { StepWrapper, StepHeader, StepContent } from "../step_ui/index";
|
||||
import { StepRadio } from "../step_ui/step_radio";
|
||||
import { AxisStepRadio } from "../step_ui/step_radio";
|
||||
import { StepInputBox } from "../inputs/step_input_box";
|
||||
import { Row, Col } from "../../ui";
|
||||
import { t } from "../../i18next_wrapper";
|
||||
import { Home } from "farmbot";
|
||||
|
||||
export function TileMoveHome(props: StepParams) {
|
||||
const { dispatch, currentStep, index, currentSequence } = props;
|
||||
|
@ -20,9 +21,9 @@ export function TileMoveHome(props: StepParams) {
|
|||
index={index}
|
||||
confirmStepDeletion={props.confirmStepDeletion} />
|
||||
<StepContent className={className}>
|
||||
<StepRadio
|
||||
<AxisStepRadio
|
||||
currentSequence={currentSequence}
|
||||
currentStep={currentStep}
|
||||
currentStep={currentStep as Home}
|
||||
dispatch={dispatch}
|
||||
index={index}
|
||||
label={t("Home")} />
|
||||
|
|
|
@ -3,52 +3,18 @@ import { StepParams } from "../interfaces";
|
|||
import { ToolTips } from "../../constants";
|
||||
import { StepWrapper, StepHeader, StepContent } from "../step_ui/index";
|
||||
import { t } from "../../i18next_wrapper";
|
||||
import { Row, Col } from "../../ui";
|
||||
import { ALLOWED_PACKAGES, SequenceBodyItem, Reboot } from "farmbot";
|
||||
import { editStep } from "../../api/crud";
|
||||
import { StepRadio } from "../step_ui/step_radio";
|
||||
|
||||
type StringMap = Record<string, string>;
|
||||
|
||||
interface MultiChoiceRadioProps<T extends StringMap> {
|
||||
uuid: string;
|
||||
choices: T;
|
||||
currentChoice: keyof T;
|
||||
onChange(key: keyof T): void;
|
||||
}
|
||||
|
||||
export const MultiChoiceRadio =
|
||||
<T extends StringMap>(props: MultiChoiceRadioProps<T>) => {
|
||||
const choices = Object.keys(props.choices);
|
||||
return <Row>
|
||||
<Col xs={12}>
|
||||
<div className="bottom-content">
|
||||
<div className="channel-fields">
|
||||
<form>
|
||||
{choices.map((choice, i) =>
|
||||
<div key={`${props.uuid} ${i}`} style={{ display: "inline" }}>
|
||||
<label>
|
||||
<input type="radio"
|
||||
value={choice}
|
||||
onChange={() => props.onChange(choice)}
|
||||
checked={props.currentChoice === choice} />
|
||||
{t(props.choices[choice])}
|
||||
</label>
|
||||
</div>)}
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</Col>
|
||||
</Row>;
|
||||
};
|
||||
|
||||
const PACKAGE_CHOICES: Record<ALLOWED_PACKAGES, string> = {
|
||||
"arduino_firmware": "Just the Arduino",
|
||||
"farmbot_os": "Entire system"
|
||||
};
|
||||
const PACKAGE_CHOICES = (): Record<ALLOWED_PACKAGES, string> => ({
|
||||
"arduino_firmware": t("Just the Arduino"),
|
||||
"farmbot_os": t("Entire system")
|
||||
});
|
||||
|
||||
function assertReboot(x: SequenceBodyItem): asserts x is Reboot {
|
||||
if (x.kind !== "reboot") {
|
||||
throw new Error("Impossible");
|
||||
throw new Error(`${x.kind} is not "reboot"`);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -74,7 +40,7 @@ export const editTheRebootStep =
|
|||
|
||||
export function TileReboot(props: StepParams) {
|
||||
const { dispatch, currentStep, index, currentSequence } = props;
|
||||
const className = "take-photo-step";
|
||||
const className = "reboot-step";
|
||||
assertReboot(currentStep);
|
||||
return <StepWrapper>
|
||||
<StepHeader
|
||||
|
@ -86,9 +52,9 @@ export function TileReboot(props: StepParams) {
|
|||
index={index}
|
||||
confirmStepDeletion={props.confirmStepDeletion} />
|
||||
<StepContent className={className}>
|
||||
<MultiChoiceRadio
|
||||
uuid={currentSequence.uuid + index}
|
||||
choices={PACKAGE_CHOICES}
|
||||
<StepRadio
|
||||
choices={Object.keys(PACKAGE_CHOICES())}
|
||||
choiceLabelLookup={PACKAGE_CHOICES()}
|
||||
currentChoice={currentStep.args.package as ALLOWED_PACKAGES}
|
||||
onChange={editTheRebootStep(props)} />
|
||||
</StepContent>
|
||||
|
|
|
@ -2,17 +2,18 @@ import * as React from "react";
|
|||
import { StepInputBox } from "../inputs/step_input_box";
|
||||
import { StepParams } from "../interfaces";
|
||||
import { ToolTips } from "../../constants";
|
||||
import { StepWrapper, StepHeader, StepContent } from "../step_ui/index";
|
||||
import { StepWrapper, StepHeader, StepContent } from "../step_ui";
|
||||
import { Row, Col } from "../../ui/index";
|
||||
import { t } from "../../i18next_wrapper";
|
||||
import { MultiChoiceRadio } from "./tile_reboot";
|
||||
import { SetServoAngle } from "farmbot";
|
||||
import { editStep } from "../../api/crud";
|
||||
import { StepRadio } from "../step_ui/step_radio";
|
||||
|
||||
const PACKAGE_CHOICES: Record<string, string> = {
|
||||
"4": "Pin 4",
|
||||
"5": "Pin 5",
|
||||
};
|
||||
const PIN_CHOICES = ["4", "5", "6", "11"];
|
||||
const CHOICE_LABELS = () => PIN_CHOICES.reduce((acc, pinNumber) => {
|
||||
acc[pinNumber] = `${t("Pin")} ${pinNumber}`;
|
||||
return acc;
|
||||
}, {} as Record<string, string>);
|
||||
|
||||
type Keys =
|
||||
| "dispatch"
|
||||
|
@ -35,14 +36,14 @@ export const pinNumberChanger = (props: Props) => (y: string) => {
|
|||
};
|
||||
|
||||
export function ServoPinSelection(props: Props) {
|
||||
const { currentSequence, index, currentStep } = props;
|
||||
const { currentStep } = props;
|
||||
const num = (currentStep as SetServoAngle).args.pin_number;
|
||||
if (typeof num !== "number") { throw new Error("NO!"); }
|
||||
const onChange = pinNumberChanger(props);
|
||||
|
||||
return <MultiChoiceRadio
|
||||
uuid={currentSequence.uuid + index}
|
||||
choices={PACKAGE_CHOICES}
|
||||
return <StepRadio
|
||||
choices={PIN_CHOICES}
|
||||
choiceLabelLookup={CHOICE_LABELS()}
|
||||
currentChoice={"" + num}
|
||||
onChange={onChange} />;
|
||||
}
|
||||
|
@ -79,5 +80,4 @@ export function TileSetServoAngle(props: StepParams) {
|
|||
</Row>
|
||||
</StepContent>
|
||||
</StepWrapper>;
|
||||
|
||||
}
|
||||
|
|
|
@ -2,8 +2,9 @@ import * as React from "react";
|
|||
import { StepParams } from "../interfaces";
|
||||
import { ToolTips } from "../../constants";
|
||||
import { StepWrapper, StepHeader, StepContent } from "../step_ui/index";
|
||||
import { StepRadio } from "../step_ui/step_radio";
|
||||
import { t } from "../../i18next_wrapper";
|
||||
import { AxisStepRadio } from "../step_ui/step_radio";
|
||||
import { Zero } from "farmbot";
|
||||
|
||||
export function TileSetZero(props: StepParams) {
|
||||
const { dispatch, currentStep, index, currentSequence } = props;
|
||||
|
@ -18,9 +19,9 @@ export function TileSetZero(props: StepParams) {
|
|||
index={index}
|
||||
confirmStepDeletion={props.confirmStepDeletion} />
|
||||
<StepContent className={className}>
|
||||
<StepRadio
|
||||
<AxisStepRadio
|
||||
currentSequence={currentSequence}
|
||||
currentStep={currentStep}
|
||||
currentStep={currentStep as Zero}
|
||||
dispatch={dispatch}
|
||||
index={index}
|
||||
label={t("Zero")} />
|
||||
|
|
|
@ -1,14 +1,16 @@
|
|||
jest.mock("../../../api/crud", () => ({ overwrite: jest.fn() }));
|
||||
let mockStep = {};
|
||||
jest.mock("../../../api/crud", () => ({
|
||||
editStep: jest.fn(x => x.executor(mockStep)),
|
||||
}));
|
||||
|
||||
import * as React from "react";
|
||||
import { mount } from "enzyme";
|
||||
import { StepRadio, StepRadioProps } from "../step_radio";
|
||||
import { AxisStepRadio, AxisStepRadioProps } from "../step_radio";
|
||||
import { fakeSequence } from "../../../__test_support__/fake_state/resources";
|
||||
import { FindHome, Calibrate, Zero } from "farmbot";
|
||||
import { overwrite } from "../../../api/crud";
|
||||
|
||||
describe("<StepRadio />", () => {
|
||||
const currentStep: FindHome = {
|
||||
const findHomeStep: FindHome = {
|
||||
kind: "find_home",
|
||||
args: {
|
||||
speed: 100,
|
||||
|
@ -16,55 +18,55 @@ describe("<StepRadio />", () => {
|
|||
}
|
||||
};
|
||||
|
||||
const fakeProps = (): StepRadioProps => ({
|
||||
const fakeProps = (): AxisStepRadioProps => ({
|
||||
currentSequence: fakeSequence(),
|
||||
currentStep,
|
||||
currentStep: findHomeStep,
|
||||
dispatch: jest.fn(),
|
||||
index: 0,
|
||||
label: "Find",
|
||||
});
|
||||
|
||||
it("renders", () => {
|
||||
const wrapper = mount(<StepRadio {...fakeProps()} />);
|
||||
const wrapper = mount(<AxisStepRadio {...fakeProps()} />);
|
||||
expect(wrapper.find("input").length).toEqual(4);
|
||||
expect(wrapper.text()).toContain("Find");
|
||||
});
|
||||
|
||||
it("handles update for find_home", () => {
|
||||
const p = fakeProps();
|
||||
const wrapper = mount(<StepRadio {...p} />);
|
||||
mockStep = p.currentStep;
|
||||
const wrapper = mount(<AxisStepRadio {...p} />);
|
||||
wrapper.find("input").last().simulate("change");
|
||||
const expectedStep: FindHome = {
|
||||
kind: "find_home",
|
||||
args: { speed: 100, axis: "all" }
|
||||
};
|
||||
expect(overwrite).toHaveBeenCalledWith(p.currentSequence,
|
||||
expect.objectContaining({ body: [expectedStep] }));
|
||||
expect(mockStep).toEqual(expectedStep);
|
||||
});
|
||||
|
||||
it("handles update for calibrate", () => {
|
||||
const p = fakeProps();
|
||||
p.currentStep = { kind: "calibrate", args: { axis: "x" } };
|
||||
const wrapper = mount(<StepRadio {...p} />);
|
||||
mockStep = p.currentStep;
|
||||
const wrapper = mount(<AxisStepRadio {...p} />);
|
||||
wrapper.find("input").last().simulate("change");
|
||||
const expectedStep: Calibrate = {
|
||||
kind: "calibrate",
|
||||
args: { axis: "all" }
|
||||
};
|
||||
expect(overwrite).toHaveBeenCalledWith(p.currentSequence,
|
||||
expect.objectContaining({ body: [expectedStep] }));
|
||||
expect(mockStep).toEqual(expectedStep);
|
||||
});
|
||||
|
||||
it("handles update for zero", () => {
|
||||
const p = fakeProps();
|
||||
p.currentStep = { kind: "zero", args: { axis: "x" } };
|
||||
const wrapper = mount(<StepRadio {...p} />);
|
||||
mockStep = p.currentStep;
|
||||
const wrapper = mount(<AxisStepRadio {...p} />);
|
||||
wrapper.find("input").last().simulate("change");
|
||||
const expectedStep: Zero = {
|
||||
kind: "zero",
|
||||
args: { axis: "all" }
|
||||
};
|
||||
expect(overwrite).toHaveBeenCalledWith(p.currentSequence,
|
||||
expect.objectContaining({ body: [expectedStep] }));
|
||||
expect(mockStep).toEqual(expectedStep);
|
||||
});
|
||||
});
|
||||
|
|
|
@ -1,57 +1,32 @@
|
|||
import * as React from "react";
|
||||
import { Row, Col } from "../../ui/index";
|
||||
import {
|
||||
TaggedSequence, SequenceBodyItem, ALLOWED_AXIS
|
||||
} from "farmbot";
|
||||
import { overwrite } from "../../api/crud";
|
||||
import { defensiveClone } from "../../util";
|
||||
import { t } from "../../i18next_wrapper";
|
||||
import {
|
||||
TaggedSequence, ALLOWED_AXIS, FindHome, Home, Calibrate, Zero
|
||||
} from "farmbot";
|
||||
import { editStep } from "../../api/crud";
|
||||
|
||||
export interface StepRadioProps {
|
||||
currentSequence: TaggedSequence;
|
||||
currentStep: SequenceBodyItem;
|
||||
dispatch: Function;
|
||||
index: number;
|
||||
label: string;
|
||||
export interface StepRadioProps<T extends string> {
|
||||
choices: T[];
|
||||
choiceLabelLookup: Record<T, string>;
|
||||
currentChoice: T;
|
||||
onChange(key: T): void;
|
||||
}
|
||||
|
||||
const AXIS_CHOICES: ALLOWED_AXIS[] = ["x", "y", "z", "all"];
|
||||
|
||||
export function StepRadio(props: StepRadioProps) {
|
||||
const isSelected = (choice: ALLOWED_AXIS) => {
|
||||
if (props.currentStep.kind === "find_home"
|
||||
|| props.currentStep.kind === "calibrate"
|
||||
|| props.currentStep.kind === "zero") {
|
||||
return props.currentStep.args.axis === choice;
|
||||
}
|
||||
};
|
||||
|
||||
const handleUpdate = (choice: ALLOWED_AXIS) => {
|
||||
const update = defensiveClone(props.currentStep);
|
||||
if (update.kind === "find_home"
|
||||
|| update.kind === "calibrate"
|
||||
|| update.kind === "zero") {
|
||||
const nextSequence = defensiveClone(props.currentSequence).body;
|
||||
update.args.axis = choice;
|
||||
(nextSequence.body || [])[props.index] = update;
|
||||
props.dispatch(overwrite(props.currentSequence, nextSequence));
|
||||
}
|
||||
};
|
||||
|
||||
return <Row>
|
||||
export const StepRadio = <T extends string>(props: StepRadioProps<T>) =>
|
||||
<Row>
|
||||
<Col xs={12}>
|
||||
<div className="bottom-content">
|
||||
<div className="channel-fields">
|
||||
<form>
|
||||
{AXIS_CHOICES.map((choice, i) =>
|
||||
{props.choices.map((choice, i) =>
|
||||
<div key={i} style={{ display: "inline" }}>
|
||||
<label>
|
||||
<input type="radio"
|
||||
value={choice}
|
||||
onChange={e =>
|
||||
handleUpdate(e.currentTarget.value as typeof choice)}
|
||||
checked={isSelected(choice)} />
|
||||
{` ${t(props.label)} ${choice}`}
|
||||
onChange={() => props.onChange(choice)}
|
||||
checked={props.currentChoice === choice} />
|
||||
{t(props.choiceLabelLookup[choice])}
|
||||
</label>
|
||||
</div>)}
|
||||
</form>
|
||||
|
@ -59,4 +34,37 @@ export function StepRadio(props: StepRadioProps) {
|
|||
</div>
|
||||
</Col>
|
||||
</Row>;
|
||||
|
||||
type AxisStep = FindHome | Home | Calibrate | Zero;
|
||||
|
||||
export interface AxisStepRadioProps {
|
||||
currentSequence: TaggedSequence;
|
||||
currentStep: AxisStep;
|
||||
dispatch: Function;
|
||||
index: number;
|
||||
label: string;
|
||||
}
|
||||
|
||||
export const AxisStepRadio = (props: AxisStepRadioProps) => {
|
||||
const AXIS_CHOICES: ALLOWED_AXIS[] = ["x", "y", "z", "all"];
|
||||
const CHOICE_LABELS = AXIS_CHOICES.reduce((acc, axis) => {
|
||||
acc[axis] = `${t(props.label)} ${axis}`;
|
||||
return acc;
|
||||
}, {} as Record<ALLOWED_AXIS, string>);
|
||||
|
||||
const handleUpdate = (axis: ALLOWED_AXIS) => {
|
||||
const { currentStep, index, currentSequence } = props;
|
||||
props.dispatch(editStep({
|
||||
step: currentStep,
|
||||
index,
|
||||
sequence: currentSequence,
|
||||
executor: (step: AxisStep) => step.args.axis = axis,
|
||||
}));
|
||||
};
|
||||
|
||||
return <StepRadio
|
||||
choices={AXIS_CHOICES}
|
||||
choiceLabelLookup={CHOICE_LABELS}
|
||||
currentChoice={props.currentStep.args.axis}
|
||||
onChange={handleUpdate} />;
|
||||
};
|
||||
|
|
Loading…
Reference in New Issue