diff --git a/.ruby-version b/.ruby-version index 4f5e69734c..2aa5131992 100755 --- a/.ruby-version +++ b/.ruby-version @@ -1 +1 @@ -3.4.5 +3.4.7 diff --git a/Gemfile b/Gemfile index 7bac44de02..baa1181942 100755 --- a/Gemfile +++ b/Gemfile @@ -1,5 +1,5 @@ source "https://rubygems.org" -ruby "~> 3.4.5" +ruby "~> 3.4.7" gem "rails", "~> 6" gem "active_model_serializers" diff --git a/Gemfile.lock b/Gemfile.lock index 8f7a4554c7..6effdf408b 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -70,8 +70,8 @@ GEM amq-protocol (2.3.4) base64 (0.3.0) bcrypt (3.1.20) - benchmark (0.4.1) - bigdecimal (3.2.2) + benchmark (0.5.0) + bigdecimal (3.3.1) builder (3.3.0) bunny (2.24.0) amq-protocol (~> 2.3) @@ -81,7 +81,7 @@ GEM climate_control (1.2.0) coderay (1.1.3) concurrent-ruby (1.3.5) - crack (1.0.0) + crack (1.0.1) bigdecimal rexml crass (1.0.6) @@ -91,7 +91,7 @@ GEM activerecord (>= 5.a) database_cleaner-core (~> 2.0) database_cleaner-core (2.0.1) - date (3.4.1) + date (3.5.0) declarative (0.0.20) delayed_job (4.1.13) activesupport (>= 3.0, < 9.0) @@ -113,24 +113,24 @@ GEM drb (2.2.3) e2mmap (0.1.0) erubi (1.13.1) - factory_bot (6.5.5) + factory_bot (6.5.6) activesupport (>= 6.1.0) - factory_bot_rails (6.5.0) + factory_bot_rails (6.5.1) factory_bot (~> 6.5) railties (>= 6.1.0) faker (3.5.2) i18n (>= 1.8.11, < 2) - faraday (2.13.4) + faraday (2.14.0) faraday-net_http (>= 2.0, < 3.5) json logger - faraday-follow_redirects (0.3.0) + faraday-follow_redirects (0.4.0) faraday (>= 1, < 3) faraday-net_http (3.4.1) net-http (>= 0.5.0) - globalid (1.2.1) + globalid (1.3.0) activesupport (>= 6.1) - google-apis-core (1.0.1) + google-apis-core (1.0.2) addressable (~> 2.8, >= 2.8.7) faraday (~> 2.13) faraday-follow_redirects (~> 0.3) @@ -138,9 +138,9 @@ GEM mini_mime (~> 1.1) representable (~> 3.0) retriable (~> 3.1) - google-apis-iamcredentials_v1 (0.24.0) + google-apis-iamcredentials_v1 (0.25.0) google-apis-core (>= 0.15.0, < 2.a) - google-apis-storage_v1 (0.56.0) + google-apis-storage_v1 (0.57.0) google-apis-core (>= 0.15.0, < 2.a) google-cloud-core (1.8.0) google-cloud-env (>= 1.0, < 3.a) @@ -159,7 +159,7 @@ GEM googleauth (~> 1.9) mini_mime (~> 1.0) google-logging-utils (0.2.0) - googleauth (1.15.0) + googleauth (1.15.1) faraday (>= 1.0, < 3.a) google-cloud-env (~> 2.2) google-logging-utils (~> 0.1) @@ -167,11 +167,11 @@ GEM multi_json (~> 1.11) os (>= 0.9, < 2.0) signet (>= 0.16, < 2.a) - hashdiff (1.2.0) + hashdiff (1.2.1) hashie (4.1.0) i18n (1.14.7) concurrent-ruby (~> 1.0) - json (2.13.2) + json (2.15.2) jsonapi-renderer (0.2.2) jwt (3.1.2) base64 @@ -196,22 +196,23 @@ GEM loofah (2.24.1) crass (~> 1.0.2) nokogiri (>= 1.12.0) - mail (2.8.1) + mail (2.9.0) + logger mini_mime (>= 0.1.1) net-imap net-pop net-smtp - marcel (1.0.4) + marcel (1.1.0) method_source (1.1.0) mini_mime (1.1.5) - minitest (5.25.5) + minitest (5.26.0) multi_json (1.17.0) mutations (0.9.1) activesupport mutex_m (0.3.0) - net-http (0.6.0) + net-http (0.7.0) uri - net-imap (0.5.10) + net-imap (0.5.12) date net-protocol net-pop (0.1.2) @@ -220,15 +221,15 @@ GEM timeout net-smtp (0.5.1) net-protocol - nio4r (2.7.4) - nokogiri (1.18.9-aarch64-linux-gnu) + nio4r (2.7.5) + nokogiri (1.18.10-aarch64-linux-gnu) racc (~> 1.4) - nokogiri (1.18.9-x86_64-linux-gnu) + nokogiri (1.18.10-x86_64-linux-gnu) racc (~> 1.4) orm_adapter (0.5.0) os (1.1.4) ostruct (0.6.3) - passenger (6.0.27) + passenger (6.1.0) rack (>= 1.6.13) rackup (>= 1.0.1) rake (>= 12.3.3) @@ -247,8 +248,8 @@ GEM hashie (~> 4.1) multi_json (~> 1.15) racc (1.8.1) - rack (2.2.17) - rack-attack (6.7.0) + rack (2.2.20) + rack-attack (6.8.0) rack (>= 1.0, < 4) rack-cors (2.0.2) rack (>= 2.0.0) @@ -290,7 +291,7 @@ GEM method_source rake (>= 12.2) thor (~> 1.0) - rake (13.3.0) + rake (13.3.1) rbtree (0.4.6) redis (4.8.1) representable (3.2.0) @@ -303,18 +304,18 @@ GEM actionpack (>= 5.2) railties (>= 5.2) retriable (3.1.2) - rexml (3.4.2) + rexml (3.4.4) rollbar (3.6.2) - rspec (3.13.1) + rspec (3.13.2) rspec-core (~> 3.13.0) rspec-expectations (~> 3.13.0) rspec-mocks (~> 3.13.0) - rspec-core (3.13.5) + rspec-core (3.13.6) rspec-support (~> 3.13.0) rspec-expectations (3.13.5) diff-lcs (>= 1.2.0, < 2.0) rspec-support (~> 3.13.0) - rspec-mocks (3.13.5) + rspec-mocks (3.13.7) diff-lcs (>= 1.2.0, < 2.0) rspec-support (~> 3.13.0) rspec-rails (6.1.5) @@ -325,7 +326,7 @@ GEM rspec-expectations (~> 3.13) rspec-mocks (~> 3.13) rspec-support (~> 3.13) - rspec-support (3.13.5) + rspec-support (3.13.6) rspec_junit_formatter (0.6.0) rspec-core (>= 2, < 4, != 2.12.0) scenic (1.9.0) @@ -361,20 +362,20 @@ GEM thor (1.4.0) thwait (0.2.0) e2mmap - timeout (0.4.3) + timeout (0.4.4) trailblazer-option (0.1.2) tzinfo (2.0.6) concurrent-ruby (~> 1.0) tzinfo-data (1.2025.2) tzinfo (>= 1.0.0) uber (0.1.0) - uri (1.0.3) + uri (1.1.0) valid_url (0.0.4) addressable rails warden (1.2.9) rack (>= 2.0.9) - webmock (3.25.1) + webmock (3.26.1) addressable (>= 2.8.0) crack (>= 0.3.2) hashdiff (>= 0.4.0, < 2.0.0) @@ -438,7 +439,7 @@ DEPENDENCIES webmock RUBY VERSION - ruby 3.4.5p51 + ruby 3.4.7p58 BUNDLED WITH - 2.7.1 + 2.7.2 diff --git a/app/models/alert.rb b/app/models/alert.rb index e60abef525..3cabebc294 100644 --- a/app/models/alert.rb +++ b/app/models/alert.rb @@ -1,9 +1,9 @@ class Alert < ApplicationRecord belongs_to :device DEFAULTS = [ - SEED_DATA = { problem_tag: "api.seed_data.missing", priority: 400 }, - DOCUMENTATION = { problem_tag: "api.documentation.unread", priority: 300 }, - TOUR = { problem_tag: "api.tour.not_taken", priority: 200 }, + SEED_DATA = { problem_tag: "api.seed_data.missing", priority: 200 }, + DOCUMENTATION = { problem_tag: "api.documentation.unread", priority: 400 }, + TOUR = { problem_tag: "api.tour.not_taken", priority: 300 }, USER = { problem_tag: "api.user.not_welcomed", priority: 100 }, BULLETIN = { problem_tag: "api.bulletin.unread", priority: 100 }, DEMO = { problem_tag: "api.demo_account.in_use", priority: 100 }, diff --git a/app/mutations/devices/create.rb b/app/mutations/devices/create.rb index 5ff81f7300..5cbd221103 100644 --- a/app/mutations/devices/create.rb +++ b/app/mutations/devices/create.rb @@ -16,8 +16,6 @@ class Create < Mutations::Command def execute merge_default_values device = Device.create!({ name: "FarmBot" }.merge(inputs.except(:user))) - Alerts::Create.run!(Alert::SEED_DATA.merge(device: device)) - Alerts::Create.run!(Alert::TOUR.merge(device: device)) Alerts::Create.run!(Alert::USER.merge(device: device)) Alerts::Create.run!(Alert::DOCUMENTATION.merge(device: device)) diff --git a/app/mutations/devices/create_seed_data.rb b/app/mutations/devices/create_seed_data.rb index 66a9a0e40d..8efe56fe2e 100644 --- a/app/mutations/devices/create_seed_data.rb +++ b/app/mutations/devices/create_seed_data.rb @@ -34,6 +34,10 @@ class CreateSeedData < Mutations::Command end def execute + if device.account_seeded_at + return { done: "Device already has seed data." } + end + device.update(account_seeded_at: Time.now) self.delay.run_seeds! { done: "Loading resources now." } end diff --git a/app/mutations/devices/reset.rb b/app/mutations/devices/reset.rb index be57e5fd4b..7b5ddcbf16 100644 --- a/app/mutations/devices/reset.rb +++ b/app/mutations/devices/reset.rb @@ -20,7 +20,10 @@ def execute def run_it ActiveRecord::Base.transaction do - device.update!(name: "FarmBot", mounted_tool_id: nil) + device.update!(name: "FarmBot", + mounted_tool_id: nil, + setup_completed_at: nil, + account_seeded_at: nil) device.folders.update_all(parent_id: nil) Device::SINGULAR_RESOURCES.keys.map do |resource| device.send(resource).destroy! diff --git a/app/mutations/devices/seeders/abstract_seeder.rb b/app/mutations/devices/seeders/abstract_seeder.rb index e7deff99df..215a3db9f4 100644 --- a/app/mutations/devices/seeders/abstract_seeder.rb +++ b/app/mutations/devices/seeders/abstract_seeder.rb @@ -33,7 +33,6 @@ class AbstractSeeder :settings_default_map_size_y, :settings_device_name, :settings_change_firmware_config_defaults, - :settings_soil_height, :settings_firmware, :settings_gantry_height, :settings_hide_sensors, @@ -86,9 +85,7 @@ def initialize(device) @device = device end - def settings_hide_sensors - device.web_app_config.update!(hide_sensors: false) - end + def settings_hide_sensors; end def peripherals_lighting add_peripheral(7, ToolNames::LIGHTING) @@ -209,11 +206,6 @@ def settings_default_map_size_x; end def settings_default_map_size_y; end def settings_device_name; end def settings_change_firmware_config_defaults; end - def settings_soil_height; end - - def settings_soil_height - device.fbos_config.update!(soil_height: -500) - end def settings_three_d; end diff --git a/app/mutations/devices/seeders/demo_account_seeder.rb b/app/mutations/devices/seeders/demo_account_seeder.rb index 332503ca4e..5ec7b8f17a 100644 --- a/app/mutations/devices/seeders/demo_account_seeder.rb +++ b/app/mutations/devices/seeders/demo_account_seeder.rb @@ -8,7 +8,9 @@ class DemoAccountSeeder < AbstractSeeder "Genesis XL" => "Genesis_XL_Demo_Webcam.jpg", "Genesis" => "Genesis_Demo_Webcam.jpg", } - UNUSED_ALERTS = ["api.seed_data.missing", "api.user.not_welcomed"] + UNUSED_ALERTS = [ + Alert::USER[:problem_tag], + ] def feed(product_line) feed_name = "" @@ -151,6 +153,7 @@ def marketing_bulletin DEMO_ALERTS = [ Alert::DEMO, Alert::BULLETIN.merge(slug: "buy-a-farmbot", priority: 9999), + Alert::TOUR, ] DEMO_LOGS = [ diff --git a/app/mutations/devices/seeders/none.rb b/app/mutations/devices/seeders/none.rb index 0a0888962f..486866509d 100644 --- a/app/mutations/devices/seeders/none.rb +++ b/app/mutations/devices/seeders/none.rb @@ -35,7 +35,6 @@ def sequences_grid; end def sequences_dispense_water; end def settings_default_map_size_x; end def settings_default_map_size_y; end - def settings_soil_height; end def settings_gantry_height; end def settings_firmware; end def settings_hide_sensors; end diff --git a/app/mutations/devices/update.rb b/app/mutations/devices/update.rb index 087140fb64..4bcdc979f0 100644 --- a/app/mutations/devices/update.rb +++ b/app/mutations/devices/update.rb @@ -11,6 +11,7 @@ class Update < Mutations::Command string :timezone string :fb_order_number, nils: true string :setup_completed_at, nils: true + string :account_seeded_at, nils: true integer :mounted_tool_id, nils: true integer :ota_hour, nils: true float :lat, nils: true diff --git a/app/serializers/device_serializer.rb b/app/serializers/device_serializer.rb index 8e0d8547c7..3718ae3385 100644 --- a/app/serializers/device_serializer.rb +++ b/app/serializers/device_serializer.rb @@ -12,6 +12,7 @@ class DeviceSerializer < ApplicationSerializer :rpi, :serial_number, :setup_completed_at, + :account_seeded_at, :throttled_at, :throttled_until, :timezone, diff --git a/app/views/dashboard/_common_assets.html.erb b/app/views/dashboard/_common_assets.html.erb index 13181975ab..fe9f95bb88 100644 --- a/app/views/dashboard/_common_assets.html.erb +++ b/app/views/dashboard/_common_assets.html.erb @@ -18,5 +18,3 @@ window.process = { <%= render "addons" %> <%= javascript_include_tag *@js_assets %> - - diff --git a/app/views/dashboard/demo.html.erb b/app/views/dashboard/demo.html.erb index 216bad188c..041b092f1d 100644 --- a/app/views/dashboard/demo.html.erb +++ b/app/views/dashboard/demo.html.erb @@ -38,7 +38,7 @@ bottom: 60px; box-shadow: 0 0 15px rgba(0,0,0,0.4); color: #fff; - font-family: "Cabin", sans-serif; + font-family: "Cabin", "Cabin Fallback", sans-serif; font-size: 25px; font-weight: bold; padding: 15px 30px; diff --git a/app/views/layouts/dashboard.html.erb b/app/views/layouts/dashboard.html.erb index e8d42b0f60..bbecce5eca 100644 --- a/app/views/layouts/dashboard.html.erb +++ b/app/views/layouts/dashboard.html.erb @@ -1,5 +1,5 @@ - +
@@ -18,8 +18,6 @@ text-align: center; width: 100%; padding-top: 10%; color: #434343; } <%= stylesheet_link_tag *@css_assets %> - - <% manifest_file = diff --git a/app/views/layouts/mailer.html.erb b/app/views/layouts/mailer.html.erb index 5a1da3f022..8078b5c3b0 100644 --- a/app/views/layouts/mailer.html.erb +++ b/app/views/layouts/mailer.html.erb @@ -1,9 +1,9 @@ - + <%= yield %> - \ No newline at end of file + diff --git a/config/application.rb b/config/application.rb index 1ee18cd100..c466f58c63 100755 --- a/config/application.rb +++ b/config/application.rb @@ -54,6 +54,14 @@ class Application < Rails::Application credentials: false, # No cookies. max_age: 0 end + unless ENV["GCS_BUCKET"] + allow do + origins ["#{ENV.fetch("API_HOST")}:#{API_PORT}", "localhost:#{API_PORT}"] + resource "*", + headers: :any, + methods: [:get, :options] + end + end end API_PORT = ENV["API_PORT"] Rails.application.routes.default_url_options[:host] = LOCAL_API_HOST diff --git a/config/initializers/rack_attack.rb b/config/initializers/rack_attack.rb index 717b33b1d4..aea610c3d5 100644 --- a/config/initializers/rack_attack.rb +++ b/config/initializers/rack_attack.rb @@ -27,7 +27,7 @@ class Rack::Attack end ### Don't allow too many demo account requests ### - throttle("demo_accounts/ip", limit: 10, period: 10.minutes) do |req| + throttle("demo_accounts/ip", limit: 50, period: 1.hour) do |req| case req.path.downcase when "/demo", "/try_farmbot" req.ip diff --git a/db/migrate/20250925195004_change_soil_height_default.rb b/db/migrate/20250925195004_change_soil_height_default.rb new file mode 100644 index 0000000000..62cd9f668a --- /dev/null +++ b/db/migrate/20250925195004_change_soil_height_default.rb @@ -0,0 +1,5 @@ +class ChangeSoilHeightDefault < ActiveRecord::Migration[6.1] + def change + change_column_default(:fbos_configs, :soil_height, from: 0, to: -500) + end +end diff --git a/db/migrate/20250930204600_add_account_seeded_at_to_device.rb b/db/migrate/20250930204600_add_account_seeded_at_to_device.rb new file mode 100644 index 0000000000..6e6e45148c --- /dev/null +++ b/db/migrate/20250930204600_add_account_seeded_at_to_device.rb @@ -0,0 +1,9 @@ +class AddAccountSeededAtToDevice < ActiveRecord::Migration[6.1] + def up + add_column :devices, :account_seeded_at, :datetime + end + + def down + remove_column :devices, :account_seeded_at + end +end diff --git a/db/structure.sql b/db/structure.sql index 9a974c3f62..12e5713051 100644 --- a/db/structure.sql +++ b/db/structure.sql @@ -389,7 +389,8 @@ CREATE TABLE public.devices ( rpi character varying(3), max_log_age_in_days integer DEFAULT 0, max_sequence_count integer DEFAULT 0, - max_sequence_length integer DEFAULT 0 + max_sequence_length integer DEFAULT 0, + account_seeded_at timestamp without time zone ); @@ -576,7 +577,7 @@ CREATE TABLE public.fbos_configs ( update_channel character varying(7) DEFAULT 'stable'::character varying, boot_sequence_id integer, safe_height integer DEFAULT 0, - soil_height integer DEFAULT 0, + soil_height integer DEFAULT '-500'::integer, gantry_height integer DEFAULT 0, default_axis_order character varying(10) DEFAULT 'xy,z;high'::character varying ); @@ -3987,6 +3988,8 @@ INSERT INTO "schema_migrations" (version) VALUES ('20250502201109'), ('20250514203443'), ('20250722234106'), -('20250802174543'); +('20250802174543'), +('20250925195004'), +('20250930204600'); diff --git a/docker_configs/api.Dockerfile b/docker_configs/api.Dockerfile index b32180adff..699b9f5c23 100644 --- a/docker_configs/api.Dockerfile +++ b/docker_configs/api.Dockerfile @@ -1,4 +1,4 @@ -FROM ruby:3.4.5 +FROM ruby:3.4.7 RUN curl https://www.postgresql.org/media/keys/ACCC4CF8.asc | gpg --dearmor | tee /etc/apt/trusted.gpg.d/apt.postgresql.org.gpg > /dev/null && \ sh -c '. /etc/os-release; echo $VERSION_CODENAME; echo "deb http://apt.postgresql.org/pub/repos/apt/ $VERSION_CODENAME-pgdg main" >> /etc/apt/sources.list.d/pgdg.list' && \ apt-get update -qq && apt-get install -y build-essential libpq-dev postgresql postgresql-contrib && \ diff --git a/frontend/__test_support__/fake_state/app.ts b/frontend/__test_support__/fake_state/app.ts index 0f4bf5251f..e48c7a2797 100644 --- a/frontend/__test_support__/fake_state/app.ts +++ b/frontend/__test_support__/fake_state/app.ts @@ -3,7 +3,6 @@ import { fakeMovementState } from "../fake_bot_data"; import { controlsState, curvesPanelState, - jobsState, metricPanelState, plantsPanelState, pointsPanelState, @@ -25,6 +24,5 @@ export const app: AppState = { toasts: {}, movement: fakeMovementState(), controls: controlsState(), - jobs: jobsState(), popups: popUpsState(), }; diff --git a/frontend/__test_support__/panel_state.ts b/frontend/__test_support__/panel_state.ts index 6a7f2387a8..506d9bff34 100644 --- a/frontend/__test_support__/panel_state.ts +++ b/frontend/__test_support__/panel_state.ts @@ -6,7 +6,6 @@ import { SequencesPanelState, MetricPanelState, CurvesPanelState, - JobsAndLogsState, ControlsState, PopupsState, } from "../interfaces"; @@ -75,11 +74,6 @@ export const controlsState = (): ControlsState => ({ webcams: false, }); -export const jobsState = (): JobsAndLogsState => ({ - jobs: true, - logs: false, -}); - export const popUpsState = (): PopupsState => ({ timeTravel: false, controls: false, diff --git a/frontend/__test_support__/three_d_mocks.tsx b/frontend/__test_support__/three_d_mocks.tsx index 5fe6a4432c..9860b0ea78 100644 --- a/frontend/__test_support__/three_d_mocks.tsx +++ b/frontend/__test_support__/three_d_mocks.tsx @@ -563,7 +563,12 @@ jest.mock("@react-three/drei", () => {+ extends React.Component
{ + state: DemoAccountState = { error: undefined, stage: t("DEMO THE APP"), productLine: "genesis_1.8", @@ -69,28 +70,29 @@ export class DemoIframe extends React.Component<{}, State> { this.connectMqtt().then(this.connectApi); }; - ok = () => { + protected seedDataSelect = (): React.ReactElement => { const selection = this.state.productLine; - return
{t("Device ID")}: {id}
+{t("Order number")}: + {fb_order_number || t("Unset")}
{controller_version ?{t("Version")}: { reformatFbosVersion(controller_version)}
@@ -177,14 +180,21 @@ export class Connectivity render() { const { realtime, network, history } = this.props.metricPanelState; return