From 86fe6fba783f9d23d832968d1b977f61a32f0b92 Mon Sep 17 00:00:00 2001 From: Rick Carlino Date: Mon, 4 Feb 2019 08:32:26 -0600 Subject: [PATCH] Part I of syntheticimport issues :-\ --- .../resource_index_builder.ts | 6 ++--- frontend/api/__tests__/crud_data_tracking.ts | 4 +-- frontend/api/crud.ts | 10 +++---- frontend/app.tsx | 4 +-- frontend/connectivity/log_handlers.ts | 4 +-- frontend/controls/axis_input_box_group.tsx | 8 +++--- .../controls/move/motor_position_plot.tsx | 26 +++++++++---------- frontend/controls/move/step_size_selector.tsx | 6 ++--- frontend/controls/state_to_props.ts | 6 ++--- frontend/controls/webcam/edit.tsx | 4 +-- frontend/devices/__tests__/reducer_test.ts | 6 ++--- frontend/devices/actions.ts | 18 ++++++------- .../components/bot_config_input_box.tsx | 6 ++--- frontend/devices/components/mcu_input_box.tsx | 4 +-- .../connectivity/__tests__/index_test.tsx | 4 +-- .../devices/pin_bindings/rpi_gpio_diagram.tsx | 10 +++---- frontend/devices/timezones/guess_timezone.ts | 4 +-- .../devices/timezones/timezone_selector.tsx | 4 +-- frontend/farm_designer/actions.ts | 6 ++--- .../farm_events/calendar/index.ts | 6 ++--- .../farm_designer/farm_events/farm_events.tsx | 8 +++--- .../map/active_plant/hovered_plant.tsx | 4 +-- .../farm_designer/map/background/grid.tsx | 6 ++--- .../map/layers/farmbot/bot_peripherals.tsx | 8 +++--- .../map/layers/farmbot/bot_trail.tsx | 22 ++++++++-------- .../map/layers/plants/plant_layer.tsx | 1 - .../map/layers/tool_slots/tool_slot_point.tsx | 6 ++--- frontend/farm_designer/plants/crop_info.tsx | 10 +++---- .../plants/map_state_to_props.tsx | 12 ++++----- frontend/farm_designer/plants/plant_panel.tsx | 10 +++---- frontend/farm_designer/search_selectors.ts | 5 ++-- frontend/farm_designer/state_to_props.ts | 9 +++---- frontend/farm_designer/util.ts | 6 ++--- frontend/farmware/farmware_forms.tsx | 8 +++--- frontend/farmware/images/photos.tsx | 4 +-- frontend/farmware/state_to_props.ts | 8 +++--- frontend/farmware/weed_detector/actions.tsx | 9 +++---- frontend/farmware/weed_detector/config.tsx | 4 +-- .../farmware/weed_detector/farmbot_picker.tsx | 6 ++--- .../weed_detector/remote_env/constants.ts | 8 +++--- .../weed_detector/remote_env/selectors.ts | 5 ++-- frontend/front_page/front_page.tsx | 4 +-- frontend/hotkeys.tsx | 4 +-- frontend/interceptor_support.ts | 6 ++--- frontend/interceptors.ts | 8 +++--- frontend/logs/components/filter_menu.tsx | 4 +-- frontend/logs/state_to_props.ts | 4 +-- frontend/password_reset/index.tsx | 1 - frontend/redux/__tests__/store_tests.ts | 14 +++++----- frontend/regimens/bulk_scheduler/utils.ts | 8 +++--- frontend/regimens/reducer.ts | 4 +-- frontend/regimens/state_to_props.ts | 8 +++--- .../resources/__tests__/selectors_test.ts | 4 +-- frontend/resources/selectors.ts | 4 +-- frontend/resources/selectors_by_id.ts | 5 ++-- frontend/resources/util.ts | 6 ++--- .../locals_list/location_form_list.ts | 5 ++-- .../pin_and_peripheral_support_test.tsx | 4 +-- frontend/sequences/step_tiles/index.tsx | 10 +++---- .../sequences/step_tiles/tile_execute.tsx | 4 +-- frontend/sequences/step_tiles/tile_if/if.tsx | 4 +-- .../sequences/step_tiles/tile_if/index.tsx | 10 +++---- .../step_tiles/tile_move_absolute.tsx | 6 ++--- .../sequences/step_tiles/tile_pin_support.tsx | 6 ++--- .../step_tiles/tile_send_message.tsx | 4 +-- frontend/sync/actions.ts | 4 +-- frontend/tools/state_to_props.ts | 10 +++---- frontend/util/errors.ts | 6 ++--- frontend/util/integer_clamp.ts | 3 +-- frontend/util/util.ts | 24 ++++++++++------- package.json | 5 +--- tsconfig.json | 2 +- 72 files changed, 244 insertions(+), 252 deletions(-) diff --git a/frontend/__test_support__/resource_index_builder.ts b/frontend/__test_support__/resource_index_builder.ts index d4a950df5..b91850670 100644 --- a/frontend/__test_support__/resource_index_builder.ts +++ b/frontend/__test_support__/resource_index_builder.ts @@ -7,11 +7,11 @@ import { TaggedSequence, TaggedRegimen, } from "farmbot"; -import * as _ from "lodash"; import { resourceReducer, emptyState } from "../resources/reducer"; import { resourceReady } from "../sync/actions"; import { threeWayComparison as c3 } from "../util/move"; import { defensiveClone } from "../util/util"; +import { chain } from "lodash"; export function fakeDevice(): TaggedDevice { return { "kind": "Device", @@ -374,7 +374,7 @@ export function buildResourceIndex(resources: TaggedResource[] = FAKE_RESOURCES, const sortedResources = repairBrokeReferences(resources) .sort((l, r) => c3(KIND_PRIORITY[l.kind], KIND_PRIORITY[r.kind])); type K = keyof typeof KIND_PRIORITY; - return _.chain(sortedResources) + return chain(sortedResources) .groupBy(KIND) .toPairs() .sort((l, r) => c3(KIND_PRIORITY[l[0] as K || 4], KIND_PRIORITY[r[0] as K || 4])) @@ -420,7 +420,7 @@ const blankReg: TaggedRegimen = { * number of failed tests. To circumvent this, we "repair" faulty foreign keys * in TaggedResources. This applies to many legacy tests. - RC*/ function repairBrokeReferences(resources: TaggedResource[]): TaggedResource[] { - const table = _.chain(resources).groupBy(x => x.kind).value(); + const table = chain(resources).groupBy(x => x.kind).value(); resources.map(resource => { if (resource.kind === "FarmEvent") { // Find FarmEvents const { executable_type, executable_id } = resource.body; diff --git a/frontend/api/__tests__/crud_data_tracking.ts b/frontend/api/__tests__/crud_data_tracking.ts index ff17f14e3..3a397d641 100644 --- a/frontend/api/__tests__/crud_data_tracking.ts +++ b/frontend/api/__tests__/crud_data_tracking.ts @@ -23,7 +23,7 @@ import { maybeStartTracking } from "../maybe_start_tracking"; import { API } from "../api"; import { betterCompact } from "../../util"; import { SpecialStatus, TaggedUser } from "farmbot"; -import * as _ from "lodash"; +import { uniq } from "lodash"; describe("AJAX data tracking", () => { API.setBaseUrl("http://blah.whatever.party"); @@ -54,7 +54,7 @@ describe("AJAX data tracking", () => { expect(maybeStartTracking).toHaveBeenCalled(); const list = (maybeStartTracking as jest.Mock).mock.calls; const uuids: string[] = - _.uniq(list.map((x: string[]) => x[0])); + uniq(list.map((x: string[]) => x[0])); expect(uuids.length).toEqual(r.length); }); diff --git a/frontend/api/crud.ts b/frontend/api/crud.ts index a3d1c4a5c..e65c0a882 100644 --- a/frontend/api/crud.ts +++ b/frontend/api/crud.ts @@ -15,13 +15,13 @@ import { defensiveClone, unpackUUID } from "../util"; import { EditResourceParams } from "./interfaces"; import { ResourceIndex } from "../resources/interfaces"; import { SequenceBodyItem } from "farmbot/dist"; -import _ from "lodash"; import { Actions } from "../constants"; import { maybeStartTracking } from "./maybe_start_tracking"; import { t } from "i18next"; import { newTaggedResource } from "../sync/actions"; import { arrayUnwrap } from "../resources/util"; import { findByUuid } from "../resources/reducer_support"; +import { assign, noop } from "lodash"; export function edit(tr: TaggedResource, changes: Partial): ReduxAction { @@ -135,7 +135,7 @@ export function refresh(resource: TaggedResource, urlNeedsId = false) { .then(resp => { const r1 = defensiveClone(resource); const r2 = { body: defensiveClone(resp.data) }; - const newTR = _.assign({}, r1, r2); + const newTR = assign({}, r1, r2); if (isTaggedResource(newTR)) { dispatch(refreshOK(newTR)); } else { @@ -223,8 +223,8 @@ export function destroyAll(resourceName: ResourceName, force = false) { } export function saveAll(input: TaggedResource[], - callback: () => void = _.noop, - errBack: (err: UnsafeError) => void = _.noop) { + callback: () => void = noop, + errBack: (err: UnsafeError) => void = noop) { return function (dispatch: Function) { const p = input .filter(x => x.specialStatus === SpecialStatus.DIRTY) @@ -293,7 +293,7 @@ export function updateViaAjax(payl: AjaxUpdatePayload) { .then(function (resp) { const r1 = defensiveClone(resource); const r2 = { body: defensiveClone(resp.data) }; - const newTR = _.assign({}, r1, r2); + const newTR = assign({}, r1, r2); if (isTaggedResource(newTR)) { dispatch(saveOK(newTR)); } else { diff --git a/frontend/app.tsx b/frontend/app.tsx index a25919b13..56c2b5ef4 100644 --- a/frontend/app.tsx +++ b/frontend/app.tsx @@ -1,7 +1,6 @@ import * as React from "react"; import { t } from "i18next"; import { connect } from "react-redux"; -import _ from "lodash"; import { init, error } from "farmbot-toastr"; import { NavBar } from "./nav"; import { Everything } from "./interfaces"; @@ -24,6 +23,7 @@ import { getWebAppConfigValue, GetWebAppConfigValue } from "./config_storage/act import { takeSortedLogs } from "./logs/state_to_props"; import { FirmwareConfig } from "farmbot/dist/resources/configs/firmware"; import { getFirmwareConfig } from "./resources/getters"; +import { intersection } from "lodash"; /** Remove 300ms delay on touch devices - https://github.com/ftlabs/fastclick */ // const fastClick = require("fastclick"); @@ -89,7 +89,7 @@ const MUST_LOAD: ResourceName[] = [ export class App extends React.Component { private get isLoaded() { return (MUST_LOAD.length === - _.intersection(this.props.loaded, MUST_LOAD).length); + intersection(this.props.loaded, MUST_LOAD).length); } /** diff --git a/frontend/connectivity/log_handlers.ts b/frontend/connectivity/log_handlers.ts index c742eb176..0440f7bc4 100644 --- a/frontend/connectivity/log_handlers.ts +++ b/frontend/connectivity/log_handlers.ts @@ -8,8 +8,8 @@ import { import { GetState } from "../redux/interfaces"; import { dispatchNetworkDown } from "."; import { Log } from "farmbot/dist/resources/api_resources"; -import _ from "lodash"; import { globalQueue } from "./batch_queue"; +import { isUndefined, get } from "lodash"; const LEGACY_META_KEY_NAMES: (keyof Log)[] = [ "type", @@ -25,7 +25,7 @@ function legacyKeyTransformation(log: Log, key: keyof Log) { const before = log[key]; // You don't want to use || here, trust me. -RC - log[key] = !_.isUndefined(before) ? before : _.get(log, ["meta", key], undefined); + log[key] = !isUndefined(before) ? before : get(log, ["meta", key], undefined); } export const onLogs = diff --git a/frontend/controls/axis_input_box_group.tsx b/frontend/controls/axis_input_box_group.tsx index acd70f17b..e75a08e5e 100644 --- a/frontend/controls/axis_input_box_group.tsx +++ b/frontend/controls/axis_input_box_group.tsx @@ -7,7 +7,7 @@ import { AxisInputBoxGroupState, Vector } from "./interfaces"; -import _ from "lodash"; +import { isNumber } from "lodash"; /** Coordinate input and GO button for Move widget. */ export class AxisInputBoxGroup extends @@ -29,9 +29,9 @@ export class AxisInputBoxGroup extends z2 = p.z; return { - x: _.isNumber(x) ? x : (x2 || 0), - y: _.isNumber(y) ? y : (y2 || 0), - z: _.isNumber(z) ? z : (z2 || 0) + x: isNumber(x) ? x : (x2 || 0), + y: isNumber(y) ? y : (y2 || 0), + z: isNumber(z) ? z : (z2 || 0) }; } diff --git a/frontend/controls/move/motor_position_plot.tsx b/frontend/controls/move/motor_position_plot.tsx index 88c79f105..1eb114997 100644 --- a/frontend/controls/move/motor_position_plot.tsx +++ b/frontend/controls/move/motor_position_plot.tsx @@ -1,10 +1,10 @@ import * as React from "react"; -import _ from "lodash"; import { Xyz, LocationName, Dictionary } from "farmbot"; import moment from "moment"; import { BotLocationData, BotPosition } from "../../devices/interfaces"; import { trim } from "../../util"; import { t } from "i18next"; +import { cloneDeep, max, get, isNumber, isEqual, takeRight, ceil, range } from "lodash"; const HEIGHT = 50; const HISTORY_LENGTH_SECONDS = 120; @@ -32,9 +32,9 @@ type Entry = { type Paths = Record>; const getArray = (): Entry[] => - JSON.parse(_.get(sessionStorage, MotorPositionHistory.array, "[]")); + JSON.parse(get(sessionStorage, MotorPositionHistory.array, "[]")); -const getReversedArray = (): Entry[] => _.cloneDeep(getArray()).reverse(); +const getReversedArray = (): Entry[] => cloneDeep(getArray()).reverse(); const getLastEntry = (): Entry | undefined => { const array = getArray(); @@ -43,21 +43,21 @@ const getLastEntry = (): Entry | undefined => { const findYLimit = (): number => { const array = getArray(); - const arrayAbsMax = _.max(array.map(entry => - _.max(["position", "scaled_encoders"].map((name: LocationName) => - _.max(["x", "y", "z"].map((axis: Xyz) => + const arrayAbsMax = max(array.map(entry => + max(["position", "scaled_encoders"].map((name: LocationName) => + max(["x", "y", "z"].map((axis: Xyz) => Math.abs(entry.locationData[name][axis] || 0) + 1)))))); - return Math.max(_.ceil(arrayAbsMax || 0, -2), DEFAULT_Y_MAX); + return Math.max(ceil(arrayAbsMax || 0, -2), DEFAULT_Y_MAX); }; const updateArray = (update: Entry): Entry[] => { const arr = getArray(); const last = getLastEntry(); - if (update && _.isNumber(update.locationData.position.x) && - (!last || !_.isEqual(last.timestamp, update.timestamp))) { + if (update && isNumber(update.locationData.position.x) && + (!last || !isEqual(last.timestamp, update.timestamp))) { arr.push(update); } - const newArray = _.takeRight(arr, 100) + const newArray = takeRight(arr, 100) .filter(x => { const entryAge = (last ? last.timestamp : moment().unix()) - x.timestamp; return entryAge <= HISTORY_LENGTH_SECONDS; @@ -82,8 +82,8 @@ const getPaths = (): Paths => { ["x", "y", "z"].map((axis: Xyz) => { const lastPos = last.locationData[name][axis]; const pos = entry.locationData[name][axis]; - if (_.isNumber(lastPos) && _.isFinite(lastPos) - && _.isNumber(maxY) && _.isNumber(pos)) { + if (isNumber(lastPos) && isFinite(lastPos) + && isNumber(maxY) && isNumber(pos)) { if (!paths[name][axis].startsWith("M")) { const yStart = -lastPos / maxY * HEIGHT / 2; paths[name][axis] = `M ${MAX_X},${yStart} `; @@ -135,7 +135,7 @@ const XAxisLabels = () => fontStyle={"italic"}> {t("seconds ago")} - {_.range(0, HISTORY_LENGTH_SECONDS + 1, 20).map(secondsAgo => + {range(0, HISTORY_LENGTH_SECONDS + 1, 20).map(secondsAgo => {secondsAgo} diff --git a/frontend/controls/move/step_size_selector.tsx b/frontend/controls/move/step_size_selector.tsx index 753afbb6d..59c99b631 100644 --- a/frontend/controls/move/step_size_selector.tsx +++ b/frontend/controls/move/step_size_selector.tsx @@ -1,16 +1,16 @@ import * as React from "react"; import { Component } from "react"; import { StepSizeSelectorProps } from "./interfaces"; -import _ from "lodash"; +import { first, last } from "lodash"; export class StepSizeSelector extends Component { cssForIndex(num: number) { const choices = this.props.choices; let css = "move-amount no-radius fb-button "; - if (num === _.first(choices)) { + if (num === first(choices)) { css += "leftmost "; } - if (num === _.last(choices)) { + if (num === last(choices)) { css += "rightmost "; } if (num === this.props.selected) { diff --git a/frontend/controls/state_to_props.ts b/frontend/controls/state_to_props.ts index 2681b742a..3b3e90489 100644 --- a/frontend/controls/state_to_props.ts +++ b/frontend/controls/state_to_props.ts @@ -9,16 +9,16 @@ import { } from "../resources/selectors"; import { Props } from "./interfaces"; import { maybeFetchUser } from "../resources/selectors"; -import _ from "lodash"; import { validFwConfig, shouldDisplay, determineInstalledOsVersion } from "../util"; import { getWebAppConfigValue } from "../config_storage/actions"; import { getFirmwareConfig } from "../resources/getters"; +import { uniq } from "lodash"; export function mapStateToProps(props: Everything): Props { - const peripherals = _.uniq(selectAllPeripherals(props.resources.index)); - const sensors = _.uniq(selectAllSensors(props.resources.index)); + const peripherals = uniq(selectAllPeripherals(props.resources.index)); + const sensors = uniq(selectAllSensors(props.resources.index)); const resources = props.resources; const bot2mqtt = props.bot.connectivity["bot.mqtt"]; const botToMqttStatus = bot2mqtt ? bot2mqtt.state : "down"; diff --git a/frontend/controls/webcam/edit.tsx b/frontend/controls/webcam/edit.tsx index f63185586..960cdb3fa 100644 --- a/frontend/controls/webcam/edit.tsx +++ b/frontend/controls/webcam/edit.tsx @@ -5,10 +5,10 @@ import { ToolTips } from "../../constants"; import { WebcamPanelProps } from "./interfaces"; import { KeyValEditRow } from "../key_val_edit_row"; import { SpecialStatus, TaggedWebcamFeed } from "farmbot"; -import _ from "lodash"; +import { sortBy } from "lodash"; export function sortedFeeds(feeds: TaggedWebcamFeed[]): TaggedWebcamFeed[] { - return _.sortBy(feeds, (f) => { return f.body.id || Infinity; }); + return sortBy(feeds, (f) => { return f.body.id || Infinity; }); } export function Edit(props: WebcamPanelProps) { diff --git a/frontend/devices/__tests__/reducer_test.ts b/frontend/devices/__tests__/reducer_test.ts index 4339169af..1d4f40b14 100644 --- a/frontend/devices/__tests__/reducer_test.ts +++ b/frontend/devices/__tests__/reducer_test.ts @@ -1,12 +1,12 @@ import { botReducer, initialState } from "../reducer"; import { Actions } from "../../constants"; import { ControlPanelState } from "../interfaces"; -import * as _ from "lodash"; import { defensiveClone } from "../../util"; import { networkUp, networkDown } from "../../connectivity/actions"; import { stash } from "../../connectivity/data_consistency"; import { incomingStatus } from "../../connectivity/connect_device"; import { Vector3 } from "farmbot"; +import { values, omit } from "lodash"; describe("botReducer", () => { it("Starts / stops an update", () => { @@ -49,8 +49,8 @@ describe("botReducer", () => { }); const bulkToggable = - _.omit(state.controlPanelState, "power_and_reset", "diagnostic_dumps"); - _.values(bulkToggable).map(value => { + omit(state.controlPanelState, "power_and_reset", "diagnostic_dumps"); + values(bulkToggable).map(value => { expect(value).toBeTruthy(); }); }); diff --git a/frontend/devices/actions.ts b/frontend/devices/actions.ts index e6b89a07d..e3f8b36e5 100644 --- a/frontend/devices/actions.ts +++ b/frontend/devices/actions.ts @@ -1,6 +1,5 @@ import { t } from "i18next"; import axios from "axios"; -import _ from "lodash"; import { success, warning, info, error } from "farmbot-toastr"; import { getDevice } from "../device"; import { Everything } from "../interfaces"; @@ -22,6 +21,7 @@ import { Log } from "farmbot/dist/resources/api_resources"; import { FbosConfig } from "farmbot/dist/resources/configs/fbos"; import { FirmwareConfig } from "farmbot/dist/resources/configs/firmware"; import { getFirmwareConfig, getFbosConfig } from "../resources/getters"; +import { isObject, isString, get, noop } from "lodash"; const ON = 1, OFF = 0; export type ConfigKey = keyof McuParams; @@ -37,7 +37,7 @@ const BAD_WORDS = ["WPA", "PSK", "PASSWORD", "NERVES"]; // tslint:disable-next-line:no-any export function isLog(x: any): x is Log { - const yup = _.isObject(x) && _.isString(_.get(x, "message" as keyof Log)); + const yup = isObject(x) && isString(get(x, "message" as keyof Log)); if (yup) { if (oneOf(BAD_WORDS, x.message.toUpperCase())) {// SECURITY CRITICAL CODE. throw new Error("Refusing to display log: " + JSON.stringify(x)); @@ -219,7 +219,7 @@ export const fetchReleases = * @param x axios response data */ function validMinOsFeatureLookup(x: MinOsFeatureLookup): boolean { - return _.isObject(x) && + return isObject(x) && Object.entries(x).every(([key, val]) => typeof key === "string" && // feature name typeof val === "string" && // version string @@ -296,7 +296,7 @@ export function settingToggle( } else { return getDevice() .updateMcu(update) - .then(_.noop, commandErr(noun)); + .then(noop, commandErr(noun)); } }; } @@ -304,28 +304,28 @@ export function settingToggle( export function moveRelative(props: MoveRelProps) { return getDevice() .moveRelative(props) - .then(_.noop, commandErr("Relative movement")); + .then(noop, commandErr("Relative movement")); } export function moveAbs(props: MoveRelProps) { const noun = "Absolute movement"; return getDevice() .moveAbsolute(props) - .then(_.noop, commandErr(noun)); + .then(noop, commandErr(noun)); } export function pinToggle(pin_number: number) { const noun = "Setting toggle"; return getDevice() .togglePin({ pin_number }) - .then(_.noop, commandErr(noun)); + .then(noop, commandErr(noun)); } export function readPin(pin_number: number, label: string, pin_mode: number) { const noun = "Read pin"; return getDevice() .readPin({ pin_number, label, pin_mode }) - .then(_.noop, commandErr(noun)); + .then(noop, commandErr(noun)); } export function homeAll(speed: number) { @@ -405,7 +405,7 @@ export function updateConfig(config: Configuration) { } else { getDevice() .updateConfig(config) - .then(_.noop, commandErr(noun)); + .then(noop, commandErr(noun)); } }; } diff --git a/frontend/devices/components/bot_config_input_box.tsx b/frontend/devices/components/bot_config_input_box.tsx index 2cdc6f67e..0e2f6cfc1 100644 --- a/frontend/devices/components/bot_config_input_box.tsx +++ b/frontend/devices/components/bot_config_input_box.tsx @@ -1,10 +1,10 @@ import * as React from "react"; -import _ from "lodash"; import { BlurableInput } from "../../ui/index"; import { SourceFbosConfig } from "../interfaces"; import { ConfigurationName } from "farmbot/dist"; import { updateConfig } from "../actions"; import { parseIntInput } from "../../util"; +import { isNumber, isBoolean, isNaN } from "lodash"; export interface BotConfigInputBoxProps { setting: ConfigurationName; @@ -27,7 +27,7 @@ export class BotConfigInputBox return (event: React.FormEvent) => { const next = parseIntInput(event.currentTarget.value); const current = this.config.value; - if (!_.isNaN(next) && (next !== current)) { + if (!isNaN(next) && (next !== current)) { dispatch(updateConfig({ [key]: next })); } }; @@ -35,7 +35,7 @@ export class BotConfigInputBox render() { const current = this.config.value; - const boxValue = (_.isNumber(current) || _.isBoolean(current)) + const boxValue = (isNumber(current) || isBoolean(current)) ? current.toString() : ""; return { @@ -20,7 +20,7 @@ export class McuInputBox extends React.Component { get value() { const v = this.config.value; const { filter } = this.props; - const goodValue = !_.isUndefined(v) && !(filter && v > filter); + const goodValue = !isUndefined(v) && !(filter && v > filter); return goodValue ? (v || 0).toString() : ""; } diff --git a/frontend/devices/connectivity/__tests__/index_test.tsx b/frontend/devices/connectivity/__tests__/index_test.tsx index d474e4929..366b0a6f6 100644 --- a/frontend/devices/connectivity/__tests__/index_test.tsx +++ b/frontend/devices/connectivity/__tests__/index_test.tsx @@ -2,9 +2,9 @@ import * as React from "react"; import { render, mount } from "enzyme"; import { ConnectivityPanel } from "../index"; import { StatusRowProps } from "../connectivity_row"; -import * as _ from "lodash"; import { SpecialStatus } from "farmbot"; import { bot } from "../../../__test_support__/fake_state/bot"; +import { fill } from "lodash"; describe("", () => { function test() { @@ -16,7 +16,7 @@ describe("", () => { connectionStatus: false, children: "Can't do things with stuff." }; - const rowData: StatusRowProps[] = _.fill(Array(5), statusRow); + const rowData: StatusRowProps[] = fill(Array(5), statusRow); return { component: {[3, 5.5].map((x, xi) => { - return _.range(8, 56, 2.5).map((y, yi) => { + return range(8, 56, 2.5).map((y, yi) => { const pin = gpio[yi][xi]; const normalColor = () => { switch (pin) { @@ -72,10 +72,10 @@ export class RpiGpioDiagram return Color.green; } }; - const color = _.isNumber(pin) && reservedPiGPIO.includes(pin) + const color = isNumber(pin) && reservedPiGPIO.includes(pin) ? Color.magenta : normalColor(); - const pinColor = _.includes(this.props.boundPins, pin) + const pinColor = includes(this.props.boundPins, pin) ? Color.darkGray : color; return - _.isNumber(pin) ? this.props.setSelectedPin(pin) : _.noop} />; + isNumber(pin) ? this.props.setSelectedPin(pin) : noop} />; }); })} ({ label: x, value: x })); @@ -30,7 +30,7 @@ export class TimezoneSelector extends React.Component { } itemSelected = (d: DropDownItem): void => { - if (_.isString(d.value)) { + if (isString(d.value)) { this.props.onUpdate(d.value); } } diff --git a/frontend/farm_designer/actions.ts b/frontend/farm_designer/actions.ts index e80c9c79d..aac6b121e 100644 --- a/frontend/farm_designer/actions.ts +++ b/frontend/farm_designer/actions.ts @@ -1,20 +1,20 @@ import { MovePlantProps, DraggableEvent } from "./interfaces"; import { defensiveClone } from "../util"; import { edit } from "../api/crud"; -import _ from "lodash"; import { history, getPathArray } from "../history"; import { Actions } from "../constants"; import { svgToUrl, DEFAULT_ICON } from "../open_farm/icons"; import { getMode } from "./map/util"; import { Mode } from "./map/interfaces"; +import { clamp } from "lodash"; export function movePlant(payload: MovePlantProps) { const tr = payload.plant; const update = defensiveClone(payload.plant).body; update.x += payload.deltaX; update.y += payload.deltaY; - update.x = _.clamp(update.x, 0, payload.gridSize.x); - update.y = _.clamp(update.y, 0, payload.gridSize.y); + update.x = clamp(update.x, 0, payload.gridSize.x); + update.y = clamp(update.y, 0, payload.gridSize.y); return edit(tr, update); } diff --git a/frontend/farm_designer/farm_events/calendar/index.ts b/frontend/farm_designer/farm_events/calendar/index.ts index f36208ac6..b0ee6e9c7 100644 --- a/frontend/farm_designer/farm_events/calendar/index.ts +++ b/frontend/farm_designer/farm_events/calendar/index.ts @@ -1,7 +1,7 @@ import { Dictionary } from "farmbot/dist"; import { CalendarOccurrence, CalendarDay } from "../../interfaces"; import moment from "moment"; -import _ from "lodash"; +import { chain, sortBy } from "lodash"; export class Calendar { /** We sort by this attribute. Left as const so that the compiler can catch @@ -44,10 +44,10 @@ export class Calendar { year: parseInt(item.mmddyy.slice(4, 6)), month: Calendar.MONTHS[item.mmddyy.slice(0, 2)] || "???", day: parseInt(item.mmddyy.slice(2, 4)), - items: _.sortBy(items, Calendar.SORT_KEY) + items: sortBy(items, Calendar.SORT_KEY) }; }); - return _.chain(all).sortBy(Calendar.SORT_KEY).value(); + return chain(all).sortBy(Calendar.SORT_KEY).value(); } findByDate(m: moment.Moment): CalendarOccurrence[] { diff --git a/frontend/farm_designer/farm_events/farm_events.tsx b/frontend/farm_designer/farm_events/farm_events.tsx index a9b389c48..436568557 100644 --- a/frontend/farm_designer/farm_events/farm_events.tsx +++ b/frontend/farm_designer/farm_events/farm_events.tsx @@ -6,13 +6,13 @@ import { mapStateToProps } from "./map_state_to_props"; import { FarmEventProps, CalendarOccurrence, FarmEventState } from "../interfaces"; -import _ from "lodash"; import moment from "moment"; import { Content } from "../../constants"; import { DesignerNavTabs } from "../panel_header"; import { Link } from "../../link"; import { DesignerPanel, DesignerPanelContent } from "../plants/designer_panel"; import { EmptyStateWrapper, EmptyStateGraphic } from "../../ui/empty_state_wrapper"; +import { chain, some, uniq, map } from "lodash"; const filterSearch = (term: string) => (item: CalendarOccurrence) => item.heading.toLowerCase().includes(term) @@ -31,7 +31,7 @@ export class PureFarmEvents innerRows = (items: CalendarOccurrence[]) => { - return _.chain(items) + return chain(items) .sortBy(x => x.sortKey) .value() .filter(filterSearch(this.searchTerm)) @@ -67,7 +67,7 @@ export class PureFarmEvents return day.year == year; }) .filter(item => !this.searchTerm || - _.some(item.items.map(filterSearch(this.searchTerm)))) + some(item.items.map(filterSearch(this.searchTerm)))) .map(item => { return
@@ -86,7 +86,7 @@ export class PureFarmEvents } renderCalendarRows() { - const years = _.uniq(_.map(this.props.calendarRows, "year")); + const years = uniq(map(this.props.calendarRows, "year")); return years.map(year => { return
diff --git a/frontend/farm_designer/map/active_plant/hovered_plant.tsx b/frontend/farm_designer/map/active_plant/hovered_plant.tsx index b541c9f1b..36f3e70bc 100644 --- a/frontend/farm_designer/map/active_plant/hovered_plant.tsx +++ b/frontend/farm_designer/map/active_plant/hovered_plant.tsx @@ -4,7 +4,7 @@ import { transformXY, round } from "../util"; import { MapTransformProps, TaggedPlant } from "../interfaces"; import { SpreadCircle } from "../layers/spread/spread_layer"; import { Circle } from "../layers/plants/circle"; -import _ from "lodash"; +import { noop } from "lodash"; /** * For showing the map plant hovered in the plant panel. @@ -73,7 +73,7 @@ export class HoveredPlant extends - {_.range(100, gridSize.x, 100).map((i) => { + {range(100, gridSize.x, 100).map((i) => { const location = transformXY(i, -10, mapTransformProps); return {i}; })} - {_.range(100, gridSize.y, 100).map((i) => { + {range(100, gridSize.y, 100).map((i) => { const location = transformXY(-15, i, mapTransformProps); return {i}; diff --git a/frontend/farm_designer/map/layers/farmbot/bot_peripherals.tsx b/frontend/farm_designer/map/layers/farmbot/bot_peripherals.tsx index 2846adf9e..689175007 100644 --- a/frontend/farm_designer/map/layers/farmbot/bot_peripherals.tsx +++ b/frontend/farm_designer/map/layers/farmbot/bot_peripherals.tsx @@ -2,10 +2,10 @@ import * as React from "react"; import { AxisNumberProperty, MapTransformProps } from "../../interfaces"; import { getMapSize, transformXY } from "../../util"; import { BotPosition } from "../../../../devices/interfaces"; -import _ from "lodash"; import { trim } from "../../../../util"; import { GetWebAppConfigValue } from "../../../../config_storage/actions"; import { BooleanSetting } from "../../../../session_keys"; +import { range } from "lodash"; export interface BotPeripheralsProps { position: BotPosition; @@ -73,11 +73,11 @@ function waterFigure( - {_.range(0, copies).map(s => { + {range(0, copies).map(s => { return - {_.range(0, 360, 15).map(rotation => { + {range(0, 360, 15).map(rotation => { return ; })} @@ -110,7 +110,7 @@ function vacuumFigure( - {_.range(0, copies).map(s => { + {range(0, copies).map(s => { return diff --git a/frontend/farm_designer/map/layers/farmbot/bot_trail.tsx b/frontend/farm_designer/map/layers/farmbot/bot_trail.tsx index eeb2ecdf4..8ed9de11c 100644 --- a/frontend/farm_designer/map/layers/farmbot/bot_trail.tsx +++ b/frontend/farm_designer/map/layers/farmbot/bot_trail.tsx @@ -1,9 +1,9 @@ import * as React from "react"; -import _ from "lodash"; import { MapTransformProps } from "../../interfaces"; import { transformXY } from "../../util"; import { BotPosition } from "../../../../devices/interfaces"; import { Color } from "../../../../ui"; +import { get, isNumber, takeRight, isEqual, round, first } from "lodash"; type TrailRecord = { coord: Record<"x" | "y", number | undefined>, @@ -17,18 +17,18 @@ export enum VirtualTrail { function getNewTrailArray(update: TrailRecord, watering: boolean): TrailRecord[] { const key = VirtualTrail.records; // sessionStorage location - const trailLength = _.get(sessionStorage, VirtualTrail.length, 100); - const arr: TrailRecord[] = JSON.parse(_.get(sessionStorage, key, "[]")); + const trailLength = get(sessionStorage, VirtualTrail.length, 100); + const arr: TrailRecord[] = JSON.parse(get(sessionStorage, key, "[]")); if (arr.length > (trailLength - 1)) { arr.shift(); } // max length reached const last = arr[arr.length - 1]; // most recent item in array if (update && update.coord && - (!last || !_.isEqual(last.coord, update.coord))) { // coordinate comparison + (!last || !isEqual(last.coord, update.coord))) { // coordinate comparison arr.push(update); // unique addition } else { // nothing new to add, increase water circle size if watering - if (watering && last && _.isNumber(last.water)) { last.water += 1; } + if (watering && last && isNumber(last.water)) { last.water += 1; } } sessionStorage.setItem(key, JSON.stringify(arr)); // save array - return _.takeRight(arr, trailLength); + return takeRight(arr, trailLength); } export interface BotTrailProps { @@ -42,7 +42,7 @@ export function BotTrail(props: BotTrailProps) { transformXY(ox, oy, props.mapTransformProps); const { x, y } = props.position; - const watering = !!_.first(props.peripherals + const watering = !!first(props.peripherals .filter(p => p.label.toLowerCase().includes("water")) .map(p => p.value)); @@ -51,10 +51,10 @@ export function BotTrail(props: BotTrailProps) { return {array.map((cur: TrailRecord, i: number) => { const prev = (array[i - 1] || { coord: undefined }).coord; // prev coord - const opacity = _.round(Math.max(0.25, i / (array.length - 1)), 2); - if (i > 0 && cur && prev && _.isNumber(prev.x) && _.isNumber(prev.y) - && _.isNumber(cur.coord.x) && _.isNumber(cur.coord.y) - && _.isNumber(cur.water)) { + const opacity = round(Math.max(0.25, i / (array.length - 1)), 2); + if (i > 0 && cur && prev && isNumber(prev.x) && isNumber(prev.y) + && isNumber(cur.coord.x) && isNumber(cur.coord.y) + && isNumber(cur.water)) { const p1 = toQ(cur.coord.x, cur.coord.y); const p2 = toQ(prev.x, prev.y); return diff --git a/frontend/farm_designer/map/layers/plants/plant_layer.tsx b/frontend/farm_designer/map/layers/plants/plant_layer.tsx index c24615c0c..9f3794b02 100644 --- a/frontend/farm_designer/map/layers/plants/plant_layer.tsx +++ b/frontend/farm_designer/map/layers/plants/plant_layer.tsx @@ -1,5 +1,4 @@ import * as React from "react"; -import _ from "lodash"; import { GardenPlant } from "./garden_plant"; import { PlantLayerProps } from "../../interfaces"; import { unpackUUID } from "../../../../util"; diff --git a/frontend/farm_designer/map/layers/tool_slots/tool_slot_point.tsx b/frontend/farm_designer/map/layers/tool_slots/tool_slot_point.tsx index f1d80fe33..58c51c4a3 100644 --- a/frontend/farm_designer/map/layers/tool_slots/tool_slot_point.tsx +++ b/frontend/farm_designer/map/layers/tool_slots/tool_slot_point.tsx @@ -2,9 +2,9 @@ import * as React from "react"; import { SlotWithTool } from "../../../../resources/interfaces"; import { transformXY } from "../../util"; import { MapTransformProps } from "../../interfaces"; -import _ from "lodash"; import { ToolbaySlot, ToolNames, Tool } from "./tool_graphics"; import { ToolLabel } from "./tool_label"; +import { includes } from "lodash"; export interface TSPProps { slot: SlotWithTool; @@ -28,8 +28,8 @@ export class ToolSlotPoint extends reduceToolName = (raw: string | undefined) => { const lower = (raw || "").toLowerCase(); - if (_.includes(lower, "seed bin")) { return ToolNames.seedBin; } - if (_.includes(lower, "seed tray")) { return ToolNames.seedTray; } + if (includes(lower, "seed bin")) { return ToolNames.seedBin; } + if (includes(lower, "seed tray")) { return ToolNames.seedTray; } return ToolNames.tool; } diff --git a/frontend/farm_designer/plants/crop_info.tsx b/frontend/farm_designer/plants/crop_info.tsx index 0df0c7887..56fb7f889 100644 --- a/frontend/farm_designer/plants/crop_info.tsx +++ b/frontend/farm_designer/plants/crop_info.tsx @@ -1,6 +1,5 @@ import * as React from "react"; import { t } from "i18next"; -import _ from "lodash"; import { svgToUrl } from "../../open_farm/icons"; import { CropInfoProps, CropLiveSearchResult, OpenfarmSearch @@ -23,6 +22,7 @@ import { Actions } from "../../constants"; import { EmptyStateWrapper, EmptyStateGraphic } from "../../ui/empty_state_wrapper"; +import { startCase, isArray, chain, isNumber } from "lodash"; interface InfoFieldProps { title: string; @@ -40,7 +40,7 @@ interface SummaryItemProps { const InfoField = (props: InfoFieldProps) =>
  • - {t(_.startCase(props.title))} + {t(startCase(props.title))}

    {props.children} @@ -87,7 +87,7 @@ const CmProperty = ({ i, field, value }: SummaryItemProps) => /** Comma-separated list of crop common names. */ const CommonNames = ({ i, field, value }: SummaryItemProps) => - {(_.isArray(value) + {(isArray(value) ? value.join(", ") : value) || NO_VALUE} ; @@ -119,7 +119,7 @@ const handleDisplay = ([field, value]: string[], i: number) => { const CropInfoList = (crop: OpenFarm.OFCrop) => { return
      - {_(crop) + {chain(crop) .omit(OMITTED_PROPERTIES) .toPairs() .map(handleDisplay) @@ -138,7 +138,7 @@ const AddPlantHereButton = (props: { }) => { const { botPosition, openedSavedGarden, cropName, slug, dispatch } = props; const { x, y } = botPosition; - const botXY = _.isNumber(x) && _.isNumber(y) ? + const botXY = isNumber(x) && isNumber(y) ? { x: round(x), y: round(y) } : undefined; const botXYLabel = botXY ? `(${botXY.x}, ${botXY.y})` : "(unknown)"; const click = () => botXY diff --git a/frontend/farm_designer/plants/map_state_to_props.tsx b/frontend/farm_designer/plants/map_state_to_props.tsx index 4e20ceed9..bbfa585d1 100644 --- a/frontend/farm_designer/plants/map_state_to_props.tsx +++ b/frontend/farm_designer/plants/map_state_to_props.tsx @@ -6,8 +6,8 @@ import { } from "../../resources/selectors"; import { history } from "../../history"; import { PlantStage } from "farmbot"; -import _ from "lodash"; import { TaggedPlant } from "../map/interfaces"; +import { isNumber, get } from "lodash"; export function mapStateToProps(props: Everything): EditPlantInfoProps { const openedSavedGarden = @@ -15,7 +15,7 @@ export function mapStateToProps(props: Everything): EditPlantInfoProps { const gardenOpen = !!openedSavedGarden; const findPlant = (id: string | undefined) => { const num = parseInt(id || "NOPE", 10); - if (_.isNumber(num) && !_.isNaN(num)) { + if (isNumber(num) && !isNaN(num)) { return gardenOpen ? maybeFindPlantTemplateById(props.resources.index, num) : maybeFindPlantById(props.resources.index, num); @@ -49,9 +49,9 @@ export interface FormattedPlantInfo { export function formatPlantInfo(rsrc: TaggedPlant): FormattedPlantInfo { const p = rsrc.body; - const plantedAt = _.get(p, "planted_at", moment()) - ? moment(_.get(p, "planted_at", moment())) - : moment(_.get(p, "created_at", moment())); + const plantedAt = get(p, "planted_at", moment()) + ? moment(get(p, "planted_at", moment())) + : moment(get(p, "created_at", moment())); const currentDay = moment(); const daysOld = currentDay.diff(plantedAt, "days") + 1; return { @@ -63,6 +63,6 @@ export function formatPlantInfo(rsrc: TaggedPlant): FormattedPlantInfo { y: p.y, uuid: rsrc.uuid, plantedAt, - plantStatus: _.get(p, "plant_stage", "planned"), + plantStatus: get(p, "plant_stage", "planned"), }; } diff --git a/frontend/farm_designer/plants/plant_panel.tsx b/frontend/farm_designer/plants/plant_panel.tsx index 98ad53514..0f5560da0 100644 --- a/frontend/farm_designer/plants/plant_panel.tsx +++ b/frontend/farm_designer/plants/plant_panel.tsx @@ -1,5 +1,4 @@ import * as React from "react"; -import _ from "lodash"; import { t } from "i18next"; import { FormattedPlantInfo } from "./map_state_to_props"; import { round } from "../map/util"; @@ -12,6 +11,7 @@ import { Actions } from "../../constants"; import { Link } from "../../link"; import { DesignerPanelContent } from "./designer_panel"; import { parseIntInput } from "../../util"; +import { startCase, isNumber } from "lodash"; export interface PlantPanelProps { info: FormattedPlantInfo; @@ -149,17 +149,17 @@ export function PlantPanel(props: PlantPanelProps) {
        - {_.startCase(name)} + {startCase(name)} - {_.startCase(slug)} + {startCase(slug)} - {(updatePlant && _.isNumber(props.timeOffset) && !inSavedGarden) + {(updatePlant && isNumber(props.timeOffset) && !inSavedGarden) ? - : t(_.startCase(plantStatus))} + : t(startCase(plantStatus))}
      diff --git a/frontend/farm_designer/search_selectors.ts b/frontend/farm_designer/search_selectors.ts index 4293da211..5a32b52de 100644 --- a/frontend/farm_designer/search_selectors.ts +++ b/frontend/farm_designer/search_selectors.ts @@ -1,12 +1,11 @@ -import _ from "lodash"; import { CropLiveSearchResult } from "./interfaces"; import { t } from "i18next"; import { DEFAULT_ICON } from "../open_farm/icons"; -import { startCase } from "lodash"; +import { startCase, chain } from "lodash"; export function findBySlug( crops: CropLiveSearchResult[], slug?: string): CropLiveSearchResult { - const crop = _.chain(crops).find((result) => result.crop.slug === slug).value(); + const crop = chain(crops).find((result) => result.crop.slug === slug).value(); return crop || { crop: { name: startCase((slug || t("Name")).split("-").join(" ")), diff --git a/frontend/farm_designer/state_to_props.ts b/frontend/farm_designer/state_to_props.ts index 1db6a975a..95469319a 100644 --- a/frontend/farm_designer/state_to_props.ts +++ b/frontend/farm_designer/state_to_props.ts @@ -12,7 +12,6 @@ import { selectAllSensors, maybeGetDevice } from "../resources/selectors"; -import _ from "lodash"; import { validBotLocationData, validFwConfig, unpackUUID, shouldDisplay as shouldDisplayFunc, @@ -22,7 +21,7 @@ import { getWebAppConfigValue } from "../config_storage/actions"; import { Props } from "./interfaces"; import { TaggedPlant } from "./map/interfaces"; import { RestResources } from "../resources/interfaces"; -import { isString } from "lodash"; +import { isString, uniq, chain } from "lodash"; import { BooleanSetting } from "../session_keys"; import { Feature } from "../devices/interfaces"; import { reduceFarmwareEnv } from "../farmware/state_to_props"; @@ -66,7 +65,7 @@ export function mapStateToProps(props: Everything): Props { const { movement_step_per_mm_x, movement_step_per_mm_y } = firmwareSettings; - const peripherals = _.uniq(selectAllPeripherals(props.resources.index)) + const peripherals = uniq(selectAllPeripherals(props.resources.index)) .map(x => { const label = x.body.label; const pinStatus = x.body.pin @@ -76,7 +75,7 @@ export function mapStateToProps(props: Everything): Props { return { label, value }; }); - const latestImages = _.chain(selectAllImages(props.resources.index)) + const latestImages = chain(selectAllImages(props.resources.index)) .sortBy(x => x.body.id) .reverse() .value(); @@ -100,7 +99,7 @@ export function mapStateToProps(props: Everything): Props { calibrationZ: env["CAMERA_CALIBRATION_camera_z"], }; - const sensorReadings = _.chain(selectAllSensorReadings(props.resources.index)) + const sensorReadings = chain(selectAllSensorReadings(props.resources.index)) .sortBy(x => x.body.created_at) .reverse() .take(500) diff --git a/frontend/farm_designer/util.ts b/frontend/farm_designer/util.ts index e2ae2265f..c7de1fd8d 100644 --- a/frontend/farm_designer/util.ts +++ b/frontend/farm_designer/util.ts @@ -1,9 +1,9 @@ import axios, { AxiosPromise } from "axios"; -import _ from "lodash"; import { OpenFarm, CropSearchResult } from "./openfarm"; import { DEFAULT_ICON } from "../open_farm/icons"; import { Actions } from "../constants"; import { ExecutableType } from "farmbot/dist/resources/api_resources"; +import { get } from "lodash"; const url = (q: string) => `${OpenFarm.cropUrl}?include=pictures&filter=${q}`; const openFarmSearchQuery = (q: string): AxiosPromise => @@ -21,14 +21,14 @@ export let OFSearch = (searchTerm: string) => openFarmSearchQuery(searchTerm) .then(resp => { const images: { [key: string]: string } = {}; - _.get(resp, "data.included", FALLBACK) + get(resp, "data.included", FALLBACK) .map((item: OpenFarm.Included) => { return { id: item.id, url: item.attributes.thumbnail_url }; }) .map((val: IdURL) => images[val.id] = val.url); const payload = resp.data.data.map(datum => { const crop = datum.attributes; - const id = _.get(datum, "relationships.pictures.data[0].id", ""); + const id = get(datum, "relationships.pictures.data[0].id", ""); return { crop, image: (images[id] || DEFAULT_ICON) }; }); dispatch({ type: Actions.OF_SEARCH_RESULTS_OK, payload }); diff --git a/frontend/farmware/farmware_forms.tsx b/frontend/farmware/farmware_forms.tsx index cbdf606b8..0ea77e37c 100644 --- a/frontend/farmware/farmware_forms.tsx +++ b/frontend/farmware/farmware_forms.tsx @@ -3,10 +3,10 @@ import { Col, BlurableInput } from "../ui/index"; import { t } from "i18next"; import { FarmwareManifest, Pair, FarmwareConfig } from "farmbot"; import { getDevice } from "../device"; -import _ from "lodash"; import { ShouldDisplay, Feature, SaveFarmwareEnv, UserEnv } from "../devices/interfaces"; +import { kebabCase, toString, snakeCase } from "lodash"; export interface FarmwareFormProps { farmware: FarmwareManifest; @@ -18,7 +18,7 @@ export interface FarmwareFormProps { /** Namespace a Farmware config with the Farmware name. */ export function getConfigEnvName(farmwareName: string, configName: string) { - return `${_.snakeCase(farmwareName)}_${configName}`; + return `${snakeCase(farmwareName)}_${configName}`; } /** Farmware description and version info for help text contents. */ @@ -71,7 +71,7 @@ export function FarmwareForm(props: FarmwareFormProps): JSX.Element { /** Get a Farmware input value from FBOS. */ function getValue(farmwareName: string, currentConfig: FarmwareConfig) { return (user_env[getConfigEnvName(farmwareName, currentConfig.name)] - || _.toString(currentConfig.value)); + || toString(currentConfig.value)); } /** Execute a Farmware using the provided inputs. */ @@ -86,7 +86,7 @@ export function FarmwareForm(props: FarmwareFormProps): JSX.Element { const { farmware, user_env } = props; return -
      +