Skip to content

Commit 70ed04c

Browse files
Merge pull request #2483 from FarmBot/staging
v15.14.0
2 parents 0ac5f4f + 1b30aa0 commit 70ed04c

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

47 files changed

+900
-287
lines changed

Gemfile.lock

Lines changed: 24 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ GEM
6767
zeitwerk (~> 2.3)
6868
addressable (2.8.7)
6969
public_suffix (>= 2.0.2, < 7.0)
70-
amq-protocol (2.3.2)
70+
amq-protocol (2.3.3)
7171
ast (2.4.2)
7272
base64 (0.2.0)
7373
bcrypt (3.1.20)
@@ -104,16 +104,16 @@ GEM
104104
railties (>= 4.1.0)
105105
responders
106106
warden (~> 1.2.3)
107-
diff-lcs (1.5.1)
107+
diff-lcs (1.6.0)
108108
digest-crc (0.7.0)
109109
rake (>= 12.0.0, < 14.0.0)
110110
discard (1.4.0)
111111
activerecord (>= 4.2, < 9.0)
112112
docile (1.4.1)
113113
e2mmap (0.1.0)
114114
erubi (1.13.1)
115-
factory_bot (6.5.0)
116-
activesupport (>= 5.0.0)
115+
factory_bot (6.5.1)
116+
activesupport (>= 6.1.0)
117117
factory_bot_rails (6.4.4)
118118
factory_bot (~> 6.5)
119119
railties (>= 5.0.0)
@@ -139,20 +139,20 @@ GEM
139139
retriable (>= 2.0, < 4.a)
140140
google-apis-iamcredentials_v1 (0.22.0)
141141
google-apis-core (>= 0.15.0, < 2.a)
142-
google-apis-storage_v1 (0.49.0)
142+
google-apis-storage_v1 (0.50.0)
143143
google-apis-core (>= 0.15.0, < 2.a)
144144
google-cloud-core (1.7.1)
145145
google-cloud-env (>= 1.0, < 3.a)
146146
google-cloud-errors (~> 1.0)
147147
google-cloud-env (2.2.1)
148148
faraday (>= 1.0, < 3.a)
149149
google-cloud-errors (1.4.0)
150-
google-cloud-storage (1.54.0)
150+
google-cloud-storage (1.55.0)
151151
addressable (~> 2.8)
152152
digest-crc (~> 0.4)
153153
google-apis-core (~> 0.13)
154154
google-apis-iamcredentials_v1 (~> 0.18)
155-
google-apis-storage_v1 (~> 0.38)
155+
google-apis-storage_v1 (>= 0.42)
156156
google-cloud-core (~> 1.6)
157157
googleauth (~> 1.9)
158158
mini_mime (~> 1.0)
@@ -167,10 +167,11 @@ GEM
167167
signet (>= 0.16, < 2.a)
168168
hashdiff (1.1.2)
169169
hashie (4.1.0)
170-
httpclient (2.8.3)
170+
httpclient (2.9.0)
171+
mutex_m
171172
i18n (1.14.7)
172173
concurrent-ruby (~> 1.0)
173-
json (2.9.1)
174+
json (2.10.1)
174175
jsonapi-renderer (0.2.2)
175176
jwt (2.10.1)
176177
base64
@@ -186,7 +187,7 @@ GEM
186187
activerecord
187188
kaminari-core (= 1.2.2)
188189
kaminari-core (1.2.2)
189-
logger (1.6.5)
190+
logger (1.6.6)
190191
lograge (0.14.0)
191192
actionpack (>= 4)
192193
activesupport (>= 4)
@@ -210,23 +211,23 @@ GEM
210211
mutex_m (0.3.0)
211212
net-http (0.6.0)
212213
uri
213-
net-imap (0.5.5)
214+
net-imap (0.5.6)
214215
date
215216
net-protocol
216217
net-pop (0.1.2)
217218
net-protocol
218219
net-protocol (0.2.2)
219220
timeout
220-
net-smtp (0.5.0)
221+
net-smtp (0.5.1)
221222
net-protocol
222223
nio4r (2.7.4)
223-
nokogiri (1.18.2-aarch64-linux-gnu)
224+
nokogiri (1.18.3-aarch64-linux-gnu)
224225
racc (~> 1.4)
225-
nokogiri (1.18.2-x86_64-linux-gnu)
226+
nokogiri (1.18.3-x86_64-linux-gnu)
226227
racc (~> 1.4)
227228
orm_adapter (0.5.0)
228229
os (1.1.4)
229-
parser (3.3.7.0)
230+
parser (3.3.7.1)
230231
ast (~> 2.4.1)
231232
racc
232233
passenger (6.0.23)
@@ -247,7 +248,7 @@ GEM
247248
hashie (~> 4.1)
248249
multi_json (~> 1.15)
249250
racc (1.8.1)
250-
rack (2.2.10)
251+
rack (2.2.11)
251252
rack-attack (6.7.0)
252253
rack (>= 1.0, < 4)
253254
rack-cors (2.0.2)
@@ -303,13 +304,13 @@ GEM
303304
actionpack (>= 5.2)
304305
railties (>= 5.2)
305306
retriable (3.1.2)
306-
rexml (3.4.0)
307-
rollbar (3.6.0)
307+
rexml (3.4.1)
308+
rollbar (3.6.1)
308309
rspec (3.13.0)
309310
rspec-core (~> 3.13.0)
310311
rspec-expectations (~> 3.13.0)
311312
rspec-mocks (~> 3.13.0)
312-
rspec-core (3.13.2)
313+
rspec-core (3.13.3)
313314
rspec-support (~> 3.13.0)
314315
rspec-expectations (3.13.3)
315316
diff-lcs (>= 1.2.0, < 2.0)
@@ -331,7 +332,7 @@ GEM
331332
scenic (1.8.0)
332333
activerecord (>= 4.0.0)
333334
railties (>= 4.0.0)
334-
scout_apm (5.6.0)
335+
scout_apm (5.6.1)
335336
parser
336337
secure_headers (7.1.0)
337338
set (1.1.1)
@@ -369,13 +370,13 @@ GEM
369370
tzinfo-data (1.2025.1)
370371
tzinfo (>= 1.0.0)
371372
uber (0.1.0)
372-
uri (1.0.2)
373+
uri (1.0.3)
373374
valid_url (0.0.4)
374375
addressable
375376
rails
376377
warden (1.2.9)
377378
rack (>= 2.0.9)
378-
webmock (3.24.0)
379+
webmock (3.25.0)
379380
addressable (>= 2.8.0)
380381
crack (>= 0.3.2)
381382
hashdiff (>= 0.4.0, < 2.0.0)
@@ -384,7 +385,7 @@ GEM
384385
base64
385386
websocket-extensions (>= 0.1.0)
386387
websocket-extensions (0.1.5)
387-
zeitwerk (2.7.1)
388+
zeitwerk (2.7.2)
388389

