Farmbot-Web-App/frontend/farmware/index.tsx

273 lines
10 KiB
TypeScript
Raw Normal View History

2017-06-29 12:54:02 -06:00
import * as React from "react";
import { connect } from "react-redux";
2018-06-21 15:04:21 -06:00
import {
2020-02-28 09:35:32 -07:00
Page, Row, LeftPanel, CenterPanel, RightPanel, DocSlug,
2018-06-21 15:04:21 -06:00
} from "../ui/index";
2018-11-09 13:40:36 -07:00
import { mapStateToProps, isPendingInstallation } from "./state_to_props";
2017-07-28 15:24:21 -06:00
import { Photos } from "./images/photos";
import { CameraCalibration } from "./camera_calibration/camera_calibration";
2017-06-29 12:54:02 -06:00
import { FarmwareProps } from "../devices/interfaces";
2017-07-28 15:24:21 -06:00
import { WeedDetector } from "./weed_detector/index";
import { envGet } from "./weed_detector/remote_env/selectors";
2018-06-21 15:04:21 -06:00
import { setActiveFarmwareByName } from "./set_active_farmware_by_name";
import { FarmwareList } from "./farmware_list";
import {
2020-02-28 09:35:32 -07:00
FarmwareForm, needsFarmwareForm, farmwareHelpText,
2018-06-21 15:04:21 -06:00
} from "./farmware_forms";
import { urlFriendly } from "../util";
2019-04-09 19:45:59 -06:00
import { ToolTips, Actions } from "../constants";
2018-06-21 15:04:21 -06:00
import { FarmwareInfo } from "./farmware_info";
2019-03-20 14:18:19 -06:00
import { Farmwares, FarmwareManifestInfo } from "./interfaces";
2018-06-21 15:04:21 -06:00
import { commandErr } from "../devices/actions";
import { getDevice } from "../device";
2019-04-02 13:59:37 -06:00
import { t } from "../i18next_wrapper";
2019-04-09 19:15:50 -06:00
import { isBotOnline } from "../devices/must_be_online";
2019-04-09 23:17:03 -06:00
import { BooleanSetting } from "../session_keys";
2019-04-26 16:11:33 -06:00
import { Dictionary } from "farmbot";
2019-12-27 11:37:54 -07:00
import { WDENVKey } from "./weed_detector/remote_env/interfaces";
2018-01-22 13:17:29 -07:00
2018-06-21 15:04:21 -06:00
/** Get the correct help text for the provided Farmware. */
const getToolTipByFarmware =
(farmwares: Farmwares, farmwareName: string | undefined) => {
if (farmwareName) {
switch (urlFriendly(farmwareName).replace("-", "_")) {
case "take_photo":
case "photos":
return ToolTips.PHOTOS;
case "camera_calibration":
return ToolTips.CAMERA_CALIBRATION;
case "plant_detection":
case "weed_detector":
return ToolTips.WEED_DETECTOR;
default:
return farmwareHelpText(getFarmwareByName(farmwares, farmwareName));
}
} else {
return "";
}
};
/** Get a documentation link for the provided Farmware if one exists. */
const getDocLinkByFarmware =
(farmwareName: string | undefined): DocSlug | undefined => {
if (farmwareName) {
switch (urlFriendly(farmwareName).replace("-", "_")) {
case "camera_calibration":
2019-06-14 16:59:11 -06:00
return "camera-calibration";
2018-06-21 15:04:21 -06:00
case "plant_detection":
case "weed_detector":
2019-06-14 16:59:11 -06:00
return "weed-detection";
2018-06-21 15:04:21 -06:00
}
}
};
/** Get Farmware details for the provided Farmware name. */
const getFarmwareByName =
(farmwares: Farmwares, farmwareName: string | undefined) => {
switch (farmwareName) {
case "Photos":
return farmwares["take-photo"];
case "Camera Calibration":
return farmwares["camera-calibration"];
case "Weed Detector":
return farmwares["plant-detection"];
default:
return farmwares[farmwareName || ""];
}
};
2019-04-26 16:11:33 -06:00
const FARMWARE_NAMES_1ST_PARTY: Dictionary<string> = {
"take-photo": "Photos",
"camera-calibration": "Camera Calibration",
"plant-detection": "Weed Detector",
};
export const getFormattedFarmwareName = (farmwareName: string) =>
FARMWARE_NAMES_1ST_PARTY[farmwareName] || farmwareName;
export const farmwareUrlFriendly = (farmwareName: string) =>
urlFriendly(farmwareName).replace(/-/g, "_");
2018-06-21 15:04:21 -06:00
/** Execute a Farmware. */
2018-11-09 13:40:36 -07:00
const run = (farmwareName: string) => () => {
getDevice().execScript(farmwareName)
.then(() => { }, commandErr("Farmware execution"));
2018-06-21 15:04:21 -06:00
};
2017-06-29 12:54:02 -06:00
2019-04-09 19:15:50 -06:00
interface BasicFarmwarePageProps {
farmwareName: string;
farmware: FarmwareManifestInfo | undefined;
botOnline: boolean;
}
export const BasicFarmwarePage = ({ farmwareName, farmware, botOnline }:
BasicFarmwarePageProps) =>
2020-02-28 09:34:28 -07:00
<div className={"basic-farmware-page"}>
2018-11-09 13:40:36 -07:00
<button
className="fb-button green farmware-button"
2019-04-09 19:15:50 -06:00
disabled={isPendingInstallation(farmware) || !botOnline}
2020-02-28 09:34:28 -07:00
title={t("Run Farmware")}
2018-11-09 13:40:36 -07:00
onClick={run(farmwareName)}>
{t("Run")}
</button>
<p>
{isPendingInstallation(farmware)
? t("Pending installation.")
: t("No inputs provided.")}
</p>
</div>;
2019-09-19 13:09:00 -06:00
export class RawFarmwarePage extends React.Component<FarmwareProps, {}> {
2018-06-21 15:04:21 -06:00
get current() { return this.props.currentFarmware; }
2019-04-09 19:15:50 -06:00
get botOnline() {
return isBotOnline(this.props.syncStatus, this.props.botToMqttStatus);
}
2020-05-06 16:03:15 -06:00
componentDidMount() {
2019-06-14 16:59:11 -06:00
if (window.innerWidth > 450) {
this.props.dispatch({
type: Actions.SELECT_FARMWARE,
payload: "Photos"
});
}
2019-04-29 20:23:55 -06:00
const farmwareNames = Object.values(this.props.farmwares).map(x => x.name)
.concat(Object.keys(FARMWARE_NAMES_1ST_PARTY));
setActiveFarmwareByName(farmwareNames);
2018-06-21 15:04:21 -06:00
}
/** Load Farmware input panel contents for 1st & 3rd party Farmware. */
getPanelByFarmware(farmwareName: string) {
2019-12-27 11:37:54 -07:00
const wDEnvGet = (key: WDENVKey) => envGet(key, this.props.wDEnv);
2019-04-26 16:11:33 -06:00
switch (farmwareUrlFriendly(farmwareName)) {
2018-06-21 15:04:21 -06:00
case "take_photo":
case "photos":
return <Photos
2019-02-10 22:10:58 -07:00
syncStatus={this.props.syncStatus}
botToMqttStatus={this.props.botToMqttStatus}
2019-04-09 23:17:03 -06:00
timeSettings={this.props.timeSettings}
2018-06-21 15:04:21 -06:00
dispatch={this.props.dispatch}
images={this.props.images}
2019-12-27 11:37:54 -07:00
env={this.props.env}
currentImage={this.props.currentImage}
imageJobs={this.props.imageJobs} />;
2018-06-21 15:04:21 -06:00
case "camera_calibration":
return <CameraCalibration
syncStatus={this.props.syncStatus}
dispatch={this.props.dispatch}
currentImage={this.props.currentImage}
images={this.props.images}
2019-12-27 11:37:54 -07:00
wDEnv={this.props.wDEnv}
2018-06-21 15:04:21 -06:00
env={this.props.env}
2018-11-01 11:17:18 -06:00
saveFarmwareEnv={this.props.saveFarmwareEnv}
2019-12-27 11:37:54 -07:00
iteration={wDEnvGet("CAMERA_CALIBRATION_iteration")}
morph={wDEnvGet("CAMERA_CALIBRATION_morph")}
blur={wDEnvGet("CAMERA_CALIBRATION_blur")}
H_LO={wDEnvGet("CAMERA_CALIBRATION_H_LO")}
S_LO={wDEnvGet("CAMERA_CALIBRATION_S_LO")}
V_LO={wDEnvGet("CAMERA_CALIBRATION_V_LO")}
H_HI={wDEnvGet("CAMERA_CALIBRATION_H_HI")}
S_HI={wDEnvGet("CAMERA_CALIBRATION_S_HI")}
V_HI={wDEnvGet("CAMERA_CALIBRATION_V_HI")}
2019-04-09 23:17:03 -06:00
timeSettings={this.props.timeSettings}
2018-11-01 11:17:18 -06:00
shouldDisplay={this.props.shouldDisplay}
2018-06-21 15:04:21 -06:00
botToMqttStatus={this.props.botToMqttStatus} />;
case "plant_detection":
case "weed_detector":
return <WeedDetector {...this.props} />;
default:
const farmware = getFarmwareByName(this.props.farmwares, farmwareName);
return farmware && needsFarmwareForm(farmware)
? <FarmwareForm farmware={farmware}
2019-12-27 11:37:54 -07:00
env={this.props.env}
2018-11-01 11:17:18 -06:00
shouldDisplay={this.props.shouldDisplay}
saveFarmwareEnv={this.props.saveFarmwareEnv}
2019-04-09 19:15:50 -06:00
botOnline={this.botOnline}
2018-11-01 11:17:18 -06:00
dispatch={this.props.dispatch} />
2018-11-09 13:40:36 -07:00
: <BasicFarmwarePage
farmwareName={farmwareName}
2019-04-09 19:15:50 -06:00
farmware={farmware}
botOnline={this.botOnline} />;
2018-06-21 15:04:21 -06:00
}
}
2019-04-09 19:45:59 -06:00
FarmwareBackButton = (props: { className: string }) => {
const infoOpen = props.className.includes("farmware-info-open");
2019-06-06 17:54:48 -06:00
return <i
className={`back-to-farmware fa fa-arrow-left ${props.className}`}
onClick={() => infoOpen
? this.props.dispatch({
type: Actions.SET_FARMWARE_INFO_STATE, payload: false
})
: this.props.dispatch({
type: Actions.SELECT_FARMWARE, payload: undefined
})}
title={infoOpen ? t("back to farmware") : t("back to farmware list")} />;
2019-04-09 19:45:59 -06:00
};
FarmwareInfoButton = (props: { className: string, online: boolean }) =>
2019-06-06 17:54:48 -06:00
<button
className={`farmware-info-button fb-button gray ${props.className}`}
disabled={!props.online}
2020-02-28 09:34:28 -07:00
title={t("open Farmware info")}
2019-06-06 17:54:48 -06:00
onClick={() => this.props.dispatch({
type: Actions.SET_FARMWARE_INFO_STATE, payload: true
})}>
{t("farmware info")}
</button>
2019-04-09 19:45:59 -06:00
2017-06-29 12:54:02 -06:00
render() {
2018-06-21 15:04:21 -06:00
const farmware = getFarmwareByName(
this.props.farmwares, this.current || "take-photo");
2019-04-09 19:45:59 -06:00
const farmwareOpen = this.current ? "open" : "";
const online = this.props.botToMqttStatus === "up";
const infoOpen = (this.props.infoOpen && online) ? "farmware-info-open" : "";
const activeClasses = [farmwareOpen, infoOpen].join(" ");
2019-04-09 23:17:03 -06:00
const showFirstParty =
!!this.props.getConfigValue(BooleanSetting.show_first_party_farmware);
2019-02-06 18:36:11 -07:00
return <Page className="farmware-page">
2017-06-29 12:54:02 -06:00
<Row>
2018-06-21 15:04:21 -06:00
<LeftPanel
2019-04-09 19:45:59 -06:00
className={`farmware-list-panel ${activeClasses}`}
2019-06-21 15:43:46 -06:00
title={t("Farmware")}>
2018-06-21 15:04:21 -06:00
<FarmwareList
current={this.current}
2017-06-29 12:54:02 -06:00
dispatch={this.props.dispatch}
2018-11-02 13:53:17 -06:00
shouldDisplay={this.props.shouldDisplay}
2018-02-14 22:07:36 -07:00
farmwares={this.props.farmwares}
2018-11-05 18:37:09 -07:00
installations={this.props.taggedFarmwareInstallations}
2018-06-21 15:04:21 -06:00
firstPartyFarmwareNames={this.props.firstPartyFarmwareNames}
2019-04-09 23:17:03 -06:00
showFirstParty={showFirstParty} />
2018-06-21 15:04:21 -06:00
</LeftPanel>
<CenterPanel
2019-04-09 19:45:59 -06:00
className={`farmware-input-panel ${activeClasses}`}
2019-06-06 17:54:48 -06:00
backButton={<this.FarmwareBackButton className={activeClasses} />}
title={getFormattedFarmwareName(this.current || "Photos")}>
2018-06-21 15:04:21 -06:00
{<div className="farmware-input-panel-contents">
2019-06-06 17:54:48 -06:00
<this.FarmwareInfoButton className={activeClasses} online={online} />
2018-06-21 15:04:21 -06:00
{this.getPanelByFarmware(this.current ? this.current : "photos")}
</div>}
</CenterPanel>
<RightPanel
2019-04-09 19:45:59 -06:00
className={`farmware-info-panel ${activeClasses}`}
2019-06-06 17:54:48 -06:00
backButton={<this.FarmwareBackButton className={activeClasses} />}
2018-06-21 15:04:21 -06:00
title={t("Information")}
helpText={getToolTipByFarmware(this.props.farmwares, this.current)
|| ToolTips.PHOTOS}
docPage={getDocLinkByFarmware(this.current)}
2018-06-21 15:04:21 -06:00
show={!!farmware}>
<FarmwareInfo
2018-11-05 18:37:09 -07:00
dispatch={this.props.dispatch}
2018-06-21 15:04:21 -06:00
farmware={farmware}
2018-11-05 18:37:09 -07:00
installations={this.props.taggedFarmwareInstallations}
shouldDisplay={this.props.shouldDisplay}
2018-06-21 15:04:21 -06:00
firstPartyFarmwareNames={this.props.firstPartyFarmwareNames}
2019-04-09 23:17:03 -06:00
showFirstParty={showFirstParty} />
2018-06-21 15:04:21 -06:00
</RightPanel>
2017-06-29 12:54:02 -06:00
</Row>
</Page>;
}
2017-07-26 19:13:02 -06:00
}
2019-09-19 13:09:00 -06:00
export const FarmwarePage = connect(mapStateToProps)(RawFarmwarePage);