cleanup and refactoring
parent
a49e5e67ba
commit
edb96d3ca8
|
@ -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}
|
||||||
|
|
|
@ -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);
|
||||||
});
|
});
|
||||||
|
|
|
@ -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>;
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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)} />;
|
||||||
|
}
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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();
|
||||||
|
|
|
@ -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");
|
||||||
});
|
});
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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)}
|
||||||
|
|
|
@ -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"}
|
||||||
|
|
|
@ -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 => {
|
||||||
|
|
|
@ -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> => ({
|
||||||
|
|
|
@ -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: "" };
|
||||||
|
|
|
@ -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>> {
|
||||||
|
|
|
@ -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");
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|
|
@ -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),
|
||||||
|
|
|
@ -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");
|
||||||
});
|
});
|
||||||
|
|
|
@ -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
|
||||||
|
|
Loading…
Reference in New Issue