simplify board type dropdown component

pull/1277/head
gabrielburnworth 2019-07-15 15:53:28 -07:00
parent 42430c569b
commit 676f83f05c
14 changed files with 157 additions and 194 deletions

View File

@ -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");
});
});

View File

@ -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("<BoardType/>", () => {
const fakeConfig = fakeFbosConfig();
@ -31,70 +35,8 @@ describe("<BoardType/>", () => {
timeSettings: fakeTimeSettings(),
});
it("Farmduino", () => {
const p = fakeProps();
p.bot.hardware.informational_settings.firmware_version = "5.0.3.F";
const wrapper = mount(<BoardType {...p} />);
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(<BoardType {...p} />);
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(<BoardType {...p} />);
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<BoardType>(<BoardType {...p} />);
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<BoardType>(<BoardType {...p} />);
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(<BoardType {...p} />);
expect(wrapper.text()).toContain("None");
});
it("Disconnected", () => {
const p = fakeProps();
p.bot.hardware.informational_settings.firmware_version = "Arduino Disconnected!";
expect(mount(<BoardType {...p} />).text()).toContain("None");
p.bot.hardware.informational_settings.firmware_version = "disconnected";
expect(mount(<BoardType {...p} />).text()).toContain("None");
});
it("Stubbed", () => {
const p = fakeProps();
p.bot.hardware.informational_settings.firmware_version = "STUBFW";
const wrapper = mount(<BoardType {...p} />);
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(<BoardType {...p} />);
expect(wrapper.text()).toContain("Farmduino");
@ -102,22 +44,32 @@ describe("<BoardType/>", () => {
it("calls updateConfig", () => {
const p = fakeProps();
p.bot.hardware.informational_settings.firmware_version = "Arduino Disconnected!";
const wrapper = shallow(<BoardType {...p} />);
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(<BoardType {...p} />);
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(<BoardType {...fakeProps()} />);
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("<BoardType/>", () => {
const wrapper = shallow(<BoardType {...p} />);
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" },
]);
});
});

View File

@ -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<BoardTypeProps, BoardTypeState> {
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<BoardTypeProps, BoardTypeState> {
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<BoardTypeProps, BoardTypeState> {
<Col xs={ColWidth.description}>
<div>
<FBSelect
key={this.state.boardType}
key={this.apiValue}
extraClass={this.state.sending ? "dim" : ""}
list={this.firmwareChoices}
list={getFirmwareChoices(this.props.shouldDisplay)}
selectedItem={this.selectedBoard}
onChange={this.sendOffConfig} />
</div>

View File

@ -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;

View File

@ -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] : []),
]);

View File

@ -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", () => {

View File

@ -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
};

View File

@ -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<Props, {}> {

View File

@ -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<Record<Feature, string>>;

View File

@ -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",
});
});

View File

@ -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<CommonAlertCardProps, AlertComponentState> {
state: AlertComponentState = { bulletin: undefined, no_content: false };
extends React.Component<CommonAlertCardProps, BulletinAlertComponentState> {
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 = () =>
<table className="firmware-hardware-choice-table">
<thead>
@ -207,11 +196,13 @@ const FirmwareMissing = (props: FirmwareMissingProps) =>
<Col xs={5}>
<FBSelect
key={props.apiFirmwareValue}
list={FIRMWARE_CHOICES}
selectedItem={FIRMWARE_CHOICES_DDI[props.apiFirmwareValue || "arduino"]}
list={getFirmwareChoices()}
customNullLabel={t("Select one")}
selectedItem={props.apiFirmwareValue
? FIRMWARE_CHOICES_DDI[props.apiFirmwareValue] : undefined}
onChange={changeFirmwareHardware(props.dispatch)} />
</Col>
<Col xs={3}>
<Col xs={3} hidden={true}>
<FlashFirmwareBtn
apiFirmwareValue={props.apiFirmwareValue}
botOnline={true} />

View File

@ -89,7 +89,7 @@ export interface Bulletin {
title: string | undefined;
}
export interface AlertComponentState {
export interface BulletinAlertComponentState {
bulletin: Bulletin | undefined;
no_content: boolean;
}

View File

@ -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",
};
}

View File

@ -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));