Part I of syntheticimport issues :-\
parent
cf6cf0e2b8
commit
86fe6fba78
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
});
|
||||
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -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 =
|
||||
|
|
|
@ -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)
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -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}
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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";
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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();
|
||||
});
|
||||
});
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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() : "";
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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}
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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[] {
|
||||
|
|
|
@ -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">
|
||||
|
|
|
@ -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}
|
||||
|
|
|
@ -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>;
|
||||
|
|
|
@ -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" />
|
||||
|
|
|
@ -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}>
|
||||
|
|
|
@ -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";
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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"),
|
||||
};
|
||||
}
|
||||
|
|
|
@ -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} />
|
||||
|
|
|
@ -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(" ")),
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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 });
|
||||
|
|
|
@ -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)}>
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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>;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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];
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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[] = [
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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)}
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
import "../css/_index.scss";
|
||||
import { detectLanguage } from "../i18n";
|
||||
import * as I18n from "i18next";
|
||||
import { onInit } from "./on_init";
|
||||
|
|
|
@ -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", () => {
|
||||
|
|
|
@ -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";
|
||||
|
|
|
@ -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
|
||||
};
|
||||
|
|
|
@ -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;
|
||||
});
|
||||
}
|
||||
|
|
|
@ -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");
|
||||
});
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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[] {
|
||||
|
|
|
@ -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")))
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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]);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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} />}
|
||||
|
|
|
@ -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.");
|
||||
|
|
|
@ -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.");
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
};
|
||||
|
||||
|
|
|
@ -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> {
|
||||
|
|
|
@ -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 }; }
|
||||
|
|
|
@ -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 (_) {
|
||||
|
|
|
@ -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",
|
||||
|
|
|
@ -6,8 +6,8 @@
|
|||
"es2017.object"
|
||||
],
|
||||
"allowJs": true,
|
||||
"allowSyntheticDefaultImports": true,
|
||||
"allowUnreachableCode": false,
|
||||
"allowSyntheticDefaultImports": true,
|
||||
"experimentalDecorators": true,
|
||||
"jsx": "react",
|
||||
"module": "esnext",
|
||||
|
|
Loading…
Reference in New Issue