[UNSTABLE] Pull out more junk

pull/1061/head
Rick Carlino 2018-11-29 10:52:26 -06:00
parent 6a37826043
commit 47d924f8a9
4 changed files with 23 additions and 275 deletions

View File

@ -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("<ParentVariableForm/>", () => {
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("<ParentVariableForm/>", () => {
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);

View File

@ -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 <div className="parent-variable-form">
<Row>
@ -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 });
}} />
</Col>
</Row>
<Row>
@ -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
? <ParentVariableForm
betterParent={betterParent}
deprecatedParent={betterParent.celeryNode}
parent={parent}
sequence={props.deprecatedSequence}
resources={props.deprecatedResources}
onChange={REWRITE_THIS} />

View File

@ -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;
};

View File

@ -96,11 +96,12 @@ const SequenceHeader = (props: SequenceHeaderProps) => {
export class SequenceEditorMiddleActive extends
React.Component<ActiveMiddleProps, {}> {
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 <div className="sequence-editor-content">