diff --git a/config/routes.rb b/config/routes.rb index d520ee7519..930514526c 100755 --- a/config/routes.rb +++ b/config/routes.rb @@ -109,7 +109,7 @@ get "/logout" => "dashboard#logout", as: :logout get "/app" => "dashboard#main_app", as: :dashboard - get "/app/controls" => "dashboard#main_app", as: :app_landing_page + get "/app/designer/controls" => "dashboard#main_app", as: :app_landing_page get "/app/messages" => "dashboard#main_app", as: :app_message_center match "/app/*path", to: "dashboard#main_app", via: :all, constraints: { format: "html" } diff --git a/frontend/__tests__/app_test.tsx b/frontend/__tests__/app_test.tsx index bf3350a8fd..38764652b1 100644 --- a/frontend/__tests__/app_test.tsx +++ b/frontend/__tests__/app_test.tsx @@ -1,7 +1,7 @@ -let mockPath = ""; -jest.mock("../history", () => ({ - getPathArray: jest.fn(() => mockPath.split("/")), - history: { getCurrentLocation: () => ({ pathname: mockPath }) } +let mockShowPopUp = false; +jest.mock("../controls_popup", () => ({ + ControlsPopup: () =>
, + showControlsPopup: () => mockShowPopUp, })); import * as React from "react"; @@ -47,28 +47,16 @@ const fakeProps = (): AppProps => ({ }); describe(": Controls Pop-Up", () => { - it.each<["renders" | "doesn't render", string]>([ - ["renders", "designer"], - ["renders", "designer/plants"], - ["doesn't render", "controls"], - ["renders", "device"], - ["renders", "sequences"], - ["renders", "sequences/for_regimens"], - ["doesn't render", "regimens"], - ["renders", "tools"], - ["renders", "farmware"], - ["renders", "messages"], - ["renders", "logs"], - ["renders", "help"], - ["doesn't render", "account"], - ])("%s controls pop-up on %s page", (expected, page) => { - mockPath = "/app/" + page; + it("renders controls pop-up", () => { + mockShowPopUp = true; const wrapper = mount(); - if (expected == "renders") { - expect(wrapper.html()).toContain("controls-popup"); - } else { - expect(wrapper.html()).not.toContain("controls-popup"); - } + expect(wrapper.html()).toContain("controls-popup"); + }); + + it("doesn't render controls pop-up", () => { + mockShowPopUp = false; + const wrapper = mount(); + expect(wrapper.html()).not.toContain("controls-popup"); }); }); @@ -123,7 +111,6 @@ describe(": NavBar", () => { const t = wrapper.text(); const strings = [ "Farm Designer", - "Controls", "Sequences", "Regimens", ]; diff --git a/frontend/__tests__/controls_popup_test.tsx b/frontend/__tests__/controls_popup_test.tsx index a4852e68aa..8ff9a91a0c 100644 --- a/frontend/__tests__/controls_popup_test.tsx +++ b/frontend/__tests__/controls_popup_test.tsx @@ -1,3 +1,9 @@ +let mockPath = ""; +jest.mock("../history", () => ({ + getPathArray: jest.fn(() => mockPath.split("/")), + history: { getCurrentLocation: () => ({ pathname: mockPath }) } +})); + const mockDevice = { moveRelative: jest.fn(() => Promise.resolve()), takePhoto: jest.fn(() => Promise.resolve()), @@ -5,7 +11,7 @@ const mockDevice = { jest.mock("../device", () => ({ getDevice: () => mockDevice })); import * as React from "react"; -import { ControlsPopup } from "../controls_popup"; +import { ControlsPopup, showControlsPopup } from "../controls_popup"; import { mount } from "enzyme"; import { bot } from "../__test_support__/fake_state/bot"; import { ControlsPopupProps } from "../controls/move/interfaces"; @@ -101,3 +107,25 @@ describe("", () => { expect(mockDevice.takePhoto).not.toHaveBeenCalled(); }); }); + +describe("showControlsPopup()", () => { + it.each<["shows" | "doesn't show", string]>([ + ["shows", "designer"], + ["shows", "designer/plants"], + ["doesn't show", "designer/controls"], + ["shows", "device"], + ["shows", "sequences"], + ["shows", "sequences/for_regimens"], + ["doesn't show", "regimens"], + ["shows", "tools"], + ["shows", "farmware"], + ["shows", "messages"], + ["shows", "logs"], + ["shows", "help"], + ["shows", ""], + ["doesn't show", "account"], + ])("%s controls pop-up on %s page", (expected, page) => { + mockPath = "/app/" + page; + expect(showControlsPopup()).toEqual(expected == "shows"); + }); +}); diff --git a/frontend/account/labs/labs_features_list_data.ts b/frontend/account/labs/labs_features_list_data.ts index 2acc81fd4b..f1e0e93afc 100644 --- a/frontend/account/labs/labs_features_list_data.ts +++ b/frontend/account/labs/labs_features_list_data.ts @@ -46,7 +46,7 @@ export const fetchLabFeatures = value: false }, { - name: t("Hide Sensors widget"), + name: t("Hide Sensors panel"), description: t(Content.HIDE_SENSORS_WIDGET), storageKey: BooleanSetting.hide_sensors, value: false diff --git a/frontend/app.tsx b/frontend/app.tsx index 596aaeffa7..522787655e 100644 --- a/frontend/app.tsx +++ b/frontend/app.tsx @@ -14,11 +14,10 @@ import { getDeviceAccountSettings, } from "./resources/selectors"; import { HotKeys } from "./hotkeys"; -import { ControlsPopup } from "./controls_popup"; +import { ControlsPopup, showControlsPopup } from "./controls_popup"; import { Content } from "./constants"; import { validBotLocationData, validFwConfig, validFbosConfig } from "./util"; import { BooleanSetting } from "./session_keys"; -import { getPathArray } from "./history"; import { getWebAppConfigValue, GetWebAppConfigValue, } from "./config_storage/actions"; @@ -132,7 +131,6 @@ export class RawApp extends React.Component { render() { const syncLoaded = this.isLoaded; - const currentPage = getPathArray()[2]; const { location_data, mcu_params } = this.props.bot.hardware; return
{!syncLoaded && } @@ -153,7 +151,7 @@ export class RawApp extends React.Component { apiFirmwareValue={this.props.apiFirmwareValue} pings={this.props.pings} />} {syncLoaded && this.props.children} - {!(["controls", "account", "regimens"].includes(currentPage)) && + {showControlsPopup() && ({ push: jest.fn() })); + import * as React from "react"; import { mount } from "enzyme"; -import { RawControls as Controls } from "../controls"; -import { bot } from "../../__test_support__/fake_state/bot"; -import { - fakePeripheral, fakeWebcamFeed, fakeSensor, -} from "../../__test_support__/fake_state/resources"; -import { Dictionary } from "farmbot"; -import { Props } from "../interfaces"; -import { fakeTimeSettings } from "../../__test_support__/fake_time_settings"; +import { Controls } from "../controls"; +import { push } from "../../history"; describe("", () => { - const mockConfig: Dictionary = {}; - - const fakeProps = (): Props => ({ - dispatch: jest.fn(), - bot: bot, - feeds: [fakeWebcamFeed()], - peripherals: [fakePeripheral()], - sensors: [fakeSensor()], - firmwareSettings: bot.hardware.mcu_params, - shouldDisplay: () => true, - getWebAppConfigVal: jest.fn(key => mockConfig[key]), - sensorReadings: [], - timeSettings: fakeTimeSettings(), - env: {}, - firmwareHardware: undefined, - }); - - it("shows webcam widget", () => { - mockConfig.hide_webcam_widget = false; - const wrapper = mount(); - const txt = wrapper.text().toLowerCase(); - ["webcam", "move", "peripherals", "sensors"] - .map(string => expect(txt).toContain(string)); - }); - - it("hides webcam widget", () => { - mockConfig.hide_webcam_widget = true; - const wrapper = mount(); - const txt = wrapper.text().toLowerCase(); - ["move", "peripherals", "sensors"] - .map(string => expect(txt).toContain(string)); - expect(txt).not.toContain("webcam"); - }); - - it("shows sensors widget", () => { - mockConfig.hide_webcam_widget = false; - mockConfig.hide_sensors = false; - const wrapper = mount(); - const txt = wrapper.text().toLowerCase(); - ["webcam", "move", "peripherals", "sensors"] - .map(string => expect(txt).toContain(string)); - }); - - it("hides sensors widget", () => { - mockConfig.hide_webcam_widget = true; - mockConfig.hide_sensors = true; - const wrapper = mount(); - const txt = wrapper.text().toLowerCase(); - ["move", "peripherals"] - .map(string => expect(txt).toContain(string)); - ["webcam", "sensors"] - .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; - const wrapper = mount(); - const txt = wrapper.text().toLowerCase(); - expect(txt).not.toContain("sensor history"); - }); - - it("shows sensor readings widget", () => { - const p = fakeProps(); - mockConfig.hide_sensors = false; - const wrapper = mount(); - const txt = wrapper.text().toLowerCase(); - expect(txt).toContain("sensor history"); + it("redirects", () => { + const wrapper = mount(); + expect(wrapper.text().toLowerCase()).toContain("redirecting"); + expect(push).toHaveBeenCalledWith("/app/designer/controls"); }); }); diff --git a/frontend/controls/__tests__/state_to_props_test.ts b/frontend/controls/__tests__/state_to_props_test.ts deleted file mode 100644 index 9582649781..0000000000 --- a/frontend/controls/__tests__/state_to_props_test.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { mapStateToProps } from "../state_to_props"; -import { buildResourceIndex } from "../../__test_support__/resource_index_builder"; -import { - fakeUser, fakeFarmwareEnv, -} from "../../__test_support__/fake_state/resources"; -import { fakeState } from "../../__test_support__/fake_state"; - -describe("mapStateToProps()", () => { - it("fetches the appropriate resources", () => { - const state = fakeState(); - state.resources = buildResourceIndex([fakeUser()]); - const result = mapStateToProps(state); - expect(result.timeSettings).toEqual({ utcOffset: 0, hour24: false }); - }); - - it("returns api props", () => { - const state = fakeState(); - const fakeEnv = fakeFarmwareEnv(); - state.resources = buildResourceIndex([fakeEnv]); - state.bot.minOsFeatureData = { api_farmware_env: "8.0.0" }; - state.bot.hardware.informational_settings.controller_version = "8.0.0"; - const result = mapStateToProps(state); - expect(result.env).toEqual({ [fakeEnv.body.key]: fakeEnv.body.value }); - }); -}); diff --git a/frontend/controls/controls.tsx b/frontend/controls/controls.tsx index 969e342566..87a5ed33c2 100644 --- a/frontend/controls/controls.tsx +++ b/frontend/controls/controls.tsx @@ -1,98 +1,14 @@ import * as React from "react"; -import { connect } from "react-redux"; -import { Peripherals } from "./peripherals"; -import { Sensors } from "./sensors"; -import { Row, Page, Col } from "../ui/index"; -import { mapStateToProps } from "./state_to_props"; -import { WebcamPanel } from "./webcam"; -import { Props } from "./interfaces"; -import { Move } from "./move/move"; -import { BooleanSetting } from "../session_keys"; -import { SensorReadings } from "./sensor_readings/sensor_readings"; -import { isBotOnlineFromState } from "../devices/must_be_online"; -import { hasSensors } from "../devices/components/firmware_hardware_support"; - -/** Controls page. */ -export class RawControls extends React.Component { - get arduinoBusy() { - return !!this.props.bot.hardware.informational_settings.busy; - } - - get botOnline() { - return isBotOnlineFromState(this.props.bot); - } - - get hideSensors() { - return this.props.getWebAppConfigVal(BooleanSetting.hide_sensors) - || !hasSensors(this.props.firmwareHardware); - } - - move = () => - - peripherals = () => - - webcams = () => - - sensors = () => this.hideSensors - ?
- : - - sensorReadings = () => this.hideSensors - ?
- : +import { Page } from "../ui/index"; +import { t } from "../i18next_wrapper"; +import { push } from "../history"; +/** Controls page redirect. */ +export class Controls extends React.Component { render() { - const showWebcamWidget = - !this.props.getWebAppConfigVal(BooleanSetting.hide_webcam_widget); + push("/app/designer/controls"); return - {showWebcamWidget - ? - - - - - - - - - - - - : - - - - - - - - - - } +

{t("This page has moved. Redirecting...")}

; } } - -export const Controls = connect(mapStateToProps)(RawControls); diff --git a/frontend/controls/interfaces.ts b/frontend/controls/interfaces.ts index 1ea41f8b12..131daf79e5 100644 --- a/frontend/controls/interfaces.ts +++ b/frontend/controls/interfaces.ts @@ -1,30 +1,5 @@ -import { - BotState, BotPosition, ShouldDisplay, UserEnv, -} from "../devices/interfaces"; -import { Vector3, McuParams, FirmwareHardware, Xyz, AxisState } from "farmbot"; -import { - TaggedWebcamFeed, - TaggedPeripheral, - TaggedSensor, - TaggedSensorReading, -} from "farmbot"; -import { GetWebAppConfigValue } from "../config_storage/actions"; -import { TimeSettings } from "../interfaces"; - -export interface Props { - dispatch: Function; - bot: BotState; - feeds: TaggedWebcamFeed[]; - peripherals: TaggedPeripheral[]; - sensors: TaggedSensor[]; - firmwareSettings: McuParams; - shouldDisplay: ShouldDisplay; - getWebAppConfigVal: GetWebAppConfigValue; - sensorReadings: TaggedSensorReading[]; - timeSettings: TimeSettings; - env: UserEnv; - firmwareHardware: FirmwareHardware | undefined; -} +import { BotPosition } from "../devices/interfaces"; +import { Vector3, McuParams, Xyz, AxisState } from "farmbot"; export interface AxisDisplayGroupProps { position: BotPosition; diff --git a/frontend/controls/state_to_props.ts b/frontend/controls/state_to_props.ts deleted file mode 100644 index 4fc3a457ae..0000000000 --- a/frontend/controls/state_to_props.ts +++ /dev/null @@ -1,45 +0,0 @@ -import { Everything } from "../interfaces"; -import { - selectAllPeripherals, - selectAllWebcamFeeds, - selectAllSensors, - selectAllSensorReadings, - maybeGetTimeSettings, -} from "../resources/selectors"; -import { Props } from "./interfaces"; -import { validFwConfig, validFbosConfig } from "../util"; -import { getWebAppConfigValue } from "../config_storage/actions"; -import { getFirmwareConfig, getFbosConfig } from "../resources/getters"; -import { uniq } from "lodash"; -import { getEnv, getShouldDisplayFn } from "../farmware/state_to_props"; -import { sourceFbosConfigValue } from "../devices/components/source_config_value"; -import { isFwHardwareValue } from "../devices/components/firmware_hardware_support"; - -export function mapStateToProps(props: Everything): Props { - const fwConfig = validFwConfig(getFirmwareConfig(props.resources.index)); - const { mcu_params } = props.bot.hardware; - - const shouldDisplay = getShouldDisplayFn(props.resources.index, props.bot); - const env = getEnv(props.resources.index, shouldDisplay, props.bot); - - const { configuration } = props.bot.hardware; - const fbosConfig = validFbosConfig(getFbosConfig(props.resources.index)); - const sourceFbosConfig = sourceFbosConfigValue(fbosConfig, configuration); - const { value } = sourceFbosConfig("firmware_hardware"); - const firmwareHardware = isFwHardwareValue(value) ? value : undefined; - - return { - feeds: selectAllWebcamFeeds(props.resources.index), - dispatch: props.dispatch, - bot: props.bot, - peripherals: uniq(selectAllPeripherals(props.resources.index)), - sensors: uniq(selectAllSensors(props.resources.index)), - firmwareSettings: fwConfig || mcu_params, - getWebAppConfigVal: getWebAppConfigValue(() => props), - shouldDisplay, - sensorReadings: selectAllSensorReadings(props.resources.index), - timeSettings: maybeGetTimeSettings(props.resources.index), - env, - firmwareHardware, - }; -} diff --git a/frontend/controls_popup.tsx b/frontend/controls_popup.tsx index bda4aca294..c8ff870d51 100644 --- a/frontend/controls_popup.tsx +++ b/frontend/controls_popup.tsx @@ -9,6 +9,7 @@ import { cameraBtnProps, } from "./devices/components/fbos_settings/camera_selection"; import { t } from "./i18next_wrapper"; +import { getPathArray } from "./history"; interface State { isOpen: boolean; @@ -64,3 +65,13 @@ export class ControlsPopup
; } } + +export const showControlsPopup = () => { + const currentPage = getPathArray()[2] || ""; + const currentPanel = getPathArray()[3] || ""; + const pagesNotShown = ["account", "regimens"]; + const panelsNotShown = ["controls"]; + const hide = pagesNotShown.includes(currentPage) + || (currentPage == "designer" && panelsNotShown.includes(currentPanel)); + return !hide; +}; diff --git a/frontend/css/farm_designer/farm_designer_panels.scss b/frontend/css/farm_designer/farm_designer_panels.scss index 5ee7bc2f98..aa30aaddf6 100644 --- a/frontend/css/farm_designer/farm_designer_panels.scss +++ b/frontend/css/farm_designer/farm_designer_panels.scss @@ -549,6 +549,15 @@ z-index: 10; } +.scroll-indicator { + position: absolute; + top: 0; + right: 0; + width: 2rem; + height: 100%; + background: linear-gradient(-90deg, $translucent, transparent) +} + .panel-header { .panel-header-description, .crop-info-description { @@ -885,15 +894,53 @@ padding: 0; } +.settings-panel { + .panel-top { + .fa-chevron-right, + .fa-chevron-down { + font-size: 1.25rem !important; + padding: 0.1rem; + } + } +} + .settings-panel-content { - padding: 0; - margin-top: 6rem; + max-height: calc(100vh - 22rem); + overflow-y: auto; + overflow-x: hidden; padding-bottom: inherit; + .expandable-header { + margin-top: 1.5rem; + margin-bottom: 0; + } .section { - margin-bottom: 2rem; + position: relative; + margin-bottom: 0; + .hw-warn { + position: absolute; + top: -0.35rem; + right: 2rem; + i { + font-size: 1.4rem; + } + } } - .bulk-expand-controls { - margin-left: 1rem; + .bp3-collapse::-webkit-scrollbar { + display:none !important; + width: 0px !important; + background-color: transparent !important; + } + .disable_scrollbar::-webkit-scrollbar { + width: 0px; + background: transparent; + } + .bp3-collapse-body::-webkit-scrollbar { + display: none !important; + width: 0px !important; + background-color: transparent !important; + } + .section { + margin-bottom: 2rem; } .row:first-child { margin-right: 0; @@ -991,53 +1038,6 @@ .help-icon { margin-left: 1rem; } - .all-settings-content { - max-height: calc(100vh - 22rem); - overflow-y: auto; - overflow-x: hidden; - margin-top: 1rem; - padding-left: 1rem; - padding-bottom: 12rem; - .expandable-header { - margin-top: 1.5rem; - margin-bottom: 0; - } - .section { - position: relative; - margin-bottom: 0; - .hw-warn { - position: absolute; - top: -0.35rem; - right: 2rem; - i { - font-size: 1.4rem; - } - } - } - .bp3-collapse::-webkit-scrollbar { - display:none !important; - width: 0px !important; - background-color: transparent !important; - } - .disable_scrollbar::-webkit-scrollbar { - width: 0px; - background: transparent; - } - .bp3-collapse-body::-webkit-scrollbar { - display: none !important; - width: 0px !important; - background-color: transparent !important; - } - } - .designer-settings { - max-height: calc(100vh - 14rem); - overflow-y: auto; - overflow-x: hidden; - margin-right: -10px; - padding-right: 1rem; - padding-left: 1rem; - padding-bottom: 12rem; - } .designer-setting { &.disabled { input { @@ -1430,37 +1430,50 @@ background: none; } } - .bp3-popover-wrapper { - padding-top: 2rem; - float: right; - .fa-gear { - color: $dark_gray; - } + .title-help-icon:hover { + color: $dark_gray !important; } - .jog-controls-group { - label { - margin-top: 0; - } + .title-help-text.open { + color: $dark_gray !important; + font-size: 1.2rem; } - .bot-position-rows { - padding-left: 1rem; - padding-right: 1rem; - label { - margin-top: 0; - } - .axis-titles { - margin-bottom: 1rem; - } + } +} + +.controls-panel { + .move-settings.bp3-popover-wrapper { + padding-top: 2rem; + float: right; + .fa-gear { + color: $dark_gray; } - .index-indicator { - background: $dark_gray; + } + .jog-controls-group { + label { + margin-top: 0; } } + .bot-position-rows { + padding-left: 1rem; + padding-right: 1rem; + label { + margin-top: 0; + } + .axis-titles { + margin-bottom: 1rem; + } + } + .index-indicator { + background: $dark_gray; + } } .sensors-panel { .panel-content { padding-top: 6rem; + label { + margin-top: 0; + } } } diff --git a/frontend/css/global.scss b/frontend/css/global.scss index 1c096eec97..074e7495da 100644 --- a/frontend/css/global.scss +++ b/frontend/css/global.scss @@ -1390,7 +1390,8 @@ ul { height: 2rem; span { position: relative; - top: 0.15rem; + top: -0.1rem; + font-size: 1.3rem; } } } diff --git a/frontend/css/navbar.scss b/frontend/css/navbar.scss index e6d446070e..e854a655d4 100644 --- a/frontend/css/navbar.scss +++ b/frontend/css/navbar.scss @@ -163,9 +163,6 @@ nav { overflow: hidden; visibility: hidden; } - .bp3-popover-arrow-fill { - fill: $dark_gray; - } } .menu-popover { @@ -205,6 +202,9 @@ nav { } } } + .bp3-popover-arrow-fill { + fill: $dark_gray; + } } .mobile-menu { diff --git a/frontend/devices/components/__tests__/firmware_hardware_support_test.ts b/frontend/devices/components/__tests__/firmware_hardware_support_test.ts index 96cb2cad5b..b3056eea4d 100644 --- a/frontend/devices/components/__tests__/firmware_hardware_support_test.ts +++ b/frontend/devices/components/__tests__/firmware_hardware_support_test.ts @@ -1,4 +1,6 @@ -import { boardType, getFwHardwareValue, getBoardCategory } from "../firmware_hardware_support"; +import { + boardType, getFwHardwareValue, getBoardCategory, hasSensors, +} from "../firmware_hardware_support"; import { fakeFbosConfig } from "../../../__test_support__/fake_state/resources"; describe("boardType()", () => { @@ -56,3 +58,15 @@ describe("getBoardCategory()", () => { expect(getBoardCategory(undefined)).toEqual("Farmduino"); }); }); + +describe("hasSensors()", () => { + it("has sensors", () => { + expect(hasSensors(undefined)).toEqual(true); + expect(hasSensors("arduino")).toEqual(true); + expect(hasSensors("farmduino")).toEqual(true); + }); + + it("doesn't have sensors", () => { + expect(hasSensors("express_k10")).toEqual(false); + }); +}); diff --git a/frontend/devices/components/__tests__/maybe_highlight_test.tsx b/frontend/devices/components/__tests__/maybe_highlight_test.tsx index d35cfcc65a..02c036a6f3 100644 --- a/frontend/devices/components/__tests__/maybe_highlight_test.tsx +++ b/frontend/devices/components/__tests__/maybe_highlight_test.tsx @@ -48,7 +48,21 @@ describe("", () => { expect(wrapper.find("div").first().props().hidden).toEqual(false); }); - it("hides", () => { + it("doesn't hide: content matches search term", () => { + mockState.resources.consumers.farm_designer.settingsSearchTerm = "speed"; + const wrapper = mount(); + expect(wrapper.find("div").first().props().hidden).toEqual(false); + }); + + it("hides: not section header", () => { + mockState.resources.consumers.farm_designer.settingsSearchTerm = "speed"; + const p = fakeProps(); + p.className = undefined; + const wrapper = mount(); + expect(wrapper.find("div").first().props().hidden).toEqual(true); + }); + + it("hides: doesn't match search term", () => { mockState.resources.consumers.farm_designer.settingsSearchTerm = "encoder"; const wrapper = mount(); expect(wrapper.find("div").first().props().hidden).toEqual(true); diff --git a/frontend/devices/components/maybe_highlight.tsx b/frontend/devices/components/maybe_highlight.tsx index 807e021af0..bc0b0fe53e 100644 --- a/frontend/devices/components/maybe_highlight.tsx +++ b/frontend/devices/components/maybe_highlight.tsx @@ -4,7 +4,7 @@ import { ControlPanelState } from "../interfaces"; import { toggleControlPanel, bulkToggleControlPanel } from "../actions"; import { urlFriendly } from "../../util"; import { DeviceSetting } from "../../constants"; -import { trim } from "lodash"; +import { trim, some } from "lodash"; import { push } from "../../history"; const FARMBOT_PANEL = [ @@ -28,7 +28,6 @@ const POWER_AND_RESET_PANEL = [ DeviceSetting.powerAndReset, DeviceSetting.restartFarmbot, DeviceSetting.shutdownFarmbot, - DeviceSetting.restartFirmware, DeviceSetting.factoryReset, DeviceSetting.autoFactoryReset, DeviceSetting.connectionAttemptPeriod, @@ -109,6 +108,7 @@ const FARM_DESIGNER_PANEL = [ DeviceSetting.farmDesigner, DeviceSetting.animations, DeviceSetting.trail, + DeviceSetting.mapMissedSteps, DeviceSetting.dynamicMap, DeviceSetting.mapSize, DeviceSetting.rotateMap, @@ -131,6 +131,21 @@ PIN_GUARD_PANEL.map(s => SETTING_PANEL_LOOKUP[s] = "pin_guard"); PARAMETER_MANAGEMENT_PANEL.map(s => SETTING_PANEL_LOOKUP[s] = "parameter_management"); FARM_DESIGNER_PANEL.map(s => SETTING_PANEL_LOOKUP[s] = "farm_designer"); +const CONTENT_LOOKUP = {} as Record; +CONTENT_LOOKUP[DeviceSetting.farmbotSettings] = FARMBOT_PANEL; +CONTENT_LOOKUP[DeviceSetting.firmwareSection] = FIRMWARE_PANEL; +CONTENT_LOOKUP[DeviceSetting.powerAndReset] = POWER_AND_RESET_PANEL; +CONTENT_LOOKUP[DeviceSetting.axisSettings] = AXES_PANEL; +CONTENT_LOOKUP[DeviceSetting.motors] = MOTORS_PANEL; +CONTENT_LOOKUP[DeviceSetting.encoders] = ENCODERS_PANEL; +CONTENT_LOOKUP[DeviceSetting.stallDetection] = ENCODERS_PANEL; +CONTENT_LOOKUP[DeviceSetting.limitSwitchSettings] = LIMIT_SWITCHES_PANEL; +CONTENT_LOOKUP[DeviceSetting.errorHandling] = ERROR_HANDLING_PANEL; +CONTENT_LOOKUP[DeviceSetting.pinBindings] = PIN_BINDINGS_PANEL; +CONTENT_LOOKUP[DeviceSetting.pinGuard] = PIN_GUARD_PANEL; +CONTENT_LOOKUP[DeviceSetting.parameterManagement] = PARAMETER_MANAGEMENT_PANEL; +CONTENT_LOOKUP[DeviceSetting.farmDesigner] = FARM_DESIGNER_PANEL; + /** Keep string up until first `(` character (trailing whitespace removed). */ const stripUnits = (settingName: string) => trim(settingName.split("(")[0]); @@ -218,9 +233,18 @@ export class Highlight extends React.Component { toggleHover = (hovered: boolean) => () => this.setState({ hovered }); + get show() { + return !this.searchTerm + // if searching, look for setting name match + || this.props.settingName.toLowerCase() + .includes(this.searchTerm.toLowerCase()) + // if match not found, look for section content match + || this.props.className?.includes("section") && + some((CONTENT_LOOKUP[this.props.settingName] || []) + .map(s => s.toLowerCase().includes(this.searchTerm.toLowerCase()))); + } + render() { - const show = !this.searchTerm || - this.props.settingName.toLowerCase().includes(this.searchTerm.toLowerCase()); return
{ ].join(" ")} onMouseEnter={this.toggleHover(true)} onMouseLeave={this.toggleHover(false)} - hidden={!show}> + hidden={!this.show}> {this.props.children} {this.props.settingName && ({ + getWebAppConfigValue: jest.fn(() => () => 1), + toggleWebAppBool: jest.fn(), +})); + import * as React from "react"; import { mount } from "enzyme"; import { @@ -13,6 +18,8 @@ import { import { fakeWebAppConfig, fakeFbosConfig, } from "../../__test_support__/fake_state/resources"; +import { toggleWebAppBool } from "../../config_storage/actions"; +import { BooleanSetting } from "../../session_keys"; describe("", () => { const fakeProps = (): DesignerControlsProps => ({ @@ -38,6 +45,20 @@ describe("", () => { const wrapper = mount(); expect(wrapper.text().toLowerCase()).toContain("seconds ago"); }); + + it("hides webcam feeds", () => { + const p = fakeProps(); + p.getWebAppConfigVal = () => true; + const wrapper = mount(); + expect(wrapper.text().toLowerCase()).not.toContain("webcam"); + }); + + it("toggles value", () => { + const wrapper = mount( + ); + wrapper.instance().toggle(BooleanSetting.show_pins)(); + expect(toggleWebAppBool).toHaveBeenCalledWith(BooleanSetting.show_pins); + }); }); describe("mapStateToProps()", () => { diff --git a/frontend/farm_designer/__tests__/panel_header_test.tsx b/frontend/farm_designer/__tests__/panel_header_test.tsx index 58cebba10a..2b67cea8ed 100644 --- a/frontend/farm_designer/__tests__/panel_header_test.tsx +++ b/frontend/farm_designer/__tests__/panel_header_test.tsx @@ -126,4 +126,31 @@ describe("", () => { expect(wrapper.hasClass("gray-panel")).toBeTruthy(); expect(wrapper.html()).toContain("active"); }); + + it("renders scroll indicator", () => { + Object.defineProperty(document, "getElementsByClassName", { + value: () => [{}, { scrollWidth: 100, scrollLeft: 0, clientWidth: 75 }], + configurable: true + }); + const wrapper = shallow(); + expect(wrapper.html()).toContain("scroll-indicator"); + }); + + it("doesn't render scroll indicator when wide", () => { + Object.defineProperty(document, "getElementsByClassName", { + value: () => [{}, { scrollWidth: 500, scrollLeft: 0, clientWidth: 75 }], + configurable: true + }); + const wrapper = shallow(); + expect(wrapper.html()).not.toContain("scroll-indicator"); + }); + + it("doesn't render scroll indicator when at end", () => { + Object.defineProperty(document, "getElementsByClassName", { + value: () => [{}, { scrollWidth: 100, scrollLeft: 25, clientWidth: 75 }], + configurable: true + }); + const wrapper = shallow(); + expect(wrapper.html()).not.toContain("scroll-indicator"); + }); }); diff --git a/frontend/farm_designer/controls.tsx b/frontend/farm_designer/controls.tsx index bab53afb08..68138db5d3 100644 --- a/frontend/farm_designer/controls.tsx +++ b/frontend/farm_designer/controls.tsx @@ -90,34 +90,36 @@ export class RawDesignerControls return - - - - + + + + + + + - - - - - {this.props.getWebAppConfigVal(BooleanSetting.show_motor_plot) && - } + + {this.props.getWebAppConfigVal(BooleanSetting.show_motor_plot) && + } +


- + {!this.props.getWebAppConfigVal(BooleanSetting.hide_webcam_widget) && + } ; } diff --git a/frontend/farm_designer/designer_panel.tsx b/frontend/farm_designer/designer_panel.tsx index 6270c771bc..e874a461ef 100644 --- a/frontend/farm_designer/designer_panel.tsx +++ b/frontend/farm_designer/designer_panel.tsx @@ -81,10 +81,11 @@ interface DesignerPanelTopProps { onClick?(): void; title?: string; children?: React.ReactNode; + withButton?: boolean; } export const DesignerPanelTop = (props: DesignerPanelTopProps) => { - const withBtn = !!props.linkTo || !!props.onClick; + const withBtn = !!props.withButton || !!props.linkTo || !!props.onClick; return
{props.children} {props.onClick && diff --git a/frontend/farm_designer/map/layers/farmbot/__tests__/bot_trail_test.tsx b/frontend/farm_designer/map/layers/farmbot/__tests__/bot_trail_test.tsx index db4cb5b8ce..b3554e7dd0 100644 --- a/frontend/farm_designer/map/layers/farmbot/__tests__/bot_trail_test.tsx +++ b/frontend/farm_designer/map/layers/farmbot/__tests__/bot_trail_test.tsx @@ -1,8 +1,3 @@ -let mockDev = false; -jest.mock("../../../../../account/dev/dev_support", () => ({ - DevSettings: { futureFeaturesEnabled: () => mockDev } -})); - import * as React from "react"; import { shallow } from "enzyme"; import { @@ -23,8 +18,9 @@ describe("", () => { return { position: { x: 0, y: 0, z: 0 }, missedSteps: undefined, + displayMissedSteps: false, mapTransformProps: fakeMapTransformProps(), - peripherals: [] + peripherals: [], }; } @@ -84,9 +80,9 @@ describe("", () => { }); it("shows missed step indicators", () => { - mockDev = true; const p = fakeProps(); p.missedSteps = { x: 60, y: 70, z: 80 }; + p.displayMissedSteps = true; const wrapper = shallow(); expect(wrapper.find(".virtual-bot-trail").find("text").length).toEqual(3); }); diff --git a/frontend/farm_designer/map/layers/farmbot/bot_trail.tsx b/frontend/farm_designer/map/layers/farmbot/bot_trail.tsx index 8bc69723d0..678a70a1b9 100644 --- a/frontend/farm_designer/map/layers/farmbot/bot_trail.tsx +++ b/frontend/farm_designer/map/layers/farmbot/bot_trail.tsx @@ -6,7 +6,6 @@ import { Color } from "../../../../ui"; import { get, isNumber, takeRight, isEqual, round, first } from "lodash"; import { Xyz } from "farmbot"; import { indicatorColor } from "../../../../controls/move/missed_step_indicator"; -import { DevSettings } from "../../../../account/dev/dev_support"; type TrailRecord = { coord: Record<"x" | "y", number | undefined>, @@ -38,6 +37,7 @@ function getNewTrailArray(update: TrailRecord, watering: boolean): TrailRecord[] export interface BotTrailProps { position: BotPosition; missedSteps: BotPosition | undefined; + displayMissedSteps: boolean; mapTransformProps: MapTransformProps; peripherals: { label: string, value: boolean }[]; } @@ -73,7 +73,6 @@ export function BotTrail(props: BotTrailProps) { Z} ; - const showMissed = DevSettings.futureFeaturesEnabled(); return {array.map((cur: TrailRecord, i: number) => { const prev = (array[i - 1] || { coord: undefined }).coord; // prev coord @@ -91,7 +90,7 @@ export function BotTrail(props: BotTrailProps) { } - {showMissed && missedStepIcons(p1, cur.miss, opacity)} + {props.displayMissedSteps && missedStepIcons(p1, cur.miss, opacity)} ; } })} diff --git a/frontend/farm_designer/map/layers/farmbot/index.tsx b/frontend/farm_designer/map/layers/farmbot/index.tsx index 068b0743bb..a726678aa9 100644 --- a/frontend/farm_designer/map/layers/farmbot/index.tsx +++ b/frontend/farm_designer/map/layers/farmbot/index.tsx @@ -11,6 +11,8 @@ export function VirtualFarmBot(props: VirtualFarmBotProps) { mapTransformProps, plantAreaOffset, peripherals, eStopStatus, getConfigValue } = props; const displayTrail = !!getConfigValue(BooleanSetting.display_trail); + const displayMissedSteps = + !!getConfigValue(BooleanSetting.display_map_missed_steps); const encoderFigure = !!getConfigValue(BooleanSetting.encoder_figure); return @@ -39,6 +41,7 @@ export function VirtualFarmBot(props: VirtualFarmBotProps) { } ; diff --git a/frontend/farm_designer/panel_header.tsx b/frontend/farm_designer/panel_header.tsx index b640ee9b4f..fbce5d1bd7 100644 --- a/frontend/farm_designer/panel_header.tsx +++ b/frontend/farm_designer/panel_header.tsx @@ -3,6 +3,11 @@ import { getPathArray } from "../history"; import { Link } from "../link"; import { t } from "../i18next_wrapper"; import { DevSettings } from "../account/dev/dev_support"; +import { getWebAppConfigValue } from "../config_storage/actions"; +import { store } from "../redux/store"; +import { BooleanSetting } from "../session_keys"; +import { getFwHardwareValue, hasSensors } from "../devices/components/firmware_hardware_support"; +import { getFbosConfig } from "../resources/getters"; export enum Panel { Map = "Map", @@ -124,10 +129,26 @@ const NavTab = (props: NavTabProps) => {} ; +const displayScrollIndicator = () => { + const element = document.getElementsByClassName("panel-tabs")[1]; + const mobile = element?.scrollWidth < 430; + const end = element?.scrollWidth - element?.scrollLeft == element?.clientWidth; + return mobile && !end; +}; + +const showSensors = () => { + const getWebAppConfigVal = getWebAppConfigValue(store.getState); + const firmwareHardware = getFwHardwareValue(getFbosConfig( + store.getState().resources.index)); + return !getWebAppConfigVal(BooleanSetting.hide_sensors) + && hasSensors(firmwareHardware); +}; + export function DesignerNavTabs(props: { hidden?: boolean }) { const tab = getCurrentTab(); const hidden = props.hidden ? "hidden" : ""; return
+ {displayScrollIndicator() &&
}
- {DevSettings.futureFeaturesEnabled() && - } - {DevSettings.futureFeaturesEnabled() && + + {showSensors() && ", () => { const fakeProps = (): StepButtonProps => ({ @@ -30,3 +34,19 @@ describe("", () => { .toEqual("/app/designer/sequences/"); }); }); + +describe("mapStateToProps()", () => { + it("doesn't return active sequence", () => { + const state = fakeState(); + state.resources.consumers.sequences.current = undefined; + expect(mapStateToProps(state).current).toEqual(undefined); + }); + + it("returns active sequence", () => { + const state = fakeState(); + const sequence = fakeSequence(); + state.resources = buildResourceIndex([sequence]); + state.resources.consumers.sequences.current = sequence.uuid; + expect(mapStateToProps(state).current).toEqual(sequence); + }); +}); diff --git a/frontend/farm_designer/sequences/commands.tsx b/frontend/farm_designer/sequences/commands.tsx index 3ce223c169..105127169c 100644 --- a/frontend/farm_designer/sequences/commands.tsx +++ b/frontend/farm_designer/sequences/commands.tsx @@ -3,12 +3,25 @@ import { connect } from "react-redux"; import { DesignerPanel, DesignerPanelContent, DesignerPanelHeader, } from "../designer_panel"; -import { mapStateToProps } from "../../sequences/state_to_props"; import { t } from "../../i18next_wrapper"; import { StepButtonCluster, StepButtonProps, } from "../../sequences/step_button_cluster"; import { urlFriendly } from "../../util"; +import { Everything } from "../../interfaces"; +import { findSequence } from "../../resources/selectors"; +import { getShouldDisplayFn } from "../../farmware/state_to_props"; + +export const mapStateToProps = (props: Everything): StepButtonProps => { + const uuid = props.resources.consumers.sequences.current; + const current = uuid ? findSequence(props.resources.index, uuid) : undefined; + return { + dispatch: props.dispatch, + current, + shouldDisplay: getShouldDisplayFn(props.resources.index, props.bot), + stepIndex: props.resources.consumers.sequences.stepIndex, + }; +}; export class RawDesignerSequenceCommands extends React.Component { diff --git a/frontend/farm_designer/settings/__tests__/farm_designer_settings_test.tsx b/frontend/farm_designer/settings/__tests__/farm_designer_settings_test.tsx index 9a4b288dc9..15d2073ca5 100644 --- a/frontend/farm_designer/settings/__tests__/farm_designer_settings_test.tsx +++ b/frontend/farm_designer/settings/__tests__/farm_designer_settings_test.tsx @@ -2,11 +2,6 @@ jest.mock("../../map/layers/farmbot/bot_trail", () => ({ resetVirtualTrail: jest.fn(), })); -let mockDev = false; -jest.mock("../../../account/dev/dev_support", () => ({ - DevSettings: { futureFeaturesEnabled: () => mockDev } -})); - import * as React from "react"; import { mount } from "enzyme"; import { PlainDesignerSettings } from "../farm_designer_settings"; @@ -37,10 +32,4 @@ describe("", () => { wrapper.find("button").at(1).simulate("click"); expect(resetVirtualTrail).toHaveBeenCalled(); }); - - it("displays setting", () => { - mockDev = true; - const wrapper = mount(
{PlainDesignerSettings(fakeProps())}
); - expect(wrapper.find("label").at(2).text()).toContain("load"); - }); }); diff --git a/frontend/farm_designer/settings/__tests__/index_test.tsx b/frontend/farm_designer/settings/__tests__/index_test.tsx index b664915f1f..81ba725e4c 100644 --- a/frontend/farm_designer/settings/__tests__/index_test.tsx +++ b/frontend/farm_designer/settings/__tests__/index_test.tsx @@ -26,6 +26,7 @@ import { Motors } from "../hardware_settings"; import { SearchField } from "../../../ui/search_field"; import { maybeOpenPanel } from "../../../devices/components/maybe_highlight"; import { ControlPanelState } from "../../../devices/interfaces"; +import { panelState } from "../../../__test_support__/control_panel_state"; const getSetting = (wrapper: ReactWrapper, position: number, containsString: string) => { @@ -61,7 +62,7 @@ describe("", () => { expect(wrapper.text()).toContain("size"); expect(wrapper.text().toLowerCase()).toContain("pin"); const settings = wrapper.find(".designer-setting"); - expect(settings.length).toEqual(7); + expect(settings.length).toEqual(8); }); it("mounts", () => { @@ -102,8 +103,9 @@ describe("", () => { it("expands all", () => { const p = fakeProps(); + p.bot.controlPanelState = panelState(); const wrapper = mount(); - clickButton(wrapper, 0, "expand all"); + clickButton(wrapper, 0, ""); expect(p.dispatch).toHaveBeenCalledWith({ type: Actions.BULK_TOGGLE_CONTROL_PANEL, payload: true, @@ -112,8 +114,10 @@ describe("", () => { it("collapses all", () => { const p = fakeProps(); + p.bot.controlPanelState = panelState(); + p.bot.controlPanelState.motors = true; const wrapper = mount(); - clickButton(wrapper, 1, "collapse all"); + clickButton(wrapper, 0, ""); expect(p.dispatch).toHaveBeenCalledWith({ type: Actions.BULK_TOGGLE_CONTROL_PANEL, payload: false, @@ -122,14 +126,17 @@ describe("", () => { it("renders defaultOn setting", () => { const p = fakeProps(); + p.bot.controlPanelState.farm_designer = true; p.getConfigValue = () => undefined; const wrapper = mount(); - const confirmDeletion = getSetting(wrapper, 6, "confirm plant"); + const confirmDeletion = getSetting(wrapper, 7, "confirm plant"); expect(confirmDeletion.find("button").text()).toEqual("on"); }); it("toggles setting", () => { - const wrapper = mount(); + const p = fakeProps(); + p.bot.controlPanelState.farm_designer = true; + const wrapper = mount(); const trailSetting = getSetting(wrapper, 1, "trail"); trailSetting.find("button").simulate("click"); expect(setWebAppConfigValue) @@ -138,9 +145,10 @@ describe("", () => { it("changes origin", () => { const p = fakeProps(); + p.bot.controlPanelState.farm_designer = true; p.getConfigValue = () => 2; const wrapper = mount(); - const originSetting = getSetting(wrapper, 5, "origin"); + const originSetting = getSetting(wrapper, 6, "origin"); originSetting.find("div").last().simulate("click"); expect(setWebAppConfigValue).toHaveBeenCalledWith( NumericSetting.bot_origin_quadrant, 4); diff --git a/frontend/farm_designer/settings/farm_designer_settings.tsx b/frontend/farm_designer/settings/farm_designer_settings.tsx index 64a4c87c4a..7d416f004c 100644 --- a/frontend/farm_designer/settings/farm_designer_settings.tsx +++ b/frontend/farm_designer/settings/farm_designer_settings.tsx @@ -15,7 +15,6 @@ import { DesignerSettingsSectionProps, SettingProps, DesignerSettingsPropsBase, SettingDescriptionProps, } from "./interfaces"; -import { DevSettings } from "../../account/dev/dev_support"; export const Designer = (props: DesignerSettingsSectionProps) => { const { getConfigValue, dispatch, controlPanelState } = props; @@ -82,11 +81,11 @@ const DESIGNER_SETTINGS = setting: BooleanSetting.display_trail, callback: resetVirtualTrail, }, - ...(DevSettings.futureFeaturesEnabled() ? [{ + { title: DeviceSetting.mapMissedSteps, description: t(Content.MAP_MISSED_STEPS), setting: BooleanSetting.display_map_missed_steps, - }] : []), + }, { title: DeviceSetting.dynamicMap, description: t(Content.DYNAMIC_MAP_SIZE), diff --git a/frontend/farm_designer/settings/index.tsx b/frontend/farm_designer/settings/index.tsx index 880143c5d1..b2dc7b0a95 100644 --- a/frontend/farm_designer/settings/index.tsx +++ b/frontend/farm_designer/settings/index.tsx @@ -1,6 +1,6 @@ import * as React from "react"; import { connect } from "react-redux"; -import { DesignerPanel, DesignerPanelContent } from "../designer_panel"; +import { DesignerPanel, DesignerPanelContent, DesignerPanelTop } from "../designer_panel"; import { t } from "../../i18next_wrapper"; import { DesignerNavTabs, Panel } from "../panel_header"; import { @@ -19,6 +19,30 @@ import { SearchField } from "../../ui/search_field"; import { mapStateToProps } from "./state_to_props"; import { Actions } from "../../constants"; import { ExtraSettings } from "../map/easter_eggs/bugs"; +import { ControlPanelState } from "../../devices/interfaces"; + +interface ToggleSettingsOpenProps { + dispatch: Function; + panels: ControlPanelState; +} + +class ToggleSettingsOpen extends React.Component { + + get open() { + return Object.values(this.props.panels) + .filter((open: boolean) => open) + .length > 0; + } + + render() { + return ; + } +} export class RawDesignerSettings extends React.Component { @@ -44,7 +68,7 @@ export class RawDesignerSettings const { busy } = this.props.bot.hardware.informational_settings; return - + -
-
- - -
-
- - - - - - - - - - - - - {ExtraSettings(this.props.searchTerm)} -
-
+ +
+ + + + + + + + + + + + + + {ExtraSettings(this.props.searchTerm)}
; } diff --git a/frontend/front_page/front_page.tsx b/frontend/front_page/front_page.tsx index d0013498a1..1fa9dce257 100644 --- a/frontend/front_page/front_page.tsx +++ b/frontend/front_page/front_page.tsx @@ -17,7 +17,7 @@ import { TermsCheckbox } from "./terms_checkbox"; import { get } from "lodash"; import { t } from "../i18next_wrapper"; -export const DEFAULT_APP_PAGE = "/app/controls"; +export const DEFAULT_APP_PAGE = "/app/designer/controls"; export const attachFrontPage = () => attachToRoot(FrontPage, {}); diff --git a/frontend/help/__tests__/tours_test.ts b/frontend/help/__tests__/tours_test.ts index 4eefd63524..3b4dfe8a9d 100644 --- a/frontend/help/__tests__/tours_test.ts +++ b/frontend/help/__tests__/tours_test.ts @@ -23,7 +23,7 @@ describe("tourPageNavigation()", () => { testCase(".farm-designer"); testCase(".plant-inventory-panel"); testCase(".farm-event-panel"); - testCase(".move-widget"); + testCase(".move"); testCase(".peripherals-widget"); testCase(".sequence-list-panel"); testCase(".regimen-list-panel"); diff --git a/frontend/help/tours.ts b/frontend/help/tours.ts index 9143739813..7da98a551f 100644 --- a/frontend/help/tours.ts +++ b/frontend/help/tours.ts @@ -88,7 +88,7 @@ export const TOUR_STEPS = (): { [x: string]: TourStep[] } => ({ ], [Tours.monitoring]: [ { - target: ".move-widget", + target: ".move", content: t(TourContent.LOCATION_GRID), title: t("View current location"), }, @@ -128,9 +128,9 @@ export const tourPageNavigation = (nextStepTarget: string | HTMLElement) => { case ".farm-event-panel": history.push("/app/designer/events"); break; - case ".move-widget": + case ".move": case ".peripherals-widget": - history.push("/app/controls"); + history.push("/app/designer/controls"); break; case ".sequence-list-panel": history.push("/app/sequences"); diff --git a/frontend/nav/__tests__/nav_links_test.tsx b/frontend/nav/__tests__/nav_links_test.tsx index 81547832ac..4b2e8953e8 100644 --- a/frontend/nav/__tests__/nav_links_test.tsx +++ b/frontend/nav/__tests__/nav_links_test.tsx @@ -3,11 +3,6 @@ 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,17 +22,6 @@ describe("", () => { expect(wrapper.text()).toContain("1"); }); - it("shows links", () => { - const wrapper = mount(); - 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/index.tsx b/frontend/nav/index.tsx index bd66a959e1..2c61c5d98c 100644 --- a/frontend/nav/index.tsx +++ b/frontend/nav/index.tsx @@ -73,7 +73,6 @@ export class NavBar extends React.Component> { `${hasName.split(" ")[0].slice(0, 9)} ▾` : `${t("Menu")} ▾`; return
string; @@ -25,8 +24,6 @@ interface NavLinkParams { export const getLinks = (): NavLinkParams[] => betterCompact([ { name: "Farm Designer", icon: "leaf", slug: "designer" }, - DevSettings.futureFeaturesEnabled() ? undefined : - { name: "Controls", icon: "keyboard-o", slug: "controls" }, { name: "Sequences", icon: "server", slug: "sequences", computeHref: computeEditorUrlFromState("Sequence")