diff --git a/frontend/devices/components/farmbot_os_settings.tsx b/frontend/devices/components/farmbot_os_settings.tsx index 1498f5868..6b6dbf5f7 100644 --- a/frontend/devices/components/farmbot_os_settings.tsx +++ b/frontend/devices/components/farmbot_os_settings.tsx @@ -17,6 +17,7 @@ import { PowerAndReset } from "./fbos_settings/power_and_reset"; import { BootSequenceSelector } from "./fbos_settings/boot_sequence_selector"; import { ExternalUrl } from "../../external_urls"; import { Highlight } from "./maybe_highlight"; +import { OtaTimeSelectorRow } from "./fbos_settings/ota_time_selector"; export enum ColWidth { label = 3, @@ -78,8 +79,6 @@ export class FarmbotOsSettings const { bot, sourceFbosConfig, botToMqttStatus } = this.props; const { sync_status } = bot.hardware.informational_settings; const botOnline = isBotOnline(sync_status, botToMqttStatus); - const timeFormat = this.props.webAppConfig.body.time_format_24_hour ? - "24h" : "12h"; return
e.preventDefault()}> @@ -133,11 +132,14 @@ export class FarmbotOsSettings shouldDisplay={this.props.shouldDisplay} timeSettings={this.props.timeSettings} sourceFbosConfig={sourceFbosConfig} /> - + ", () => { @@ -20,10 +20,8 @@ describe("", () => { state.resources = buildResourceIndex([fakeConfig]); const fakeProps = (): AutoUpdateRowProps => ({ - timeFormat: "12h", - device: fakeDevice(), dispatch: jest.fn(x => x(jest.fn(), () => state)), - sourceFbosConfig: () => ({ value: 1, consistent: true }) + sourceFbosConfig: () => ({ value: 1, consistent: true }), }); it("renders", () => { @@ -35,7 +33,7 @@ describe("", () => { const p = fakeProps(); p.sourceFbosConfig = () => ({ value: 0, consistent: true }); const wrapper = mount(); - wrapper.find("button").at(1).simulate("click"); + wrapper.find("button").first().simulate("click"); expect(edit).toHaveBeenCalledWith(fakeConfig, { os_auto_update: true }); expect(save).toHaveBeenCalledWith(fakeConfig.uuid); }); @@ -44,7 +42,7 @@ describe("", () => { const p = fakeProps(); p.sourceFbosConfig = () => ({ value: 1, consistent: true }); const wrapper = mount(); - wrapper.find("button").at(1).simulate("click"); + wrapper.find("button").first().simulate("click"); expect(edit).toHaveBeenCalledWith(fakeConfig, { os_auto_update: false }); expect(save).toHaveBeenCalledWith(fakeConfig.uuid); }); diff --git a/frontend/devices/components/fbos_settings/auto_update_row.tsx b/frontend/devices/components/fbos_settings/auto_update_row.tsx index 2540daecf..173ed5ddf 100644 --- a/frontend/devices/components/fbos_settings/auto_update_row.tsx +++ b/frontend/devices/components/fbos_settings/auto_update_row.tsx @@ -6,38 +6,30 @@ import { updateConfig } from "../../actions"; import { Content, DeviceSetting } from "../../../constants"; import { AutoUpdateRowProps } from "./interfaces"; import { t } from "../../../i18next_wrapper"; -import { OtaTimeSelector, changeOtaHour } from "./ota_time_selector"; import { Highlight } from "../maybe_highlight"; export function AutoUpdateRow(props: AutoUpdateRowProps) { const osAutoUpdate = props.sourceFbosConfig("os_auto_update"); - return
- - - - - - - -

- {t(Content.OS_AUTO_UPDATE)} -

- - - props.dispatch(updateConfig({ - os_auto_update: !osAutoUpdate.value - }))} /> - -
-
-
; + return + + + + + +

+ {t(Content.OS_AUTO_UPDATE)} +

