diff --git a/frontend/constants.ts b/frontend/constants.ts
index e778b7e00..49bc3ffeb 100644
--- a/frontend/constants.ts
+++ b/frontend/constants.ts
@@ -346,7 +346,7 @@ export namespace ToolTips {
trim(`The Mark As step allows FarmBot to programmatically edit the
properties of the UTM, plants, and weeds from within a sequence.
For example, you can mark a plant as "planted" during a seeding
- sequence or delete a weed after removing it.`);
+ sequence or mark a weed as "removed" after removing it.`);
export const REBOOT =
trim(`Power cycle FarmBot's onboard computer.`);
diff --git a/frontend/css/steps.scss b/frontend/css/steps.scss
index 1d91cd6eb..d8dc65365 100644
--- a/frontend/css/steps.scss
+++ b/frontend/css/steps.scss
@@ -106,7 +106,7 @@
&.take-photo-step {
background: $brown;
}
- &.resource-update-step {
+ &.update-resource-step {
background: $brown;
}
&.set-servo-angle-step {
@@ -226,7 +226,7 @@
&.take-photo-step a {
color: $dark_brown;
}
- &.resource-update-step {
+ &.update-resource-step {
background: $light_brown;
}
&.set-servo-angle-step {
diff --git a/frontend/devices/interfaces.ts b/frontend/devices/interfaces.ts
index b644b80a9..55320c32d 100644
--- a/frontend/devices/interfaces.ts
+++ b/frontend/devices/interfaces.ts
@@ -81,6 +81,7 @@ export enum Feature {
ota_update_hour = "ota_update_hour",
rpi_led_control = "rpi_led_control",
sensors = "sensors",
+ update_resource = "update_resource",
use_update_channel = "use_update_channel",
variables = "variables",
}
diff --git a/frontend/sequences/__tests__/sequence_editor_middle_active_test.tsx b/frontend/sequences/__tests__/sequence_editor_middle_active_test.tsx
index 1e16408d6..df6162da9 100644
--- a/frontend/sequences/__tests__/sequence_editor_middle_active_test.tsx
+++ b/frontend/sequences/__tests__/sequence_editor_middle_active_test.tsx
@@ -1,3 +1,5 @@
+jest.mock("../../history", () => ({ push: jest.fn() }));
+
jest.mock("../../api/crud", () => ({
destroy: jest.fn(),
save: jest.fn(),
@@ -55,6 +57,7 @@ import { DropAreaProps } from "../../draggable/interfaces";
import { Actions } from "../../constants";
import { setWebAppConfigValue } from "../../config_storage/actions";
import { BooleanSetting } from "../../session_keys";
+import { push } from "../../history";
describe("", () => {
const fakeProps = (): ActiveMiddleProps => {
@@ -73,10 +76,13 @@ describe("", () => {
};
};
- it("saves", () => {
- const wrapper = mount();
- clickButton(wrapper, 0, "Save * ");
+ it("saves", async () => {
+ const p = fakeProps();
+ p.dispatch = () => Promise.resolve();
+ const wrapper = mount();
+ await clickButton(wrapper, 0, "Save * ");
expect(save).toHaveBeenCalledWith(expect.stringContaining("Sequence"));
+ expect(push).toHaveBeenCalledWith("/app/sequences/fake");
});
it("tests", () => {
diff --git a/frontend/sequences/locals_list/handle_select.ts b/frontend/sequences/locals_list/handle_select.ts
index 1f03ac1a6..1a6023eb4 100644
--- a/frontend/sequences/locals_list/handle_select.ts
+++ b/frontend/sequences/locals_list/handle_select.ts
@@ -66,32 +66,45 @@ interface NewVarProps {
newVarLabel?: string;
}
-const nothingVar =
- ({ identifierLabel: label, allowedVariableNodes }: NewVarProps): VariableWithAValue =>
- createVariableNode(allowedVariableNodes)(label, NOTHING_SELECTED);
+const nothingVar = ({
+ identifierLabel: label, allowedVariableNodes
+}: NewVarProps): VariableWithAValue =>
+ createVariableNode(allowedVariableNodes)(label, NOTHING_SELECTED);
-const toolVar = (value: string | number) =>
- ({ identifierLabel: label, allowedVariableNodes }: NewVarProps): VariableWithAValue =>
- createVariableNode(allowedVariableNodes)(label, {
- kind: "tool",
- args: { tool_id: parseInt("" + value) }
- });
+const toolVar = (value: string | number) => ({
+ identifierLabel: label, allowedVariableNodes
+}: NewVarProps): VariableWithAValue =>
+ createVariableNode(allowedVariableNodes)(label, {
+ kind: "tool",
+ args: { tool_id: parseInt("" + value) }
+ });
const pointVar = (
pointer_type: "Plant" | "GenericPointer" | "Weed",
value: string | number,
-) => ({ identifierLabel: label, allowedVariableNodes }: NewVarProps): VariableWithAValue =>
+) => ({
+ identifierLabel: label, allowedVariableNodes
+}: NewVarProps): VariableWithAValue =>
createVariableNode(allowedVariableNodes)(label, {
kind: "point",
args: { pointer_type, pointer_id: parseInt("" + value) }
});
-const manualEntry = (value: string | number) =>
- ({ identifierLabel: label, allowedVariableNodes }: NewVarProps): VariableWithAValue =>
- createVariableNode(allowedVariableNodes)(label, {
- kind: "coordinate",
- args: value ? JSON.parse("" + value) : { x: 0, y: 0, z: 0 }
- });
+const groupVar = (value: string | number) => ({
+ identifierLabel: label, allowedVariableNodes
+}: NewVarProps): VariableWithAValue =>
+ createVariableNode(allowedVariableNodes)(label, {
+ kind: "point_group",
+ args: { point_group_id: parseInt("" + value) }
+ });
+
+const manualEntry = (value: string | number) => ({
+ identifierLabel: label, allowedVariableNodes
+}: NewVarProps): VariableWithAValue =>
+ createVariableNode(allowedVariableNodes)(label, {
+ kind: "coordinate",
+ args: value ? JSON.parse("" + value) : { x: 0, y: 0, z: 0 }
+ });
/**
* Create a parameter declaration or a parameter application containing an
@@ -129,15 +142,7 @@ const createNewVariable = (props: NewVarProps): VariableNode | undefined => {
case "Tool": return toolVar(ddi.value)(props);
case "parameter": return newParameter(props);
case "Coordinate": return manualEntry(ddi.value)(props);
- case "PointGroup":
- const point_group_id = parseInt("" + ddi.value, 10);
- return {
- kind: "parameter_application",
- args: {
- label: props.identifierLabel,
- data_value: { kind: "point_group", args: { point_group_id } }
- }
- };
+ case "PointGroup": return groupVar(ddi.value)(props);
}
console.error("WARNING: Don't know how to handle " + (ddi.headingId || "NA"));
return undefined;
diff --git a/frontend/sequences/sequence_editor_middle_active.tsx b/frontend/sequences/sequence_editor_middle_active.tsx
index 66695a79f..479b7656b 100644
--- a/frontend/sequences/sequence_editor_middle_active.tsx
+++ b/frontend/sequences/sequence_editor_middle_active.tsx
@@ -12,7 +12,7 @@ import { save, edit, destroy } from "../api/crud";
import { TestButton } from "./test_button";
import { AllSteps } from "./all_steps";
import { LocalsList, localListCallback } from "./locals_list/locals_list";
-import { betterCompact } from "../util";
+import { betterCompact, urlFriendly } from "../util";
import { AllowedVariableNodes } from "./locals_list/locals_list_support";
import { ResourceIndex } from "../resources/interfaces";
import { ShouldDisplay } from "../devices/interfaces";
@@ -135,7 +135,8 @@ const SequenceBtnGroup = ({
}: SequenceBtnGroupProps) =>
dispatch(save(sequence.uuid))} />
+ onClick={() => dispatch(save(sequence.uuid)).then(() =>
+ push(`/app/sequences/${urlFriendly(sequence.body.name)}`))} />
);
- shouldDisplay(Feature.mark_as_step) && ALL_THE_BUTTONS.push(
{t("Mark As...")}
diff --git a/frontend/sequences/step_tiles/__tests__/index_test.ts b/frontend/sequences/step_tiles/__tests__/index_test.ts
index 4515b18e5..7201d313c 100644
--- a/frontend/sequences/step_tiles/__tests__/index_test.ts
+++ b/frontend/sequences/step_tiles/__tests__/index_test.ts
@@ -147,17 +147,32 @@ describe("renderCeleryNode()", () => {
node: { kind: "wait", args: { milliseconds: 100 } },
expected: "milliseconds"
},
+ {
+ node: {
+ kind: "update_resource",
+ args: {
+ resource: {
+ kind: "resource",
+ args: { resource_id: 23, resource_type: "Plant" }
+ },
+ body: [
+ { kind: "pair", args: { label: "plant_stage", value: "planted" } },
+ ]
+ }
+ },
+ expected: "markplant 23 as"
+ },
{
node: {
kind: "resource_update",
args: {
resource_id: 23,
resource_type: "Plant",
- label: "x",
- value: 300
+ label: "plant_stage",
+ value: "planted",
}
},
- expected: "MarkPlantasx = 300"
+ expected: "mark plant 23 plant_stage as plantedthis step has been deprecated."
},
{
node: { kind: "set_servo_angle", args: { pin_number: 4, pin_value: 90 } },
diff --git a/frontend/sequences/step_tiles/__tests__/tile_old_mark_as_test.tsx b/frontend/sequences/step_tiles/__tests__/tile_old_mark_as_test.tsx
new file mode 100644
index 000000000..91737bf58
--- /dev/null
+++ b/frontend/sequences/step_tiles/__tests__/tile_old_mark_as_test.tsx
@@ -0,0 +1,106 @@
+const mockEditStep = jest.fn();
+jest.mock("../../../api/crud", () => ({
+ editStep: mockEditStep
+}));
+
+import * as React from "react";
+import { mount } from "enzyme";
+import { TileOldMarkAs } from "../tile_old_mark_as";
+import { fakeSequence } from "../../../__test_support__/fake_state/resources";
+import { emptyState } from "../../../resources/reducer";
+import { StepParams } from "../../interfaces";
+import { editStep } from "../../../api/crud";
+import { SequenceBodyItem } from "farmbot";
+import { cloneDeep } from "lodash";
+
+describe("", () => {
+ const currentStep = {
+ kind: "resource_update",
+ args: {
+ resource_type: "Device",
+ resource_id: 0,
+ label: "mounted_tool_id",
+ value: 0,
+ }
+ } as unknown as SequenceBodyItem;
+
+ const fakeProps = (): StepParams => ({
+ currentSequence: fakeSequence(),
+ currentStep: currentStep,
+ dispatch: jest.fn(),
+ index: 0,
+ resources: emptyState().index,
+ confirmStepDeletion: false,
+ });
+
+ it("renders deprecation notice", () => {
+ const block = mount();
+ expect(block.text()).toContain("deprecated");
+ expect(block.text()).not.toContain("convert");
+ });
+
+ it("renders deprecation notice and convert button", () => {
+ const p = fakeProps();
+ p.shouldDisplay = () => true;
+ const block = mount();
+ expect(block.text()).toContain("deprecated");
+ expect(block.text()).toContain("convert");
+ });
+
+ it("converts set mounted tool step", () => {
+ const p = fakeProps();
+ p.shouldDisplay = () => true;
+ const block = mount();
+ expect(block.text()).toContain("deprecated");
+ expect(block.text()).toContain("convert");
+ block.find("button").last().simulate("click");
+ expect(editStep).toHaveBeenCalled();
+ const step = cloneDeep(p.currentStep);
+ mockEditStep.mock.calls[0][0].executor(step);
+ expect(step).toEqual({
+ kind: "update_resource",
+ args: {
+ resource: {
+ kind: "resource",
+ args: { resource_type: "Device", resource_id: 0 }
+ }
+ },
+ body: [{
+ kind: "pair", args: { label: "mounted_tool_id", value: 0 }
+ }],
+ });
+ });
+
+ it("converts remove weed step", () => {
+ const p = fakeProps();
+ p.currentStep = {
+ kind: "resource_update",
+ args: {
+ resource_type: "Weed",
+ resource_id: 123,
+ label: "discarded_at",
+ value: "?",
+ }
+ } as unknown as SequenceBodyItem;
+ p.shouldDisplay = () => true;
+ const block = mount();
+ expect(block.text()).toContain("deprecated");
+ expect(block.text()).toContain("convert");
+ block.find("button").last().simulate("click");
+ expect(editStep).toHaveBeenCalled();
+ const step = cloneDeep(p.currentStep);
+ mockEditStep.mock.calls[0][0].executor(step);
+ expect(step).toEqual({
+ kind: "update_resource",
+ args: {
+ resource: {
+ kind: "resource",
+ args: { resource_type: "Weed", resource_id: 123 }
+ }
+ },
+ body: [{
+ kind: "pair", args: { label: "plant_stage", value: "removed" }
+ }],
+ });
+ });
+});
diff --git a/frontend/sequences/step_tiles/index.tsx b/frontend/sequences/step_tiles/index.tsx
index fc68fea1f..09e0442cf 100644
--- a/frontend/sequences/step_tiles/index.tsx
+++ b/frontend/sequences/step_tiles/index.tsx
@@ -1,7 +1,7 @@
import * as React from "react";
import {
CeleryNode, LegalArgString, If, Execute, Nothing,
- SequenceBodyItem as Step, TaggedSequence,
+ SequenceBodyItem as Step, TaggedSequence, LegalSequenceKind,
} from "farmbot";
import { FLOAT_NUMERIC_FIELDS, NUMERIC_FIELDS } from "../interfaces";
import { ExecuteBlock } from "./tile_execute";
@@ -33,6 +33,7 @@ import { t } from "../../i18next_wrapper";
import { TileAssertion } from "./tile_assertion";
import { TileEmergencyStop } from "./tile_emergency_stop";
import { TileReboot } from "./tile_reboot";
+import { TileOldMarkAs } from "./tile_old_mark_as";
interface MoveParams {
step: Step;
@@ -149,7 +150,9 @@ export function renderCeleryNode(props: StepParams) {
case "take_photo": return ;
case "wait": return ;
case "write_pin": return ;
- case "resource_update": return ;
+ case "update_resource": return ;
+ case "resource_update" as LegalSequenceKind:
+ return ;
case "set_servo_angle": return ;
case "toggle_pin": return ;
case "zero": return ;
diff --git a/frontend/sequences/step_tiles/mark_as.tsx b/frontend/sequences/step_tiles/mark_as.tsx
index 598efeb07..305ef2cd4 100644
--- a/frontend/sequences/step_tiles/mark_as.tsx
+++ b/frontend/sequences/step_tiles/mark_as.tsx
@@ -4,7 +4,7 @@ import { StepWrapper, StepHeader, StepContent } from "../step_ui/index";
import { ToolTips } from "../../constants";
import * as React from "react";
import { unpackStep } from "./mark_as/unpack_step";
-import { ResourceUpdate } from "farmbot";
+import { UpdateResource } from "farmbot";
import { resourceList } from "./mark_as/resource_list";
import { actionList } from "./mark_as/action_list";
import { commitStepChanges } from "./mark_as/commit_step_changes";
@@ -15,7 +15,7 @@ const NONE = (): DropDownItem => ({ label: t("Select one"), value: 0 });
export class MarkAs extends React.Component {
state: MarkAsState = { nextResource: undefined };
- className = "resource-update-step";
+ className = "update-resource-step";
commitSelection = (nextAction: DropDownItem) => {
this.props.dispatch(commitStepChanges({
@@ -23,13 +23,13 @@ export class MarkAs extends React.Component {
nextAction,
nextResource: this.state.nextResource,
sequence: this.props.currentSequence,
- step: this.props.currentStep as ResourceUpdate,
+ step: this.props.currentStep as UpdateResource,
}));
this.setState({ nextResource: undefined });
};
render() {
- const step = this.props.currentStep as ResourceUpdate;
+ const step = this.props.currentStep as UpdateResource;
const { rightSide, leftSide } =
unpackStep({ step, resourceIndex: this.props.resources });
return
@@ -54,7 +54,8 @@ export class MarkAs extends React.Component {
diff --git a/frontend/sequences/step_tiles/mark_as/__tests__/action_list_test.ts b/frontend/sequences/step_tiles/mark_as/__tests__/action_list_test.ts
index 04d6d33c8..df3524d88 100644
--- a/frontend/sequences/step_tiles/mark_as/__tests__/action_list_test.ts
+++ b/frontend/sequences/step_tiles/mark_as/__tests__/action_list_test.ts
@@ -1,5 +1,5 @@
import { actionList } from "../action_list";
-import { resourceUpdate, markAsResourceFixture } from "../assertion_support";
+import { updateResource, markAsResourceFixture } from "../test_support";
import {
buildResourceIndex,
} from "../../../../__test_support__/resource_index_builder";
@@ -7,7 +7,10 @@ import { PLANT_OPTIONS } from "../constants";
describe("actionList()", () => {
it("uses args.resource_type if DropDownItem is undefined", () => {
- const step = resourceUpdate({ resource_type: "Plant" });
+ const step = updateResource({
+ kind: "resource",
+ args: { resource_type: "Plant", resource_id: 0 }
+ });
const { index } = markAsResourceFixture();
const result = actionList(undefined, step, index);
expect(result).toEqual(PLANT_OPTIONS());
@@ -15,9 +18,9 @@ describe("actionList()", () => {
it("provides a list of tool mount actions", () => {
const ddi = { label: "test case", value: 1, headingId: "Device" };
- const step = resourceUpdate({});
+ const step = updateResource();
const { index } = markAsResourceFixture();
- const result = actionList(ddi, step, index);
+ const result = actionList(ddi.headingId, step, index);
expect(result.length).toBe(3);
const labels = result.map(x => x.label);
expect(labels).toContain("Not Mounted");
@@ -27,9 +30,9 @@ describe("actionList()", () => {
it("provides a list of generic pointer actions", () => {
const ddi = { label: "test case", value: 1, headingId: "GenericPointer" };
- const step = resourceUpdate({});
+ const step = updateResource();
const { index } = markAsResourceFixture();
- const result = actionList(ddi, step, index);
+ const result = actionList(ddi.headingId, step, index);
expect(result.length).toBe(1);
const labels = result.map(x => x.label);
expect(labels).toContain("Removed");
@@ -37,19 +40,26 @@ describe("actionList()", () => {
it("provides a list of weed pointer actions", () => {
const ddi = { label: "test case", value: 1, headingId: "Weed" };
- const step = resourceUpdate({});
+ const step = updateResource();
const { index } = markAsResourceFixture();
- const result = actionList(ddi, step, index);
+ const result = actionList(ddi.headingId, step, index);
expect(result.length).toBe(1);
const labels = result.map(x => x.label);
expect(labels).toContain("Removed");
});
- it("returns an empty list for all other options", () => {
+ it("returns an empty list for identifiers", () => {
const ddi = { label: "test case", value: 1, headingId: "USB Cables" };
- const step = resourceUpdate({});
+ const step = updateResource();
const { index } = buildResourceIndex([]);
- const result = actionList(ddi, step, index);
+ const result = actionList(ddi.headingId, step, index);
+ expect(result.length).toBe(0);
+ });
+
+ it("returns an empty list for all other options", () => {
+ const step = updateResource({ kind: "identifier", args: { label: "var" } });
+ const { index } = buildResourceIndex([]);
+ const result = actionList("Other", step, index);
expect(result.length).toBe(0);
});
});
diff --git a/frontend/sequences/step_tiles/mark_as/__tests__/commit_selection_test.ts b/frontend/sequences/step_tiles/mark_as/__tests__/commit_selection_test.ts
index 6b537f3bf..8e79ebbdb 100644
--- a/frontend/sequences/step_tiles/mark_as/__tests__/commit_selection_test.ts
+++ b/frontend/sequences/step_tiles/mark_as/__tests__/commit_selection_test.ts
@@ -1,6 +1,6 @@
-import { fakeMarkAsProps } from "../assertion_support";
+import { fakeMarkAsProps } from "../test_support";
import { commitStepChanges } from "../commit_step_changes";
-import { ResourceUpdate, TaggedSequence } from "farmbot";
+import { UpdateResource, TaggedSequence } from "farmbot";
import { Actions } from "../../../../constants";
import { unpackUUID } from "../../../../util";
@@ -10,7 +10,7 @@ describe("commitSelection", () => {
const results = commitStepChanges({
nextAction: { label: "X", value: "some_action" },
nextResource: undefined,
- step: p.currentStep as ResourceUpdate,
+ step: p.currentStep as UpdateResource,
index: p.index,
sequence: p.currentSequence
});
@@ -19,7 +19,7 @@ describe("commitSelection", () => {
expect(unpackUUID(payload.uuid).kind).toBe("Sequence");
const s = payload.update as TaggedSequence["body"];
expect(s.kind).toBe("sequence");
- const step = (s.body || [])[0] as ResourceUpdate;
- expect(step.args.value).toBe("some_action");
+ const step = (s.body || [])[0] as UpdateResource;
+ expect(step.body?.[0].args.value).toBe("some_action");
});
});
diff --git a/frontend/sequences/step_tiles/mark_as/__tests__/component_test.tsx b/frontend/sequences/step_tiles/mark_as/__tests__/component_test.tsx
index c3d645d10..52c76f866 100644
--- a/frontend/sequences/step_tiles/mark_as/__tests__/component_test.tsx
+++ b/frontend/sequences/step_tiles/mark_as/__tests__/component_test.tsx
@@ -7,7 +7,7 @@ import * as React from "react";
import { shallow, mount } from "enzyme";
import { MarkAs } from "../../mark_as";
import { FBSelect } from "../../../../ui";
-import { fakeMarkAsProps } from "../assertion_support";
+import { fakeMarkAsProps } from "../test_support";
import { commitStepChanges } from "../commit_step_changes";
describe("", () => {
diff --git a/frontend/sequences/step_tiles/mark_as/__tests__/pack_step_test.ts b/frontend/sequences/step_tiles/mark_as/__tests__/pack_step_test.ts
index 9b425cc60..1e4e03f8b 100644
--- a/frontend/sequences/step_tiles/mark_as/__tests__/pack_step_test.ts
+++ b/frontend/sequences/step_tiles/mark_as/__tests__/pack_step_test.ts
@@ -1,36 +1,45 @@
-import { resourceUpdate } from "../assertion_support";
+import { updateResource } from "../test_support";
import { packStep } from "../pack_step";
import { TOP_HALF } from "../constants";
+import { Resource, Identifier } from "farmbot";
describe("packStep()", () => {
- const plant = resourceUpdate({ resource_type: "Plant", resource_id: 6 });
-
- it("serializes 'discard' actions", () => {
- const actionDDI = { value: "removed", label: "Removed" };
- const { args } = packStep(plant, undefined, actionDDI);
- expect(args.label).toEqual("discarded_at");
- expect(args.value).toEqual("{{ Time.now }}");
- expect(args.resource_id).toEqual(6);
- expect(args.resource_type).toEqual("Plant");
+ const plant = updateResource({
+ kind: "resource",
+ args: { resource_type: "Plant", resource_id: 6 }
});
it("serializes 'plant_stage' actions", () => {
const actionDDI = { value: "harvested", label: "harvested" };
- const { args } = packStep(plant, undefined, actionDDI);
- expect(args.label).toEqual("plant_stage");
- expect(args.value).toEqual("harvested");
- expect(args.resource_id).toEqual(6);
- expect(args.resource_type).toEqual("Plant");
+ const { args, body } = packStep(plant, undefined, actionDDI);
+ expect(body?.[0].args.label).toEqual("plant_stage");
+ expect(body?.[0].args.value).toEqual("harvested");
+ expect((args.resource as Resource).args.resource_id).toEqual(6);
+ expect((args.resource as Resource).args.resource_type).toEqual("Plant");
});
it("serializes 'mounted_tool_id' actions", () => {
const resourceDDI = TOP_HALF[0];
const actionDDI = { value: 23, label: "Mounted to can opener" };
- const device = resourceUpdate({ resource_type: "Device", resource_id: 7 });
- const { args } = packStep(device, resourceDDI, actionDDI);
- expect(args.label).toEqual("mounted_tool_id");
- expect(args.resource_type).toEqual("Device");
- expect(args.resource_id).toEqual(0);
- expect(args.value).toEqual(23);
+ const device = updateResource({
+ kind: "resource",
+ args: { resource_type: "Device", resource_id: 7 }
+ });
+ const { args, body } = packStep(device, resourceDDI, actionDDI);
+ expect(body?.[0].args.label).toEqual("mounted_tool_id");
+ expect((args.resource as Resource).args.resource_type).toEqual("Device");
+ expect((args.resource as Resource).args.resource_id).toEqual(0);
+ expect(body?.[0].args.value).toEqual(23);
+ });
+
+ it("serializes 'plant_stage' actions: identifier", () => {
+ const actionDDI = { value: "harvested", label: "harvested" };
+ const identifier = updateResource({
+ kind: "identifier", args: { label: "var" }
+ });
+ const { args, body } = packStep(identifier, undefined, actionDDI);
+ expect(body?.[0].args.label).toEqual("plant_stage");
+ expect(body?.[0].args.value).toEqual("harvested");
+ expect((args.resource as Identifier).args.label).toEqual("var");
});
});
diff --git a/frontend/sequences/step_tiles/mark_as/__tests__/resource_list_test.ts b/frontend/sequences/step_tiles/mark_as/__tests__/resource_list_test.ts
index 41e882a62..1ba6019bb 100644
--- a/frontend/sequences/step_tiles/mark_as/__tests__/resource_list_test.ts
+++ b/frontend/sequences/step_tiles/mark_as/__tests__/resource_list_test.ts
@@ -1,5 +1,5 @@
import { resourceList } from "../resource_list";
-import { markAsResourceFixture } from "../assertion_support";
+import { markAsResourceFixture } from "../test_support";
describe("resourceList()", () => {
it("lists defaults, plus saved points", () => {
diff --git a/frontend/sequences/step_tiles/mark_as/__tests__/unpack_step_test.ts b/frontend/sequences/step_tiles/mark_as/__tests__/unpack_step_test.ts
index cc2375c36..9f95449c4 100644
--- a/frontend/sequences/step_tiles/mark_as/__tests__/unpack_step_test.ts
+++ b/frontend/sequences/step_tiles/mark_as/__tests__/unpack_step_test.ts
@@ -1,13 +1,13 @@
import { fakeResourceIndex } from "../../../locals_list/test_helpers";
-import { resourceUpdate } from "../assertion_support";
+import { updateResource } from "../test_support";
import { unpackStep, TOOL_MOUNT, DISMOUNTED } from "../unpack_step";
import {
selectAllPlantPointers,
selectAllTools,
- selectAllGenericPointers,
+ selectAllWeedPointers,
} from "../../../../resources/selectors";
import { DropDownPair } from "../interfaces";
-import { fakeTool } from "../../../../__test_support__/fake_state/resources";
+import { fakeTool, fakeWeed } from "../../../../__test_support__/fake_state/resources";
import {
buildResourceIndex,
} from "../../../../__test_support__/resource_index_builder";
@@ -25,7 +25,7 @@ describe("unpackStep()", () => {
it("unpacks empty tool_ids", () => {
const result = unpackStep({
- step: resourceUpdate({ label: "mounted_tool_id", value: 0 }),
+ step: updateResource(undefined, { label: "mounted_tool_id", value: 0 }),
resourceIndex: fakeResourceIndex()
});
expect(result).toEqual(DISMOUNTED());
@@ -37,7 +37,8 @@ describe("unpackStep()", () => {
expect(body).toBeTruthy();
const result = unpackStep({
- step: resourceUpdate({ label: "mounted_tool_id", value: body.id || NaN }),
+ step: updateResource(undefined,
+ { label: "mounted_tool_id", value: body.id || NaN }),
resourceIndex
});
const actionLabel = "Mounted to: Generic Tool";
@@ -54,7 +55,8 @@ describe("unpackStep()", () => {
expect(body).toBeTruthy();
const result = unpackStep({
- step: resourceUpdate({ label: "mounted_tool_id", value: body.id || NaN }),
+ step: updateResource(undefined,
+ { label: "mounted_tool_id", value: body.id || NaN }),
resourceIndex
});
const actionLabel = "Mounted to: Untitled Tool";
@@ -64,7 +66,8 @@ describe("unpackStep()", () => {
it("unpacks invalid tool_ids (that may have been valid previously)", () => {
const result = unpackStep({
- step: resourceUpdate({ label: "mounted_tool_id", value: Infinity }),
+ step: updateResource(undefined,
+ { label: "mounted_tool_id", value: Infinity }),
resourceIndex: fakeResourceIndex()
});
const actionLabel = "Mounted to: an unknown tool";
@@ -72,49 +75,70 @@ describe("unpackStep()", () => {
assertGoodness(result, actionLabel, "mounted", label, value);
});
- it("unpacks discarded_at operations", () => {
- const resourceIndex = fakeResourceIndex();
- const { body } = selectAllGenericPointers(resourceIndex)[0];
- expect(body.pointer_type).toBe("GenericPointer");
-
- const result = unpackStep({
- step: resourceUpdate({
- resource_type: "GenericPointer",
- resource_id: body.id || -1,
- label: "discarded_at",
- value: "non-configurable"
- }), resourceIndex
- });
- assertGoodness(result,
- "Removed",
- "removed",
- `${body.name} (${body.x}, ${body.y}, ${body.z})`,
- body.id || NaN);
- });
-
- it("unpacks plant_stage operations", () => {
+ it("unpacks plant_stage operations: plants", () => {
const resourceIndex = fakeResourceIndex();
const plant = selectAllPlantPointers(resourceIndex)[1];
expect(plant).toBeTruthy();
const result = unpackStep({
- step: resourceUpdate({
- resource_type: "Plant",
- resource_id: plant.body.id || -1,
- label: "plant_stage",
- value: "wilting"
- }), resourceIndex
+ step: updateResource({
+ kind: "resource",
+ args: { resource_type: "Plant", resource_id: plant.body.id || -1 }
+ },
+ { label: "plant_stage", value: "wilting" }),
+ resourceIndex
});
const { body } = plant;
const plantName = `${body.name} (${body.x}, ${body.y}, ${body.z})`;
assertGoodness(result, "wilting", "wilting", plantName, body.id || NaN);
});
- it("unpacks unknown resource_update steps", () => {
+ it("unpacks plant_stage operations: weeds", () => {
+ const resourceIndex = fakeResourceIndex([fakeWeed()]);
+ const weed = selectAllWeedPointers(resourceIndex)[1];
+ expect(weed).toBeTruthy();
+
const result = unpackStep({
- step: resourceUpdate({}),
+ step: updateResource({
+ kind: "resource",
+ args: { resource_type: "Weed", resource_id: weed.body.id || -1 }
+ },
+ { label: "plant_stage", value: "removed" }),
+ resourceIndex
+ });
+ const { body } = weed;
+ const plantName = `${body.name} (${body.x}, ${body.y}, ${body.z})`;
+ assertGoodness(result, "Removed", "removed", plantName, body.id || NaN);
+ });
+
+ it("unpacks plant_stage operations: identifier", () => {
+ const resourceIndex = fakeResourceIndex();
+ const result = unpackStep({
+ step: updateResource(
+ { kind: "identifier", args: { label: "var" } },
+ { label: "plant_stage", value: "removed" }),
+ resourceIndex
+ });
+ assertGoodness(result, "Removed", "removed", "var", "var");
+ });
+
+ it("unpacks unknown resource update_resource steps", () => {
+ const result = unpackStep({
+ step: updateResource(),
resourceIndex: fakeResourceIndex()
});
- assertGoodness(result, "some_attr = some_value", "some_value", "Other", 1);
+ assertGoodness(result,
+ "some_value", "some_value",
+ "Other 1 some_attr", "some_attr");
+ });
+
+ it("unpacks unknown identifier update_resource steps", () => {
+ const result = unpackStep({
+ step: updateResource({ kind: "identifier", args: { label: "var" } }),
+ resourceIndex: fakeResourceIndex()
+ });
+ assertGoodness(result,
+ "some_value", "some_value",
+ "variable 0 some_attr", "some_attr");
});
});
diff --git a/frontend/sequences/step_tiles/mark_as/action_list.ts b/frontend/sequences/step_tiles/mark_as/action_list.ts
index 60225c797..f19bf6d43 100644
--- a/frontend/sequences/step_tiles/mark_as/action_list.ts
+++ b/frontend/sequences/step_tiles/mark_as/action_list.ts
@@ -2,7 +2,7 @@ import { Dictionary } from "farmbot";
import { DropDownItem } from "../../../ui";
import { ListBuilder } from "./interfaces";
import { ResourceIndex } from "../../../resources/interfaces";
-import { ResourceUpdate } from "farmbot";
+import { UpdateResource } from "farmbot";
import { selectAllTools } from "../../../resources/selectors";
import {
MOUNTED_TO,
@@ -27,16 +27,19 @@ const DEFAULT = "Default";
const ACTION_LIST: Dictionary = {
"Device": (i) => [DISMOUNT(), ...allToolsAsDDI(i)],
"Plant": () => PLANT_OPTIONS(),
- "GenericPointer": () => POINT_OPTIONS,
- "Weed": () => POINT_OPTIONS,
+ "GenericPointer": () => POINT_OPTIONS(),
+ "Weed": () => POINT_OPTIONS(),
[DEFAULT]: () => []
};
-const getList =
- (t = DEFAULT): ListBuilder => (ACTION_LIST[t] || ACTION_LIST[DEFAULT]);
+const getList = (t: string): ListBuilder =>
+ (ACTION_LIST[t] || ACTION_LIST[DEFAULT]);
-export const actionList = (d: DropDownItem | undefined,
- r: ResourceUpdate,
+export const actionList = (d: string | undefined,
+ r: UpdateResource,
i: ResourceIndex): DropDownItem[] => {
- return getList(d ? d.headingId : r.args.resource_type)(i);
+ const resourceType = r.args.resource.kind == "identifier"
+ ? DEFAULT
+ : r.args.resource.args.resource_type;
+ return getList(d || resourceType)(i);
};
diff --git a/frontend/sequences/step_tiles/mark_as/commit_step_changes.ts b/frontend/sequences/step_tiles/mark_as/commit_step_changes.ts
index 1817060d6..2813cedbe 100644
--- a/frontend/sequences/step_tiles/mark_as/commit_step_changes.ts
+++ b/frontend/sequences/step_tiles/mark_as/commit_step_changes.ts
@@ -1,4 +1,4 @@
-import { ResourceUpdate } from "farmbot";
+import { UpdateResource } from "farmbot";
import { editStep } from "../../../api/crud";
import { packStep } from "./pack_step";
import { MarkAsEditProps } from "./interfaces";
@@ -11,8 +11,10 @@ export const commitStepChanges = (p: MarkAsEditProps) => {
step,
index,
sequence,
- executor(c: ResourceUpdate) {
- c.args = packStep(step, nextResource, nextAction).args;
+ executor(c: UpdateResource) {
+ const { args, body } = packStep(step, nextResource, nextAction);
+ c.args = args;
+ c.body = body;
}
});
};
diff --git a/frontend/sequences/step_tiles/mark_as/constants.ts b/frontend/sequences/step_tiles/mark_as/constants.ts
index 256ca247d..4216df74f 100644
--- a/frontend/sequences/step_tiles/mark_as/constants.ts
+++ b/frontend/sequences/step_tiles/mark_as/constants.ts
@@ -8,7 +8,7 @@ export const DISMOUNT = (): DropDownItem =>
({ label: t("Not Mounted"), value: 0 });
/** Legal "actions" for "Mark As.." block when marking Point resources */
-export const POINT_OPTIONS: DropDownItem[] = [
+export const POINT_OPTIONS = (): DropDownItem[] => [
{ label: t("Removed"), value: "removed" },
];
diff --git a/frontend/sequences/step_tiles/mark_as/interfaces.ts b/frontend/sequences/step_tiles/mark_as/interfaces.ts
index f312c50a7..e8bf92745 100644
--- a/frontend/sequences/step_tiles/mark_as/interfaces.ts
+++ b/frontend/sequences/step_tiles/mark_as/interfaces.ts
@@ -1,25 +1,29 @@
import { ResourceIndex } from "../../../resources/interfaces";
import { DropDownItem } from "../../../ui";
-import { ResourceUpdate, TaggedSequence } from "farmbot";
+import { UpdateResource, TaggedSequence, Resource, Identifier } from "farmbot";
/** Function that converts resources into dropdown selections based on
* use-case specific rules */
export type ListBuilder = (i: ResourceIndex) => DropDownItem[];
-/** Shape of step.args when step.kind = "resource_update" */
-export type ResourceUpdateArgs = Partial;
-
/** Input data for calls to commitStepChanges() */
export interface MarkAsEditProps {
nextAction: DropDownItem;
nextResource: DropDownItem | undefined;
- step: ResourceUpdate;
+ step: UpdateResource;
index: number;
sequence: TaggedSequence
}
-export interface StepWithResourceIndex {
- step: ResourceUpdate;
+export interface PackedStepWithResourceIndex {
+ step: UpdateResource;
+ resourceIndex: ResourceIndex;
+}
+
+export interface UnpackedStepWithResourceIndex {
+ resource: Resource | Identifier;
+ field: string;
+ value: string | number | boolean;
resourceIndex: ResourceIndex;
}
diff --git a/frontend/sequences/step_tiles/mark_as/pack_step.ts b/frontend/sequences/step_tiles/mark_as/pack_step.ts
index 5f657312b..e4121e858 100644
--- a/frontend/sequences/step_tiles/mark_as/pack_step.ts
+++ b/frontend/sequences/step_tiles/mark_as/pack_step.ts
@@ -1,4 +1,4 @@
-import { ResourceUpdate, resource_type as RESOURCE_TYPE } from "farmbot";
+import { UpdateResource, Resource, Identifier, resource_type } from "farmbot";
import { DropDownItem } from "../../../ui";
/**
@@ -8,43 +8,54 @@ import { DropDownItem } from "../../../ui";
* local changes as well as a copy of older data from the API.
*
* PROBLEM: You need to take the component's local state plus the
- * shape of the "resource_update" ("Mark As..") block and merge them
+ * shape of the "update_resource" ("Mark As..") block and merge them
* together so that you can render the form in the editor.
*
* SOLUTION: Use the celery node + pieces of the component's state (resourceDDI,
* actionDDI) to properly populate dropdown menus and determine the
- * shape of the new "resource_update" step when it is saved.
+ * shape of the new "update_resource" step when it is saved.
* */
-export const packStep =
- (csNode: ResourceUpdate,
- resourceDDI: DropDownItem | undefined,
- actionDDI: DropDownItem): ResourceUpdate => {
- const resource_type = (resourceDDI ?
- resourceDDI.headingId : csNode.args.resource_type) as RESOURCE_TYPE;
- const resource_id = (resourceDDI ?
- resourceDDI.value : csNode.args.resource_id) as number;
- switch (resource_type) {
+export const packStep = (
+ csNode: UpdateResource,
+ resourceDDI: DropDownItem | undefined,
+ actionDDI: DropDownItem,
+): UpdateResource => {
+ const resource = resourceDDI?.headingId
+ ? resourceNode(resourceDDI.headingId, resourceDDI.value)
+ : csNode.args.resource;
+ if (resource.kind == "identifier") {
+ return updateResource(resource, "plant_stage", actionDDI.value);
+ } else {
+ switch (resource.args.resource_type) {
case "Device":
/* Scenario I: Changing tool mount */
- return {
- kind: "resource_update",
- args: {
- resource_id,
- resource_type,
- label: "mounted_tool_id",
- value: actionDDI.value
- }
- };
-
+ return updateResource(resource, "mounted_tool_id", actionDDI.value);
default:
/* Scenario II: Changing a point */
- const label = "" +
- (actionDDI.value == "removed" ? "discarded_at" : "plant_stage");
- const value = "" +
- (label === "discarded_at" ? "{{ Time.now }}" : actionDDI.value);
- return {
- kind: "resource_update",
- args: { resource_id, resource_type, label, value }
- };
+ return updateResource(resource, "plant_stage", actionDDI.value);
}
- };
+ }
+};
+
+const resourceNode = (type: string, id: string | number): Resource => ({
+ kind: "resource",
+ args: {
+ resource_type: type as resource_type,
+ resource_id: parseInt("" + id),
+ }
+});
+
+const updateResource = (
+ resource: Resource | Identifier,
+ field: string,
+ value: string | number,
+): UpdateResource => ({
+ kind: "update_resource",
+ args: { resource },
+ body: [{
+ kind: "pair", args: {
+ label: field,
+ value: value,
+ }
+ }]
+});
diff --git a/frontend/sequences/step_tiles/mark_as/assertion_support.ts b/frontend/sequences/step_tiles/mark_as/test_support.ts
similarity index 60%
rename from frontend/sequences/step_tiles/mark_as/assertion_support.ts
rename to frontend/sequences/step_tiles/mark_as/test_support.ts
index 289b3be68..e618c0e72 100644
--- a/frontend/sequences/step_tiles/mark_as/assertion_support.ts
+++ b/frontend/sequences/step_tiles/mark_as/test_support.ts
@@ -1,4 +1,6 @@
-import { ResourceUpdate, TaggedSequence, resource_type } from "farmbot";
+import {
+ UpdateResource, TaggedSequence, resource_type, Pair, Resource, Identifier,
+} from "farmbot";
import {
buildResourceIndex,
} from "../../../__test_support__/resource_index_builder";
@@ -11,18 +13,26 @@ import {
} from "../../../__test_support__/fake_state/resources";
import { betterMerge } from "../../../util";
import { MarkAs } from "../mark_as";
-import { ResourceUpdateArgs } from "./interfaces";
-export function resourceUpdate(i: ResourceUpdateArgs): ResourceUpdate {
+export function updateResource(
+ resource?: Resource | Identifier, pairArgs?: Pair["args"]): UpdateResource {
return {
- kind: "resource_update",
+ kind: "update_resource",
args: {
- resource_type: "Other" as resource_type,
- resource_id: 1,
- label: "some_attr",
- value: "some_value",
- ...i
- }
+ resource: resource || {
+ kind: "resource", args: {
+ resource_type: "Other" as resource_type,
+ resource_id: 1,
+ }
+ },
+ },
+ body: [{
+ kind: "pair", args: {
+ label: "some_attr",
+ value: "some_value",
+ ...pairArgs,
+ }
+ }],
};
}
@@ -38,13 +48,14 @@ export const markAsResourceFixture = () => buildResourceIndex([
export function fakeMarkAsProps() {
const steps: TaggedSequence["body"]["body"] = [
{
- kind: "resource_update",
+ kind: "update_resource",
args: {
- resource_type: "Device",
- resource_id: 0,
- label: "mounted_tool_id",
- value: 0
- }
+ resource: {
+ kind: "resource",
+ args: { resource_id: 0, resource_type: "Device" }
+ }
+ },
+ body: [{ kind: "pair", args: { label: "mounted_tool_id", value: 0 } }],
},
];
const currentSequence: TaggedSequence =
diff --git a/frontend/sequences/step_tiles/mark_as/unpack_step.ts b/frontend/sequences/step_tiles/mark_as/unpack_step.ts
index fe04769b7..e0e702082 100644
--- a/frontend/sequences/step_tiles/mark_as/unpack_step.ts
+++ b/frontend/sequences/step_tiles/mark_as/unpack_step.ts
@@ -1,12 +1,17 @@
import { DropDownItem } from "../../../ui";
import {
- findToolById, findPointerByTypeAndId,
+ findToolById,
+ findPointerByTypeAndId,
} from "../../../resources/selectors";
import { point2ddi } from "./resource_list";
import { MOUNTED_TO } from "./constants";
-import { DropDownPair, StepWithResourceIndex } from "./interfaces";
+import {
+ DropDownPair, PackedStepWithResourceIndex, UnpackedStepWithResourceIndex,
+} from "./interfaces";
import { t } from "../../../i18next_wrapper";
-import { PLANT_STAGE_DDI_LOOKUP } from "../../../farm_designer/plants/edit_plant_status";
+import {
+ PLANT_STAGE_DDI_LOOKUP,
+} from "../../../farm_designer/plants/edit_plant_status";
export const TOOL_MOUNT = (): DropDownItem => ({
label: t("Tool Mount"), value: "tool_mount"
@@ -17,14 +22,13 @@ export const DISMOUNTED = (): DropDownPair => ({
rightSide: NOT_IN_USE()
});
const DEFAULT_TOOL_NAME = () => t("Untitled Tool");
-const REMOVED_ACTION = () => ({ label: t("Removed"), value: "removed" });
const mountedTo = (toolName = DEFAULT_TOOL_NAME()): DropDownItem =>
({ label: `${MOUNTED_TO()} ${toolName}`, value: "mounted" });
/** The user wants to change the `mounted_tool_id` of their Device. */
-function mountTool(i: StepWithResourceIndex): DropDownPair {
- const { value } = i.step.args;
+function mountTool(i: UnpackedStepWithResourceIndex): DropDownPair {
+ const { value } = i;
if (typeof value === "number" && value > 0) {
try { // Good tool id
const tool = findToolById(i.resourceIndex, value as number);
@@ -41,33 +45,34 @@ function mountTool(i: StepWithResourceIndex): DropDownPair {
/** When we can't properly guess the correct way to to render the screen,
* possibly for legacy reasons or because the user wrote their CeleryScript by
* hand. */
-function unknownOption(i: StepWithResourceIndex): DropDownPair {
- const { resource_type, resource_id, label, value } = i.step.args;
-
+function unknownOption(i: UnpackedStepWithResourceIndex): DropDownPair {
+ const { resource } = i;
+ const resource_type =
+ resource.kind == "resource" ? resource.args.resource_type : "variable";
+ const resource_id =
+ resource.kind == "resource" ? resource.args.resource_id : 0;
+ const { field, value } = i;
+ const leftLabel = `${resource_type} ${resource_id} ${field}`;
return {
- leftSide: { label: resource_type, value: resource_id },
- rightSide: { label: `${label} = ${value}`, value: "" + value }
- };
-}
-
-/** The user wants to mark a the `discarded_at` attribute of a Point. */
-function discardPoint(i: StepWithResourceIndex): DropDownPair {
- const { resource_id, resource_type } = i.step.args;
- const pointerBody =
- findPointerByTypeAndId(i.resourceIndex, resource_type, resource_id).body;
- return {
- leftSide: point2ddi(pointerBody),
- rightSide: REMOVED_ACTION(),
+ leftSide: { label: leftLabel, value: field },
+ rightSide: { label: "" + value, value: "" + value }
};
}
/** The user wants to mark a the `plant_stage` attribute of a Plant resource. */
-function plantStage(i: StepWithResourceIndex): DropDownPair {
- const { resource_id, resource_type, value } = i.step.args;
- const pointerBody =
- findPointerByTypeAndId(i.resourceIndex, resource_type, resource_id).body;
+function plantStage(i: UnpackedStepWithResourceIndex): DropDownPair {
+ const { resource } = i;
+ const resource_type =
+ resource.kind == "resource" ? resource.args.resource_type : "";
+ const resource_id =
+ resource.kind == "resource" ? resource.args.resource_id : 0;
+ const { value } = i;
+ const leftSide = resource.kind == "resource"
+ ? point2ddi(findPointerByTypeAndId(
+ i.resourceIndex, resource_type, resource_id).body)
+ : { label: "" + resource.args.label, value: "" + resource.args.label };
return {
- leftSide: point2ddi(pointerBody),
+ leftSide,
rightSide: PLANT_STAGE_DDI_LOOKUP()["" + value]
|| { label: "" + value, value: "" + value },
};
@@ -76,12 +81,14 @@ function plantStage(i: StepWithResourceIndex): DropDownPair {
/** We can guess how the "Mark As.." UI will be rendered (left and right side
* drop downs) based on the shape of the current step. There are several
* strategies and this function will dispatch the appropriate one. */
-export function unpackStep(i: StepWithResourceIndex): DropDownPair {
- const { label } = i.step.args;
- switch (label) {
- case "mounted_tool_id": return mountTool(i);
- case "discarded_at": return discardPoint(i);
- case "plant_stage": return plantStage(i);
- default: return unknownOption(i);
+export function unpackStep(p: PackedStepWithResourceIndex): DropDownPair {
+ const { resource } = p.step.args;
+ const { label, value } = p.step.body?.[0]?.args || { label: "", value: "" };
+ const field = label;
+ const unpacked = { resourceIndex: p.resourceIndex, resource, field, value };
+ switch (field) {
+ case "mounted_tool_id": return mountTool(unpacked);
+ case "plant_stage": return plantStage(unpacked);
+ default: return unknownOption(unpacked);
}
}
diff --git a/frontend/sequences/step_tiles/step_title_bar.tsx b/frontend/sequences/step_tiles/step_title_bar.tsx
index d77bdc8b9..cec15d60d 100644
--- a/frontend/sequences/step_tiles/step_title_bar.tsx
+++ b/frontend/sequences/step_tiles/step_title_bar.tsx
@@ -1,5 +1,7 @@
import * as React from "react";
-import { SequenceBodyItem as Step, SequenceBodyItem } from "farmbot";
+import {
+ SequenceBodyItem as Step, SequenceBodyItem, LegalSequenceKind,
+} from "farmbot";
import { StepTitleBarProps } from "../interfaces";
import { BlurableInput } from "../../ui/index";
import { updateStepTitle } from "./index";
@@ -19,7 +21,8 @@ function translate(input: Step): string {
"read_pin": t("Read Sensor"),
"send_message": t("Send Message"),
"take_photo": t("Take a Photo"),
- "resource_update": t("Mark As"),
+ "update_resource": t("Mark As"),
+ ["resource_update" as LegalSequenceKind]: t("Deprecated Mark As"),
"assertion": t("Assertion"),
"set_servo_angle": t("Control Servo"),
"wait": t("Wait"),
diff --git a/frontend/sequences/step_tiles/tile_old_mark_as.tsx b/frontend/sequences/step_tiles/tile_old_mark_as.tsx
new file mode 100644
index 000000000..bfe7e5512
--- /dev/null
+++ b/frontend/sequences/step_tiles/tile_old_mark_as.tsx
@@ -0,0 +1,61 @@
+import * as React from "react";
+import { StepParams } from "../interfaces";
+import { ToolTips } from "../../constants";
+import { StepWrapper, StepHeader, StepContent } from "../step_ui/index";
+import { editStep } from "../../api/crud";
+import { SequenceBodyItem, LegalArgString } from "farmbot";
+import { Feature } from "../../devices/interfaces";
+import { trim } from "../../util";
+
+const convertOldMarkAs = (oldStep: SequenceBodyItem) =>
+ (step: SequenceBodyItem) => {
+ const stepArgs = oldStep.args as Record;
+ step.kind = "update_resource";
+ step.args = {
+ resource: {
+ kind: "resource", args: {
+ resource_type: stepArgs.resource_type,
+ resource_id: stepArgs.resource_id,
+ }
+ }
+ };
+ const field = stepArgs.label;
+ step.body = [{
+ kind: "pair", args: {
+ label: field == "discarded_at" ? "plant_stage" : field,
+ value: field == "discarded_at" ? "removed" : stepArgs.value,
+ }
+ }];
+ };
+
+export function TileOldMarkAs(props: StepParams) {
+ const { dispatch, currentStep, index, currentSequence } = props;
+ const oldStepArgs = currentStep.args as Record;
+ const className = "update-resource-step";
+ return
+
+
+ {trim(`Mark ${oldStepArgs.resource_type} ${oldStepArgs.resource_id}
+ ${oldStepArgs.label} as ${oldStepArgs.value}`)}
+
+ {"This step has been deprecated."}
+ {props.shouldDisplay?.(Feature.update_resource) &&
+ }
+
+ ;
+}
diff --git a/package.json b/package.json
index d6409e772..b570b17fd 100644
--- a/package.json
+++ b/package.json
@@ -45,7 +45,7 @@
"coveralls": "3.0.11",
"enzyme": "3.11.0",
"enzyme-adapter-react-16": "1.15.2",
- "farmbot": "9.2.3",
+ "farmbot": "10.0.0-rc1",
"i18next": "19.4.1",
"install": "0.13.0",
"lodash": "4.17.15",