Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 11 additions & 11 deletions Gemfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ GEM
base64 (0.3.0)
bcrypt (3.1.22)
benchmark (0.5.0)
bigdecimal (4.1.1)
bigdecimal (4.1.2)
brakeman (8.0.4)
racc
builder (3.3.0)
Expand Down Expand Up @@ -133,14 +133,14 @@ GEM
docile (1.4.1)
drb (2.2.3)
e2mmap (0.1.0)
erb (6.0.2)
erb (6.0.4)
erubi (1.13.1)
factory_bot (6.5.6)
activesupport (>= 6.1.0)
factory_bot_rails (6.5.1)
factory_bot (~> 6.5)
railties (>= 6.1.0)
faker (3.6.1)
faker (3.8.0)
i18n (>= 1.8.11, < 2)
faraday (2.14.1)
faraday-net_http (>= 2.0, < 3.5)
Expand Down Expand Up @@ -200,7 +200,7 @@ GEM
prism (>= 1.3.0)
rdoc (>= 4.0.0)
reline (>= 0.4.2)
json (2.19.3)
json (2.19.4)
jsonapi-renderer (0.2.2)
jwt (3.1.2)
base64
Expand Down Expand Up @@ -236,10 +236,10 @@ GEM
marcel (1.1.0)
method_source (1.1.0)
mini_mime (1.1.5)
minitest (6.0.3)
minitest (6.0.5)
drb (~> 2.0)
prism (~> 1.5)
multi_json (1.19.1)
multi_json (1.20.1)
mutations (0.9.2)
activesupport
mutex_m (0.3.0)
Expand All @@ -262,7 +262,7 @@ GEM
orm_adapter (0.5.0)
os (1.1.4)
ostruct (0.6.3)
parallel (1.28.0)
parallel (2.0.1)
parser (3.3.11.1)
ast (~> 2.4.1)
racc
Expand Down Expand Up @@ -300,7 +300,7 @@ GEM
rack-cors (3.0.0)
logger
rack (>= 3.0.14)
rack-session (2.1.1)
rack-session (2.1.2)
base64 (>= 0.1.0)
rack (>= 3.0.0)
rack-test (2.2.0)
Expand Down Expand Up @@ -338,7 +338,7 @@ GEM
tsort (>= 0.2)
zeitwerk (~> 2.6)
rainbow (3.1.1)
rake (13.3.1)
rake (13.4.2)
rbtree (0.4.6)
rdoc (7.2.0)
erb
Expand Down Expand Up @@ -383,11 +383,11 @@ GEM
rspec-support (3.13.7)
rspec_junit_formatter (0.6.0)
rspec-core (>= 2, < 4, != 2.12.0)
rubocop (1.86.0)
rubocop (1.86.1)
json (~> 2.3)
language_server-protocol (~> 3.17.0.2)
lint_roller (~> 1.1.0)
parallel (~> 1.10)
parallel (>= 1.10)
parser (>= 3.3.0.2)
rainbow (>= 2.2.2, < 4.0)
regexp_parser (>= 2.9.3, < 3.0)
Expand Down
2 changes: 1 addition & 1 deletion app/views/layouts/dashboard.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
.initial-loading-text { position: absolute; top: 385px;
text-align: center; width: 100%; padding-top: 10%; color: #434343; }
</style>
<%= stylesheet_link_tag *@css_assets %>
<%= stylesheet_link_tag(*@css_assets, preload_links_header: false) %>
<link rel="icon" href="/favicon.ico" type="image/x-icon">
<link rel="apple-touch-icon" href="/images/favicon.png" type="image/png">
<% manifest_file =
Expand Down
154 changes: 77 additions & 77 deletions bun.lock

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
class AddNew3dViewOptionsToWebAppConfig < ActiveRecord::Migration[8.1]
def up
add_column :web_app_configs, :top_down_view, :boolean, default: false
add_column :web_app_configs, :viewpoint_heading, :integer, default: 0
end

def down
remove_column :web_app_configs, :top_down_view
remove_column :web_app_configs, :viewpoint_heading
end
end
5 changes: 5 additions & 0 deletions db/migrate/20260422013033_change_viewpoint_heading_default.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
class ChangeViewpointHeadingDefault < ActiveRecord::Migration[8.1]
def change
change_column_default(:web_app_configs, :viewpoint_heading, from: 0, to: 30)
end
end
6 changes: 5 additions & 1 deletion db/structure.sql
Original file line number Diff line number Diff line change
Expand Up @@ -2037,7 +2037,9 @@ CREATE TABLE public.web_app_configs (
show_missed_step_plot boolean DEFAULT false,
enable_3d_electronics_box_top boolean DEFAULT true,
three_d_garden boolean DEFAULT false,
dark_mode boolean DEFAULT true
dark_mode boolean DEFAULT true,
top_down_view boolean DEFAULT false,
viewpoint_heading integer DEFAULT 30
);


Expand Down Expand Up @@ -3763,6 +3765,8 @@ ALTER TABLE ONLY public.users
SET search_path TO "$user", public;

INSERT INTO "schema_migrations" (version) VALUES
('20260422013033'),
('20260417190743'),
('20260305192457'),
('20250930204600'),
('20250925195004'),
Expand Down
16 changes: 9 additions & 7 deletions frontend/__test_support__/bun_test_setup.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ const ensureSyntaxError = () => {
writable: true,
});
};
assign(globalThis as unknown as Record<string, unknown>);
assign(globalThis);
assign(globalAny.window as unknown as Record<string, unknown> | undefined);
const windowCtor = globalAny.window?.constructor as
| { prototype?: Record<string, unknown> }
Expand Down Expand Up @@ -74,13 +74,11 @@ const withAxiosDefaultExport = (factory: () => unknown) => () => {

if (globalAny.jest?.mock) {
const originalMock = globalAny.jest.mock.bind(globalAny.jest);
globalAny.jest.mock = ((specifier: string, factory?: unknown) => {
const moduleFactory =
typeof factory === "function" ? factory as () => unknown : undefined;
globalAny.jest.mock = ((specifier: string, factory?: () => unknown) => {
return specifier === "axios" && typeof factory === "function"
? originalMock(specifier,
withAxiosDefaultExport(moduleFactory as () => unknown))
: originalMock(specifier, factory as never);
withAxiosDefaultExport(factory))
: originalMock(specifier, factory);
}) as typeof globalAny.jest.mock;
}

Expand Down Expand Up @@ -229,6 +227,10 @@ const defaultThreeFiberState = () => ({
scene: { traverse: jest.fn() },
size: { width: 800, height: 600 },
pointer: { x: 0, y: 0 },
raycaster: {
setFromCamera: jest.fn(),
intersectObjects: jest.fn(() => []),
},
});

type MockLike<TArgs extends unknown[] = unknown[], TResult = unknown> = {
Expand Down Expand Up @@ -274,7 +276,7 @@ beforeEach(() => {
resetMutableFixture(globalAny.globalConfig, globalConfigBaseline);
} else {
globalAny.globalConfig =
cloneForReset(globalConfigBaseline) as Record<string, string>;
cloneForReset(globalConfigBaseline);
}
globalThis.localStorage?.clear();
globalThis.sessionStorage?.clear();
Expand Down
3 changes: 2 additions & 1 deletion frontend/__test_support__/fake_designer_state.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,8 @@ export const fakeDesignerState = (): DesignerState => ({
cropRadius: undefined,
distanceIndicator: "",
panelOpen: true,
threeDTopDownView: false,
threeDTopDownView: undefined,
threeDCameraSelection: false,
threeDExaggeratedZ: false,
threeDTime: undefined,
});
Expand Down
15 changes: 15 additions & 0 deletions frontend/__test_support__/setup_tests.ts
Original file line number Diff line number Diff line change
@@ -1,2 +1,17 @@
import "@testing-library/jest-dom";
import "./customMatchers";

expect.extend({
toContainHTML(received: Element | { innerHTML?: string }, expected: string) {
const actual = received?.innerHTML ?? "";
const pass = actual.includes(expected);

return {
pass,
message: () =>
`expected html to${pass ? " not" : ""} contain ` +
`${this.utils.printExpected(expected)}\n` +
`received: ${this.utils.printReceived(actual)}`,
};
},
});
10 changes: 9 additions & 1 deletion frontend/__test_support__/three_d_mocks.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,7 @@ jest.mock("../three_d_garden/components", () => ({
instanceColor: { needsUpdate: false },
}) as unknown as THREE.InstancedMesh);
return <InstancedMeshForTests
ref={ref as React.Ref<THREE.InstancedMesh>}
ref={ref}
{...rest} />;
},
),
Expand Down Expand Up @@ -203,6 +203,10 @@ jest.mock("@react-three/fiber", () => ({
scene: { traverse: jest.fn() },
size: { width: 800, height: 600 },
pointer: { x: 0, y: 0 },
raycaster: {
setFromCamera: jest.fn(),
intersectObjects: jest.fn(() => []),
},
})),
useThree: jest.fn(() => ({
gl: {
Expand All @@ -214,6 +218,10 @@ jest.mock("@react-three/fiber", () => ({
scene: { traverse: jest.fn() },
pointer: { x: 0, y: 0 },
camera: new THREE.PerspectiveCamera(),
raycaster: {
setFromCamera: jest.fn(),
intersectObjects: jest.fn(() => []),
},
size: { width: 800, height: 600 },
})),
extend: jest.fn(),
Expand Down
2 changes: 1 addition & 1 deletion frontend/__tests__/loading_plant_test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ describe("<LoadingPlant/>", () => {
});

it("clears initial loading text", () => {
const el = { outerHTML: "hidden" } as Pick<Element, "outerHTML">;
const el = { outerHTML: "hidden" };
const collection =
[el as unknown as Element] as unknown as HTMLCollectionOf<Element>;
jest.spyOn(document, "getElementsByClassName")
Expand Down
2 changes: 1 addition & 1 deletion frontend/__tests__/revert_to_english_test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { revertToEnglish } from "../revert_to_english";
describe("revertToEnglish", () => {
it("runs without throwing", async () => {
jest.spyOn(I18n, "detectLanguage")
.mockResolvedValue({ lng: "en" } as never);
.mockResolvedValue({ lng: "en" });

await expect(Promise.resolve(revertToEnglish() as unknown))
.resolves.toBeUndefined();
Expand Down
8 changes: 4 additions & 4 deletions frontend/api/__tests__/crud_data_tracking_test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ describe("AJAX data tracking", () => {
if (!destroy) { return; }
const thunk = destroy(uuid);
if (typeof thunk !== "function") { return; }
await thunk(dispatch as unknown as Function, () =>
await thunk(dispatch, () =>
({ resources: { index: resourceIndex() } }));
expect(maybeStartTrackingModule.maybeStartTracking).toHaveBeenCalled();
});
Expand All @@ -69,7 +69,7 @@ describe("AJAX data tracking", () => {
});
const saveAllAction = loadCrud().saveAll?.(r);
if (typeof saveAllAction !== "function") { return; }
await saveAllAction(dispatch as unknown as Function);
await saveAllAction(dispatch);
expect(maybeStartTrackingModule.maybeStartTracking).toHaveBeenCalled();
});

Expand All @@ -94,7 +94,7 @@ describe("AJAX data tracking", () => {
email: "test@test.com"
});
if (typeof initSaveGetIdAction !== "function") { return; }
const result = initSaveGetIdAction(statefulDispatch as unknown as Function);
const result = initSaveGetIdAction(statefulDispatch);
if (result && typeof result === "object" && result && "catch" in result) {
await (result as Promise<unknown>).catch(() => { });
}
Expand All @@ -107,7 +107,7 @@ describe("AJAX data tracking", () => {
email: "test@test.com"
});
if (typeof action !== "function") { return; }
await action(dispatch as unknown as Function);
await action(dispatch);
expect(maybeStartTrackingModule.maybeStartTracking).toHaveBeenCalled();
});
});
8 changes: 4 additions & 4 deletions frontend/api/__tests__/crud_destroy_test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ describe("destroy", () => {
.mockImplementation(() => mockReadonlyState);
mockDelete = Promise.resolve({});
deleteSpy = jest.spyOn(axios, "delete")
.mockImplementation(() => mockDelete as never);
.mockImplementation(() => mockDelete);
});

API.setBaseUrl("http://localhost:3000");
Expand Down Expand Up @@ -183,11 +183,11 @@ describe("destroyAll", () => {
.mockImplementation(() => mockReadonlyState);
mockDelete = Promise.resolve({});
deleteSpy = jest.spyOn(axios, "delete")
.mockImplementation(() => mockDelete as never);
.mockImplementation(() => mockDelete);
});

it("confirmed", async () => {
deleteSpy.mockResolvedValueOnce(undefined as never);
deleteSpy.mockResolvedValueOnce(undefined);
const result = fakeDestroyAll("FarmwareEnv", true);
if (!result) { return; }
await expect(result).resolves.toEqual(undefined);
Expand Down Expand Up @@ -230,7 +230,7 @@ describe("destroyAll", () => {
});

it("rejected", async () => {
deleteSpy.mockRejectedValueOnce("error" as never);
deleteSpy.mockRejectedValueOnce("error");
const result = fakeDestroyAll("FarmwareEnv", true);
if (!result) { return; }
await expect(result).rejects.toEqual("error");
Expand Down
4 changes: 2 additions & 2 deletions frontend/config/__tests__/actions_test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,9 +29,9 @@ describe("ready()", () => {
didLoginSpy = jest.spyOn(authActions, "didLogin")
.mockImplementation(() => { });
maybeRefreshTokenSpy = jest.spyOn(refreshToken, "maybeRefreshToken")
.mockImplementation(() => Promise.resolve(undefined) as never);
.mockImplementation(() => Promise.resolve(undefined));
timeoutSpy = jest.spyOn(promiseTimeoutModule, "timeout")
.mockImplementation(() => mockTimeout as never);
.mockImplementation(() => mockTimeout);
fetchStoredTokenSpy = jest.spyOn(Session, "fetchStoredToken")
.mockReturnValue(undefined);
clearSpy = jest.spyOn(Session, "clear")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -339,7 +339,7 @@ describe("onPublicBroadcast", () => {
log.message = "bot xyz is offline";
const taggedLog = fn(log);
const getStateSpy =
jest.spyOn(store, "getState").mockReturnValue(fakeState() as never);
jest.spyOn(store, "getState").mockReturnValue(fakeState());
globalQueue.maybeWork();
getStateSpy.mockRestore();
expect(taggedLog?.kind).toEqual("Log");
Expand Down
13 changes: 13 additions & 0 deletions frontend/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1015,6 +1015,12 @@ export namespace Content {
trim(`Select a map origin by clicking on one of the four quadrants to
adjust the garden map to your viewing angle.`);

export const TOP_DOWN_VIEW =
trim(`Upon open, display the 3D garden map from a top-down perspective.`);

export const CAMERA_STARTING_LOCATION =
trim(`Location of the camera when the 3D garden map is opened.`);

export const CROP_MAP_IMAGES =
trim(`Crop images displayed in the garden map to remove black borders
from image rotation. Crop amount determined by CAMERA ROTATION value.`);
Expand Down Expand Up @@ -1773,6 +1779,10 @@ export namespace SetupWizardContent {
map to your real life FarmBot. The relevant controls are available
below the video for your convenience.`);

export const SET_CAMERA_LOCATION =
trim(`Press the "SET" button to show camera location options.
Select the correct camera angle by clicking on the camera location.`);

export const PRESS_RIGHT_JOG_BUTTON =
trim(`Standing from where you will normally view the FarmBot,
**press the right arrow button**.`);
Expand Down Expand Up @@ -2234,6 +2244,8 @@ export enum DeviceSetting {
mapSize = `Map size`,
rotateMap = `Rotate map`,
mapOrigin = `Map origin`,
topDownView = `Top down view`,
setCameraStartingLocation = `Set camera starting location`,
cropMapImages = `Crop map images`,
clipPhotosOutOfBounds = `Clip photos out of bounds`,
cameraView = `Camera view`,
Expand Down Expand Up @@ -2562,6 +2574,7 @@ export enum Actions {
// 3D
SET_DISTANCE_INDICATOR = "SET_DISTANCE_INDICATOR",
TOGGLE_3D_TOP_DOWN_VIEW = "TOGGLE_3D_TOP_DOWN_VIEW",
TOGGLE_3D_CAMERA_SELECTION = "TOGGLE_3D_CAMERA_SELECTION",
TOGGLE_3D_EXAGGERATED_Z = "TOGGLE_3D_EXAGGERATED_Z",
SET_3D_TIME = "RESET_3D_TIME",

Expand Down
Loading
Loading