Skip to content

Commit

Permalink
add 3D electronics box top UI
Browse files Browse the repository at this point in the history
  • Loading branch information
gabrielburnworth committed Jan 18, 2024
1 parent 4a1dc1d commit af49278
Show file tree
Hide file tree
Showing 37 changed files with 1,212 additions and 206 deletions.
1 change: 1 addition & 0 deletions config/application.rb
Expand Up @@ -126,6 +126,7 @@ class Application < Rails::Application
"'unsafe-inline'",
"'unsafe-eval'",
"'self'",
"blob:", # 3D
],
style_src: %w(
maxcdn.bootstrapcdn.com
Expand Down
@@ -0,0 +1,9 @@
class AddEnable3dElectronicsBoxTopToWebAppConfig < ActiveRecord::Migration[6.1]
def up
add_column :web_app_configs, :enable_3d_electronics_box_top, :boolean, default: true
end

def down
remove_column :web_app_configs, :enable_3d_electronics_box_top
end
end
6 changes: 4 additions & 2 deletions db/structure.sql
Expand Up @@ -2032,7 +2032,8 @@ CREATE TABLE public.web_app_configs (
go_button_axes character varying(3) DEFAULT 'XY'::character varying NOT NULL,
show_uncropped_camera_view_area boolean DEFAULT false,
default_plant_depth integer DEFAULT 5,
show_missed_step_plot boolean DEFAULT false
show_missed_step_plot boolean DEFAULT false,
enable_3d_electronics_box_top boolean DEFAULT true
);


Expand Down Expand Up @@ -3979,6 +3980,7 @@ INSERT INTO "schema_migrations" (version) VALUES
('20230712201622'),
('20230714010144'),
('20230714173031'),
('20230808192946');
('20230808192946'),
('20240118204046');


7 changes: 7 additions & 0 deletions frontend/__test_support__/additional_mocks.tsx
Expand Up @@ -35,3 +35,10 @@ jest.mock("../history", () => ({
push: jest.fn(),
getPathArray: () => [],
}));

window.ResizeObserver = (() => ({
observe: jest.fn(),
unobserve: jest.fn(),
disconnect: jest.fn(),
// eslint-disable-next-line @typescript-eslint/no-explicit-any
})) as any;
4 changes: 4 additions & 0 deletions frontend/__test_support__/fake_state/resources.ts
Expand Up @@ -36,6 +36,9 @@ 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;
Expand Down Expand Up @@ -333,6 +336,7 @@ export function fakeWebAppConfig(): TaggedWebAppConfig {
display_map_missed_steps: false,
display_trail: false,
dynamic_map: false,
["enable_3d_electronics_box_top" as BooleanWebAppConfigKey]: true,
encoder_figure: false,
go_button_axes: "XY",
hide_webcam_widget: false,
Expand Down
7 changes: 6 additions & 1 deletion frontend/constants.ts
Expand Up @@ -782,6 +782,10 @@ export namespace Content {
trim(`If not using sensors, use this setting to remove the
panel from the Farm Designer.`);

export const ENABLE_3D_ELECTRONICS_BOX_TOP =
trim(`Show a 3D model of FarmBot's electronics box instead of a 2D view
in the Peripherals tab of the Controls pop-up.`);

export const BROWSER_SPEAK_LOGS =
trim(`Have the browser also read aloud log messages on the
"Speak" channel that are spoken by FarmBot.`);
Expand Down Expand Up @@ -1868,7 +1872,7 @@ export namespace SetupWizardContent {
trim(`Customize which Action or Sequence you want FarmBot to execute
when you press Button 3, 4, or 5 on the electronics box. To start, we
recommend setting Button 5 to the 'Find Home' sequence. You can change
this later from the controls panel.`);
this later from the controls pop-up.`);

export const PROBLEM_GETTING_IMAGE =
trim(`There is a 'camera not detected' or 'problem getting image' error
Expand Down Expand Up @@ -2197,6 +2201,7 @@ export enum DeviceSetting {
showSecondsInTime = `Show seconds in time`,
hideWebcamWidget = `Hide Webcam widget`,
hideSensorsPanel = `Hide Sensors panel`,
enable3dElectronicsBox = `Enable 3D electronics box`,
readSpeakLogsInBrowser = `Read speak logs in browser`,
landingPage = `Landing page`,
browserFarmbotActivityBeep = `Browser FarmBot activity beep`,
Expand Down
1 change: 1 addition & 0 deletions frontend/controls/controls.tsx
Expand Up @@ -83,6 +83,7 @@ export class ControlsPanel extends React.Component<ControlsPanelProps> {
Peripherals = () => {
return <div className={"peripherals-tab"}>
<Peripherals
getConfigValue={this.props.getConfigValue}
firmwareHardware={this.props.firmwareHardware}
bot={this.props.bot}
peripherals={this.props.peripherals}
Expand Down
1 change: 1 addition & 0 deletions frontend/controls/peripherals/__tests__/index_test.tsx
Expand Up @@ -18,6 +18,7 @@ describe("<Peripherals />", () => {
dispatch: jest.fn(),
firmwareHardware: undefined,
resources: buildResourceIndex([]).index,
getConfigValue: () => false,
});

it("renders", () => {
Expand Down
29 changes: 19 additions & 10 deletions frontend/controls/peripherals/index.tsx
Expand Up @@ -10,8 +10,10 @@ import { Content } from "../../constants";
import { uniq, isNumber } from "lodash";
import { t } from "../../i18next_wrapper";
import { DIGITAL } from "farmbot";
import { isBotOnlineFromState } from "../../devices/must_be_online";
import { BoxTopButtons } from "../../settings/pin_bindings/box_top_gpio_diagram";
import { isBotOnline } from "../../devices/must_be_online";
import { getStatus } from "../../connectivity/reducer_support";
import { BoxTop } from "../../settings/pin_bindings/box_top";
import { BooleanSetting } from "../../session_keys";

export class Peripherals
extends React.Component<PeripheralsProps, PeripheralState> {
Expand All @@ -20,9 +22,16 @@ export class Peripherals
this.state = { isEditing: false };
}

get botOnline() {
const { hardware, connectivity } = this.props.bot;
const { sync_status } = hardware.informational_settings;
const botToMqttStatus = getStatus(connectivity.uptime["bot.mqtt"]);
return isBotOnline(sync_status, botToMqttStatus);
}

get disabled() {
return !!this.props.bot.hardware.informational_settings.busy
|| !isBotOnlineFromState(this.props.bot);
|| !this.botOnline;
}

toggle = () => this.setState({ isEditing: !this.state.isEditing });
Expand Down Expand Up @@ -114,15 +123,15 @@ export class Peripherals
: t("Edit");
return <div className={"peripherals-widget"}>
{!this.props.hidePinBindings &&
<BoxTopButtons
firmwareHardware={this.props.firmwareHardware}
<BoxTop
threeDimensions={!!this.props.getConfigValue(
BooleanSetting.enable_3d_electronics_box_top)}
isEditing={isEditing}
dispatch={this.props.dispatch}
resources={this.props.resources}
botOnline={isBotOnlineFromState(this.props.bot)}
syncStatus={this.props.bot.hardware.informational_settings.sync_status}
locked={this.props.bot.hardware.informational_settings.locked}
isEditing={isEditing} />}
<hr />
firmwareHardware={this.props.firmwareHardware}
bot={this.props.bot}
botOnline={this.botOnline} />}
<EmptyStateWrapper
notEmpty={this.props.peripherals.length > 0 || isEditing}
graphic={EmptyStateGraphic.regimens}
Expand Down
2 changes: 2 additions & 0 deletions frontend/controls/peripherals/interfaces.ts
@@ -1,6 +1,7 @@
import { Pins, TaggedPeripheral, FirmwareHardware } from "farmbot";
import { BotState } from "../../devices/interfaces";
import { ResourceIndex } from "../../resources/interfaces";
import { GetWebAppConfigValue } from "../../config_storage/actions";

export interface PeripheralState {
isEditing: boolean;
Expand All @@ -26,4 +27,5 @@ export interface PeripheralsProps {
firmwareHardware: FirmwareHardware | undefined;
resources: ResourceIndex;
hidePinBindings?: boolean;
getConfigValue: GetWebAppConfigValue;
}
76 changes: 69 additions & 7 deletions frontend/css/global.scss
Expand Up @@ -858,11 +858,6 @@ fieldset {
margin-top: 2rem;
}

.peripherals-tab {
overflow-y: scroll;
overflow-x: hidden;
}

.webcam-stream-unavailable {
position: relative;
width: 100%;
Expand Down Expand Up @@ -2011,6 +2006,69 @@ ul {
}
}

.electronics-box-3d-model {
margin-bottom: 1rem;
.led-label,
.btn-label {
display: block;
margin: auto;
width: max-content;
color: $off_white;
font-size: 1rem;
background: $dark_gray;
padding: 0.25rem 0.5rem;
border-radius: 0.5rem;
white-space: normal;
max-height: 3.4rem;
overflow-y: hidden;
font-weight: 700;
line-height: 1;
text-align: center;
&.hovered {
background: $black;
}
}
.led-label {
max-width: 7rem;
}
.btn-label {
max-width: 5.8rem;
}
.filter-search {
max-width: 5.5rem;
.fa-caret-down {
bottom: -0.5rem;
right: 0.25rem;
color: $off_white;
}
button {
padding: 0.25rem;
background: $dark_gray !important;
border-radius: 0.5rem;
height: max-content !important;
min-height: 0;
&:hover {
background: $dark_gray !important;
}
}
span {
color: $off_white;
white-space: normal !important;
text-overflow: revert !important;
font-weight: 700;
font-size: 1rem;
text-align: center;
margin-right: 0.5rem;
}
}
div {
z-index: 0 !important;
}
canvas {
height: 23rem;
}
}

.webcam-widget {
.no-flipper-image-container {
background: none !important;
Expand All @@ -2030,7 +2088,6 @@ ul {
}

.peripheral-list {
margin-top: 1rem;
label {
margin-top: 0 !important;
}
Expand All @@ -2043,7 +2100,12 @@ ul {
}
}

.box-top-wrapper {
.peripheral-form,
.peripheral-list {
padding-top: 1rem;
}

.box-top-2d-wrapper {
margin-top: 2rem;
.box-top-leds,
.box-top-buttons {
Expand Down
5 changes: 4 additions & 1 deletion frontend/session_keys.ts
Expand Up @@ -4,7 +4,8 @@ import {
StringConfigKey as WebAppStringConfigKey,
} from "farmbot/dist/resources/configs/web_app";

type WebAppBooleanConfigKeyAll = WebAppBooleanConfigKey;
type WebAppBooleanConfigKeyAll = WebAppBooleanConfigKey
| "enable_3d_electronics_box_top";
type WebAppNumberConfigKeyAll = WebAppNumberConfigKey;
type WebAppStringConfigKeyAll = WebAppStringConfigKey;

Expand Down Expand Up @@ -62,6 +63,8 @@ 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_browser_speak: "enable_browser_speak",
discard_unsaved: "discard_unsaved",
time_format_24_hour: "time_format_24_hour",
Expand Down
5 changes: 5 additions & 0 deletions frontend/settings/account/account_settings.tsx
Expand Up @@ -155,6 +155,11 @@ const APP_SETTINGS = (): SettingDescriptionProps[] => ([
description: Content.HIDE_SENSORS_WIDGET,
setting: BooleanSetting.hide_sensors,
},
{
title: DeviceSetting.enable3dElectronicsBox,
description: Content.ENABLE_3D_ELECTRONICS_BOX_TOP,
setting: BooleanSetting.enable_3d_electronics_box_top,
},
{
title: DeviceSetting.readSpeakLogsInBrowser,
description: Content.BROWSER_SPEAK_LOGS,
Expand Down
1 change: 1 addition & 0 deletions frontend/settings/default_values.ts
Expand Up @@ -19,6 +19,7 @@ const DEFAULT_WEB_APP_CONFIG_VALUES: Record<Key, Value> = {
disable_i18n: false,
display_trail: true,
dynamic_map: false,
["enable_3d_electronics_box_top" as Key]: true,
encoder_figure: false,
go_button_axes: "XY",
hide_webcam_widget: false,
Expand Down
1 change: 1 addition & 0 deletions frontend/settings/maybe_highlight.tsx
Expand Up @@ -205,6 +205,7 @@ const APP_SETTINGS = [
DeviceSetting.showSecondsInTime,
DeviceSetting.hideWebcamWidget,
DeviceSetting.hideSensorsPanel,
DeviceSetting.enable3dElectronicsBox,
DeviceSetting.readSpeakLogsInBrowser,
DeviceSetting.landingPage,
DeviceSetting.browserFarmbotActivityBeep,
Expand Down

0 comments on commit af49278

Please sign in to comment.