diff --git a/Gemfile.lock b/Gemfile.lock index 2ead3bdfbe..88e57cf222 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -71,7 +71,7 @@ GEM minitest (>= 5.1) tzinfo (~> 2.0) zeitwerk (~> 2.3) - addressable (2.8.5) + addressable (2.8.6) public_suffix (>= 2.0.2, < 6.0) amq-protocol (2.3.2) bcrypt (3.1.20) @@ -114,10 +114,10 @@ GEM docile (1.4.0) e2mmap (0.1.0) erubi (1.12.0) - factory_bot (6.2.1) + factory_bot (6.4.2) activesupport (>= 5.0.0) - factory_bot_rails (6.2.0) - factory_bot (~> 6.2.0) + factory_bot_rails (6.4.2) + factory_bot (~> 6.4) railties (>= 5.0.0) faker (3.2.2) i18n (>= 1.8.11, < 2) @@ -161,11 +161,11 @@ GEM google-apis-core (>= 0.11.0, < 2.a) google-apis-storage_v1 (0.29.0) google-apis-core (>= 0.11.0, < 2.a) - google-cloud-core (1.6.0) - google-cloud-env (~> 1.0) + google-cloud-core (1.6.1) + google-cloud-env (>= 1.0, < 3.a) google-cloud-errors (~> 1.0) - google-cloud-env (1.6.0) - faraday (>= 0.17.3, < 3.0) + google-cloud-env (2.1.0) + faraday (>= 1.0, < 3.a) google-cloud-errors (1.3.1) google-cloud-storage (1.45.0) addressable (~> 2.8) @@ -175,13 +175,14 @@ GEM google-cloud-core (~> 1.6) googleauth (>= 0.16.2, < 2.a) mini_mime (~> 1.0) - googleauth (1.8.1) - faraday (>= 0.17.3, < 3.a) + googleauth (1.9.1) + faraday (>= 1.0, < 3.a) + google-cloud-env (~> 2.1) jwt (>= 1.4, < 3.0) multi_json (~> 1.11) os (>= 0.9, < 2.0) signet (>= 0.16, < 2.a) - hashdiff (1.0.1) + hashdiff (1.1.0) hashie (4.1.0) httpclient (2.8.3) i18n (1.14.1) @@ -221,7 +222,7 @@ GEM multipart-post (2.3.0) mutations (0.9.1) activesupport - net-imap (0.4.5) + net-imap (0.4.8) date net-protocol net-pop (0.1.2) @@ -230,7 +231,7 @@ GEM timeout net-smtp (0.4.0) net-protocol - nio4r (2.6.1) + nio4r (2.7.0) nokogiri (1.15.5-x86_64-linux) racc (~> 1.4) orm_adapter (0.5.0) @@ -306,7 +307,7 @@ GEM railties (>= 5.2) retriable (3.1.2) rexml (3.2.6) - rollbar (3.4.1) + rollbar (3.4.2) rspec (3.12.0) rspec-core (~> 3.12.0) rspec-expectations (~> 3.12.0) @@ -335,7 +336,7 @@ GEM activerecord (>= 4.0.0) railties (>= 4.0.0) secure_headers (6.5.0) - set (1.0.3) + set (1.0.4) signet (0.18.0) addressable (~> 2.8) faraday (>= 0.17.5, < 3.a) @@ -432,4 +433,4 @@ RUBY VERSION ruby 3.1.4p223 BUNDLED WITH - 2.4.22 + 2.5.0 diff --git a/frontend/__test_support__/fake_html_events.ts b/frontend/__test_support__/fake_html_events.ts index a4a660f6c7..dd3fa91a56 100644 --- a/frontend/__test_support__/fake_html_events.ts +++ b/frontend/__test_support__/fake_html_events.ts @@ -1,4 +1,4 @@ -import { DeepPartial } from "redux"; +import { DeepPartial } from "../redux/interfaces"; type DomEvent = React.SyntheticEvent; export const inputEvent = (value: string, name?: string): DomEvent => { diff --git a/frontend/api/__tests__/crud_data_tracking_test.ts b/frontend/api/__tests__/crud_data_tracking_test.ts index 72f6104437..3f046e80b5 100644 --- a/frontend/api/__tests__/crud_data_tracking_test.ts +++ b/frontend/api/__tests__/crud_data_tracking_test.ts @@ -17,7 +17,7 @@ import { destroy, saveAll, initSave, initSaveGetId } from "../crud"; import { buildResourceIndex } from "../../__test_support__/resource_index_builder"; import { createStore, applyMiddleware } from "redux"; import { resourceReducer } from "../../resources/reducer"; -import thunk from "redux-thunk"; +import { thunk } from "redux-thunk"; import { ReduxAction } from "../../redux/interfaces"; import { maybeStartTracking } from "../maybe_start_tracking"; import { API } from "../api"; diff --git a/frontend/connectivity/__tests__/connect_device/connect_device_test.ts b/frontend/connectivity/__tests__/connect_device/connect_device_test.ts index fc10c21d5f..ac7be397d4 100644 --- a/frontend/connectivity/__tests__/connect_device/connect_device_test.ts +++ b/frontend/connectivity/__tests__/connect_device/connect_device_test.ts @@ -6,7 +6,7 @@ jest.mock("../../../device", () => { import { fetchNewDevice } from "../../../device"; import { connectDevice } from "../../connect_device"; -import { DeepPartial } from "redux"; +import { DeepPartial } from "../../../redux/interfaces"; import { AuthState } from "../../../auth/interfaces"; import { fakeState } from "../../../__test_support__/fake_state"; diff --git a/frontend/connectivity/__tests__/index_test.ts b/frontend/connectivity/__tests__/index_test.ts index 52fcdd6435..d1eefe1564 100644 --- a/frontend/connectivity/__tests__/index_test.ts +++ b/frontend/connectivity/__tests__/index_test.ts @@ -26,11 +26,10 @@ import { networkUptimeThrottleStats, } from "../index"; import { networkUp, networkDown } from "../actions"; -import { GetState } from "../../redux/interfaces"; +import { GetState, DeepPartial } from "../../redux/interfaces"; import { autoSync, routeMqttData } from "../auto_sync"; import { handleInbound } from "../auto_sync_handle_inbound"; import { store } from "../../redux/store"; -import { DeepPartial } from "redux"; import { Everything } from "../../interfaces"; import { Actions } from "../../constants"; diff --git a/frontend/connectivity/__tests__/ping_mqtt_test.ts b/frontend/connectivity/__tests__/ping_mqtt_test.ts index 872f881f72..296328a462 100644 --- a/frontend/connectivity/__tests__/ping_mqtt_test.ts +++ b/frontend/connectivity/__tests__/ping_mqtt_test.ts @@ -14,7 +14,7 @@ import { import { Farmbot } from "farmbot"; import { FarmBotInternalConfig } from "farmbot/dist/config"; import { pingNO } from "../index"; -import { DeepPartial } from "redux"; +import { DeepPartial } from "../../redux/interfaces"; const state: Partial = { LAST_PING_IN: 123, diff --git a/frontend/css/farm_designer/farm_designer.scss b/frontend/css/farm_designer/farm_designer.scss index e131a8a44f..d5d2060d8a 100644 --- a/frontend/css/farm_designer/farm_designer.scss +++ b/frontend/css/farm_designer/farm_designer.scss @@ -671,11 +671,11 @@ .garden-map-legend { position: fixed; top: 110px; - right: -140px; + right: -155px; z-index: 3; transition: all 0.4s ease; &.active { - transform: translateX(-150px); + transform: translateX(-165px); } .content { display: flex; diff --git a/frontend/css/global.scss b/frontend/css/global.scss index 711de12636..b3c9e5ddaa 100644 --- a/frontend/css/global.scss +++ b/frontend/css/global.scss @@ -759,7 +759,7 @@ a { .sensor-selection, .sensor-history-time-selection, .sensor-history-location-selection { - margin-bottom: 1rem; + margin-bottom: 1rem !important; } .row { margin-bottom: 0 !important; @@ -775,7 +775,9 @@ a { .add-sensor-reading-menu { width: 300px; .green { - margin-bottom: 1rem; + position: absolute; + bottom: 1rem; + right: 1rem; } .reading-location, .add-reading-value-form { @@ -1782,7 +1784,7 @@ ul { width: 2rem; height: 2rem; text-align: center; - line-height: 1.7rem; + line-height: 1.3rem; margin-left: 5px; } .markdown { diff --git a/frontend/devices/__tests__/actions_test.ts b/frontend/devices/__tests__/actions_test.ts index 8eb76ad323..ede05d510a 100644 --- a/frontend/devices/__tests__/actions_test.ts +++ b/frontend/devices/__tests__/actions_test.ts @@ -55,7 +55,7 @@ import { buildResourceIndex } from "../../__test_support__/resource_index_builde import axios from "axios"; import { success, error, warning, info } from "../../toast/toast"; import { edit, save } from "../../api/crud"; -import { DeepPartial } from "redux"; +import { DeepPartial } from "../../redux/interfaces"; import { Farmbot } from "farmbot"; import { goToFbosSettings } from "../../settings/maybe_highlight"; diff --git a/frontend/farm_designer/__tests__/index_test.tsx b/frontend/farm_designer/__tests__/index_test.tsx index 19e743bd65..26acd1746b 100644 --- a/frontend/farm_designer/__tests__/index_test.tsx +++ b/frontend/farm_designer/__tests__/index_test.tsx @@ -126,7 +126,7 @@ describe("", () => { it("renders saved garden indicator", () => { const p = fakeProps(); - p.designer.openedSavedGarden = "SavedGardenUuid"; + p.designer.openedSavedGarden = 1; const wrapper = mount(); expect(wrapper.text().toLowerCase()).toContain("viewing saved garden"); }); diff --git a/frontend/farm_designer/__tests__/reducer_test.ts b/frontend/farm_designer/__tests__/reducer_test.ts index f95dbc4b8b..71ac71edd4 100644 --- a/frontend/farm_designer/__tests__/reducer_test.ts +++ b/frontend/farm_designer/__tests__/reducer_test.ts @@ -256,10 +256,10 @@ describe("designer reducer", () => { }); it("sets opened saved garden", () => { - const payload = "savedGardenUuid"; - const action: ReduxAction = { + const payload = 1; + const action: ReduxAction = { type: Actions.CHOOSE_SAVED_GARDEN, - payload + payload, }; const newState = designer(oldState(), action); expect(newState.openedSavedGarden).toEqual(payload); diff --git a/frontend/farm_designer/__tests__/state_to_props_test.ts b/frontend/farm_designer/__tests__/state_to_props_test.ts index 2be33fa70f..ee1d4bf7dd 100644 --- a/frontend/farm_designer/__tests__/state_to_props_test.ts +++ b/frontend/farm_designer/__tests__/state_to_props_test.ts @@ -167,8 +167,8 @@ describe("getPlants()", () => { it("returns plant templates", () => { const resources = fakeResources(); - const savedGardenUuid = Object.keys(resources.index.byKind["SavedGarden"])[0]; - resources.consumers.farm_designer.openedSavedGarden = savedGardenUuid; + const savedGardenId = 1; + resources.consumers.farm_designer.openedSavedGarden = savedGardenId; expect(getPlants(resources).length).toEqual(1); }); diff --git a/frontend/farm_designer/interfaces.ts b/frontend/farm_designer/interfaces.ts index 119de9742c..bbf966016a 100644 --- a/frontend/farm_designer/interfaces.ts +++ b/frontend/farm_designer/interfaces.ts @@ -165,7 +165,7 @@ export interface DesignerState { chosenLocation: BotPosition; drawnPoint: DrawnPointPayl | undefined; drawnWeed: DrawnWeedPayl | undefined; - openedSavedGarden: string | undefined; + openedSavedGarden: number | undefined; tryGroupSortType: ExtendedPointGroupSortType | undefined; editGroupAreaInMap: boolean; visualizedSequence: UUID | undefined; @@ -311,7 +311,7 @@ export type PlantOptions = Partial; export interface EditPlantInfoProps { dispatch: Function; findPlant(stringyID: string | undefined): TaggedPlant | undefined; - openedSavedGarden: string | undefined; + openedSavedGarden: number | undefined; timeSettings: TimeSettings; getConfigValue: GetWebAppConfigValue; soilHeightPoints: TaggedGenericPointer[]; diff --git a/frontend/farm_designer/map/layers/plants/__tests__/plant_actions_test.ts b/frontend/farm_designer/map/layers/plants/__tests__/plant_actions_test.ts index 1851ab2ad5..ef84ef6444 100644 --- a/frontend/farm_designer/map/layers/plants/__tests__/plant_actions_test.ts +++ b/frontend/farm_designer/map/layers/plants/__tests__/plant_actions_test.ts @@ -54,7 +54,7 @@ describe("newPlantKindAndBody()", () => { y: 0, slug: "mint", cropName: "Mint", - openedSavedGarden: "SavedGarden.1.1", + openedSavedGarden: 1, depth: 0, designer: fakeDesignerState(), }; diff --git a/frontend/farm_designer/map/layers/plants/plant_actions.ts b/frontend/farm_designer/map/layers/plants/plant_actions.ts index d3ff4979b0..184616c6e3 100644 --- a/frontend/farm_designer/map/layers/plants/plant_actions.ts +++ b/frontend/farm_designer/map/layers/plants/plant_actions.ts @@ -4,8 +4,7 @@ import { AxisNumberProperty, TaggedPlant, MapTransformProps, } from "../../interfaces"; import { Plant, DEFAULT_PLANT_RADIUS } from "../../../plant"; -import { unpackUUID } from "../../../../util"; -import { isNumber, isString } from "lodash"; +import { isNumber } from "lodash"; import { DesignerState, GardenMapState, MovePointsProps, } from "../../../interfaces"; @@ -25,7 +24,7 @@ export interface NewPlantKindAndBodyProps { y: number; slug: string; cropName: string; - openedSavedGarden: string | undefined; + openedSavedGarden: number | undefined; depth: number; designer: DesignerState; } @@ -35,9 +34,7 @@ export const newPlantKindAndBody = (props: NewPlantKindAndBodyProps): { kind: TaggedPlant["kind"], body: TaggedPlant["body"], } => { - const savedGardenId = isString(props.openedSavedGarden) - ? unpackUUID(props.openedSavedGarden).remoteId - : undefined; + const savedGardenId = props.openedSavedGarden || undefined; return isNumber(savedGardenId) ? { kind: "PlantTemplate", @@ -75,7 +72,7 @@ export interface CreatePlantProps { gardenCoords: AxisNumberProperty; gridSize: AxisNumberProperty | undefined; dispatch: Function; - openedSavedGarden: string | undefined; + openedSavedGarden: number | undefined; depth: number; designer: DesignerState; } diff --git a/frontend/farm_designer/reducer.ts b/frontend/farm_designer/reducer.ts index e4a1b088b7..a71d8648d8 100644 --- a/frontend/farm_designer/reducer.ts +++ b/frontend/farm_designer/reducer.ts @@ -188,7 +188,7 @@ export const designer = generateReducer(initialState) push(Path.location({ x: payload.x, y: payload.y })); return s; }) - .add(Actions.CHOOSE_SAVED_GARDEN, (s, { payload }) => { + .add(Actions.CHOOSE_SAVED_GARDEN, (s, { payload }) => { s.openedSavedGarden = payload; return s; }) diff --git a/frontend/farm_designer/state_to_props.ts b/frontend/farm_designer/state_to_props.ts index da327ae913..3c2b6cc8e6 100644 --- a/frontend/farm_designer/state_to_props.ts +++ b/frontend/farm_designer/state_to_props.ts @@ -22,13 +22,13 @@ import { selectAllFarmwareEnvs, selectAllCurves, } from "../resources/selectors"; -import { validFwConfig, unpackUUID, validFbosConfig } from "../util"; +import { validFwConfig, validFbosConfig } from "../util"; import { validBotLocationData } from "../util/location"; import { getWebAppConfigValue } from "../config_storage/actions"; import { FarmDesignerProps, CameraCalibrationData } from "./interfaces"; import { TaggedPlant, BotSize } from "./map/interfaces"; import { RestResources } from "../resources/interfaces"; -import { isString, uniq, chain } from "lodash"; +import { isFinite, uniq, chain } from "lodash"; import { BooleanSetting } from "../session_keys"; import { getEnv } from "../farmware/state_to_props"; import { getFirmwareConfig, getFbosConfig } from "../resources/getters"; @@ -50,9 +50,9 @@ export const getPlants = (resources: RestResources) => { const onlyPlants = selectAllPlantPointers(resources.index); const plantTemplates = selectAllPlantTemplates(resources.index); const { openedSavedGarden } = resources.consumers.farm_designer; - return isString(openedSavedGarden) + return isFinite(openedSavedGarden) ? plantTemplates.filter(x => - x.body.saved_garden_id === unpackUUID(openedSavedGarden).remoteId) + x.body.saved_garden_id === openedSavedGarden) : onlyPlants; }; diff --git a/frontend/folders/__tests__/actions_test.ts b/frontend/folders/__tests__/actions_test.ts index 56eeae7013..c2ad506eba 100644 --- a/frontend/folders/__tests__/actions_test.ts +++ b/frontend/folders/__tests__/actions_test.ts @@ -21,7 +21,7 @@ import { sequenceEditMaybeSave, } from "../actions"; import { store } from "../../redux/store"; -import { DeepPartial } from "redux"; +import { DeepPartial } from "../../redux/interfaces"; import { Everything } from "../../interfaces"; import { buildResourceIndex } from "../../__test_support__/resource_index_builder"; import { newTaggedResource } from "../../sync/actions"; diff --git a/frontend/folders/actions.ts b/frontend/folders/actions.ts index 86f9ddcf00..6e6911c4d3 100644 --- a/frontend/folders/actions.ts +++ b/frontend/folders/actions.ts @@ -2,7 +2,7 @@ import { Color, SpecialStatus, TaggedSequence } from "farmbot"; import { store } from "../redux/store"; import { initSave, destroy, edit, save, init } from "../api/crud"; import { Folder } from "farmbot/dist/resources/api_resources"; -import { DeepPartial } from "redux"; +import { DeepPartial } from "../redux/interfaces"; import { findFolderById } from "../resources/selectors_by_id"; import { Actions } from "../constants"; import { t } from "../i18next_wrapper"; diff --git a/frontend/plants/__tests__/map_state_to_props_test.ts b/frontend/plants/__tests__/map_state_to_props_test.ts index 62ef2bd72f..bef6a75df8 100644 --- a/frontend/plants/__tests__/map_state_to_props_test.ts +++ b/frontend/plants/__tests__/map_state_to_props_test.ts @@ -29,7 +29,7 @@ describe("mapStateToProps()", () => { template.body.id = 10; state.resources = buildResourceIndex([template]); const uuid = Object.keys(state.resources.index.all)[0]; - state.resources.consumers.farm_designer.openedSavedGarden = "uuid"; + state.resources.consumers.farm_designer.openedSavedGarden = 1; const result = mapStateToProps(state); expect(result.findPlant("10")).toEqual( expect.objectContaining({ uuid })); diff --git a/frontend/plants/__tests__/plant_info_test.tsx b/frontend/plants/__tests__/plant_info_test.tsx index 5073da687a..c0f1f760e0 100644 --- a/frontend/plants/__tests__/plant_info_test.tsx +++ b/frontend/plants/__tests__/plant_info_test.tsx @@ -98,7 +98,7 @@ describe("", () => { it("gets template id", () => { mockPath = Path.mock(Path.plantTemplates(2)); const p = fakeProps(); - p.openedSavedGarden = "uuid"; + p.openedSavedGarden = 1; const wrapper = mount(); expect(wrapper.instance().stringyID).toEqual("2"); }); diff --git a/frontend/plants/__tests__/plant_inventory_test.tsx b/frontend/plants/__tests__/plant_inventory_test.tsx index aa8f072b6d..0e19613ee1 100644 --- a/frontend/plants/__tests__/plant_inventory_test.tsx +++ b/frontend/plants/__tests__/plant_inventory_test.tsx @@ -158,7 +158,7 @@ describe("", () => { window.confirm = () => true; const p = fakeProps(); p.plantsPanelState.plants = true; - p.openedSavedGarden = "fake"; + p.openedSavedGarden = 1; const wrapper = mount(); const plantsSection = wrapper.find(PanelSection).at(2); expect(plantsSection.text().toLowerCase()).not.toContain("delete all"); diff --git a/frontend/plants/__tests__/select_plants_test.tsx b/frontend/plants/__tests__/select_plants_test.tsx index 39bdf2b46c..cf9c5ec957 100644 --- a/frontend/plants/__tests__/select_plants_test.tsx +++ b/frontend/plants/__tests__/select_plants_test.tsx @@ -63,7 +63,7 @@ describe("", () => { getConfigValue: () => true, plants: [plant1, plant2], dispatch: jest.fn(x => x), - gardenOpen: undefined, + gardenOpenId: undefined, allPoints: [], toolTransformProps: fakeToolTransformProps(), isActive: () => false, @@ -377,7 +377,7 @@ describe("", () => { it("doesn't create group", () => { const p = fakeProps(); - p.gardenOpen = "uuid"; + p.gardenOpenId = 1; const wrapper = mount(); wrapper.find(".dark-blue").simulate("click"); expect(createGroup).not.toHaveBeenCalled(); diff --git a/frontend/plants/crop_info.tsx b/frontend/plants/crop_info.tsx index 510dc3b3a1..af975467f4 100644 --- a/frontend/plants/crop_info.tsx +++ b/frontend/plants/crop_info.tsx @@ -204,7 +204,7 @@ const Companions = (props: CropInfoListProps) => { interface AddPlantHereButtonProps { botPosition: BotPosition; - openedSavedGarden: string | undefined; + openedSavedGarden: number | undefined; cropName: string; slug: string; dispatch: Function; diff --git a/frontend/plants/plant_info.tsx b/frontend/plants/plant_info.tsx index ee74842b41..2372f5670c 100644 --- a/frontend/plants/plant_info.tsx +++ b/frontend/plants/plant_info.tsx @@ -9,7 +9,7 @@ import { } from "../farm_designer/designer_panel"; import { t } from "../i18next_wrapper"; import { EditPlantInfoProps, PlantOptions } from "../farm_designer/interfaces"; -import { isString } from "lodash"; +import { isFinite } from "lodash"; import { push } from "../history"; import { destroy, edit, save } from "../api/crud"; import { BooleanSetting } from "../session_keys"; @@ -20,7 +20,7 @@ import { validGoButtonAxes } from "../farm_designer/move_to"; export type UpdatePlant = (uuid: string, update: PlantOptions) => void; export class RawPlantInfo extends React.Component { - get templates() { return isString(this.props.openedSavedGarden); } + get templates() { return isFinite(this.props.openedSavedGarden); } get stringyID() { return Path.getSlug((this.templates ? Path.plantTemplates diff --git a/frontend/plants/plant_inventory.tsx b/frontend/plants/plant_inventory.tsx index 1058ddb378..7315fac020 100644 --- a/frontend/plants/plant_inventory.tsx +++ b/frontend/plants/plant_inventory.tsx @@ -48,7 +48,7 @@ export interface PlantInventoryProps { allPoints: TaggedPoint[]; plantTemplates: TaggedPlantTemplate[]; plantPointerCount: number; - openedSavedGarden: string | undefined; + openedSavedGarden: number | undefined; plantsPanelState: PlantsPanelState; getConfigValue: GetWebAppConfigValue; } diff --git a/frontend/plants/select_plants.tsx b/frontend/plants/select_plants.tsx index 8055cbd236..8553d6e98e 100644 --- a/frontend/plants/select_plants.tsx +++ b/frontend/plants/select_plants.tsx @@ -116,7 +116,7 @@ export const mapStateToProps = (props: Everything): SelectPlantsProps => { plants: getPlants(props.resources), allPoints: selectAllActivePoints(props.resources.index), dispatch: props.dispatch, - gardenOpen: openedSavedGarden, + gardenOpenId: openedSavedGarden, tools: selectAllTools(props.resources.index), groups: selectAllPointGroups(props.resources.index), isActive: isActive(selectAllToolSlotPointers(props.resources.index)), @@ -135,7 +135,7 @@ export interface SelectPlantsProps { selected: UUID[] | undefined; selectionPointType: PointType[] | undefined; getConfigValue: GetWebAppConfigValue; - gardenOpen: string | undefined; + gardenOpenId: number | undefined; toolTransformProps: ToolTransformProps; isActive(id: number | undefined): boolean; tools: TaggedTool[]; @@ -288,7 +288,7 @@ export class RawSelectPlants