settings updates

pull/1724/head
gabrielburnworth 2020-02-28 08:50:14 -08:00
parent c8c57d5340
commit 4d2ea00130
18 changed files with 137 additions and 32 deletions

View File

@ -10,6 +10,9 @@ export const panelState = (): ControlPanelState => {
pin_bindings: false,
danger_zone: false,
power_and_reset: false,
pin_guard: false
pin_guard: false,
farm_designer: false,
firmware: false,
farmbot_os: false,
};
};

View File

@ -1,19 +1,10 @@
import { Everything } from "../../interfaces";
import { panelState } from "../control_panel_state";
export const bot: Everything["bot"] = {
"consistent": true,
"stepSize": 100,
"controlPanelState": {
homing_and_calibration: false,
motors: false,
encoders: false,
endstops: false,
error_handling: false,
pin_bindings: false,
danger_zone: false,
power_and_reset: false,
pin_guard: false,
},
"controlPanelState": panelState(),
"hardware": {
"gpio_registry": {},
"mcu_params": {

View File

@ -1005,10 +1005,11 @@ export enum DeviceSetting {
pinBindings = `Pin Bindings`,
// FarmBot OS
farmbot = `FarmBot`,
name = `name`,
timezone = `timezone`,
camera = `camera`,
firmware = `firmware`,
firmware = `Firmware`,
applySoftwareUpdates = `update time`,
farmbotOSAutoUpdate = `auto update`,
farmbotOS = `Farmbot OS`,
@ -1024,6 +1025,20 @@ export enum DeviceSetting {
autoFactoryReset = `Automatic Factory Reset`,
connectionAttemptPeriod = `Connection Attempt Period`,
changeOwnership = `Change Ownership`,
// Farm Designer
farmDesigner = `Farm Designer`,
animations = `Plant animations`,
trail = `Virtual FarmBot trail`,
dynamicMap = `Dynamic map size`,
mapSize = `Map size`,
rotateMap = `Rotate map`,
mapOrigin = `Map origin`,
confirmPlantDeletion = `Confirm plant deletion`,
// Firmware
firmwareSection = `Firmware`,
flashFirmware = `Flash firmware`,
}
export namespace DiagnosticMessages {

View File

@ -31,7 +31,7 @@ describe("<HardwareSettings />", () => {
it("renders", () => {
const wrapper = mount(<HardwareSettings {...fakeProps()} />);
["expand all", "x axis", "motors"].map(string =>
["expand all", "motors"].map(string =>
expect(wrapper.text().toLowerCase()).toContain(string));
});

View File

@ -6,6 +6,13 @@ jest.mock("../../../../api/crud", () => ({
save: jest.fn(),
}));
let mockDev = false;
jest.mock("../../../../account/dev/dev_support", () => ({
DevSettings: {
futureFeaturesEnabled: () => mockDev,
}
}));
import * as React from "react";
import { PowerAndReset } from "../power_and_reset";
import { mount } from "enzyme";
@ -21,6 +28,10 @@ import {
import { edit, save } from "../../../../api/crud";
describe("<PowerAndReset/>", () => {
beforeEach(() => {
mockDev = false;
});
const fakeConfig = fakeFbosConfig();
const state = fakeState();
state.resources = buildResourceIndex([fakeConfig]);
@ -36,11 +47,22 @@ describe("<PowerAndReset/>", () => {
const p = fakeProps();
p.controlPanelState.power_and_reset = true;
const wrapper = mount(<PowerAndReset {...p} />);
["Power and Reset", "Restart", "Shutdown", "Restart Firmware",
["Power and Reset", "Restart", "Shutdown",
"Factory Reset", "Automatic Factory Reset",
"Connection Attempt Period", "Change Ownership"]
.map(string => expect(wrapper.text().toLowerCase())
.toContain(string.toLowerCase()));
expect(wrapper.text().toLowerCase())
.toContain("Restart Firmware".toLowerCase());
});
it("doesn't render restart firmware", () => {
mockDev = true;
const p = fakeProps();
p.controlPanelState.power_and_reset = true;
const wrapper = mount(<PowerAndReset {...p} />);
expect(wrapper.text().toLowerCase())
.not.toContain("Restart Firmware".toLowerCase());
});
it("renders as closed", () => {

View File

@ -26,7 +26,7 @@ export const FirmwareHardwareStatusIcon =
return <i className={`fa ${icon} status-icon ${status}`} title={statusText} />;
};
const lookup = (value: string | undefined) =>
export const lookup = (value: string | undefined) =>
value && Object.keys(FIRMWARE_CHOICES_DDI).includes(value)
? FIRMWARE_CHOICES_DDI[value].label : undefined;

View File

@ -9,6 +9,7 @@ import { Content, DeviceSetting } from "../../../constants";
import { reboot, powerOff, restartFirmware } 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;
@ -35,13 +36,14 @@ export function PowerAndReset(props: PowerAndResetProps) {
buttonText={t("SHUTDOWN")}
color={"red"}
action={powerOff} />
<FbosButtonRow
botOnline={botOnline}
label={DeviceSetting.restartFirmware}
description={Content.RESTART_FIRMWARE}
buttonText={t("RESTART")}
color={"yellow"}
action={restartFirmware} />
{!DevSettings.futureFeaturesEnabled() &&
<FbosButtonRow
botOnline={botOnline}
label={DeviceSetting.restartFirmware}
description={Content.RESTART_FIRMWARE}
buttonText={t("RESTART")}
color={"yellow"}
action={restartFirmware} />}
<FactoryResetRows
dispatch={dispatch}
sourceFbosConfig={sourceFbosConfig}

View File

@ -9,7 +9,6 @@ import { PinGuard } from "./hardware_settings/pin_guard";
import { Encoders } from "./hardware_settings/encoders";
import { EndStops } from "./hardware_settings/endstops";
import { Motors } from "./hardware_settings/motors";
import { SpacePanelHeader } from "./hardware_settings/space_panel_header";
import {
HomingAndCalibration,
} from "./hardware_settings/homing_and_calibration";
@ -59,9 +58,6 @@ export class HardwareSettings extends
<i className="fa fa-download" />
<FwParamExportMenu firmwareConfig={firmwareConfig} />
</Popover>
<div className="label-headings">
<SpacePanelHeader />
</div>
<HomingAndCalibration {...commonProps}
bot={bot}
sourceFwConfig={sourceFwConfig}
@ -78,15 +74,15 @@ export class HardwareSettings extends
sourceFwConfig={sourceFwConfig} />
<ErrorHandling {...commonProps}
sourceFwConfig={sourceFwConfig} />
<PinBindings {...commonProps}
resources={resources}
firmwareHardware={firmwareHardware} />
<PinGuard {...commonProps}
resources={resources}
sourceFwConfig={sourceFwConfig} />
<DangerZone {...commonProps}
onReset={MCUFactoryReset}
botDisconnected={botDisconnected} />
<PinBindings {...commonProps}
resources={resources}
firmwareHardware={firmwareHardware} />
</WidgetBody>
</Widget>;
}

View File

@ -7,6 +7,7 @@ import { Header } from "./header";
import { Collapse } from "@blueprintjs/core";
import { hasEncoders } from "../firmware_hardware_support";
import { Highlight } from "../maybe_highlight";
import { SpacePanelHeader } from "./space_panel_header";
export function Encoders(props: EncodersProps) {
@ -30,6 +31,9 @@ export function Encoders(props: EncodersProps) {
panel={"encoders"}
dispatch={dispatch} />
<Collapse isOpen={!!encoders}>
<div className="label-headings">
<SpacePanelHeader />
</div>
<BooleanMCUInputGroup
label={!showEncoders
? DeviceSetting.enableStallDetection

View File

@ -5,6 +5,7 @@ import { EndStopsProps } from "../interfaces";
import { Header } from "./header";
import { Collapse } from "@blueprintjs/core";
import { Highlight } from "../maybe_highlight";
import { SpacePanelHeader } from "./space_panel_header";
export function EndStops(props: EndStopsProps) {
@ -19,6 +20,9 @@ export function EndStops(props: EndStopsProps) {
panel={"endstops"}
dispatch={dispatch} />
<Collapse isOpen={!!endstops}>
<div className="label-headings">
<SpacePanelHeader />
</div>
<BooleanMCUInputGroup
label={DeviceSetting.enableEndstops}
tooltip={ToolTips.ENABLE_ENDSTOPS}

View File

@ -9,6 +9,7 @@ import { settingToggle } from "../../actions";
import { SingleSettingRow } from "./single_setting_row";
import { ToggleButton } from "../../../controls/toggle_button";
import { Highlight } from "../maybe_highlight";
import { SpacePanelHeader } from "./space_panel_header";
export function ErrorHandling(props: ErrorHandlingProps) {
@ -24,6 +25,9 @@ export function ErrorHandling(props: ErrorHandlingProps) {
panel={"error_handling"}
dispatch={dispatch} />
<Collapse isOpen={!!error_handling}>
<div className="label-headings">
<SpacePanelHeader />
</div>
<NumericMCUInputGroup
label={DeviceSetting.timeoutAfter}
tooltip={ToolTips.TIMEOUT_AFTER}

View File

@ -14,6 +14,7 @@ import { getDevice } from "../../../device";
import { commandErr } from "../../actions";
import { CONFIG_DEFAULTS } from "farmbot/dist/config";
import { Highlight } from "../maybe_highlight";
import { SpacePanelHeader } from "./space_panel_header";
export function HomingAndCalibration(props: HomingAndCalibrationProps) {
@ -40,6 +41,9 @@ export function HomingAndCalibration(props: HomingAndCalibrationProps) {
dispatch={dispatch}
expanded={homing_and_calibration} />
<Collapse isOpen={!!homing_and_calibration}>
<div className="label-headings">
<SpacePanelHeader />
</div>
<CalibrationRow
type={"find_home"}
title={DeviceSetting.homing}

View File

@ -13,6 +13,7 @@ import { calcMicrostepsPerMm } from "../../../controls/move/direction_axes_props
import { isTMCBoard } from "../firmware_hardware_support";
import { SingleSettingRow } from "./single_setting_row";
import { Highlight } from "../maybe_highlight";
import { SpacePanelHeader } from "./space_panel_header";
export const calculateScale =
(sourceFwConfig: SourceFwConfig): Record<Xyz, number | undefined> => {
@ -43,6 +44,9 @@ export function Motors(props: MotorsProps) {
panel={"motors"}
dispatch={dispatch} />
<Collapse isOpen={!!controlPanelState.motors}>
<div className="label-headings">
<SpacePanelHeader />
</div>
<NumericMCUInputGroup
label={DeviceSetting.maxSpeed}
tooltip={ToolTips.MAX_SPEED}

View File

@ -75,6 +75,36 @@ const POWER_AND_RESET_PANEL = [
DeviceSetting.changeOwnership,
];
const FARM_DESIGNER_PANEL = [
DeviceSetting.farmDesigner,
DeviceSetting.animations,
DeviceSetting.trail,
DeviceSetting.dynamicMap,
DeviceSetting.mapSize,
DeviceSetting.rotateMap,
DeviceSetting.mapOrigin,
DeviceSetting.confirmPlantDeletion,
];
const FIRMWARE_PANEL = [
DeviceSetting.firmwareSection,
DeviceSetting.firmware,
DeviceSetting.flashFirmware,
DeviceSetting.restartFirmware,
];
const FARMBOT_PANEL = [
DeviceSetting.farmbot,
DeviceSetting.name,
DeviceSetting.timezone,
DeviceSetting.camera,
DeviceSetting.applySoftwareUpdates,
DeviceSetting.farmbotOSAutoUpdate,
DeviceSetting.farmbotOS,
DeviceSetting.autoSync,
DeviceSetting.bootSequence,
];
/** Look up parent panels for settings. */
const SETTING_PANEL_LOOKUP = {} as Record<DeviceSetting, keyof ControlPanelState>;
HOMING_PANEL.map(s => SETTING_PANEL_LOOKUP[s] = "homing_and_calibration");
@ -86,6 +116,9 @@ PIN_GUARD_PANEL.map(s => SETTING_PANEL_LOOKUP[s] = "pin_guard");
DANGER_ZONE_PANEL.map(s => SETTING_PANEL_LOOKUP[s] = "danger_zone");
PIN_BINDINGS_PANEL.map(s => SETTING_PANEL_LOOKUP[s] = "pin_bindings");
POWER_AND_RESET_PANEL.map(s => SETTING_PANEL_LOOKUP[s] = "power_and_reset");
FARM_DESIGNER_PANEL.map(s => SETTING_PANEL_LOOKUP[s] = "farm_designer");
FIRMWARE_PANEL.map(s => SETTING_PANEL_LOOKUP[s] = "firmware");
FARMBOT_PANEL.map(s => SETTING_PANEL_LOOKUP[s] = "farmbot_os");
/** Keep string up until first `(` character (trailing whitespace removed). */
const stripUnits = (settingName: string) => trim(settingName.split("(")[0]);

View File

@ -254,4 +254,7 @@ export interface ControlPanelState {
danger_zone: boolean;
pin_bindings: boolean;
power_and_reset: boolean;
farm_designer: boolean;
firmware: boolean;
farmbot_os: boolean;
}

View File

@ -32,7 +32,10 @@ export const initialState = (): BotState => ({
pin_bindings: false,
danger_zone: false,
power_and_reset: false,
pin_guard: false
pin_guard: false,
farm_designer: false,
firmware: false,
farmbot_os: false,
},
hardware: {
gpio_registry: {},
@ -124,6 +127,10 @@ export const botReducer = generateReducer<BotState>(initialState())
s.controlPanelState.pin_bindings = a.payload;
s.controlPanelState.pin_guard = a.payload;
s.controlPanelState.danger_zone = a.payload;
s.controlPanelState.power_and_reset = a.payload;
s.controlPanelState.farm_designer = a.payload;
s.controlPanelState.firmware = a.payload;
s.controlPanelState.farmbot_os = a.payload;
return s;
})
.add<OsUpdateInfo>(Actions.FETCH_OS_UPDATE_INFO_OK, (s, { payload }) => {

View File

@ -3,6 +3,11 @@ jest.mock("../../history", () => ({
getPathArray: jest.fn(() => mockPath.split("/")),
}));
let mockDev = false;
jest.mock("../../account/dev/dev_support", () => ({
DevSettings: { futureFeaturesEnabled: () => mockDev }
}));
import * as React from "react";
import { shallow, mount } from "enzyme";
import { NavLinks } from "../nav_links";
@ -27,6 +32,12 @@ describe("<NavLinks />", () => {
expect(wrapper.text().toLowerCase()).not.toContain("tools");
});
it("doesn't show link", () => {
mockDev = true;
const wrapper = mount(<NavLinks close={jest.fn()} alertCount={1} />);
expect(wrapper.text().toLowerCase()).not.toContain("device");
});
it("shows active link", () => {
mockPath = "/app/designer";
const wrapper = shallow(<NavLinks close={jest.fn()} alertCount={1} />);

View File

@ -7,6 +7,7 @@ import {
import { Link } from "../link";
import { t } from "../i18next_wrapper";
import { betterCompact } from "../util";
import { DevSettings } from "../account/dev/dev_support";
/** Uses a slug and a child path to compute the `href` of a navbar link. */
export type LinkComputeFn = (slug: string, childPath: string) => string;
@ -27,7 +28,8 @@ interface NavLinkParams {
export const getLinks = (): NavLinkParams[] => betterCompact([
{ name: "Farm Designer", icon: "leaf", slug: "designer" },
{ name: "Controls", icon: "keyboard-o", slug: "controls" },
{ name: "Device", icon: "cog", slug: "device" },
DevSettings.futureFeaturesEnabled() ? undefined :
{ name: "Device", icon: "cog", slug: "device" },
{
name: "Sequences", icon: "server", slug: "sequences",
computeHref: computeEditorUrlFromState("Sequence")