diff --git a/webpack/sequences/__tests__/locals_list_test.tsx b/webpack/sequences/__tests__/locals_list_test.tsx index d85b255ab..f678d0859 100644 --- a/webpack/sequences/__tests__/locals_list_test.tsx +++ b/webpack/sequences/__tests__/locals_list_test.tsx @@ -5,9 +5,6 @@ import { } from "../locals_list"; import { VariableDeclaration, - ParameterDeclaration, - Tool, - Point, Coordinate } from "farmbot"; import { @@ -23,12 +20,7 @@ import { InputBox, generateList, handleSelect } from "../step_tiles/tile_move_absolute/index"; import { - extractParent, - setParent, - guessFromDataType, - guessVecFromLabel, ParentVariableFormProps, - PARENT, LocalsListProps, } from "../locals_list_support"; import { DELETE_ME_LATER } from "../../resources/interfaces"; @@ -36,7 +28,6 @@ import { DELETE_ME_LATER } from "../../resources/interfaces"; const coord: Coordinate = { kind: "coordinate", args: { x: 1, y: 2, z: 3 } }; const t = fakeTool(); t.body.id = 5; -const tool: Tool = { kind: "tool", args: { tool_id: t.body.id } }; const mrGoodVar: VariableDeclaration = { // https://en.wikipedia.org/wiki/Mr._Goodbar kind: "variable_declaration", @@ -53,162 +44,10 @@ const fakeProps = (): LocalsListProps => { }; }; -describe("extractParent()", () => { - const irrelevant: VariableDeclaration = { - kind: "variable_declaration", - args: { label: "nope", data_value: coord } - }; - - const paramDeclr: ParameterDeclaration = { - kind: "parameter_declaration", - args: { label: "parent", data_type: "coordinate" } - }; - - it("returns undefined on empty arrays", () => { - expect(extractParent([])).toBeUndefined(); - expect(extractParent()).toBeUndefined(); - }); - - it("returns undefined on arrays that don't have a parent", () => { - expect(extractParent([irrelevant])).toBeUndefined(); - }); - - it("returns parent if it is a PARAMETER declaration.", () => { - const result = extractParent([paramDeclr]); - expect(result).toBeDefined(); - expect(result).toBe(paramDeclr); - }); - - it("returns the first result found", () => { - const paramIsFirst = [paramDeclr, mrGoodVar, irrelevant]; - const r1 = extractParent(paramIsFirst); - if (r1) { - expect(r1.kind).toBe("parameter_declaration"); - expect(r1.args.label).toBe("parent"); - } else { - fail(); - } - - const varIsFirst = [irrelevant, mrGoodVar, paramDeclr]; - const r2 = extractParent(varIsFirst); - if (r2) { - expect(r2.kind).toBe("variable_declaration"); - expect(r2.args.label).toBe("parent"); - } else { - fail(); - } - }); -}); - -describe("setParent()", () => { - const point: Point = { - kind: "point", - args: { pointer_type: "point", pointer_id: 5 } - }; - - it("deals with parameter declarations", () => { - const data_value: ParameterDeclaration = { - kind: "parameter_declaration", args: { label: "---", data_type: "point" } - }; - const sequence = fakeSequence(); - const expected = { - kind: "scope_declaration", - args: {}, - body: [{ - kind: "parameter_declaration", - args: { label: "parent", data_type: "point" } - }] - }; - const result = setParent(sequence, data_value); - const actual = result.args.locals; - - expect(actual.args).toEqual(expected.args); - expect(actual.body).toEqual(expected.body); - expect(actual.kind).toEqual(expected.kind); - }); - - it("crashes on `identifier` nodes (no re-binding of vars yet)", () => { - const seq = fakeSequence(); - const cb = () => - setParent(seq, { kind: "identifier", args: { label: "foo" } }); - expect(cb).toThrow(); - }); - - it("sets tools, points and coordinates as new `parent` var", () => { - const seq = fakeSequence(); - [tool, point, coord].map(item => { - const result = setParent(seq, item).args.locals.body || []; - expect(result.length).toEqual(1); - const parent = result[0]; - expect(parent.args.label).toEqual("parent"); - expect(parent.kind).toEqual("variable_declaration"); - (parent.kind === "variable_declaration") && - expect(parent.args.data_value).toBe(item); - }); - }); -}); - -describe("guessFromDataType()", () => { - it("returns undefined if not coord", () => { - expect(guessFromDataType(tool)).toBe(undefined); - }); - - it("returns coord.args", () => { - expect(guessFromDataType(coord)).toBe(coord.args); - }); -}); - -describe("guessVecFromLabel()", () => { - it("returns undefined on malformed strings", () => { - [ - "", - "))((1,(),2,3)", - " ()()()", - "Alphabetical (a, b, c)", - "tool 1,2,3", - "Something else (test123)", - "Tool_1512679072 ", - "Tool" - ].map(bad => { - expect(guessVecFromLabel(bad)).toBeUndefined(); - }); - }); - it("returns vec3 on well formed strings", () => { - [ - { - string: "Point_1512679072 (20, 50, 0)", - expectation: { x: 20, y: 50, z: 0 } - }, - { - string: "carrot (360, 290, 0)", - expectation: { x: 360, y: 290, z: 0 } - }, - { - string: "Safe-Remove Weed (633, 450, 0)", - expectation: { x: 633, y: 450, z: 0 } - }, - { - string: "Point_1512679072 (0, 100, 0)", - expectation: { x: 0, y: 100, z: 0 } - } - ].map(xmp => { - const result = guessVecFromLabel(xmp.string); - if (result) { - expect(result.x).toBe(xmp.expectation.x); - expect(result.y).toBe(xmp.expectation.y); - expect(result.y).toBe(xmp.expectation.y); - } else { - fail("No result obtained."); - } - }); - }); -}); - describe("", () => { it("renders correct UI components", () => { const props: ParentVariableFormProps = { - betterParent: DELETE_ME_LATER, - deprecatedParent: mrGoodVar, + parent: DELETE_ME_LATER, sequence: fakeSequence(), resources: buildResourceIndex().index, onChange: jest.fn() @@ -221,7 +60,7 @@ describe("", () => { expect(selects.length).toBe(1); const p = selects.first().props(); expect(p.allowEmpty).toBe(true); - const choices = generateList(props.resources, [PARENT]); + const choices = generateList(props.resources, []); expect(p.list).toEqual(choices); const choice = choices[1]; p.onChange(choice); diff --git a/webpack/sequences/locals_list.tsx b/webpack/sequences/locals_list.tsx index aace00dc2..3b28e14e1 100644 --- a/webpack/sequences/locals_list.tsx +++ b/webpack/sequences/locals_list.tsx @@ -1,15 +1,12 @@ import * as React from "react"; -import { - ParentVariableFormProps, - PARENT, - LocalsListProps -} from "./locals_list_support"; import { Row, Col, FBSelect } from "../ui"; import { t } from "i18next"; import { generateList } from "./step_tiles/tile_move_absolute/generate_list"; import { InputBox } from "./step_tiles/tile_move_absolute/input_box"; +import { handleSelect } from "./step_tiles/tile_move_absolute/handle_select"; +import { ParentVariableFormProps, LocalsListProps, PARENT } from "./locals_list_support"; const REWRITE_THIS = () => { console.error("Re write this callback, OK? RC"); @@ -19,9 +16,9 @@ const REWRITE_THIS = () => { * Allows the user to chose the value of the `parent` variable, etc. */ export const ParentVariableForm = (props: ParentVariableFormProps) => { - const { sequence, resources } = props; - const { x, y, z } = props.betterParent.location; - const isDisabled = !props.betterParent.editable; + const { sequence, resources, onChange } = props; + const { x, y, z } = props.parent.location; + const isDisabled = !props.parent.editable; return
@@ -31,11 +28,12 @@ export const ParentVariableForm = key={JSON.stringify(sequence)} allowEmpty={true} list={generateList(resources, [PARENT])} - selectedItem={props.betterParent.dropdown} - onChange={(x) => { - console.log("REIMPLEMENT ME:"); - console.dir(x); - } /> + selectedItem={props.parent.dropdown} + onChange={(ddi) => { + console.error("FINISH ME"); + handleSelect(props.resources, ddi); + onChange({ x: -23, y: -23, z: -23 }); + }} /> @@ -73,11 +71,10 @@ export const ParentVariableForm = /** List of local variable declarations for a sequence. If no variables are * found, shows nothing. */ export const LocalsList = (props: LocalsListProps) => { - const betterParent = props.variableData["parent"]; - return betterParent + const parent = props.variableData["parent"]; + return parent ? diff --git a/webpack/sequences/locals_list_support.ts b/webpack/sequences/locals_list_support.ts index 219e3977b..15fa5494f 100644 --- a/webpack/sequences/locals_list_support.ts +++ b/webpack/sequences/locals_list_support.ts @@ -1,18 +1,11 @@ import { - ParameterDeclaration, - VariableDeclaration, + TaggedSequence, Vector3, - ScopeDeclarationBodyItem } from "farmbot"; import { ResourceIndex, VariableNameSet } from "../resources/interfaces"; -import { CeleryVariable } from "./step_tiles/tile_move_absolute/index"; -import { TaggedSequence } from "farmbot"; -import { defensiveClone } from "../util"; -import { isNaN } from "lodash"; import { SequenceMeta } from "../resources/sequence_meta"; type OnChange = (data_type: Vector3) => void; -type DataValue = VariableDeclaration["args"]["data_value"]; export interface LocalsListProps { variableData: VariableNameSet; @@ -22,8 +15,7 @@ export interface LocalsListProps { } export interface ParentVariableFormProps { - betterParent: SequenceMeta; - deprecatedParent: VariableDeclaration | ParameterDeclaration; + parent: SequenceMeta; sequence: TaggedSequence; resources: ResourceIndex; onChange: OnChange; @@ -32,88 +24,7 @@ export interface ParentVariableFormProps { export const PARENT = ({ value: "parent", label: "Parent", headingId: "parameter" }); -const KINDS = ["parameter_declaration", "variable_declaration"]; -/** Given an array of variable declarations (or undefined), finds the "parent" - * special identifier */ export const extractParent = - (list?: ScopeDeclarationBodyItem[]): ScopeDeclarationBodyItem | undefined => { - const p = (list ? list : []).filter(x => { - const isParent = x.args.label === "parent"; - const isVar = KINDS.includes(x.kind); - return isVar && isParent; - })[0]; - switch (p && p.kind) { - case "variable_declaration": - case "parameter_declaration": - return p; - default: - return undefined; - } - }; - -/** Takes a sequence and data_value. Turn the data_value into the sequence's new - * `parent` variable. This is a _pure function_. */ -export const setParent = - (sequence: TaggedSequence, data_value: CeleryVariable) => { - const nextSeq: typeof sequence.body = defensiveClone(sequence.body); - switch (data_value.kind) { - case "tool": - case "point": - case "coordinate": - nextSeq.args.locals = { - kind: "scope_declaration", - args: {}, - body: [ - { - kind: "variable_declaration", - args: { - label: "parent", - data_value - } - } - ] - }; - break; - case "parameter_declaration": - nextSeq.args.locals = { - kind: "scope_declaration", - args: {}, - body: [{ - kind: "parameter_declaration", - args: { label: "parent", data_type: "point" } - }] - }; - break; - default: - throw new Error("Bad kind in setParent(): " + data_value.kind); - } - return nextSeq; - }; - -/** If variable is a coordinate, just use the coordinates. */ -export const guessFromDataType = - (x: DataValue): Vector3 | undefined => (x.kind === "coordinate") ? - x.args : undefined; - -/** GLORIOUS hack: We spend a *lot* of time in the sequence editor looking up -* resource x/y/z. It's resource intensive and often hard to understand. -* Instead of adding more selectors and complexity, we make a "best effort" -* attempt to read the resource's `x`, `y`, `z` that are cached (as strings) -* in the drop down label. -* -* String manipulation is bad, but I think it is warranted here: */ -export const guessVecFromLabel = - (label: string): Vector3 | undefined => { - const step1 = label - .trim() - .replace(")", "") - .replace(/^\s+|\s+$/g, "") - .split(/\(|\,/); - const vec = step1 - .slice(Math.max(step1.length - 3, 1)) - .map(x => parseInt(x, 10)) - .filter(x => !isNaN(x)); - - return (vec.length === 3) ? - { x: vec[0], y: vec[1], z: vec[2] } : undefined; + (i: ResourceIndex, uuid: string): SequenceMeta | undefined => { + return (i.sequenceMetas[uuid] || {}).parent; }; diff --git a/webpack/sequences/sequence_editor_middle_active.tsx b/webpack/sequences/sequence_editor_middle_active.tsx index a024bc4e3..a7b06bc22 100644 --- a/webpack/sequences/sequence_editor_middle_active.tsx +++ b/webpack/sequences/sequence_editor_middle_active.tsx @@ -96,11 +96,12 @@ const SequenceHeader = (props: SequenceHeaderProps) => { export class SequenceEditorMiddleActive extends React.Component { get stepSectionHeight() { + const { resources, sequence } = this.props; const variable = this.props.shouldDisplay(Feature.variables) - ? !!extractParent(this.props.sequence.body.args.locals.body) - : false; + ? !!extractParent(resources, sequence.uuid) : false; return `calc(100vh - ${variable ? "38" : "25"}rem)`; } + render() { const { dispatch, sequence } = this.props; return