Merge branch 'staging' of https://github.com/FarmBot/Farmbot-Web-App into sync_object_sequel
commit
793c6cf895
|
@ -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",
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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<User>(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());
|
||||
|
|
|
@ -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("<PowerAndReset/>", () => {
|
|||
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", () => {
|
||||
|
|
|
@ -31,8 +31,7 @@ interface TourState {
|
|||
export class Tour extends React.Component<TourProps, TourState> {
|
||||
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") {
|
||||
|
|
|
@ -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("<Logs />", () => {
|
|||
const fakeProps = (): LogsProps => {
|
||||
return {
|
||||
logs: fakeLogs(),
|
||||
bot,
|
||||
timeOffset: 0,
|
||||
dispatch: jest.fn(),
|
||||
sourceFbosConfig: jest.fn(),
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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),
|
||||
};
|
||||
|
|
Loading…
Reference in New Issue