refactor using new ts features
parent
a32d9f025b
commit
a38e7b6b91
|
@ -7,11 +7,11 @@ export function clickButton(
|
|||
position: number,
|
||||
text: string,
|
||||
options?: { partial_match?: boolean, button_tag?: string }) {
|
||||
const btnTag = options && options.button_tag ? options.button_tag : "button";
|
||||
const btnTag = options?.button_tag ? options.button_tag : "button";
|
||||
const button = wrapper.find(btnTag).at(position);
|
||||
const expectedText = text.toLowerCase();
|
||||
const actualText = button.text().toLowerCase();
|
||||
options && options.partial_match
|
||||
options?.partial_match
|
||||
? expect(actualText).toContain(expectedText)
|
||||
: expect(actualText).toEqual(expectedText);
|
||||
button.simulate("click");
|
||||
|
|
|
@ -32,7 +32,7 @@ test("buildResourceIndex - add a FarmEvent", () => {
|
|||
const key = Object.keys(db.index.byKind.FarmEvent)[0];
|
||||
const fe = db.index.references[key];
|
||||
expect(fe).toBeTruthy();
|
||||
if (fe && fe.kind === "FarmEvent") {
|
||||
if (fe?.kind === "FarmEvent") {
|
||||
const { body } = fe;
|
||||
expect(body).toEqual(STUB_RESOURCE.body);
|
||||
} else {
|
||||
|
|
|
@ -1,12 +1,11 @@
|
|||
import * as React from "react";
|
||||
import { AxisInputBoxProps } from "./interfaces";
|
||||
import { Col, BlurableInput } from "../ui/index";
|
||||
import { isUndefined } from "lodash";
|
||||
|
||||
export const AxisInputBox = ({ onChange, value, axis }: AxisInputBoxProps) => {
|
||||
return <Col xs={3}>
|
||||
<BlurableInput
|
||||
value={(isUndefined(value) ? "" : value)}
|
||||
value={value ?? ""}
|
||||
type="number"
|
||||
allowEmpty={true}
|
||||
onCommit={e => {
|
||||
|
|
|
@ -36,8 +36,8 @@ export function BooleanMCUInputGroup(props: BooleanMCUInputGroupProps) {
|
|||
</Col>
|
||||
<Col xs={2} className={"centered-button-div"}>
|
||||
<ToggleButton
|
||||
grayscale={grayscale && grayscale.x}
|
||||
disabled={disable && disable.x}
|
||||
grayscale={grayscale?.x}
|
||||
disabled={disable?.x}
|
||||
dim={!xParam.consistent}
|
||||
toggleValue={xParam.value}
|
||||
toggleAction={() =>
|
||||
|
@ -45,8 +45,8 @@ export function BooleanMCUInputGroup(props: BooleanMCUInputGroupProps) {
|
|||
</Col>
|
||||
<Col xs={2} className={"centered-button-div"}>
|
||||
<ToggleButton
|
||||
grayscale={grayscale && grayscale.y}
|
||||
disabled={disable && disable.y}
|
||||
grayscale={grayscale?.y}
|
||||
disabled={disable?.y}
|
||||
dim={!yParam.consistent}
|
||||
toggleValue={yParam.value}
|
||||
toggleAction={() =>
|
||||
|
@ -54,8 +54,8 @@ export function BooleanMCUInputGroup(props: BooleanMCUInputGroupProps) {
|
|||
</Col>
|
||||
<Col xs={2} className={"centered-button-div"}>
|
||||
<ToggleButton
|
||||
grayscale={grayscale && grayscale.z}
|
||||
disabled={disable && disable.z}
|
||||
grayscale={grayscale?.z}
|
||||
disabled={disable?.z}
|
||||
dim={!zParam.consistent}
|
||||
toggleValue={zParam.value}
|
||||
toggleAction={() =>
|
||||
|
|
|
@ -115,7 +115,7 @@ describe("<PinBindingInputGroup/>", () => {
|
|||
const p = fakeProps();
|
||||
const key = Object.keys(p.resources.byKind.Sequence)[0];
|
||||
const s = p.resources.references[key];
|
||||
const id = s && s.body.id;
|
||||
const id = s?.body.id;
|
||||
const wrapper = mount<PinBindingInputGroup>(<PinBindingInputGroup {...p} />);
|
||||
expect(wrapper.instance().state.sequenceIdInput).toEqual(undefined);
|
||||
wrapper.instance().setSequenceIdInput({ label: "label", value: "" + id });
|
||||
|
|
|
@ -79,8 +79,8 @@ export const mcuParamValidator =
|
|||
(ok: () => void, no?: (message: string) => void): void => {
|
||||
const validator = edgeCases[key];
|
||||
const result = validator && validator(key, val, state);
|
||||
if (result && result.outcome === "NO") {
|
||||
return (no && no(result.errorMessage));
|
||||
if (result?.outcome === "NO") {
|
||||
return (no?.(result.errorMessage));
|
||||
} else {
|
||||
return ok();
|
||||
}
|
||||
|
|
|
@ -26,7 +26,7 @@ describe("draggableReducer", () => {
|
|||
const dt = nextState.dataTransfer;
|
||||
expect(Object.keys(dt)).toContain(payload.uuid);
|
||||
const entry = dt[payload.uuid];
|
||||
expect(entry && entry.uuid).toEqual(payload.uuid);
|
||||
expect(entry?.uuid).toEqual(payload.uuid);
|
||||
});
|
||||
|
||||
it("drops a step", () => {
|
||||
|
|
|
@ -56,7 +56,7 @@ export const DesignerPanelHeader = (props: DesignerPanelHeaderProps) => {
|
|||
title={t("go back") + backToText(props.backTo)}
|
||||
onClick={() => {
|
||||
props.backTo ? routeHistory.push(props.backTo) : history.back();
|
||||
props.onBack && props.onBack();
|
||||
props.onBack?.();
|
||||
}} />
|
||||
{props.title &&
|
||||
<span className={`title ${textColor}-text`}>
|
||||
|
|
|
@ -16,10 +16,10 @@ export function occurrence(
|
|||
CalendarOccurrence {
|
||||
const normalHeading = fe.executable.name || fe.executable_type;
|
||||
const heading = () => {
|
||||
if (modifiers && modifiers.empty) {
|
||||
if (modifiers?.empty) {
|
||||
return "*Empty*";
|
||||
}
|
||||
if (modifiers && modifiers.numHidden) {
|
||||
if (modifiers?.numHidden) {
|
||||
return `+ ${modifiers.numHidden} more: ` + normalHeading;
|
||||
}
|
||||
return normalHeading;
|
||||
|
|
|
@ -36,7 +36,7 @@ const addOrRemoveFromGroup =
|
|||
const group = fetchGroupFromUrl(resources);
|
||||
const point =
|
||||
resources.references[clickedPlantUuid] as TaggedPoint | undefined;
|
||||
if (group && point && point.body.id) {
|
||||
if (group && point?.body.id) {
|
||||
type Body = (typeof group)["body"];
|
||||
const nextGroup: Body = ({
|
||||
...group.body,
|
||||
|
@ -54,7 +54,7 @@ const addOrRemoveFromSelection =
|
|||
(clickedPlantUuid: UUID, selectedPlants: UUID[] | undefined) => {
|
||||
const nextSelected =
|
||||
(selectedPlants || []).filter(uuid => uuid !== clickedPlantUuid);
|
||||
if (!(selectedPlants && selectedPlants.includes(clickedPlantUuid))) {
|
||||
if (!(selectedPlants?.includes(clickedPlantUuid))) {
|
||||
nextSelected.push(clickedPlantUuid);
|
||||
}
|
||||
return selectPlant(nextSelected);
|
||||
|
|
|
@ -21,7 +21,7 @@ function getNewTrailArray(update: TrailRecord, watering: boolean): TrailRecord[]
|
|||
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 &&
|
||||
if (update?.coord &&
|
||||
(!last || !isEqual(last.coord, update.coord))) { // coordinate comparison
|
||||
arr.push(update); // unique addition
|
||||
} else { // nothing new to add, increase water circle size if watering
|
||||
|
|
|
@ -7,7 +7,7 @@ import { TaggedPlant } from "../map/interfaces";
|
|||
import { DesignerPanel, DesignerPanelHeader } from "../designer_panel";
|
||||
import { t } from "../../i18next_wrapper";
|
||||
import { EditPlantInfoProps, PlantOptions } from "../interfaces";
|
||||
import { isString, isUndefined } from "lodash";
|
||||
import { isString } from "lodash";
|
||||
import { history, getPathArray } from "../../history";
|
||||
import { destroy, edit, save } from "../../api/crud";
|
||||
import { BooleanSetting } from "../../session_keys";
|
||||
|
@ -20,7 +20,7 @@ export class RawPlantInfo extends React.Component<EditPlantInfoProps, {}> {
|
|||
get confirmDelete() {
|
||||
const confirmSetting = this.props.getConfigValue(
|
||||
BooleanSetting.confirm_plant_deletion);
|
||||
return isUndefined(confirmSetting) ? true : confirmSetting;
|
||||
return confirmSetting ?? true;
|
||||
}
|
||||
|
||||
destroy = (plantUUID: string) => {
|
||||
|
|
|
@ -51,7 +51,7 @@ describe("", () => {
|
|||
|
||||
const sort = (sortType: PointGroupSortType): string[] => {
|
||||
const array = SORT_OPTIONS[sortType](plants as TaggedPlant[]);
|
||||
return array.map(x => x && x.body && (x.body.name || "NA"));
|
||||
return array.map(x => x?.body?.name || "NA");
|
||||
};
|
||||
|
||||
it("sorts randomly", () => {
|
||||
|
|
|
@ -66,7 +66,7 @@ export const mapStateToProps = (props: Everything): EditGardenProps => {
|
|||
const savedGarden = findSavedGardenByUrl(props.resources.index);
|
||||
return {
|
||||
savedGarden,
|
||||
gardenIsOpen: !!(savedGarden && savedGarden.uuid === openedSavedGarden),
|
||||
gardenIsOpen: !!(savedGarden?.uuid === openedSavedGarden),
|
||||
dispatch: props.dispatch,
|
||||
plantPointerCount: selectAllPlantPointers(props.resources.index).length,
|
||||
};
|
||||
|
|
|
@ -71,7 +71,7 @@ const Setting = (props: SettingProps) => {
|
|||
toggleValue={props.invert ? !value : value}
|
||||
toggleAction={() => {
|
||||
props.dispatch(setWebAppConfigValue(setting, !value));
|
||||
callback && callback();
|
||||
callback?.();
|
||||
}}
|
||||
title={`${t("toggle")} ${title}`}
|
||||
customText={{ textFalse: t("off"), textTrue: t("on") }} />}
|
||||
|
|
|
@ -100,7 +100,7 @@ export class RawAddToolSlot
|
|||
: "initializing"}
|
||||
<SaveBtn onClick={this.save} status={SpecialStatus.DIRTY} />
|
||||
</DesignerPanelContent>
|
||||
</DesignerPanel >;
|
||||
</DesignerPanel>;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -24,7 +24,7 @@ export function FarmwareConfigMenu(props: FarmwareConfigMenuProps) {
|
|||
className="fb-button gray fa fa-download"
|
||||
onClick={() => {
|
||||
const p = getDevice().installFirstPartyFarmware();
|
||||
p && p.catch(commandErr("Farmware installation"));
|
||||
p?.catch(commandErr("Farmware installation"));
|
||||
}}
|
||||
disabled={props.firstPartyFwsInstalled} />
|
||||
</fieldset>
|
||||
|
|
|
@ -108,6 +108,6 @@ export function FarmwareForm(props: FarmwareFormProps): JSX.Element {
|
|||
|
||||
/** Determine if a Farmware has requested inputs. */
|
||||
export function needsFarmwareForm(farmware: FarmwareManifestInfo): Boolean {
|
||||
const needsWidget = farmware.config && farmware.config.length > 0;
|
||||
const needsWidget = farmware.config?.length > 0;
|
||||
return needsWidget;
|
||||
}
|
||||
|
|
|
@ -57,7 +57,7 @@ const PendingInstallNameError =
|
|||
}): JSX.Element => {
|
||||
const installation: TaggedFarmwareInstallation | undefined =
|
||||
installations.filter(x => x.body.url === url)[0];
|
||||
const packageError = installation && installation.body.package_error;
|
||||
const packageError = installation?.body.package_error;
|
||||
return (url && installation && packageError)
|
||||
? <div className="error-with-button">
|
||||
<label>{t("Could not fetch package name")}</label>
|
||||
|
|
|
@ -116,7 +116,7 @@ export class Photos extends React.Component<PhotosProps, {}> {
|
|||
|
||||
deletePhoto = () => {
|
||||
const img = this.props.currentImage || this.props.images[0];
|
||||
if (img && img.uuid) {
|
||||
if (img?.uuid) {
|
||||
this.props.dispatch(destroy(img.uuid))
|
||||
.then(() => success(t("Image Deleted.")))
|
||||
.catch(() => error(t("Could not delete image.")));
|
||||
|
|
|
@ -61,7 +61,7 @@ export class ImageWorkspace extends React.Component<ImageWorkspaceProps, {}> {
|
|||
|
||||
maybeProcessPhoto = () => {
|
||||
const img = this.props.currentImage || this.props.images[0];
|
||||
if (img && img.body.id) {
|
||||
if (img?.body.id) {
|
||||
this.props.onProcessPhoto(img.body.id);
|
||||
}
|
||||
};
|
||||
|
|
|
@ -80,7 +80,7 @@ export const FolderListItem = (props: FolderItemProps) => {
|
|||
onMouseUp={() => props.toggleSequenceMove(sequence.uuid)} />
|
||||
</div>
|
||||
</li>
|
||||
</StepDragger >;
|
||||
</StepDragger>;
|
||||
};
|
||||
|
||||
const ToggleFolderBtn = (props: ToggleFolderBtnProps) => {
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
import { TaggedResource, TaggedSequence } from "farmbot";
|
||||
|
||||
import { RootFolderNode, FolderUnion } from "./constants";
|
||||
|
||||
export interface FolderSearchProps {
|
||||
|
|
|
@ -18,7 +18,7 @@ export const clickHandler =
|
|||
/** BEGIN LEGACY SHIMS */
|
||||
const { onClick, to } = props;
|
||||
navigate(maybeStripLegacyUrl(to));
|
||||
onClick && onClick(e);
|
||||
onClick?.(e);
|
||||
};
|
||||
|
||||
export class Link extends React.Component<LinkProps, {}> {
|
||||
|
|
|
@ -180,7 +180,7 @@ const FirmwareChoiceTable = () =>
|
|||
export const changeFirmwareHardware = (dispatch: Function | undefined) =>
|
||||
(ddi: DropDownItem) => {
|
||||
if (isFwHardwareValue(ddi.value)) {
|
||||
dispatch && dispatch(updateConfig({ firmware_hardware: ddi.value }));
|
||||
dispatch?.(updateConfig({ firmware_hardware: ddi.value }));
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -11,7 +11,7 @@ export const computeEditorUrlFromState =
|
|||
: resources.consumers.regimens.currentRegimen;
|
||||
const r = resources.index.references[current || ""];
|
||||
const base = `/app/${resource === "Sequence" ? "sequences" : "regimens"}/`;
|
||||
if (r && r.kind == resource) {
|
||||
if (r?.kind == resource) {
|
||||
return base + urlFriendly(r.body.name);
|
||||
} else {
|
||||
return base;
|
||||
|
|
|
@ -59,7 +59,7 @@ export class NavBar extends React.Component<NavBarProps, Partial<NavBarState>> {
|
|||
BooleanSetting.disable_emergency_unlock_confirmation)} />
|
||||
|
||||
AccountMenu = () => {
|
||||
const hasName = this.props.user && this.props.user.body.name;
|
||||
const hasName = this.props.user?.body.name;
|
||||
const firstName = hasName ?
|
||||
`${hasName.split(" ")[0].slice(0, 9)} ▾` : `${t("Menu")} ▾`;
|
||||
return <div className="menu-popover">
|
||||
|
|
|
@ -43,10 +43,7 @@ const promiseCache: Dictionary<Promise<Readonly<OFCropAttrs>>> = {};
|
|||
|
||||
const cacheTheIcon = (slug: string) =>
|
||||
(resp: AxiosResponse<OFCropResponse>): OFIcon => {
|
||||
if (resp
|
||||
&& resp.data
|
||||
&& resp.data.data
|
||||
&& resp.data.data.attributes) {
|
||||
if (resp?.data?.data?.attributes) {
|
||||
const icon = {
|
||||
slug: resp.data.data.attributes.slug,
|
||||
spread: resp.data.data.attributes.spread,
|
||||
|
|
|
@ -35,7 +35,7 @@ export function getMiddleware(env: EnvName) {
|
|||
.map((mwc) => mwc.fn);
|
||||
// tslint:disable-next-line:no-any
|
||||
const wow = (window as any).__REDUX_DEVTOOLS_EXTENSION_COMPOSE__;
|
||||
const dtCompose = wow && wow({
|
||||
const dtCompose = wow?.({
|
||||
actionsBlacklist: [
|
||||
Actions.NETWORK_EDGE_CHANGE,
|
||||
Actions.PING_NO,
|
||||
|
|
|
@ -12,10 +12,8 @@ const WEB_APP_CONFIG: ResourceName = "WebAppConfig";
|
|||
* resources, downloading the filtered log list as required from the API. */
|
||||
// tslint:disable-next-line:no-any
|
||||
export const fn: Middleware = () => (dispatch) => (action: any) => {
|
||||
const needsRefresh = action
|
||||
&& action.payload
|
||||
&& action.type === Actions.SAVE_RESOURCE_OK
|
||||
&& action.payload.kind === WEB_APP_CONFIG;
|
||||
const needsRefresh = action?.payload?.kind === WEB_APP_CONFIG
|
||||
&& action.type === Actions.SAVE_RESOURCE_OK;
|
||||
|
||||
needsRefresh && throttledLogRefresh(dispatch);
|
||||
|
||||
|
|
|
@ -23,16 +23,11 @@ const WEB_APP_CONFIG: ResourceName = "WebAppConfig";
|
|||
// tslint:disable-next-line:no-any
|
||||
const fn: Middleware = () => (dispatch) => (action: any) => {
|
||||
const x: DeepPartial<SyncResponse<TaggedWebAppConfig>> = action;
|
||||
if (x
|
||||
&& x.type === Actions.RESOURCE_READY
|
||||
&& x.payload
|
||||
&& x.payload.body
|
||||
if (x?.type === Actions.RESOURCE_READY
|
||||
&& x.payload?.body
|
||||
&& x.payload.kind === WEB_APP_CONFIG) {
|
||||
const conf = arrayUnwrap(x.payload.body);
|
||||
conf
|
||||
&& conf.body
|
||||
&& conf.body.disable_i18n
|
||||
&& revertToEnglish();
|
||||
conf?.body?.disable_i18n && revertToEnglish();
|
||||
}
|
||||
|
||||
return dispatch(action);
|
||||
|
|
|
@ -12,10 +12,9 @@ export function dontStopThem() { }
|
|||
const shouldStop =
|
||||
(allResources: TaggedResource[], config: TaggedWebAppConfig | undefined) => {
|
||||
const loggedIn = !!localStorage.getItem("session");
|
||||
const discardUnsaved = config && config.body.discard_unsaved;
|
||||
const discardUnsaved = config?.body.discard_unsaved;
|
||||
const sequenceResources = allResources.filter(r => r.kind === "Sequence");
|
||||
const discardUnsavedSequences =
|
||||
config && config.body.discard_unsaved_sequences;
|
||||
const discardUnsavedSequences = config?.body.discard_unsaved_sequences;
|
||||
|
||||
/**
|
||||
* For the unsaved notification to show, a user must:
|
||||
|
@ -59,6 +58,6 @@ export function registerSubscribers(store: Store) {
|
|||
subscriptions.forEach(function (s) {
|
||||
ENV_LIST.includes &&
|
||||
ENV_LIST.includes(s.env) &&
|
||||
store.subscribe(() => s.fn && s.fn(store.getState()));
|
||||
store.subscribe(() => s.fn?.(store.getState()));
|
||||
});
|
||||
}
|
||||
|
|
|
@ -23,7 +23,7 @@ const fn: MW =
|
|||
// tslint:disable-next-line:no-any
|
||||
(action: any) => {
|
||||
const fbos = getVersionFromState(store.getState());
|
||||
window.Rollbar && window.Rollbar.configure({ payload: { fbos } });
|
||||
window.Rollbar?.configure({ payload: { fbos } });
|
||||
return dispatch(action);
|
||||
};
|
||||
|
||||
|
|
|
@ -17,7 +17,7 @@ const BAD_UUID = "WARNING: Not a sequence UUID.";
|
|||
export class BulkScheduler extends React.Component<BulkEditorProps, {}> {
|
||||
selected = (): DropDownItem => {
|
||||
const s = this.props.selectedSequence;
|
||||
return (s && s.body.id)
|
||||
return (s?.body.id)
|
||||
? { label: s.body.name, value: s.uuid }
|
||||
: NULL_CHOICE;
|
||||
};
|
||||
|
@ -66,7 +66,7 @@ export class BulkScheduler extends React.Component<BulkEditorProps, {}> {
|
|||
|
||||
render() {
|
||||
const { dispatch, weeks, sequences } = this.props;
|
||||
const active = !!(sequences && sequences.length);
|
||||
const active = !!(sequences?.length);
|
||||
return <div className="bulk-scheduler-content">
|
||||
<AddButton
|
||||
active={active}
|
||||
|
|
|
@ -66,7 +66,7 @@ describe("<RegimenEditor />", () => {
|
|||
p.dispatch = jest.fn(() => Promise.resolve());
|
||||
const wrapper = mount(<RegimenEditor {...p} />);
|
||||
clickButton(wrapper, 2, "delete");
|
||||
const expectedUuid = p.current && p.current.uuid;
|
||||
const expectedUuid = p.current?.uuid;
|
||||
expect(destroy).toHaveBeenCalledWith(expectedUuid);
|
||||
});
|
||||
|
||||
|
@ -74,7 +74,7 @@ describe("<RegimenEditor />", () => {
|
|||
const p = fakeProps();
|
||||
const wrapper = mount(<RegimenEditor {...p} />);
|
||||
clickButton(wrapper, 0, "save", { partial_match: true });
|
||||
const expectedUuid = p.current && p.current.uuid;
|
||||
const expectedUuid = p.current?.uuid;
|
||||
expect(save).toHaveBeenCalledWith(expectedUuid);
|
||||
});
|
||||
});
|
||||
|
|
|
@ -177,7 +177,7 @@ describe("maybeGetSequence", () => {
|
|||
const i = buildResourceIndex([s]);
|
||||
const result = Selector.maybeGetSequence(i.index, s.uuid);
|
||||
expect(result).toBeTruthy();
|
||||
result && expect(result.uuid).toBe(s.uuid);
|
||||
expect(result?.uuid).toBe(s.uuid);
|
||||
});
|
||||
});
|
||||
|
||||
|
|
|
@ -188,7 +188,7 @@ const reindexAllSequences = (i: ResourceIndex) => {
|
|||
const mapper = reindexSequences(i);
|
||||
betterCompact(Object.keys(i.byKind["Sequence"]).map(uuid => {
|
||||
const resource = i.references[uuid];
|
||||
return (resource && resource.kind == "Sequence") ? resource : undefined;
|
||||
return (resource?.kind == "Sequence") ? resource : undefined;
|
||||
})).map(mapper);
|
||||
};
|
||||
|
||||
|
@ -283,7 +283,7 @@ const AFTER_HOOKS: IndexerHook = {
|
|||
FbosConfig: (i) => {
|
||||
const conf = getFbosConfig(i);
|
||||
|
||||
if (conf && conf.body.boot_sequence_id) {
|
||||
if (conf?.body.boot_sequence_id) {
|
||||
const { boot_sequence_id } = conf.body;
|
||||
const tracker = i.inUse["Sequence.FbosConfig"];
|
||||
const uuid = i.byKindAndId[joinKindAndId("Sequence", boot_sequence_id)];
|
||||
|
@ -345,7 +345,7 @@ export const indexUpsert: IndexUpsert = (db, resources, strategy) => {
|
|||
const { kind } = arrayUnwrap(resources);
|
||||
// Clean up indexes (if needed)
|
||||
const before = BEFORE_HOOKS[kind];
|
||||
before && before(db, strategy);
|
||||
before?.(db, strategy);
|
||||
|
||||
// Run indexers
|
||||
ups.map(callback => {
|
||||
|
@ -354,14 +354,14 @@ export const indexUpsert: IndexUpsert = (db, resources, strategy) => {
|
|||
|
||||
// Finalize indexing (if needed)
|
||||
const after = AFTER_HOOKS[kind];
|
||||
after && after(db, strategy);
|
||||
after?.(db, strategy);
|
||||
};
|
||||
|
||||
export function indexRemove(db: ResourceIndex, resource: TaggedResource) {
|
||||
downs.map(callback => arrayWrap(resource).map(r => callback(r, db)));
|
||||
// Finalize indexing (if needed)
|
||||
const after = AFTER_HOOKS[resource.kind];
|
||||
after && after(db, "ongoing");
|
||||
after?.(db, "ongoing");
|
||||
}
|
||||
|
||||
export const beforeEach = (state: RestResources,
|
||||
|
|
|
@ -77,7 +77,7 @@ export function findPointerByTypeAndId(index: ResourceIndex,
|
|||
const uuid = "" + index.byKindAndId[pni];
|
||||
const resource = index.references[uuid];
|
||||
|
||||
if (resource && resource.kind === "Point") {
|
||||
if (resource?.kind === "Point") {
|
||||
return resource;
|
||||
} else {
|
||||
// We might have a sequence dependency leak if this exception is ever
|
||||
|
@ -204,7 +204,7 @@ export function maybeGetTimeSettings(index: ResourceIndex): TimeSettings {
|
|||
|
||||
export function maybeGetDevice(index: ResourceIndex): TaggedDevice | undefined {
|
||||
const dev = index.references[Object.keys(index.byKind.Device)[0] || "nope"];
|
||||
return (dev && dev.kind === "Device") ?
|
||||
return (dev?.kind === "Device") ?
|
||||
dev : undefined;
|
||||
}
|
||||
|
||||
|
@ -227,7 +227,7 @@ export function maybeFetchUser(index: ResourceIndex):
|
|||
if (user && sanityCheck(user) && list.length > 1) {
|
||||
throw new Error("PROBLEM: Expected 1 user. Got: " + list.length);
|
||||
}
|
||||
if ((list.length === 1) && user && user.kind === "User") {
|
||||
if ((list.length === 1) && user?.kind === "User") {
|
||||
return user;
|
||||
} else {
|
||||
return undefined;
|
||||
|
|
|
@ -50,7 +50,7 @@ export const determineVector =
|
|||
return ts ? ts.body : undefined;
|
||||
case "identifier":
|
||||
const variable = maybeFindVariable(node.args.label, resources, uuid);
|
||||
return variable && variable.vector;
|
||||
return variable?.vector;
|
||||
}
|
||||
return undefined;
|
||||
};
|
||||
|
|
|
@ -127,7 +127,7 @@ describe("<SequenceEditorMiddleActive/>", () => {
|
|||
p.dispatch = dispatch;
|
||||
const wrapper = mount(<SequenceEditorMiddleActive {...p} />);
|
||||
const props = wrapper.find("DropArea").props() as DropAreaProps;
|
||||
props.callback && props.callback("key");
|
||||
props.callback?.("key");
|
||||
dispatch.mock.calls[0][0](() =>
|
||||
({ value: 1, intent: "step_splice", draggerId: 2 }));
|
||||
expect(splice).toHaveBeenCalledWith(expect.objectContaining({
|
||||
|
|
|
@ -148,7 +148,7 @@ const SequenceBtnGroup = ({
|
|||
onClick={() => {
|
||||
const confirm = getWebAppConfigValue(
|
||||
BooleanSetting.confirm_sequence_deletion);
|
||||
const force = isUndefined(confirm) ? false : !confirm;
|
||||
const force = !(confirm ?? true);
|
||||
dispatch(destroy(sequence.uuid, force))
|
||||
.then(() => push("/app/sequences/"));
|
||||
}}>
|
||||
|
|
|
@ -19,7 +19,7 @@ import {
|
|||
export function mapStateToProps(props: Everything): Props {
|
||||
const uuid = props.resources.consumers.sequences.current;
|
||||
const sequence = uuid ? findSequence(props.resources.index, uuid) : undefined;
|
||||
sequence && (sequence.body.body || []).map(x => getStepTag(x));
|
||||
(sequence?.body.body || []).map(x => getStepTag(x));
|
||||
|
||||
const fwConfig = validFwConfig(getFirmwareConfig(props.resources.index));
|
||||
const { mcu_params } = props.bot.hardware;
|
||||
|
|
|
@ -83,7 +83,7 @@ describe("<TileExecuteScript/>", () => {
|
|||
it("shows special 1st-party Farmware name", () => {
|
||||
const p = fakeProps();
|
||||
(p.currentStep as ExecuteScript).args.label = "plant-detection";
|
||||
p.farmwareData && p.farmwareData.farmwareNames.push("plant-detection");
|
||||
p.farmwareData?.farmwareNames.push("plant-detection");
|
||||
const wrapper = mount(<TileExecuteScript {...p} />);
|
||||
expect(wrapper.find("label").length).toEqual(1);
|
||||
expect(wrapper.text()).toContain("Weed Detector");
|
||||
|
|
|
@ -54,7 +54,7 @@ export function TileExecuteScript(props: StepParams) {
|
|||
|
||||
/** Configs (inputs) from Farmware manifest for <FarmwareInputs />. */
|
||||
const currentFarmwareConfigDefaults = (fwName: string): FarmwareConfig[] => {
|
||||
return farmwareData && farmwareData.farmwareConfigs[fwName]
|
||||
return farmwareData?.farmwareConfigs[fwName]
|
||||
? farmwareData.farmwareConfigs[fwName]
|
||||
: [];
|
||||
};
|
||||
|
|
|
@ -24,8 +24,8 @@ import {
|
|||
const fakeResourceIndex = buildResourceIndex(FAKE_RESOURCES).index;
|
||||
const fakeTaggedSequence = fakeResourceIndex
|
||||
.references[Object.keys(fakeResourceIndex.byKind.Sequence)[0]] as TaggedSequence;
|
||||
const fakeId = fakeTaggedSequence && fakeTaggedSequence.body.id || 0;
|
||||
const fakeName = fakeTaggedSequence && fakeTaggedSequence.body.name || "";
|
||||
const fakeId = fakeTaggedSequence.body.id || 0;
|
||||
const fakeName = fakeTaggedSequence.body.name || "";
|
||||
const expectedItem = { label: fakeName, value: fakeId };
|
||||
|
||||
function fakeProps(): IfParams {
|
||||
|
|
|
@ -30,7 +30,7 @@ export const newTaggedResource = <T extends TR>(kind: T["kind"],
|
|||
return {
|
||||
kind: kind as TaggedResource["kind"],
|
||||
body: body as TaggedResource["body"],
|
||||
uuid: generateUuid(body && body.id ? body.id : undefined, kind),
|
||||
uuid: generateUuid(body?.id, kind),
|
||||
specialStatus
|
||||
} as T;
|
||||
});
|
||||
|
|
|
@ -11,7 +11,7 @@ export class ToolBayList extends React.Component<ToolBayListProps, {}> {
|
|||
ToolSlotListItem = (slot: TaggedToolSlotPointer, index: number) => {
|
||||
const { getToolByToolSlotUUID } = this.props;
|
||||
const tool = getToolByToolSlotUUID(slot.uuid);
|
||||
const name = (tool && tool.body.name) || t("None");
|
||||
const name = (tool?.body.name) || t("None");
|
||||
return <Row key={slot.uuid}>
|
||||
<Col xs={1}><label>{index + 1}</label></Col>
|
||||
<Col xs={2}>{slot.body.gantry_mounted ? t("Gantry") : slot.body.x}</Col>
|
||||
|
|
|
@ -6,7 +6,7 @@ interface BackArrowProps {
|
|||
export function BackArrow(props: BackArrowProps) {
|
||||
const onClick = () => {
|
||||
history.back();
|
||||
props.onClick && props.onClick();
|
||||
props.onClick?.();
|
||||
};
|
||||
|
||||
return <a onClick={onClick} className="back-arrow">
|
||||
|
|
|
@ -47,7 +47,7 @@ export class BlurableInput extends React.Component<BIProps, Partial<BIState>> {
|
|||
withinLimits = (options?: { toasts?: boolean }): boolean => {
|
||||
const onError = (msg: string) => {
|
||||
this.setState({ error: msg });
|
||||
options && options.toasts && error(msg);
|
||||
options?.toasts && error(msg);
|
||||
};
|
||||
|
||||
if (this.props.type === "number") {
|
||||
|
|
|
@ -131,18 +131,6 @@ describe("util", () => {
|
|||
});
|
||||
});
|
||||
|
||||
describe("isUndefined()", () => {
|
||||
it("undefined", () => {
|
||||
const result = Util.isUndefined(undefined);
|
||||
expect(result).toBeTruthy();
|
||||
});
|
||||
|
||||
it("defined", () => {
|
||||
const result = Util.isUndefined({});
|
||||
expect(result).toBeFalsy();
|
||||
});
|
||||
});
|
||||
|
||||
describe("randomColor()", () => {
|
||||
it("only picks valid colors", () => {
|
||||
times(Util.colors.length * 1.5, () =>
|
||||
|
|
|
@ -28,7 +28,7 @@ export function prettyPrintApiErrors(err: AxiosErrorResponse) {
|
|||
|
||||
function safelyFetchErrors(err: AxiosErrorResponse): Dictionary<string> {
|
||||
// In case the interpreter gives us an oddball error message.
|
||||
if (err && err.response && err.response.data) {
|
||||
if (err.response?.data) {
|
||||
return err.response.data;
|
||||
} else {
|
||||
return {
|
||||
|
@ -42,7 +42,7 @@ export function bail(message: string): never {
|
|||
}
|
||||
|
||||
export const catchErrors = (error: Error) => {
|
||||
if (window.Rollbar && window.Rollbar.error) {
|
||||
if (window.Rollbar?.error) {
|
||||
window.Rollbar.error(error);
|
||||
} else {
|
||||
throw error;
|
||||
|
|
|
@ -14,7 +14,6 @@ import {
|
|||
sortBy,
|
||||
merge,
|
||||
isNumber,
|
||||
isUndefined as lodashIsUndefined
|
||||
} from "lodash";
|
||||
import { t } from "../i18next_wrapper";
|
||||
|
||||
|
@ -88,10 +87,6 @@ export type CowardlyDictionary<T> = Dictionary<T | undefined>;
|
|||
*/
|
||||
export const NOT_SAVED = -1;
|
||||
|
||||
export function isUndefined(x: object | undefined): x is undefined {
|
||||
return lodashIsUndefined(x);
|
||||
}
|
||||
|
||||
/** Better than Array.proto.filter and compact() because the type checker
|
||||
* knows what's going on.
|
||||
*/
|
||||
|
@ -190,7 +185,7 @@ export function validBotLocationData(
|
|||
*/
|
||||
export function validFwConfig(config: TaggedFirmwareConfig | undefined):
|
||||
TaggedFirmwareConfig["body"] | undefined {
|
||||
return (config && config.body.api_migrated)
|
||||
return (config?.body.api_migrated)
|
||||
? config.body
|
||||
: undefined;
|
||||
}
|
||||
|
@ -200,7 +195,7 @@ export function validFwConfig(config: TaggedFirmwareConfig | undefined):
|
|||
*/
|
||||
export function validFbosConfig(
|
||||
config: TaggedFbosConfig | undefined): TaggedFbosConfig["body"] | undefined {
|
||||
return (config && config.body.api_migrated)
|
||||
return (config?.body.api_migrated)
|
||||
? config.body
|
||||
: undefined;
|
||||
}
|
||||
|
@ -232,4 +227,4 @@ export const parseIntInput = (input: string): number => {
|
|||
|
||||
export const timeFormatString =
|
||||
(timeSettings: TimeSettings | undefined): string =>
|
||||
(timeSettings && timeSettings.hour24) ? "H:mm" : "h:mma";
|
||||
(timeSettings?.hour24) ? "H:mm" : "h:mma";
|
||||
|
|
Loading…
Reference in New Issue