add every_point to UI
parent
ed56ef7fb5
commit
622eaa4696
|
@ -1,7 +1,8 @@
|
|||
import {
|
||||
createSequenceMeta,
|
||||
determineDropdown,
|
||||
findVariableByName
|
||||
findVariableByName,
|
||||
determineVector
|
||||
} from "../sequence_meta";
|
||||
import {
|
||||
fakeSequence,
|
||||
|
@ -36,37 +37,70 @@ describe("determineDropdown", () => {
|
|||
expect(r.label).toBe("Coordinate (0, 1, 2)");
|
||||
expect(r.value).toBe("?");
|
||||
});
|
||||
});
|
||||
|
||||
it("Returns a label for `identifier`", () => {
|
||||
const r = determineDropdown({
|
||||
kind: "variable_declaration",
|
||||
args: {
|
||||
label: "x",
|
||||
data_value: { kind: "identifier", args: { label: "parent1" } }
|
||||
}
|
||||
}, buildResourceIndex([]).index);
|
||||
expect(r.label).toBe("Parent1");
|
||||
expect(r.value).toBe("?");
|
||||
});
|
||||
it("Returns a label for `identifier`", () => {
|
||||
const r = determineDropdown({
|
||||
kind: "variable_declaration",
|
||||
args: {
|
||||
label: "x",
|
||||
data_value: { kind: "identifier", args: { label: "parent1" } }
|
||||
}
|
||||
}, buildResourceIndex([]).index);
|
||||
expect(r.label).toBe("Parent1");
|
||||
expect(r.value).toBe("?");
|
||||
});
|
||||
|
||||
it("Returns a label for `point`", () => {
|
||||
const point = fakePoint();
|
||||
const r = determineDropdown({
|
||||
kind: "variable_declaration",
|
||||
args: {
|
||||
label: "x",
|
||||
data_value: {
|
||||
kind: "point",
|
||||
args: {
|
||||
pointer_id: point.body.id || -0,
|
||||
pointer_type: "Point"
|
||||
it("Returns a label for `every_point`", () => {
|
||||
const r = determineDropdown({
|
||||
kind: "variable_declaration",
|
||||
args: {
|
||||
label: "x",
|
||||
data_value: { kind: "every_point", args: { every_point_type: "Plant" } }
|
||||
}
|
||||
}, buildResourceIndex([]).index);
|
||||
expect(r.label).toBe("All plants");
|
||||
expect(r.value).toBe("Plant");
|
||||
});
|
||||
|
||||
it("Returns a label for `point`", () => {
|
||||
const point = fakePoint();
|
||||
const r = determineDropdown({
|
||||
kind: "variable_declaration",
|
||||
args: {
|
||||
label: "x",
|
||||
data_value: {
|
||||
kind: "point",
|
||||
args: {
|
||||
pointer_id: point.body.id || -0,
|
||||
pointer_type: "Point"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}, buildResourceIndex([point]).index);
|
||||
expect(r.label).toBe(formatPoint(point).label);
|
||||
expect(r.value).toBe("" + point.body.id);
|
||||
}, buildResourceIndex([point]).index);
|
||||
expect(r.label).toBe(formatPoint(point).label);
|
||||
expect(r.value).toBe("" + point.body.id);
|
||||
});
|
||||
});
|
||||
|
||||
describe("determineVector()", () => {
|
||||
it("determines vector for point", () => {
|
||||
const point = fakePoint();
|
||||
const v = determineVector({
|
||||
kind: "variable_declaration",
|
||||
args: {
|
||||
label: "x",
|
||||
data_value: {
|
||||
kind: "point",
|
||||
args: {
|
||||
pointer_id: point.body.id || -0,
|
||||
pointer_type: "Point"
|
||||
}
|
||||
}
|
||||
}
|
||||
}, buildResourceIndex([point]).index);
|
||||
const { x, y, z } = point.body;
|
||||
expect(v).toEqual(expect.objectContaining({ x, y, z }));
|
||||
});
|
||||
});
|
||||
|
||||
describe("createSequenceMeta", () => {
|
||||
|
|
|
@ -9,7 +9,7 @@ import { findPointerByTypeAndId } from "./selectors";
|
|||
import { findSlotByToolId, findToolById } from "./selectors_by_id";
|
||||
import { capitalize } from "lodash";
|
||||
import {
|
||||
formatPoint
|
||||
formatPoint, safeEveryPointType, everyPointDDI
|
||||
} from "../sequences/step_tiles/tile_move_absolute/generate_list";
|
||||
|
||||
export interface SequenceMeta {
|
||||
|
@ -64,6 +64,9 @@ export const determineDropdown =
|
|||
return { label: `Coordinate (${x}, ${y}, ${z})`, value: "?" };
|
||||
case "identifier":
|
||||
return { label: capitalize(data_value.args.label), value: "?" };
|
||||
case "every_point":
|
||||
const { every_point_type } = data_value.args;
|
||||
return everyPointDDI(safeEveryPointType(every_point_type));
|
||||
case "point":
|
||||
const { pointer_id, pointer_type } = data_value.args;
|
||||
const pointer =
|
||||
|
|
|
@ -51,7 +51,7 @@ describe("convertDDItoDeclaration()", () => {
|
|||
const variable = convertDDItoDeclaration({ label: "parent" })(ddi);
|
||||
const expected: ScopeDeclarationBodyItem = {
|
||||
kind: "parameter_declaration",
|
||||
args: { data_type: "point", label: "parent" }
|
||||
args: { label: "parent", data_type: "point" }
|
||||
};
|
||||
expect(variable).toEqual(expected);
|
||||
});
|
||||
|
@ -64,9 +64,25 @@ describe("convertDDItoDeclaration()", () => {
|
|||
const expected: ScopeDeclarationBodyItem = {
|
||||
kind: "variable_declaration",
|
||||
args: {
|
||||
label: "parent",
|
||||
data_value: {
|
||||
kind: "identifier", args: { label: "parent0" }
|
||||
}, label: "parent"
|
||||
}
|
||||
}
|
||||
};
|
||||
expect(variable).toEqual(expected);
|
||||
});
|
||||
|
||||
it("returns location data: every_point", () => {
|
||||
const ddi = ({ headingId: "every_point", label: "All Plants", value: "Plant" });
|
||||
const variable = convertDDItoDeclaration({ label: "label" })(ddi);
|
||||
const expected: ScopeDeclarationBodyItem = {
|
||||
kind: "variable_declaration",
|
||||
args: {
|
||||
label: "label",
|
||||
data_value: {
|
||||
kind: "every_point", args: { every_point_type: "Plant" }
|
||||
}
|
||||
}
|
||||
};
|
||||
expect(variable).toEqual(expected);
|
||||
|
|
|
@ -14,7 +14,7 @@ import {
|
|||
} from "../locals_list_support";
|
||||
import { difference } from "lodash";
|
||||
import { VariableNameSet } from "../../../resources/interfaces";
|
||||
import { generateList } from "../../step_tiles/tile_move_absolute/generate_list";
|
||||
import { locationFormList } from "../../step_tiles/tile_move_absolute/generate_list";
|
||||
import { convertDDItoDeclaration } from "../handle_select";
|
||||
|
||||
describe("<LocationForm/>", () => {
|
||||
|
@ -43,7 +43,7 @@ describe("<LocationForm/>", () => {
|
|||
expect(selects.length).toBe(1);
|
||||
const select = selects.first().props();
|
||||
expect(select.allowEmpty).toBe(true);
|
||||
const choices = generateList(p.resources, [PARENT]);
|
||||
const choices = locationFormList(p.resources, [PARENT], true);
|
||||
const actualLabels = select.list.map(x => x.label).sort();
|
||||
const expectedLabels = choices.map(x => x.label).sort();
|
||||
const diff = difference(actualLabels, expectedLabels);
|
||||
|
|
|
@ -9,13 +9,14 @@ import {
|
|||
Dictionary,
|
||||
Identifier,
|
||||
Point,
|
||||
Tool
|
||||
Tool,
|
||||
EveryPoint
|
||||
} from "farmbot";
|
||||
|
||||
export const EMPTY_COORD: Coordinate =
|
||||
({ kind: "coordinate", args: { x: 0, y: 0, z: 0 } });
|
||||
|
||||
type DataValue = Coordinate | Identifier | Point | Tool;
|
||||
type DataValue = Coordinate | Identifier | Point | Tool | EveryPoint;
|
||||
const createVariableDeclaration =
|
||||
(label: string, data_value: DataValue): VariableDeclaration =>
|
||||
({
|
||||
|
@ -39,6 +40,14 @@ const pointVar = (
|
|||
args: { pointer_type, pointer_id: parseInt("" + value) }
|
||||
});
|
||||
|
||||
const everyPointVar =
|
||||
(value: string | number) =>
|
||||
({ label }: { label: string }): VariableDeclaration =>
|
||||
createVariableDeclaration(label, {
|
||||
kind: "every_point",
|
||||
args: { every_point_type: "" + value }
|
||||
});
|
||||
|
||||
const manualEntry = ({ label }: { label: string }): VariableDeclaration =>
|
||||
createVariableDeclaration(label, {
|
||||
kind: "coordinate", args: { x: 0, y: 0, z: 0 }
|
||||
|
@ -71,13 +80,14 @@ const newDeclarationCreator = (ddi: DropDownItem):
|
|||
newVarLabel?: string,
|
||||
useIdentifier?: boolean
|
||||
}) => ScopeDeclarationBodyItem | undefined => {
|
||||
if (ddi.isNull) { return manualEntry; } // Caller decides X/Y/Z
|
||||
if (ddi.isNull) { return manualEntry; } // Coordinate
|
||||
switch (ddi.headingId) {
|
||||
case "Plant":
|
||||
case "GenericPointer": return pointVar(ddi.headingId, ddi.value);
|
||||
case "Tool": return toolVar(ddi.value);
|
||||
case "parameter": return newParameter; // Caller decides X/Y/Z
|
||||
case "Other": return manualEntry;
|
||||
case "every_point": return everyPointVar(ddi.value);
|
||||
case "Other": return manualEntry; // Coordinate
|
||||
}
|
||||
return () => undefined;
|
||||
};
|
||||
|
|
|
@ -1,12 +1,12 @@
|
|||
import * as React from "react";
|
||||
import { Row, Col, FBSelect, BlurableInput } from "../../ui";
|
||||
import { t } from "i18next";
|
||||
import { generateList } from "../step_tiles/tile_move_absolute/generate_list";
|
||||
import { locationFormList } from "../step_tiles/tile_move_absolute/generate_list";
|
||||
import {
|
||||
convertDDItoDeclaration, addOrEditDeclaration
|
||||
} from "../locals_list/handle_select";
|
||||
import {
|
||||
LocationFormProps, LocalsListProps, PARENT, AllowedDeclaration
|
||||
LocationFormProps, LocalsListProps, PARENT, AllowedDeclaration,
|
||||
} from "../locals_list/locals_list_support";
|
||||
import { defensiveClone, betterCompact } from "../../util/util";
|
||||
import {
|
||||
|
@ -73,7 +73,8 @@ export const LocationForm =
|
|||
(props: LocationFormProps) => {
|
||||
const {
|
||||
sequenceUuid, resources, onChange, declarations, variable,
|
||||
hideVariableLabel, locationDropdownKey, allowedDeclarations
|
||||
hideVariableLabel, locationDropdownKey, allowedDeclarations,
|
||||
disallowGroups
|
||||
} = props;
|
||||
const { celeryNode, dropdown, vector } =
|
||||
maybeUseStepData({
|
||||
|
@ -84,7 +85,7 @@ export const LocationForm =
|
|||
const useIdentifier = allowedDeclarations === AllowedDeclaration.identifier;
|
||||
const variableListItems = (props.shouldDisplay(Feature.variables) &&
|
||||
allowedDeclarations !== AllowedDeclaration.variable) ? [PARENT] : [];
|
||||
const list = generateList(resources, variableListItems);
|
||||
const list = locationFormList(resources, variableListItems, !disallowGroups);
|
||||
/** Variable name. */
|
||||
const { label } = celeryNode.args;
|
||||
const declaration = defensiveClone(celeryNode);
|
||||
|
|
|
@ -38,6 +38,8 @@ interface CommonProps {
|
|||
* chooses between reassignment vs. creation for new variables,
|
||||
* and determines which variables to display in the form. */
|
||||
allowedDeclarations: AllowedDeclaration;
|
||||
/** Don't display group dropdown items. */
|
||||
disallowGroups?: boolean;
|
||||
}
|
||||
|
||||
export interface LocalsListProps extends CommonProps {
|
||||
|
|
|
@ -181,6 +181,7 @@ export class TileMoveAbsolute extends Component<StepParams, MoveAbsState> {
|
|||
hideVariableLabel={true}
|
||||
locationDropdownKey={JSON.stringify(this.props.currentSequence)}
|
||||
allowedDeclarations={AllowedDeclaration.identifier}
|
||||
disallowGroups={true}
|
||||
width={3} />
|
||||
|
||||
SpeedForm = () =>
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
import { generateList, dropDownName } from "../generate_list";
|
||||
import { locationFormList, dropDownName } from "../generate_list";
|
||||
import { fakeResourceIndex } from "../test_helpers";
|
||||
|
||||
describe("generateList()", () => {
|
||||
describe("locationFormList()", () => {
|
||||
it("returns dropdown list", () => {
|
||||
const items = generateList(fakeResourceIndex(), []);
|
||||
const items = locationFormList(fakeResourceIndex(), []);
|
||||
const toolHeading = items[0];
|
||||
expect(toolHeading).toEqual({
|
||||
headingId: "Tool",
|
||||
|
@ -24,7 +24,7 @@ describe("generateList()", () => {
|
|||
value: 0,
|
||||
heading: true,
|
||||
});
|
||||
const plant = items[4];
|
||||
const plant = items[3];
|
||||
expect(plant).toEqual({
|
||||
headingId: "Plant",
|
||||
label: "Plant 1 (1, 2, 3)",
|
||||
|
|
|
@ -32,7 +32,7 @@ export function activeTools(resources: ResourceIndex): ToolAndLocation[] {
|
|||
: undefined));
|
||||
}
|
||||
|
||||
type DropdownHeadingId = PointerTypeName | typeof TOOL;
|
||||
type DropdownHeadingId = PointerTypeName | typeof TOOL | "Other";
|
||||
|
||||
/** Location selection menu section names. */
|
||||
export const NAME_MAP: Record<DropdownHeadingId, string> = {
|
||||
|
@ -40,38 +40,47 @@ export const NAME_MAP: Record<DropdownHeadingId, string> = {
|
|||
"Plant": "Plants",
|
||||
"ToolSlot": "Tool Slots",
|
||||
"Tool": "Tools",
|
||||
"Other": "Other",
|
||||
};
|
||||
|
||||
/** Location selection menu section headers. */
|
||||
const HEADINGS: () => DropDownItem[] = () => [
|
||||
...Object.keys(NAME_MAP)
|
||||
.filter(x => x !== "ToolSlot")
|
||||
.map((name: DropdownHeadingId) => {
|
||||
return ({
|
||||
label: t(NAME_MAP[name]),
|
||||
heading: true,
|
||||
value: 0,
|
||||
headingId: name
|
||||
});
|
||||
})
|
||||
];
|
||||
const heading = (name: DropdownHeadingId) => ({
|
||||
label: t(NAME_MAP[name]),
|
||||
heading: true,
|
||||
value: 0,
|
||||
headingId: name
|
||||
});
|
||||
|
||||
const ddiFrom = (points: TaggedPoint[], pointerType: PointerTypeName) => points
|
||||
.filter(x => x.body.pointer_type === pointerType)
|
||||
.map(formatPoint)
|
||||
.filter(x => parseInt("" + x.value) > 0);
|
||||
|
||||
const maybeGroup = (display: boolean) =>
|
||||
(groupDDI: DropDownItem): DropDownItem[] =>
|
||||
display ? [groupDDI] : [];
|
||||
|
||||
/** Location selection menu items. */
|
||||
export function generateList(input: ResourceIndex,
|
||||
additionalItems: DropDownItem[]): DropDownItem[] {
|
||||
const SORT_KEY: keyof DropDownItem = "headingId";
|
||||
export function locationFormList(input: ResourceIndex,
|
||||
additionalItems: DropDownItem[], displayGroups?: boolean): DropDownItem[] {
|
||||
const points = selectAllActivePoints(input)
|
||||
.filter(x => (x.body.pointer_type !== "ToolSlot"));
|
||||
const toolDDI: DropDownItem[] =
|
||||
activeTools(input).map(({ tool, location }) => formatTools(tool, location));
|
||||
return _(points)
|
||||
.map(formatPoint)
|
||||
.filter(x => x.body.pointer_type !== "ToolSlot");
|
||||
const plantDDI = ddiFrom(points, "Plant");
|
||||
const genericPointerDDI = ddiFrom(points, "GenericPointer");
|
||||
const toolDDI: DropDownItem[] = activeTools(input)
|
||||
.map(({ tool, location }) => formatTools(tool, location))
|
||||
.filter(x => parseInt("" + x.value) > 0);
|
||||
const group = maybeGroup(!!displayGroups);
|
||||
return _(heading("Tool"))
|
||||
.concat(toolDDI)
|
||||
.filter(x => parseInt("" + x.value) > 0)
|
||||
.concat(HEADINGS())
|
||||
.sortBy(SORT_KEY)
|
||||
.reverse()
|
||||
.concat({ label: t("Other"), heading: true, value: 0, headingId: "Other" })
|
||||
.concat(group(everyPointDDI("Tool")))
|
||||
.concat(group(everyPointDDI("ToolSlot")))
|
||||
.concat(heading("Plant"))
|
||||
.concat(plantDDI)
|
||||
.concat(group(everyPointDDI("Plant")))
|
||||
.concat(heading("GenericPointer"))
|
||||
.concat(genericPointerDDI)
|
||||
.concat(group(everyPointDDI("GenericPointer")))
|
||||
.concat(heading("Other"))
|
||||
.concat(additionalItems)
|
||||
.value();
|
||||
}
|
||||
|
@ -102,3 +111,26 @@ export function dropDownName(name: string, v?: Vector3) {
|
|||
if (v) { label += ` (${v.x}, ${v.y}, ${v.z})`; }
|
||||
return capitalize(label);
|
||||
}
|
||||
|
||||
export const EVERY_POINT_LABEL = {
|
||||
"Plant": "All plants",
|
||||
"GenericPointer": "All map points",
|
||||
"Tool": "All tools",
|
||||
"ToolSlot": "All tool slots",
|
||||
};
|
||||
|
||||
export type EveryPointType = keyof typeof EVERY_POINT_LABEL;
|
||||
|
||||
const isEveryPointType = (x: string): x is EveryPointType =>
|
||||
Object.keys(EVERY_POINT_LABEL).includes(x);
|
||||
|
||||
export const safeEveryPointType = (x: string): EveryPointType => {
|
||||
if (isEveryPointType(x)) {
|
||||
return x;
|
||||
} else {
|
||||
throw new Error(`'${x}' is not of type EveryPointType`);
|
||||
}
|
||||
};
|
||||
|
||||
export const everyPointDDI = (value: EveryPointType) =>
|
||||
({ value, label: EVERY_POINT_LABEL[value], headingId: "every_point" });
|
||||
|
|
Loading…
Reference in New Issue