From b0914d00ed586d58c3406c37dc775386bd6e6ef8 Mon Sep 17 00:00:00 2001 From: gabrielburnworth Date: Fri, 19 Jan 2024 12:36:47 -0800 Subject: [PATCH 01/12] add unbound button style --- frontend/css/global.scss | 3 +++ frontend/settings/pin_bindings/model.tsx | 12 ++++++++---- 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/frontend/css/global.scss b/frontend/css/global.scss index 29b9c6180..22336b4ad 100644 --- a/frontend/css/global.scss +++ b/frontend/css/global.scss @@ -2027,6 +2027,9 @@ ul { &.hovered { background: $black; } + &.unbound { + background: $placeholder_gray; + } } .led-label { max-width: 7rem; diff --git a/frontend/settings/pin_bindings/model.tsx b/frontend/settings/pin_bindings/model.tsx index f8b4724c5..7706edc78 100644 --- a/frontend/settings/pin_bindings/model.tsx +++ b/frontend/settings/pin_bindings/model.tsx @@ -141,7 +141,7 @@ export const Model = (props: BoxTopBaseProps) => { const BUTTONS: ButtonOrLedItem[] = [ { - label: t("E-Stop"), + label: t("Button 1"), pinNumber: ButtonPin.estop, on: props.botOnline && !locked, position: -60, @@ -152,7 +152,7 @@ export const Model = (props: BoxTopBaseProps) => { ref: estop, }, { - label: t("Unlock"), + label: t("Button 2"), pinNumber: ButtonPin.unlock, blink: props.botOnline && locked, position: -30, @@ -321,7 +321,7 @@ export const Model = (props: BoxTopBaseProps) => { position={[-30, btnPosition, Z]} rotation={[Math.PI / 2, 0, 0]} /> @@ -339,7 +339,11 @@ export const Model = (props: BoxTopBaseProps) => { resources={props.resources} sequenceIdInput={binding?.sequence_id} specialActionInput={binding?.special_action} /> - :

+ :

{getLabel(binding) || label}

} From 527688f0fdc788879b7db6ab6815dacff216e070 Mon Sep 17 00:00:00 2001 From: gabrielburnworth Date: Fri, 19 Jan 2024 12:37:07 -0800 Subject: [PATCH 02/12] fix move to negative coordinate bug --- frontend/farm_designer/move_to.tsx | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/frontend/farm_designer/move_to.tsx b/frontend/farm_designer/move_to.tsx index e0b45c0e2..d53744fa7 100644 --- a/frontend/farm_designer/move_to.tsx +++ b/frontend/farm_designer/move_to.tsx @@ -131,7 +131,9 @@ export const chooseLocation = (props: { }) => { if (props.gardenCoords) { props.dispatch(chooseLocationAction({ - x: props.gardenCoords.x, y: props.gardenCoords.y, z: 0 + x: Math.max(0, props.gardenCoords.x), + y: Math.max(0, props.gardenCoords.y), + z: 0, })); } }; @@ -156,7 +158,7 @@ interface GoToThisLocationButtonState { export class GoToThisLocationButton extends React.Component { + GoToThisLocationButtonState> { state: GoToThisLocationButtonState = { open: false, setAsDefault: false }; toggle = (key: keyof GoToThisLocationButtonState) => () => From 9eb7d3dda7e25415079ce9bfa6ff74846084e296 Mon Sep 17 00:00:00 2001 From: gabrielburnworth Date: Fri, 19 Jan 2024 12:37:20 -0800 Subject: [PATCH 03/12] update fbjs --- frontend/__test_support__/fake_state/resources.ts | 5 +---- frontend/session_keys.ts | 6 ++---- frontend/settings/default_values.ts | 2 +- package.json | 4 ++-- 4 files changed, 6 insertions(+), 11 deletions(-) diff --git a/frontend/__test_support__/fake_state/resources.ts b/frontend/__test_support__/fake_state/resources.ts index 678137292..c1e5e5564 100644 --- a/frontend/__test_support__/fake_state/resources.ts +++ b/frontend/__test_support__/fake_state/resources.ts @@ -36,9 +36,6 @@ import { } from "farmbot/dist/resources/api_resources"; import { MessageType } from "../../sequences/interfaces"; import { TaggedPointGroup } from "../../resources/interfaces"; -import { - BooleanConfigKey as BooleanWebAppConfigKey, -} from "farmbot/dist/resources/configs/web_app"; export const resources: Everything["resources"] = buildResourceIndex(); let idCounter = 1; @@ -336,7 +333,7 @@ export function fakeWebAppConfig(): TaggedWebAppConfig { display_map_missed_steps: false, display_trail: false, dynamic_map: false, - ["enable_3d_electronics_box_top" as BooleanWebAppConfigKey]: true, + enable_3d_electronics_box_top: true, encoder_figure: false, go_button_axes: "XY", hide_webcam_widget: false, diff --git a/frontend/session_keys.ts b/frontend/session_keys.ts index 73e225a2c..a112a9744 100644 --- a/frontend/session_keys.ts +++ b/frontend/session_keys.ts @@ -4,8 +4,7 @@ import { StringConfigKey as WebAppStringConfigKey, } from "farmbot/dist/resources/configs/web_app"; -type WebAppBooleanConfigKeyAll = WebAppBooleanConfigKey - | "enable_3d_electronics_box_top"; +type WebAppBooleanConfigKeyAll = WebAppBooleanConfigKey; type WebAppNumberConfigKeyAll = WebAppNumberConfigKey; type WebAppStringConfigKeyAll = WebAppStringConfigKey; @@ -63,8 +62,7 @@ export const BooleanSetting: BooleanSettings = { disable_i18n: "disable_i18n", hide_webcam_widget: "hide_webcam_widget", hide_sensors: "hide_sensors", - enable_3d_electronics_box_top: - "enable_3d_electronics_box_top" as WebAppBooleanConfigKey, + enable_3d_electronics_box_top: "enable_3d_electronics_box_top", enable_browser_speak: "enable_browser_speak", discard_unsaved: "discard_unsaved", time_format_24_hour: "time_format_24_hour", diff --git a/frontend/settings/default_values.ts b/frontend/settings/default_values.ts index 6ba086369..007a579b6 100644 --- a/frontend/settings/default_values.ts +++ b/frontend/settings/default_values.ts @@ -19,7 +19,7 @@ const DEFAULT_WEB_APP_CONFIG_VALUES: Record = { disable_i18n: false, display_trail: true, dynamic_map: false, - ["enable_3d_electronics_box_top" as Key]: true, + enable_3d_electronics_box_top: true, encoder_figure: false, go_button_axes: "XY", hide_webcam_widget: false, diff --git a/package.json b/package.json index a338b7cc5..c0bef45a7 100644 --- a/package.json +++ b/package.json @@ -35,7 +35,7 @@ "@monaco-editor/react": "4.6.0", "@parcel/transformer-sass": "2.11.0", "@parcel/transformer-typescript-tsc": "2.11.0", - "@react-three/drei": "9.96.0", + "@react-three/drei": "9.96.1", "@react-three/fiber": "8.15.14", "@types/lodash": "4.14.202", "@types/markdown-it": "13.0.7", @@ -50,7 +50,7 @@ "bowser": "2.11.0", "browser-speech": "1.1.1", "events": "3.3.0", - "farmbot": "15.8.5", + "farmbot": "15.8.7", "i18next": "23.7.16", "lodash": "4.17.21", "markdown-it": "14.0.0", From 6c05ee03fe2170e61385711b8c3871a8b2a257cc Mon Sep 17 00:00:00 2001 From: gabrielburnworth Date: Fri, 19 Jan 2024 16:17:21 -0800 Subject: [PATCH 04/12] update instructions and fix url --- README.md | 2 +- ubuntu_example.sh | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index f3746e31e..8dbd43400 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ # FarmBot Web App [![codebeat badge](https://codebeat.co/badges/7f81859b-67fe-4bdb-b56f-050bfed35e9c)](https://codebeat.co/projects/github-com-farmbot-farmbot-web-app-staging) -[![codecov](https://codecov.io/gh/FarmBot/Farmbot-Web-App/branch/main/graph/badge.svg)](https://codecov.io/gh/FarmBot/Farmbot-Web-App) +[![codecov](https://codecov.io/gh/FarmBot/Farmbot-Web-App/branch/staging/graph/badge.svg)](https://codecov.io/gh/FarmBot/Farmbot-Web-App) [![Coverage Status](https://coveralls.io/repos/github/FarmBot/Farmbot-Web-App/badge.svg)](https://coveralls.io/github/FarmBot/Farmbot-Web-App) [![Maintainability](https://api.codeclimate.com/v1/badges/74091163d8a02bb8988f/maintainability)](https://codeclimate.com/github/FarmBot/Farmbot-Web-App/maintainability) diff --git a/ubuntu_example.sh b/ubuntu_example.sh index d39251db6..bd160fb1e 100644 --- a/ubuntu_example.sh +++ b/ubuntu_example.sh @@ -19,7 +19,7 @@ sudo apt remove docker docker.io containerd runc # Install docker and docker compose sudo apt update sudo apt install ca-certificates curl gnupg -y -. /etc/os-release +source /etc/os-release sudo install -m 0755 -d /etc/apt/keyrings curl -fsSL https://download.docker.com/linux/$ID/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg sudo chmod a+r /etc/apt/keyrings/docker.gpg From dd8db418af07ce01191a8c41922e7434e3aa2a78 Mon Sep 17 00:00:00 2001 From: gabrielburnworth Date: Fri, 19 Jan 2024 16:17:49 -0800 Subject: [PATCH 05/12] update tours --- frontend/constants.ts | 2 +- frontend/css/global.scss | 3 +++ frontend/help/tours/data.tsx | 3 ++- frontend/plants/crop_info.tsx | 2 +- 4 files changed, 7 insertions(+), 3 deletions(-) diff --git a/frontend/constants.ts b/frontend/constants.ts index d2d3a4c00..1a5b6f89c 100644 --- a/frontend/constants.ts +++ b/frontend/constants.ts @@ -1475,7 +1475,7 @@ export namespace TourContent { lot of plants at once? Go to the next step of the tour!`); export const GRID_AND_ROW_PLANTING = - trim(`To add a grid or row of plants, scroll to the bottom of the panel, + trim(`To add a grid or row of plants, press the + GRID button, enter values into the grid and row planting fields and click PREVIEW. The previewed plants will show in the map in grayscale. Make adjustments as necessary and when you are happy with the preview, click SAVE. diff --git a/frontend/css/global.scss b/frontend/css/global.scss index 22336b4ad..dbb15d430 100644 --- a/frontend/css/global.scss +++ b/frontend/css/global.scss @@ -974,6 +974,9 @@ hr { box-shadow: 0 0 10px $translucent5, 0 0 5px inset rgba(255, 255, 255, 0.2) !important; } } + &.hard { + border-radius: 5px; + } } a { diff --git a/frontend/help/tours/data.tsx b/frontend/help/tours/data.tsx index 749e253d7..4924e7e39 100644 --- a/frontend/help/tours/data.tsx +++ b/frontend/help/tours/data.tsx @@ -163,7 +163,7 @@ export const TOURS = ( title: t("E-STOP Button"), content: TourContent.ESTOP_BUTTON, beacons: undefined, - activeBeacons: [{ class: "e-stop-btn", type: "soft", keep: true }], + activeBeacons: [{ class: "e-stop-btn", type: "hard", keep: true }], url: undefined, dispatchActions: [ { type: Actions.CLOSE_POPUP, payload: undefined }, @@ -240,6 +240,7 @@ export const TOURS = ( content: TourContent.GRID_AND_ROW_PLANTING, beacons: undefined, activeBeacons: [ + { class: "plus-grid-btn", type: "soft", keep: true }, { class: "grid-and-row-planting", type: "soft" }, { class: "preview-button", type: "hard" }, { class: "save-button", type: "hard" }, diff --git a/frontend/plants/crop_info.tsx b/frontend/plants/crop_info.tsx index af975467f..ec7eaf6a6 100644 --- a/frontend/plants/crop_info.tsx +++ b/frontend/plants/crop_info.tsx @@ -394,7 +394,7 @@ export class RawCropInfo extends React.Component { svgIcon={svgToUrl(result.crop.svg_icon)} /> + target={} content={
From 1239f94854ce07b3e7bf01e913e236e5cff0792c Mon Sep 17 00:00:00 2001 From: gabrielburnworth Date: Wed, 24 Jan 2024 09:46:45 -0800 Subject: [PATCH 06/12] allow lua in shared sequences --- app/mutations/sequences/publish.rb | 2 +- frontend/constants.ts | 3 +++ frontend/css/sequences.scss | 3 +++ .../sequence_editor_middle_active_test.tsx | 22 ++++++++++++++++++- .../panel/__tests__/preview_test.tsx | 17 ++++++++++++++ frontend/sequences/panel/preview_support.tsx | 2 ++ .../sequence_editor_middle_active.tsx | 2 ++ spec/mutations/sequences/publish_spec.rb | 6 ++--- 8 files changed, 52 insertions(+), 5 deletions(-) diff --git a/app/mutations/sequences/publish.rb b/app/mutations/sequences/publish.rb index 460519436..f1bdcd71d 100644 --- a/app/mutations/sequences/publish.rb +++ b/app/mutations/sequences/publish.rb @@ -3,7 +3,7 @@ class Publish < Mutations::Command NOT_YOURS = "Can't publish sequences you didn't create." OK_KINDS = %w( axis axis_addition axis_overwrite calibrate channel channel_name coordinate emergency_lock execute execute_script - find_home identifier is_outdated label location_placeholder + find_home identifier is_outdated label location_placeholder lua message message_type milliseconds move move_absolute move_relative nothing number number_placeholder numeric op package pair parameter_application parameter_declaration diff --git a/frontend/constants.ts b/frontend/constants.ts index 1a5b6f89c..cc9f55559 100644 --- a/frontend/constants.ts +++ b/frontend/constants.ts @@ -1105,6 +1105,9 @@ export namespace Content { FarmBot and make changes. If the original author of the sequence publishes a new version, you will have the option to upgrade your copy.`); + export const INCLUDES_LUA_WARNING = + trim(`This sequence includes Lua code. Review carefully before executing.`); + export const IMPORTED_SEQUENCE = trim(`This sequence was imported from a publicly shared sequence. If the original author publishes a new version, you may upgrade your copy. diff --git a/frontend/css/sequences.scss b/frontend/css/sequences.scss index b8c8fa11b..5bb4c28db 100644 --- a/frontend/css/sequences.scss +++ b/frontend/css/sequences.scss @@ -1481,6 +1481,9 @@ display: inline-block; margin-left: 1rem; } + p { + margin-left: 1rem; + } } .import-banner { diff --git a/frontend/sequences/__tests__/sequence_editor_middle_active_test.tsx b/frontend/sequences/__tests__/sequence_editor_middle_active_test.tsx index da8e388e0..c558cd32e 100644 --- a/frontend/sequences/__tests__/sequence_editor_middle_active_test.tsx +++ b/frontend/sequences/__tests__/sequence_editor_middle_active_test.tsx @@ -96,7 +96,7 @@ import { execSequence } from "../../devices/actions"; import { clickButton } from "../../__test_support__/helpers"; import { fakeVariableNameSet } from "../../__test_support__/fake_variables"; import { DropAreaProps } from "../../draggable/interfaces"; -import { Actions, DeviceSetting } from "../../constants"; +import { Actions, Content, DeviceSetting } from "../../constants"; import { setWebAppConfigValue } from "../../config_storage/actions"; import { BooleanSetting } from "../../session_keys"; import { push } from "../../history"; @@ -448,6 +448,26 @@ describe("", () => { expect(wrapper.state().view).toEqual("public"); }); + it("shows warning", () => { + mockPath = Path.mock(Path.sequences("1")); + const p = fakeProps(); + p.sequence.body.sequence_version_id = 1; + p.sequence.body.body = [{ kind: "lua", args: { lua: "" } }]; + maybeTagStep(p.sequence.body.body[0]); + const wrapper = mount(); + expect(wrapper.text()).toContain(Content.INCLUDES_LUA_WARNING); + }); + + it("doesn't show warning", () => { + mockPath = Path.mock(Path.sequences("1")); + const p = fakeProps(); + p.sequence.body.sequence_version_id = 1; + p.sequence.body.body = [{ kind: "sync", args: {} }]; + maybeTagStep(p.sequence.body.body[0]); + const wrapper = mount(); + expect(wrapper.text()).not.toContain(Content.INCLUDES_LUA_WARNING); + }); + it("edits description", () => { mockPath = Path.mock(Path.sequences("1")); const p = fakeProps(); diff --git a/frontend/sequences/panel/__tests__/preview_test.tsx b/frontend/sequences/panel/__tests__/preview_test.tsx index 455bc9cff..d5eb45088 100644 --- a/frontend/sequences/panel/__tests__/preview_test.tsx +++ b/frontend/sequences/panel/__tests__/preview_test.tsx @@ -25,6 +25,7 @@ import { push } from "../../../history"; import { installSequence } from "../../actions"; import { Path } from "../../../internal_urls"; import { emptyState } from "../../../resources/reducer"; +import { Content } from "../../../constants"; describe("", () => { API.setBaseUrl(""); @@ -78,6 +79,22 @@ describe("", () => { expect(wrapper.text().toLowerCase()).not.toContain("error"); }); + it("shows warning", async () => { + const sequence = fakeSequence(); + sequence.body.body = [{ kind: "lua", args: { lua: "" } }]; + mockGet = Promise.resolve({ data: sequence.body }); + const wrapper = await mount(); + expect(wrapper.text()).toContain(Content.INCLUDES_LUA_WARNING); + }); + + it("doesn't show warning", async () => { + const sequence = fakeSequence(); + sequence.body.body = [{ kind: "sync", args: {} }]; + mockGet = Promise.resolve({ data: sequence.body }); + const wrapper = await mount(); + expect(wrapper.text()).not.toContain(Content.INCLUDES_LUA_WARNING); + }); + it("errors while loading sequence", async () => { mockGet = Promise.reject("Error"); const wrapper = await mount(); diff --git a/frontend/sequences/panel/preview_support.tsx b/frontend/sequences/panel/preview_support.tsx index a6ce8dae2..4d61768c9 100644 --- a/frontend/sequences/panel/preview_support.tsx +++ b/frontend/sequences/panel/preview_support.tsx @@ -146,6 +146,7 @@ interface ImportBannerProps { export const ImportBanner = (props: ImportBannerProps) => { const [importing, setImporting] = React.useState(false); const { sequence } = props; + const includesLua = sequence?.body.body?.map(x => x.kind).includes("lua"); return
@@ -159,6 +160,7 @@ export const ImportBanner = (props: ImportBannerProps) => { {importing ? t("importing") : t("import")} {importing && } } + {includesLua &&

{t(Content.INCLUDES_LUA_WARNING)}

}
; }; diff --git a/frontend/sequences/sequence_editor_middle_active.tsx b/frontend/sequences/sequence_editor_middle_active.tsx index 83786def8..c8bcfb0dd 100644 --- a/frontend/sequences/sequence_editor_middle_active.tsx +++ b/frontend/sequences/sequence_editor_middle_active.tsx @@ -752,6 +752,7 @@ export const ImportedBanner = (props: ImportedBannerProps) => { {currentVersionItem?.label}

; + const includesLua = props.sequence.body.body?.map(x => x.kind).includes("lua"); return versionId ?
@@ -762,6 +763,7 @@ export const ImportedBanner = (props: ImportedBannerProps) => { onClick={upgradeSequence(props.sequence.body.id, latestId)}> {revertAvailable ? t("revert changes") : t("upgrade to latest")} } + {includesLua &&

{t(Content.INCLUDES_LUA_WARNING)}

}
Date: Wed, 24 Jan 2024 09:47:51 -0800 Subject: [PATCH 07/12] simplify login form --- .../front_page/__tests__/front_page_test.tsx | 5 +- frontend/front_page/__tests__/login_test.tsx | 29 +++++----- frontend/front_page/login.tsx | 55 ++++--------------- 3 files changed, 27 insertions(+), 62 deletions(-) diff --git a/frontend/front_page/__tests__/front_page_test.tsx b/frontend/front_page/__tests__/front_page_test.tsx index a2c642e89..83ccfee3a 100644 --- a/frontend/front_page/__tests__/front_page_test.tsx +++ b/frontend/front_page/__tests__/front_page_test.tsx @@ -79,9 +79,10 @@ describe("", () => { expect(location.assign).toHaveBeenCalledWith(DEFAULT_APP_PAGE); }); - it("updates login state", () => { + it("updates state", () => { const wrapper = mount(); - changeBlurableInput(wrapper, "email", 1); + wrapper.setState({ activePanel: "forgotPassword" }); + changeBlurableInput(wrapper, "email", 0); expect(wrapper.state().email).toEqual("email"); }); diff --git a/frontend/front_page/__tests__/login_test.tsx b/frontend/front_page/__tests__/login_test.tsx index dbe2bbcaa..18a936522 100644 --- a/frontend/front_page/__tests__/login_test.tsx +++ b/frontend/front_page/__tests__/login_test.tsx @@ -1,7 +1,6 @@ import React from "react"; import { mount, shallow } from "enzyme"; import { Login, LoginProps } from "../login"; -import { changeBlurableInput } from "../../__test_support__/helpers"; describe("", () => { const fakeProps = (): LoginProps => ({ @@ -17,14 +16,17 @@ describe("", () => { const wrapper = mount(); ["Email", "Password", "Forgot password?", "Login"] .map(string => expect(wrapper.text()).toContain(string)); - changeBlurableInput(wrapper, "email", 1); - expect(p.onEmailChange).toHaveBeenCalledWith( - { currentTarget: { value: "email" } }); - const input = shallow(wrapper.find("input").at(2).getElement()); - input.simulate("change", { target: { value: "password" } }); - input.simulate("blur", { currentTarget: { value: "password" } }); - expect(p.onLoginPasswordChange).toHaveBeenCalledWith( - { currentTarget: { value: "password" } }); + }); + + it("interacts with login options", () => { + const p = fakeProps(); + const wrapper = shallow(); + const e1 = { currentTarget: { value: "email" } }; + wrapper.find("input").first().simulate("change", e1); + expect(p.onEmailChange).toHaveBeenCalledWith(e1); + const e2 = { currentTarget: { value: "password" } }; + wrapper.find("input").last().simulate("change", e2); + expect(p.onLoginPasswordChange).toHaveBeenCalledWith(e2); wrapper.find("a").first().simulate("click"); expect(p.onToggleForgotPassword).toHaveBeenCalled(); }); @@ -32,12 +34,7 @@ describe("", () => { it("submits", () => { const p = fakeProps(); const wrapper = shallow(); - const e = { persist: jest.fn(), preventDefault: jest.fn() }; - jest.useFakeTimers(); - wrapper.find("form").simulate("submit", e); - expect(e.persist).toHaveBeenCalled(); - expect(e.preventDefault).toHaveBeenCalled(); - jest.runAllTimers(); - expect(p.onSubmit).toHaveBeenCalledWith(e); + wrapper.find("form").simulate("submit"); + expect(p.onSubmit).toHaveBeenCalled(); }); }); diff --git a/frontend/front_page/login.tsx b/frontend/front_page/login.tsx index d803f9126..edb373861 100644 --- a/frontend/front_page/login.tsx +++ b/frontend/front_page/login.tsx @@ -1,20 +1,10 @@ -import * as React from "react"; -import { - BlurableInput, - Col, - Widget, - WidgetBody, - WidgetHeader, - Row, -} from "../ui/index"; -import { BlurablePassword } from "../ui/blurable_password"; +import React from "react"; import { t } from "../i18next_wrapper"; +import { Col, Widget, WidgetBody, WidgetHeader, Row } from "../ui"; import { updatePageInfo } from "../util"; export interface LoginProps { - /** Attributes */ email: string | undefined; - /** Callbacks */ onToggleForgotPassword(): void; onSubmit(e: React.FormEvent): void; onEmailChange(e: React.SyntheticEvent): void; @@ -22,17 +12,6 @@ export interface LoginProps { } export class Login extends React.Component { - /** PROBLEM: only updates when when `blur` event happens. - * * No update when you push return key- that's a submit event. - * SOLUTION: Intercept the `submit` event and forcibly focus on a hidden - * input control, thereby triggering the blur event across all - * fields. - */ - private hiddenFieldRef: HTMLElement | undefined = undefined; - - /** CSS to hide the fake input field used to change focus. */ - HIDE_ME = { background: "transparent", border: "none", display: "node" }; - render() { const { email, @@ -46,35 +25,23 @@ export class Login extends React.Component { -
{ - e.persist(); - e.preventDefault(); - /** Force focus on fake input. Triggers blur on all inputs. */ - this.hiddenFieldRef && this.hiddenFieldRef.focus(); - /** Give React time to update stuff before triggering callback. */ - setTimeout(() => onSubmit(e), 3); - }}> -
- x && (this.hiddenFieldRef = x)} /> -
+ - + onChange={onEmailChange} /> - + From b783308cebb223593081d6268011cfe2202e1a1b Mon Sep 17 00:00:00 2001 From: gabrielburnworth Date: Wed, 24 Jan 2024 17:36:22 -0800 Subject: [PATCH 08/12] add 3D box button cursor styles --- frontend/css/global.scss | 1 + .../pin_bindings/__tests__/model_test.tsx | 16 ++++++++++++++++ frontend/settings/pin_bindings/model.tsx | 15 +++++++++++---- 3 files changed, 28 insertions(+), 4 deletions(-) diff --git a/frontend/css/global.scss b/frontend/css/global.scss index dbb15d430..d791f1144 100644 --- a/frontend/css/global.scss +++ b/frontend/css/global.scss @@ -2027,6 +2027,7 @@ ul { font-weight: 700; line-height: 1; text-align: center; + user-select: none; &.hovered { background: $black; } diff --git a/frontend/settings/pin_bindings/__tests__/model_test.tsx b/frontend/settings/pin_bindings/__tests__/model_test.tsx index a0fb7657e..630fae644 100644 --- a/frontend/settings/pin_bindings/__tests__/model_test.tsx +++ b/frontend/settings/pin_bindings/__tests__/model_test.tsx @@ -180,6 +180,22 @@ describe("", () => { expect(e.object.parent?.children[0].position.z).toEqual(131); }); + it("changes cursor: bound", () => { + const wrapper = mount(); + expect(document.body.style.cursor).toEqual("default"); + wrapper.find({ name: "action-group" }).first().simulate("pointermove"); + expect(document.body.style.cursor).toEqual("pointer"); + document.body.style.cursor = "default"; + }); + + it("changes cursor: unbound", () => { + const wrapper = mount(); + expect(document.body.style.cursor).toEqual("default"); + wrapper.find({ name: "action-group" }).last().simulate("pointermove"); + expect(document.body.style.cursor).toEqual("not-allowed"); + document.body.style.cursor = "default"; + }); + it("renders: off", () => { const p = fakeProps(); p.isEditing = true; diff --git a/frontend/settings/pin_bindings/model.tsx b/frontend/settings/pin_bindings/model.tsx index 7706edc78..e38a40b14 100644 --- a/frontend/settings/pin_bindings/model.tsx +++ b/frontend/settings/pin_bindings/model.tsx @@ -2,7 +2,7 @@ /* eslint-disable no-null/no-null */ import React, { useRef } from "react"; import { - Cylinder, Html, PerspectiveCamera, useCursor, useGLTF, + Cylinder, Html, PerspectiveCamera, useGLTF, } from "@react-three/drei"; import { Canvas, ThreeEvent, useFrame } from "@react-three/fiber"; import { GLTF } from "three-stdlib"; @@ -10,7 +10,7 @@ import { BindingTargetDropdown, pinBindingLabel } from "./pin_binding_input_grou import { BoxTopBaseProps, PinBindingListItems } from "./interfaces"; import { setPinBinding, findBinding, triggerBinding } from "./actions"; import { BufferGeometry } from "three"; -import { debounce, isUndefined, some } from "lodash"; +import { debounce, some } from "lodash"; import { t } from "../../i18next_wrapper"; import { isExpress } from "../../settings/firmware/firmware_hardware_support"; import { ButtonPin } from "./list_and_label_support"; @@ -259,10 +259,10 @@ export const Model = (props: BoxTopBaseProps) => { }; const [hovered, setHovered] = React.useState(); - useCursor(!isUndefined(hovered)); const leave = (e: ThreeEvent) => { setHovered(undefined); setZForAllInGroup(e, Z); + document.body.style.cursor = "default"; }; return @@ -296,7 +296,12 @@ export const Model = (props: BoxTopBaseProps) => { const binding = findPinBinding(pinNumber); const isHovered = hovered == pinNumber; const click = debounce(clickBinding(pinNumber)); - const enter = () => !props.isEditing && setHovered(pinNumber); + const setCursor = () => + document.body.style.cursor = binding ? "pointer" : "not-allowed"; + const enter = () => { + !props.isEditing && setHovered(pinNumber); + setCursor(); + }; return { material-color={0xcccccc} /> { if (!props.isEditing) { From c3e97d5c50d8302bb2dfe0eff65758d3900402e6 Mon Sep 17 00:00:00 2001 From: gabrielburnworth Date: Wed, 24 Jan 2024 17:36:50 -0800 Subject: [PATCH 09/12] change title and widget styles --- frontend/css/static_pages.scss | 4 ++++ frontend/css/widgets.scss | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/frontend/css/static_pages.scss b/frontend/css/static_pages.scss index a7e4d0354..23a568fd3 100644 --- a/frontend/css/static_pages.scss +++ b/frontend/css/static_pages.scss @@ -14,6 +14,8 @@ text-shadow: 0 0 25px rgba(0, 0, 0, 0.1), 0 0 25px rgba(0, 0, 0, 0.1); } h1 { + font-family: "Inknut Antiqua" !important; + font-weight: bold !important; font-size: 3.4rem; line-height: 3.6rem; } @@ -25,6 +27,8 @@ } input { margin-bottom: 1rem; + font-family: revert; + font-size: revert; } .all-content-wrapper { max-width: 50rem; diff --git a/frontend/css/widgets.scss b/frontend/css/widgets.scss index 2d9e5413a..b7b388e18 100644 --- a/frontend/css/widgets.scss +++ b/frontend/css/widgets.scss @@ -29,6 +29,8 @@ >*:not(h5):not(.title-help-icon):not(.title-help) { margin-left: 1rem; } + border-top-left-radius: 5px; + border-top-right-radius: 5px; .title-help{ display: inline; .title-help-text { @@ -109,6 +111,8 @@ >.row:not(:first-of-type) { margin-top: 1rem; } + border-bottom-left-radius: 5px; + border-bottom-right-radius: 5px; } .widget-footer { From a54409e264c96f959711a86eae95a6cf08709219 Mon Sep 17 00:00:00 2001 From: gabrielburnworth Date: Thu, 25 Jan 2024 14:55:50 -0800 Subject: [PATCH 10/12] upgrade deps --- Gemfile.lock | 44 +++++++++++++++++++++----------------------- package.json | 20 ++++++++++---------- 2 files changed, 31 insertions(+), 33 deletions(-) diff --git a/Gemfile.lock b/Gemfile.lock index 4e0d566ee..10959b320 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -83,7 +83,7 @@ GEM activesupport climate_control (1.2.0) coderay (1.1.3) - concurrent-ruby (1.2.2) + concurrent-ruby (1.2.3) crack (0.4.5) rexml crass (1.0.6) @@ -114,12 +114,12 @@ GEM docile (1.4.0) e2mmap (0.1.0) erubi (1.12.0) - factory_bot (6.4.4) + factory_bot (6.4.5) activesupport (>= 5.0.0) - factory_bot_rails (6.4.2) + factory_bot_rails (6.4.3) factory_bot (~> 6.4) railties (>= 5.0.0) - faker (3.2.2) + faker (3.2.3) i18n (>= 1.8.11, < 2) faraday (1.10.3) faraday-em_http (~> 1.0) @@ -148,34 +148,33 @@ GEM faraday (~> 1.0) globalid (1.2.1) activesupport (>= 6.1) - google-apis-core (0.11.2) + google-apis-core (0.12.0) addressable (~> 2.5, >= 2.5.1) - googleauth (>= 0.16.2, < 2.a) + googleauth (~> 1.9) httpclient (>= 2.8.1, < 3.a) mini_mime (~> 1.0) representable (~> 3.0) retriable (>= 2.0, < 4.a) rexml - webrick - google-apis-iamcredentials_v1 (0.17.0) - google-apis-core (>= 0.11.0, < 2.a) - google-apis-storage_v1 (0.29.0) - google-apis-core (>= 0.11.0, < 2.a) + google-apis-iamcredentials_v1 (0.18.0) + google-apis-core (>= 0.12.0, < 2.a) + google-apis-storage_v1 (0.33.0) + google-apis-core (>= 0.12.0, < 2.a) google-cloud-core (1.6.1) google-cloud-env (>= 1.0, < 3.a) google-cloud-errors (~> 1.0) google-cloud-env (2.1.0) faraday (>= 1.0, < 3.a) google-cloud-errors (1.3.1) - google-cloud-storage (1.45.0) + google-cloud-storage (1.48.0) addressable (~> 2.8) digest-crc (~> 0.4) - google-apis-iamcredentials_v1 (~> 0.1) - google-apis-storage_v1 (~> 0.29.0) + google-apis-iamcredentials_v1 (~> 0.18) + google-apis-storage_v1 (~> 0.33) google-cloud-core (~> 1.6) - googleauth (>= 0.16.2, < 2.a) + googleauth (~> 1.9) mini_mime (~> 1.0) - googleauth (1.9.1) + googleauth (1.9.2) faraday (>= 1.0, < 3.a) google-cloud-env (~> 2.1) jwt (>= 1.4, < 3.0) @@ -217,26 +216,26 @@ GEM marcel (1.0.2) method_source (1.0.0) mini_mime (1.1.5) - minitest (5.20.0) + minitest (5.21.2) multi_json (1.15.0) multipart-post (2.3.0) mutations (0.9.1) activesupport - net-imap (0.4.9) + net-imap (0.4.9.1) date net-protocol net-pop (0.1.2) net-protocol net-protocol (0.2.2) timeout - net-smtp (0.4.0) + net-smtp (0.4.0.1) net-protocol nio4r (2.7.0) nokogiri (1.16.0-x86_64-linux) racc (~> 1.4) orm_adapter (0.5.0) os (1.1.4) - passenger (6.0.19) + passenger (6.0.20) rack rake (>= 0.8.1) pg (1.5.4) @@ -307,7 +306,7 @@ GEM railties (>= 5.2) retriable (3.1.2) rexml (3.2.6) - rollbar (3.4.2) + rollbar (3.5.1) rspec (3.12.0) rspec-core (~> 3.12.0) rspec-expectations (~> 3.12.0) @@ -320,7 +319,7 @@ GEM rspec-mocks (3.12.6) diff-lcs (>= 1.2.0, < 2.0) rspec-support (~> 3.12.0) - rspec-rails (6.1.0) + rspec-rails (6.1.1) actionpack (>= 6.1) activesupport (>= 6.1) railties (>= 6.1) @@ -378,7 +377,6 @@ GEM addressable (>= 2.8.0) crack (>= 0.3.2) hashdiff (>= 0.4.0, < 2.0.0) - webrick (1.8.1) websocket-driver (0.7.6) websocket-extensions (>= 0.1.0) websocket-extensions (0.1.5) diff --git a/package.json b/package.json index c0bef45a7..629a25b1a 100644 --- a/package.json +++ b/package.json @@ -35,30 +35,30 @@ "@monaco-editor/react": "4.6.0", "@parcel/transformer-sass": "2.11.0", "@parcel/transformer-typescript-tsc": "2.11.0", - "@react-three/drei": "9.96.1", - "@react-three/fiber": "8.15.14", + "@react-three/drei": "9.96.3", + "@react-three/fiber": "8.15.15", "@types/lodash": "4.14.202", "@types/markdown-it": "13.0.7", - "@types/node": "20.11.5", + "@types/node": "20.11.6", "@types/promise-timeout": "1.3.3", "@types/react": "18.2.48", "@types/react-color": "3.0.11", "@types/react-dom": "18.2.18", "@types/three": "0.160.0", "@types/ws": "8.5.10", - "axios": "1.6.5", + "axios": "1.6.7", "bowser": "2.11.0", "browser-speech": "1.1.1", "events": "3.3.0", "farmbot": "15.8.7", - "i18next": "23.7.16", + "i18next": "23.7.19", "lodash": "4.17.21", "markdown-it": "14.0.0", "markdown-it-emoji": "3.0.0", "moment": "2.30.1", "monaco-editor": "0.45.0", "mqtt": "5.1.4", - "npm": "10.3.0", + "npm": "10.4.0", "parcel": "2.11.0", "process": "0.11.10", "promise-timeout": "1.3.0", @@ -72,7 +72,7 @@ "redux-immutable-state-invariant": "2.1.0", "redux-thunk": "3.1.0", "takeme": "0.12.0", - "three": "0.160.0", + "three": "0.160.1", "typescript": "5.3.3", "url": "0.11.3", "xterm": "5.3.0" @@ -81,8 +81,8 @@ "@types/enzyme": "3.10.12", "@types/jest": "29.5.11", "@types/readable-stream": "4.0.10", - "@typescript-eslint/eslint-plugin": "6.19.0", - "@typescript-eslint/parser": "6.19.0", + "@typescript-eslint/eslint-plugin": "6.19.1", + "@typescript-eslint/parser": "6.19.1", "@wojtekmaj/enzyme-adapter-react-17": "0.8.0", "enzyme": "3.11.0", "eslint": "8.56.0", @@ -106,7 +106,7 @@ "react-test-renderer": "18.2.0", "sass": "1.70.0", "sass-lint": "1.13.1", - "ts-jest": "29.1.1", + "ts-jest": "29.1.2", "tslint": "6.1.3" } } From fb75c29d0b7b0cfc55ceca511c515766aee891b4 Mon Sep 17 00:00:00 2001 From: gabrielburnworth Date: Fri, 26 Jan 2024 14:35:32 -0800 Subject: [PATCH 11/12] add more envs to example.env --- app/models/transport.rb | 3 ++- example.env | 11 +++++++++++ 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/app/models/transport.rb b/app/models/transport.rb index 78bb32730..e49202528 100644 --- a/app/models/transport.rb +++ b/app/models/transport.rb @@ -4,9 +4,10 @@ # change protocols class Transport OPTS = { read_timeout: 10, heartbeat: 10, log_level: "warn" } + CLOUDAMQP_ENV_KEY = ENV.fetch("WHERE_IS_CLOUDAMQP_URL", "CLOUDAMQP_URL") def self.amqp_url - @amqp_url ||= ENV["CLOUDAMQP_URL"] || + @amqp_url ||= ENV[CLOUDAMQP_ENV_KEY] || ENV["RABBITMQ_URL"] || "amqp://admin:#{ENV.fetch("ADMIN_PASSWORD")}@mqtt:5672" end diff --git a/example.env b/example.env index a479371b3..b08cfb702 100644 --- a/example.env +++ b/example.env @@ -98,9 +98,14 @@ GCS_BUCKET=GOOGLE_CLOUD_STORAGE_BUCKET_NAME_FOR_IMAGE_FILES GCS_ID=GOOGLE_CLOUD_STORAGE='interop' id # Most self hosting users will want to delete this. GCS_KEY=GOOGLE_CLOUD_STORAGE='interop' key +GCS_PROJECT= +GOOGLE_CLOUD_KEYFILE_JSON= # Can be deleted unless you are a Rollbar customer. ROLLBAR_ACCESS_TOKEN=____ ROLLBAR_CLIENT_TOKEN=____ +ROLLBAR_ENV= +# Can be deleted unless you are using codecov. +CODECOV_TOKEN= # This can be set to anything. # Most users can just delete it. # This is used for people writing modifications to the software, mostly. @@ -128,6 +133,10 @@ EXTRA_DOMAINS=staging.farm.bot,whatever.farm.bot # Include the protocol! (http vs. https) # DELETE THIS LINE if you are a self-hosted user. RABBIT_MGMT_URL=http://delete_this_line.com +# defaults to `CLOUDAMQP_URL` +WHERE_IS_CLOUDAMQP_URL= +CLOUDAMQP_URL= +RABBITMQ_URL= # Allow only certain users on the server. If the user's email domain is not # on the list of trusted domains, they can not use the server. # The example below only allows users with `@farmbot.io` or `@farm.bot` emails @@ -156,6 +165,8 @@ FEEDBACK_WEBHOOK_URL=http://localhost:3000/change_this # Email address of a "publisher account" that is used to # publish shared sequences via `rake sequences:publish ` AUTHORIZED_PUBLISHER=foo@bar.com +# URL to send release info to. +RELEASE_WEBHOOK_URL= # OpenAI API key. Delete this line if you don't have one. OPENAI_API_KEY= # OpenAI API sampling temperature. Optional. Float between 0 and 2. From ef69bb7e16a7b884d410bfed60ee8fa531e55213 Mon Sep 17 00:00:00 2001 From: gabrielburnworth Date: Fri, 26 Jan 2024 14:37:37 -0800 Subject: [PATCH 12/12] use setting instead of hardware to show sensors --- .../__tests__/panel_header_test.tsx | 18 ++++++++++++++- frontend/farm_designer/panel_header.tsx | 9 +------- frontend/nav/__tests__/nav_links_test.tsx | 23 +++++++++++-------- 3 files changed, 31 insertions(+), 19 deletions(-) diff --git a/frontend/farm_designer/__tests__/panel_header_test.tsx b/frontend/farm_designer/__tests__/panel_header_test.tsx index 79355df98..59328c26a 100644 --- a/frontend/farm_designer/__tests__/panel_header_test.tsx +++ b/frontend/farm_designer/__tests__/panel_header_test.tsx @@ -20,7 +20,7 @@ import { shallow, mount, ReactWrapper } from "enzyme"; import { DesignerNavTabs } from "../panel_header"; import { buildResourceIndex } from "../../__test_support__/resource_index_builder"; import { - fakeFarmwareInstallation, + fakeFarmwareInstallation, fakeWebAppConfig, } from "../../__test_support__/fake_state/resources"; // eslint-disable-next-line @typescript-eslint/no-explicit-any @@ -64,6 +64,22 @@ describe("", () => { expectActive(wrapper, "zones"); }); + it("shows sensors tab", () => { + const config = fakeWebAppConfig(); + config.body.hide_sensors = false; + mockState.resources = buildResourceIndex([config]); + const wrapper = mount(); + expect(wrapper.html()).toContain("sensors"); + }); + + it("doesn't show sensors tab", () => { + const config = fakeWebAppConfig(); + config.body.hide_sensors = true; + mockState.resources = buildResourceIndex([config]); + const wrapper = mount(); + expect(wrapper.html()).not.toContain("sensors"); + }); + it("renders scroll indicator", () => { Object.defineProperty(document, "getElementsByClassName", { value: () => [{}, { scrollWidth: 100, scrollLeft: 0, clientWidth: 75 }], diff --git a/frontend/farm_designer/panel_header.tsx b/frontend/farm_designer/panel_header.tsx index 6ba6dea40..8a41d1ae4 100644 --- a/frontend/farm_designer/panel_header.tsx +++ b/frontend/farm_designer/panel_header.tsx @@ -6,10 +6,6 @@ import { DevSettings } from "../settings/dev/dev_support"; import { getWebAppConfigValue } from "../config_storage/actions"; import { store } from "../redux/store"; import { BooleanSetting } from "../session_keys"; -import { - getFwHardwareValue, hasSensors, -} from "../settings/firmware/firmware_hardware_support"; -import { getFbosConfig } from "../resources/getters"; import { computeEditorUrlFromState } from "../nav/compute_editor_url_from_state"; import { compact } from "lodash"; import { selectAllFarmwareInstallations } from "../resources/selectors"; @@ -218,10 +214,7 @@ const displayScrollIndicator = () => { export const showSensors = () => { const getWebAppConfigVal = getWebAppConfigValue(store.getState); - const firmwareHardware = getFwHardwareValue(getFbosConfig( - store.getState().resources.index)); - return !getWebAppConfigVal(BooleanSetting.hide_sensors) - && hasSensors(firmwareHardware); + return !getWebAppConfigVal(BooleanSetting.hide_sensors); }; export const showFarmware = () => { diff --git a/frontend/nav/__tests__/nav_links_test.tsx b/frontend/nav/__tests__/nav_links_test.tsx index 6a8af8220..0cecf0af0 100644 --- a/frontend/nav/__tests__/nav_links_test.tsx +++ b/frontend/nav/__tests__/nav_links_test.tsx @@ -4,13 +4,6 @@ jest.mock("../../history", () => ({ getPathArray: jest.fn(() => mockPath.split("/")), })); -let mockHasSensors = false; -jest.mock("../../settings/firmware/firmware_hardware_support", () => ({ - hasSensors: () => mockHasSensors, - getFwHardwareValue: jest.fn(), - isExpress: jest.fn(), -})); - import { fakeState } from "../../__test_support__/fake_state"; const mockState = fakeState(); jest.mock("../../redux/store", () => ({ store: { getState: () => mockState } })); @@ -21,7 +14,7 @@ import { NavLinks } from "../nav_links"; import { NavLinksProps } from "../interfaces"; import { buildResourceIndex } from "../../__test_support__/resource_index_builder"; import { - fakeFarmwareInstallation, + fakeFarmwareInstallation, fakeWebAppConfig, } from "../../__test_support__/fake_state/resources"; import { fakeHelpState } from "../../__test_support__/fake_designer_state"; @@ -60,16 +53,26 @@ describe("", () => { mockPath = Path.mock(Path.plants()); const wrapper = shallow(); expect(wrapper.find("Link").at(1).hasClass("active")).toBeTruthy(); - expect(wrapper.html().toLowerCase()).not.toContain("sensors"); }); it("shows sensors link", () => { - mockHasSensors = true; + const config = fakeWebAppConfig(); + config.body.hide_sensors = false; + mockState.resources = buildResourceIndex([config]); const p = fakeProps(); const wrapper = shallow(); expect(wrapper.html().toLowerCase()).toContain("sensors"); }); + it("doesn't show sensors link", () => { + const config = fakeWebAppConfig(); + config.body.hide_sensors = true; + mockState.resources = buildResourceIndex([config]); + const p = fakeProps(); + const wrapper = shallow(); + expect(wrapper.html().toLowerCase()).not.toContain("sensors"); + }); + it("doesn't show farmware link", () => { const farmware = fakeFarmwareInstallation(); farmware.body.package = "included";