Farmbot-Web-App/frontend/farm_designer/points/create_points.tsx

313 lines
8.7 KiB
TypeScript
Raw Normal View History

2018-02-20 17:13:14 -07:00
import * as React from "react";
import { connect } from "react-redux";
2019-09-16 10:55:50 -06:00
import {
Everything,
2020-02-28 09:35:32 -07:00
ResourceColor,
2019-09-16 10:55:50 -06:00
} from "../../interfaces";
2018-02-20 17:13:14 -07:00
import { initSave } from "../../api/crud";
import {
2019-09-16 10:55:50 -06:00
Row,
Col,
BlurableInput,
2020-02-28 09:35:32 -07:00
ColorPicker,
2018-02-20 17:13:14 -07:00
} from "../../ui/index";
import { DrawnPointPayl } from "../interfaces";
2018-08-01 18:25:00 -06:00
import { Actions, Content } from "../../constants";
2018-02-20 17:13:14 -07:00
import { deletePoints } from "../../farmware/weed_detector/actions";
import { GenericPointer, WeedPointer } from "farmbot/dist/resources/api_resources";
import {
2019-09-16 10:55:50 -06:00
DesignerPanel,
DesignerPanelHeader,
2020-02-28 09:35:32 -07:00
DesignerPanelContent,
2019-12-10 13:09:52 -07:00
} from "../designer_panel";
2019-01-13 16:39:26 -07:00
import { parseIntInput } from "../../util";
2019-04-02 13:59:37 -06:00
import { t } from "../../i18next_wrapper";
2019-10-25 09:33:33 -06:00
import { Panel } from "../panel_header";
2020-02-26 11:10:59 -07:00
import { history, getPathArray } from "../../history";
2019-12-10 13:09:52 -07:00
import { ListItem } from "../plants/plant_panel";
2020-02-26 11:10:59 -07:00
import { success } from "../../toast/toast";
2018-02-20 17:13:14 -07:00
export function mapStateToProps(props: Everything): CreatePointsProps {
const { position } = props.bot.hardware.location_data;
const { drawnPoint, drawnWeed } = props.resources.consumers.farm_designer;
2018-02-20 17:13:14 -07:00
return {
dispatch: props.dispatch,
drawnPoint: drawnPoint || drawnWeed,
deviceX: position.x || 0,
deviceY: position.y || 0,
2018-02-20 17:13:14 -07:00
};
}
export interface CreatePointsProps {
dispatch: Function;
drawnPoint: DrawnPointPayl | undefined;
deviceX: number;
deviceY: number;
2018-02-20 17:13:14 -07:00
}
type CreatePointsState = Partial<DrawnPointPayl>;
2018-02-20 17:13:14 -07:00
const DEFAULTS: DrawnPointPayl = {
2019-11-07 12:17:50 -07:00
name: undefined,
2019-09-16 10:55:50 -06:00
cx: 1,
cy: 1,
r: 15,
2019-11-07 12:17:50 -07:00
color: undefined,
2019-09-16 10:55:50 -06:00
};
2019-09-19 13:09:00 -06:00
export class RawCreatePoints
2018-02-20 17:13:14 -07:00
extends React.Component<CreatePointsProps, Partial<CreatePointsState>> {
constructor(props: CreatePointsProps) {
super(props);
this.state = {};
}
attr = <T extends (keyof DrawnPointPayl & keyof CreatePointsState)>(key: T,
fallback = DEFAULTS[key]): DrawnPointPayl[T] => {
const p = this.props.drawnPoint;
const userValue = this.state[key] as DrawnPointPayl[T] | undefined;
2019-09-16 10:55:50 -06:00
const propValue = p ? p[key] : fallback;
if (typeof userValue === "undefined") {
return propValue;
} else {
return userValue;
}
};
2018-02-20 17:13:14 -07:00
2019-11-07 12:17:50 -07:00
get defaultName() {
return this.panel == "weeds"
? t("Created Weed")
: t("Created Point");
}
get defaultColor() { return this.panel == "weeds" ? "red" : "green"; }
getPointData = (): DrawnPointPayl => {
2019-09-16 10:55:50 -06:00
return {
name: this.attr("name"),
cx: this.attr("cx"),
cy: this.attr("cy"),
r: this.attr("r"),
2019-11-07 12:17:50 -07:00
color: this.attr("color") || this.defaultColor,
2019-09-16 10:55:50 -06:00
};
2018-02-20 17:13:14 -07:00
}
cancel = () => {
this.props.dispatch({
type: this.panel == "weeds"
? Actions.SET_DRAWN_WEED_DATA
: Actions.SET_DRAWN_POINT_DATA,
2018-02-20 17:13:14 -07:00
payload: undefined
});
2019-08-23 15:18:28 -06:00
this.setState({
cx: undefined,
cy: undefined,
2019-09-16 14:15:15 -06:00
r: undefined,
color: undefined
2019-08-23 15:18:28 -06:00
});
2018-02-20 17:13:14 -07:00
}
2019-11-07 12:17:50 -07:00
loadDefaultPoint = () => {
2018-02-20 17:13:14 -07:00
this.props.dispatch({
type: this.panel == "weeds"
? Actions.SET_DRAWN_WEED_DATA
: Actions.SET_DRAWN_POINT_DATA,
2019-11-07 12:17:50 -07:00
payload: {
name: this.defaultName,
cx: DEFAULTS.cx,
cy: DEFAULTS.cy,
r: DEFAULTS.r,
color: this.defaultColor,
} as DrawnPointPayl
2018-02-20 17:13:14 -07:00
});
}
2020-05-06 16:03:15 -06:00
componentDidMount() {
2019-11-07 12:17:50 -07:00
this.loadDefaultPoint();
}
componentWillUnmount() {
this.cancel();
}
2019-08-23 15:18:28 -06:00
/** Update fields. */
updateValue = (key: keyof CreatePointsState) => {
2018-02-20 17:13:14 -07:00
return (e: React.SyntheticEvent<HTMLInputElement>) => {
2019-08-23 15:18:28 -06:00
const { value } = e.currentTarget;
if (this.props.drawnPoint) {
2019-09-16 10:55:50 -06:00
const point = this.getPointData();
2019-08-23 15:18:28 -06:00
switch (key) {
case "name":
case "color":
2019-11-07 12:17:50 -07:00
this.setState({ [key]: value });
2019-08-23 15:18:28 -06:00
point[key] = value;
break;
default:
2019-11-07 12:17:50 -07:00
const intValue = parseIntInput(value);
this.setState({ [key]: intValue });
point[key] = intValue;
2019-08-23 15:18:28 -06:00
}
2018-02-20 17:13:14 -07:00
this.props.dispatch({
type: this.panel == "weeds"
? Actions.SET_DRAWN_WEED_DATA
: Actions.SET_DRAWN_POINT_DATA,
2018-02-20 17:13:14 -07:00
payload: point
});
}
};
}
2019-01-13 17:16:22 -07:00
changeColor = (color: ResourceColor) => {
2018-02-20 17:13:14 -07:00
this.setState({ color });
2019-11-07 12:17:50 -07:00
const point = this.getPointData();
point.color = color;
2019-09-16 10:55:50 -06:00
this.props.dispatch({
type: this.panel == "weeds"
? Actions.SET_DRAWN_WEED_DATA
: Actions.SET_DRAWN_POINT_DATA,
2019-11-07 12:17:50 -07:00
payload: point
2019-09-16 10:55:50 -06:00
});
2018-02-20 17:13:14 -07:00
}
2019-11-07 12:17:50 -07:00
get panel() { return getPathArray()[3] || "points"; }
2018-02-20 17:13:14 -07:00
createPoint = () => {
const body: GenericPointer | WeedPointer = {
pointer_type: this.panel == "weeds" ? "Weed" : "GenericPointer",
2019-11-07 12:17:50 -07:00
name: this.attr("name") || this.defaultName,
2019-09-16 10:55:50 -06:00
meta: {
2019-11-07 12:17:50 -07:00
color: this.attr("color") || this.defaultColor,
created_by: "farm-designer",
type: this.panel == "weeds" ? "weed" : "point",
2019-09-16 10:55:50 -06:00
},
x: this.attr("cx"),
y: this.attr("cy"),
2018-10-31 19:01:31 -06:00
z: 0,
2019-09-16 10:55:50 -06:00
radius: this.attr("r"),
2018-02-20 17:13:14 -07:00
};
2018-10-31 19:01:31 -06:00
this.props.dispatch(initSave("Point", body));
2020-02-26 11:10:59 -07:00
success(this.panel == "weeds"
? t("Weed created.")
: t("Point created."));
2018-02-20 17:13:14 -07:00
this.cancel();
2020-02-26 11:10:59 -07:00
history.push(`/app/designer/${this.panel}`);
2018-02-20 17:13:14 -07:00
}
2020-02-26 11:10:59 -07:00
2019-11-20 12:48:55 -07:00
PointProperties = () =>
<ul>
<li>
2020-04-13 13:24:38 -06:00
<Row>
<div className={"point-name-input"}>
<Col xs={10}>
<label>{t("Name")}</label>
<BlurableInput
name="name"
type="text"
onCommit={this.updateValue("name")}
value={this.attr("name") || this.defaultName} />
</Col>
</div>
<div className={"point-color-input"}>
<Col xs={2}>
<ColorPicker
current={(this.attr("color") || this.defaultColor) as ResourceColor}
onChange={this.changeColor} />
</Col>
</div>
</Row>
2019-11-20 12:48:55 -07:00
</li>
<ListItem name={t("Location")}>
<Row>
<Col xs={6}>
<label>{t("X (mm)")}</label>
<BlurableInput
name="cx"
type="number"
onCommit={this.updateValue("cx")}
value={this.attr("cx", this.props.deviceX)} />
</Col>
<Col xs={6}>
<label>{t("Y (mm)")}</label>
<BlurableInput
name="cy"
type="number"
onCommit={this.updateValue("cy")}
value={this.attr("cy", this.props.deviceY)} />
</Col>
</Row>
</ListItem>
<ListItem name={t("Size")}>
<Row>
<Col xs={6}>
<label>{t("radius")}</label>
<BlurableInput
name="r"
type="number"
onCommit={this.updateValue("r")}
value={this.attr("r")}
min={0} />
</Col>
</Row>
</ListItem>
</ul>
2018-08-01 19:27:19 -06:00
PointActions = () =>
<Row>
<button className="fb-button green"
2020-02-28 09:34:28 -07:00
title={t("save")}
2018-08-01 19:27:19 -06:00
onClick={this.createPoint}>
2019-11-07 12:17:50 -07:00
{t("Save")}
2018-08-01 19:27:19 -06:00
</button>
</Row>
DeleteAllPoints = (type: "point" | "weed") => {
const meta = { created_by: "farm-designer" };
return <Row>
2018-08-01 19:27:19 -06:00
<div className="delete-row">
<label>{t("delete")}</label>
2019-11-07 12:17:50 -07:00
<p>{type === "weed"
? t("Delete all of the weeds created through this panel.")
: t("Delete all of the points created through this panel.")}</p>
2018-08-01 19:27:19 -06:00
<button className="fb-button red delete"
2020-02-28 09:34:28 -07:00
title={t("delete all")}
2018-08-01 19:27:19 -06:00
onClick={() => {
2019-11-07 12:17:50 -07:00
if (confirm(type === "weed"
? t("Delete all the weeds you have created?")
: t("Delete all the points you have created?"))) {
this.props.dispatch(deletePoints("points", {
pointer_type: type === "weed" ? "Weed" : "GenericPointer",
meta,
2019-11-07 12:17:50 -07:00
}));
2018-08-01 19:27:19 -06:00
this.cancel();
}
}}>
2019-11-07 12:17:50 -07:00
{type === "weed"
? t("Delete all created weeds")
: t("Delete all created points")}
2018-08-01 19:27:19 -06:00
</button>
</div>
</Row>;
};
2018-08-01 19:27:19 -06:00
render() {
2019-11-07 12:17:50 -07:00
const panelType = this.panel == "weeds" ? Panel.Weeds : Panel.Points;
const panelDescription = this.panel == "weeds" ?
Content.CREATE_WEEDS_DESCRIPTION : Content.CREATE_POINTS_DESCRIPTION;
return <DesignerPanel panelName={"point-creation"} panel={panelType}>
<DesignerPanelHeader
panelName={"point-creation"}
2019-11-07 12:17:50 -07:00
panel={panelType}
2020-02-20 19:38:50 -07:00
title={this.panel == "weeds" ? t("Add weed") : t("Add point")}
2019-11-07 12:17:50 -07:00
backTo={`/app/designer/${this.panel}`}
description={panelDescription} />
<DesignerPanelContent panelName={"point-creation"}>
2018-08-01 19:27:19 -06:00
<this.PointProperties />
<this.PointActions />
2019-11-07 12:17:50 -07:00
{this.DeleteAllPoints(this.panel == "weeds" ? "weed" : "point")}
</DesignerPanelContent>
</DesignerPanel>;
2018-02-20 17:13:14 -07:00
}
}
2019-09-19 13:09:00 -06:00
export const CreatePoints = connect(mapStateToProps)(RawCreatePoints);