Part I of syntheticimport issues :-\

pull/1103/head
Rick Carlino 2019-02-04 08:32:26 -06:00
parent cf6cf0e2b8
commit 86fe6fba78
72 changed files with 244 additions and 252 deletions

View File

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

View File

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

View File

@ -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<typeof tr.body>):
ReduxAction<EditResourceParams> {
@ -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 {

View File

@ -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<AppProps, {}> {
private get isLoaded() {
return (MUST_LOAD.length ===
_.intersection(this.props.loaded, MUST_LOAD).length);
intersection(this.props.loaded, MUST_LOAD).length);
}
/**

View File

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

View File

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

View File

@ -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<LocationName, Record<Xyz, string>>;
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")}
</text>
{_.range(0, HISTORY_LENGTH_SECONDS + 1, 20).map(secondsAgo =>
{range(0, HISTORY_LENGTH_SECONDS + 1, 20).map(secondsAgo =>
<text key={"x_axis_label_" + secondsAgo}
x={MAX_X - secondsAgo} y={HEIGHT / 2 + BORDER_WIDTH / 3}>
{secondsAgo}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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<HTMLInputElement>) => {
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 <BlurableInput

View File

@ -1,5 +1,4 @@
import * as React from "react";
import _ from "lodash";
import { warning } from "farmbot-toastr";
import { McuInputBoxProps } from "../interfaces";
import { updateMCU } from "../actions";
@ -8,6 +7,7 @@ import {
clampUnsignedInteger, IntegerSize, getMaxInputFromIntSize
} from "../../util";
import { t } from "i18next";
import { isUndefined } from "lodash";
export class McuInputBox extends React.Component<McuInputBoxProps, {}> {
@ -20,7 +20,7 @@ export class McuInputBox extends React.Component<McuInputBoxProps, {}> {
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() : "";
}

View File

@ -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("<ConnectivityPanel/>", () => {
function test() {
@ -16,7 +16,7 @@ describe("<ConnectivityPanel/>", () => {
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: <ConnectivityPanel

View File

@ -1,7 +1,7 @@
import * as React from "react";
import { Color } from "../../ui/colors";
import _ from "lodash";
import { reservedPiGPIO } from "./list_and_label_support";
import { range, isNumber, includes, noop } from "lodash";
export interface RpiGpioDiagramProps {
boundPins: number[] | undefined;
@ -55,7 +55,7 @@ export class RpiGpioDiagram
<circle fill={Color.gray} strokeWidth={1.5} stroke={"yellow"}
cx={5} cy={4} r={2} />
{[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 <rect strokeWidth={0.5} key={`gpio_${pin}_${xi}_${yi}`}
@ -84,7 +84,7 @@ export class RpiGpioDiagram
onMouseEnter={this.hover(pin)}
onMouseLeave={this.hover(undefined)}
onClick={() =>
_.isNumber(pin) ? this.props.setSelectedPin(pin) : _.noop} />;
isNumber(pin) ? this.props.setSelectedPin(pin) : noop} />;
});
})}
<rect fill={Color.white}

View File

@ -1,6 +1,6 @@
import { t } from "i18next";
import _ from "lodash";
import { Content } from "../../constants";
import { isString } from "lodash";
/** Used for every new account the first time the Device page is loaded. */
const ONLY_ONCE = {
@ -33,7 +33,7 @@ export function inferTimezone(current: string | undefined): string {
export function timezoneMismatch(botTime: string | undefined,
userTime: string | undefined = maybeResolveTZ()): boolean {
if (_.isString(botTime) && _.isString(userTime)) {
if (isString(botTime) && isString(userTime)) {
return botTime.toUpperCase() !== userTime.toUpperCase();
} else {
// Don't show warnings if TZ data is unavailable.

View File

@ -2,7 +2,7 @@ import * as React from "react";
import { FBSelect, DropDownItem } from "../../ui/index";
import { list } from "./tz_list";
import { inferTimezone } from "./guess_timezone";
import _ from "lodash";
import { isString } from "lodash";
const CHOICES: DropDownItem[] = list.map(x => ({ label: x, value: x }));
@ -30,7 +30,7 @@ export class TimezoneSelector extends React.Component<TZSelectorProps, {}> {
}
itemSelected = (d: DropDownItem): void => {
if (_.isString(d.value)) {
if (isString(d.value)) {
this.props.onUpdate(d.value);
}
}

View File

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

View File

@ -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[] {

View File

@ -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 <div className="farm-event" key={item.sortKey}>
<div className="farm-event-date">
@ -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 <div key={moment(year, "YY").unix()}>
<div className="farm-event-year">

View File

@ -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
<image
visibility={hovered ? "visible" : "hidden"}
style={isEditing ? {} : { pointerEvents: "none" }}
onClick={_.noop}
onClick={noop}
className="hovered-plant-copy"
opacity={alpha}
x={qx - scaledRadius}

View File

@ -1,8 +1,8 @@
import * as React from "react";
import { GridProps } from "../interfaces";
import { transformXY, transformForQuadrant } from "../util";
import _ from "lodash";
import { Color } from "../../../ui/index";
import { range } from "lodash";
export function Grid(props: GridProps) {
const { mapTransformProps } = props;
@ -59,12 +59,12 @@ export function Grid(props: GridProps) {
<g id="axis-values" fontFamily="Arial" fontSize="10"
textAnchor="middle" dominantBaseline="central" fill="rgba(0, 0, 0, 0.3)">
{_.range(100, gridSize.x, 100).map((i) => {
{range(100, gridSize.x, 100).map((i) => {
const location = transformXY(i, -10, mapTransformProps);
return <text key={"x-label-" + i}
x={location.qx} y={location.qy}>{i}</text>;
})}
{_.range(100, gridSize.y, 100).map((i) => {
{range(100, gridSize.y, 100).map((i) => {
const location = transformXY(-15, i, mapTransformProps);
return <text key={"y-label-" + i}
x={location.qx} y={location.qy}>{i}</text>;

View File

@ -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(
</g>
</defs>
{_.range(0, copies).map(s => {
{range(0, copies).map(s => {
return <g
className={`water-spray delay-${s} ${animateClass}`} key={`spray-${s}`}>
<use xlinkHref="#water-circle" />
{_.range(0, 360, 15).map(rotation => {
{range(0, 360, 15).map(rotation => {
return <use xlinkHref="#water-line" key={`spray-line-${rotation}`}
transform={`rotate(${rotation}, ${cx}, ${cy})`} />;
})}
@ -110,7 +110,7 @@ function vacuumFigure(
</g>
</defs>
{_.range(0, copies).map(s => {
{range(0, copies).map(s => {
return <g
className={`vacuum delay-${s} ${animateClass}`} key={`vacuum-${s}`}>
<use xlinkHref="#vacuum-wave" />

View File

@ -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 <g className="virtual-bot-trail">
{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 <g key={i}>

View File

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

View File

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

View File

@ -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) =>
<li>
<p>
{t(_.startCase(props.title))}
{t(startCase(props.title))}
</p>
<div>
{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) =>
<InfoField key={i} title={field}>
{(_.isArray(value)
{(isArray(value)
? value.join(", ")
: value) || NO_VALUE}
</InfoField>;
@ -119,7 +119,7 @@ const handleDisplay = ([field, value]: string[], i: number) => {
const CropInfoList = (crop: OpenFarm.OFCrop) => {
return <div className="object-list">
<ul>
{_(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

View File

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

View File

@ -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) {
</label>
<ul>
<ListItem name={t("Full Name")}>
{_.startCase(name)}
{startCase(name)}
</ListItem>
<ListItem name={t("Plant Type")}>
<Link
title={t("View crop info")}
to={`/app/designer/plants/crop_search/` + slug}>
{_.startCase(slug)}
{startCase(slug)}
</Link>
</ListItem>
<ListItem name={t("Started")}>
{(updatePlant && _.isNumber(props.timeOffset) && !inSavedGarden)
{(updatePlant && isNumber(props.timeOffset) && !inSavedGarden)
? <EditDatePlanted
uuid={uuid}
datePlanted={plantedAt}
@ -183,7 +183,7 @@ export function PlantPanel(props: PlantPanelProps) {
uuid={uuid}
plantStatus={plantStatus}
updatePlant={updatePlant} />
: t(_.startCase(plantStatus))}
: t(startCase(plantStatus))}
</ListItem>
</ul>
<MoveToPlant x={x} y={y} dispatch={dispatch} isEditing={isEditing} />

View File

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

View File

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

View File

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

View File

@ -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 <Col key={farmware.name}>
<div className={_.kebabCase(farmware.name)}>
<div className={kebabCase(farmware.name)}>
<button
className="fb-button green farmware-button"
onClick={() => run(farmware.name, farmware.config)}>

View File

@ -1,5 +1,4 @@
import * as React from "react";
import _ from "lodash";
import moment from "moment";
import { t } from "i18next";
import { success, error } from "farmbot-toastr";
@ -14,6 +13,7 @@ import {
downloadProgress
} from "../../devices/components/fbos_settings/os_update_button";
import { JobProgress, TaggedImage } from "farmbot";
import { startCase } from "lodash";
interface MetaInfoProps {
/** Default conversion is `attr_name ==> Attr Name`.
@ -26,7 +26,7 @@ interface MetaInfoProps {
}
function MetaInfo({ obj, attr, label }: MetaInfoProps) {
const top = label || _.startCase(attr.split("_").join());
const top = label || startCase(attr.split("_").join());
const bottom = safeStringFetch(obj, attr);
return <div>
<label>{top}:</label>

View File

@ -6,7 +6,6 @@ import {
FarmwareProps, Feature, SaveFarmwareEnv, UserEnv
} from "../devices/interfaces";
import { prepopulateEnv } from "./weed_detector/remote_env/selectors";
import _ from "lodash";
import {
selectAllFarmwareEnvs, selectAllFarmwareInstallations
} from "../resources/selectors_by_kind";
@ -20,6 +19,7 @@ import { TaggedFarmwareEnv, FarmwareManifest, JobProgress } from "farmbot";
import { save, edit, initSave } from "../api/crud";
import { t } from "i18next";
import { getWebAppConfig } from "../resources/getters";
import { chain, cloneDeep } from "lodash";
/** Edit an existing Farmware env variable or add a new one. */
export const saveOrEditFarmwareEnv = (ri: ResourceIndex): SaveFarmwareEnv =>
@ -48,7 +48,7 @@ export const reduceFarmwareEnv =
};
export function mapStateToProps(props: Everything): FarmwareProps {
const images = _.chain(selectAllImages(props.resources.index))
const images = chain(selectAllImages(props.resources.index))
.sortBy(x => x.body.id)
.reverse()
.value();
@ -56,7 +56,7 @@ export function mapStateToProps(props: Everything): FarmwareProps {
const currentImage = images
.filter(i => i.uuid === props.resources.consumers.farmware.currentImage)[0]
|| firstImage;
const { farmwares } = _.cloneDeep(props.bot.hardware.process_info);
const { farmwares } = cloneDeep(props.bot.hardware.process_info);
const conf = getWebAppConfig(props.resources.index);
const { currentFarmware, firstPartyFarmwareNames } =
props.resources.consumers.farmware;
@ -107,7 +107,7 @@ export function mapStateToProps(props: Everything): FarmwareProps {
const jobs = props.bot.hardware.jobs || {};
const imageJobNames = Object.keys(jobs).filter(x => x != "FBOS_OTA");
const imageJobs: JobProgress[] =
_.chain(betterCompact(imageJobNames.map(x => jobs[x])))
chain(betterCompact(imageJobNames.map(x => jobs[x])))
.sortBy("time")
.reverse()
.value();

View File

@ -1,4 +1,3 @@
import _ from "lodash";
import axios from "axios";
import { t } from "i18next";
import { success, error } from "farmbot-toastr";
@ -6,7 +5,7 @@ import { Thunk } from "../../redux/interfaces";
import { API } from "../../api";
import { Progress, ProgressCallback, trim } from "../../util";
import { getDevice } from "../../device";
import { noop } from "lodash";
import { noop, chunk } from "lodash";
import { GenericPointer } from "farmbot/dist/resources/api_resources";
import { Actions } from "../../constants";
@ -21,12 +20,12 @@ export function deletePoints(
const ids = resp.data.map(x => x.id);
// If you delete too many points, you will violate the URL length
// limitation of 2,083. Chunking helps fix that.
const chunks = _.chunk(ids, 179 /* Prime numbers, why not? */);
const chunks = chunk(ids, 179 /* Prime numbers, why not? */);
const prog = new Progress(chunks.length, cb || noop);
prog.inc();
const promises = chunks.map(function (chunk) {
const promises = chunks.map(function (c) {
return axios
.delete(API.current.pointsPath + chunk.join(","))
.delete(API.current.pointsPath + c.join(","))
.then(function (x) {
prog.inc();
return x;

View File

@ -6,13 +6,13 @@ import {
FBSelect, NULL_CHOICE, DropDownItem
} from "../../ui/index";
import { SettingsMenuProps } from "./interfaces";
import _ from "lodash";
import {
SPECIAL_VALUE_DDI, CALIBRATION_DROPDOWNS, ORIGIN_DROPDOWNS
} from "./constants";
import { WD_ENV } from "./remote_env/interfaces";
import { envGet } from "./remote_env/selectors";
import { SPECIAL_VALUES } from "./remote_env/constants";
import { isNumber } from "lodash";
export class WeedDetectorConfig extends React.Component<SettingsMenuProps, {}> {
NumberBox = ({ conf, label }: {
@ -32,7 +32,7 @@ export class WeedDetectorConfig extends React.Component<SettingsMenuProps, {}> {
};
setDDI = (k: keyof WD_ENV) => (d: DropDownItem) => {
if (_.isNumber(d.value)) {
if (isNumber(d.value)) {
this.props.onChange(k, d.value);
} else {
throw new Error("Weed detector got a non-numeric value");

View File

@ -1,8 +1,8 @@
import * as React from "react";
import { Hue, Saturation } from "react-color/lib/components/common";
import { FarmbotPickerProps } from "./interfaces";
import _ from "lodash";
import { Color } from "../../ui/index";
import { noop } from "lodash";
/** Wrapper class around `react-color`'s `<Saturation />` and `<Hue />`.
* Add an extra white box feature for showing user weed detection settings.
@ -108,7 +108,7 @@ export class FarmbotColorPicker extends React.Component<FarmbotPickerProps, {}>
<Hue
{...dontTouchThis}
pointer={this.customPointer}
onChange={_.noop} />
onChange={noop} />
{getHueBoxes(this.props.h, !!this.props.invertHue)
.map((box, i) => <div key={i} style={box} />)}
</div>
@ -117,7 +117,7 @@ export class FarmbotColorPicker extends React.Component<FarmbotPickerProps, {}>
<Saturation
{...dontTouchThis}
pointer={this.customPointer}
onChange={_.noop} />
onChange={noop} />
<div style={this.saturationboxCSS()} />
</div>
</div>;

View File

@ -1,6 +1,6 @@
import { box } from "boxed_value";
import _ from "lodash";
import { WDENVKey, Translation, FormatTranslationMap } from "./interfaces";
import { snakeCase, get, isUndefined } from "lodash";
/** I would rather not deal with all the weird edge cases that come with
* supporting strings and numbers right now. It adds too many edge cases for the
@ -97,10 +97,10 @@ export const TRANSLATORS: FormatTranslationMap = {};
export function getSpecialValue(key: string | number):
SPECIAL_VALUES {
const k = _.snakeCase(("" + key).toUpperCase()).toUpperCase();
const v = _.get(SPECIAL_VALUES, k, NaN);
const k = snakeCase(("" + key).toUpperCase()).toUpperCase();
const v = get(SPECIAL_VALUES, k, NaN);
if (_.isUndefined(v) || _.isNaN(v)) {
if (isUndefined(v) || isNaN(v)) {
throw new Error("Not a SPECIAL_VALUE: " + k);
} else {
return v;

View File

@ -2,9 +2,8 @@
import { WDENVKey, WD_ENV } from "./interfaces";
import { WD_KEY_DEFAULTS, EVERY_WD_KEY } from "./constants";
import { defensiveClone, betterParseNum } from "../../../util";
import _ from "lodash";
import { parseEnvKey } from "./translators";
import { isNumber } from "lodash";
import { isNumber, isString } from "lodash";
import { UserEnv } from "../../../devices/interfaces";
/** Given a half formed set of weed detector environment variables, creates a
@ -15,7 +14,7 @@ export function prepopulateEnv(env: UserEnv): WD_ENV {
EVERY_WD_KEY.map(key => {
const initial = env[key];
let val: string;
if (_.isString(initial)) {
if (isString(initial)) {
val = initial;
} else {
val = "" + WD_KEY_DEFAULTS[key];

View File

@ -1,7 +1,6 @@
import * as React from "react";
import axios from "axios";
import { t } from "i18next";
import _ from "lodash";
import { error as log, success, init as logInit } from "farmbot-toastr";
import { AuthState } from "../auth/interfaces";
import { prettyPrintApiErrors, attachToRoot } from "../util";
@ -16,6 +15,7 @@ import { CreateAccount } from "./create_account";
import { Content } from "../constants";
import { LaptopSplash } from "./laptop_splash";
import { TermsCheckbox } from "./terms_checkbox";
import { get } from "lodash";
export const attachFrontPage =
() => attachToRoot(FrontPage, {});
@ -85,7 +85,7 @@ export class FrontPage extends React.Component<{}, Partial<FrontPageState>> {
Session.replaceToken(resp.data);
window.location.href = "/app/controls";
}).catch((error: Error) => {
switch (_.get(error, "response.status")) {
switch (get(error, "response.status")) {
case 451: // TOS was updated; User must agree to terms.
window.location.assign("/tos_update");
break;

View File

@ -1,5 +1,4 @@
import * as React from "react";
import _ from "lodash";
import { t } from "i18next";
import { links } from "./nav/nav_links";
import { sync } from "./devices/actions";
@ -13,6 +12,7 @@ import {
Overlay,
Classes
} from "@blueprintjs/core";
import { findIndex } from "lodash";
interface Props {
dispatch: Function;
@ -65,7 +65,7 @@ export class HotKeys extends React.Component<Props, Partial<State>> {
this.setState({ [property]: !this.state[property] });
private hotkeys(dispatch: Function, slug: string) {
const idx = _.findIndex(links, { slug });
const idx = findIndex(links, { slug });
const right = "/app/" + (links[idx + 1] || links[0]).slug;
const left = "/app/" + (links[idx - 1] || links[links.length - 1]).slug;
const hotkeyMap: IHotkeyProps[] = [

View File

@ -1,6 +1,6 @@
import { DataChangeType, Dictionary } from "farmbot/dist";
import { box } from "boxed_value";
import _ from "lodash";
import { isNumber, isNaN } from "lodash";
export let METHOD_MAP: Dictionary<DataChangeType> = {
"post": "add",
@ -18,9 +18,9 @@ export function inferUpdateId(url: string) {
.split("/")
.filter(x => !x.includes(",")) // Don't allow batch endpoints to participate.
.map(x => parseInt(x, 10))
.filter(x => !_.isNaN(x));
.filter(x => !isNaN(x));
const id: number | undefined = ids[0];
const isNum = _.isNumber(id);
const isNum = isNumber(id);
const onlyOne = ids.length === 1;
return (isNum && onlyOne) ? ("" + id) : "*";
} catch (error) { // Don't crash - just keep moving along. This is a temp patch.

View File

@ -6,25 +6,25 @@ import {
} from "./interceptor_support";
import { API } from "./api/index";
import { AuthState } from "./auth/interfaces";
import _ from "lodash";
import { AxiosRequestConfig, AxiosResponse } from "axios";
import { Content } from "./constants";
import { dispatchNetworkUp, dispatchNetworkDown } from "./connectivity/index";
import { Dictionary } from "farmbot";
import { outstandingRequests } from "./connectivity/data_consistency";
import { Session } from "./session";
import { get } from "lodash";
export function responseFulfilled(input: AxiosResponse): AxiosResponse {
dispatchNetworkUp("user.api", undefined, "responseFulfilled()");
return input;
}
/** These will raise type errors if our _.get usage ever requires changing. */
/** These will raise type errors if our get usage ever requires changing. */
const request: keyof SafeError = "request";
const responseUrl: keyof SafeError["request"] = "responseURL";
export const isLocalRequest = (x: SafeError) =>
_.get(x, [request, responseUrl], "").includes(API.current.baseUrl);
get(x, [request, responseUrl], "").includes(API.current.baseUrl);
let ONLY_ONCE = true;
export function responseRejected(x: SafeError | undefined) {
@ -33,7 +33,7 @@ export function responseRejected(x: SafeError | undefined) {
const a = ![451, 401, 422].includes(x.response.status);
const b = x.response.status > 399;
// Openfarm API was sending too many 404's.
const c = !_.get(x, "response.config.url", "").includes("openfarm.cc/");
const c = !get(x, "response.config.url", "").includes("openfarm.cc/");
if (a && b && c) {
setTimeout(() => {
// Explicitly throw error so error reporting tool will save it.

View File

@ -1,9 +1,9 @@
import * as React from "react";
import { LogsFilterMenuProps } from "../interfaces";
import _ from "lodash";
import { Slider } from "@blueprintjs/core";
import { t } from "i18next";
import { Filters } from "../interfaces";
import { startCase } from "lodash";
export const LogsFilterMenu = (props: LogsFilterMenuProps) => {
/** Filter level 0: logs hidden. */
@ -32,7 +32,7 @@ export const LogsFilterMenu = (props: LogsFilterMenuProps) => {
return <fieldset key={logType}>
<label>
<div className={`saucer ${logType}`} />
{t(_.startCase(logType))}
{t(startCase(logType))}
</label>
<button
className={"fb-button fb-toggle-button " + btnColor(logType)}

View File

@ -1,6 +1,5 @@
import { Everything } from "../interfaces";
import { selectAllLogs, maybeGetTimeOffset } from "../resources/selectors";
import _ from "lodash";
import { LogsProps } from "./interfaces";
import {
sourceFbosConfigValue
@ -10,11 +9,12 @@ import { ResourceIndex } from "../resources/interfaces";
import { TaggedLog } from "farmbot";
import { getWebAppConfigValue } from "../config_storage/actions";
import { getFbosConfig } from "../resources/getters";
import { chain } from "lodash";
/** Take the specified number of logs after sorting by time created. */
export function takeSortedLogs(
numberOfLogs: number, ri: ResourceIndex): TaggedLog[] {
return _.chain(selectAllLogs(ri))
return chain(selectAllLogs(ri))
.sortBy("body.created_at")
.reverse()
.take(numberOfLogs)

View File

@ -1,4 +1,3 @@
import "../css/_index.scss";
import { detectLanguage } from "../i18n";
import * as I18n from "i18next";
import { onInit } from "./on_init";

View File

@ -1,27 +1,27 @@
import { configureStore } from "../store";
import * as _ from "lodash";
import { get, set } from "lodash";
describe("configureStore", () => {
it("calls the appropriate ENV", () => {
const result1 = configureStore();
const old = _.get(process.env, "NODE_ENV", "development");
_.set(process.env, "NODE_ENV", "production");
const old = get(process.env, "NODE_ENV", "development");
set(process.env, "NODE_ENV", "production");
const result2 = configureStore();
_.set(process.env, "NODE_ENV", old);
set(process.env, "NODE_ENV", old);
expect(result1).not.toBe(result2);
});
it("Does not crash if process.env.NODE_ENV is undefined", () => {
const old = _.get(process.env, "NODE_ENV", "development");
_.set(process.env, "NODE_ENV", "");
const old = get(process.env, "NODE_ENV", "development");
set(process.env, "NODE_ENV", "");
const result1 = configureStore();
expect(result1)
.toEqual(expect.objectContaining({ getState: expect.anything() }));
_.set(process.env, "NODE_ENV", old);
set(process.env, "NODE_ENV", old);
});
it("does not crash on malformed states", () => {

View File

@ -1,11 +1,11 @@
import moment from "moment";
import _ from "lodash";
import { isNumber, padStart } from "lodash";
export function msToTime(ms: number) {
if (_.isNumber(ms)) {
if (isNumber(ms)) {
const d = moment.duration(ms);
const h = _.padStart(d.hours().toString(), 2, "0");
const m = _.padStart(d.minutes().toString(), 2, "0");
const h = padStart(d.hours().toString(), 2, "0");
const m = padStart(d.minutes().toString(), 2, "0");
return `${h}:${m}`;
} else {
return "00:01";

View File

@ -1,4 +1,4 @@
import _ from "lodash";
import { times } from "lodash";
import { Dictionary, TaggedResource } from "farmbot";
import { Week, DAYS } from "./bulk_scheduler/interfaces";
import { generateReducer } from "../redux/generate_reducer";
@ -28,7 +28,7 @@ function newWeek() {
function newState(): RegimenState {
return {
dailyOffsetMs: 300000,
weeks: _.times(10, newWeek),
weeks: times(10, newWeek),
selectedSequenceUUID: undefined,
currentRegimen: undefined
};

View File

@ -20,8 +20,8 @@ import {
randomColor, determineInstalledOsVersion,
shouldDisplay as shouldDisplayFunc
} from "../util";
import _ from "lodash";
import { resourceUsageList } from "../resources/in_use";
import { groupBy, chain } from "lodash";
export function mapStateToProps(props: Everything): Props {
const { resources, dispatch, bot } = props;
@ -81,9 +81,9 @@ function generateCalendar(regimen: TaggedRegimen,
dispatch: Function): CalendarRow[] {
const mapper = createRows(index, dispatch, regimen);
const rows = regimen.body.regimen_items.map(mapper);
const dict = _.groupBy(rows, "day");
const dict = groupBy(rows, "day");
const makeRows = (day: string): CalendarRow => ({ day: day, items: dict[day] });
const days = _.chain(dict)
const days = chain(dict)
.keys()
.map(x => parseInt(x))
.sort((a, b) => a - b)
@ -92,7 +92,7 @@ function generateCalendar(regimen: TaggedRegimen,
return days
.map(makeRows)
.map((x) => {
x.items = _.chain(x.items).sortBy(SORT_KEY).value();
x.items = chain(x.items).sortBy(SORT_KEY).value();
return x;
});
}

View File

@ -13,10 +13,10 @@ import {
fakeSequence,
fakePlant
} from "../../__test_support__/fake_state/resources";
import * as _ from "lodash";
import { resourceReducer } from "../reducer";
import { emptyState } from "../reducer";
import { resourceReady, newTaggedResource } from "../../sync/actions";
import { chain } from "lodash";
// import { Actions } from "../../constants";
const TOOL_ID = 99;
@ -77,7 +77,7 @@ describe("selectAllLogs", () => {
it("stays truthful to its name by finding all logs", () => {
const results = Selector.selectAllLogs(fakeIndex);
expect(results.length).toBeGreaterThan(0);
const kinds = _.chain(results).map("kind").uniq().value();
const kinds = chain(results).map("kind").uniq().value();
expect(kinds.length).toEqual(1);
expect(kinds[0]).toEqual("Log");
});

View File

@ -1,4 +1,3 @@
import _ from "lodash";
import { ResourceIndex } from "./interfaces";
import {
ResourceName,
@ -26,6 +25,7 @@ import { findAllById } from "./selectors_by_id";
import { findPoints, selectAllPoints, selectAllActivePoints } from "./selectors_by_kind";
import { assertUuid } from "./util";
import { joinKindAndId } from "./reducer_support";
import { chain } from "lodash";
export * from "./selectors_by_id";
export * from "./selectors_by_kind";
@ -57,7 +57,7 @@ export let findId = (index: ResourceIndex, kind: ResourceName, id: number) => {
export let isKind = (name: ResourceName) => (tr: TaggedResource) => tr.kind === name;
export function groupPointsByType(index: ResourceIndex) {
return _.chain(selectAllActivePoints(index))
return chain(selectAllActivePoints(index))
// If this fails to compile....
.tap(x => x[0].body.pointer_type)
// ... this line must be updated:

View File

@ -16,8 +16,7 @@ import {
TaggedToolSlotPointer,
} from "farmbot";
import { ResourceIndex } from "./interfaces";
import { isNumber } from "lodash";
import _ from "lodash";
import { isNumber, find } from "lodash";
import { joinKindAndId } from "./reducer_support";
import { findAll } from "./find_all";
@ -84,7 +83,7 @@ export let findSlotByToolId = (index: ResourceIndex, tool_id: number) => {
const every = Object
.keys(index.references)
.map(x => index.references[x]);
const tts = _.find(every, query);
const tts = find(every, query);
if (tts && !isNumber(tts) && isTaggedToolSlotPointer(tts) && sanityCheck(tts)) {
return tts;
} else {

View File

@ -1,7 +1,7 @@
import { ResourceName } from "farmbot";
import { Dictionary } from "farmbot/dist";
import { betterCompact } from "../util";
import _ from "lodash";
import { isArray } from "lodash";
import { ResourceIndex } from "./interfaces";
import { joinKindAndId } from "./reducer_support";
@ -11,12 +11,12 @@ export function generateUuid(id: number | undefined, kind: ResourceName) {
}
export function arrayWrap<T>(input: T | (T[])): T[] {
return _.isArray(input) ? input : [input];
return isArray(input) ? input : [input];
}
/** For when you have an array that is guaranteed to have a length of 1 */
export function arrayUnwrap<T>(input: T | T[]): T {
return _.isArray(input) ? input[0] : input;
return isArray(input) ? input[0] : input;
}
export function entries<T>(input: Dictionary<T | undefined>): T[] {

View File

@ -7,9 +7,8 @@ import { betterCompact } from "../../util";
import { TaggedTool, TaggedPoint } from "farmbot";
import { DropDownItem } from "../../ui";
import { Vector3 } from "farmbot/dist";
import _ from "lodash";
import { t } from "i18next";
import { capitalize } from "lodash";
import { capitalize, chain } from "lodash";
import { joinKindAndId } from "../../resources/reducer_support";
import { Point } from "farmbot/dist/resources/api_resources";
@ -71,7 +70,7 @@ export function locationFormList(resources: ResourceIndex,
.map(({ tool, location }) => formatTools(tool, location))
.filter(x => parseInt("" + x.value) > 0);
const group = maybeGroup(!!displayGroups);
return _.chain(heading("Tool"))
return chain(heading("Tool"))
.concat(toolDDI)
.concat(group(everyPointDDI("Tool")))
.concat(group(everyPointDDI("ToolSlot")))

View File

@ -20,7 +20,6 @@ import {
celery2DropDown,
BoxLed,
} from "../pin_and_peripheral_support";
import * as _ from "lodash";
import {
fakePeripheral,
fakeSensor,
@ -32,6 +31,7 @@ import {
} from "farmbot";
import { StepParams } from "../../interfaces";
import { Actions } from "../../../constants";
import { chain } from "lodash";
describe("Pin and Peripheral support files", () => {
const newIndex = () => {
@ -61,7 +61,7 @@ describe("Pin and Peripheral support files", () => {
.toBe(PIN_RANGE.length + 1); // 54 pins plus the header.
expect(pinDropdowns(n => n)[0]).toBe(PIN_HEADING);
// Grab all uniq heading IDs- we expect only 1.
const values = _.chain(pinDropdowns(n => n))
const values = chain(pinDropdowns(n => n))
.tail()
.map((x: DropDownItem) => x.headingId)
.uniq()

View File

@ -16,13 +16,13 @@ import { TileSendMessage } from "./tile_send_message";
import { TileWritePin } from "./tile_write_pin";
import { TileExecuteScript } from "./tile_execute_script";
import { TileTakePhoto } from "./tile_take_photo";
import _ from "lodash";
import { overwrite } from "../../api/crud";
import { TileFindHome } from "./tile_find_home";
import { t } from "i18next";
import { MarkAs } from "./mark_as";
import { TileUnknown } from "./tile_unknown";
import { forceSetStepTag } from "../../resources/sequence_tagging";
import { compact, assign } from "lodash";
interface MoveParams {
step: Step;
@ -41,7 +41,7 @@ export function move({ step, sequence, to, from }: MoveParams) {
} else {
seq.body.splice(to, 0, defensiveClone(copy));
delete seq.body[from];
seq.body = _.compact(seq.body);
seq.body = compact(seq.body);
}
return overwrite(sequence, next.body);
}
@ -76,7 +76,7 @@ export function remove(props: RemoveParams) {
const update = defensiveClone(original);
update.body.body = (update.body.body || []);
delete update.body.body[index];
update.body.body = _.compact(update.body.body);
update.body.body = compact(update.body.body);
dispatch(overwrite(original, update.body));
}
}
@ -93,7 +93,7 @@ export function updateStep(props: StepInputProps) {
if (isNumeric) {
numericNonsense(val, stepCopy, field);
} else {
_.assign(stepCopy.args, { [field]: val });
assign(stepCopy.args, { [field]: val });
}
seqCopy.body[index] = stepCopy;
@ -122,7 +122,7 @@ function numericNonsense(val: string, copy: CeleryNode, field: LegalArgString) {
const parsedNumber = FLOAT_NUMERIC_FIELDS.includes(field)
? parseFloat(val)
: parseInt(val, 10);
return _.assign(copy.args, { [field]: parsedNumber });
return assign(copy.args, { [field]: parsedNumber });
}
export function renderCeleryNode(props: StepParams) {

View File

@ -1,4 +1,3 @@
import _ from "lodash";
import * as React from "react";
import { StepParams } from "../interfaces";
import { t } from "i18next";
@ -17,6 +16,7 @@ import {
addOrEditVarDeclaration, declarationList
} from "../locals_list/declaration_support";
import { AllowedDeclaration } from "../locals_list/locals_list_support";
import { isNumber } from "lodash";
/** Replaces the execute step body with a new array of declarations. */
const assignVariable = (props: ExecBlockParams) =>
@ -72,7 +72,7 @@ export class RefactoredExecuteBlock
step: currentStep,
index: index,
executor: (step: Execute) => {
if (_.isNumber(input.value)) {
if (isNumber(input.value)) {
step.args.sequence_id = input.value;
const sequenceUuid = findSequenceById(resources, input.value).uuid;
step.body = declarationList(resources.sequenceMetas[sequenceUuid]);

View File

@ -1,4 +1,3 @@
import _ from "lodash";
import * as React from "react";
import { IfParams, LHSOptions, operatorOptions } from "./index";
import { t } from "i18next";
@ -14,6 +13,7 @@ import {
import { ALLOWED_OPS } from "farmbot/dist";
import { updateLhs } from "./update_lhs";
import { displayLhs } from "./display_lhs";
import { isString } from "lodash";
const IS_UNDEFINED: ALLOWED_OPS = "is_undefined";
const label_ops: Record<ALLOWED_OPS, string> = {
@ -42,7 +42,7 @@ export function If_(props: IfParams) {
const seqCopy = defensiveClone(sequence).body;
const val = e.value;
seqCopy.body = seqCopy.body || [];
if (_.isString(val)) {
if (isString(val)) {
stepCopy.args[field] = val;
}
seqCopy.body[index] = stepCopy;

View File

@ -1,4 +1,3 @@
import _ from "lodash";
import * as React from "react";
import { t } from "i18next";
import { DropDownItem, NULL_CHOICE } from "../../../ui/index";
@ -18,6 +17,7 @@ import {
sensorsAsDropDowns, peripheralsAsDropDowns, pinDropdowns
} from "../pin_and_peripheral_support";
import { ShouldDisplay, Feature } from "../../../devices/interfaces";
import { isNumber, isString } from "lodash";
export interface IfParams {
currentSequence: TaggedSequence;
@ -60,7 +60,7 @@ export function seqDropDown(i: ResourceIndex) {
selectAllSequences(i)
.map(function (x) {
const { body } = x;
if (_.isNumber(body.id)) {
if (isNumber(body.id)) {
results.push({ label: body.name, value: body.id });
}
});
@ -72,7 +72,7 @@ export function initialValue(input: Execute | Nothing, index: ResourceIndex) {
case "execute":
const id = input.args.sequence_id;
const seq = findSequenceById(index, id).body;
if (_.isNumber(seq.id)) {
if (isNumber(seq.id)) {
return { label: seq.name, value: seq.id };
} else {
throw new Error("Failed seq id type assertion.");
@ -134,7 +134,7 @@ export let IfBlockDropDownHandler = (props: IfParams,
} else {
const value = (block.kind === "execute") && block.args.sequence_id;
const label = value && findSequenceById(props.resources, value).body.name;
if (_.isNumber(value) && _.isString(label)) {
if (isNumber(value) && isString(label)) {
return { label, value };
} else {
throw new Error("Failed type assertion");
@ -151,7 +151,7 @@ export let IfBlockDropDownHandler = (props: IfParams,
}
function onChange(e: DropDownItem) {
if (e.value && _.isNumber(e.value)) {
if (e.value && isNumber(e.value)) {
const v = e.value;
overwriteStep({ kind: "execute", args: { sequence_id: v } });
} else {

View File

@ -1,4 +1,3 @@
import _ from "lodash";
import * as React from "react";
import { t } from "i18next";
import { Component } from "react";
@ -41,6 +40,7 @@ import {
} from "../../resources/sequence_meta";
import { LocationForm } from "../locals_list/location_form";
import { AllowedDeclaration } from "../locals_list/locals_list_support";
import { merge, some } from "lodash";
/** Union of all types found in a move_abs "args" attribute. */
export type LocationData = MoveAbsolute["args"]["location"];
@ -114,7 +114,7 @@ export class TileMoveAbsolute extends Component<StepParams, MoveAbsState> {
(e: React.SyntheticEvent<HTMLInputElement>) => {
const num = parseFloat(e.currentTarget.value);
const update = { [place]: { args: { [axis]: num } } };
this.updateArgs(_.merge({}, this.args, update));
this.updateArgs(merge({}, this.args, update));
}
/** Determine if location conflicts with bot settings. */
@ -231,7 +231,7 @@ export class TileMoveAbsolute extends Component<StepParams, MoveAbsState> {
dispatch={dispatch}
index={index}
confirmStepDeletion={this.props.confirmStepDeletion}>
{_.some(this.settingConflicts) &&
{some(this.settingConflicts) &&
<StepWarning
warning={this.settingConflictWarning}
conflicts={this.settingConflicts} />}

View File

@ -1,9 +1,9 @@
import { t } from "i18next";
import { editStep } from "../../api/crud";
import _ from "lodash";
import { WritePin, SequenceBodyItem } from "farmbot";
import { DropDownItem } from "../../ui/index";
import { StepParams } from "../interfaces";
import { isNumber } from "lodash";
export const PIN_MODES = [
{ value: 1, label: t("Analog") },
@ -42,7 +42,7 @@ export function setPinMode(
step: currentStep,
index: index,
executor: (step: WritePin) => {
if (_.isNumber(x.value)) {
if (isNumber(x.value)) {
step.args.pin_mode = x.value;
} else {
throw new Error("Numbers only in pin_mode.");
@ -58,7 +58,7 @@ export function setPinValue(
step: currentStep,
index: index,
executor: (step: WritePin) => {
if (_.isNumber(x.value)) {
if (isNumber(x.value)) {
step.args.pin_value = x.value;
} else {
throw new Error("Numbers only in pin_value.");

View File

@ -3,7 +3,6 @@ import { FBSelect, DropDownItem, Row, Col } from "../../ui/index";
import { t } from "i18next";
import { StepInputBox } from "../inputs/step_input_box";
import { SendMessage, TaggedSequence } from "farmbot";
import _ from "lodash";
import { StepParams, ChannelName } from "../interfaces";
import { ResourceIndex } from "../../resources/interfaces";
import { editStep } from "../../api/crud";
@ -15,6 +14,7 @@ import {
MESSAGE_STATUSES_DDI
} from "./tile_send_message_support";
import { StepWrapper, StepHeader, StepContent } from "../step_ui/index";
import { isString } from "lodash";
export function TileSendMessage(props: StepParams) {
if (props.currentStep.kind === "send_message") {
@ -84,7 +84,7 @@ export class RefactoredSendMessage
step: this.step,
index: this.index,
executor: (step: SendMessage) => {
if (_.isString(x.value)) {
if (isString(x.value)) {
step.args.message_type = x.value;
} else {
throw new Error("Strings only in send_message.");

View File

@ -36,10 +36,8 @@ export const newTaggedResource = <T extends TR>(kind: T["kind"],
});
};
console.log("Yes, HMR works on refresh");
function fail(e: Error) {
console.log("WEE OOO");
console.error("DATA SYNC ERROR!!");
Session.clear();
throw e;
}

View File

@ -1,6 +1,5 @@
import { Everything } from "../interfaces";
import { Props } from "./interfaces";
import _ from "lodash";
import {
selectAllToolSlotPointers,
selectAllTools,
@ -13,6 +12,7 @@ import { edit } from "../api/crud";
import { DropDownItem, NULL_CHOICE } from "../ui";
import { validBotLocationData } from "../util";
import { TaggedTool, TaggedToolSlotPointer } from "farmbot";
import { chain, isNumber, noop } from "lodash";
export function mapStateToProps(props: Everything): Props {
const toolSlots = selectAllToolSlotPointers(props.resources.index);
@ -23,17 +23,17 @@ export function mapStateToProps(props: Everything): Props {
/** Returns all tools in an <FBSelect /> compatible format. */
const getToolOptions = () => {
return _.chain(tools)
return chain(tools)
.map(tool => ({
label: tool.body.name || "untitled",
value: (tool.body.id as number)
}))
.filter(ddi => _.isNumber(ddi.value) && ddi.value > 0)
.filter(ddi => isNumber(ddi.value) && ddi.value > 0)
.compact()
.value();
};
const activeTools = _.chain(toolSlots).map(x => x.body.tool_id).compact().value();
const activeTools = chain(toolSlots).map(x => x.body.tool_id).compact().value();
const isActive =
(t: TaggedTool) => !!(t.body.id && activeTools.includes(t.body.id));
@ -72,7 +72,7 @@ export function mapStateToProps(props: Everything): Props {
getToolByToolSlotUUID,
changeToolSlot,
isActive,
dispatch: _.noop,
dispatch: noop,
botPosition,
};

View File

@ -1,7 +1,7 @@
import { Dictionary } from "farmbot";
import { t } from "i18next";
import _ from "lodash";
import { Content } from "../constants";
import { capitalize, map } from "lodash";
export interface AxiosErrorResponse {
response?: {
@ -13,7 +13,7 @@ export interface AxiosErrorResponse {
const mapper = (v: string, k: string) => {
// "Reason: Explanation lorem ipsum dolor ipsum."
const reason = _.capitalize(("" + k).split("_").join(" "));
const reason = capitalize(("" + k).split("_").join(" "));
const explanation = v.toString();
return t(`${reason}: ${explanation}`);
@ -23,7 +23,7 @@ const mapper = (v: string, k: string) => {
* pairs returned by the /api/xyz endpoint. */
export function prettyPrintApiErrors(err: AxiosErrorResponse) {
const errors = safelyFetchErrors(err);
return _.map(errors, mapper).join(" ");
return map(errors, mapper).join(" ");
}
function safelyFetchErrors(err: AxiosErrorResponse): Dictionary<string> {

View File

@ -1,4 +1,3 @@
import _ from "lodash";
import { parseIntInput } from "./util";
/** The firmware will have an integer overflow if you don't check this one. */
@ -31,7 +30,7 @@ export function clampUnsignedInteger(
const result = parseIntInput(input);
// Clamp to prevent overflow.
if (_.isNaN(result)) { return { outcome: "malformed", result: undefined }; }
if (isNaN(result)) { return { outcome: "malformed", result: undefined }; }
const max = getMaxInputFromIntSize(size);
if (result > max) { return { outcome: "high", result: max }; }
if (result < MIN_INPUT) { return { outcome: "low", result: MIN_INPUT }; }

View File

@ -1,5 +1,4 @@
import { t } from "i18next";
import _ from "lodash";
import { ResourceColor } from "../interfaces";
import { box } from "boxed_value";
import {
@ -10,6 +9,13 @@ import {
ResourceName,
} from "farmbot";
import { BotLocationData } from "../devices/interfaces";
import {
sample,
padStart,
sortBy,
merge,
isNumber
} from "lodash";
export let colors: Array<ResourceColor> = [
"blue",
@ -24,7 +30,7 @@ export let colors: Array<ResourceColor> = [
/** Picks a color that is compliant with sequence / regimen color codes */
export function randomColor(): ResourceColor {
return _.sample(colors) as typeof colors[0];
return sample(colors) as typeof colors[0];
}
export function defensiveClone<T>(target: T): T {
@ -62,7 +68,7 @@ export function fancyDebug<T extends {}>(d: T): T {
.keys(d)
.map(key => [key, (d as Dictionary<string>)[key]])
.map((x) => {
const key = _.padStart(x[0], 20, " ");
const key = padStart(x[0], 20, " ");
const val = (JSON.stringify(x[1]) || "Nothing").slice(0, 52);
return `${key} => ${val}`;
@ -82,10 +88,10 @@ export type CowardlyDictionary<T> = Dictionary<T | undefined>;
export const NOT_SAVED = -1;
export function isUndefined(x: object | undefined): x is undefined {
return _.isUndefined(x);
return isUndefined(x);
}
/** Better than Array.proto.filter and _.compact() because the type checker
/** Better than Array.proto.filter and compact() because the type checker
* knows what's going on.
*/
export function betterCompact<T>(input: (T | undefined)[]): T[] {
@ -96,11 +102,11 @@ export function betterCompact<T>(input: (T | undefined)[]): T[] {
/** Sorts a list of tagged resources. Unsaved resource get put on the end. */
export function sortResourcesById<T extends TaggedResource>(input: T[]): T[] {
return _.sortBy(input, (x) => x.body.id || Infinity);
return sortBy(input, (x) => x.body.id || Infinity);
}
/**
* Light wrapper around _.merge() to prevent common type errors / mistakes.
* Light wrapper around merge() to prevent common type errors / mistakes.
*
* NOTE: If you rely solely on `betterMerge()` to combine array-bearing
* CeleryScript nodes, the API will reject them because they contain
@ -108,7 +114,7 @@ export function sortResourcesById<T extends TaggedResource>(input: T[]): T[] {
* safety reasons.
*/
export function betterMerge<T, U>(target: T, update: U): T & U {
return _.merge({}, target, update);
return merge({}, target, update);
}
/** Like parseFloat, but allows you to control fallback value instead of
@ -117,7 +123,7 @@ export function betterParseNum(num: string | undefined,
fallback: number): number {
try {
const maybe = JSON.parse("" + num);
if (_.isNumber(maybe) && !_.isNaN(maybe)) {
if (isNumber(maybe) && !isNaN(maybe)) {
return maybe;
}
} catch (_) {

View File

@ -29,7 +29,7 @@
"@types/enzyme": "3.1.15",
"@types/fastclick": "1.0.28",
"@types/jest": "23.3.12",
"@types/lodash": "4.14.119",
"@types/lodash": "4.14.120",
"@types/markdown-it": "0.0.7",
"@types/moxios": "0.4.8",
"@types/node": "10.12.18",
@ -101,9 +101,6 @@
"SHORT_REVISION": "--------"
}
},
"moduleNameMapper": {
"^.*\\.scss$": "<rootDir>/frontend/__test_support__/stub.ts"
},
"setupFiles": [
"./frontend/__test_support__/setup_enzyme.js",
"./frontend/__test_support__/localstorage.js",

View File

@ -6,8 +6,8 @@
"es2017.object"
],
"allowJs": true,
"allowSyntheticDefaultImports": true,
"allowUnreachableCode": false,
"allowSyntheticDefaultImports": true,
"experimentalDecorators": true,
"jsx": "react",
"module": "esnext",