frontend/farm_designer/map/background/selection_box_actions.ts
import { isNumber, uniq, cloneDeep, isEqual } from "lodash";
import { TaggedPlant, AxisNumberProperty, Mode } from "../interfaces";
import { SelectionBoxData } from "./selection_box";
import { GardenMapState } from "../../interfaces";
import { selectPoint } from "../actions";
import { getMode } from "../util";
import { editGtLtCriteria } from "../../../point_groups/criteria";
import { TaggedPointGroup, TaggedPoint, PointType } from "farmbot";
import { unpackUUID } from "../../../util";
import { UUID } from "../../../resources/interfaces";
import { getFilteredPoints } from "../../../plants/select_plants";
import { GetWebAppConfigValue } from "../../../config_storage/actions";
import { overwriteGroup } from "../../../point_groups/actions";
import { Path } from "../../../internal_urls";
/** Return all plants within the selection box. */
export const getSelected = (
plants: (TaggedPlant | TaggedPoint)[],
box: SelectionBoxData | undefined,
): string[] | undefined => {
const arraySelected = plants.filter(p => {
if (box &&
isNumber(box.x0) && isNumber(box.y0) &&
isNumber(box.x1) && isNumber(box.y1)) {
return (
p.body.x >= Math.min(box.x0, box.x1) &&
p.body.x <= Math.max(box.x0, box.x1) &&
p.body.y >= Math.min(box.y0, box.y1) &&
p.body.y <= Math.max(box.y0, box.y1)
);
}
}).map(p => { return p.uuid; });
return arraySelected.length > 0 ? arraySelected : undefined;
};
export interface ResizeSelectionBoxProps {
selectionBox: SelectionBoxData | undefined;
plants: TaggedPlant[];
allPoints: TaggedPoint[];
selectionPointType: PointType[] | undefined;
getConfigValue: GetWebAppConfigValue;
gardenCoords: AxisNumberProperty | undefined;
setMapState: (x: Partial<GardenMapState>) => void;
dispatch: Function;
plantActions: boolean;
navigate(url: string): void;
}
/** Resize a selection box. */
export const resizeBox = (props: ResizeSelectionBoxProps) => {
if (props.selectionBox) {
const current = props.gardenCoords;
if (current) {
const { x0, y0 } = props.selectionBox;
const newSelectionBox = {
x0, y0, // Keep box starting corner
x1: current.x, y1: current.y // Update box active corner
};
props.setMapState({ selectionBox: newSelectionBox });
if (props.plantActions) {
// Select all plants within the updated selection box
const { plants, allPoints, selectionPointType, getConfigValue } = props;
const points =
getFilteredPoints({
plants, allPoints, selectionPointType, getConfigValue
});
const payload = getSelected(points, newSelectionBox);
if (payload && getMode() === Mode.none) {
props.navigate(Path.plants("select"));
}
props.dispatch(selectPoint(payload));
}
}
}
};
export interface StartNewSelectionBoxProps {
gardenCoords: AxisNumberProperty | undefined;
setMapState: (x: Partial<GardenMapState>) => void;
dispatch: Function;
plantActions: boolean;
}
/** Create a new selection box. */
export const startNewSelectionBox = (props: StartNewSelectionBoxProps) => {
if (props.gardenCoords) {
// Set the starting point (initial corner) of a selection box
props.setMapState({
selectionBox: {
x0: props.gardenCoords.x, y0: props.gardenCoords.y,
x1: undefined, y1: undefined
}
});
}
if (props.plantActions) {
// Clear the previous plant selection when starting a new selection box
props.dispatch(selectPoint(undefined));
}
};
export interface MaybeUpdateGroupProps {
selectionBox: SelectionBoxData | undefined;
dispatch: Function;
group: TaggedPointGroup | undefined;
editGroupAreaInMap: boolean;
boxSelected: UUID[] | undefined;
}
export const maybeUpdateGroup =
(props: MaybeUpdateGroupProps) => {
const { group } = props;
if (props.selectionBox && group) {
if (props.editGroupAreaInMap) {
props.dispatch(editGtLtCriteria(group, props.selectionBox));
} else {
const nextGroupBody = cloneDeep(group.body);
props.boxSelected?.map(uuid => {
const { kind, remoteId } = unpackUUID(uuid);
remoteId && kind == "Point" && nextGroupBody.point_ids.push(remoteId);
});
nextGroupBody.point_ids = uniq(nextGroupBody.point_ids);
if (!isEqual(group.body.point_ids, nextGroupBody.point_ids)) {
props.dispatch(overwriteGroup(group, nextGroupBody));
props.dispatch(selectPoint(undefined));
}
}
}
};