Farmbot-Web-App/frontend/resources/sequence_meta.ts

166 lines
5.8 KiB
TypeScript
Raw Normal View History

2018-12-20 20:18:10 -07:00
import { VariableNameSet, ResourceIndex, UUID } from "./interfaces";
import {
TaggedSequence,
Vector3,
2019-02-22 19:09:40 -07:00
ScopeDeclarationBodyItem,
} from "farmbot";
import { DropDownItem } from "../ui";
2019-09-26 10:34:22 -06:00
import { findPointerByTypeAndId, findPointGroup } from "./selectors";
2018-11-30 15:31:42 -07:00
import {
findSlotByToolId,
findToolById,
2020-02-28 09:35:32 -07:00
findResourceById,
} from "./selectors_by_id";
import {
formatPoint,
NO_VALUE_SELECTED_DDI,
2019-06-21 15:46:11 -06:00
formatTool,
2020-02-28 09:35:32 -07:00
COORDINATE_DDI,
2019-01-13 17:16:22 -07:00
} from "../sequences/locals_list/location_form_list";
2019-02-22 19:09:40 -07:00
import { VariableNode } from "../sequences/locals_list/locals_list_support";
2019-06-04 16:07:52 -06:00
import { t } from "../i18next_wrapper";
2020-02-20 19:38:50 -07:00
export interface Vector3Plus extends Vector3 {
gantry_mounted: boolean;
}
export interface SequenceMeta {
2019-02-22 19:09:40 -07:00
celeryNode: VariableNode;
dropdown: DropDownItem;
2020-02-20 19:38:50 -07:00
vector: Vector3 | Vector3Plus | undefined;
2019-06-21 15:46:11 -06:00
default?: boolean;
}
/** Converts a "scope declaration body item" (AKA a CeleryScript variable) into
* a 3 dimensional location vector. If unable a vector cannot be determined,
2019-06-04 16:07:52 -06:00
* `undefined` is returned. Provide a UUID when calling from a sequence step to
2018-12-20 20:18:10 -07:00
* make an attempt to show the resolved vector from the sequence scope. */
export const determineVector =
2019-02-22 19:09:40 -07:00
(node: VariableNode, resources: ResourceIndex, uuid?: UUID):
2018-12-20 20:18:10 -07:00
Vector3 | undefined => {
if (node.kind == "parameter_declaration") {
2018-12-20 20:18:10 -07:00
// parameter_declaration coordinates can't be known until runtime
return undefined;
}
const variableContents = node.args.data_value;
switch (variableContents.kind) {
case "coordinate": return variableContents.args;
case "point":
2018-12-03 07:18:48 -07:00
const { pointer_type, pointer_id } = variableContents.args;
2018-12-20 20:18:10 -07:00
return findPointerByTypeAndId(resources, pointer_type, pointer_id).body;
case "tool":
2018-12-20 20:18:10 -07:00
const ts = findSlotByToolId(resources, variableContents.args.tool_id);
return ts ? ts.body : undefined;
case "identifier":
2019-06-04 16:07:52 -06:00
const variable = maybeFindVariable(node.args.label, resources, uuid);
2020-01-03 13:04:45 -07:00
return variable?.vector;
2019-06-04 16:07:52 -06:00
}
return undefined;
};
/** Try to find a vector in scope declarations for the variable. */
2020-04-30 17:55:14 -06:00
export const maybeFindVariable = (
2020-02-28 09:35:32 -07:00
label: string, resources: ResourceIndex, uuid?: UUID,
2019-06-06 17:54:48 -06:00
): SequenceMeta | undefined =>
uuid ? findVariableByName(resources, uuid, label) : undefined;
2019-06-28 13:05:19 -06:00
/** Add "Location Variable - " prefix to string. */
export const withPrefix = (label: string) =>
`${t("Location Variable")} - ${label}`;
2019-06-06 17:54:48 -06:00
2019-06-14 16:59:11 -06:00
interface DetermineVarDDILabelProps {
label: string;
resources: ResourceIndex;
uuid?: UUID;
forceExternal?: boolean;
}
2019-06-06 17:54:48 -06:00
export const determineVarDDILabel =
2019-06-14 16:59:11 -06:00
({ label, resources, uuid, forceExternal }: DetermineVarDDILabelProps):
string => {
if (forceExternal) { return t("Externally defined"); }
2019-06-06 17:54:48 -06:00
const variable = maybeFindVariable(label, resources, uuid);
if (variable) {
if (variable.celeryNode.kind === "parameter_declaration") {
return withPrefix(t("Externally defined"));
}
if (variable.celeryNode.kind !== "variable_declaration") {
return withPrefix(t("Select a location"));
}
return withPrefix(variable.dropdown.label);
}
2019-06-06 17:54:48 -06:00
return withPrefix(t("Add new"));
};
2019-02-22 19:09:40 -07:00
/** Given a CeleryScript parameter application and a resource index
* Returns a DropDownItem representation of said variable. */
2018-12-05 13:37:02 -07:00
export const determineDropdown =
2019-06-04 16:07:52 -06:00
(node: VariableNode, resources: ResourceIndex, uuid?: UUID): DropDownItem => {
2018-12-20 20:18:10 -07:00
if (node.kind === "parameter_declaration") {
2019-06-04 16:07:52 -06:00
return {
2019-06-14 16:59:11 -06:00
label: t("Externally defined"),
value: "?"
2019-06-04 16:07:52 -06:00
};
}
2018-12-20 20:18:10 -07:00
const { data_value } = node.args;
switch (data_value.kind) {
case "coordinate":
2019-06-21 15:46:11 -06:00
return COORDINATE_DDI(data_value.args);
case "identifier":
2019-06-04 16:07:52 -06:00
const { label } = data_value.args;
2019-06-14 16:59:11 -06:00
const varName = determineVarDDILabel({ label, resources, uuid });
2019-06-04 16:07:52 -06:00
return { label: varName, value: "?" };
case "point":
const { pointer_id, pointer_type } = data_value.args;
const pointer =
2018-12-20 20:18:10 -07:00
findPointerByTypeAndId(resources, pointer_type, pointer_id);
return formatPoint(pointer);
case "tool":
2019-06-04 16:07:52 -06:00
const { tool_id } = data_value.args;
const toolSlot = findSlotByToolId(resources, tool_id);
return formatTool(findToolById(resources, tool_id), toolSlot);
case "point_group":
2019-10-03 13:25:33 -06:00
const value = data_value.args.point_group_id;
2019-09-26 10:34:22 -06:00
const uuid2 = findResourceById(resources, "PointGroup", value);
const group = findPointGroup(resources, uuid2);
return {
label: group.body.name,
value
};
case "nothing" as unknown:
2019-01-16 19:24:59 -07:00
return NO_VALUE_SELECTED_DDI();
}
2018-12-03 07:18:48 -07:00
throw new Error("WARNING: Unknown, possibly new data_value.kind?");
};
/** Can this CeleryScript variable be edited? Should we gray out the form? */
2019-02-22 19:09:40 -07:00
export const determineEditable = (node: VariableNode): boolean => {
return node.kind !== "parameter_declaration" &&
node.args.data_value.kind == "coordinate";
};
/** Creates the sequence meta data lookup table for an entire ResourceIndex.
* Used to overwrite the entire index on any data change. */
2018-12-20 20:18:10 -07:00
export const createSequenceMeta =
(resources: ResourceIndex, sequence: TaggedSequence): VariableNameSet => {
const collection = sequence.body.args.locals.body || [];
const reducer = (acc: VariableNameSet, celeryNode: ScopeDeclarationBodyItem):
VariableNameSet => ({
...acc,
[celeryNode.args.label]: {
celeryNode,
2019-06-04 16:07:52 -06:00
vector: determineVector(celeryNode, resources, sequence.uuid),
dropdown: determineDropdown(celeryNode, resources, sequence.uuid),
2018-12-20 20:18:10 -07:00
}
});
return collection.reduce(reducer, {});
2018-11-30 15:31:42 -07:00
};
2018-12-20 20:18:10 -07:00
/** Search a sequence's scope declaration for a particular variable by name. */
2018-11-30 15:31:42 -07:00
export const findVariableByName =
(i: ResourceIndex, uuid: string, label: string): SequenceMeta | undefined => {
return (i.sequenceMetas[uuid] || {})[label];
};