389390
PLATFORMS
390391
aarch64-linux

frontend/__test_support__/additional_mocks.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ window.location = {
1313
ancestorOrigins,
1414
pathname: "", href: "", hash: "", search: "",
1515
hostname: "", origin: "", port: "", protocol: "", host: "",
16-
};
16+
} as unknown as Location & string;
1717

1818
console.error = jest.fn(); // enzyme
1919

@@ -43,6 +43,7 @@ global.mockNavigate = jest.fn(() => jest.fn());
4343

4444
jest.mock("react-router", () => ({
4545
BrowserRouter: jest.fn(({ children }) => <div>{children}</div>),
46+
MemoryRouter: jest.fn(({ children }) => <div>{children}</div>),
4647
Route: jest.fn(({ children }) => <div>{children}</div>),
4748
Routes: jest.fn(({ children }) => <div>{children}</div>),
4849
useNavigate: () => mockNavigate,

frontend/__test_support__/three_d_mocks.tsx

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import * as THREE from "three";
1010
import React, { ReactNode } from "react";
1111
import { TransitionFn, UseSpringProps } from "@react-spring/three";
1212
import { ThreeElements } from "@react-three/fiber";
13+
import { Cloud, Clouds, Image, Tube } from "@react-three/drei";
1314

1415
const GroupForTests = (props: ThreeElements["group"]) =>
1516
// @ts-expect-error Property does not exist on type JSX.IntrinsicElements
@@ -612,8 +613,9 @@ jest.mock("@react-three/drei", () => {
612613
<div className={"line"}>{name}</div>,
613614
Trail: ({ name }: { name: string }) =>
614615
<div className={"trail"}>{name}</div>,
615-
Tube: ({ name, children }: { name: string, children: ReactNode }) =>
616-
<div className={"tube" + name}>{children}</div>,
616+
Tube: (props: React.ComponentProps<typeof Tube>) =>
617+
// @ts-expect-error geometry props not assignable to div
618+
<div className={"tube"} {...props}>{props.children}</div>,
617619
Center: ({ children }: { children: ReactNode }) =>
618620
<div className={"center"}>{children}</div>,
619621
Text3D: ({ children }: { children: ReactNode }) =>
@@ -642,12 +644,15 @@ jest.mock("@react-three/drei", () => {
642644
<div className={"stats"}>{name}</div>,
643645
Billboard: ({ name, children }: { name: string, children: ReactNode }) =>
644646
<div className={"billboard" + name}>{children}</div>,
645-
Image: ({ name, url }: { name: string, url: string }) =>
646-
<div className={"image"}>{name} {url}</div>,
647-
Clouds: ({ name }: { name: string }) =>
648-
<div className={"clouds"}>{name}</div>,
649-
Cloud: ({ name }: { name: string }) =>
650-
<div className={"cloud"}>{name}</div>,
647+
Image: (props: React.ComponentProps<typeof Image>) =>
648+
// @ts-expect-error geometry props not assignable to div
649+
<div className={"image"} {...props}>{props.name} {props.url}</div>,
650+
Clouds: (props: React.ComponentProps<typeof Clouds>) =>
651+
// @ts-expect-error geometry props not assignable to div
652+
<div className={"clouds"} {...props}>{props.children}</div>,
653+
Cloud: (props: React.ComponentProps<typeof Cloud>) =>
654+
// @ts-expect-error geometry props not assignable to div
655+
<div className={"cloud"} {...props} />,
651656
OrthographicCamera: ({ name }: { name: string }) =>
652657
<div className={"orthographic-camera"}>{name}</div>,
653658
};

frontend/__tests__/hotkeys_test.tsx

Lines changed: 7 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
const mockSyncThunk = jest.fn();
22
jest.mock("../devices/actions", () => ({ sync: () => mockSyncThunk }));
3-
jest.mock("../farm_designer/map/actions", () => ({ unselectPlant: jest.fn() }));
43

54
import { fakeState } from "../__test_support__/fake_state";
65
const mockState = fakeState();
@@ -16,10 +15,10 @@ import {
1615
HotKey, HotKeys, HotKeysProps, hotkeysWithActions, toggleHotkeyHelpOverlay,
1716
} from "../hotkeys";
1817
import { sync } from "../devices/actions";
19-
import { unselectPlant } from "../farm_designer/map/actions";
2018
import { save } from "../api/crud";
2119
import { Actions } from "../constants";
2220
import { Path } from "../internal_urls";
21+
import { mockDispatch } from "../__test_support__/fake_dispatch";
2322

2423
describe("hotkeysWithActions()", () => {
2524
beforeEach(() => {
@@ -59,14 +58,12 @@ describe("hotkeysWithActions()", () => {
5958
hotkeys[HotKey.addEvent].onKeyDown?.(e);
6059
expect(navigate).toHaveBeenCalledWith(Path.farmEvents("add"));
6160

62-
hotkeysSettingsPath[HotKey.backToPlantOverview].onKeyDown?.(e);
63-
expect(navigate).toHaveBeenCalledWith(Path.plants());
64-
expect(unselectPlant).toHaveBeenCalled();
65-
jest.clearAllMocks();
66-
const hotkeysPhotosPath = hotkeysWithActions(navigate, dispatch, "photos");
67-
hotkeysPhotosPath[HotKey.backToPlantOverview].onKeyDown?.(e);
68-
expect(navigate).not.toHaveBeenCalled();
69-
expect(unselectPlant).not.toHaveBeenCalled();
61+
const hotkeysWithDispatch =
62+
hotkeysWithActions(navigate, mockDispatch(dispatch), "");
63+
hotkeysWithDispatch[HotKey.closePanel].onKeyDown?.(e);
64+
expect(dispatch).toHaveBeenCalledWith({
65+
type: Actions.SET_PANEL_OPEN, payload: false,
66+
});
7067
});
7168
});
7269

frontend/css/farm_designer/farm_designer_panels.scss

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -362,16 +362,6 @@
362362
}
363363
}
364364

365-
.additional-weed-properties {
366-
li {
367-
display: grid;
368-
grid-template-columns: 1fr 1fr;
369-
gap: 1rem;
370-
align-items: center;
371-
margin-top: 1rem;
372-
}
373-
}
374-
375365
.panel-section {
376366
.delete {
377367
height: 2rem;

frontend/farm_designer/__tests__/map_size_setting_test.tsx

Lines changed: 15 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -5,21 +5,27 @@ jest.mock("../../config_storage/actions", () => ({
55

66
import React from "react";
77
import { MapSizeInputs, MapSizeInputsProps } from "../map_size_setting";
8-
import { mount } from "enzyme";
8+
import { render, screen } from "@testing-library/react";
99
import { setWebAppConfigValue } from "../../config_storage/actions";
1010
import { NumericSetting } from "../../session_keys";
11+
import { fakeWebAppConfig } from "../../__test_support__/fake_state/resources";
12+
import { WebAppConfig } from "farmbot/dist/resources/configs/web_app";
13+
import { changeBlurableInputRTL } from "../../__test_support__/helpers";
1114

1215
describe("<MapSizeInputs />", () => {
13-
const fakeProps = (): MapSizeInputsProps => ({
14-
getConfigValue: () => 100,
15-
dispatch: jest.fn(),
16-
});
16+
const fakeProps = (config: WebAppConfig): MapSizeInputsProps => {
17+
return {
18+
getConfigValue: key => config[key],
19+
dispatch: jest.fn(),
20+
};
21+
};
1722

1823
it("changes value", () => {
19-
const wrapper = mount(<MapSizeInputs {...fakeProps()} />);
20-
wrapper.find("input").last().simulate("change"), {
21-
currentTarget: { value: 100 }
22-
};
24+
const config = fakeWebAppConfig();
25+
const p = fakeProps(config.body);
26+
render(<MapSizeInputs {...p} />);
27+
const input = screen.getByDisplayValue("" + config.body.map_size_y);
28+
changeBlurableInputRTL(input, "100");
2329
expect(setWebAppConfigValue).toHaveBeenCalledWith(
2430
NumericSetting.map_size_y, "100");
2531
});

frontend/farm_designer/map_size_setting.tsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import {
33
GetWebAppConfigValue, setWebAppConfigValue,
44
} from "../config_storage/actions";
55
import { t } from "../i18next_wrapper";
6-
import { Row } from "../ui";
6+
import { BlurableInput, Row } from "../ui";
77
import { NumericSetting } from "../session_keys";
88
import {
99
NumberConfigKey as WebAppNumberConfigKey,
@@ -20,12 +20,12 @@ interface LengthInputProps {
2020
const LengthInput = (props: LengthInputProps) =>
2121
<Row className="grid-2-col map-size-grid">
2222
<label>{t(props.label)}</label>
23-
<input
23+
<BlurableInput
2424
type="number"
2525
name={props.setting}
2626
className={getModifiedClassName(props.setting)}
2727
value={"" + props.value}
28-
onChange={e => props.dispatch(setWebAppConfigValue(
28+
onCommit={e => props.dispatch(setWebAppConfigValue(
2929
props.setting, e.currentTarget.value))} />
3030
</Row>;
3131

frontend/hotkeys.tsx

Lines changed: 9 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,9 @@ import React from "react";
22
import { getLinks } from "./nav/nav_links";
33
import { sync } from "./devices/actions";
44
import { HotkeyConfig, useHotkeys, HotkeysDialog2 } from "@blueprintjs/core";
5-
import { unselectPlant } from "./farm_designer/map/actions";
6-
import { getPanelPath, PANEL_BY_SLUG } from "./farm_designer/panel_header";
5+
import {
6+
getPanelPath, PANEL_BY_SLUG, setPanelOpen,
7+
} from "./farm_designer/panel_header";
78
import { t } from "./i18next_wrapper";
89
import { store } from "./redux/store";
910
import { save } from "./api/crud";
@@ -25,7 +26,7 @@ export enum HotKey {
2526
navigateLeft = "navigateLeft",
2627
addPlant = "addPlant",
2728
addEvent = "addEvent",
28-
backToPlantOverview = "backToPlantOverview",
29+
closePanel = "closePanel",
2930
openGuide = "openGuide",
3031
}
3132

@@ -54,9 +55,9 @@ const HOTKEY_BASE_MAP = (): HotkeyConfigs => ({
5455
combo: "ctrl + shift + e",
5556
label: t("Add Event"),
5657
},
57-
[HotKey.backToPlantOverview]: {
58+
[HotKey.closePanel]: {
5859
combo: "escape",
59-
label: t("Back to plant overview"),
60+
label: t("Close panel"),
6061
},
6162
[HotKey.openGuide]: {
6263
combo: "shift + ?",
@@ -106,14 +107,9 @@ export const hotkeysWithActions = (
106107
...hotkeysBase[HotKey.addEvent],
107108
onKeyDown: () => { navigate(Path.farmEvents("add")); },
108109
},
109-
[HotKey.backToPlantOverview]: {
110-
...hotkeysBase[HotKey.backToPlantOverview],
111-
onKeyDown: () => {
112-
if (slug != "photos") {
113-
navigate(Path.plants());
114-
dispatch(unselectPlant(dispatch));
115-
}
116-
},
110+
[HotKey.closePanel]: {
111+
...hotkeysBase[HotKey.closePanel],
112+
onKeyDown: () => { dispatch(setPanelOpen(false)); },
117113
},
118114
[HotKey.openGuide]: hotkeysBase[HotKey.openGuide],
119115
};

0 commit comments

Comments
 (0)