import * as React from "react"; import { history } from "../../history"; import { connect } from "react-redux"; import { Everything } from "../../interfaces"; import { PlantInventoryItem } from "./plant_inventory_item"; import { destroy } from "../../api/crud"; import { unselectPlant, selectPoint, setHoveredPlant } from "../map/actions"; import { Actions, Content } from "../../constants"; import { TaggedPlant } from "../map/interfaces"; import { getPlants } from "../state_to_props"; import { DesignerPanel, DesignerPanelHeader, DesignerPanelContent, } from "../designer_panel"; import { t } from "../../i18next_wrapper"; import { createGroup } from "../point_groups/actions"; import { PanelColor } from "../panel_header"; import { error } from "../../toast/toast"; import { PlantStatusBulkUpdate } from "./edit_plant_status"; import { FBSelect, DropDownItem } from "../../ui"; import { PointType, TaggedPoint, TaggedGenericPointer, TaggedToolSlotPointer, TaggedTool, TaggedWeedPointer, TaggedPointGroup, } from "farmbot"; import { UUID } from "../../resources/interfaces"; import { selectAllActivePoints, selectAllToolSlotPointers, selectAllTools, selectAllPointGroups, } from "../../resources/selectors"; import { PointInventoryItem } from "../points/point_inventory_item"; import { ToolSlotInventoryItem } from "../tools"; import { getWebAppConfigValue, GetWebAppConfigValue, } from "../../config_storage/actions"; import { BooleanSetting, NumericSetting } from "../../session_keys"; import { isBotOriginQuadrant, BotOriginQuadrant } from "../interfaces"; import { isActive } from "../tools/edit_tool"; import { uniq } from "lodash"; import { POINTER_TYPES } from "../point_groups/criteria/interfaces"; import { WeedInventoryItem } from "../weeds/weed_inventory_item"; import { pointsSelectedByGroup } from "../point_groups/criteria"; // tslint:disable-next-line:no-any export const isPointType = (x: any): x is PointType => POINTER_TYPES.includes(x); export const validPointTypes = (pointerTypes: unknown[] | undefined): PointType[] | undefined => { const validValues = (pointerTypes || []) .filter(x => isPointType(x)).map(x => x as PointType); return validValues.length > 0 ? validValues : undefined; }; export const setSelectionPointType = (payload: PointType[] | undefined) => (dispatch: Function) => dispatch({ type: Actions.SET_SELECTION_POINT_TYPE, payload }); export const POINTER_TYPE_DDI_LOOKUP = (): { [x: string]: DropDownItem } => ({ Plant: { label: t("Plants"), value: "Plant" }, GenericPointer: { label: t("Points"), value: "GenericPointer" }, Weed: { label: t("Weeds"), value: "Weed" }, ToolSlot: { label: t("Slots"), value: "ToolSlot" }, All: { label: t("All"), value: "All" }, Other: { label: t("Other"), value: "Other" }, }); export const POINTER_TYPE_LIST = () => [ POINTER_TYPE_DDI_LOOKUP().Plant, POINTER_TYPE_DDI_LOOKUP().GenericPointer, POINTER_TYPE_DDI_LOOKUP().Weed, POINTER_TYPE_DDI_LOOKUP().ToolSlot, POINTER_TYPE_DDI_LOOKUP().All, ]; export const mapStateToProps = (props: Everything): SelectPlantsProps => { const getWebAppConfig = getWebAppConfigValue(() => props); const xySwap = !!getWebAppConfig(BooleanSetting.xy_swap); const rawQuadrant = getWebAppConfig(NumericSetting.bot_origin_quadrant); const quadrant = isBotOriginQuadrant(rawQuadrant) ? rawQuadrant : 2; return { selected: props.resources.consumers.farm_designer.selectedPoints, selectionPointType: props.resources.consumers.farm_designer.selectionPointType, getConfigValue: getWebAppConfig, plants: getPlants(props.resources), allPoints: selectAllActivePoints(props.resources.index), dispatch: props.dispatch, gardenOpen: props.resources.consumers.farm_designer.openedSavedGarden, tools: selectAllTools(props.resources.index), groups: selectAllPointGroups(props.resources.index), isActive: isActive(selectAllToolSlotPointers(props.resources.index)), xySwap, quadrant, }; }; export interface SelectPlantsProps { plants: TaggedPlant[]; allPoints: TaggedPoint[]; dispatch: Function; selected: UUID[] | undefined; selectionPointType: PointType[] | undefined; getConfigValue: GetWebAppConfigValue; gardenOpen: string | undefined; xySwap: boolean; quadrant: BotOriginQuadrant; isActive(id: number | undefined): boolean; tools: TaggedTool[]; groups: TaggedPointGroup[]; } interface SelectPlantsState { group_id: number | undefined; more: boolean; } export class RawSelectPlants extends React.Component { state: SelectPlantsState = { group_id: undefined, more: false }; componentDidMount() { const { dispatch, selected } = this.props; if (selected && selected.length == 1) { unselectPlant(dispatch)(); } else { dispatch(setHoveredPlant(undefined)); dispatch({ type: Actions.HOVER_PLANT_LIST_ITEM, payload: undefined }); } } componentWillUnmount = () => this.props.dispatch(setSelectionPointType(undefined)); get selected() { return this.props.selected || []; } destroySelected = (plantUUIDs: string[] | undefined) => { if (plantUUIDs && plantUUIDs.length > 0 && confirm(t("Are you sure you want to delete {{length}} plants?", { length: plantUUIDs.length }))) { plantUUIDs.map(uuid => { this.props.dispatch(destroy(uuid, true)) .then(() => { }, () => { }); }); history.push("/app/designer/plants"); } } get selectionPointType() { const selectionPointTypes = this.props.selectionPointType || ["Plant"]; return selectionPointTypes.length > 1 ? "All" : selectionPointTypes[0]; } get groupDDILookup(): Record { const lookup: Record = {}; this.props.groups.map(group => { const { id } = group.body; const groupName = group.body.name; const count = pointsSelectedByGroup(group, this.props.allPoints).length; const label = `${groupName} (${t("{{count}} items", { count })})`; id && (lookup[id] = { label, value: id }); }); return lookup; } selectGroup = (ddi: DropDownItem) => { const group_id = parseInt("" + ddi.value); this.setState({ group_id }); const group = this.props.groups .filter(pg => pg.body.id == group_id)[0]; const points = pointsSelectedByGroup(group, this.props.allPoints); const pointUuids = points.map(p => p.uuid); const pointerTypes = group.body.criteria.string_eq.pointer_type as PointType[] | undefined; const uniqPointTypes = uniq(points.map(p => p.body.pointer_type)); const pointTypes = uniqPointTypes.length == 1 ? [uniqPointTypes[0]] : undefined; this.props.dispatch(setSelectionPointType( pointerTypes || pointTypes || POINTER_TYPES)); this.props.dispatch(selectPoint(pointUuids)); } ActionButtons = () =>
{ this.props.dispatch(selectPoint(undefined)); this.setState({ group_id: undefined }); this.props.dispatch(setSelectionPointType( ddi.value == "All" ? POINTER_TYPES : validPointTypes([ddi.value]))); }} />
this.setState({ more: !this.state.more })}>

