add shutdown sequence command

pull/1772/head
gabrielburnworth 2020-04-28 07:18:04 -07:00
parent 66553d143d
commit c9511593a3
10 changed files with 115 additions and 43 deletions

View File

@ -348,9 +348,6 @@ export namespace ToolTips {
For example, you can mark a plant as "planted" during a seeding For example, you can mark a plant as "planted" during a seeding
sequence or mark a weed as "removed" after removing it.`); sequence or mark a weed as "removed" after removing it.`);
export const REBOOT =
trim(`Power cycle FarmBot's onboard computer.`);
export const SET_SERVO_ANGLE = export const SET_SERVO_ANGLE =
trim(`Move a servo to the provided angle. An angle of 90 degrees trim(`Move a servo to the provided angle. An angle of 90 degrees
corresponds to the servo midpoint (or, for a continuous rotation corresponds to the servo midpoint (or, for a continuous rotation
@ -362,6 +359,9 @@ export namespace ToolTips {
export const MOVE_TO_HOME = export const MOVE_TO_HOME =
trim(`Move FarmBot to home for the provided axis.`); trim(`Move FarmBot to home for the provided axis.`);
export const ASSERTION =
trim(`Evaluate Lua commands. For power users and software developers.`);
export const FIRMWARE_ACTION = export const FIRMWARE_ACTION =
trim(`FarmBot OS or micro-controller firmware action.`); trim(`FarmBot OS or micro-controller firmware action.`);
@ -740,6 +740,15 @@ export namespace Content {
encoders, stall detection, or endstops enabled for the chosen axis. encoders, stall detection, or endstops enabled for the chosen axis.
Enable endstops, encoders, or stall detection from the Device page for: `); Enable endstops, encoders, or stall detection from the Device page for: `);
export const REBOOT_STEP =
trim(`Power cycle FarmBot's onboard computer.`);
export const SHUTDOWN_STEP =
trim(`Power down FarmBot's onboard computer.`);
export const ESTOP_STEP =
trim(`Unlocking a device requires user intervention.`);
export const IN_USE = export const IN_USE =
trim(`Used in another resource. Protected from deletion.`); trim(`Used in another resource. Protected from deletion.`);

View File

@ -136,6 +136,9 @@
&.reboot-step { &.reboot-step {
background: $brown; background: $brown;
} }
&.shutdown-step {
background: $brown;
}
&.unknown-step { &.unknown-step {
background: $gray; background: $gray;
} }
@ -253,6 +256,9 @@
&.emergency-stop-step { &.emergency-stop-step {
background: $light_red; background: $light_red;
} }
&.shutdown-step {
background: $light_brown;
}
&.reboot-step { &.reboot-step {
background: $light_brown; background: $light_brown;
} }

View File

@ -95,6 +95,11 @@ export function StepButtonCluster(props: StepButtonProps) {
color="brown"> color="brown">
{t("REBOOT")} {t("REBOOT")}
</StepButton>, </StepButton>,
<StepButton {...commonStepProps}
step={{ kind: "power_off", args: {} }}
color="brown">
{t("SHUTDOWN")}
</StepButton>,
<StepButton {...commonStepProps} <StepButton {...commonStepProps}
step={{ kind: "emergency_lock", args: {} }} step={{ kind: "emergency_lock", args: {} }}
color="red"> color="red">

View File

@ -5,59 +5,56 @@ import { render } from "enzyme";
import React from "react"; import React from "react";
import { StepParams } from "../../interfaces"; import { StepParams } from "../../interfaces";
import { fakeSequence } from "../../../__test_support__/fake_state/resources"; import { fakeSequence } from "../../../__test_support__/fake_state/resources";
import { buildResourceIndex } from "../../../__test_support__/resource_index_builder"; import {
buildResourceIndex,
} from "../../../__test_support__/resource_index_builder";
import { editStep } from "../../../api/crud"; import { editStep } from "../../../api/crud";
import { Reboot } from "farmbot"; import { Reboot } from "farmbot";
import { Content } from "../../../constants";
const fakeProps = (): StepParams => { const fakeProps = (): StepParams => ({
const currentSequence = fakeSequence(); currentSequence: fakeSequence(),
const resources = buildResourceIndex().index; currentStep: {
kind: "reboot",
return { args: {
currentSequence, package: "farmbot_os"
currentStep: { }
kind: "reboot", },
args: { dispatch: jest.fn(),
package: "farmbot_os" index: 1,
} resources: buildResourceIndex().index,
}, confirmStepDeletion: false,
dispatch: jest.fn(), });
index: 1,
resources,
confirmStepDeletion: false,
};
};
describe("<TileReboot/>", () => { describe("<TileReboot/>", () => {
it("renders", () => { it("renders", () => {
const el = render(<TileReboot {...fakeProps()} />); const block = render(<TileReboot {...fakeProps()} />);
const verbiage = el.text(); expect(block.text()).toContain(Content.REBOOT_STEP);
expect(verbiage).toContain("Power cycle FarmBot's onboard computer.");
}); });
it("crashes if the step is of the wrong `kind`", () => { it("crashes if the step is of the wrong `kind`", () => {
const props = fakeProps(); const p = fakeProps();
props.currentStep = { kind: "sync", args: {} }; p.currentStep = { kind: "sync", args: {} };
const boom = () => TileReboot(props); const boom = () => TileReboot(p);
expect(boom).toThrowError(); expect(boom).toThrowError();
}); });
it("edits the reboot step", () => { it("edits the reboot step", () => {
const props = fakeProps(); const p = fakeProps();
const editFn = editTheRebootStep(props); const editFn = editTheRebootStep(p);
editFn("arduino_firmware"); editFn("arduino_firmware");
expect(props.dispatch).toHaveBeenCalled(); expect(p.dispatch).toHaveBeenCalled();
expect(editStep).toHaveBeenCalledWith({ expect(editStep).toHaveBeenCalledWith({
step: props.currentStep, step: p.currentStep,
index: props.index, index: p.index,
sequence: props.currentSequence, sequence: p.currentSequence,
executor: expect.any(Function), executor: expect.any(Function),
}); });
}); });
it("executes the executor", () => { it("executes the executor", () => {
const props = fakeProps(); const p = fakeProps();
const step = props.currentStep as Reboot; const step = p.currentStep as Reboot;
step.args.package = "X"; step.args.package = "X";
const fn = rebootExecutor("arduino_firmware"); const fn = rebootExecutor("arduino_firmware");
fn(step); fn(step);

View File

@ -0,0 +1,29 @@
import * as React from "react";
import { mount } from "enzyme";
import { TileShutdown } from "../tile_shutdown";
import { fakeSequence } from "../../../__test_support__/fake_state/resources";
import { PowerOff } from "farmbot";
import { emptyState } from "../../../resources/reducer";
import { StepParams } from "../../interfaces";
import { Content } from "../../../constants";
describe("<TileShutdown />", () => {
const currentStep: PowerOff = {
kind: "power_off",
args: {},
};
const fakeProps = (): StepParams => ({
currentSequence: fakeSequence(),
currentStep: currentStep,
dispatch: jest.fn(),
index: 0,
resources: emptyState().index,
confirmStepDeletion: false,
});
it("renders step", () => {
const block = mount(<TileShutdown {...fakeProps()} />);
expect(block.text()).toContain(Content.SHUTDOWN_STEP);
});
});

View File

@ -34,6 +34,7 @@ import { TileAssertion } from "./tile_assertion";
import { TileEmergencyStop } from "./tile_emergency_stop"; import { TileEmergencyStop } from "./tile_emergency_stop";
import { TileReboot } from "./tile_reboot"; import { TileReboot } from "./tile_reboot";
import { TileOldMarkAs } from "./tile_old_mark_as"; import { TileOldMarkAs } from "./tile_old_mark_as";
import { TileShutdown } from "./tile_shutdown";
interface MoveParams { interface MoveParams {
step: Step; step: Step;
@ -161,7 +162,8 @@ export function renderCeleryNode(props: StepParams) {
case "reboot": return <TileReboot {...props} />; case "reboot": return <TileReboot {...props} />;
case "emergency_lock": return <TileEmergencyStop {...props} />; case "emergency_lock": return <TileEmergencyStop {...props} />;
case "assertion": return <TileAssertion {...props} />; case "assertion": return <TileAssertion {...props} />;
case "sync": case "power_off": case "read_status": case "power_off": return <TileShutdown {...props} />;
case "sync": case "read_status":
case "emergency_unlock": case "install_first_party_farmware": case "emergency_unlock": case "install_first_party_farmware":
return <TileSystemAction {...props} />; return <TileSystemAction {...props} />;
case "check_updates": case "factory_reset": case "check_updates": case "factory_reset":

View File

@ -7,6 +7,7 @@ import { TypePart } from "./tile_assertion/type_part";
import { LuaPart } from "./tile_assertion/lua_part"; import { LuaPart } from "./tile_assertion/lua_part";
import { SequencePart } from "./tile_assertion/sequence_part"; import { SequencePart } from "./tile_assertion/sequence_part";
import { Assertion } from "farmbot/dist/corpus"; import { Assertion } from "farmbot/dist/corpus";
import { ToolTips } from "../../constants";
export interface AssertionStepProps extends StepParams { export interface AssertionStepProps extends StepParams {
currentStep: Assertion; currentStep: Assertion;
@ -24,7 +25,7 @@ export function TileAssertion(props: StepParams) {
return <StepWrapper> return <StepWrapper>
<StepHeader <StepHeader
className={CLASS_NAME} className={CLASS_NAME}
helpText={""} helpText={ToolTips.ASSERTION}
currentSequence={p.currentSequence} currentSequence={p.currentSequence}
currentStep={p.currentStep} currentStep={p.currentStep}
dispatch={p.dispatch} dispatch={p.dispatch}

View File

@ -1,6 +1,6 @@
import * as React from "react"; import * as React from "react";
import { StepParams } from "../interfaces"; import { StepParams } from "../interfaces";
import { ToolTips } from "../../constants"; import { ToolTips, Content } from "../../constants";
import { StepWrapper, StepHeader, StepContent } from "../step_ui"; import { StepWrapper, StepHeader, StepContent } from "../step_ui";
import { Col, Row } from "../../ui/index"; import { Col, Row } from "../../ui/index";
import { t } from "../../i18next_wrapper"; import { t } from "../../i18next_wrapper";
@ -21,7 +21,7 @@ export function TileEmergencyStop(props: StepParams) {
<Row> <Row>
<Col xs={12}> <Col xs={12}>
<p> <p>
{t("Unlocking a device requires user intervention.")} {t(Content.ESTOP_STEP)}
</p> </p>
</Col> </Col>
</Row> </Row>

View File

@ -1,6 +1,6 @@
import * as React from "react"; import * as React from "react";
import { StepParams } from "../interfaces"; import { StepParams } from "../interfaces";
import { ToolTips } from "../../constants"; import { Content } from "../../constants";
import { StepWrapper, StepHeader, StepContent } from "../step_ui/index"; import { StepWrapper, StepHeader, StepContent } from "../step_ui/index";
import { t } from "../../i18next_wrapper"; import { t } from "../../i18next_wrapper";
import { ALLOWED_PACKAGES, SequenceBodyItem, Reboot } from "farmbot"; import { ALLOWED_PACKAGES, SequenceBodyItem, Reboot } from "farmbot";
@ -44,7 +44,7 @@ export function TileReboot(props: StepParams) {
return <StepWrapper> return <StepWrapper>
<StepHeader <StepHeader
className={className} className={className}
helpText={ToolTips.REBOOT} helpText={Content.RESTART_FARMBOT}
currentSequence={currentSequence} currentSequence={currentSequence}
currentStep={currentStep} currentStep={currentStep}
dispatch={dispatch} dispatch={dispatch}
@ -52,7 +52,7 @@ export function TileReboot(props: StepParams) {
confirmStepDeletion={props.confirmStepDeletion} /> confirmStepDeletion={props.confirmStepDeletion} />
<StepContent className={className}> <StepContent className={className}>
<p> <p>
{t(ToolTips.REBOOT)} {t(Content.REBOOT_STEP)}
</p> </p>
{/* <StepRadio {/* <StepRadio
choices={Object.keys(PACKAGE_CHOICES())} choices={Object.keys(PACKAGE_CHOICES())}

View File

@ -0,0 +1,23 @@
import * as React from "react";
import { StepParams } from "../interfaces";
import { Content } from "../../constants";
import { StepWrapper, StepHeader, StepContent } from "../step_ui/index";
import { t } from "../../i18next_wrapper";
export function TileShutdown(props: StepParams) {
const { dispatch, currentStep, index, currentSequence } = props;
const className = "shutdown-step";
return <StepWrapper>
<StepHeader
className={className}
helpText={Content.SHUTDOWN_FARMBOT}
currentSequence={currentSequence}
currentStep={currentStep}
dispatch={dispatch}
index={index}
confirmStepDeletion={props.confirmStepDeletion} />
<StepContent className={className}>
<p>{t(Content.SHUTDOWN_STEP)}</p>
</StepContent>
</StepWrapper>;
}