From b1c2b36a37432deffef4a28c0e2490481deabdd7 Mon Sep 17 00:00:00 2001 From: gabrielburnworth Date: Fri, 13 Mar 2020 14:06:40 -0700 Subject: [PATCH] settings refactoring --- frontend/app.tsx | 10 +- frontend/auth/__tests__/actions_test.ts | 5 +- frontend/auth/actions.ts | 5 +- frontend/connectivity/reducer_support.ts | 2 +- frontend/constants.ts | 2 + frontend/controls/__tests__/controls_test.tsx | 14 +- frontend/controls/controls.tsx | 7 +- frontend/controls/interfaces.ts | 3 +- .../controls/move/__tests__/move_test.tsx | 1 - frontend/controls/move/interfaces.ts | 2 - frontend/controls/move/move.tsx | 8 +- frontend/controls/state_to_props.ts | 2 - frontend/controls/toggle_button.tsx | 10 +- frontend/css/global.scss | 33 +-- frontend/devices/__tests__/actions_test.ts | 49 +++- frontend/devices/__tests__/devices_test.tsx | 29 --- frontend/devices/__tests__/reducer_test.ts | 30 ++- frontend/devices/actions.ts | 34 ++- .../__tests__/farmbot_os_settings_test.tsx | 137 ++++------- .../__tests__/hardware_settings_test.tsx | 27 ++- .../__tests__/lockable_button_test.tsx | 32 ++- .../__tests__/mcu_input_box_test.tsx | 23 +- .../components/boolean_mcu_input_group.tsx | 70 +++--- .../components/farmbot_os_settings.tsx | 229 +++++++----------- .../__tests__/board_type_test.tsx | 33 ++- .../__tests__/boot_sequence_selector_test.tsx | 16 +- .../__tests__/farmbot_os_row_test.tsx | 14 +- .../__tests__/fbos_details_test.tsx | 4 +- .../firmware_hardware_status_test.tsx | 16 -- .../fbos_settings/__tests__/firmware_test.tsx | 57 +++++ .../__tests__/last_seen_row_test.tsx | 44 ++-- .../fbos_settings/__tests__/name_row_test.tsx | 34 +++ .../__tests__/ota_time_selector_test.tsx | 78 ++++-- .../__tests__/power_and_reset_test.tsx | 34 +-- .../__tests__/timezone_row_test.tsx | 34 +++ .../fbos_settings/auto_sync_row.tsx | 26 +- .../fbos_settings/auto_update_row.tsx | 27 ++- .../components/fbos_settings/board_type.tsx | 48 ++-- .../fbos_settings/boot_sequence_selector.tsx | 36 ++- .../fbos_settings/camera_selection.tsx | 12 +- .../fbos_settings/factory_reset_row.tsx | 78 +++--- .../fbos_settings/farmbot_os_row.tsx | 135 +++++++---- .../fbos_settings/fbos_button_row.tsx | 26 +- .../components/fbos_settings/firmware.tsx | 49 ++++ .../firmware_hardware_status.tsx | 21 -- .../fbos_settings/flash_firmware_row.tsx | 42 ++++ .../components/fbos_settings/interfaces.ts | 31 ++- .../fbos_settings/last_seen_row.tsx | 8 + .../components/fbos_settings/name_row.tsx | 34 +++ .../fbos_settings/ota_time_selector.tsx | 19 +- .../fbos_settings/power_and_reset.tsx | 11 +- .../components/fbos_settings/timezone_row.tsx | 51 ++++ .../devices/components/hardware_settings.tsx | 16 +- .../__tests__/calibration_row_test.tsx | 2 +- .../__tests__/homing_and_calibration_test.tsx | 2 +- .../hardware_settings/calibration_row.tsx | 50 ++-- .../hardware_settings/danger_zone.tsx | 32 +-- .../components/hardware_settings/encoders.tsx | 4 +- .../components/hardware_settings/endstops.tsx | 4 +- .../hardware_settings/error_handling.tsx | 4 +- .../homing_and_calibration.tsx | 12 +- .../components/hardware_settings/motors.tsx | 6 +- .../hardware_settings/pin_guard.tsx | 43 ++-- .../hardware_settings/single_setting_row.tsx | 23 +- .../hardware_settings/space_panel_header.tsx | 42 ++-- frontend/devices/components/interfaces.ts | 6 +- .../devices/components/lockable_button.tsx | 5 +- .../devices/components/maybe_highlight.tsx | 14 +- .../components/numeric_mcu_input_group.tsx | 55 +++-- .../components/pin_guard_input_group.tsx | 134 +++++++--- frontend/devices/devices.tsx | 18 +- frontend/devices/interfaces.ts | 30 ++- frontend/devices/must_be_online.tsx | 8 + .../pin_bindings/pin_binding_input_group.tsx | 96 +++++--- .../devices/pin_bindings/pin_bindings.tsx | 9 +- .../pin_bindings/pin_bindings_list.tsx | 33 ++- frontend/devices/reducer.ts | 41 ++-- frontend/devices/state_to_props.ts | 13 +- .../__tests__/search_selectors_test.ts | 2 +- frontend/farm_designer/move_to.tsx | 7 +- .../plants/__tests__/crop_info_test.tsx | 6 +- frontend/farm_designer/plants/crop_info.tsx | 2 +- frontend/farm_designer/search_selectors.ts | 15 +- .../tools/__tests__/index_test.tsx | 5 +- frontend/farm_designer/tools/index.tsx | 12 +- frontend/messages/alerts.tsx | 5 +- 86 files changed, 1533 insertions(+), 1005 deletions(-) create mode 100644 frontend/devices/components/fbos_settings/__tests__/firmware_test.tsx create mode 100644 frontend/devices/components/fbos_settings/__tests__/name_row_test.tsx create mode 100644 frontend/devices/components/fbos_settings/__tests__/timezone_row_test.tsx create mode 100644 frontend/devices/components/fbos_settings/firmware.tsx create mode 100644 frontend/devices/components/fbos_settings/flash_firmware_row.tsx create mode 100644 frontend/devices/components/fbos_settings/name_row.tsx create mode 100644 frontend/devices/components/fbos_settings/timezone_row.tsx diff --git a/frontend/app.tsx b/frontend/app.tsx index cdf2c1519..6a32eb57d 100644 --- a/frontend/app.tsx +++ b/frontend/app.tsx @@ -26,11 +26,11 @@ import { getFirmwareConfig, getFbosConfig } from "./resources/getters"; import { intersection } from "lodash"; import { t } from "./i18next_wrapper"; import { ResourceIndex } from "./resources/interfaces"; -import { isBotOnline } from "./devices/must_be_online"; -import { getStatus } from "./connectivity/reducer_support"; +import { isBotOnlineFromState } from "./devices/must_be_online"; import { getAllAlerts } from "./messages/state_to_props"; import { PingDictionary } from "./devices/connectivity/qos"; import { getEnv, getShouldDisplayFn } from "./farmware/state_to_props"; +import { filterAlerts } from "./messages/alerts"; /** For the logger module */ init(); @@ -81,7 +81,7 @@ export function mapStateToProps(props: Everything): AppProps { tour: props.resources.consumers.help.currentTour, resources: props.resources.index, autoSync: !!(fbosConfig && fbosConfig.auto_sync), - alertCount: getAllAlerts(props.resources).length, + alertCount: getAllAlerts(props.resources).filter(filterAlerts).length, pings: props.bot.connectivity.pings, env, }; @@ -124,8 +124,6 @@ export class RawApp extends React.Component { const syncLoaded = this.isLoaded; const currentPage = getPathArray()[2]; const { location_data, mcu_params } = this.props.bot.hardware; - const { sync_status } = this.props.bot.hardware.informational_settings; - const bot2mqtt = this.props.bot.connectivity.uptime["bot.mqtt"]; return
{!syncLoaded && } @@ -151,7 +149,7 @@ export class RawApp extends React.Component { firmwareSettings={this.props.firmwareConfig || mcu_params} xySwap={this.props.xySwap} arduinoBusy={!!this.props.bot.hardware.informational_settings.busy} - botOnline={isBotOnline(sync_status, getStatus(bot2mqtt))} + botOnline={isBotOnlineFromState(this.props.bot)} env={this.props.env} stepSize={this.props.bot.stepSize} />}
; diff --git a/frontend/auth/__tests__/actions_test.ts b/frontend/auth/__tests__/actions_test.ts index 29d9aa9f6..c3e7bb9a4 100644 --- a/frontend/auth/__tests__/actions_test.ts +++ b/frontend/auth/__tests__/actions_test.ts @@ -3,8 +3,8 @@ jest.mock("axios", () => ({ response: { use: jest.fn() }, request: { use: jest.fn() } }, - post: jest.fn(() => { return Promise.resolve({ data: { foo: "bar" } }); }), - get: jest.fn(() => { return Promise.resolve({ data: { foo: "bar" } }); }), + post: jest.fn(() => Promise.resolve({ data: { foo: "bar" } })), + get: jest.fn(() => Promise.resolve({ data: { foo: "bar" } })), })); jest.mock("../../api/api", () => ({ @@ -22,6 +22,7 @@ jest.mock("../../devices/actions", () => ({ fetchReleases: jest.fn(), fetchLatestGHBetaRelease: jest.fn(), fetchMinOsFeatureData: jest.fn(), + fetchOsReleaseNotes: jest.fn(), })); import { didLogin } from "../actions"; diff --git a/frontend/auth/actions.ts b/frontend/auth/actions.ts index f8d417137..10199c84f 100644 --- a/frontend/auth/actions.ts +++ b/frontend/auth/actions.ts @@ -2,6 +2,7 @@ import axios from "axios"; import { fetchReleases, fetchMinOsFeatureData, fetchLatestGHBetaRelease, + fetchOsReleaseNotes, } from "../devices/actions"; import { AuthState } from "./interfaces"; import { ReduxAction } from "../redux/interfaces"; @@ -16,7 +17,6 @@ import { Actions } from "../constants"; import { connectDevice } from "../connectivity/connect_device"; import { getFirstPartyFarmwareList } from "../farmware/actions"; import { readOnlyInterceptor } from "../read_only_mode"; -import { ExternalUrl } from "../external_urls"; export function didLogin(authState: AuthState, dispatch: Function) { API.setBaseUrl(authState.token.unencoded.iss); @@ -25,7 +25,8 @@ export function didLogin(authState: AuthState, dispatch: Function) { beta_os_update_server && beta_os_update_server != "NOT_SET" && dispatch(fetchLatestGHBetaRelease(beta_os_update_server)); dispatch(getFirstPartyFarmwareList()); - dispatch(fetchMinOsFeatureData(ExternalUrl.featureMinVersions)); + dispatch(fetchMinOsFeatureData()); + dispatch(fetchOsReleaseNotes()); dispatch(setToken(authState)); Sync.fetchSyncData(dispatch); dispatch(connectDevice(authState)); diff --git a/frontend/connectivity/reducer_support.ts b/frontend/connectivity/reducer_support.ts index 41db3fdee..d86e0434a 100644 --- a/frontend/connectivity/reducer_support.ts +++ b/frontend/connectivity/reducer_support.ts @@ -1,5 +1,5 @@ import { ConnectionStatus } from "./interfaces"; export function getStatus(cs: ConnectionStatus | undefined): "up" | "down" { - return (cs && cs.state) || "down"; + return cs?.state || "down"; } diff --git a/frontend/constants.ts b/frontend/constants.ts index 15b21f9a1..b0abe47c0 100644 --- a/frontend/constants.ts +++ b/frontend/constants.ts @@ -1127,6 +1127,8 @@ export enum Actions { FETCH_BETA_OS_UPDATE_INFO_ERROR = "FETCH_BETA_OS_UPDATE_INFO_ERROR", FETCH_MIN_OS_FEATURE_INFO_OK = "FETCH_MIN_OS_FEATURE_INFO_OK", FETCH_MIN_OS_FEATURE_INFO_ERROR = "FETCH_MIN_OS_FEATURE_INFO_ERROR", + FETCH_OS_RELEASE_NOTES_OK = "FETCH_OS_RELEASE_NOTES_OK", + FETCH_OS_RELEASE_NOTES_ERROR = "FETCH_OS_RELEASE_NOTES_ERROR", INVERT_JOG_BUTTON = "INVERT_JOG_BUTTON", DISPLAY_ENCODER_DATA = "DISPLAY_ENCODER_DATA", STASH_STATUS = "STASH_STATUS", diff --git a/frontend/controls/__tests__/controls_test.tsx b/frontend/controls/__tests__/controls_test.tsx index aba980723..396de7375 100644 --- a/frontend/controls/__tests__/controls_test.tsx +++ b/frontend/controls/__tests__/controls_test.tsx @@ -18,10 +18,9 @@ describe("", () => { feeds: [fakeWebcamFeed()], peripherals: [fakePeripheral()], sensors: [fakeSensor()], - botToMqttStatus: "up", firmwareSettings: bot.hardware.mcu_params, shouldDisplay: () => true, - getWebAppConfigVal: jest.fn((key) => (mockConfig[key])), + getWebAppConfigVal: jest.fn(key => mockConfig[key]), sensorReadings: [], timeSettings: fakeTimeSettings(), env: {}, @@ -65,6 +64,17 @@ describe("", () => { .map(string => expect(txt).not.toContain(string)); }); + it("hides sensors widget based on model", () => { + mockConfig.hide_sensors = false; + const p = fakeProps(); + p.firmwareHardware = "express_k10"; + const wrapper = mount(); + const txt = wrapper.text().toLowerCase(); + ["move", "peripherals"] + .map(string => expect(txt).toContain(string)); + ["sensors"].map(string => expect(txt).not.toContain(string)); + }); + it("doesn't show sensor readings widget", () => { const p = fakeProps(); mockConfig.hide_sensors = true; diff --git a/frontend/controls/controls.tsx b/frontend/controls/controls.tsx index 5149af504..969e34256 100644 --- a/frontend/controls/controls.tsx +++ b/frontend/controls/controls.tsx @@ -9,7 +9,7 @@ import { Props } from "./interfaces"; import { Move } from "./move/move"; import { BooleanSetting } from "../session_keys"; import { SensorReadings } from "./sensor_readings/sensor_readings"; -import { isBotOnline } from "../devices/must_be_online"; +import { isBotOnlineFromState } from "../devices/must_be_online"; import { hasSensors } from "../devices/components/firmware_hardware_support"; /** Controls page. */ @@ -19,9 +19,7 @@ export class RawControls extends React.Component { } get botOnline() { - return isBotOnline( - this.props.bot.hardware.informational_settings.sync_status, - this.props.botToMqttStatus); + return isBotOnlineFromState(this.props.bot); } get hideSensors() { @@ -34,7 +32,6 @@ export class RawControls extends React.Component { env={this.props.env} dispatch={this.props.dispatch} arduinoBusy={this.arduinoBusy} - botToMqttStatus={this.props.botToMqttStatus} firmwareSettings={this.props.firmwareSettings} firmwareHardware={this.props.firmwareHardware} getWebAppConfigVal={this.props.getWebAppConfigVal} /> diff --git a/frontend/controls/interfaces.ts b/frontend/controls/interfaces.ts index 038dda123..93f1e8069 100644 --- a/frontend/controls/interfaces.ts +++ b/frontend/controls/interfaces.ts @@ -8,7 +8,6 @@ import { TaggedSensor, TaggedSensorReading, } from "farmbot"; -import { NetworkState } from "../connectivity/interfaces"; import { GetWebAppConfigValue } from "../config_storage/actions"; import { TimeSettings } from "../interfaces"; @@ -18,7 +17,6 @@ export interface Props { feeds: TaggedWebcamFeed[]; peripherals: TaggedPeripheral[]; sensors: TaggedSensor[]; - botToMqttStatus: NetworkState; firmwareSettings: McuParams; shouldDisplay: ShouldDisplay; getWebAppConfigVal: GetWebAppConfigValue; @@ -60,4 +58,5 @@ export interface ToggleButtonProps { dim?: boolean; grayscale?: boolean; title?: string; + className?: string; } diff --git a/frontend/controls/move/__tests__/move_test.tsx b/frontend/controls/move/__tests__/move_test.tsx index eae4f86f4..7ef748009 100644 --- a/frontend/controls/move/__tests__/move_test.tsx +++ b/frontend/controls/move/__tests__/move_test.tsx @@ -29,7 +29,6 @@ describe("", () => { dispatch: jest.fn(), bot: bot, arduinoBusy: false, - botToMqttStatus: "up", firmwareSettings: bot.hardware.mcu_params, getWebAppConfigVal: jest.fn((key) => (mockConfig[key])), env: {}, diff --git a/frontend/controls/move/interfaces.ts b/frontend/controls/move/interfaces.ts index 6d549b46e..914006f4e 100644 --- a/frontend/controls/move/interfaces.ts +++ b/frontend/controls/move/interfaces.ts @@ -1,6 +1,5 @@ import { BotPosition, BotState, UserEnv } from "../../devices/interfaces"; import { McuParams, Xyz, FirmwareHardware } from "farmbot"; -import { NetworkState } from "../../connectivity/interfaces"; import { GetWebAppConfigValue } from "../../config_storage/actions"; import { BooleanConfigKey } from "farmbot/dist/resources/configs/web_app"; @@ -11,7 +10,6 @@ export interface MoveProps { dispatch: Function; bot: BotState; arduinoBusy: boolean; - botToMqttStatus: NetworkState; firmwareSettings: McuParams; getWebAppConfigVal: GetWebAppConfigValue; env: UserEnv; diff --git a/frontend/controls/move/move.tsx b/frontend/controls/move/move.tsx index dd3916082..f752a6406 100644 --- a/frontend/controls/move/move.tsx +++ b/frontend/controls/move/move.tsx @@ -13,6 +13,7 @@ import { MotorPositionPlot } from "./motor_position_plot"; import { Popover, Position } from "@blueprintjs/core"; import { BooleanConfigKey } from "farmbot/dist/resources/configs/web_app"; import { t } from "../../i18next_wrapper"; +import { getStatus } from "../../connectivity/reducer_support"; export class Move extends React.Component { @@ -23,7 +24,8 @@ export class Move extends React.Component { !!this.props.getWebAppConfigVal(BooleanSetting[key]); render() { - const { location_data, informational_settings } = this.props.bot.hardware; + const { bot } = this.props; + const { location_data, informational_settings } = bot.hardware; const locationData = validBotLocationData(location_data); return { props), shouldDisplay, diff --git a/frontend/controls/toggle_button.tsx b/frontend/controls/toggle_button.tsx index a724ee954..cf2c24f2a 100644 --- a/frontend/controls/toggle_button.tsx +++ b/frontend/controls/toggle_button.tsx @@ -40,12 +40,16 @@ export class ToggleButton extends React.Component { } render() { - const addCss = (this.props.dim ? " dim" : "") - + (this.props.grayscale ? " grayscale" : ""); + const allCss = [ + this.css(), + this.props.className, + this.props.dim ? "dim" : "", + this.props.grayscale ? "grayscale" : "", + ].join(" "); const cb = () => !this.props.disabled && this.props.toggleAction(); return - - ; + + {newFormat &&

{t(props.description)}

} + ; }; diff --git a/frontend/devices/components/fbos_settings/firmware.tsx b/frontend/devices/components/fbos_settings/firmware.tsx new file mode 100644 index 000000000..001138c4a --- /dev/null +++ b/frontend/devices/components/fbos_settings/firmware.tsx @@ -0,0 +1,49 @@ +import * as React from "react"; +import { Header } from "../hardware_settings/header"; +import { Collapse } from "@blueprintjs/core"; +import { FirmwareProps } from "./interfaces"; +import { FbosButtonRow } from "./fbos_button_row"; +import { Content, DeviceSetting } from "../../../constants"; +import { restartFirmware } from "../../actions"; +import { t } from "../../../i18next_wrapper"; +import { Highlight } from "../maybe_highlight"; +import { BoardType } from "./board_type"; +import { isFwHardwareValue } from "../firmware_hardware_support"; +import { FlashFirmwareRow } from "./flash_firmware_row"; + +export function Firmware(props: FirmwareProps) { + const { dispatch, sourceFbosConfig, botOnline } = props; + const { firmware } = props.bot.controlPanelState; + + const { value } = props.sourceFbosConfig("firmware_hardware"); + const firmwareHardware = isFwHardwareValue(value) ? value : undefined; + return +
+ + + + + + ; +} diff --git a/frontend/devices/components/fbos_settings/firmware_hardware_status.tsx b/frontend/devices/components/fbos_settings/firmware_hardware_status.tsx index b85c3b3f0..48f859534 100644 --- a/frontend/devices/components/fbos_settings/firmware_hardware_status.tsx +++ b/frontend/devices/components/fbos_settings/firmware_hardware_status.tsx @@ -6,7 +6,6 @@ import { t } from "../../../i18next_wrapper"; import { BotState } from "../../interfaces"; import { FirmwareAlerts } from "../../../messages/alerts"; import { TimeSettings } from "../../../interfaces"; -import { trim } from "../../../util"; import { Alert } from "farmbot"; import { isFwHardwareValue, boardType } from "../firmware_hardware_support"; @@ -56,22 +55,6 @@ export const FlashFirmwareBtn = (props: FlashFirmwareBtnProps) => { ; }; -export interface FirmwareActionsProps { - apiFirmwareValue: string | undefined; - botOnline: boolean; -} - -export const FirmwareActions = (props: FirmwareActionsProps) => { - const { apiFirmwareValue } = props; - return
-

- {trim(`${t("Flash the")} ${lookup(apiFirmwareValue) || ""} - ${t("firmware to your device")}:`)} -

- -
; -}; - export const FirmwareHardwareStatusDetails = (props: FirmwareHardwareStatusDetailsProps) => { return
@@ -81,10 +64,6 @@ export const FirmwareHardwareStatusDetails =

{lookup(props.botFirmwareValue) || t("unknown")}

{lookup(props.mcuFirmwareValue) || t("unknown")}

- - { + + Description = () => +

+ {trim(`${t("Flash the")} ${lookup(this.props.firmwareHardware) || ""} + ${t("firmware to your device")}:`)} +

; + + render() { + const newFormat = DevSettings.futureFeaturesEnabled(); + + return + + + + + {!newFormat && + + } + + + + + {newFormat && } + ; + } +} diff --git a/frontend/devices/components/fbos_settings/interfaces.ts b/frontend/devices/components/fbos_settings/interfaces.ts index 7cf855a65..ce7dc6413 100644 --- a/frontend/devices/components/fbos_settings/interfaces.ts +++ b/frontend/devices/components/fbos_settings/interfaces.ts @@ -10,9 +10,21 @@ import { Alert, InformationalSettings, TaggedDevice, + FirmwareHardware, } from "farmbot"; import { TimeSettings } from "../../../interfaces"; +export interface NameRowProps { + dispatch: Function; + device: TaggedDevice; + widget?: boolean; +} + +export interface TimezoneRowProps { + dispatch: Function; + device: TaggedDevice; +} + export interface AutoSyncRowProps { dispatch: Function; sourceFbosConfig: SourceFbosConfig; @@ -50,6 +62,22 @@ export interface BoardTypeProps { shouldDisplay: ShouldDisplay; timeSettings: TimeSettings; sourceFbosConfig: SourceFbosConfig; + firmwareHardware: FirmwareHardware | undefined; +} + +export interface FirmwareProps { + botOnline: boolean; + bot: BotState; + alerts: Alert[]; + dispatch: Function; + shouldDisplay: ShouldDisplay; + timeSettings: TimeSettings; + sourceFbosConfig: SourceFbosConfig; +} + +export interface FlashFirmwareRowProps { + botOnline: boolean; + firmwareHardware: FirmwareHardware | undefined; } export interface PowerAndResetProps { @@ -67,13 +95,10 @@ export interface FactoryResetRowsProps { export interface FarmbotOsRowProps { bot: BotState; - osReleaseNotesHeading: string; - osReleaseNotes: string; dispatch: Function; sourceFbosConfig: SourceFbosConfig; shouldDisplay: ShouldDisplay; botOnline: boolean; - botToMqttLastSeen: number; timeSettings: TimeSettings; deviceAccount: TaggedDevice; } diff --git a/frontend/devices/components/fbos_settings/last_seen_row.tsx b/frontend/devices/components/fbos_settings/last_seen_row.tsx index 607d6476e..71aee37a4 100644 --- a/frontend/devices/components/fbos_settings/last_seen_row.tsx +++ b/frontend/devices/components/fbos_settings/last_seen_row.tsx @@ -6,6 +6,14 @@ import { t } from "../../../i18next_wrapper"; import { TimeSettings } from "../../../interfaces"; import { timeFormatString } from "../../../util"; import { refresh } from "../../../api/crud"; +import { BotState } from "../../interfaces"; + +export const getLastSeenNumber = (bot: BotState): number => { + const { uptime } = bot.connectivity; + const bot2Mqtt = uptime["bot.mqtt"]; + const botToMqttLastSeen = bot2Mqtt?.state === "up" ? bot2Mqtt.at : ""; + return new Date(botToMqttLastSeen).getTime(); +}; export interface LastSeenProps { dispatch: Function; diff --git a/frontend/devices/components/fbos_settings/name_row.tsx b/frontend/devices/components/fbos_settings/name_row.tsx new file mode 100644 index 000000000..8dfb16313 --- /dev/null +++ b/frontend/devices/components/fbos_settings/name_row.tsx @@ -0,0 +1,34 @@ +import * as React from "react"; +import { Row, Col } from "../../../ui/index"; +import { DeviceSetting } from "../../../constants"; +import { ColWidth } from "../farmbot_os_settings"; +import { NameRowProps } from "./interfaces"; +import { t } from "../../../i18next_wrapper"; +import { Highlight } from "../maybe_highlight"; +import { edit, save } from "../../../api/crud"; +import { DevSettings } from "../../../account/dev/dev_support"; + +export class NameRow extends React.Component { + NameInput = () => + this.props.dispatch(edit(this.props.device, { + name: e.currentTarget.value + }))} + onBlur={() => this.props.dispatch(save(this.props.device.uuid))} + value={this.props.device.body.name} />; + + render() { + const newFormat = DevSettings.futureFeaturesEnabled(); + return + + + + + {!newFormat && } + + {newFormat && } + ; + } +} diff --git a/frontend/devices/components/fbos_settings/ota_time_selector.tsx b/frontend/devices/components/fbos_settings/ota_time_selector.tsx index 425579545..d11b11e9e 100644 --- a/frontend/devices/components/fbos_settings/ota_time_selector.tsx +++ b/frontend/devices/components/fbos_settings/ota_time_selector.tsx @@ -7,6 +7,7 @@ import { ColWidth } from "../farmbot_os_settings"; import { DeviceSetting } from "../../../constants"; import { Highlight } from "../maybe_highlight"; import { OtaTimeSelectorRowProps } from "./interfaces"; +import { DevSettings } from "../../../account/dev/dev_support"; // tslint:disable-next-line:no-null-keyword const UNDEFINED = null as unknown as undefined; @@ -40,7 +41,7 @@ type HOUR = | 23; type TimeTable = Record; type EveryTimeTable = Record; -const ASAP = () => t("As soon as possible"); +export const ASAP = () => t("As soon as possible"); const TIME_TABLE_12H = (): TimeTable => ({ 0: { label: t("Midnight"), value: 0 }, 1: { label: "1:00 AM", value: 1 }, @@ -102,7 +103,7 @@ const TIME_FORMATS = (): EveryTimeTable => ({ "24h": TIME_TABLE_24H() }); -interface OtaTimeSelectorProps { +export interface OtaTimeSelectorProps { disabled: boolean; timeFormat: PreferredHourFormat; onChange(hour24: number | undefined): void; @@ -116,7 +117,8 @@ export const changeOtaHour = dispatch(save(device.uuid)); }; -export function assertIsHour(val: number | undefined): asserts val is (HOUR | undefined) { +export function assertIsHour( + val: number | undefined): asserts val is (HOUR | undefined) { if ((val === null) || (val === undefined)) { return; } @@ -147,9 +149,10 @@ export const OtaTimeSelector = (props: OtaTimeSelectorProps): JSX.Element => { .sort((_x, _y) => (_x.value > _y.value) ? 1 : -1); const selectedItem = (typeof value == "number") ? theTimeTable[value as HOUR] : theTimeTable[DEFAULT_HOUR]; - return - - + const newFormat = DevSettings.futureFeaturesEnabled(); + return + + @@ -161,8 +164,8 @@ export const OtaTimeSelector = (props: OtaTimeSelectorProps): JSX.Element => { list={list} extraClass={disabled ? "disabled" : ""} /> - - ; + + ; }; export function OtaTimeSelectorRow(props: OtaTimeSelectorRowProps) { diff --git a/frontend/devices/components/fbos_settings/power_and_reset.tsx b/frontend/devices/components/fbos_settings/power_and_reset.tsx index 5464fc31c..670dbaa63 100644 --- a/frontend/devices/components/fbos_settings/power_and_reset.tsx +++ b/frontend/devices/components/fbos_settings/power_and_reset.tsx @@ -6,10 +6,9 @@ import { PowerAndResetProps } from "./interfaces"; import { ChangeOwnershipForm } from "./change_ownership_form"; import { FbosButtonRow } from "./fbos_button_row"; import { Content, DeviceSetting } from "../../../constants"; -import { reboot, powerOff, restartFirmware } from "../../actions"; +import { reboot, powerOff } from "../../actions"; import { t } from "../../../i18next_wrapper"; import { Highlight } from "../maybe_highlight"; -import { DevSettings } from "../../../account/dev/dev_support"; export function PowerAndReset(props: PowerAndResetProps) { const { dispatch, sourceFbosConfig, botOnline } = props; @@ -36,14 +35,6 @@ export function PowerAndReset(props: PowerAndResetProps) { buttonText={t("SHUTDOWN")} color={"red"} action={powerOff} /> - {!DevSettings.futureFeaturesEnabled() && - } { + + Note = () => +
+ {timezoneMismatch(this.props.device.body.timezone) + ? t(Content.DIFFERENT_TZ_WARNING) : ""} +
; + + Selector = () => + { + this.props.dispatch(edit(this.props.device, { timezone })); + this.props.dispatch(save(this.props.device.uuid)); + }} />; + + render() { + const newFormat = DevSettings.futureFeaturesEnabled(); + + return + + + + + {!newFormat && + + + + } + + {newFormat && + + + } + ; + } +} diff --git a/frontend/devices/components/hardware_settings.tsx b/frontend/devices/components/hardware_settings.tsx index 06be4f1a0..0bd20fe45 100644 --- a/frontend/devices/components/hardware_settings.tsx +++ b/frontend/devices/components/hardware_settings.tsx @@ -2,7 +2,7 @@ import * as React from "react"; import { MCUFactoryReset, bulkToggleControlPanel } from "../actions"; import { Widget, WidgetHeader, WidgetBody, Color } from "../../ui/index"; import { HardwareSettingsProps, SourceFwConfig } from "../interfaces"; -import { isBotOnline } from "../must_be_online"; +import { isBotOnlineFromState } from "../must_be_online"; import { ToolTips } from "../../constants"; import { DangerZone } from "./hardware_settings/danger_zone"; import { PinGuard } from "./hardware_settings/pin_guard"; @@ -17,24 +17,18 @@ import { FwParamExportMenu } from "./hardware_settings/export_menu"; import { t } from "../../i18next_wrapper"; import { PinBindings } from "./hardware_settings/pin_bindings"; import { ErrorHandling } from "./hardware_settings/error_handling"; -import { maybeOpenPanel } from "./maybe_highlight"; import type { FirmwareConfig } from "farmbot/dist/resources/configs/firmware"; import type { McuParamName } from "farmbot"; export class HardwareSettings extends React.Component { - componentDidMount = () => - this.props.dispatch(maybeOpenPanel(this.props.controlPanelState)); - render() { const { bot, dispatch, sourceFwConfig, controlPanelState, firmwareConfig, - botToMqttStatus, firmwareHardware, resources + firmwareHardware, resources } = this.props; - const { informational_settings } = this.props.bot.hardware; - const { sync_status } = informational_settings; - const botDisconnected = !isBotOnline(sync_status, botToMqttStatus); + const botOnline = !isBotOnlineFromState(bot); const commonProps = { dispatch, controlPanelState }; return @@ -63,7 +57,7 @@ export class HardwareSettings extends sourceFwConfig={sourceFwConfig} firmwareConfig={firmwareConfig} firmwareHardware={firmwareHardware} - botDisconnected={botDisconnected} /> + botOnline={botOnline} /> @@ -82,7 +76,7 @@ export class HardwareSettings extends sourceFwConfig={sourceFwConfig} /> + botOnline={botOnline} /> ; } diff --git a/frontend/devices/components/hardware_settings/__tests__/calibration_row_test.tsx b/frontend/devices/components/hardware_settings/__tests__/calibration_row_test.tsx index e7c47b59b..34673fcd7 100644 --- a/frontend/devices/components/hardware_settings/__tests__/calibration_row_test.tsx +++ b/frontend/devices/components/hardware_settings/__tests__/calibration_row_test.tsx @@ -9,7 +9,7 @@ describe("", () => { const fakeProps = (): CalibrationRowProps => ({ type: "calibrate", hardware: bot.hardware.mcu_params, - botDisconnected: false, + botOnline: true, action: jest.fn(), toolTip: "calibrate", title: DeviceSetting.calibration, diff --git a/frontend/devices/components/hardware_settings/__tests__/homing_and_calibration_test.tsx b/frontend/devices/components/hardware_settings/__tests__/homing_and_calibration_test.tsx index 2b951aacf..0c272b531 100644 --- a/frontend/devices/components/hardware_settings/__tests__/homing_and_calibration_test.tsx +++ b/frontend/devices/components/hardware_settings/__tests__/homing_and_calibration_test.tsx @@ -33,7 +33,7 @@ describe("", () => { value: bot.hardware.mcu_params[x], consistent: true }), firmwareConfig: fakeFirmwareConfig().body, - botDisconnected: false, + botOnline: true, firmwareHardware: undefined, }); diff --git a/frontend/devices/components/hardware_settings/calibration_row.tsx b/frontend/devices/components/hardware_settings/calibration_row.tsx index 145020de3..10963de0f 100644 --- a/frontend/devices/components/hardware_settings/calibration_row.tsx +++ b/frontend/devices/components/hardware_settings/calibration_row.tsx @@ -6,33 +6,45 @@ import { CalibrationRowProps } from "../interfaces"; import { t } from "../../../i18next_wrapper"; import { Position } from "@blueprintjs/core"; import { Highlight } from "../maybe_highlight"; +import { DevSettings } from "../../../account/dev/dev_support"; -export function CalibrationRow(props: CalibrationRowProps) { +export class CalibrationRow extends React.Component { - const { hardware, botDisconnected } = props; + get newFormat() { return DevSettings.futureFeaturesEnabled(); } - return - - - - - + Axes = () => { + const { type, botOnline, axisTitle, hardware, action } = this.props; + return
{axisTrackingStatus(hardware) .map(row => { const { axis } = row; - const hardwareDisabled = props.type == "zero" ? false : row.disabled; - return + const hardwareDisabled = type == "zero" ? false : row.disabled; + return props.action(axis)}> - {`${t(props.axisTitle)} ${axis}`} + disabled={hardwareDisabled || !botOnline} + title={t(axisTitle)} + onClick={() => action(axis)}> + {`${t(axisTitle)} ${axis}`} ; })} - - ; +
; + } + + render() { + return + + + + + + {!this.newFormat && } + + {this.newFormat && } + ; + } } diff --git a/frontend/devices/components/hardware_settings/danger_zone.tsx b/frontend/devices/components/hardware_settings/danger_zone.tsx index 0d0d941eb..140e08801 100644 --- a/frontend/devices/components/hardware_settings/danger_zone.tsx +++ b/frontend/devices/components/hardware_settings/danger_zone.tsx @@ -6,12 +6,13 @@ import { Collapse } from "@blueprintjs/core"; import { Content, DeviceSetting } from "../../../constants"; import { t } from "../../../i18next_wrapper"; import { Highlight } from "../maybe_highlight"; +import { DevSettings } from "../../../account/dev/dev_support"; export function DangerZone(props: DangerZoneProps) { - const { dispatch, onReset, botDisconnected } = props; + const { dispatch, onReset, botOnline } = props; const { danger_zone } = props.controlPanelState; - + const newFormat = DevSettings.futureFeaturesEnabled(); return
- - - + + + - -

- {t(Content.RESTORE_DEFAULT_HARDWARE_SETTINGS)} -

- - + {!newFormat && + +

+ {t(Content.RESTORE_DEFAULT_HARDWARE_SETTINGS)} +

+ } + -
-
+ + {newFormat && +

{t(Content.RESTORE_DEFAULT_HARDWARE_SETTINGS)}

} +
; } diff --git a/frontend/devices/components/hardware_settings/encoders.tsx b/frontend/devices/components/hardware_settings/encoders.tsx index 40a7fa219..60f9d6213 100644 --- a/frontend/devices/components/hardware_settings/encoders.tsx +++ b/frontend/devices/components/hardware_settings/encoders.tsx @@ -31,9 +31,7 @@ export function Encoders(props: EncodersProps) { panel={"encoders"} dispatch={dispatch} /> -
- -
+ -
- -
+ -
- -
+ -
- -
+ + botOnline={botOnline} /> getDevice().calibrate({ axis }) .catch(commandErr("Calibration"))} hardware={hardware} - botDisconnected={botDisconnected} /> + botOnline={botOnline} /> getDevice().setZero(axis) .catch(commandErr("Zeroing"))} hardware={hardware} - botDisconnected={botDisconnected} /> + botOnline={botOnline} /> -
- -
+ dispatch( @@ -149,6 +148,7 @@ export function Motors(props: MotorsProps) { label={DeviceSetting.invert2ndXMotor} tooltip={ToolTips.INVERT_MOTORS}>
- - - - - - - - - - - - + {!newFormat && + + + + + + + + + + + + } - - - + ({ label, tooltip, settingType, children }: SingleSettingRowProps) => { + const newFormat = DevSettings.futureFeaturesEnabled(); + return + + - + {settingType === "button" - ? {children} - : {children}} - - ; + ? + {children} + + : {children}} + + ; + }; diff --git a/frontend/devices/components/hardware_settings/space_panel_header.tsx b/frontend/devices/components/hardware_settings/space_panel_header.tsx index dfb70cedd..b9b052abc 100644 --- a/frontend/devices/components/hardware_settings/space_panel_header.tsx +++ b/frontend/devices/components/hardware_settings/space_panel_header.tsx @@ -1,23 +1,29 @@ import * as React from "react"; import { Row, Col } from "../../../ui/index"; import { t } from "../../../i18next_wrapper"; +import { DevSettings } from "../../../account/dev/dev_support"; -export function SpacePanelHeader(_: {}) { - return - - - - - - - - - - ; +export function SpacePanelHeader() { + const newFormat = DevSettings.futureFeaturesEnabled(); + const width = newFormat ? 4 : 2; + const offset = newFormat ? 0 : 6; + return
+ + + + + + + + + + + +
; } diff --git a/frontend/devices/components/interfaces.ts b/frontend/devices/components/interfaces.ts index cfb683fd7..823e141f7 100644 --- a/frontend/devices/components/interfaces.ts +++ b/frontend/devices/components/interfaces.ts @@ -18,7 +18,7 @@ export interface HomingAndCalibrationProps { controlPanelState: ControlPanelState; sourceFwConfig: SourceFwConfig; firmwareConfig: FirmwareConfig | undefined; - botDisconnected: boolean; + botOnline: boolean; firmwareHardware: FirmwareHardware | undefined; } @@ -39,7 +39,7 @@ export interface BooleanMCUInputGroupProps { export interface CalibrationRowProps { type: "find_home" | "calibrate" | "zero"; hardware: McuParams; - botDisconnected: boolean; + botOnline: boolean; action(axis: Axis): void; toolTip: string; title: DeviceSetting; @@ -116,5 +116,5 @@ export interface DangerZoneProps { dispatch: Function; controlPanelState: ControlPanelState; onReset(): void; - botDisconnected: boolean; + botOnline: boolean; } diff --git a/frontend/devices/components/lockable_button.tsx b/frontend/devices/components/lockable_button.tsx index 1bcd74f5c..c45ad1059 100644 --- a/frontend/devices/components/lockable_button.tsx +++ b/frontend/devices/components/lockable_button.tsx @@ -1,13 +1,14 @@ import * as React from "react"; -interface Props { +export interface LockableButtonProps { onClick: Function; disabled: boolean; children?: React.ReactNode; title?: string; } -export function LockableButton({ onClick, disabled, children, title }: Props) { +export function LockableButton(props: LockableButtonProps) { + const { onClick, disabled, children, title } = props; const className = disabled ? "gray" : "yellow"; return - - ; + Type = () => + + + Action = () => + this.state.bindingType == PinBindingType.special + ? + : + + render() { + const newFormat = DevSettings.futureFeaturesEnabled(); + return
+ {newFormat && } + {newFormat && } + {newFormat && + + + + + + + } + + {!newFormat && + + + } + {!newFormat && + + + } + + + + +
; } } @@ -153,9 +175,9 @@ export const PinNumberInputGroup = (props: { label: generatePinLabel(pinNumberInput), value: "" + pinNumberInput } : undefined; - + const newFormat = DevSettings.futureFeaturesEnabled(); return - + - + diff --git a/frontend/devices/pin_bindings/pin_bindings.tsx b/frontend/devices/pin_bindings/pin_bindings.tsx index d009211b2..14992a42c 100644 --- a/frontend/devices/pin_bindings/pin_bindings.tsx +++ b/frontend/devices/pin_bindings/pin_bindings.tsx @@ -16,6 +16,7 @@ import { PinBinding, } from "farmbot/dist/resources/api_resources"; import { t } from "../../i18next_wrapper"; +import { DevSettings } from "../../account/dev/dev_support"; /** Width of UI columns in Pin Bindings widget. */ export enum PinBindingColWidth { @@ -70,13 +71,15 @@ const PinBindingsListHeader = () => export const PinBindingsContent = (props: PinBindingsContentProps) => { const { dispatch, resources, firmwareHardware } = props; const pinBindings = apiPinBindings(resources); - + const newFormat = DevSettings.futureFeaturesEnabled(); return
+ {newFormat && } @@ -87,7 +90,7 @@ export const PinBindingsContent = (props: PinBindingsContentProps) => {
- + {!newFormat && } { const { pinBindings, resources, dispatch } = props; @@ -26,22 +30,33 @@ export const PinBindingsList = (props: PinBindingsListProps) => { const delBtnColor = (pin: number) => sysBtnBindings.includes(pin) ? "pseudo-disabled" : "red"; + const bindingText = ( + sequence_id: number | undefined, + binding_type: PinBindingType | undefined, + special_action: PinBindingSpecialAction | undefined, + ) => + `${t(bindingTypeLabelLookup[binding_type || ""])}: ${(sequence_id + ? findSequenceById(resources, sequence_id).body.name + : t(getSpecialActionLabel(special_action)))}`; + + const newFormat = DevSettings.futureFeaturesEnabled(); return
+ {newFormat && } {pinBindings .sort((a, b) => sortByNameAndPin(a.pin_number, b.pin_number)) .map(x => { const { pin_number, sequence_id, binding_type, special_action } = x; + const binding = bindingText(sequence_id, binding_type, special_action); return - - {generatePinLabel(pin_number)} + +

{generatePinLabel(pin_number)}

+

{newFormat && binding}

- - {t(bindingTypeLabelLookup[binding_type || ""])}:  - {sequence_id - ? findSequenceById(resources, sequence_id).body.name - : t(getSpecialActionLabel(special_action))} - - + {!newFormat && + + {binding} + } +