From 676f83f05ce9cee559e2a00c5d22ce8479c7b0b3 Mon Sep 17 00:00:00 2001 From: gabrielburnworth Date: Mon, 15 Jul 2019 15:53:28 -0700 Subject: [PATCH] simplify board type dropdown component --- .../firmware_hardware_support_test.ts | 29 ++++++ .../__tests__/board_type_test.tsx | 90 +++++------------- .../components/fbos_settings/board_type.tsx | 94 ++----------------- .../firmware_hardware_status.tsx | 3 +- .../components/firmware_hardware_support.ts | 68 ++++++++++++++ .../__tests__/status_checks_test.ts | 2 +- .../devices/connectivity/status_checks.tsx | 8 +- frontend/devices/devices.tsx | 2 +- frontend/devices/interfaces.ts | 1 + frontend/messages/__tests__/reducer_test.ts | 2 +- frontend/messages/cards.tsx | 29 ++---- frontend/messages/interfaces.ts | 2 +- frontend/messages/reducer.ts | 2 +- frontend/messages/state_to_props.ts | 19 ++-- 14 files changed, 157 insertions(+), 194 deletions(-) create mode 100644 frontend/devices/components/__tests__/firmware_hardware_support_test.ts create mode 100644 frontend/devices/components/firmware_hardware_support.ts diff --git a/frontend/devices/components/__tests__/firmware_hardware_support_test.ts b/frontend/devices/components/__tests__/firmware_hardware_support_test.ts new file mode 100644 index 000000000..9c252cdc6 --- /dev/null +++ b/frontend/devices/components/__tests__/firmware_hardware_support_test.ts @@ -0,0 +1,29 @@ +import { boardType } from "../firmware_hardware_support"; + +describe("boardType()", () => { + it("returns Farmduino", () => { + expect(boardType("5.0.3.F")).toEqual("farmduino"); + }); + + it("returns Farmduino k1.4", () => { + expect(boardType("5.0.3.G")).toEqual("farmduino_k14"); + }); + + it("returns Farmduino Express k1.0", () => { + expect(boardType("5.0.3.E")).toEqual("express_k10"); + }); + + it("returns Arduino/RAMPS", () => { + expect(boardType("5.0.3.R")).toEqual("arduino"); + }); + + it("returns unknown", () => { + expect(boardType(undefined)).toEqual("unknown"); + expect(boardType("Arduino Disconnected!")).toEqual("unknown"); + expect(boardType("STUBFW")).toEqual("unknown"); + }); + + it("returns None", () => { + expect(boardType("none")).toEqual("none"); + }); +}); diff --git a/frontend/devices/components/fbos_settings/__tests__/board_type_test.tsx b/frontend/devices/components/fbos_settings/__tests__/board_type_test.tsx index dd7cd3cc8..b6bfdbfaa 100644 --- a/frontend/devices/components/fbos_settings/__tests__/board_type_test.tsx +++ b/frontend/devices/components/fbos_settings/__tests__/board_type_test.tsx @@ -8,13 +8,17 @@ import { mount, shallow } from "enzyme"; import { BoardType } from "../board_type"; import { BoardTypeProps } from "../interfaces"; import { fakeState } from "../../../../__test_support__/fake_state"; -import { fakeFbosConfig } from "../../../../__test_support__/fake_state/resources"; +import { + fakeFbosConfig +} from "../../../../__test_support__/fake_state/resources"; import { buildResourceIndex } from "../../../../__test_support__/resource_index_builder"; import { edit, save } from "../../../../api/crud"; import { bot } from "../../../../__test_support__/fake_state/bot"; -import { fakeTimeSettings } from "../../../../__test_support__/fake_time_settings"; +import { + fakeTimeSettings +} from "../../../../__test_support__/fake_time_settings"; describe("", () => { const fakeConfig = fakeFbosConfig(); @@ -31,70 +35,8 @@ describe("", () => { timeSettings: fakeTimeSettings(), }); - it("Farmduino", () => { - const p = fakeProps(); - p.bot.hardware.informational_settings.firmware_version = "5.0.3.F"; - const wrapper = mount(); - expect(wrapper.text()).toContain("Farmduino"); - }); - - it("Farmduino k1.4", () => { - const p = fakeProps(); - p.bot.hardware.informational_settings.firmware_version = "5.0.3.G"; - const wrapper = mount(); - expect(wrapper.text()).toContain("1.4"); - }); - - it("Farmduino Express k1.0", () => { - const p = fakeProps(); - p.bot.hardware.informational_settings.firmware_version = "5.0.3.E"; - const wrapper = mount(); - expect(wrapper.text()).toContain("Express"); - }); - - it("Arduino/RAMPS", () => { - const p = fakeProps(); - p.bot.hardware.informational_settings.firmware_version = "5.0.3.R"; - const wrapper = mount(); - expect(wrapper.text()).toContain("Arduino/RAMPS"); - }); - - it("changes boardType", () => { - const p = fakeProps(); - p.bot.hardware.informational_settings.firmware_version = "5.0.3.R"; - const wrapper = mount(); - expect(wrapper.text()).toContain("Arduino/RAMPS"); - expect(wrapper.state().boardType).toEqual("arduino"); - p.bot.hardware.informational_settings.firmware_version = "5.0.3.F"; - wrapper.setProps(p); - expect(wrapper.state().boardType).toEqual("farmduino"); - }); - - it("Undefined", () => { - const p = fakeProps(); - p.bot.hardware.informational_settings.firmware_version = undefined; - const wrapper = mount(); - expect(wrapper.text()).toContain("None"); - }); - - it("Disconnected", () => { - const p = fakeProps(); - p.bot.hardware.informational_settings.firmware_version = "Arduino Disconnected!"; - expect(mount().text()).toContain("None"); - p.bot.hardware.informational_settings.firmware_version = "disconnected"; - expect(mount().text()).toContain("None"); - }); - - it("Stubbed", () => { - const p = fakeProps(); - p.bot.hardware.informational_settings.firmware_version = "STUBFW"; - const wrapper = mount(); - expect(wrapper.text()).toContain("None"); - }); - it("Disconnected with valid FirmwareConfig", () => { const p = fakeProps(); - p.bot.hardware.informational_settings.firmware_version = "Arduino Disconnected!"; p.sourceFbosConfig = () => ({ value: "farmduino", consistent: false }); const wrapper = mount(); expect(wrapper.text()).toContain("Farmduino"); @@ -102,22 +44,32 @@ describe("", () => { it("calls updateConfig", () => { const p = fakeProps(); - p.bot.hardware.informational_settings.firmware_version = "Arduino Disconnected!"; const wrapper = shallow(); wrapper.find("FBSelect").simulate("change", { label: "firmware_hardware", value: "farmduino" }); - expect(edit).toHaveBeenCalledWith(fakeConfig, { firmware_hardware: "farmduino" }); + expect(edit).toHaveBeenCalledWith(fakeConfig, { + firmware_hardware: "farmduino" + }); expect(save).toHaveBeenCalledWith(fakeConfig.uuid); }); + it("deosn't call updateConfig", () => { + const p = fakeProps(); + const wrapper = shallow(); + wrapper.find("FBSelect").simulate("change", + { label: "firmware_hardware", value: "unknown" }); + expect(edit).not.toHaveBeenCalled(); + expect(save).not.toHaveBeenCalled(); + }); + it("displays standard boards", () => { const wrapper = shallow(); const { list } = wrapper.find("FBSelect").props(); expect(list).toEqual([ - { label: "None", value: "none" }, { label: "Arduino/RAMPS (Genesis v1.2)", value: "arduino" }, { label: "Farmduino (Genesis v1.3)", value: "farmduino" }, - { label: "Farmduino (Genesis v1.4)", value: "farmduino_k14" }]); + { label: "Farmduino (Genesis v1.4)", value: "farmduino_k14" }, + ]); }); it("displays new boards", () => { @@ -126,11 +78,11 @@ describe("", () => { const wrapper = shallow(); const { list } = wrapper.find("FBSelect").props(); expect(list).toEqual([ - { label: "None", value: "none" }, { label: "Arduino/RAMPS (Genesis v1.2)", value: "arduino" }, { label: "Farmduino (Genesis v1.3)", value: "farmduino" }, { label: "Farmduino (Genesis v1.4)", value: "farmduino_k14" }, { label: "Farmduino (Express v1.0)", value: "express_k10" }, + { label: "None", value: "none" }, ]); }); }); diff --git a/frontend/devices/components/fbos_settings/board_type.tsx b/frontend/devices/components/fbos_settings/board_type.tsx index 85e9f9212..9c69fd681 100644 --- a/frontend/devices/components/fbos_settings/board_type.tsx +++ b/frontend/devices/components/fbos_settings/board_type.tsx @@ -7,65 +7,19 @@ import { updateConfig } from "../../actions"; import { BoardTypeProps } from "./interfaces"; import { t } from "../../../i18next_wrapper"; import { FirmwareHardwareStatus } from "./firmware_hardware_status"; -import { Feature } from "../../interfaces"; +import { + isFwHardwareValue, getFirmwareChoices, FIRMWARE_CHOICES_DDI +} from "../firmware_hardware_support"; -const ARDUINO = { label: "Arduino/RAMPS (Genesis v1.2)", value: "arduino" }; -const FARMDUINO = { label: "Farmduino (Genesis v1.3)", value: "farmduino" }; -const FARMDUINO_K14 = { - label: "Farmduino (Genesis v1.4)", value: "farmduino_k14" -}; -const EXPRESS_K10 = { - label: "Farmduino (Express v1.0)", value: "express_k10" -}; -const NONE = { label: "None", value: "none" }; - -export const FIRMWARE_CHOICES_DDI = { - [ARDUINO.value]: ARDUINO, - [FARMDUINO.value]: FARMDUINO, - [FARMDUINO_K14.value]: FARMDUINO_K14, - [EXPRESS_K10.value]: EXPRESS_K10, - [NONE.value]: NONE -}; - -export const isFwHardwareValue = (x?: unknown): x is FirmwareHardware => { - const values: FirmwareHardware[] = - ["arduino", "farmduino", "farmduino_k14", "express_k10", "none"]; - return !!values.includes(x as FirmwareHardware); -}; - -export const boardType = - (firmwareVersion: string | undefined): FirmwareHardware | "unknown" => { - if (firmwareVersion) { - const boardIdentifier = firmwareVersion.slice(-1); - switch (boardIdentifier) { - case "R": - return "arduino"; - case "F": - return "farmduino"; - case "G": - return "farmduino_k14"; - case "E": - return "express_k10"; - default: - return "unknown"; - } - } else { - return "unknown"; - } - }; - -interface BoardTypeState { boardType: string, sending: boolean } +interface BoardTypeState { sending: boolean } export class BoardType extends React.Component { state = { - boardType: this.boardType, sending: this.sending }; componentWillReceiveProps() { this.setState({ sending: this.sending }); - !["unknown", "Present"].includes(this.boardType) && - this.setState({ boardType: this.boardType }); } get sending() { @@ -77,42 +31,8 @@ export class BoardType extends React.Component { return isFwHardwareValue(value) ? value : undefined; } - get firmwareChoices() { - const { shouldDisplay } = this.props; - const others = shouldDisplay(Feature.express_k10) ? [EXPRESS_K10] : []; - return [ - NONE, - ARDUINO, - FARMDUINO, - FARMDUINO_K14, - ...others - ]; - } - - get firmwareVersion() { - return this.props.bot.hardware.informational_settings.firmware_version; - } - - get boardType() { return boardType(this.firmwareVersion); } - get selectedBoard(): DropDownItem | undefined { - switch (this.state.boardType) { - case "arduino": - return FIRMWARE_CHOICES_DDI["arduino"]; - case "farmduino": - return FIRMWARE_CHOICES_DDI["farmduino"]; - case "farmduino_k14": - return FIRMWARE_CHOICES_DDI["farmduino_k14"]; - case "express_k10": - return FIRMWARE_CHOICES_DDI["express_k10"]; - case "unknown": - // If unknown/disconnected, display API FirmwareHardware value if valid - return (this.sending && this.apiValue) - ? FIRMWARE_CHOICES_DDI[this.apiValue] - : undefined; - default: - return undefined; - } + return this.apiValue ? FIRMWARE_CHOICES_DDI[this.apiValue] : undefined; } sendOffConfig = (selectedItem: DropDownItem) => { @@ -135,9 +55,9 @@ export class BoardType extends React.Component {
diff --git a/frontend/devices/components/fbos_settings/firmware_hardware_status.tsx b/frontend/devices/components/fbos_settings/firmware_hardware_status.tsx index 9fc2f8f20..a355d02b3 100644 --- a/frontend/devices/components/fbos_settings/firmware_hardware_status.tsx +++ b/frontend/devices/components/fbos_settings/firmware_hardware_status.tsx @@ -1,6 +1,6 @@ import * as React from "react"; import { Popover, Position } from "@blueprintjs/core"; -import { FIRMWARE_CHOICES_DDI, isFwHardwareValue, boardType } from "./board_type"; +import { FIRMWARE_CHOICES_DDI } from "../firmware_hardware_support"; import { flashFirmware } from "../../actions"; import { t } from "../../../i18next_wrapper"; import { BotState, Feature, ShouldDisplay } from "../../interfaces"; @@ -8,6 +8,7 @@ import { FirmwareAlerts } from "../../../messages/alerts"; import { TimeSettings } from "../../../interfaces"; import { trim } from "../../../util"; import { Alert } from "farmbot"; +import { isFwHardwareValue, boardType } from "../firmware_hardware_support"; export interface FirmwareHardwareStatusIconProps { firmwareHardware: string | undefined; diff --git a/frontend/devices/components/firmware_hardware_support.ts b/frontend/devices/components/firmware_hardware_support.ts new file mode 100644 index 000000000..91b42e60f --- /dev/null +++ b/frontend/devices/components/firmware_hardware_support.ts @@ -0,0 +1,68 @@ +import { FirmwareHardware } from "farmbot"; +import { ShouldDisplay, Feature } from "../interfaces"; + +export const isFwHardwareValue = (x?: unknown): x is FirmwareHardware => { + const values: FirmwareHardware[] = + ["arduino", "farmduino", "farmduino_k14", "express_k10", "none"]; + return !!values.includes(x as FirmwareHardware); +}; + +export const getBoardIdentifier = + (firmwareVersion: string | undefined): string => + firmwareVersion ? firmwareVersion.slice(-1) : "undefined"; + +export const isKnownBoard = (firmwareVersion: string | undefined): boolean => { + const boardIdentifier = getBoardIdentifier(firmwareVersion); + return ["R", "F", "G", "E"].includes(boardIdentifier); +}; + +export const getBoardCategory = + (firmwareVersion: string | undefined): "Farmduino" | "Arduino" => { + const boardIdentifier = getBoardIdentifier(firmwareVersion); + return boardIdentifier === "R" ? "Arduino" : "Farmduino"; + }; + +export const boardType = + (firmwareVersion: string | undefined): FirmwareHardware | "unknown" => { + if (firmwareVersion === "none") { return "none"; } + const boardIdentifier = getBoardIdentifier(firmwareVersion); + switch (boardIdentifier) { + case "R": + return "arduino"; + case "F": + return "farmduino"; + case "G": + return "farmduino_k14"; + case "E": + return "express_k10"; + default: + return "unknown"; + } + }; + +const ARDUINO = { label: "Arduino/RAMPS (Genesis v1.2)", value: "arduino" }; +const FARMDUINO = { label: "Farmduino (Genesis v1.3)", value: "farmduino" }; +const FARMDUINO_K14 = { + label: "Farmduino (Genesis v1.4)", value: "farmduino_k14" +}; +const EXPRESS_K10 = { + label: "Farmduino (Express v1.0)", value: "express_k10" +}; +const NONE = { label: "None", value: "none" }; + +export const FIRMWARE_CHOICES_DDI = { + [ARDUINO.value]: ARDUINO, + [FARMDUINO.value]: FARMDUINO, + [FARMDUINO_K14.value]: FARMDUINO_K14, + [EXPRESS_K10.value]: EXPRESS_K10, + [NONE.value]: NONE +}; + +export const getFirmwareChoices = + (shouldDisplay: ShouldDisplay = () => true) => ([ + ARDUINO, + FARMDUINO, + FARMDUINO_K14, + ...(shouldDisplay(Feature.express_k10) ? [EXPRESS_K10] : []), + ...(shouldDisplay(Feature.none_firmware) ? [NONE] : []), + ]); diff --git a/frontend/devices/connectivity/__tests__/status_checks_test.ts b/frontend/devices/connectivity/__tests__/status_checks_test.ts index 5dd8aa722..2566a9597 100644 --- a/frontend/devices/connectivity/__tests__/status_checks_test.ts +++ b/frontend/devices/connectivity/__tests__/status_checks_test.ts @@ -85,7 +85,7 @@ describe("botToFirmware()", () => { it("board undefined", () => { const output = botToFirmware(undefined); - expect(output.to).toContain("Arduino"); + expect(output.to).toContain("Farmduino"); }); it("handles lack of connectivity", () => { diff --git a/frontend/devices/connectivity/status_checks.tsx b/frontend/devices/connectivity/status_checks.tsx index a6e429579..1e6ade6d0 100644 --- a/frontend/devices/connectivity/status_checks.tsx +++ b/frontend/devices/connectivity/status_checks.tsx @@ -3,6 +3,9 @@ import moment from "moment"; import { StatusRowProps } from "./connectivity_row"; import { ConnectionStatus } from "../../connectivity/interfaces"; import { t } from "../../i18next_wrapper"; +import { + getBoardCategory, isKnownBoard +} from "../components/firmware_hardware_support"; const HOUR = 1000 * 60 * 60; @@ -59,9 +62,8 @@ export function browserToMQTT(status: } export function botToFirmware(version: string | undefined): StatusRowProps { - const boardIdentifier = version ? version.slice(-1) : "undefined"; const connection = (): { status: boolean | undefined, msg: string } => { - const status = ["R", "F", "G", "E"].includes(boardIdentifier); + const status = isKnownBoard(version); if (isUndefined(version)) { return { status: undefined, msg: t("Unknown.") }; } @@ -74,7 +76,7 @@ export function botToFirmware(version: string | undefined): StatusRowProps { return { connectionName: "botFirmware", from: "Raspberry Pi", - to: ["F", "G", "E"].includes(boardIdentifier) ? "Farmduino" : "Arduino", + to: getBoardCategory(version), children: connection().msg, connectionStatus: connection().status }; diff --git a/frontend/devices/devices.tsx b/frontend/devices/devices.tsx index 5ce86eb61..a39d7c1cc 100644 --- a/frontend/devices/devices.tsx +++ b/frontend/devices/devices.tsx @@ -8,7 +8,7 @@ import { Props } from "./interfaces"; import { PinBindings } from "./pin_bindings/pin_bindings"; import { selectAllDiagnosticDumps } from "../resources/selectors"; import { getStatus } from "../connectivity/reducer_support"; -import { isFwHardwareValue } from "./components/fbos_settings/board_type"; +import { isFwHardwareValue } from "./components/firmware_hardware_support"; @connect(mapStateToProps) export class Devices extends React.Component { diff --git a/frontend/devices/interfaces.ts b/frontend/devices/interfaces.ts index 9715bd37a..fc2ca6694 100644 --- a/frontend/devices/interfaces.ts +++ b/frontend/devices/interfaces.ts @@ -85,6 +85,7 @@ export enum Feature { long_scaling_factor = "long_scaling_factor", flash_firmware = "flash_firmware", express_k10 = "express_k10", + none_firmware = "none_firmware", } /** Object fetched from FEATURE_MIN_VERSIONS_URL. */ export type MinOsFeatureLookup = Partial>; diff --git a/frontend/messages/__tests__/reducer_test.ts b/frontend/messages/__tests__/reducer_test.ts index 6271d5b9d..616d2e2cf 100644 --- a/frontend/messages/__tests__/reducer_test.ts +++ b/frontend/messages/__tests__/reducer_test.ts @@ -17,7 +17,7 @@ describe("Contextual `Alert` creation", () => { expect(results[0]).toEqual({ created_at: 1, problem_tag: "farmbot_os.firmware.missing", - priority: 99999, + priority: 0, slug: "firmware-missing", }); }); diff --git a/frontend/messages/cards.tsx b/frontend/messages/cards.tsx index 2ec5abdf1..317f14e45 100644 --- a/frontend/messages/cards.tsx +++ b/frontend/messages/cards.tsx @@ -6,7 +6,7 @@ import { CommonAlertCardProps, DismissAlertProps, Bulletin, - AlertComponentState + BulletinAlertComponentState } from "./interfaces"; import { formatLogTime } from "../logs"; import { @@ -18,8 +18,8 @@ import { TourList } from "../help/tour_list"; import { splitProblemTag } from "./alerts"; import { destroy } from "../api/crud"; import { - isFwHardwareValue -} from "../devices/components/fbos_settings/board_type"; + isFwHardwareValue, FIRMWARE_CHOICES_DDI, getFirmwareChoices +} from "../devices/components/firmware_hardware_support"; import { updateConfig } from "../devices/actions"; import { fetchBulletinContent, seedAccount } from "./actions"; import { startCase } from "lodash"; @@ -83,8 +83,8 @@ const ICON_LOOKUP: { [x: string]: string } = { }; class BulletinAlert - extends React.Component { - state: AlertComponentState = { bulletin: undefined, no_content: false }; + extends React.Component { + state: BulletinAlertComponentState = { bulletin: undefined, no_content: false }; componentDidMount() { fetchBulletinContent(this.props.alert.slug) @@ -139,17 +139,6 @@ const UnknownAlert = (props: CommonAlertCardProps) => { findApiAlertById={props.findApiAlertById} />; }; -const FIRMWARE_CHOICES: DropDownItem[] = [ - { label: "Arduino/RAMPS (Genesis v1.2)", value: "arduino" }, - { label: "Farmduino (Genesis v1.3)", value: "farmduino" }, - { label: "Farmduino (Genesis v1.4)", value: "farmduino_k14" }, - { label: "Farmduino (Express v1.0)", value: "express_k10" }, - { label: "None", value: "none" }, -]; - -const FIRMWARE_CHOICES_DDI: { [x: string]: DropDownItem } = {}; -FIRMWARE_CHOICES.map(x => FIRMWARE_CHOICES_DDI[x.value] = x); - const FirmwareChoiceTable = () => @@ -207,11 +196,13 @@ const FirmwareMissing = (props: FirmwareMissingProps) => - + diff --git a/frontend/messages/interfaces.ts b/frontend/messages/interfaces.ts index d9e8f8ce0..d9eebd809 100644 --- a/frontend/messages/interfaces.ts +++ b/frontend/messages/interfaces.ts @@ -89,7 +89,7 @@ export interface Bulletin { title: string | undefined; } -export interface AlertComponentState { +export interface BulletinAlertComponentState { bulletin: Bulletin | undefined; no_content: boolean; } diff --git a/frontend/messages/reducer.ts b/frontend/messages/reducer.ts index da753b98e..41f937ece 100644 --- a/frontend/messages/reducer.ts +++ b/frontend/messages/reducer.ts @@ -23,7 +23,7 @@ const toggleAlert = (s: State, body: TaggedFbosConfig["body"]) => { s.alerts[FIRMWARE_MISSING] = { created_at: 1, problem_tag: FIRMWARE_MISSING, - priority: 99999, + priority: 0, slug: "firmware-missing", }; } diff --git a/frontend/messages/state_to_props.ts b/frontend/messages/state_to_props.ts index 8f1918fee..413e2746e 100644 --- a/frontend/messages/state_to_props.ts +++ b/frontend/messages/state_to_props.ts @@ -6,7 +6,9 @@ import { sourceFbosConfigValue } from "../devices/components/source_config_value import { selectAllAlerts, maybeGetTimeSettings, findResourceById } from "../resources/selectors"; -import { isFwHardwareValue } from "../devices/components/fbos_settings/board_type"; +import { + isFwHardwareValue +} from "../devices/components/firmware_hardware_support"; import { ResourceIndex, UUID } from "../resources/interfaces"; import { Alert } from "farmbot"; @@ -28,16 +30,13 @@ export const mapStateToProps = (props: Everything): MessagesProps => { }; }; -export const getAllAlerts = - (resources: Everything["resources"]) => { - return [ - ...getLocalAlerts(resources.consumers.alerts), - ...getApiAlerts(resources.index) - ]; - }; +export const getAllAlerts = (resources: Everything["resources"]) => ([ + ...getApiAlerts(resources.index), + ...getLocalAlerts(resources.consumers.alerts), +]); -export const getApiAlerts = (resourceIndex: ResourceIndex): Alert[] => +const getApiAlerts = (resourceIndex: ResourceIndex): Alert[] => selectAllAlerts(resourceIndex).map(x => x.body); -export const getLocalAlerts = ({ alerts }: AlertReducerState) => +const getLocalAlerts = ({ alerts }: AlertReducerState): Alert[] => betterCompact(Object.values(alerts));