Farmbot-Web-App/frontend/app.tsx

160 lines
5.7 KiB
TypeScript
Raw Normal View History

import * as React from "react";
2017-07-06 21:26:37 -06:00
import { connect } from "react-redux";
2019-06-24 15:39:49 -06:00
import { init, error } from "./toast/toast";
2017-07-06 21:26:37 -06:00
import { NavBar } from "./nav";
2019-04-09 23:17:03 -06:00
import { Everything, TimeSettings } from "./interfaces";
2017-10-04 23:02:38 -06:00
import { LoadingPlant } from "./loading_plant";
2019-12-27 11:37:54 -07:00
import { BotState, Xyz, UserEnv } from "./devices/interfaces";
2019-04-09 18:45:51 -06:00
import { ResourceName, TaggedUser, TaggedLog } from "farmbot";
2017-12-28 13:48:03 -07:00
import {
2019-04-09 23:17:03 -06:00
maybeFetchUser,
maybeGetTimeSettings,
getDeviceAccountSettings,
2017-12-28 13:48:03 -07:00
} from "./resources/selectors";
2017-07-06 21:26:37 -06:00
import { HotKeys } from "./hotkeys";
2017-07-07 22:23:25 -06:00
import { ControlsPopup } from "./controls_popup";
import { Content } from "./constants";
2019-04-17 13:30:58 -06:00
import { validBotLocationData, validFwConfig, validFbosConfig } from "./util";
2018-01-10 13:08:56 -07:00
import { BooleanSetting } from "./session_keys";
import { getPathArray } from "./history";
2019-04-09 18:45:51 -06:00
import {
2020-02-28 09:35:32 -07:00
getWebAppConfigValue, GetWebAppConfigValue,
2019-04-09 18:45:51 -06:00
} from "./config_storage/actions";
2018-05-17 14:12:33 -06:00
import { takeSortedLogs } from "./logs/state_to_props";
2018-10-22 09:35:44 -06:00
import { FirmwareConfig } from "farmbot/dist/resources/configs/firmware";
2019-04-11 21:17:18 -06:00
import { getFirmwareConfig, getFbosConfig } from "./resources/getters";
2019-02-04 07:32:26 -07:00
import { intersection } from "lodash";
2019-04-02 13:59:37 -06:00
import { t } from "./i18next_wrapper";
2019-04-09 18:45:51 -06:00
import { ResourceIndex } from "./resources/interfaces";
2020-03-13 15:06:40 -06:00
import { isBotOnlineFromState } from "./devices/must_be_online";
2019-07-15 14:22:41 -06:00
import { getAllAlerts } from "./messages/state_to_props";
import { PingDictionary } from "./devices/connectivity/qos";
2019-12-27 11:37:54 -07:00
import { getEnv, getShouldDisplayFn } from "./farmware/state_to_props";
2020-03-13 15:06:40 -06:00
import { filterAlerts } from "./messages/alerts";
2017-06-29 12:54:02 -06:00
/** For the logger module */
2017-06-29 12:54:02 -06:00
init();
2017-09-08 12:38:46 -06:00
export interface AppProps {
2017-06-29 12:54:02 -06:00
dispatch: Function;
loaded: ResourceName[];
2018-05-17 14:12:33 -06:00
logs: TaggedLog[];
2017-06-29 12:54:02 -06:00
user: TaggedUser | undefined;
bot: BotState;
consistent: boolean;
2019-04-09 23:17:03 -06:00
timeSettings: TimeSettings;
2018-01-10 13:08:56 -07:00
axisInversion: Record<Xyz, boolean>;
2018-04-12 17:55:38 -06:00
xySwap: boolean;
2018-03-09 02:34:24 -07:00
firmwareConfig: FirmwareConfig | undefined;
animate: boolean;
2018-08-30 19:25:58 -06:00
getConfigValue: GetWebAppConfigValue;
2018-10-15 17:23:58 -06:00
tour: string | undefined;
2019-04-09 18:45:51 -06:00
resources: ResourceIndex;
2019-04-11 21:17:18 -06:00
autoSync: boolean;
2019-04-16 11:03:44 -06:00
alertCount: number;
pings: PingDictionary;
2019-12-27 11:37:54 -07:00
env: UserEnv;
2017-06-29 12:54:02 -06:00
}
2019-03-04 15:14:35 -07:00
export function mapStateToProps(props: Everything): AppProps {
const webAppConfigValue = getWebAppConfigValue(() => props);
2019-04-11 21:17:18 -06:00
const fbosConfig = validFbosConfig(getFbosConfig(props.resources.index));
2019-12-27 11:37:54 -07:00
const shouldDisplay = getShouldDisplayFn(props.resources.index, props.bot);
const env = getEnv(props.resources.index, shouldDisplay, props.bot);
2017-07-06 21:26:37 -06:00
return {
2019-04-09 23:17:03 -06:00
timeSettings: maybeGetTimeSettings(props.resources.index),
2017-06-29 12:54:02 -06:00
dispatch: props.dispatch,
user: maybeFetchUser(props.resources.index),
bot: props.bot,
2018-05-17 14:12:33 -06:00
logs: takeSortedLogs(250, props.resources.index),
loaded: props.resources.loaded,
2017-11-20 12:44:46 -07:00
consistent: !!(props.bot || {}).consistent,
2018-01-10 13:08:56 -07:00
axisInversion: {
x: !!webAppConfigValue(BooleanSetting.x_axis_inverted),
y: !!webAppConfigValue(BooleanSetting.y_axis_inverted),
z: !!webAppConfigValue(BooleanSetting.z_axis_inverted),
2018-03-09 02:34:24 -07:00
},
xySwap: !!webAppConfigValue(BooleanSetting.xy_swap),
firmwareConfig: validFwConfig(getFirmwareConfig(props.resources.index)),
animate: !webAppConfigValue(BooleanSetting.disable_animations),
2018-08-30 19:25:58 -06:00
getConfigValue: webAppConfigValue,
2018-10-15 17:23:58 -06:00
tour: props.resources.consumers.help.currentTour,
2019-04-09 18:45:51 -06:00
resources: props.resources.index,
2019-04-11 21:17:18 -06:00
autoSync: !!(fbosConfig && fbosConfig.auto_sync),
2020-03-13 15:06:40 -06:00
alertCount: getAllAlerts(props.resources).filter(filterAlerts).length,
2019-12-27 11:37:54 -07:00
pings: props.bot.connectivity.pings,
env,
2017-06-29 12:54:02 -06:00
};
}
/** Time at which the app gives up and asks the user to refresh */
const LOAD_TIME_FAILURE_MS = 25000;
2017-06-29 12:54:02 -06:00
/**
* Relational resources that *must* load before app starts.
* App will crash at load time if they are not pre-loaded.
*/
const MUST_LOAD: ResourceName[] = [
2017-10-27 07:31:25 -06:00
"Sequence",
"Regimen",
"FarmEvent",
"Point",
2019-04-09 18:45:51 -06:00
"Device",
2020-02-28 09:35:32 -07:00
"Tool", // Sequence editor needs this for rendering.
2017-06-29 12:54:02 -06:00
];
2019-09-19 13:09:00 -06:00
export class RawApp extends React.Component<AppProps, {}> {
2018-03-02 08:25:15 -07:00
private get isLoaded() {
2017-06-29 12:54:02 -06:00
return (MUST_LOAD.length ===
2019-02-04 07:32:26 -07:00
intersection(this.props.loaded, MUST_LOAD).length);
2017-06-29 12:54:02 -06:00
}
/**
* If the sync object takes more than 10s to load, the user will be granted
* access into the app, but still warned.
*/
2017-07-06 21:26:37 -06:00
componentDidMount() {
2017-06-29 12:54:02 -06:00
setTimeout(() => {
2017-07-06 21:26:37 -06:00
if (!this.isLoaded) {
error(t(Content.APP_LOAD_TIMEOUT_MESSAGE), t("Warning"));
2017-06-29 12:54:02 -06:00
}
}, LOAD_TIME_FAILURE_MS);
2017-06-29 12:54:02 -06:00
}
2017-07-06 21:26:37 -06:00
render() {
const syncLoaded = this.isLoaded;
const currentPage = getPathArray()[2];
2018-01-23 16:21:44 -07:00
const { location_data, mcu_params } = this.props.bot.hardware;
2017-06-29 12:54:02 -06:00
return <div className="app">
2019-03-04 15:14:35 -07:00
{!syncLoaded && <LoadingPlant animate={this.props.animate} />}
2017-07-07 00:00:20 -06:00
<HotKeys dispatch={this.props.dispatch} />
2019-04-09 18:45:51 -06:00
{syncLoaded && <NavBar
2019-04-09 23:17:03 -06:00
timeSettings={this.props.timeSettings}
consistent={this.props.consistent}
2017-06-29 12:54:02 -06:00
user={this.props.user}
bot={this.props.bot}
dispatch={this.props.dispatch}
2018-08-30 19:25:58 -06:00
logs={this.props.logs}
2018-10-15 17:23:58 -06:00
getConfigValue={this.props.getConfigValue}
2019-04-09 18:45:51 -06:00
tour={this.props.tour}
2019-04-11 21:17:18 -06:00
autoSync={this.props.autoSync}
2019-04-16 11:03:44 -06:00
alertCount={this.props.alertCount}
device={getDeviceAccountSettings(this.props.resources)}
pings={this.props.pings} />}
2017-07-06 21:26:37 -06:00
{syncLoaded && this.props.children}
{!(["controls", "account", "regimens"].includes(currentPage)) &&
2017-09-08 12:38:46 -06:00
<ControlsPopup
dispatch={this.props.dispatch}
2018-01-17 18:13:02 -07:00
axisInversion={this.props.axisInversion}
2018-01-23 16:21:44 -07:00
botPosition={validBotLocationData(location_data).position}
2018-04-12 19:27:06 -06:00
firmwareSettings={this.props.firmwareConfig || mcu_params}
xySwap={this.props.xySwap}
arduinoBusy={!!this.props.bot.hardware.informational_settings.busy}
2020-03-13 15:06:40 -06:00
botOnline={isBotOnlineFromState(this.props.bot)}
2019-12-27 11:37:54 -07:00
env={this.props.env}
2018-04-12 19:27:06 -06:00
stepSize={this.props.bot.stepSize} />}
2017-06-29 12:54:02 -06:00
</div>;
}
}
2019-09-19 13:09:00 -06:00
export const App = connect(mapStateToProps)(RawApp);