diff --git a/frontend/__test_support__/control_panel_state.ts b/frontend/__test_support__/control_panel_state.ts index 30fdacdeb..c90ff8580 100644 --- a/frontend/__test_support__/control_panel_state.ts +++ b/frontend/__test_support__/control_panel_state.ts @@ -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, }; }; diff --git a/frontend/__test_support__/fake_state/bot.ts b/frontend/__test_support__/fake_state/bot.ts index 98151048c..d236854cf 100644 --- a/frontend/__test_support__/fake_state/bot.ts +++ b/frontend/__test_support__/fake_state/bot.ts @@ -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": { diff --git a/frontend/constants.ts b/frontend/constants.ts index 2c9f6449d..15b21f9a1 100644 --- a/frontend/constants.ts +++ b/frontend/constants.ts @@ -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 { diff --git a/frontend/devices/components/__tests__/hardware_settings_test.tsx b/frontend/devices/components/__tests__/hardware_settings_test.tsx index e70b25e6c..90120882f 100644 --- a/frontend/devices/components/__tests__/hardware_settings_test.tsx +++ b/frontend/devices/components/__tests__/hardware_settings_test.tsx @@ -31,7 +31,7 @@ describe("", () => { it("renders", () => { const wrapper = mount(); - ["expand all", "x axis", "motors"].map(string => + ["expand all", "motors"].map(string => expect(wrapper.text().toLowerCase()).toContain(string)); }); diff --git a/frontend/devices/components/fbos_settings/__tests__/power_and_reset_test.tsx b/frontend/devices/components/fbos_settings/__tests__/power_and_reset_test.tsx index fc5cd3893..a88c28944 100644 --- a/frontend/devices/components/fbos_settings/__tests__/power_and_reset_test.tsx +++ b/frontend/devices/components/fbos_settings/__tests__/power_and_reset_test.tsx @@ -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("", () => { + beforeEach(() => { + mockDev = false; + }); + const fakeConfig = fakeFbosConfig(); const state = fakeState(); state.resources = buildResourceIndex([fakeConfig]); @@ -36,11 +47,22 @@ describe("", () => { const p = fakeProps(); p.controlPanelState.power_and_reset = true; const wrapper = mount(); - ["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(); + expect(wrapper.text().toLowerCase()) + .not.toContain("Restart Firmware".toLowerCase()); }); it("renders as closed", () => { diff --git a/frontend/devices/components/fbos_settings/firmware_hardware_status.tsx b/frontend/devices/components/fbos_settings/firmware_hardware_status.tsx index 84fd94fc7..b85c3b3f0 100644 --- a/frontend/devices/components/fbos_settings/firmware_hardware_status.tsx +++ b/frontend/devices/components/fbos_settings/firmware_hardware_status.tsx @@ -26,7 +26,7 @@ export const FirmwareHardwareStatusIcon = return ; }; -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; diff --git a/frontend/devices/components/fbos_settings/power_and_reset.tsx b/frontend/devices/components/fbos_settings/power_and_reset.tsx index 2a9fb27c3..5464fc31c 100644 --- a/frontend/devices/components/fbos_settings/power_and_reset.tsx +++ b/frontend/devices/components/fbos_settings/power_and_reset.tsx @@ -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} /> - + {!DevSettings.futureFeaturesEnabled() && + } -
- -
+ - ; } diff --git a/frontend/devices/components/hardware_settings/encoders.tsx b/frontend/devices/components/hardware_settings/encoders.tsx index 34eafd9f7..40a7fa219 100644 --- a/frontend/devices/components/hardware_settings/encoders.tsx +++ b/frontend/devices/components/hardware_settings/encoders.tsx @@ -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} /> +
+ +
+
+ +
+
+ +
+
+ +
=> { @@ -43,6 +44,9 @@ export function Motors(props: MotorsProps) { panel={"motors"} dispatch={dispatch} /> +
+ +
; 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]); diff --git a/frontend/devices/interfaces.ts b/frontend/devices/interfaces.ts index 566c863aa..7335c30a1 100644 --- a/frontend/devices/interfaces.ts +++ b/frontend/devices/interfaces.ts @@ -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; } diff --git a/frontend/devices/reducer.ts b/frontend/devices/reducer.ts index 9e0ef7416..daffac9c7 100644 --- a/frontend/devices/reducer.ts +++ b/frontend/devices/reducer.ts @@ -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(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(Actions.FETCH_OS_UPDATE_INFO_OK, (s, { payload }) => { diff --git a/frontend/nav/__tests__/nav_links_test.tsx b/frontend/nav/__tests__/nav_links_test.tsx index db3682ccb..81547832a 100644 --- a/frontend/nav/__tests__/nav_links_test.tsx +++ b/frontend/nav/__tests__/nav_links_test.tsx @@ -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("", () => { expect(wrapper.text().toLowerCase()).not.toContain("tools"); }); + it("doesn't show link", () => { + mockDev = true; + const wrapper = mount(); + expect(wrapper.text().toLowerCase()).not.toContain("device"); + }); + it("shows active link", () => { mockPath = "/app/designer"; const wrapper = shallow(); diff --git a/frontend/nav/nav_links.tsx b/frontend/nav/nav_links.tsx index 4ddfca62e..87cdfcbb8 100644 --- a/frontend/nav/nav_links.tsx +++ b/frontend/nav/nav_links.tsx @@ -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")