{this.state.more ? t("Less") : t("More")}

{(this.selectionPointType == "Plant" || this.selectionPointType == "Weed") && }
; get filteredPoints() { const { plants, allPoints, selectionPointType, getConfigValue } = this.props; return getFilteredPoints({ plants, allPoints, selectionPointType, getConfigValue }); } get selectedPointData() { const { plants, allPoints, selectionPointType } = this.props; return getSelectedPoints({ plants, allPoints, selectionPointType, selected: this.selected, }); } get allPointUuids() { return this.filteredPoints.map(p => p.uuid); } get itemName() { const { value } = POINTER_TYPE_DDI_LOOKUP()[this.selectionPointType]; const ITEM_NAME_LOOKUP: Record> = { "Plant": { singular: t("plant"), plural: t("plants") }, "GenericPointer": { singular: t("point"), plural: t("points") }, "Weed": { singular: t("weed"), plural: t("weeds") }, "ToolSlot": { singular: t("slot"), plural: t("slots") }, "All": { singular: t("item"), plural: t("items") }, }; return ITEM_NAME_LOOKUP["" + value][ this.selected.length == 1 ? "singular" : "plural"]; } render() { const { dispatch } = this.props; return {this.selectedPointData.map(p => { if (p.kind == "PlantTemplate" || p.body.pointer_type == "Plant") { return ; } else { switch (p.body.pointer_type) { case "GenericPointer": return ; case "Weed": return ; case "ToolSlot": return ; } } })} ; } } export const SelectPlants = connect(mapStateToProps)(RawSelectPlants); export interface GetFilteredPointsProps { selectionPointType: PointType[] | undefined; plants: TaggedPlant[]; allPoints: TaggedPoint[]; getConfigValue?: GetWebAppConfigValue; } export const getFilteredPoints = (props: GetFilteredPointsProps) => { const selectionPointType = (props.selectionPointType || ["Plant"]) .filter(x => !props.getConfigValue || getVisibleLayers(props.getConfigValue).includes(x)); const filterPoints = (p: TaggedPoint) => selectionPointType.includes(p.body.pointer_type); const plants = selectionPointType.includes("Plant") ? props.plants : []; const otherPoints = props.allPoints .filter(p => p.body.pointer_type != "Plant") .filter(filterPoints); const plantsAndOtherPoints: (TaggedPlant | TaggedPoint)[] = []; return uniq(plantsAndOtherPoints.concat(plants).concat(otherPoints)); }; interface GetSelectedPointsProps extends GetFilteredPointsProps { selected: UUID[]; } export const getSelectedPoints = (props: GetSelectedPointsProps) => props.selected .map(uuid => getFilteredPoints(props).filter(p => p.uuid == uuid)[0]) .filter(p => p); enum PointerType { Plant = "Plant", GenericPointer = "GenericPointer", Weed = "Weed", ToolSlot = "ToolSlot", } const getVisibleLayers = (getConfigValue: GetWebAppConfigValue): PointType[] => { const showPlants = getConfigValue(BooleanSetting.show_plants); const showPoints = getConfigValue(BooleanSetting.show_points); const showWeeds = getConfigValue(BooleanSetting.show_weeds); const showFarmbot = getConfigValue(BooleanSetting.show_farmbot); return [ ...(showPlants ? [PointerType.Plant] : []), ...(showPoints ? [PointerType.GenericPointer] : []), ...(showWeeds ? [PointerType.Weed] : []), ...(showFarmbot ? [PointerType.ToolSlot] : []), ]; }; export const SelectModeLink = () =>
;