From 2ffbb6016edfb2a82dcc1f55a7a57fb736853620 Mon Sep 17 00:00:00 2001 From: gabrielburnworth Date: Tue, 23 Oct 2018 13:17:16 -0700 Subject: [PATCH 1/3] removed unused logs prop --- webpack/logs/__tests__/index_test.tsx | 2 -- webpack/logs/interfaces.ts | 3 +-- webpack/logs/state_to_props.ts | 1 - 3 files changed, 1 insertion(+), 5 deletions(-) diff --git a/webpack/logs/__tests__/index_test.tsx b/webpack/logs/__tests__/index_test.tsx index 52feee9d1..514a8e050 100644 --- a/webpack/logs/__tests__/index_test.tsx +++ b/webpack/logs/__tests__/index_test.tsx @@ -9,7 +9,6 @@ import { mount } from "enzyme"; import { Logs } from "../index"; import { ToolTips } from "../../constants"; import { TaggedLog, Dictionary } from "farmbot"; -import { bot } from "../../__test_support__/fake_state/bot"; import { NumericSetting } from "../../session_keys"; import { fakeLog } from "../../__test_support__/fake_state/resources"; import { LogsProps } from "../interfaces"; @@ -27,7 +26,6 @@ describe("", () => { const fakeProps = (): LogsProps => { return { logs: fakeLogs(), - bot, timeOffset: 0, dispatch: jest.fn(), sourceFbosConfig: jest.fn(), diff --git a/webpack/logs/interfaces.ts b/webpack/logs/interfaces.ts index 5ed0eb09b..279640eea 100644 --- a/webpack/logs/interfaces.ts +++ b/webpack/logs/interfaces.ts @@ -1,10 +1,9 @@ import { TaggedLog, ConfigurationName, ALLOWED_MESSAGE_TYPES } from "farmbot"; -import { BotState, SourceFbosConfig } from "../devices/interfaces"; +import { SourceFbosConfig } from "../devices/interfaces"; import { GetWebAppConfigValue } from "../config_storage/actions"; export interface LogsProps { logs: TaggedLog[]; - bot: BotState; timeOffset: number; dispatch: Function; sourceFbosConfig: SourceFbosConfig; diff --git a/webpack/logs/state_to_props.ts b/webpack/logs/state_to_props.ts index d46fa9008..fede71e85 100644 --- a/webpack/logs/state_to_props.ts +++ b/webpack/logs/state_to_props.ts @@ -28,7 +28,6 @@ export function mapStateToProps(props: Everything): LogsProps { dispatch: props.dispatch, sourceFbosConfig: sourceFbosConfigValue(fbosConfig, hardware.configuration), logs: takeSortedLogs(250, props.resources.index), - bot: props.bot, timeOffset: maybeGetTimeOffset(props.resources.index), getConfigValue: getWebAppConfigValue(() => props), }; From cf7fa153cf349f6179f2f7536b9937d4a75a8cf8 Mon Sep 17 00:00:00 2001 From: gabrielburnworth Date: Tue, 23 Oct 2018 13:17:51 -0700 Subject: [PATCH 2/3] device actions cleanup --- webpack/devices/__tests__/actions_test.ts | 72 +++++++++++++++- webpack/devices/actions.ts | 83 +++++++++---------- .../__tests__/power_and_reset_test.tsx | 11 +-- 3 files changed, 107 insertions(+), 59 deletions(-) diff --git a/webpack/devices/__tests__/actions_test.ts b/webpack/devices/__tests__/actions_test.ts index c918dabd9..8102f9b7d 100644 --- a/webpack/devices/__tests__/actions_test.ts +++ b/webpack/devices/__tests__/actions_test.ts @@ -3,7 +3,7 @@ const mockDevice = { powerOff: jest.fn(() => { return Promise.resolve(); }), resetOS: jest.fn(), reboot: jest.fn(() => { return Promise.resolve(); }), - send: jest.fn(() => { return Promise.resolve(); }), + rebootFirmware: jest.fn(() => { return Promise.resolve(); }), checkArduinoUpdates: jest.fn(() => { return Promise.resolve(); }), emergencyLock: jest.fn(() => { return Promise.resolve(); }), emergencyUnlock: jest.fn(() => { return Promise.resolve(); }), @@ -15,6 +15,8 @@ const mockDevice = { sync: jest.fn(() => { return Promise.resolve(); }), readStatus: jest.fn(() => Promise.resolve()), updateConfig: jest.fn(() => Promise.resolve()), + registerGpio: jest.fn(() => Promise.reject()), + unregisterGpio: jest.fn(() => Promise.reject()), dumpInfo: jest.fn(() => Promise.resolve()), }; @@ -88,7 +90,7 @@ describe("reboot()", function () { describe("restartFirmware()", function () { it("calls restartFirmware", async () => { await actions.restartFirmware(); - expect(mockDevice.send).toHaveBeenCalled(); + expect(mockDevice.rebootFirmware).toHaveBeenCalled(); expect(success).toHaveBeenCalled(); }); }); @@ -107,9 +109,28 @@ describe("emergencyLock() / emergencyUnlock", function () { }); describe("sync()", function () { + it("calls sync", () => { + const state = fakeState(); + state.bot.hardware.informational_settings.controller_version = "999.0.0"; + actions.sync()(jest.fn(), () => state); + expect(mockDevice.sync).toHaveBeenCalled(); + }); + + it("calls badVersion", () => { + const state = fakeState(); + state.bot.hardware.informational_settings.controller_version = "1.0.0"; + actions.sync()(jest.fn(), () => state); + expect(mockDevice.sync).not.toHaveBeenCalled(); + expect(info).toBeCalledWith( + expect.stringContaining("old version"), + expect.stringContaining("Please Update"), + "red"); + }); + it("doesn't call sync: disconnected", () => { - const getState = () => fakeState(); - actions.sync()(jest.fn(), getState); + const state = fakeState(); + state.bot.hardware.informational_settings.controller_version = undefined; + actions.sync()(jest.fn(), () => state); expect(mockDevice.sync).not.toHaveBeenCalled(); const expectedMessage = ["FarmBot is not connected.", "Disconnected", "red"]; expect(info).toBeCalledWith(...expectedMessage); @@ -189,6 +210,17 @@ describe("settingToggle()", () => { type: Actions.EDIT_RESOURCE }); }); + + it("displays an alert message", () => { + const fakeConfig = fakeFirmwareConfig(); + fakeConfig.body.api_migrated = false; + window.alert = jest.fn(); + const msg = "this is an alert."; + actions.settingToggle( + "param_mov_nr_retry", jest.fn(() => ({ value: "" })), + msg)(jest.fn(), fakeState); + expect(window.alert).toHaveBeenCalledWith(msg); + }); }); describe("updateMCU()", () => { @@ -236,6 +268,22 @@ describe("updateMCU()", () => { expect(warning).toHaveBeenCalledWith( "Minimum speed should always be lower than maximum"); }); + + it("catches error", async () => { + mockDevice.updateMcu = jest.fn(() => { return Promise.reject(); }); + const dispatch = jest.fn(); + const state = fakeState(); + const fakeConfig = fakeFirmwareConfig(); + fakeConfig.body.api_migrated = false; + state.resources = buildResourceIndex([fakeConfig]); + await actions.updateMCU( + "param_mov_nr_retry", "1")(dispatch, () => state); + await expect(mockDevice.updateMcu).toHaveBeenCalled(); + expect(dispatch).toHaveBeenLastCalledWith({ + payload: undefined, type: Actions.SETTING_UPDATE_END + }); + expect(error).toHaveBeenCalledWith("Firmware config update failed"); + }); }); describe("pinToggle()", function () { @@ -454,6 +502,22 @@ describe("updateConfig()", () => { }); }); +describe("registerGpioPin()", () => { + it("catches error", async () => { + await actions.registerGpioPin({ pin_number: 1, sequence_id: 1 })(jest.fn()); + await expect(mockDevice.registerGpio).toHaveBeenCalled(); + expect(error).toHaveBeenCalledWith("Register GPIO Pin failed"); + }); +}); + +describe("unregisterGpioPin()", () => { + it("catches error", async () => { + await actions.unregisterGpioPin(1)(jest.fn()); + await expect(mockDevice.unregisterGpio).toHaveBeenCalled(); + expect(error).toHaveBeenCalledWith("Unregister GPIO Pin failed"); + }); +}); + describe("badVersion()", () => { it("warns of old FBOS version", () => { actions.badVersion(); diff --git a/webpack/devices/actions.ts b/webpack/devices/actions.ts index 02e6ff5c5..4cf8fb4ed 100644 --- a/webpack/devices/actions.ts +++ b/webpack/devices/actions.ts @@ -9,16 +9,11 @@ import { } from "./interfaces"; import { Thunk, ReduxAction } from "../redux/interfaces"; import { - McuParams, Configuration, rpcRequest, TaggedDevice, - TaggedFirmwareConfig + McuParams, Configuration, TaggedFirmwareConfig } from "farmbot"; import { Sequence } from "../sequences/interfaces"; import { ControlPanelState } from "../devices/interfaces"; -import { API } from "../api/index"; -import { User } from "../auth/interfaces"; -import { - getDeviceAccountSettings, getFirmwareConfig -} from "../resources/selectors"; +import { getFirmwareConfig } from "../resources/selectors"; import { oneOf, versionOK, trim } from "../util"; import { Actions, Content } from "../constants"; import { mcuParamValidator } from "./update_interceptor"; @@ -54,14 +49,18 @@ export function isLog(x: any): x is Log { return false; } } + +/** Toast message upon request error. */ export const commandErr = (noun = "Command") => () => error(t(`${noun} failed`)); +/** Toast message upon request success. */ export const commandOK = (noun = "Command") => () => { const msg = t(noun) + t(" request sent to device."); success(msg, t("Request sent")); }; +/** Update FBOS. */ export function checkControllerUpdates() { const noun = "Check for Updates"; commandOK(noun)(); @@ -70,6 +69,7 @@ export function checkControllerUpdates() { .catch(commandErr(noun)); } +/** Shutdown FBOS. */ export function powerOff() { const noun = "Power Off Bot"; getDevice() @@ -77,6 +77,7 @@ export function powerOff() { .then(commandOK(noun), commandErr(noun)); } +/** Factory reset FBOS. */ export function factoryReset() { if (!confirm(t(Content.FACTORY_RESET_ALERT))) { return; @@ -84,6 +85,7 @@ export function factoryReset() { getDevice().resetOS(); } +/** Reboot FBOS. */ export function reboot() { const noun = "Reboot Bot"; getDevice() @@ -91,13 +93,11 @@ export function reboot() { .then(commandOK(noun), commandErr(noun)); } +/** Restart Farmduino firmware serial connection. */ export function restartFirmware() { const noun = "Restart Firmware"; - getDevice() // TODO: add `restartFirmware()` to FBJS - .send(rpcRequest([{ - kind: "reboot", - args: { package: "arduino_firmware" } - }])) + getDevice() + .rebootFirmware() .then(commandOK(noun), commandErr(noun)); } @@ -120,23 +120,15 @@ export function emergencyUnlock() { export function sync(): Thunk { const noun = "Sync"; return function (_dispatch, getState) { - const IS_OK = versionOK(getState() - .bot - .hardware - .informational_settings - .controller_version, EXPECTED_MAJOR, EXPECTED_MINOR); + const currentFBOSversion = + getState().bot.hardware.informational_settings.controller_version; + const IS_OK = versionOK(currentFBOSversion, EXPECTED_MAJOR, EXPECTED_MINOR); if (IS_OK) { getDevice() .sync() - // TODO: Probably wrong. Fix when there is time to QA - RC 5/2/18 - .then(() => { commandOK(noun); }) .catch(commandErr(noun)); } else { - if (getState() - .bot - .hardware - .informational_settings - .controller_version) { + if (currentFBOSversion) { badVersion(); } else { info(t("FarmBot is not connected."), t("Disconnected"), "red"); @@ -160,11 +152,8 @@ export function requestDiagnostic() { return getDevice().dumpInfo().then(commandOK(noun), commandErr(noun)); } -export let saveAccountChanges: Thunk = function (_dispatch, getState) { - return save(getDeviceAccountSettings(getState().resources.index)); -}; - -export let fetchReleases = +/** Fetch FarmBot OS release data. */ +export const fetchReleases = (url: string, options = { beta: false }) => (dispatch: Function) => { axios @@ -231,15 +220,6 @@ export let fetchMinOsFeatureData = (url: string) => }); }; -export function save(input: TaggedDevice) { - return function (dispatch: Function) { - return axios - .put(API.current.devicePath, input.body) - .then(resp => dispatch({ type: Actions.SAVE_DEVICE_OK, payload: resp.data })) - .catch(() => error(t("Error saving device settings."))); - }; -} - /** * Toggles visibility of individual sections in the giant controls panel * found on the Devices page. @@ -248,10 +228,12 @@ export function toggleControlPanel(payload: keyof ControlPanelState) { return { type: Actions.TOGGLE_CONTROL_PANEL_OPTION, payload }; } +/** Toggle visibility of all hardware control panel sections. */ export function bulkToggleControlPanel(payload: boolean) { return { type: Actions.BULK_TOGGLE_CONTROL_PANEL, payload }; } +/** Factory reset all firmware settings. */ export function MCUFactoryReset() { if (!confirm(t(Content.MCU_RESET_ALERT))) { return; @@ -259,6 +241,7 @@ export function MCUFactoryReset() { return getDevice().resetMCU().catch(commandErr("MCU Reset")); } +/** Toggle a firmware setting. */ export function settingToggle( name: ConfigKey, sourceFwConfig: SourceFwConfig, @@ -325,6 +308,7 @@ export function findHome(axis: Axis, speed = CONFIG_DEFAULTS.speed) { .catch(commandErr(noun)); } +/** Start hardware settings update spinner. */ const startUpdate = () => { return { type: Actions.SETTING_UPDATE_START, @@ -332,18 +316,20 @@ const startUpdate = () => { }; }; -const updateOK = (dispatch: Function, noun: string) => { +/** Stop hardware settings update spinner. */ +const updateOK = (dispatch: Function) => { dispatch({ type: Actions.SETTING_UPDATE_END, payload: undefined }); - commandOK(noun); }; +/** Stop hardware settings update spinner and display an error toast. */ const updateNO = (dispatch: Function, noun: string) => { dispatch({ type: Actions.SETTING_UPDATE_END, payload: undefined }); - commandErr(noun); + commandErr(noun)(); }; +/** Update firmware setting. */ export function updateMCU(key: ConfigKey, val: string) { - const noun = "configuration update"; + const noun = "Firmware config update"; return function (dispatch: Function, getState: () => Everything) { const firmwareConfig = getFirmwareConfig(getState().resources.index); const getParams = () => { @@ -362,7 +348,7 @@ export function updateMCU(key: ConfigKey, val: string) { dispatch(startUpdate()); getDevice() .updateMcu({ [key]: val }) - .then(() => updateOK(dispatch, noun)) + .then(() => updateOK(dispatch)) .catch(() => updateNO(dispatch, noun)); } } @@ -374,8 +360,9 @@ export function updateMCU(key: ConfigKey, val: string) { }; } +/** Update FBOS setting. */ export function updateConfig(config: Configuration) { - const noun = "Update Config"; + const noun = "FarmBot OS config update"; return function (dispatch: Function, getState: () => Everything) { const fbosConfig = getFbosConfig(getState().resources.index); if (fbosConfig && fbosConfig.body.api_migrated) { @@ -389,27 +376,30 @@ export function updateConfig(config: Configuration) { }; } +/** Register a sequence to an RPi GPIO pin (FBOS < 6.4.4). */ export function registerGpioPin( pinBinding: { pin_number: number, sequence_id: number }) { const noun = "Register GPIO Pin"; return function (dispatch: Function) { getDevice() .registerGpio(pinBinding) - .then(() => updateOK(dispatch, noun)) + .then(() => updateOK(dispatch)) .catch(() => updateNO(dispatch, noun)); }; } +/** Remove binding from an RPi GPIO pin (FBOS < 6.4.4). */ export function unregisterGpioPin(pin_number: number) { const noun = "Unregister GPIO Pin"; return function (dispatch: Function) { getDevice() .unregisterGpio({ pin_number }) - .then(() => updateOK(dispatch, noun)) + .then(() => updateOK(dispatch)) .catch(() => updateNO(dispatch, noun)); }; } +/** Change jog button movement amount. */ export function changeStepSize(integer: number) { return { type: Actions.CHANGE_STEP_SIZE, @@ -426,6 +416,7 @@ export function resetNetwork(): ReduxAction<{}> { return { type: Actions.RESET_NETWORK, payload: {} }; } +/** for connectivity panel */ export function resetConnectionInfo() { return function (dispatch: Function) { dispatch(resetNetwork()); diff --git a/webpack/devices/components/fbos_settings/__tests__/power_and_reset_test.tsx b/webpack/devices/components/fbos_settings/__tests__/power_and_reset_test.tsx index 435548ecb..ce172d5d3 100644 --- a/webpack/devices/components/fbos_settings/__tests__/power_and_reset_test.tsx +++ b/webpack/devices/components/fbos_settings/__tests__/power_and_reset_test.tsx @@ -1,6 +1,6 @@ const mockDevice = { updateConfig: jest.fn(() => { return Promise.resolve(); }), - send: jest.fn(() => { return Promise.resolve(); }), + rebootFirmware: jest.fn(() => { return Promise.resolve(); }), }; jest.mock("../../../../device", () => ({ getDevice: () => (mockDevice) @@ -79,14 +79,7 @@ describe("", () => { expect(wrapper.text().toLowerCase()) .toContain("Restart Firmware".toLowerCase()); clickButton(wrapper, 2, "restart"); - expect(mockDevice.send).toHaveBeenCalledWith( - expect.objectContaining({ - kind: "rpc_request", - args: expect.objectContaining({ label: expect.any(String) }), - body: [expect.objectContaining({ - kind: "reboot", args: { package: "arduino_firmware" } - })] - })); + expect(mockDevice.rebootFirmware).toHaveBeenCalled(); }); it("shows change ownership button", () => { From 656492ea9792f8bc4adb81754565a604d679cbb0 Mon Sep 17 00:00:00 2001 From: gabrielburnworth Date: Tue, 23 Oct 2018 13:18:49 -0700 Subject: [PATCH 3/3] fix broken typing --- package.json | 2 +- webpack/help/tour.tsx | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/package.json b/package.json index 6d2e4b31a..c3d4246d7 100644 --- a/package.json +++ b/package.json @@ -43,7 +43,7 @@ "@types/react": "^16.4.18", "@types/react-color": "2.13.6", "@types/react-dom": "^16.0.9", - "@types/react-joyride": "^2.0.0", + "@types/react-joyride": "^2.0.1", "@types/react-redux": "6.0.9", "axios": "^0.18.0", "boxed_value": "^1.0.0", diff --git a/webpack/help/tour.tsx b/webpack/help/tour.tsx index 84b6302a1..606100263 100644 --- a/webpack/help/tour.tsx +++ b/webpack/help/tour.tsx @@ -31,8 +31,7 @@ interface TourState { export class Tour extends React.Component { state: TourState = { run: false, index: 0, }; - // tslint:disable-next-line:no-any // broken typing - callback: any = ({ action, index, step, type }: CBData) => { + callback = ({ action, index, step, type }: CBData) => { console.log("Tour debug:", step.target, type, action); tourPageNavigation(step.target); if (type === "step:after") {