Farmbot-Web-App/frontend/sequences/step_tiles/tile_if/index.tsx

175 lines
5.5 KiB
TypeScript
Raw Normal View History

2017-06-29 12:54:02 -06:00
import * as React from "react";
import { DropDownItem, NULL_CHOICE, Row } from "../../../ui/index";
2019-02-22 19:09:40 -07:00
import { TaggedSequence, ParameterApplication } from "farmbot";
2017-06-29 12:54:02 -06:00
import { If, Execute, Nothing } from "farmbot/dist";
import { ResourceIndex } from "../../../resources/interfaces";
2019-04-18 16:58:29 -06:00
import {
selectAllSequences, findSequenceById
} from "../../../resources/selectors";
2017-12-15 16:09:24 -07:00
import { isRecursive } from "../index";
2017-06-29 12:54:02 -06:00
import { If_ } from "./if";
2019-02-11 19:44:45 -07:00
import { ThenElse } from "./then_else";
2018-03-07 20:42:34 -07:00
import { defensiveClone } from "../../../util";
2017-06-29 12:54:02 -06:00
import { overwrite } from "../../../api/crud";
import { ToolTips } from "../../../constants";
2017-12-15 16:09:24 -07:00
import { StepWrapper, StepHeader, StepContent } from "../../step_ui/index";
import {
2019-04-18 16:58:29 -06:00
sensorsAsDropDowns, peripheralsAsDropDowns, pinDropdowns, PinGroupName
} from "../pin_and_peripheral_support";
2019-05-15 10:13:17 -06:00
import { ShouldDisplay } from "../../../devices/interfaces";
2019-02-04 07:32:26 -07:00
import { isNumber, isString } from "lodash";
2019-04-18 16:58:29 -06:00
import {
addOrEditParamApps, variableList
} from "../../locals_list/variable_support";
2019-04-02 13:59:37 -06:00
import { t } from "../../../i18next_wrapper";
2017-06-29 12:54:02 -06:00
export interface IfParams {
currentSequence: TaggedSequence;
currentStep: If;
dispatch: Function;
index: number;
resources: ResourceIndex;
2018-03-07 20:42:34 -07:00
shouldDisplay?: ShouldDisplay;
2018-08-30 19:25:58 -06:00
confirmStepDeletion: boolean;
2019-04-18 16:58:29 -06:00
showPins?: boolean;
2017-06-29 12:54:02 -06:00
}
2019-02-11 19:44:45 -07:00
export interface ThenElseParams extends IfParams {
thenElseKey: "_then" | "_else";
}
2017-06-29 12:54:02 -06:00
export type Operator = "lhs"
| "op"
| "rhs"
| "_then"
| "_else";
export const LHSOptions =
2019-05-15 10:13:17 -06:00
(resources: ResourceIndex, showPins: boolean
): DropDownItem[] => [
2019-09-23 12:56:35 -06:00
{
heading: true, headingId: PinGroupName.Position,
label: t("Positions"), value: 0,
},
{ value: "x", label: t("X position"), headingId: "Position" },
{ value: "y", label: t("Y position"), headingId: "Position" },
{ value: "z", label: t("Z position"), headingId: "Position" },
2019-05-15 10:13:17 -06:00
...peripheralsAsDropDowns(resources),
...sensorsAsDropDowns(resources),
2019-04-18 16:58:29 -06:00
...(showPins ? pinDropdowns(n => `pin${n}`) : []),
];
2017-06-29 12:54:02 -06:00
export const operatorOptions: DropDownItem[] = [
2018-02-27 10:49:37 -07:00
{ value: "<", label: t("is less than") },
{ value: ">", label: t("is greater than") },
{ value: "is", label: t("is equal to") },
{ value: "not", label: t("is not equal to") },
{ value: "is_undefined", label: t("is unknown") }
2017-06-29 12:54:02 -06:00
];
export function seqDropDown(i: ResourceIndex) {
2017-08-28 05:49:13 -06:00
const results: DropDownItem[] = [];
2017-06-29 12:54:02 -06:00
selectAllSequences(i)
.map(function (x) {
2017-08-28 05:49:13 -06:00
const { body } = x;
2019-02-04 07:32:26 -07:00
if (isNumber(body.id)) {
2017-06-29 12:54:02 -06:00
results.push({ label: body.name, value: body.id });
}
});
2017-06-29 12:54:02 -06:00
return results;
}
export function InnerIf(props: IfParams) {
2017-08-28 05:49:13 -06:00
const {
2017-06-29 12:54:02 -06:00
index,
dispatch,
currentStep,
2018-08-30 19:25:58 -06:00
currentSequence,
confirmStepDeletion,
2017-06-29 12:54:02 -06:00
} = props;
2017-08-28 05:49:13 -06:00
const recursive = isRecursive(currentStep, currentSequence);
2017-12-15 16:09:24 -07:00
const className = "if-step";
return <StepWrapper>
<StepHeader
className={className}
helpText={ToolTips.IF}
currentSequence={currentSequence}
currentStep={currentStep}
dispatch={dispatch}
2018-08-30 19:25:58 -06:00
index={index}
confirmStepDeletion={confirmStepDeletion}>
2019-02-11 19:44:45 -07:00
{recursive &&
2017-12-15 16:09:24 -07:00
<span>
<i className="fa fa-exclamation-triangle"></i>
&nbsp;{t("Recursive condition.")}
</span>
2019-02-11 19:44:45 -07:00
}
2017-12-15 16:09:24 -07:00
</StepHeader>
<StepContent className={className}>
<If_ {...props} />
<Row>
<ThenElse thenElseKey={"_then"} {...props} />
<ThenElse thenElseKey={"_else"} {...props} />
</Row>
2017-12-15 16:09:24 -07:00
</StepContent>
</StepWrapper>;
2017-06-29 12:54:02 -06:00
}
/** Creates a function that can be used in the `onChange` event of a _else or
* _then block in the sequence editor.
*/
export const IfBlockDropDownHandler = (props: ThenElseParams) => {
2017-06-29 12:54:02 -06:00
2019-02-11 19:44:45 -07:00
const { dispatch, index, thenElseKey } = props;
2017-08-28 05:49:13 -06:00
const step = props.currentStep;
const sequence = props.currentSequence;
2019-02-11 19:44:45 -07:00
const block = step.args[thenElseKey];
2017-08-28 05:49:13 -06:00
const selectedItem = () => {
2017-06-29 12:54:02 -06:00
if (block.kind === "nothing") {
return NULL_CHOICE;
} else {
2017-08-28 05:49:13 -06:00
const value = (block.kind === "execute") && block.args.sequence_id;
const label = value && findSequenceById(props.resources, value).body.name;
2019-02-04 07:32:26 -07:00
if (isNumber(value) && isString(label)) {
return { label, value };
2017-06-29 12:54:02 -06:00
} else {
throw new Error("Failed type assertion");
}
}
2017-07-17 12:34:46 -06:00
};
2017-06-29 12:54:02 -06:00
function overwriteStep(input: Execute | Nothing) {
2017-08-28 05:49:13 -06:00
const update = defensiveClone(step);
const nextSequence = defensiveClone(sequence).body;
2019-02-11 19:44:45 -07:00
update.args[thenElseKey] = input;
2017-06-29 12:54:02 -06:00
(nextSequence.body || [])[index] = update;
dispatch(overwrite(sequence, nextSequence));
}
function onChange(e: DropDownItem) {
2019-02-04 07:32:26 -07:00
if (e.value && isNumber(e.value)) {
2017-08-28 05:49:13 -06:00
const v = e.value;
2019-02-22 19:09:40 -07:00
const uuid = findSequenceById(props.resources, v).uuid;
const body = variableList(props.resources.sequenceMetas[uuid]);
overwriteStep({ kind: "execute", args: { sequence_id: v }, body });
2017-06-29 12:54:02 -06:00
} else {
overwriteStep({ kind: "nothing", args: {} });
}
}
2017-06-29 12:54:02 -06:00
2019-02-11 19:44:45 -07:00
const sequenceId = selectedItem().value;
const calleeUuid = sequenceId ?
findSequenceById(props.resources, sequenceId).uuid : undefined;
const calledSequenceVariableData = calleeUuid ?
props.resources.sequenceMetas[calleeUuid] : undefined;
2019-02-22 19:09:40 -07:00
/** Replaces the execute step body with a new array of bodyVariables. */
const assignVariable = (bodyVariables: ParameterApplication[]) =>
(variable: ParameterApplication) => {
block.body = addOrEditParamApps(bodyVariables, variable);
2019-02-11 19:44:45 -07:00
overwriteStep(block);
};
return { onChange, selectedItem, calledSequenceVariableData, assignVariable };
};