Added weed_detector to WebAppConfigs table. 50% done converting `keyof`s
parent
584ef721e2
commit
9d41909632
|
@ -0,0 +1,8 @@
|
|||
class AddWeedDetectorToWebAppConfig < ActiveRecord::Migration[5.1]
|
||||
def change
|
||||
add_column :web_app_configs,
|
||||
:weed_detector,
|
||||
:boolean,
|
||||
default: false
|
||||
end
|
||||
end
|
|
@ -10,7 +10,7 @@
|
|||
#
|
||||
# It's strongly recommended that you check this file into your version control system.
|
||||
|
||||
ActiveRecord::Schema.define(version: 20180105175215) do
|
||||
ActiveRecord::Schema.define(version: 20180109070610) do
|
||||
|
||||
# These are extensions that must be enabled in order to support this database
|
||||
enable_extension "plpgsql"
|
||||
|
@ -354,6 +354,7 @@ ActiveRecord::Schema.define(version: 20180105175215) do
|
|||
t.integer "fun_log", default: 1
|
||||
t.integer "debug_log", default: 1
|
||||
t.integer "successs_log", default: 1
|
||||
t.boolean "weed_detector", default: false
|
||||
t.index ["device_id"], name: "index_web_app_configs_on_device_id"
|
||||
end
|
||||
|
||||
|
|
|
@ -19,7 +19,7 @@ import { BooleanSetting } from "../session_keys";
|
|||
|
||||
describe("<LoadingPlant/>", () => {
|
||||
it("renders loading text", () => {
|
||||
mockStorj[BooleanSetting.disableAnimations] = true;
|
||||
mockStorj[BooleanSetting.disable_animations] = true;
|
||||
const wrapper = shallow(<LoadingPlant />);
|
||||
expect(wrapper.find(".loading-plant").length).toEqual(0);
|
||||
expect(wrapper.find(".loading-plant-text").props().y).toEqual(150);
|
||||
|
@ -28,7 +28,7 @@ describe("<LoadingPlant/>", () => {
|
|||
});
|
||||
|
||||
it("renders loading animation", () => {
|
||||
mockStorj[BooleanSetting.disableAnimations] = false;
|
||||
mockStorj[BooleanSetting.disable_animations] = false;
|
||||
const wrapper = shallow(<LoadingPlant />);
|
||||
expect(wrapper.find(".loading-plant")).toBeTruthy();
|
||||
const circleProps = wrapper.find(".loading-plant-circle").props();
|
||||
|
|
|
@ -26,7 +26,7 @@ describe("maybeToggleFeature()", () => {
|
|||
name: "Example",
|
||||
value: false,
|
||||
description: "I stub this.",
|
||||
storageKey: BooleanSetting.weedDetector,
|
||||
storageKey: BooleanSetting.weed_detector,
|
||||
experimental: true
|
||||
};
|
||||
const out = maybeToggleFeature(data);
|
||||
|
@ -39,9 +39,9 @@ describe("maybeToggleFeature()", () => {
|
|||
(global as any).confirm = () => true;
|
||||
const data: LabsFeature = {
|
||||
name: "Example1",
|
||||
value: (mockStorj[BooleanSetting.weedDetector] = false),
|
||||
value: (mockStorj[BooleanSetting.weed_detector] = false),
|
||||
description: "I stub this.",
|
||||
storageKey: BooleanSetting.weedDetector,
|
||||
storageKey: BooleanSetting.weed_detector,
|
||||
experimental: true
|
||||
};
|
||||
const out = maybeToggleFeature(data);
|
||||
|
@ -55,9 +55,9 @@ describe("maybeToggleFeature()", () => {
|
|||
Object.defineProperty(global, "confirm", conf);
|
||||
const output = maybeToggleFeature({
|
||||
name: "Example",
|
||||
value: (mockStorj[BooleanSetting.weedDetector] = true),
|
||||
value: (mockStorj[BooleanSetting.weed_detector] = true),
|
||||
description: "I stub this.",
|
||||
storageKey: BooleanSetting.weedDetector,
|
||||
storageKey: BooleanSetting.weed_detector,
|
||||
experimental: true
|
||||
});
|
||||
expect(conf).not.toHaveBeenCalled();
|
||||
|
@ -68,9 +68,9 @@ describe("maybeToggleFeature()", () => {
|
|||
it("updates a `LabsFeature` when consent is not required", () => {
|
||||
const data: LabsFeature = {
|
||||
name: "Example1",
|
||||
value: (mockStorj[BooleanSetting.weedDetector] = false),
|
||||
value: (mockStorj[BooleanSetting.weed_detector] = false),
|
||||
description: "I stub this.",
|
||||
storageKey: BooleanSetting.weedDetector
|
||||
storageKey: BooleanSetting.weed_detector
|
||||
};
|
||||
const out = maybeToggleFeature(data);
|
||||
out ?
|
||||
|
|
|
@ -1,14 +1,15 @@
|
|||
import { Content } from "../../constants";
|
||||
import { Session } from "../../session";
|
||||
import { BooleanSetting } from "../../session_keys";
|
||||
import { trim } from "../../util";
|
||||
import { t } from "i18next";
|
||||
import { BooleanConfigKey } from "../../config_storage/web_app_configs";
|
||||
import { BooleanSetting } from "../../session_keys";
|
||||
|
||||
export interface LabsFeature {
|
||||
name: string;
|
||||
description: string;
|
||||
/** Entry for localStorage. Must be unique. */
|
||||
storageKey: BooleanSetting;
|
||||
storageKey: BooleanConfigKey;
|
||||
value: boolean;
|
||||
experimental?: boolean;
|
||||
displayInvert?: boolean;
|
||||
|
@ -21,7 +22,7 @@ export const fetchLabFeatures = (): LabsFeature[] => ([
|
|||
{
|
||||
name: t("Internationalize Web App"),
|
||||
description: t("Turn off to set Web App to English."),
|
||||
storageKey: BooleanSetting.disableI18n,
|
||||
storageKey: BooleanSetting.disable_i18n,
|
||||
value: false,
|
||||
displayInvert: true,
|
||||
callback: () => window.location.reload()
|
||||
|
@ -30,14 +31,14 @@ export const fetchLabFeatures = (): LabsFeature[] => ([
|
|||
name: t("Confirm Sequence step deletion"),
|
||||
description: trim(t(`Show a confirmation dialog when the sequence delete step
|
||||
icon is pressed.`)),
|
||||
storageKey: BooleanSetting.confirmStepDeletion,
|
||||
storageKey: BooleanSetting.confirm_step_deletion,
|
||||
value: false
|
||||
},
|
||||
{
|
||||
name: t("Hide Webcam widget"),
|
||||
description: trim(t(`If not using a webcam, use this setting to remove the
|
||||
widget from the Controls page.`)),
|
||||
storageKey: BooleanSetting.hideWebcamWidget,
|
||||
storageKey: BooleanSetting.hide_webcam_widget,
|
||||
value: false
|
||||
},
|
||||
{
|
||||
|
@ -45,20 +46,20 @@ export const fetchLabFeatures = (): LabsFeature[] => ([
|
|||
description: trim(t(`Change the Farm Designer map size based on axis length.
|
||||
A value must be input in AXIS LENGTH and STOP AT MAX must be enabled in
|
||||
the HARDWARE widget.`)),
|
||||
storageKey: BooleanSetting.dynamicMap,
|
||||
storageKey: BooleanSetting.dynamic_map,
|
||||
value: false
|
||||
},
|
||||
{
|
||||
name: t("Double default map dimensions"),
|
||||
description: trim(t(`Double the default dimensions of the Farm Designer map
|
||||
for a map with four times the area.`)),
|
||||
storageKey: BooleanSetting.mapXL,
|
||||
storageKey: BooleanSetting.map_xl,
|
||||
value: false
|
||||
},
|
||||
{
|
||||
name: t("Display plant animations"),
|
||||
description: trim(t(`Enable plant animations in the Farm Designer.`)),
|
||||
storageKey: BooleanSetting.disableAnimations,
|
||||
storageKey: BooleanSetting.disable_animations,
|
||||
value: false,
|
||||
displayInvert: true
|
||||
}
|
||||
|
@ -75,7 +76,7 @@ export const maybeToggleFeature =
|
|||
};
|
||||
|
||||
/** Stub this when testing if need be. */
|
||||
const fetchVal = (k: BooleanSetting) => !!Session.getBool(k);
|
||||
const fetchVal = (k: BooleanConfigKey) => !!Session.getBool(k);
|
||||
|
||||
/** Takes a `LabFeature` (probably one with an uninitialized fallback / default
|
||||
* value) and sets it to the _real_ value that's in localStorage. */
|
||||
|
|
|
@ -38,6 +38,7 @@ export interface WebAppConfig {
|
|||
fun_log: number;
|
||||
debug_log: number;
|
||||
successs_log: number;
|
||||
weed_detector: boolean;
|
||||
}
|
||||
|
||||
export type NumberConfigKey = "id"
|
||||
|
@ -73,4 +74,5 @@ export type BooleanConfigKey = "confirm_step_deletion"
|
|||
|"show_points"
|
||||
|"x_axis_inverted"
|
||||
|"y_axis_inverted"
|
||||
|"z_axis_inverted";
|
||||
|"z_axis_inverted"
|
||||
|"weed_detector";
|
||||
|
|
|
@ -38,7 +38,7 @@ describe("<Controls />", () => {
|
|||
}
|
||||
|
||||
it("shows webcam widget", () => {
|
||||
mockStorj[BooleanSetting.hideWebcamWidget] = false;
|
||||
mockStorj[BooleanSetting.hide_webcam_widget] = false;
|
||||
const wrapper = mount(<Controls {...fakeProps() } />);
|
||||
const txt = wrapper.text().toLowerCase();
|
||||
["webcam", "move", "peripherals"]
|
||||
|
@ -46,7 +46,7 @@ describe("<Controls />", () => {
|
|||
});
|
||||
|
||||
it("hides webcam widget", () => {
|
||||
mockStorj[BooleanSetting.hideWebcamWidget] = true;
|
||||
mockStorj[BooleanSetting.hide_webcam_widget] = true;
|
||||
const wrapper = mount(<Controls {...fakeProps() } />);
|
||||
const txt = wrapper.text().toLowerCase();
|
||||
["move", "peripherals"].map(string => expect(txt).toContain(string));
|
||||
|
|
|
@ -20,7 +20,7 @@ export class Controls extends React.Component<Props, {}> {
|
|||
.hardware
|
||||
.informational_settings
|
||||
.busy;
|
||||
const showWebcamWidget = !Session.getBool(BooleanSetting.hideWebcamWidget);
|
||||
const showWebcamWidget = !Session.getBool(BooleanSetting.hide_webcam_widget);
|
||||
return <Page className="controls">
|
||||
{showWebcamWidget
|
||||
?
|
||||
|
|
|
@ -9,6 +9,7 @@ import { maybeNegateStatus, maybeNegateConsistency } from "../connectivity/maybe
|
|||
import { EdgeStatus } from "../connectivity/interfaces";
|
||||
import { ReduxAction } from "../redux/interfaces";
|
||||
import { connectivityReducer } from "../connectivity/reducer";
|
||||
import { BooleanConfigKey } from "../config_storage/web_app_configs";
|
||||
|
||||
const afterEach = (state: BotState, a: ReduxAction<{}>) => {
|
||||
state.connectivity = connectivityReducer(state.connectivity, a);
|
||||
|
@ -85,13 +86,13 @@ export let initialState = (): BotState => ({
|
|||
currentOSVersion: undefined,
|
||||
currentFWVersion: undefined,
|
||||
axis_inversion: {
|
||||
x: !!Session.getBool(BooleanSetting.xAxisInverted),
|
||||
y: !!Session.getBool(BooleanSetting.yAxisInverted),
|
||||
z: !!Session.getBool(BooleanSetting.zAxisInverted),
|
||||
x: !!Session.getBool(BooleanSetting.x_axis_inverted),
|
||||
y: !!Session.getBool(BooleanSetting.y_axis_inverted),
|
||||
z: !!Session.getBool(BooleanSetting.z_axis_inverted),
|
||||
},
|
||||
encoder_visibility: {
|
||||
raw_encoders: !!Session.getBool(BooleanSetting.rawEncoders),
|
||||
scaled_encoders: !!Session.getBool(BooleanSetting.scaledEncoders),
|
||||
raw_encoders: !!Session.getBool(BooleanSetting.raw_encoders),
|
||||
scaled_encoders: !!Session.getBool(BooleanSetting.scaled_encoders),
|
||||
},
|
||||
connectivity: {
|
||||
"bot.mqtt": undefined,
|
||||
|
@ -101,17 +102,17 @@ export let initialState = (): BotState => ({
|
|||
});
|
||||
|
||||
/** Translate X/Y/Z to the name that is used in `localStorage` */
|
||||
export const INVERSION_MAPPING: Record<Xyz, BooleanSetting> = {
|
||||
x: BooleanSetting.xAxisInverted,
|
||||
y: BooleanSetting.yAxisInverted,
|
||||
z: BooleanSetting.zAxisInverted,
|
||||
export const INVERSION_MAPPING: Record<Xyz, BooleanConfigKey> = {
|
||||
x: BooleanSetting.x_axis_inverted,
|
||||
y: BooleanSetting.y_axis_inverted,
|
||||
z: BooleanSetting.z_axis_inverted,
|
||||
};
|
||||
|
||||
/** Translate `encode_visibility` key name to the name that is
|
||||
* used in `localStorage` */
|
||||
export const ENCODER_MAPPING: Record<EncoderDisplay, BooleanSetting> = {
|
||||
raw_encoders: BooleanSetting.rawEncoders,
|
||||
scaled_encoders: BooleanSetting.scaledEncoders,
|
||||
export const ENCODER_MAPPING: Record<EncoderDisplay, BooleanConfigKey> = {
|
||||
raw_encoders: BooleanSetting.raw_encoders,
|
||||
scaled_encoders: BooleanSetting.scaled_encoders,
|
||||
};
|
||||
|
||||
export let botReducer = generateReducer<BotState>(initialState(), afterEach)
|
||||
|
|
|
@ -22,7 +22,7 @@ describe("getDefaultAxisLength()", () => {
|
|||
});
|
||||
|
||||
it("returns XL axis lengths", () => {
|
||||
mockStorj[BooleanSetting.mapXL] = true;
|
||||
mockStorj[BooleanSetting.map_xl] = true;
|
||||
const axes = getDefaultAxisLength();
|
||||
expect(axes).toEqual({ x: 5900, y: 2900 });
|
||||
});
|
||||
|
@ -30,7 +30,7 @@ describe("getDefaultAxisLength()", () => {
|
|||
|
||||
describe("getGridSize()", () => {
|
||||
it("returns default grid size", () => {
|
||||
mockStorj[BooleanSetting.mapXL] = false;
|
||||
mockStorj[BooleanSetting.map_xl] = false;
|
||||
const grid = getGridSize({
|
||||
x: { value: 100, isDefault: false },
|
||||
y: { value: 200, isDefault: false }
|
||||
|
@ -39,7 +39,7 @@ describe("getGridSize()", () => {
|
|||
});
|
||||
|
||||
it("returns XL grid size", () => {
|
||||
mockStorj[BooleanSetting.mapXL] = true;
|
||||
mockStorj[BooleanSetting.map_xl] = true;
|
||||
const grid = getGridSize({
|
||||
x: { value: 100, isDefault: false },
|
||||
y: { value: 200, isDefault: false }
|
||||
|
@ -48,7 +48,7 @@ describe("getGridSize()", () => {
|
|||
});
|
||||
|
||||
it("returns grid size using bot size", () => {
|
||||
mockStorj[BooleanSetting.dynamicMap] = true;
|
||||
mockStorj[BooleanSetting.dynamic_map] = true;
|
||||
const grid = getGridSize({
|
||||
x: { value: 100, isDefault: false },
|
||||
y: { value: 200, isDefault: false }
|
||||
|
|
|
@ -16,7 +16,7 @@ import { getBotSize } from "./map/util";
|
|||
import { catchErrors } from "../util";
|
||||
|
||||
export const getDefaultAxisLength = (): AxisNumberProperty => {
|
||||
if (Session.getBool(BooleanSetting.mapXL)) {
|
||||
if (Session.getBool(BooleanSetting.map_xl)) {
|
||||
return { x: 5900, y: 2900 };
|
||||
} else {
|
||||
return { x: 2900, y: 1400 };
|
||||
|
@ -24,7 +24,7 @@ export const getDefaultAxisLength = (): AxisNumberProperty => {
|
|||
};
|
||||
|
||||
export const getGridSize = (botSize: BotSize) => {
|
||||
if (Session.getBool(BooleanSetting.dynamicMap)) {
|
||||
if (Session.getBool(BooleanSetting.dynamic_map)) {
|
||||
// Render the map size according to device axis length.
|
||||
return { x: botSize.x.value, y: botSize.y.value };
|
||||
}
|
||||
|
@ -38,7 +38,7 @@ export const gridOffset: AxisNumberProperty = { x: 50, y: 50 };
|
|||
export class FarmDesigner extends React.Component<Props, Partial<State>> {
|
||||
componentDidCatch(x: Error, y: React.ErrorInfo) { catchErrors(x, y); }
|
||||
|
||||
initializeSetting = (name: keyof State, defaultValue: boolean): boolean => {
|
||||
initializeSetting = (name: (keyof State), defaultValue: boolean): boolean => {
|
||||
const currentValue = Session.getBool(safeBooleanSettting(name));
|
||||
if (isUndefined(currentValue)) {
|
||||
Session.setBool(safeBooleanSettting(name), defaultValue);
|
||||
|
@ -49,26 +49,26 @@ export class FarmDesigner extends React.Component<Props, Partial<State>> {
|
|||
}
|
||||
|
||||
getBotOriginQuadrant = (): BotOriginQuadrant => {
|
||||
const value = Session.getNum(NumericSetting.botOriginQuadrant);
|
||||
const value = Session.getNum(NumericSetting.bot_origin_quadrant);
|
||||
return isBotOriginQuadrant(value) ? value : 2;
|
||||
}
|
||||
|
||||
getZoomLevel = (): number => {
|
||||
return Session.getNum(NumericSetting.zoomLevel) || 1;
|
||||
return Session.getNum(NumericSetting.zoom_level) || 1;
|
||||
}
|
||||
|
||||
state: State = {
|
||||
legendMenuOpen: this.initializeSetting(BooleanSetting.legendMenuOpen, false),
|
||||
showPlants: this.initializeSetting(BooleanSetting.showPlants, true),
|
||||
showPoints: this.initializeSetting(BooleanSetting.showPoints, true),
|
||||
showSpread: this.initializeSetting(BooleanSetting.showSpread, false),
|
||||
showFarmbot: this.initializeSetting(BooleanSetting.showFarmbot, true),
|
||||
botOriginQuadrant: this.getBotOriginQuadrant(),
|
||||
zoomLevel: this.getZoomLevel()
|
||||
legend_menu_open: this.initializeSetting(BooleanSetting.legend_menu_open, false),
|
||||
show_plants: this.initializeSetting(BooleanSetting.show_plants, true),
|
||||
show_points: this.initializeSetting(BooleanSetting.show_points, true),
|
||||
show_spread: this.initializeSetting(BooleanSetting.show_spread, false),
|
||||
show_farmbot: this.initializeSetting(BooleanSetting.show_farmbot, true),
|
||||
bot_origin_quadrant: this.getBotOriginQuadrant(),
|
||||
zoom_level: this.getZoomLevel()
|
||||
};
|
||||
|
||||
componentDidMount() {
|
||||
this.updateBotOriginQuadrant(this.state.botOriginQuadrant)();
|
||||
this.updateBotOriginQuadrant(this.state.bot_origin_quadrant)();
|
||||
this.updateZoomLevel(0)();
|
||||
}
|
||||
|
||||
|
@ -78,14 +78,14 @@ export class FarmDesigner extends React.Component<Props, Partial<State>> {
|
|||
}
|
||||
|
||||
updateBotOriginQuadrant = (payload: BotOriginQuadrant) => () => {
|
||||
this.setState({ botOriginQuadrant: payload });
|
||||
Session.setNum(NumericSetting.botOriginQuadrant, payload);
|
||||
this.setState({ bot_origin_quadrant: payload });
|
||||
Session.setNum(NumericSetting.bot_origin_quadrant, payload);
|
||||
}
|
||||
|
||||
updateZoomLevel = (zoomIncrement: number) => () => {
|
||||
const payload = Math.round((this.getZoomLevel() + zoomIncrement) * 10) / 10;
|
||||
this.setState({ zoomLevel: payload });
|
||||
Session.setNum(NumericSetting.zoomLevel, payload);
|
||||
this.setState({ zoom_level: payload });
|
||||
Session.setNum(NumericSetting.zoom_level, payload);
|
||||
}
|
||||
|
||||
childComponent(props: Props) {
|
||||
|
@ -106,13 +106,13 @@ export class FarmDesigner extends React.Component<Props, Partial<State>> {
|
|||
}
|
||||
|
||||
const {
|
||||
legendMenuOpen,
|
||||
showPlants,
|
||||
showPoints,
|
||||
showSpread,
|
||||
showFarmbot,
|
||||
botOriginQuadrant,
|
||||
zoomLevel
|
||||
legend_menu_open,
|
||||
show_plants,
|
||||
show_points,
|
||||
show_spread,
|
||||
show_farmbot,
|
||||
bot_origin_quadrant,
|
||||
zoom_level
|
||||
} = this.state;
|
||||
|
||||
const designerTabClasses: string[] = ["active", "visible-xs"];
|
||||
|
@ -131,13 +131,13 @@ export class FarmDesigner extends React.Component<Props, Partial<State>> {
|
|||
zoom={this.updateZoomLevel}
|
||||
toggle={this.toggle}
|
||||
updateBotOriginQuadrant={this.updateBotOriginQuadrant}
|
||||
botOriginQuadrant={botOriginQuadrant}
|
||||
zoomLvl={zoomLevel}
|
||||
legendMenuOpen={legendMenuOpen}
|
||||
showPlants={showPlants}
|
||||
showPoints={showPoints}
|
||||
showSpread={showSpread}
|
||||
showFarmbot={showFarmbot} />
|
||||
bot_origin_quadrant={bot_origin_quadrant}
|
||||
zoomLvl={zoom_level}
|
||||
legendMenuOpen={legend_menu_open}
|
||||
showPlants={show_plants}
|
||||
showPoints={show_points}
|
||||
showSpread={show_spread}
|
||||
showFarmbot={show_farmbot} />
|
||||
|
||||
<div className="panel-header gray-panel designer-nav">
|
||||
<div className="panel-tabs">
|
||||
|
@ -158,12 +158,12 @@ export class FarmDesigner extends React.Component<Props, Partial<State>> {
|
|||
|
||||
<div
|
||||
className="farm-designer-map"
|
||||
style={{ zoom: zoomLevel }}>
|
||||
style={{ zoom: zoom_level }}>
|
||||
<GardenMap
|
||||
showPoints={showPoints}
|
||||
showPlants={showPlants}
|
||||
showSpread={showSpread}
|
||||
showFarmbot={showFarmbot}
|
||||
showPoints={show_points}
|
||||
showPlants={show_plants}
|
||||
showSpread={show_spread}
|
||||
showFarmbot={show_farmbot}
|
||||
selectedPlant={this.props.selectedPlant}
|
||||
crops={this.props.crops}
|
||||
dispatch={this.props.dispatch}
|
||||
|
@ -175,8 +175,8 @@ export class FarmDesigner extends React.Component<Props, Partial<State>> {
|
|||
botSize={botSize}
|
||||
stopAtHome={stopAtHome}
|
||||
hoveredPlant={this.props.hoveredPlant}
|
||||
zoomLvl={zoomLevel}
|
||||
botOriginQuadrant={botOriginQuadrant}
|
||||
zoomLvl={zoom_level}
|
||||
bot_origin_quadrant={bot_origin_quadrant}
|
||||
gridSize={getGridSize(botSize)}
|
||||
gridOffset={gridOffset}
|
||||
peripherals={this.props.peripherals}
|
||||
|
|
|
@ -28,13 +28,13 @@ export function isBotOriginQuadrant(mystery: Mystery):
|
|||
}
|
||||
|
||||
export interface State {
|
||||
legendMenuOpen: boolean;
|
||||
showPlants: boolean;
|
||||
showPoints: boolean;
|
||||
showSpread: boolean;
|
||||
showFarmbot: boolean;
|
||||
botOriginQuadrant: BotOriginQuadrant;
|
||||
zoomLevel: number;
|
||||
legend_menu_open: boolean;
|
||||
show_plants: boolean;
|
||||
show_points: boolean;
|
||||
show_spread: boolean;
|
||||
show_farmbot: boolean;
|
||||
bot_origin_quadrant: BotOriginQuadrant;
|
||||
zoom_level: number;
|
||||
}
|
||||
|
||||
export interface Props {
|
||||
|
|
|
@ -36,7 +36,7 @@ describe("<GardenPlant/>", () => {
|
|||
}
|
||||
|
||||
it("renders plant", () => {
|
||||
mockStorj[BooleanSetting.disableAnimations] = true;
|
||||
mockStorj[BooleanSetting.disable_animations] = true;
|
||||
const wrapper = shallow(<GardenPlant {...fakeProps() } />);
|
||||
expect(wrapper.find("image").length).toEqual(1);
|
||||
expect(wrapper.find("image").props().opacity).toEqual(1);
|
||||
|
@ -47,7 +47,7 @@ describe("<GardenPlant/>", () => {
|
|||
});
|
||||
|
||||
it("renders plant animations", () => {
|
||||
mockStorj[BooleanSetting.disableAnimations] = false;
|
||||
mockStorj[BooleanSetting.disable_animations] = false;
|
||||
const wrapper = shallow(<GardenPlant {...fakeProps() } />);
|
||||
expect(wrapper.find(".soil-cloud").length).toEqual(1);
|
||||
expect(wrapper.find(".animate").length).toEqual(1);
|
||||
|
|
|
@ -38,7 +38,7 @@ export class GardenPlant extends
|
|||
|
||||
const { qx, qy } = getXYFromQuadrant(round(x), round(y), quadrant, gridSize);
|
||||
const alpha = dragging ? 0.4 : 1.0;
|
||||
const animate = !Session.getBool(BooleanSetting.disableAnimations);
|
||||
const animate = !Session.getBool(BooleanSetting.disable_animations);
|
||||
|
||||
return <g id={"plant-" + id}>
|
||||
|
||||
|
|
|
@ -47,7 +47,7 @@ export class HoveredPlantLayer extends
|
|||
const hovered = !!this.props.designer.hoveredPlant.icon;
|
||||
const scaledRadius = currentPlant ? radius : radius * 1.2;
|
||||
const alpha = dragging ? 0.4 : 1.0;
|
||||
const animate = !Session.getBool(BooleanSetting.disableAnimations);
|
||||
const animate = !Session.getBool(BooleanSetting.disable_animations);
|
||||
|
||||
return <g id="hovered-plant-layer">
|
||||
{this.props.visible && hovered &&
|
||||
|
|
|
@ -84,7 +84,7 @@ export class SpreadCircle extends
|
|||
const { selected, mapTransformProps } = this.props;
|
||||
const { quadrant, gridSize } = mapTransformProps;
|
||||
const { qx, qy } = getXYFromQuadrant(round(x), round(y), quadrant, gridSize);
|
||||
const animate = !Session.getBool(BooleanSetting.disableAnimations);
|
||||
const animate = !Session.getBool(BooleanSetting.disable_animations);
|
||||
|
||||
return <g id={"spread-" + id}>
|
||||
{!selected &&
|
||||
|
|
|
@ -41,11 +41,11 @@ describe("<BotPeripherals/>", () => {
|
|||
|
||||
function animationToggle(
|
||||
props: BotPeripheralsProps, enabled: number, disabled: number) {
|
||||
mockStorj[BooleanSetting.disableAnimations] = false;
|
||||
mockStorj[BooleanSetting.disable_animations] = false;
|
||||
const wrapperEnabled = shallow(<BotPeripherals {...props } />);
|
||||
expect(wrapperEnabled.find("use").length).toEqual(enabled);
|
||||
|
||||
mockStorj[BooleanSetting.disableAnimations] = true;
|
||||
mockStorj[BooleanSetting.disable_animations] = true;
|
||||
const wrapperDisabled = shallow(<BotPeripherals {...props } />);
|
||||
expect(wrapperDisabled.find("use").length).toEqual(disabled);
|
||||
}
|
||||
|
|
|
@ -44,7 +44,7 @@ function waterFigure(
|
|||
props: { i: number, cx: number, cy: number }) {
|
||||
const { i, cx, cy } = props;
|
||||
const color = "rgb(11, 83, 148)";
|
||||
const animate = !Session.getBool(BooleanSetting.disableAnimations);
|
||||
const animate = !Session.getBool(BooleanSetting.disable_animations);
|
||||
const copies = animate ? 3 : 1;
|
||||
const animateClass = animate ? "animate" : "";
|
||||
|
||||
|
@ -85,7 +85,7 @@ function vacuumFigure(
|
|||
props: { i: number, cx: number, cy: number }) {
|
||||
const { i, cx, cy } = props;
|
||||
const color = "black";
|
||||
const animate = !Session.getBool(BooleanSetting.disableAnimations);
|
||||
const animate = !Session.getBool(BooleanSetting.disable_animations);
|
||||
const copies = animate ? 3 : 1;
|
||||
const animateClass = animate ? "animate" : "";
|
||||
|
||||
|
|
|
@ -10,8 +10,8 @@ export function VirtualFarmBot(props: VirtualFarmBotProps) {
|
|||
const {
|
||||
mapTransformProps, plantAreaOffset, peripherals, eStopStatus
|
||||
} = props;
|
||||
const displayTrail = Session.getBool(BooleanSetting.displayTrail);
|
||||
const encoderFigure = Session.getBool(BooleanSetting.encoderFigure);
|
||||
const displayTrail = Session.getBool(BooleanSetting.display_trail);
|
||||
const encoderFigure = Session.getBool(BooleanSetting.encoder_figure);
|
||||
|
||||
return <g id="virtual-farmbot">
|
||||
<BotPeripherals
|
||||
|
|
|
@ -18,7 +18,7 @@ export function getUserLang(langCode = "en_us") {
|
|||
|
||||
export function generateI18nConfig(lang: string): InitOptions {
|
||||
// NOTE: Some users prefer English over i18nized version.
|
||||
const choice = Session.getBool(BooleanSetting.disableI18n) ? "en" : lang;
|
||||
const choice = Session.getBool(BooleanSetting.disable_i18n) ? "en" : lang;
|
||||
const langi = require("../public/app-resources/languages/" + choice + ".js");
|
||||
|
||||
return {
|
||||
|
|
|
@ -3,7 +3,7 @@ import { Session } from "./session";
|
|||
import { BooleanSetting } from "./session_keys";
|
||||
|
||||
export function LoadingPlant() {
|
||||
const animations = !Session.getBool(BooleanSetting.disableAnimations);
|
||||
const animations = !Session.getBool(BooleanSetting.disable_animations);
|
||||
return <div className="loading-plant-div-container">
|
||||
<svg width="300px" height="500px">
|
||||
{animations &&
|
||||
|
|
|
@ -104,7 +104,7 @@ describe("<Logs />", () => {
|
|||
});
|
||||
|
||||
it("loads filter setting", () => {
|
||||
mockStorj[NumericSetting.warnLog] = 3;
|
||||
mockStorj[NumericSetting.warn_log] = 3;
|
||||
const wrapper = mount(<Logs logs={fakeLogs()} bot={bot} timeOffset={0} />);
|
||||
expect(wrapper.state().warn).toEqual(3);
|
||||
});
|
||||
|
@ -120,7 +120,7 @@ describe("<Logs />", () => {
|
|||
});
|
||||
|
||||
it("toggles filter", () => {
|
||||
mockStorj[NumericSetting.warnLog] = 3;
|
||||
mockStorj[NumericSetting.warn_log] = 3;
|
||||
const wrapper = mount(<Logs logs={fakeLogs()} bot={bot} timeOffset={0} />);
|
||||
// tslint:disable-next-line:no-any
|
||||
const instance = wrapper.instance() as any;
|
||||
|
@ -132,7 +132,7 @@ describe("<Logs />", () => {
|
|||
});
|
||||
|
||||
it("sets filter", () => {
|
||||
mockStorj[NumericSetting.warnLog] = 3;
|
||||
mockStorj[NumericSetting.warn_log] = 3;
|
||||
const wrapper = mount(<Logs logs={fakeLogs()} bot={bot} timeOffset={0} />);
|
||||
// tslint:disable-next-line:no-any
|
||||
const instance = wrapper.instance() as any;
|
||||
|
|
|
@ -67,11 +67,11 @@ describe("<LogsSettingsMenu />", () => {
|
|||
const setFilterLevel = jest.fn();
|
||||
const wrapper = mount(<LogsSettingsMenu
|
||||
bot={bot} setFilterLevel={() => setFilterLevel} />);
|
||||
mockStorj[NumericSetting.busyLog] = 0;
|
||||
mockStorj[NumericSetting.busy_log] = 0;
|
||||
wrapper.find("button").at(0).simulate("click");
|
||||
expect(setFilterLevel).toHaveBeenCalledWith(2);
|
||||
jest.clearAllMocks();
|
||||
mockStorj[NumericSetting.busyLog] = 3;
|
||||
mockStorj[NumericSetting.busy_log] = 3;
|
||||
wrapper.find("button").at(0).simulate("click");
|
||||
expect(setFilterLevel).not.toHaveBeenCalled();
|
||||
});
|
||||
|
|
|
@ -14,6 +14,7 @@ import { Session, safeNumericSetting } from "../session";
|
|||
import { isUndefined } from "lodash";
|
||||
import { NumericSetting } from "../session_keys";
|
||||
import { catchErrors } from "../util";
|
||||
import { NumberConfigKey } from "../config_storage/web_app_configs";
|
||||
|
||||
export const formatLogTime = (created_at: number, timeoffset: number) =>
|
||||
moment.unix(created_at).utcOffset(timeoffset).format("MMM D, h:mma");
|
||||
|
@ -22,7 +23,7 @@ export const formatLogTime = (created_at: number, timeoffset: number) =>
|
|||
export class Logs extends React.Component<LogsProps, Partial<LogsState>> {
|
||||
componentDidCatch(x: Error, y: React.ErrorInfo) { catchErrors(x, y); }
|
||||
|
||||
initialize = (name: NumericSetting, defaultValue: number): number => {
|
||||
initialize = (name: NumberConfigKey, defaultValue: number): number => {
|
||||
const currentValue = Session.getNum(safeNumericSetting(name));
|
||||
if (isUndefined(currentValue)) {
|
||||
Session.setNum(safeNumericSetting(name), defaultValue);
|
||||
|
@ -34,13 +35,13 @@ export class Logs extends React.Component<LogsProps, Partial<LogsState>> {
|
|||
|
||||
state: LogsState = {
|
||||
autoscroll: false,
|
||||
success: this.initialize(NumericSetting.successLog, 1),
|
||||
busy: this.initialize(NumericSetting.busyLog, 1),
|
||||
warn: this.initialize(NumericSetting.warnLog, 1),
|
||||
error: this.initialize(NumericSetting.errorLog, 1),
|
||||
info: this.initialize(NumericSetting.infoLog, 1),
|
||||
fun: this.initialize(NumericSetting.funLog, 1),
|
||||
debug: this.initialize(NumericSetting.debugLog, 1),
|
||||
success: this.initialize(NumericSetting.success_log, 1),
|
||||
busy: this.initialize(NumericSetting.busy_log, 1),
|
||||
warn: this.initialize(NumericSetting.warn_log, 1),
|
||||
error: this.initialize(NumericSetting.error_log, 1),
|
||||
info: this.initialize(NumericSetting.info_log, 1),
|
||||
fun: this.initialize(NumericSetting.fun_log, 1),
|
||||
debug: this.initialize(NumericSetting.debug_log, 1),
|
||||
};
|
||||
|
||||
toggle = (name: keyof LogsState) => {
|
||||
|
|
|
@ -23,14 +23,14 @@ describe("remove()", () => {
|
|||
|
||||
it("deletes step without confirmation", () => {
|
||||
const dispatch = jest.fn();
|
||||
mockStorj[BooleanSetting.confirmStepDeletion] = false;
|
||||
mockStorj[BooleanSetting.confirm_step_deletion] = false;
|
||||
remove({ index: 0, dispatch, sequence: fakeSequence() });
|
||||
expect(dispatch).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("deletes step with confirmation", () => {
|
||||
const dispatch = jest.fn();
|
||||
mockStorj[BooleanSetting.confirmStepDeletion] = true;
|
||||
mockStorj[BooleanSetting.confirm_step_deletion] = true;
|
||||
remove({ index: 0, dispatch, sequence: fakeSequence() });
|
||||
expect(dispatch).not.toHaveBeenCalled();
|
||||
// tslint:disable-next-line:no-any
|
||||
|
|
|
@ -66,7 +66,7 @@ interface RemoveParams {
|
|||
}
|
||||
|
||||
export function remove({ dispatch, index, sequence }: RemoveParams) {
|
||||
if (!Session.getBool(BooleanSetting.confirmStepDeletion) ||
|
||||
if (!Session.getBool(BooleanSetting.confirm_step_deletion) ||
|
||||
confirm(t("Are you sure you want to delete this step?"))) {
|
||||
const original = sequence;
|
||||
const update = defensiveClone(original);
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
import { AuthState } from "./auth/interfaces";
|
||||
import { box } from "boxed_value";
|
||||
import { get, isNumber, isBoolean } from "lodash";
|
||||
import { BooleanConfigKey, NumberConfigKey } from "./config_storage/web_app_configs";
|
||||
import { BooleanSetting, NumericSetting } from "./session_keys";
|
||||
|
||||
/** The `Session` namespace is a wrapper for `localStorage`.
|
||||
|
@ -45,54 +46,54 @@ export namespace Session {
|
|||
|
||||
/** Fetch a *boolean* value from localstorage. Returns `undefined` when
|
||||
* none are found.*/
|
||||
export function getBool(key: BooleanSetting): boolean | undefined {
|
||||
export function getBool(key: BooleanConfigKey): boolean | undefined {
|
||||
const output = JSON.parse(localStorage.getItem(key) || "null");
|
||||
return (isBoolean(output)) ? output : undefined;
|
||||
}
|
||||
|
||||
/** Store a boolean value in `localStorage` */
|
||||
export function setBool(key: BooleanSetting, val: boolean): boolean {
|
||||
export function setBool(key: BooleanConfigKey, val: boolean): boolean {
|
||||
localStorage.setItem(key, JSON.stringify(val));
|
||||
return val;
|
||||
}
|
||||
|
||||
export function invertBool(key: BooleanSetting): boolean {
|
||||
export function invertBool(key: BooleanConfigKey): boolean {
|
||||
return Session.setBool(key, !Session.getBool(key));
|
||||
}
|
||||
|
||||
/** Extract numeric settings from `localStorage`. Returns `undefined` when
|
||||
* none are found. */
|
||||
export function getNum(key: NumericSetting): number | undefined {
|
||||
export function getNum(key: NumberConfigKey): number | undefined {
|
||||
const output = JSON.parse(get(localStorage, key, "null"));
|
||||
return (isNumber(output)) ? output : undefined;
|
||||
}
|
||||
|
||||
/** Set a numeric value in `localStorage`. */
|
||||
export function setNum(key: NumericSetting, val: number): void {
|
||||
export function setNum(key: NumberConfigKey, val: number): void {
|
||||
localStorage.setItem(key, JSON.stringify(val));
|
||||
}
|
||||
}
|
||||
|
||||
export const isBooleanSetting =
|
||||
// tslint:disable-next-line:no-any
|
||||
(x: any): x is BooleanSetting => !!BooleanSetting[x];
|
||||
(x: any): x is BooleanConfigKey => !!BooleanSetting[x as BooleanConfigKey];
|
||||
|
||||
export function safeBooleanSettting(name: string): BooleanSetting {
|
||||
export function safeBooleanSettting(name: string): BooleanConfigKey {
|
||||
if (isBooleanSetting(name)) {
|
||||
return name;
|
||||
} else {
|
||||
throw new Error(`Expected BooleanSetting but got '${name}'`);
|
||||
throw new Error(`Expected BooleanConfigKey but got '${name}'`);
|
||||
}
|
||||
}
|
||||
|
||||
export const isNumericSetting =
|
||||
// tslint:disable-next-line:no-any
|
||||
(x: any): x is NumericSetting => !!NumericSetting[x];
|
||||
(x: any): x is NumberConfigKey => !!NumericSetting[x as NumberConfigKey];
|
||||
|
||||
export function safeNumericSetting(name: string): NumericSetting {
|
||||
export function safeNumericSetting(name: string): NumberConfigKey {
|
||||
if (isNumericSetting(name)) {
|
||||
return name;
|
||||
} else {
|
||||
throw new Error(`Expected NumericSetting but got '${name}'`);
|
||||
throw new Error(`Expected NumberConfigKey but got '${name}'`);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,36 +1,40 @@
|
|||
export enum BooleanSetting {
|
||||
xAxisInverted = "xAxisInverted",
|
||||
yAxisInverted = "yAxisInverted",
|
||||
zAxisInverted = "zAxisInverted",
|
||||
rawEncoders = "rawEncoders",
|
||||
scaledEncoders = "scaledEncoders",
|
||||
legendMenuOpen = "legendMenuOpen",
|
||||
showPlants = "showPlants",
|
||||
showPoints = "showPoints",
|
||||
showSpread = "showSpread",
|
||||
showFarmbot = "showFarmbot",
|
||||
import { BooleanConfigKey, NumberConfigKey } from "./config_storage/web_app_configs";
|
||||
|
||||
export const BooleanSetting: Record<BooleanConfigKey, BooleanConfigKey> = {
|
||||
x_axis_inverted: "x_axis_inverted",
|
||||
y_axis_inverted: "y_axis_inverted",
|
||||
z_axis_inverted: "z_axis_inverted",
|
||||
raw_encoders: "raw_encoders",
|
||||
scaled_encoders: "scaled_encoders",
|
||||
legend_menu_open: "legend_menu_open",
|
||||
show_plants: "show_plants",
|
||||
show_points: "show_points",
|
||||
show_spread: "show_spread",
|
||||
show_farmbot: "show_farmbot",
|
||||
|
||||
/** "Labs" feature names. */
|
||||
weedDetector = "weedDetector",
|
||||
disableI18n = "disableI18n",
|
||||
confirmStepDeletion = "confirmStepDeletion",
|
||||
hideWebcamWidget = "hideWebcamWidget",
|
||||
dynamicMap = "dynamicMap",
|
||||
mapXL = "mapXL",
|
||||
disableAnimations = "disableAnimations",
|
||||
displayTrail = "displayTrail",
|
||||
encoderFigure = "encoderFigure",
|
||||
}
|
||||
weed_detector: "weed_detector",
|
||||
disable_i18n: "disable_i18n",
|
||||
confirm_step_deletion: "confirm_step_deletion",
|
||||
hide_webcam_widget: "hide_webcam_widget",
|
||||
dynamic_map: "dynamic_map",
|
||||
map_xl: "map_xl",
|
||||
disable_animations: "disable_animations",
|
||||
display_trail: "display_trail",
|
||||
encoder_figure: "encoder_figure",
|
||||
};
|
||||
|
||||
export enum NumericSetting {
|
||||
botOriginQuadrant = "botOriginQuadrant",
|
||||
zoomLevel = "zoomLevel",
|
||||
successLog = "successLog",
|
||||
busyLog = "busyLog",
|
||||
warnLog = "warnLog",
|
||||
errorLog = "errorLog",
|
||||
infoLog = "infoLog",
|
||||
funLog = "funLog",
|
||||
debugLog = "debugLog",
|
||||
successsLog = "successsLog"
|
||||
}
|
||||
export const NumericSetting: Record<NumberConfigKey, NumberConfigKey> = {
|
||||
bot_origin_quadrant: "bot_origin_quadrant",
|
||||
busy_log: "busy_log",
|
||||
debug_log: "debug_log",
|
||||
device_id: "device_id",
|
||||
error_log: "error_log",
|
||||
fun_log: "fun_log",
|
||||
id: "id",
|
||||
info_log: "info_log",
|
||||
success_log: "success_log",
|
||||
successs_log: "successs_log",
|
||||
warn_log: "warn_log",
|
||||
zoom_level: "zoom_level",
|
||||
};
|
||||
|
|
Loading…
Reference in New Issue