cleanup and refactoring

pull/1721/head
gabrielburnworth 2020-02-26 12:08:49 -08:00
parent a49e5e67ba
commit edb96d3ca8
19 changed files with 85 additions and 167 deletions

View File

@ -17,6 +17,7 @@ import { PowerAndReset } from "./fbos_settings/power_and_reset";
import { BootSequenceSelector } from "./fbos_settings/boot_sequence_selector"; import { BootSequenceSelector } from "./fbos_settings/boot_sequence_selector";
import { ExternalUrl } from "../../external_urls"; import { ExternalUrl } from "../../external_urls";
import { Highlight } from "./maybe_highlight"; import { Highlight } from "./maybe_highlight";
import { OtaTimeSelectorRow } from "./fbos_settings/ota_time_selector";
export enum ColWidth { export enum ColWidth {
label = 3, label = 3,
@ -78,8 +79,6 @@ export class FarmbotOsSettings
const { bot, sourceFbosConfig, botToMqttStatus } = this.props; const { bot, sourceFbosConfig, botToMqttStatus } = this.props;
const { sync_status } = bot.hardware.informational_settings; const { sync_status } = bot.hardware.informational_settings;
const botOnline = isBotOnline(sync_status, botToMqttStatus); const botOnline = isBotOnline(sync_status, botToMqttStatus);
const timeFormat = this.props.webAppConfig.body.time_format_24_hour ?
"24h" : "12h";
return <Widget className="device-widget"> return <Widget className="device-widget">
<form onSubmit={(e) => e.preventDefault()}> <form onSubmit={(e) => e.preventDefault()}>
<WidgetHeader title="Device"> <WidgetHeader title="Device">
@ -133,11 +132,14 @@ export class FarmbotOsSettings
shouldDisplay={this.props.shouldDisplay} shouldDisplay={this.props.shouldDisplay}
timeSettings={this.props.timeSettings} timeSettings={this.props.timeSettings}
sourceFbosConfig={sourceFbosConfig} /> sourceFbosConfig={sourceFbosConfig} />
<AutoUpdateRow <OtaTimeSelectorRow
timeFormat={timeFormat} timeSettings={this.props.timeSettings}
device={this.props.deviceAccount} device={this.props.deviceAccount}
dispatch={this.props.dispatch} dispatch={this.props.dispatch}
sourceFbosConfig={sourceFbosConfig} /> sourceFbosConfig={sourceFbosConfig} />
<AutoUpdateRow
dispatch={this.props.dispatch}
sourceFbosConfig={sourceFbosConfig} />
<FarmbotOsRow <FarmbotOsRow
bot={this.props.bot} bot={this.props.bot}
osReleaseNotesHeading={this.osReleaseNotes.heading} osReleaseNotesHeading={this.osReleaseNotes.heading}

View File

@ -11,7 +11,7 @@ import { fakeState } from "../../../../__test_support__/fake_state";
import { edit, save } from "../../../../api/crud"; import { edit, save } from "../../../../api/crud";
import { fakeFbosConfig } from "../../../../__test_support__/fake_state/resources"; import { fakeFbosConfig } from "../../../../__test_support__/fake_state/resources";
import { import {
buildResourceIndex, fakeDevice buildResourceIndex
} from "../../../../__test_support__/resource_index_builder"; } from "../../../../__test_support__/resource_index_builder";
describe("<AutoUpdateRow/>", () => { describe("<AutoUpdateRow/>", () => {
@ -20,10 +20,8 @@ describe("<AutoUpdateRow/>", () => {
state.resources = buildResourceIndex([fakeConfig]); state.resources = buildResourceIndex([fakeConfig]);
const fakeProps = (): AutoUpdateRowProps => ({ const fakeProps = (): AutoUpdateRowProps => ({
timeFormat: "12h",
device: fakeDevice(),
dispatch: jest.fn(x => x(jest.fn(), () => state)), dispatch: jest.fn(x => x(jest.fn(), () => state)),
sourceFbosConfig: () => ({ value: 1, consistent: true }) sourceFbosConfig: () => ({ value: 1, consistent: true }),
}); });
it("renders", () => { it("renders", () => {
@ -35,7 +33,7 @@ describe("<AutoUpdateRow/>", () => {
const p = fakeProps(); const p = fakeProps();
p.sourceFbosConfig = () => ({ value: 0, consistent: true }); p.sourceFbosConfig = () => ({ value: 0, consistent: true });
const wrapper = mount(<AutoUpdateRow {...p} />); const wrapper = mount(<AutoUpdateRow {...p} />);
wrapper.find("button").at(1).simulate("click"); wrapper.find("button").first().simulate("click");
expect(edit).toHaveBeenCalledWith(fakeConfig, { os_auto_update: true }); expect(edit).toHaveBeenCalledWith(fakeConfig, { os_auto_update: true });
expect(save).toHaveBeenCalledWith(fakeConfig.uuid); expect(save).toHaveBeenCalledWith(fakeConfig.uuid);
}); });
@ -44,7 +42,7 @@ describe("<AutoUpdateRow/>", () => {
const p = fakeProps(); const p = fakeProps();
p.sourceFbosConfig = () => ({ value: 1, consistent: true }); p.sourceFbosConfig = () => ({ value: 1, consistent: true });
const wrapper = mount(<AutoUpdateRow {...p} />); const wrapper = mount(<AutoUpdateRow {...p} />);
wrapper.find("button").at(1).simulate("click"); wrapper.find("button").first().simulate("click");
expect(edit).toHaveBeenCalledWith(fakeConfig, { os_auto_update: false }); expect(edit).toHaveBeenCalledWith(fakeConfig, { os_auto_update: false });
expect(save).toHaveBeenCalledWith(fakeConfig.uuid); expect(save).toHaveBeenCalledWith(fakeConfig.uuid);
}); });

View File

@ -6,38 +6,30 @@ import { updateConfig } from "../../actions";
import { Content, DeviceSetting } from "../../../constants"; import { Content, DeviceSetting } from "../../../constants";
import { AutoUpdateRowProps } from "./interfaces"; import { AutoUpdateRowProps } from "./interfaces";
import { t } from "../../../i18next_wrapper"; import { t } from "../../../i18next_wrapper";
import { OtaTimeSelector, changeOtaHour } from "./ota_time_selector";
import { Highlight } from "../maybe_highlight"; import { Highlight } from "../maybe_highlight";
export function AutoUpdateRow(props: AutoUpdateRowProps) { export function AutoUpdateRow(props: AutoUpdateRowProps) {
const osAutoUpdate = props.sourceFbosConfig("os_auto_update"); const osAutoUpdate = props.sourceFbosConfig("os_auto_update");
return <div> return <Row>
<OtaTimeSelector <Highlight settingName={DeviceSetting.farmbotOSAutoUpdate}>
timeFormat={props.timeFormat} <Col xs={ColWidth.label}>
disabled={!osAutoUpdate.value} <label>
value={props.device.body.ota_hour} {t(DeviceSetting.farmbotOSAutoUpdate)}
onChange={changeOtaHour(props.dispatch, props.device)} /> </label>
<Row> </Col>
<Highlight settingName={DeviceSetting.farmbotOSAutoUpdate}> <Col xs={ColWidth.description}>
<Col xs={ColWidth.label}> <p>
<label> {t(Content.OS_AUTO_UPDATE)}
{t(DeviceSetting.farmbotOSAutoUpdate)} </p>
</label> </Col>
</Col> <Col xs={ColWidth.button}>
<Col xs={ColWidth.description}> <ToggleButton toggleValue={osAutoUpdate.value}
<p> dim={!osAutoUpdate.consistent}
{t(Content.OS_AUTO_UPDATE)} toggleAction={() => props.dispatch(updateConfig({
</p> os_auto_update: !osAutoUpdate.value
</Col> }))} />
<Col xs={ColWidth.button}> </Col>
<ToggleButton toggleValue={osAutoUpdate.value} </Highlight>
dim={!osAutoUpdate.consistent} </Row>;
toggleAction={() => props.dispatch(updateConfig({
os_auto_update: !osAutoUpdate.value
}))} />
</Col>
</Highlight>
</Row>
</div>;
} }

View File

@ -12,7 +12,6 @@ import {
TaggedDevice, TaggedDevice,
} from "farmbot"; } from "farmbot";
import { TimeSettings } from "../../../interfaces"; import { TimeSettings } from "../../../interfaces";
import { PreferredHourFormat } from "./ota_time_selector";
export interface AutoSyncRowProps { export interface AutoSyncRowProps {
dispatch: Function; dispatch: Function;
@ -21,9 +20,14 @@ export interface AutoSyncRowProps {
export interface AutoUpdateRowProps { export interface AutoUpdateRowProps {
dispatch: Function; dispatch: Function;
timeFormat: PreferredHourFormat; sourceFbosConfig: SourceFbosConfig;
}
export interface OtaTimeSelectorRowProps {
dispatch: Function;
sourceFbosConfig: SourceFbosConfig; sourceFbosConfig: SourceFbosConfig;
device: TaggedDevice; device: TaggedDevice;
timeSettings: TimeSettings;
} }
export interface CameraSelectionProps { export interface CameraSelectionProps {

View File

@ -6,11 +6,12 @@ import { edit, save } from "../../../api/crud";
import { ColWidth } from "../farmbot_os_settings"; import { ColWidth } from "../farmbot_os_settings";
import { DeviceSetting } from "../../../constants"; import { DeviceSetting } from "../../../constants";
import { Highlight } from "../maybe_highlight"; import { Highlight } from "../maybe_highlight";
import { OtaTimeSelectorRowProps } from "./interfaces";
// tslint:disable-next-line:no-null-keyword // tslint:disable-next-line:no-null-keyword
const UNDEFINED = null as unknown as undefined; const UNDEFINED = null as unknown as undefined;
const IMMEDIATELY = -1; const IMMEDIATELY = -1;
export type PreferredHourFormat = "12h" | "24h"; type PreferredHourFormat = "12h" | "24h";
type HOUR = type HOUR =
| typeof IMMEDIATELY | typeof IMMEDIATELY
| 0 | 0
@ -163,3 +164,13 @@ export const OtaTimeSelector = (props: OtaTimeSelectorProps): JSX.Element => {
</Highlight> </Highlight>
</Row>; </Row>;
}; };
export function OtaTimeSelectorRow(props: OtaTimeSelectorRowProps) {
const osAutoUpdate = props.sourceFbosConfig("os_auto_update");
const timeFormat = props.timeSettings.hour24 ? "24h" : "12h";
return <OtaTimeSelector
timeFormat={timeFormat}
disabled={!osAutoUpdate.value}
value={props.device.body.ota_hour}
onChange={changeOtaHour(props.dispatch, props.device)} />;
}

View File

@ -71,6 +71,14 @@ describe("<DesignerNavTabs />", () => {
expect(wrapper.html()).toContain("active"); expect(wrapper.html()).toContain("active");
}); });
it("renders for tools", () => {
mockPath = "/app/designer/tools";
mockDev = false;
const wrapper = shallow(<DesignerNavTabs />);
expect(wrapper.hasClass("gray-panel")).toBeTruthy();
expect(wrapper.html()).toContain("active");
});
it("renders for zones", () => { it("renders for zones", () => {
mockPath = "/app/designer/zones"; mockPath = "/app/designer/zones";
mockDev = true; mockDev = true;

View File

@ -4,11 +4,6 @@ jest.mock("../../../../../history", () => ({
getPathArray: jest.fn(() => { return mockPath.split("/"); }) getPathArray: jest.fn(() => { return mockPath.split("/"); })
})); }));
let mockDev = false;
jest.mock("../../../../../account/dev/dev_support", () => ({
DevSettings: { futureFeaturesEnabled: () => mockDev }
}));
import * as React from "react"; import * as React from "react";
import { ToolSlotLayer, ToolSlotLayerProps } from "../tool_slot_layer"; import { ToolSlotLayer, ToolSlotLayerProps } from "../tool_slot_layer";
import { import {
@ -57,16 +52,6 @@ describe("<ToolSlotLayer/>", () => {
expect(result.find(ToolSlotPoint).length).toEqual(1); 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(<ToolSlotLayer {...p} />);
const tools = wrapper.find("g").first();
await tools.simulate("click");
expect(history.push).toHaveBeenCalledWith("/app/tools");
});
it("doesn't navigate to tools page", async () => { it("doesn't navigate to tools page", async () => {
mockPath = "/app/designer/plants/1"; mockPath = "/app/designer/plants/1";
const p = fakeProps(); const p = fakeProps();

View File

@ -1,8 +1,3 @@
let mockDev = false;
jest.mock("../../../../../account/dev/dev_support", () => ({
DevSettings: { futureFeaturesEnabled: () => mockDev }
}));
jest.mock("../../../../../history", () => ({ history: { push: jest.fn() } })); jest.mock("../../../../../history", () => ({ history: { push: jest.fn() } }));
import * as React from "react"; import * as React from "react";
@ -17,10 +12,6 @@ import { svgMount } from "../../../../../__test_support__/svg_mount";
import { history } from "../../../../../history"; import { history } from "../../../../../history";
describe("<ToolSlotPoint/>", () => { describe("<ToolSlotPoint/>", () => {
beforeEach(() => {
mockDev = false;
});
const fakeProps = (): TSPProps => ({ const fakeProps = (): TSPProps => ({
mapTransformProps: fakeMapTransformProps(), mapTransformProps: fakeMapTransformProps(),
botPositionX: undefined, botPositionX: undefined,
@ -48,10 +39,6 @@ describe("<ToolSlotPoint/>", () => {
const p = fakeProps(); const p = fakeProps();
p.slot.toolSlot.body.id = 1; p.slot.toolSlot.body.id = 1;
const wrapper = svgMount(<ToolSlotPoint {...p} />); const wrapper = svgMount(<ToolSlotPoint {...p} />);
mockDev = true;
wrapper.find("g").first().simulate("click");
expect(history.push).not.toHaveBeenCalled();
mockDev = false;
wrapper.find("g").first().simulate("click"); wrapper.find("g").first().simulate("click");
expect(history.push).toHaveBeenCalledWith("/app/designer/tool-slots/1"); expect(history.push).toHaveBeenCalledWith("/app/designer/tool-slots/1");
}); });

View File

@ -2,9 +2,7 @@ import * as React from "react";
import { SlotWithTool, UUID } from "../../../../resources/interfaces"; import { SlotWithTool, UUID } from "../../../../resources/interfaces";
import { ToolSlotPoint } from "./tool_slot_point"; import { ToolSlotPoint } from "./tool_slot_point";
import { MapTransformProps } from "../../interfaces"; import { MapTransformProps } from "../../interfaces";
import { history, getPathArray } from "../../../../history";
import { maybeNoPointer } from "../../util"; import { maybeNoPointer } from "../../util";
import { DevSettings } from "../../../../account/dev/dev_support";
export interface ToolSlotLayerProps { export interface ToolSlotLayerProps {
visible: boolean; visible: boolean;
@ -16,17 +14,11 @@ export interface ToolSlotLayerProps {
} }
export function ToolSlotLayer(props: 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 { slots, visible, mapTransformProps } = props;
const cursor = canClickTool ? "pointer" : "default";
return <g return <g
id="toolslot-layer" id="toolslot-layer"
onClick={goToToolsPage} style={maybeNoPointer({ cursor: "pointer" })}>
style={maybeNoPointer({ cursor: cursor })}>
{visible && {visible &&
slots.map(slot => slots.map(slot =>
<ToolSlotPoint <ToolSlotPoint

View File

@ -5,7 +5,6 @@ import { MapTransformProps } from "../../interfaces";
import { ToolbaySlot, ToolNames, Tool, GantryToolSlot } from "./tool_graphics"; import { ToolbaySlot, ToolNames, Tool, GantryToolSlot } from "./tool_graphics";
import { ToolLabel } from "./tool_label"; import { ToolLabel } from "./tool_label";
import { includes } from "lodash"; import { includes } from "lodash";
import { DevSettings } from "../../../../account/dev/dev_support";
import { history } from "../../../../history"; import { history } from "../../../../history";
import { t } from "../../../../i18next_wrapper"; import { t } from "../../../../i18next_wrapper";
@ -49,8 +48,7 @@ export const ToolSlotPoint = (props: TSPProps) => {
xySwap, xySwap,
}; };
return <g id={"toolslot-" + id} return <g id={"toolslot-" + id}
onClick={() => !DevSettings.futureFeaturesEnabled() && onClick={() => history.push(`/app/designer/tool-slots/${id}`)}>
history.push(`/app/designer/tool-slots/${id}`)}>
{pullout_direction && !gantry_mounted && {pullout_direction && !gantry_mounted &&
<ToolbaySlot <ToolbaySlot
id={-(id || 1)} id={-(id || 1)}

View File

@ -143,11 +143,10 @@ export function DesignerNavTabs(props: { hidden?: boolean }) {
panel={Panel.Weeds} panel={Panel.Weeds}
linkTo={"/app/designer/weeds"} linkTo={"/app/designer/weeds"}
title={t("Weeds")} /> title={t("Weeds")} />
{!DevSettings.futureFeaturesEnabled() && <NavTab
<NavTab panel={Panel.Tools}
panel={Panel.Tools} linkTo={"/app/designer/tools"}
linkTo={"/app/designer/tools"} title={t("Tools")} />
title={t("Tools")} />}
<NavTab <NavTab
panel={Panel.Settings} panel={Panel.Settings}
icon={"fa fa-gear"} icon={"fa fa-gear"}

View File

@ -9,32 +9,19 @@ import { UUID } from "../../resources/interfaces";
import { edit, save } from "../../api/crud"; import { edit, save } from "../../api/crud";
import { EditPlantStatusProps } from "./plant_panel"; import { EditPlantStatusProps } from "./plant_panel";
const PLANT_STAGES: DropDownItem[] = [ export const PLANT_STAGE_DDI_LOOKUP = (): { [x: string]: DropDownItem } => ({
{ value: "planned", label: t("Planned") }, planned: { label: t("Planned"), value: "planned" },
{ value: "planted", label: t("Planted") }, planted: { label: t("Planted"), value: "planted" },
{ value: "sprouted", label: t("Sprouted") }, sprouted: { label: t("Sprouted"), value: "sprouted" },
{ value: "harvested", label: t("Harvested") }, 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. */ /** Change `planted_at` value based on `plant_stage` update. */
const getUpdateByPlantStage = (plant_stage: PlantStage): PlantOptions => { const getUpdateByPlantStage = (plant_stage: PlantStage): PlantOptions => {
const update: PlantOptions = { plant_stage }; const update: PlantOptions = { plant_stage };
@ -52,8 +39,8 @@ const getUpdateByPlantStage = (plant_stage: PlantStage): PlantOptions => {
export function EditPlantStatus(props: EditPlantStatusProps) { export function EditPlantStatus(props: EditPlantStatusProps) {
const { plantStatus, updatePlant, uuid } = props; const { plantStatus, updatePlant, uuid } = props;
return <FBSelect return <FBSelect
list={PLANT_STAGES} list={PLANT_STAGE_LIST()}
selectedItem={PLANT_STAGES_DDI[plantStatus]} selectedItem={PLANT_STAGE_DDI_LOOKUP()[plantStatus]}
onChange={ddi => onChange={ddi =>
updatePlant(uuid, getUpdateByPlantStage(ddi.value as PlantStage))} />; updatePlant(uuid, getUpdateByPlantStage(ddi.value as PlantStage))} />;
} }
@ -70,7 +57,7 @@ export const PlantStatusBulkUpdate = (props: PlantStatusBulkUpdateProps) =>
<p>{t("update plant status to")}</p> <p>{t("update plant status to")}</p>
<FBSelect <FBSelect
key={JSON.stringify(props.selected)} key={JSON.stringify(props.selected)}
list={PLANT_STAGES} list={PLANT_STAGE_LIST()}
selectedItem={undefined} selectedItem={undefined}
customNullLabel={t("Select a status")} customNullLabel={t("Select a status")}
onChange={ddi => { onChange={ddi => {

View File

@ -9,7 +9,6 @@ import {
AddEqCriteria, AddNumberCriteria, editCriteria, AddStringCriteria, AddEqCriteria, AddNumberCriteria, editCriteria, AddStringCriteria,
toggleStringCriteria, toggleStringCriteria,
POINTER_TYPE_LIST, POINTER_TYPE_LIST,
PLANT_STAGE_LIST
} from ".."; } from "..";
import { import {
AddEqCriteriaProps, NumberCriteriaProps, DEFAULT_CRITERIA, AddEqCriteriaProps, NumberCriteriaProps, DEFAULT_CRITERIA,
@ -19,6 +18,7 @@ import {
fakePointGroup fakePointGroup
} from "../../../../__test_support__/fake_state/resources"; } from "../../../../__test_support__/fake_state/resources";
import { PointGroup } from "farmbot/dist/resources/api_resources"; import { PointGroup } from "farmbot/dist/resources/api_resources";
import { PLANT_STAGE_LIST } from "../../../plants/edit_plant_status";
describe("<AddEqCriteria<string> />", () => { describe("<AddEqCriteria<string> />", () => {
const fakeProps = (): AddEqCriteriaProps<string> => ({ const fakeProps = (): AddEqCriteriaProps<string> => ({

View File

@ -10,6 +10,9 @@ import {
AddNumberCriteriaState, AddNumberCriteriaState,
AddStringCriteriaProps, AddStringCriteriaProps,
} from "./interfaces"; } from "./interfaces";
import {
PLANT_STAGE_DDI_LOOKUP, PLANT_STAGE_LIST
} from "../../plants/edit_plant_status";
export class AddEqCriteria<T extends string | number> export class AddEqCriteria<T extends string | number>
extends React.Component<AddEqCriteriaProps<T>, AddEqCriteriaState> { extends React.Component<AddEqCriteriaProps<T>, AddEqCriteriaState> {
@ -78,19 +81,6 @@ export const POINTER_TYPE_LIST = () => [
POINTER_TYPE_DDI_LOOKUP().ToolSlot, 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 export class AddStringCriteria
extends React.Component<AddStringCriteriaProps, AddEqCriteriaState> { extends React.Component<AddStringCriteriaProps, AddEqCriteriaState> {
state: AddEqCriteriaState = { key: "", value: "" }; state: AddEqCriteriaState = { key: "", value: "" };

View File

@ -3,7 +3,7 @@ import { cloneDeep, capitalize } from "lodash";
import { Row, Col, FBSelect, DropDownItem } from "../../../ui"; import { Row, Col, FBSelect, DropDownItem } from "../../../ui";
import { import {
AddEqCriteria, toggleEqCriteria, editCriteria, AddNumberCriteria, AddEqCriteria, toggleEqCriteria, editCriteria, AddNumberCriteria,
POINTER_TYPE_DDI_LOOKUP, PLANT_STAGE_DDI_LOOKUP, AddStringCriteria, POINTER_TYPE_DDI_LOOKUP, AddStringCriteria,
CRITERIA_TYPE_DDI_LOOKUP, toggleStringCriteria CRITERIA_TYPE_DDI_LOOKUP, toggleStringCriteria
} from "."; } from ".";
import { import {
@ -14,6 +14,7 @@ import {
} from "./interfaces"; } from "./interfaces";
import { t } from "../../../i18next_wrapper"; import { t } from "../../../i18next_wrapper";
import { PointGroup } from "farmbot/dist/resources/api_resources"; import { PointGroup } from "farmbot/dist/resources/api_resources";
import { PLANT_STAGE_DDI_LOOKUP } from "../../plants/edit_plant_status";
export class EqCriteriaSelection<T extends string | number> export class EqCriteriaSelection<T extends string | number>
extends React.Component<EqCriteriaSelectionProps<T>> { extends React.Component<EqCriteriaSelectionProps<T>> {

View File

@ -1,12 +1,5 @@
jest.mock("../../history", () => ({ history: { push: jest.fn() } })); 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"; import { fakeState } from "../../__test_support__/fake_state";
const mockState = fakeState(); const mockState = fakeState();
jest.mock("../../redux/store", () => ({ jest.mock("../../redux/store", () => ({
@ -46,7 +39,6 @@ describe("tourPageNavigation()", () => {
it("includes steps based on tool count", () => { it("includes steps based on tool count", () => {
const getTargets = () => const getTargets = () =>
Object.values(TOUR_STEPS()[Tours.gettingStarted]).map(t => t.target); Object.values(TOUR_STEPS()[Tours.gettingStarted]).map(t => t.target);
mockDev = false;
mockState.resources = buildResourceIndex([]); mockState.resources = buildResourceIndex([]);
expect(getTargets()).not.toContain(".tool-slots"); expect(getTargets()).not.toContain(".tool-slots");
mockState.resources = buildResourceIndex([fakeTool()]); mockState.resources = buildResourceIndex([fakeTool()]);
@ -56,7 +48,6 @@ describe("tourPageNavigation()", () => {
it("has correct content based on board version", () => { it("has correct content based on board version", () => {
const getTitles = () => const getTitles = () =>
Object.values(TOUR_STEPS()[Tours.gettingStarted]).map(t => t.title); Object.values(TOUR_STEPS()[Tours.gettingStarted]).map(t => t.title);
mockDev = false;
mockState.resources = buildResourceIndex([]); mockState.resources = buildResourceIndex([]);
expect(getTitles()).toContain("Add tools and slots"); expect(getTitles()).toContain("Add tools and slots");
expect(getTitles()).not.toContain("Add seed containers"); expect(getTitles()).not.toContain("Add seed containers");
@ -69,13 +60,4 @@ describe("tourPageNavigation()", () => {
expect(getTitles()).not.toContain("Add seed containers and slots"); expect(getTitles()).not.toContain("Add seed containers and slots");
expect(getTitles()).toContain("Add seed containers"); 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");
});
}); });

View File

@ -2,7 +2,6 @@ import { history } from "../history";
import { Step as TourStep } from "react-joyride"; import { Step as TourStep } from "react-joyride";
import { TourContent } from "../constants"; import { TourContent } from "../constants";
import { t } from "../i18next_wrapper"; import { t } from "../i18next_wrapper";
import { DevSettings } from "../account/dev/dev_support";
import { selectAllTools } from "../resources/selectors"; import { selectAllTools } from "../resources/selectors";
import { store } from "../redux/store"; import { store } from "../redux/store";
import { getFbosConfig } from "../resources/getters"; import { getFbosConfig } from "../resources/getters";
@ -64,16 +63,8 @@ export const TOUR_STEPS = (): { [x: string]: TourStep[] } => ({
content: t(TourContent.ADD_PLANTS), content: t(TourContent.ADD_PLANTS),
title: t("Add plants"), title: t("Add plants"),
}, },
...(DevSettings.futureFeaturesEnabled() ? [{ ...toolsStep(),
target: ".tool-list", ...toolSlotsStep(),
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()),
{ {
target: ".peripherals-widget", target: ".peripherals-widget",
content: t(TourContent.ADD_PERIPHERALS), content: t(TourContent.ADD_PERIPHERALS),

View File

@ -3,11 +3,6 @@ jest.mock("../../history", () => ({
getPathArray: jest.fn(() => mockPath.split("/")), getPathArray: jest.fn(() => mockPath.split("/")),
})); }));
let mockDev = false;
jest.mock("../../account/dev/dev_support", () => ({
DevSettings: { futureFeaturesEnabled: () => mockDev }
}));
import * as React from "react"; import * as React from "react";
import { shallow, mount } from "enzyme"; import { shallow, mount } from "enzyme";
import { NavLinks } from "../nav_links"; import { NavLinks } from "../nav_links";
@ -28,7 +23,6 @@ describe("<NavLinks />", () => {
}); });
it("shows links", () => { it("shows links", () => {
mockDev = false;
const wrapper = mount(<NavLinks close={jest.fn()} alertCount={1} />); const wrapper = mount(<NavLinks close={jest.fn()} alertCount={1} />);
expect(wrapper.text().toLowerCase()).not.toContain("tools"); expect(wrapper.text().toLowerCase()).not.toContain("tools");
}); });

View File

@ -7,7 +7,6 @@ import {
import { Link } from "../link"; import { Link } from "../link";
import { t } from "../i18next_wrapper"; import { t } from "../i18next_wrapper";
import { betterCompact } from "../util"; 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. */ /** Uses a slug and a child path to compute the `href` of a navbar link. */
export type LinkComputeFn = (slug: string, childPath: string) => string; 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", name: "Regimens", icon: "calendar-check-o", slug: "regimens",
computeHref: computeEditorUrlFromState("Regimen") computeHref: computeEditorUrlFromState("Regimen")
}, },
!DevSettings.futureFeaturesEnabled() ? undefined :
{ name: "Tools", icon: "wrench", slug: "tools" },
{ {
name: "Farmware", icon: "crosshairs", slug: "farmware", name: "Farmware", icon: "crosshairs", slug: "farmware",
computeHref: computeFarmwareUrlFromState computeHref: computeFarmwareUrlFromState