+ + + props.dispatch(updateConfig({ + os_auto_update: !osAutoUpdate.value + }))} /> + +
+
; } diff --git a/frontend/devices/components/fbos_settings/interfaces.ts b/frontend/devices/components/fbos_settings/interfaces.ts index c9549e389..1056ba10f 100644 --- a/frontend/devices/components/fbos_settings/interfaces.ts +++ b/frontend/devices/components/fbos_settings/interfaces.ts @@ -12,7 +12,6 @@ import { TaggedDevice, } from "farmbot"; import { TimeSettings } from "../../../interfaces"; -import { PreferredHourFormat } from "./ota_time_selector"; export interface AutoSyncRowProps { dispatch: Function; @@ -21,9 +20,14 @@ export interface AutoSyncRowProps { export interface AutoUpdateRowProps { dispatch: Function; - timeFormat: PreferredHourFormat; + sourceFbosConfig: SourceFbosConfig; +} + +export interface OtaTimeSelectorRowProps { + dispatch: Function; sourceFbosConfig: SourceFbosConfig; device: TaggedDevice; + timeSettings: TimeSettings; } export interface CameraSelectionProps { diff --git a/frontend/devices/components/fbos_settings/ota_time_selector.tsx b/frontend/devices/components/fbos_settings/ota_time_selector.tsx index 182ca4eb6..425579545 100644 --- a/frontend/devices/components/fbos_settings/ota_time_selector.tsx +++ b/frontend/devices/components/fbos_settings/ota_time_selector.tsx @@ -6,11 +6,12 @@ import { edit, save } from "../../../api/crud"; import { ColWidth } from "../farmbot_os_settings"; import { DeviceSetting } from "../../../constants"; import { Highlight } from "../maybe_highlight"; +import { OtaTimeSelectorRowProps } from "./interfaces"; // tslint:disable-next-line:no-null-keyword const UNDEFINED = null as unknown as undefined; const IMMEDIATELY = -1; -export type PreferredHourFormat = "12h" | "24h"; +type PreferredHourFormat = "12h" | "24h"; type HOUR = | typeof IMMEDIATELY | 0 @@ -163,3 +164,13 @@ export const OtaTimeSelector = (props: OtaTimeSelectorProps): JSX.Element => { ; }; + +export function OtaTimeSelectorRow(props: OtaTimeSelectorRowProps) { + const osAutoUpdate = props.sourceFbosConfig("os_auto_update"); + const timeFormat = props.timeSettings.hour24 ? "24h" : "12h"; + return ; +} diff --git a/frontend/farm_designer/__tests__/panel_header_test.tsx b/frontend/farm_designer/__tests__/panel_header_test.tsx index 546976771..5df39adab 100644 --- a/frontend/farm_designer/__tests__/panel_header_test.tsx +++ b/frontend/farm_designer/__tests__/panel_header_test.tsx @@ -71,6 +71,14 @@ describe("", () => { expect(wrapper.html()).toContain("active"); }); + it("renders for tools", () => { + mockPath = "/app/designer/tools"; + mockDev = false; + const wrapper = shallow(); + expect(wrapper.hasClass("gray-panel")).toBeTruthy(); + expect(wrapper.html()).toContain("active"); + }); + it("renders for zones", () => { mockPath = "/app/designer/zones"; mockDev = true; diff --git a/frontend/farm_designer/map/layers/tool_slots/__tests__/tool_slot_layer_test.tsx b/frontend/farm_designer/map/layers/tool_slots/__tests__/tool_slot_layer_test.tsx index 5788588ad..f9aa07f4f 100644 --- a/frontend/farm_designer/map/layers/tool_slots/__tests__/tool_slot_layer_test.tsx +++ b/frontend/farm_designer/map/layers/tool_slots/__tests__/tool_slot_layer_test.tsx @@ -4,11 +4,6 @@ jest.mock("../../../../../history", () => ({ getPathArray: jest.fn(() => { return mockPath.split("/"); }) })); -let mockDev = false; -jest.mock("../../../../../account/dev/dev_support", () => ({ - DevSettings: { futureFeaturesEnabled: () => mockDev } -})); - import * as React from "react"; import { ToolSlotLayer, ToolSlotLayerProps } from "../tool_slot_layer"; import { @@ -57,16 +52,6 @@ describe("", () => { expect(result.find(ToolSlotPoint).length).toEqual(1); }); - it("navigates to tools page", async () => { - mockDev = true; - mockPath = "/app/designer/plants"; - const p = fakeProps(); - const wrapper = shallow(); - const tools = wrapper.find("g").first(); - await tools.simulate("click"); - expect(history.push).toHaveBeenCalledWith("/app/tools"); - }); - it("doesn't navigate to tools page", async () => { mockPath = "/app/designer/plants/1"; const p = fakeProps(); diff --git a/frontend/farm_designer/map/layers/tool_slots/__tests__/tool_slot_point_test.tsx b/frontend/farm_designer/map/layers/tool_slots/__tests__/tool_slot_point_test.tsx index a53c1508f..1aa96fc12 100644 --- a/frontend/farm_designer/map/layers/tool_slots/__tests__/tool_slot_point_test.tsx +++ b/frontend/farm_designer/map/layers/tool_slots/__tests__/tool_slot_point_test.tsx @@ -1,8 +1,3 @@ -let mockDev = false; -jest.mock("../../../../../account/dev/dev_support", () => ({ - DevSettings: { futureFeaturesEnabled: () => mockDev } -})); - jest.mock("../../../../../history", () => ({ history: { push: jest.fn() } })); import * as React from "react"; @@ -17,10 +12,6 @@ import { svgMount } from "../../../../../__test_support__/svg_mount"; import { history } from "../../../../../history"; describe("", () => { - beforeEach(() => { - mockDev = false; - }); - const fakeProps = (): TSPProps => ({ mapTransformProps: fakeMapTransformProps(), botPositionX: undefined, @@ -48,10 +39,6 @@ describe("", () => { const p = fakeProps(); p.slot.toolSlot.body.id = 1; const wrapper = svgMount(); - mockDev = true; - wrapper.find("g").first().simulate("click"); - expect(history.push).not.toHaveBeenCalled(); - mockDev = false; wrapper.find("g").first().simulate("click"); expect(history.push).toHaveBeenCalledWith("/app/designer/tool-slots/1"); }); diff --git a/frontend/farm_designer/map/layers/tool_slots/tool_slot_layer.tsx b/frontend/farm_designer/map/layers/tool_slots/tool_slot_layer.tsx index d03dcef25..cf13ff88a 100644 --- a/frontend/farm_designer/map/layers/tool_slots/tool_slot_layer.tsx +++ b/frontend/farm_designer/map/layers/tool_slots/tool_slot_layer.tsx @@ -2,9 +2,7 @@ import * as React from "react"; import { SlotWithTool, UUID } from "../../../../resources/interfaces"; import { ToolSlotPoint } from "./tool_slot_point"; import { MapTransformProps } from "../../interfaces"; -import { history, getPathArray } from "../../../../history"; import { maybeNoPointer } from "../../util"; -import { DevSettings } from "../../../../account/dev/dev_support"; export interface ToolSlotLayerProps { visible: boolean; @@ -16,17 +14,11 @@ export interface ToolSlotLayerProps { } export function ToolSlotLayer(props: ToolSlotLayerProps) { - const pathArray = getPathArray(); - const canClickTool = !(pathArray[3] === "plants" && pathArray.length > 4); - const goToToolsPage = () => canClickTool && - DevSettings.futureFeaturesEnabled() && history.push("/app/tools"); const { slots, visible, mapTransformProps } = props; - const cursor = canClickTool ? "pointer" : "default"; return + style={maybeNoPointer({ cursor: "pointer" })}> {visible && slots.map(slot => { xySwap, }; return !DevSettings.futureFeaturesEnabled() && - history.push(`/app/designer/tool-slots/${id}`)}> + onClick={() => history.push(`/app/designer/tool-slots/${id}`)}> {pullout_direction && !gantry_mounted && - {!DevSettings.futureFeaturesEnabled() && - } + ({ + planned: { label: t("Planned"), value: "planned" }, + planted: { label: t("Planted"), value: "planted" }, + sprouted: { label: t("Sprouted"), value: "sprouted" }, + harvested: { label: t("Harvested"), value: "harvested" }, +}); +export const PLANT_STAGE_LIST = () => [ + PLANT_STAGE_DDI_LOOKUP().planned, + PLANT_STAGE_DDI_LOOKUP().planted, + PLANT_STAGE_DDI_LOOKUP().sprouted, + PLANT_STAGE_DDI_LOOKUP().harvested, ]; -const PLANT_STAGES_DDI = { - [PLANT_STAGES[0].value]: { - label: PLANT_STAGES[0].label, - value: PLANT_STAGES[0].value - }, - [PLANT_STAGES[1].value]: { - label: PLANT_STAGES[1].label, - value: PLANT_STAGES[1].value - }, - [PLANT_STAGES[2].value]: { - label: PLANT_STAGES[2].label, - value: PLANT_STAGES[2].value - }, - [PLANT_STAGES[3].value]: { - label: PLANT_STAGES[3].label, - value: PLANT_STAGES[3].value - }, -}; - /** Change `planted_at` value based on `plant_stage` update. */ const getUpdateByPlantStage = (plant_stage: PlantStage): PlantOptions => { const update: PlantOptions = { plant_stage }; @@ -52,8 +39,8 @@ const getUpdateByPlantStage = (plant_stage: PlantStage): PlantOptions => { export function EditPlantStatus(props: EditPlantStatusProps) { const { plantStatus, updatePlant, uuid } = props; return updatePlant(uuid, getUpdateByPlantStage(ddi.value as PlantStage))} />; } @@ -70,7 +57,7 @@ export const PlantStatusBulkUpdate = (props: PlantStatusBulkUpdateProps) =>

{t("update plant status to")}

{ diff --git a/frontend/farm_designer/point_groups/criteria/__tests__/add_test.tsx b/frontend/farm_designer/point_groups/criteria/__tests__/add_test.tsx index f1e170901..b5cd40b6f 100644 --- a/frontend/farm_designer/point_groups/criteria/__tests__/add_test.tsx +++ b/frontend/farm_designer/point_groups/criteria/__tests__/add_test.tsx @@ -9,7 +9,6 @@ import { AddEqCriteria, AddNumberCriteria, editCriteria, AddStringCriteria, toggleStringCriteria, POINTER_TYPE_LIST, - PLANT_STAGE_LIST } from ".."; import { AddEqCriteriaProps, NumberCriteriaProps, DEFAULT_CRITERIA, @@ -19,6 +18,7 @@ import { fakePointGroup } from "../../../../__test_support__/fake_state/resources"; import { PointGroup } from "farmbot/dist/resources/api_resources"; +import { PLANT_STAGE_LIST } from "../../../plants/edit_plant_status"; describe(" />", () => { const fakeProps = (): AddEqCriteriaProps => ({ diff --git a/frontend/farm_designer/point_groups/criteria/add.tsx b/frontend/farm_designer/point_groups/criteria/add.tsx index a24826756..5081181a8 100644 --- a/frontend/farm_designer/point_groups/criteria/add.tsx +++ b/frontend/farm_designer/point_groups/criteria/add.tsx @@ -10,6 +10,9 @@ import { AddNumberCriteriaState, AddStringCriteriaProps, } from "./interfaces"; +import { + PLANT_STAGE_DDI_LOOKUP, PLANT_STAGE_LIST +} from "../../plants/edit_plant_status"; export class AddEqCriteria extends React.Component, AddEqCriteriaState> { @@ -78,19 +81,6 @@ export const POINTER_TYPE_LIST = () => [ POINTER_TYPE_DDI_LOOKUP().ToolSlot, ]; -export const PLANT_STAGE_DDI_LOOKUP = (): { [x: string]: DropDownItem } => ({ - planned: { label: t("Planned"), value: "planned" }, - planted: { label: t("Planted"), value: "planted" }, - sprouted: { label: t("Sprouted"), value: "sprouted" }, - harvested: { label: t("Harvested"), value: "harvested" }, -}); -export const PLANT_STAGE_LIST = () => [ - PLANT_STAGE_DDI_LOOKUP().planned, - PLANT_STAGE_DDI_LOOKUP().planted, - PLANT_STAGE_DDI_LOOKUP().sprouted, - PLANT_STAGE_DDI_LOOKUP().harvested, -]; - export class AddStringCriteria extends React.Component { state: AddEqCriteriaState = { key: "", value: "" }; diff --git a/frontend/farm_designer/point_groups/criteria/show.tsx b/frontend/farm_designer/point_groups/criteria/show.tsx index ad79f2326..22f301e8a 100644 --- a/frontend/farm_designer/point_groups/criteria/show.tsx +++ b/frontend/farm_designer/point_groups/criteria/show.tsx @@ -3,7 +3,7 @@ import { cloneDeep, capitalize } from "lodash"; import { Row, Col, FBSelect, DropDownItem } from "../../../ui"; import { AddEqCriteria, toggleEqCriteria, editCriteria, AddNumberCriteria, - POINTER_TYPE_DDI_LOOKUP, PLANT_STAGE_DDI_LOOKUP, AddStringCriteria, + POINTER_TYPE_DDI_LOOKUP, AddStringCriteria, CRITERIA_TYPE_DDI_LOOKUP, toggleStringCriteria } from "."; import { @@ -14,6 +14,7 @@ import { } from "./interfaces"; import { t } from "../../../i18next_wrapper"; import { PointGroup } from "farmbot/dist/resources/api_resources"; +import { PLANT_STAGE_DDI_LOOKUP } from "../../plants/edit_plant_status"; export class EqCriteriaSelection extends React.Component> { diff --git a/frontend/help/__tests__/tours_test.ts b/frontend/help/__tests__/tours_test.ts index ef6dd92db..de9ee790f 100644 --- a/frontend/help/__tests__/tours_test.ts +++ b/frontend/help/__tests__/tours_test.ts @@ -1,12 +1,5 @@ jest.mock("../../history", () => ({ history: { push: jest.fn() } })); -let mockDev = false; -jest.mock("../../account/dev/dev_support", () => ({ - DevSettings: { - futureFeaturesEnabled: () => mockDev, - } -})); - import { fakeState } from "../../__test_support__/fake_state"; const mockState = fakeState(); jest.mock("../../redux/store", () => ({ @@ -46,7 +39,6 @@ describe("tourPageNavigation()", () => { it("includes steps based on tool count", () => { const getTargets = () => Object.values(TOUR_STEPS()[Tours.gettingStarted]).map(t => t.target); - mockDev = false; mockState.resources = buildResourceIndex([]); expect(getTargets()).not.toContain(".tool-slots"); mockState.resources = buildResourceIndex([fakeTool()]); @@ -56,7 +48,6 @@ describe("tourPageNavigation()", () => { it("has correct content based on board version", () => { const getTitles = () => Object.values(TOUR_STEPS()[Tours.gettingStarted]).map(t => t.title); - mockDev = false; mockState.resources = buildResourceIndex([]); expect(getTitles()).toContain("Add tools and slots"); expect(getTitles()).not.toContain("Add seed containers"); @@ -69,13 +60,4 @@ describe("tourPageNavigation()", () => { expect(getTitles()).not.toContain("Add seed containers and slots"); expect(getTitles()).toContain("Add seed containers"); }); - - it("includes correct tour steps", () => { - mockDev = true; - const targets = - Object.values(TOUR_STEPS()[Tours.gettingStarted]).map(t => t.target); - expect(targets).not.toContain(".tools"); - expect(targets).toContain(".tool-list"); - expect(targets).toContain(".toolbay-list"); - }); }); diff --git a/frontend/help/tours.ts b/frontend/help/tours.ts index 505f9a626..6d27b3b7b 100644 --- a/frontend/help/tours.ts +++ b/frontend/help/tours.ts @@ -2,7 +2,6 @@ import { history } from "../history"; import { Step as TourStep } from "react-joyride"; import { TourContent } from "../constants"; import { t } from "../i18next_wrapper"; -import { DevSettings } from "../account/dev/dev_support"; import { selectAllTools } from "../resources/selectors"; import { store } from "../redux/store"; import { getFbosConfig } from "../resources/getters"; @@ -64,16 +63,8 @@ export const TOUR_STEPS = (): { [x: string]: TourStep[] } => ({ content: t(TourContent.ADD_PLANTS), title: t("Add plants"), }, - ...(DevSettings.futureFeaturesEnabled() ? [{ - target: ".tool-list", - content: t(TourContent.ADD_TOOLS), - title: t("Add tools and seed containers"), - }] : toolsStep()), - ...(DevSettings.futureFeaturesEnabled() ? [{ - target: ".toolbay-list", - content: t(TourContent.ADD_TOOLS_SLOTS), - title: t("Add tools to tool bay"), - }] : toolSlotsStep()), + ...toolsStep(), + ...toolSlotsStep(), { target: ".peripherals-widget", content: t(TourContent.ADD_PERIPHERALS), diff --git a/frontend/nav/__tests__/nav_links_test.tsx b/frontend/nav/__tests__/nav_links_test.tsx index 3550df51c..db3682ccb 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"; @@ -28,7 +23,6 @@ describe("", () => { }); it("shows links", () => { - mockDev = false; const wrapper = mount(); expect(wrapper.text().toLowerCase()).not.toContain("tools"); }); diff --git a/frontend/nav/nav_links.tsx b/frontend/nav/nav_links.tsx index e4d7bc76c..a0f0a6fb4 100644 --- a/frontend/nav/nav_links.tsx +++ b/frontend/nav/nav_links.tsx @@ -7,7 +7,6 @@ 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; @@ -37,8 +36,6 @@ export const getLinks = (): NavLinkParams[] => betterCompact([ name: "Regimens", icon: "calendar-check-o", slug: "regimens", computeHref: computeEditorUrlFromState("Regimen") }, - !DevSettings.futureFeaturesEnabled() ? undefined : - { name: "Tools", icon: "wrench", slug: "tools" }, { name: "Farmware", icon: "crosshairs", slug: "farmware", computeHref: computeFarmwareUrlFromState