Compare commits
148 Commits
sensor_rea
...
jebba
Author | SHA1 | Date |
---|---|---|
server | 53bc33fc3e | |
Rick Carlino | 1a7ee04d0b | |
gabrielburnworth | 4a7a683ba7 | |
Rick Carlino | 8700d50c81 | |
gabrielburnworth | 3bab5694b8 | |
Rick Carlino | e205214ba4 | |
gabrielburnworth | 73e9daed05 | |
gabrielburnworth | 426f97ddc2 | |
Rick Carlino | 88e526cce3 | |
Rick Carlino | 9e14c2125d | |
Rick Carlino | 889c78c77a | |
Rick Carlino | 3b1dbe2209 | |
gabrielburnworth | 980d39f70d | |
Rick Carlino | 461f4c2509 | |
gabrielburnworth | d2176fd6ea | |
gabrielburnworth | c9511593a3 | |
Rick Carlino | 66553d143d | |
Rick Carlino | 696350343b | |
Rick Carlino | 1f773c44fc | |
Rick Carlino | 87c22d4a96 | |
Rick Carlino | 9f35dd9992 | |
gabrielburnworth | 14bf5216e0 | |
gabrielburnworth | 1d196d633a | |
Rick Carlino | de607e3e3a | |
gabrielburnworth | d931cd1b84 | |
gabrielburnworth | b3f93dd678 | |
Rick Carlino | 7f9ecd450d | |
gabrielburnworth | 69462e4b60 | |
gabrielburnworth | d3732aed20 | |
Rick Carlino | 6213028f0f | |
gabrielburnworth | 281813369e | |
Rick Carlino | 1014eece5f | |
gabrielburnworth | 6f484ab2e3 | |
Rick Carlino | 0bd6d9a967 | |
gabrielburnworth | 25b2f18c4c | |
Rick Carlino | 1556084dbd | |
Rick Carlino | 0571100229 | |
Rick Carlino | d6909f439c | |
Rick Carlino | 36b5c90b65 | |
Rick Carlino | f3ac957485 | |
Rick Carlino | 6f834517ca | |
Rick Carlino | 44c3f7dc4e | |
Rick Carlino | 5bb77c1c14 | |
Rick Carlino | 3ee1478a58 | |
Rick Carlino | df9e0ef26b | |
Rick Carlino | 0e02ca06ee | |
Rick Carlino | 643bcb1a37 | |
Rick Carlino | 88b20a73ea | |
Rick Carlino | e8a8165635 | |
Rick Carlino | 588d4eb36e | |
Rick Carlino | efea80b593 | |
gabrielburnworth | c75d93f3c4 | |
gabrielburnworth | bee1e0e074 | |
Rick Carlino | 4375a935f0 | |
Rick Carlino | 7d5fe7c9f6 | |
Rick Carlino | e801d53d51 | |
Rick Carlino | bf0a03d11d | |
gabrielburnworth | ec757b1b29 | |
gabrielburnworth | 3c3b120b9b | |
Rick Carlino | 046035ab9e | |
Rick Carlino | 52b481e831 | |
Rick Carlino | 73422eb8ea | |
gabrielburnworth | b087e08f13 | |
Rick Carlino | 1e1b405c32 | |
Rick Carlino | dccea4e474 | |
Rick Carlino | 91d86bad0c | |
Rick Carlino | bfe4df68a8 | |
Rick Carlino | dd6a43d901 | |
Rick Carlino | 726cd6d4e7 | |
Rick Carlino | d730cd9260 | |
Rick Carlino | eb8cfd3c91 | |
Rick Carlino | 8f9bd4a5e7 | |
gabrielburnworth | 3ebf434945 | |
Rick Carlino | 92a7194c6e | |
gabrielburnworth | 24ad841d7f | |
Rick Carlino | b45f806309 | |
Rick Carlino | cf7ec86106 | |
Rick Carlino | 37f7517c51 | |
Rick Carlino | 2a04803dc6 | |
Rick Carlino | 3700406687 | |
Rick Carlino | 1ba0ff7871 | |
Rick Carlino | be23cd44b5 | |
Rick Carlino | 43d1b9da33 | |
Rick Carlino | bda30bae09 | |
Rick Carlino | de21cb16da | |
Rick Carlino | 0a153bc656 | |
Rick Carlino | 149451c270 | |
Gabriel Burnworth | d7de315c20 | |
Rick Carlino | 61c09b69b9 | |
Rick Carlino | 863071824b | |
Rick Carlino | 82f2fbef90 | |
gabrielburnworth | c736348bed | |
gabrielburnworth | 309737dd33 | |
Rick Carlino | 3a9ea9af79 | |
Rick Carlino | bc68f3e79f | |
Rick Carlino | 85be07efe5 | |
gabrielburnworth | fe9ff346a8 | |
gabrielburnworth | ec878e0dae | |
gabrielburnworth | b1c2b36a37 | |
gabrielburnworth | 11f349ac89 | |
Rick Carlino | 67373e4f7e | |
Fabio Dessi | dd46830b9d | |
Fabio Dessi | 63b333746d | |
Rick Carlino | 2c6033f57a | |
gabrielburnworth | 4d2ea00130 | |
gabrielburnworth | c8c57d5340 | |
gabrielburnworth | 4013291787 | |
gabrielburnworth | 25d944e4b7 | |
gabrielburnworth | de6f886586 | |
gabrielburnworth | 800625e8a1 | |
Rick Carlino | bce0700cd9 | |
Rick Carlino | cccecf58f6 | |
MarcRoland | c2308cb987 | |
Rick Carlino | ffbf660143 | |
gabrielburnworth | edb96d3ca8 | |
Rick Carlino | a49e5e67ba | |
gabrielburnworth | 90ddd78bb8 | |
gabrielburnworth | 9bd98aca1e | |
Rick Carlino | 49fdced812 | |
Rick Carlino | 6bc0034d67 | |
Rick Carlino | 8e0cf2603c | |
gabrielburnworth | 4a0035b9eb | |
gabrielburnworth | 19eebde8e2 | |
Rick Carlino | cd52670c0b | |
Rick Carlino | fd62ccd9aa | |
Rick Carlino | 1a4a106179 | |
Rick Carlino | ee8851b0af | |
gabrielburnworth | 40150a307c | |
Rick Carlino | a5b1d5631e | |
Rick Carlino | 26a4f66a75 | |
Rick Carlino | 73222de627 | |
Rick Carlino | ddb480921e | |
Rick Carlino | 5945d2a38d | |
gabrielburnworth | a04ec59ba5 | |
Rick Carlino | 310686508f | |
gabrielburnworth | 66b5e3c962 | |
gabrielburnworth | cf0af59e42 | |
gabrielburnworth | 9dab0c4bc5 | |
Rick Carlino | 94ee85bd83 | |
Rick Carlino | 672aae441b | |
Rick Carlino | 3d0223e56a | |
Rick Carlino | 93d2521511 | |
gabrielburnworth | aafd84fff7 | |
Rick Carlino | 8f8056a3e3 | |
Rick Carlino | e490aa83f6 | |
Rick Carlino | 3e300defa1 | |
Rick Carlino | 11d08aea99 | |
Rick Carlino | c3029d06ed |
2
Gemfile
2
Gemfile
|
@ -35,7 +35,7 @@ group :development, :test do
|
|||
gem "hashdiff"
|
||||
gem "pry-rails"
|
||||
gem "pry"
|
||||
gem "rspec-rails", "4.0.0.beta3"
|
||||
gem "rspec-rails"
|
||||
gem "rspec"
|
||||
gem 'rspec_junit_formatter'
|
||||
gem "simplecov"
|
||||
|
|
197
Gemfile.lock
197
Gemfile.lock
|
@ -7,38 +7,38 @@ GIT
|
|||
GEM
|
||||
remote: https://rubygems.org/
|
||||
specs:
|
||||
actioncable (6.0.2.1)
|
||||
actionpack (= 6.0.2.1)
|
||||
actioncable (6.0.2.2)
|
||||
actionpack (= 6.0.2.2)
|
||||
nio4r (~> 2.0)
|
||||
websocket-driver (>= 0.6.1)
|
||||
actionmailbox (6.0.2.1)
|
||||
actionpack (= 6.0.2.1)
|
||||
activejob (= 6.0.2.1)
|
||||
activerecord (= 6.0.2.1)
|
||||
activestorage (= 6.0.2.1)
|
||||
activesupport (= 6.0.2.1)
|
||||
actionmailbox (6.0.2.2)
|
||||
actionpack (= 6.0.2.2)
|
||||
activejob (= 6.0.2.2)
|
||||
activerecord (= 6.0.2.2)
|
||||
activestorage (= 6.0.2.2)
|
||||
activesupport (= 6.0.2.2)
|
||||
mail (>= 2.7.1)
|
||||
actionmailer (6.0.2.1)
|
||||
actionpack (= 6.0.2.1)
|
||||
actionview (= 6.0.2.1)
|
||||
activejob (= 6.0.2.1)
|
||||
actionmailer (6.0.2.2)
|
||||
actionpack (= 6.0.2.2)
|
||||
actionview (= 6.0.2.2)
|
||||
activejob (= 6.0.2.2)
|
||||
mail (~> 2.5, >= 2.5.4)
|
||||
rails-dom-testing (~> 2.0)
|
||||
actionpack (6.0.2.1)
|
||||
actionview (= 6.0.2.1)
|
||||
activesupport (= 6.0.2.1)
|
||||
actionpack (6.0.2.2)
|
||||
actionview (= 6.0.2.2)
|
||||
activesupport (= 6.0.2.2)
|
||||
rack (~> 2.0, >= 2.0.8)
|
||||
rack-test (>= 0.6.3)
|
||||
rails-dom-testing (~> 2.0)
|
||||
rails-html-sanitizer (~> 1.0, >= 1.2.0)
|
||||
actiontext (6.0.2.1)
|
||||
actionpack (= 6.0.2.1)
|
||||
activerecord (= 6.0.2.1)
|
||||
activestorage (= 6.0.2.1)
|
||||
activesupport (= 6.0.2.1)
|
||||
actiontext (6.0.2.2)
|
||||
actionpack (= 6.0.2.2)
|
||||
activerecord (= 6.0.2.2)
|
||||
activestorage (= 6.0.2.2)
|
||||
activesupport (= 6.0.2.2)
|
||||
nokogiri (>= 1.8.5)
|
||||
actionview (6.0.2.1)
|
||||
activesupport (= 6.0.2.1)
|
||||
actionview (6.0.2.2)
|
||||
activesupport (= 6.0.2.2)
|
||||
builder (~> 3.1)
|
||||
erubi (~> 1.4)
|
||||
rails-dom-testing (~> 2.0)
|
||||
|
@ -48,20 +48,20 @@ GEM
|
|||
activemodel (>= 4.1, < 6.1)
|
||||
case_transform (>= 0.2)
|
||||
jsonapi-renderer (>= 0.1.1.beta1, < 0.3)
|
||||
activejob (6.0.2.1)
|
||||
activesupport (= 6.0.2.1)
|
||||
activejob (6.0.2.2)
|
||||
activesupport (= 6.0.2.2)
|
||||
globalid (>= 0.3.6)
|
||||
activemodel (6.0.2.1)
|
||||
activesupport (= 6.0.2.1)
|
||||
activerecord (6.0.2.1)
|
||||
activemodel (= 6.0.2.1)
|
||||
activesupport (= 6.0.2.1)
|
||||
activestorage (6.0.2.1)
|
||||
actionpack (= 6.0.2.1)
|
||||
activejob (= 6.0.2.1)
|
||||
activerecord (= 6.0.2.1)
|
||||
activemodel (6.0.2.2)
|
||||
activesupport (= 6.0.2.2)
|
||||
activerecord (6.0.2.2)
|
||||
activemodel (= 6.0.2.2)
|
||||
activesupport (= 6.0.2.2)
|
||||
activestorage (6.0.2.2)
|
||||
actionpack (= 6.0.2.2)
|
||||
activejob (= 6.0.2.2)
|
||||
activerecord (= 6.0.2.2)
|
||||
marcel (~> 0.3.1)
|
||||
activesupport (6.0.2.1)
|
||||
activesupport (6.0.2.2)
|
||||
concurrent-ruby (~> 1.0, >= 1.0.2)
|
||||
i18n (>= 0.7, < 2)
|
||||
minitest (~> 5.1)
|
||||
|
@ -69,11 +69,11 @@ GEM
|
|||
zeitwerk (~> 2.2)
|
||||
addressable (2.7.0)
|
||||
public_suffix (>= 2.0.2, < 5.0)
|
||||
amq-protocol (2.3.0)
|
||||
amq-protocol (2.3.1)
|
||||
bcrypt (3.1.13)
|
||||
builder (3.2.4)
|
||||
bunny (2.14.3)
|
||||
amq-protocol (~> 2.3, >= 2.3.0)
|
||||
bunny (2.15.0)
|
||||
amq-protocol (~> 2.3, >= 2.3.1)
|
||||
case_transform (0.2)
|
||||
activesupport
|
||||
climate_control (0.2.0)
|
||||
|
@ -82,9 +82,9 @@ GEM
|
|||
simplecov
|
||||
url
|
||||
coderay (1.1.2)
|
||||
concurrent-ruby (1.1.5)
|
||||
concurrent-ruby (1.1.6)
|
||||
crass (1.0.6)
|
||||
database_cleaner (1.7.0)
|
||||
database_cleaner (1.8.3)
|
||||
declarative (0.0.10)
|
||||
declarative-option (0.1.0)
|
||||
delayed_job (4.1.8)
|
||||
|
@ -99,27 +99,27 @@ GEM
|
|||
responders
|
||||
warden (~> 1.2.3)
|
||||
diff-lcs (1.3)
|
||||
digest-crc (0.4.1)
|
||||
discard (1.1.0)
|
||||
digest-crc (0.5.1)
|
||||
discard (1.2.0)
|
||||
activerecord (>= 4.2, < 7)
|
||||
docile (1.3.2)
|
||||
erubi (1.9.0)
|
||||
factory_bot (5.1.1)
|
||||
factory_bot (5.1.2)
|
||||
activesupport (>= 4.2.0)
|
||||
factory_bot_rails (5.1.1)
|
||||
factory_bot (~> 5.1.0)
|
||||
railties (>= 4.2.0)
|
||||
faker (2.10.1)
|
||||
faker (2.11.0)
|
||||
i18n (>= 1.6, < 2)
|
||||
faraday (0.15.4)
|
||||
faraday (0.17.3)
|
||||
multipart-post (>= 1.2, < 3)
|
||||
faraday_middleware (0.13.1)
|
||||
faraday_middleware (0.14.0)
|
||||
faraday (>= 0.7.4, < 1.0)
|
||||
font-awesome-rails (4.7.0.5)
|
||||
railties (>= 3.2, < 6.1)
|
||||
globalid (0.4.2)
|
||||
activesupport (>= 4.2.0)
|
||||
google-api-client (0.36.4)
|
||||
google-api-client (0.37.2)
|
||||
addressable (~> 2.5, >= 2.5.1)
|
||||
googleauth (~> 0.9)
|
||||
httpclient (>= 2.8.1, < 3.0)
|
||||
|
@ -127,10 +127,12 @@ GEM
|
|||
representable (~> 3.0)
|
||||
retriable (>= 2.0, < 4.0)
|
||||
signet (~> 0.12)
|
||||
google-cloud-core (1.4.1)
|
||||
google-cloud-core (1.5.0)
|
||||
google-cloud-env (~> 1.0)
|
||||
google-cloud-env (1.3.0)
|
||||
faraday (~> 0.11)
|
||||
google-cloud-errors (~> 1.0)
|
||||
google-cloud-env (1.3.1)
|
||||
faraday (>= 0.17.3, < 2.0)
|
||||
google-cloud-errors (1.0.0)
|
||||
google-cloud-storage (1.25.1)
|
||||
addressable (~> 2.5)
|
||||
digest-crc (~> 0.4)
|
||||
|
@ -138,14 +140,14 @@ GEM
|
|||
google-cloud-core (~> 1.2)
|
||||
googleauth (~> 0.9)
|
||||
mini_mime (~> 1.0)
|
||||
googleauth (0.10.0)
|
||||
faraday (~> 0.12)
|
||||
googleauth (0.11.0)
|
||||
faraday (>= 0.17.3, < 2.0)
|
||||
jwt (>= 1.4, < 3.0)
|
||||
memoist (~> 0.16)
|
||||
multi_json (~> 1.11)
|
||||
os (>= 0.9, < 2.0)
|
||||
signet (~> 0.12)
|
||||
hashdiff (1.0.0)
|
||||
hashdiff (1.0.1)
|
||||
hashie (3.6.0)
|
||||
httpclient (2.8.3)
|
||||
i18n (1.8.2)
|
||||
|
@ -165,7 +167,7 @@ GEM
|
|||
activerecord
|
||||
kaminari-core (= 1.2.0)
|
||||
kaminari-core (1.2.0)
|
||||
loofah (2.4.0)
|
||||
loofah (2.5.0)
|
||||
crass (~> 1.0.2)
|
||||
nokogiri (>= 1.5.9)
|
||||
mail (2.7.1)
|
||||
|
@ -173,56 +175,56 @@ GEM
|
|||
marcel (0.3.3)
|
||||
mimemagic (~> 0.3.2)
|
||||
memoist (0.16.2)
|
||||
method_source (0.9.2)
|
||||
mimemagic (0.3.3)
|
||||
method_source (1.0.0)
|
||||
mimemagic (0.3.4)
|
||||
mini_mime (1.0.2)
|
||||
mini_portile2 (2.4.0)
|
||||
minitest (5.14.0)
|
||||
multi_json (1.13.1)
|
||||
multipart-post (2.1.1)
|
||||
mutations (0.9.0)
|
||||
mutations (0.9.1)
|
||||
activesupport
|
||||
nio4r (2.5.2)
|
||||
nokogiri (1.10.7)
|
||||
nokogiri (1.10.9)
|
||||
mini_portile2 (~> 2.4.0)
|
||||
orm_adapter (0.5.0)
|
||||
os (1.0.1)
|
||||
passenger (6.0.4)
|
||||
rack
|
||||
rake (>= 0.8.1)
|
||||
pg (1.2.2)
|
||||
pry (0.12.2)
|
||||
coderay (~> 1.1.0)
|
||||
method_source (~> 0.9.0)
|
||||
pg (1.2.3)
|
||||
pry (0.13.1)
|
||||
coderay (~> 1.1)
|
||||
method_source (~> 1.0)
|
||||
pry-rails (0.3.9)
|
||||
pry (>= 0.10.4)
|
||||
public_suffix (4.0.3)
|
||||
rabbitmq_http_api_client (1.12.0)
|
||||
faraday (~> 0.15.4)
|
||||
faraday_middleware (~> 0.13.0)
|
||||
rabbitmq_http_api_client (1.13.0)
|
||||
faraday (>= 0.15, < 1)
|
||||
faraday_middleware (>= 0.13.0, < 1)
|
||||
hashie (~> 3.6)
|
||||
multi_json (~> 1.13.1)
|
||||
rack (2.1.1)
|
||||
rack (2.2.2)
|
||||
rack-attack (6.2.2)
|
||||
rack (>= 1.0, < 3)
|
||||
rack-cors (1.1.1)
|
||||
rack (>= 2.0.0)
|
||||
rack-test (1.1.0)
|
||||
rack (>= 1.0, < 3)
|
||||
rails (6.0.2.1)
|
||||
actioncable (= 6.0.2.1)
|
||||
actionmailbox (= 6.0.2.1)
|
||||
actionmailer (= 6.0.2.1)
|
||||
actionpack (= 6.0.2.1)
|
||||
actiontext (= 6.0.2.1)
|
||||
actionview (= 6.0.2.1)
|
||||
activejob (= 6.0.2.1)
|
||||
activemodel (= 6.0.2.1)
|
||||
activerecord (= 6.0.2.1)
|
||||
activestorage (= 6.0.2.1)
|
||||
activesupport (= 6.0.2.1)
|
||||
rails (6.0.2.2)
|
||||
actioncable (= 6.0.2.2)
|
||||
actionmailbox (= 6.0.2.2)
|
||||
actionmailer (= 6.0.2.2)
|
||||
actionpack (= 6.0.2.2)
|
||||
actiontext (= 6.0.2.2)
|
||||
actionview (= 6.0.2.2)
|
||||
activejob (= 6.0.2.2)
|
||||
activemodel (= 6.0.2.2)
|
||||
activerecord (= 6.0.2.2)
|
||||
activestorage (= 6.0.2.2)
|
||||
activesupport (= 6.0.2.2)
|
||||
bundler (>= 1.3.0)
|
||||
railties (= 6.0.2.1)
|
||||
railties (= 6.0.2.2)
|
||||
sprockets-rails (>= 2.0.0)
|
||||
rails-dom-testing (2.0.3)
|
||||
activesupport (>= 4.2.0)
|
||||
|
@ -234,9 +236,9 @@ GEM
|
|||
rails_stdout_logging
|
||||
rails_serve_static_assets (0.0.5)
|
||||
rails_stdout_logging (0.0.5)
|
||||
railties (6.0.2.1)
|
||||
actionpack (= 6.0.2.1)
|
||||
activesupport (= 6.0.2.1)
|
||||
railties (6.0.2.2)
|
||||
actionpack (= 6.0.2.2)
|
||||
activesupport (= 6.0.2.2)
|
||||
method_source
|
||||
rake (>= 0.8.7)
|
||||
thor (>= 0.20.3, < 2.0)
|
||||
|
@ -252,44 +254,43 @@ GEM
|
|||
actionpack (>= 5.0)
|
||||
railties (>= 5.0)
|
||||
retriable (3.1.2)
|
||||
rollbar (2.23.2)
|
||||
rollbar (2.24.0)
|
||||
rspec (3.9.0)
|
||||
rspec-core (~> 3.9.0)
|
||||
rspec-expectations (~> 3.9.0)
|
||||
rspec-mocks (~> 3.9.0)
|
||||
rspec-core (3.9.1)
|
||||
rspec-support (~> 3.9.1)
|
||||
rspec-expectations (3.9.0)
|
||||
rspec-expectations (3.9.1)
|
||||
diff-lcs (>= 1.2.0, < 2.0)
|
||||
rspec-support (~> 3.9.0)
|
||||
rspec-mocks (3.9.1)
|
||||
diff-lcs (>= 1.2.0, < 2.0)
|
||||
rspec-support (~> 3.9.0)
|
||||
rspec-rails (4.0.0.beta3)
|
||||
rspec-rails (4.0.0)
|
||||
actionpack (>= 4.2)
|
||||
activesupport (>= 4.2)
|
||||
railties (>= 4.2)
|
||||
rspec-core (~> 3.8)
|
||||
rspec-expectations (~> 3.8)
|
||||
rspec-mocks (~> 3.8)
|
||||
rspec-support (~> 3.8)
|
||||
rspec-core (~> 3.9)
|
||||
rspec-expectations (~> 3.9)
|
||||
rspec-mocks (~> 3.9)
|
||||
rspec-support (~> 3.9)
|
||||
rspec-support (3.9.2)
|
||||
rspec_junit_formatter (0.4.1)
|
||||
rspec-core (>= 2, < 4, != 2.12.0)
|
||||
scenic (1.5.1)
|
||||
scenic (1.5.2)
|
||||
activerecord (>= 4.0.0)
|
||||
railties (>= 4.0.0)
|
||||
secure_headers (6.3.0)
|
||||
signet (0.12.0)
|
||||
signet (0.13.0)
|
||||
addressable (~> 2.3)
|
||||
faraday (~> 0.9)
|
||||
faraday (>= 0.17.3, < 2.0)
|
||||
jwt (>= 1.5, < 3.0)
|
||||
multi_json (~> 1.10)
|
||||
simplecov (0.17.1)
|
||||
simplecov (0.18.5)
|
||||
docile (~> 1.1)
|
||||
json (>= 1.8, < 3)
|
||||
simplecov-html (~> 0.10.0)
|
||||
simplecov-html (0.10.2)
|
||||
simplecov-html (~> 0.11)
|
||||
simplecov-html (0.12.2)
|
||||
sprockets (4.0.0)
|
||||
concurrent-ruby (~> 1.0)
|
||||
rack (> 1, < 3)
|
||||
|
@ -299,7 +300,7 @@ GEM
|
|||
sprockets (>= 3.0.0)
|
||||
thor (1.0.1)
|
||||
thread_safe (0.3.6)
|
||||
tzinfo (1.2.6)
|
||||
tzinfo (1.2.7)
|
||||
thread_safe (~> 0.1)
|
||||
uber (0.1.0)
|
||||
url (0.3.2)
|
||||
|
@ -311,7 +312,7 @@ GEM
|
|||
websocket-driver (0.7.1)
|
||||
websocket-extensions (>= 0.1.0)
|
||||
websocket-extensions (0.1.4)
|
||||
zeitwerk (2.2.2)
|
||||
zeitwerk (2.3.0)
|
||||
|
||||
PLATFORMS
|
||||
ruby
|
||||
|
@ -347,7 +348,7 @@ DEPENDENCIES
|
|||
request_store
|
||||
rollbar
|
||||
rspec
|
||||
rspec-rails (= 4.0.0.beta3)
|
||||
rspec-rails
|
||||
rspec_junit_formatter
|
||||
scenic
|
||||
secure_headers
|
||||
|
|
|
@ -46,5 +46,6 @@ module Resources
|
|||
Plant => Points,
|
||||
Point => Points,
|
||||
ToolSlot => Points,
|
||||
Weed => Points,
|
||||
}
|
||||
end # Resources
|
||||
|
|
|
@ -16,9 +16,9 @@ module CeleryScriptSettingsBag
|
|||
end
|
||||
|
||||
PIN_TYPE_MAP = { "Peripheral" => Peripheral,
|
||||
"Sensor" => Sensor,
|
||||
"BoxLed3" => BoxLed,
|
||||
"BoxLed4" => BoxLed }
|
||||
"Sensor" => Sensor,
|
||||
"BoxLed3" => BoxLed,
|
||||
"BoxLed4" => BoxLed }
|
||||
ALLOWED_AXIS = %w(x y z all)
|
||||
ALLOWED_ASSERTION_TYPES = %w(abort recover abort_recover continue)
|
||||
ALLOWED_CHANGES = %w(add remove update)
|
||||
|
@ -30,19 +30,19 @@ module CeleryScriptSettingsBag
|
|||
ALLOWED_PACKAGES = %w(farmbot_os arduino_firmware)
|
||||
ALLOWED_PIN_MODES = [DIGITAL = 0, ANALOG = 1]
|
||||
ALLOWED_PIN_TYPES = PIN_TYPE_MAP.keys
|
||||
ALLOWED_POINTER_TYPE = %w(GenericPointer ToolSlot Plant)
|
||||
ALLOWED_RESOURCE_TYPE = %w(Device Point Plant ToolSlot GenericPointer)
|
||||
ALLOWED_POINTER_TYPE = %w(GenericPointer ToolSlot Plant Weed)
|
||||
ALLOWED_RESOURCE_TYPE = %w(Device Point Plant ToolSlot Weed GenericPointer)
|
||||
ALLOWED_RPC_NODES = %w(assertion calibrate change_ownership
|
||||
check_updates dump_info emergency_lock
|
||||
check_updates emergency_lock
|
||||
emergency_unlock execute execute_script
|
||||
factory_reset find_home flash_firmware home
|
||||
install_farmware install_first_party_farmware _if
|
||||
move_absolute move_relative power_off read_pin
|
||||
read_status reboot remove_farmware resource_update
|
||||
read_status reboot remove_farmware update_resource
|
||||
send_message set_servo_angle set_user_env sync
|
||||
take_photo toggle_pin update_farmware wait
|
||||
write_pin zero)
|
||||
ALLOWED_SPEC_ACTION = %w(dump_info emergency_lock emergency_unlock power_off
|
||||
ALLOWED_SPEC_ACTION = %w(emergency_lock emergency_unlock power_off
|
||||
read_status reboot sync take_photo)
|
||||
ANY_VARIABLE = %i(tool coordinate point identifier)
|
||||
BAD_ALLOWED_PIN_MODES = '"%s" is not a valid pin_mode. Allowed values: %s'
|
||||
|
@ -73,8 +73,7 @@ module CeleryScriptSettingsBag
|
|||
ONLY_ONE_COORD = "Move Absolute does not accept a group of locations " \
|
||||
"as input. Please change your selection to a single" \
|
||||
" location."
|
||||
PLANT_STAGES = %w(planned planted harvested sprouted)
|
||||
RESOURCE_UPDATE_ARGS = [:resource_type, :resource_id, :label, :value]
|
||||
PLANT_STAGES = %w(planned planted harvested sprouted removed)
|
||||
SCOPE_DECLARATIONS = [:variable_declaration, :parameter_declaration]
|
||||
MISC_ENUM_ERR = '"%s" is not valid. Allowed values: %s'
|
||||
MAX_WAIT_MS = 1000 * 60 * 3 # Three Minutes
|
||||
|
@ -82,6 +81,13 @@ module CeleryScriptSettingsBag
|
|||
"A single wait node cannot exceed #{MAX_WAIT_MS / 1000 / 60} minutes. " +
|
||||
"Consider lowering the wait time or using multiple WAIT blocks."
|
||||
Corpus = CeleryScript::Corpus.new
|
||||
THIS_IS_DEPRECATED = {
|
||||
args: [:resource_type, :resource_id, :label, :value],
|
||||
tags: [:function, :api_writer, :network_user],
|
||||
blk: ->(n) do
|
||||
n.invalidate!("Deprecated `mark_as` detected. Delete it and re-add")
|
||||
end,
|
||||
}
|
||||
|
||||
CORPUS_VALUES = {
|
||||
boolean: [TrueClass, FalseClass],
|
||||
|
@ -278,6 +284,9 @@ module CeleryScriptSettingsBag
|
|||
lua: {
|
||||
defn: [v(:string)],
|
||||
},
|
||||
resource: {
|
||||
defn: [n(:identifier), n(:resource)],
|
||||
},
|
||||
}.map do |(name, conf)|
|
||||
blk = conf[:blk]
|
||||
defn = conf.fetch(:defn)
|
||||
|
@ -317,10 +326,6 @@ module CeleryScriptSettingsBag
|
|||
args: [:x, :y, :z],
|
||||
tags: [:data, :location_like],
|
||||
},
|
||||
dump_info: {
|
||||
tags: [:function, :network_user, :disk_user, :api_writer],
|
||||
docs: "Sends an info dump to server administrators for troubleshooting.",
|
||||
},
|
||||
emergency_lock: {
|
||||
tags: [:function, :firmware_user, :control_flow],
|
||||
},
|
||||
|
@ -513,15 +518,22 @@ module CeleryScriptSettingsBag
|
|||
tags: [:function, :firmware_user, :rpi_user],
|
||||
blk: ->(n) { no_rpi_analog(n) },
|
||||
},
|
||||
resource_update: {
|
||||
args: RESOURCE_UPDATE_ARGS,
|
||||
tags: [:function, :api_writer, :network_user],
|
||||
# DEPRECATED- Get rid of this node ASAP -RC 15 APR 2020
|
||||
resource_update: THIS_IS_DEPRECATED,
|
||||
resource: {
|
||||
args: [:resource_type, :resource_id],
|
||||
tags: [:network_user],
|
||||
blk: ->(n) do
|
||||
resource_type = n.args.fetch(:resource_type).value
|
||||
resource_id = n.args.fetch(:resource_id).value
|
||||
check_resource_type(n, resource_type, resource_id, Device.current)
|
||||
end,
|
||||
},
|
||||
update_resource: {
|
||||
args: [:resource],
|
||||
body: [:pair],
|
||||
tags: [:function, :api_writer, :network_user],
|
||||
},
|
||||
point_group: {
|
||||
args: [:point_group_id],
|
||||
tags: [:data, :list_like],
|
||||
|
@ -529,7 +541,7 @@ module CeleryScriptSettingsBag
|
|||
resource_id = n.args.fetch(:point_group_id).value
|
||||
check_resource_type(n, "PointGroup", resource_id, Device.current)
|
||||
end,
|
||||
}
|
||||
},
|
||||
}.map { |(name, list)| Corpus.node(name, **list) }
|
||||
|
||||
HASH = Corpus.as_json
|
||||
|
|
|
@ -6,8 +6,9 @@ class InUsePoint < ApplicationRecord
|
|||
DEFAULT_NAME = "point"
|
||||
FANCY_NAMES = {
|
||||
GenericPointer.name => DEFAULT_NAME,
|
||||
ToolSlot.name => "tool slot",
|
||||
ToolSlot.name => "slot",
|
||||
Plant.name => "plant",
|
||||
Weed.name => "weed"
|
||||
}
|
||||
|
||||
def readonly?
|
||||
|
|
|
@ -1,20 +1,18 @@
|
|||
class PinBinding < ApplicationRecord
|
||||
OFF_LIMITS = [
|
||||
2, 3, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 17, 19, 21, 23, 24, 25, 27
|
||||
OFF_LIMITS = [
|
||||
2, 3, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 17, 19, 21, 23, 24, 25, 27,
|
||||
]
|
||||
BAD_PIN_NUM = \
|
||||
"The following pin numbers cannot be used: %s" % OFF_LIMITS.join(", ")
|
||||
BAD_PIN_NUM = "The following pin numbers cannot be used: %s" % OFF_LIMITS.join(", ")
|
||||
|
||||
belongs_to :device
|
||||
belongs_to :sequence
|
||||
enum special_action: { dump_info: "dump_info",
|
||||
emergency_lock: "emergency_lock",
|
||||
enum special_action: { emergency_lock: "emergency_lock",
|
||||
emergency_unlock: "emergency_unlock",
|
||||
power_off: "power_off",
|
||||
read_status: "read_status",
|
||||
reboot: "reboot",
|
||||
sync: "sync",
|
||||
take_photo: "take_photo" }
|
||||
power_off: "power_off",
|
||||
read_status: "read_status",
|
||||
reboot: "reboot",
|
||||
sync: "sync",
|
||||
take_photo: "take_photo" }
|
||||
validates :pin_num, uniqueness: { scope: :device }
|
||||
|
||||
def fancy_name
|
||||
|
|
|
@ -4,7 +4,7 @@ class Point < ApplicationRecord
|
|||
# axis value > 21k right now - RC
|
||||
# Using real constants instead of strings results
|
||||
# in circular dep. errors.
|
||||
POINTER_KINDS = ["GenericPointer", "Plant", "ToolSlot"]
|
||||
POINTER_KINDS = ["GenericPointer", "Plant", "ToolSlot", "Weed"]
|
||||
self.inheritance_column = "pointer_type"
|
||||
|
||||
belongs_to :device
|
||||
|
|
|
@ -4,7 +4,7 @@ class PointGroup < ApplicationRecord
|
|||
BAD_SORT = "%{value} is not valid. Valid options are: " +
|
||||
SORT_TYPES.map(&:inspect).join(", ")
|
||||
DEFAULT_CRITERIA = {
|
||||
day: { op: "<", days: 0 },
|
||||
day: { op: "<", days_ago: 0 },
|
||||
string_eq: {},
|
||||
number_eq: {},
|
||||
number_lt: {},
|
||||
|
|
|
@ -11,7 +11,7 @@ class ToolSlot < Point
|
|||
MIN_PULLOUT = PULLOUT_DIRECTIONS.min
|
||||
PULLOUT_ERR = "must be a value between #{MIN_PULLOUT} and #{MAX_PULLOUT}. "\
|
||||
"%{value} is not valid."
|
||||
IN_USE = "already in use by another tool slot. "\
|
||||
IN_USE = "already in use by another slot. "\
|
||||
"Please un-assign the tool from its current slot"\
|
||||
" before reassigning."
|
||||
|
||||
|
|
|
@ -0,0 +1,2 @@
|
|||
class Weed < Point
|
||||
end
|
|
@ -7,7 +7,9 @@ module Devices
|
|||
"genesis_1.2" => Devices::Seeders::GenesisOneTwo,
|
||||
"genesis_1.3" => Devices::Seeders::GenesisOneThree,
|
||||
"genesis_1.4" => Devices::Seeders::GenesisOneFour,
|
||||
"genesis_1.5" => Devices::Seeders::GenesisOneFive,
|
||||
"genesis_xl_1.4" => Devices::Seeders::GenesisXlOneFour,
|
||||
"genesis_xl_1.5" => Devices::Seeders::GenesisXlOneFive,
|
||||
|
||||
"demo_account" => Devices::Seeders::DemoAccountSeeder,
|
||||
"none" => Devices::Seeders::None,
|
||||
|
|
|
@ -27,7 +27,7 @@ module Devices
|
|||
add_tool_slot(name: ToolNames::SEED_TROUGH_1,
|
||||
x: 0,
|
||||
y: 25,
|
||||
z: -200,
|
||||
z: 0,
|
||||
tool: tools_seed_trough_1,
|
||||
pullout_direction: ToolSlot::NONE,
|
||||
gantry_mounted: true)
|
||||
|
@ -37,25 +37,18 @@ module Devices
|
|||
add_tool_slot(name: ToolNames::SEED_TROUGH_2,
|
||||
x: 0,
|
||||
y: 50,
|
||||
z: -200,
|
||||
z: 0,
|
||||
tool: tools_seed_trough_2,
|
||||
pullout_direction: ToolSlot::NONE,
|
||||
gantry_mounted: true)
|
||||
end
|
||||
|
||||
def tool_slots_slot_3
|
||||
add_tool_slot(name: ToolNames::SEED_TROUGH_3,
|
||||
x: 0,
|
||||
y: 75,
|
||||
z: -200,
|
||||
tool: tools_seed_trough_3,
|
||||
pullout_direction: ToolSlot::NONE,
|
||||
gantry_mounted: true)
|
||||
end
|
||||
|
||||
def tool_slots_slot_3; end
|
||||
def tool_slots_slot_4; end
|
||||
def tool_slots_slot_5; end
|
||||
def tool_slots_slot_6; end
|
||||
def tool_slots_slot_7; end
|
||||
def tool_slots_slot_8; end
|
||||
def tools_seed_bin; end
|
||||
def tools_seed_tray; end
|
||||
|
||||
|
@ -69,11 +62,6 @@ module Devices
|
|||
add_tool(ToolNames::SEED_TROUGH_2)
|
||||
end
|
||||
|
||||
def tools_seed_trough_3
|
||||
@tools_seed_trough_3 ||=
|
||||
add_tool(ToolNames::SEED_TROUGH_3)
|
||||
end
|
||||
|
||||
def tools_seeder; end
|
||||
def tools_soil_sensor; end
|
||||
def tools_watering_nozzle; end
|
||||
|
|
|
@ -75,6 +75,9 @@ module Devices
|
|||
tool: tools_weeder)
|
||||
end
|
||||
|
||||
def tool_slots_slot_7; end
|
||||
def tool_slots_slot_8; end
|
||||
|
||||
def tools_seed_bin
|
||||
@tools_seed_bin ||=
|
||||
add_tool(ToolNames::SEED_BIN)
|
||||
|
@ -87,7 +90,6 @@ module Devices
|
|||
|
||||
def tools_seed_trough_1; end
|
||||
def tools_seed_trough_2; end
|
||||
def tools_seed_trough_3; end
|
||||
|
||||
def tools_seeder
|
||||
@tools_seeder ||=
|
||||
|
|
|
@ -37,7 +37,6 @@ module Devices
|
|||
:tools_seed_tray,
|
||||
:tools_seed_trough_1,
|
||||
:tools_seed_trough_2,
|
||||
:tools_seed_trough_3,
|
||||
:tools_seeder,
|
||||
:tools_soil_sensor,
|
||||
:tools_watering_nozzle,
|
||||
|
@ -50,6 +49,8 @@ module Devices
|
|||
:tool_slots_slot_4,
|
||||
:tool_slots_slot_5,
|
||||
:tool_slots_slot_6,
|
||||
:tool_slots_slot_7,
|
||||
:tool_slots_slot_8,
|
||||
|
||||
# WEBCAM FEEDS ===========================
|
||||
:webcam_feeds,
|
||||
|
@ -152,11 +153,12 @@ module Devices
|
|||
def tool_slots_slot_4; end
|
||||
def tool_slots_slot_5; end
|
||||
def tool_slots_slot_6; end
|
||||
def tool_slots_slot_7; end
|
||||
def tool_slots_slot_8; end
|
||||
def tools_seed_bin; end
|
||||
def tools_seed_tray; end
|
||||
def tools_seed_trough_1; end
|
||||
def tools_seed_trough_2; end
|
||||
def tools_seed_trough_3; end
|
||||
def tools_seeder; end
|
||||
def tools_soil_sensor; end
|
||||
def tools_watering_nozzle; end
|
||||
|
|
|
@ -31,7 +31,6 @@ module Devices
|
|||
LIGHTING = "Lighting"
|
||||
SEED_TROUGH_1 = "Seed Trough 1"
|
||||
SEED_TROUGH_2 = "Seed Trough 2"
|
||||
SEED_TROUGH_3 = "Seed Trough 3"
|
||||
end
|
||||
|
||||
# Stub plants ==============================
|
||||
|
|
|
@ -0,0 +1,41 @@
|
|||
module Devices
|
||||
module Seeders
|
||||
class GenesisOneFive < AbstractGenesis
|
||||
def settings_firmware
|
||||
device
|
||||
.fbos_config
|
||||
.update!(firmware_hardware: FbosConfig::FARMDUINO_K15)
|
||||
end
|
||||
|
||||
def tool_slots_slot_7
|
||||
add_tool_slot(name: ToolNames::SEED_TROUGH_1,
|
||||
x: 0,
|
||||
y: 25,
|
||||
z: 0,
|
||||
tool: tools_seed_trough_1,
|
||||
pullout_direction: ToolSlot::NONE,
|
||||
gantry_mounted: true)
|
||||
end
|
||||
|
||||
def tool_slots_slot_8
|
||||
add_tool_slot(name: ToolNames::SEED_TROUGH_2,
|
||||
x: 0,
|
||||
y: 50,
|
||||
z: 0,
|
||||
tool: tools_seed_trough_2,
|
||||
pullout_direction: ToolSlot::NONE,
|
||||
gantry_mounted: true)
|
||||
end
|
||||
|
||||
def tools_seed_trough_1
|
||||
@tools_seed_trough_1 ||=
|
||||
add_tool(ToolNames::SEED_TROUGH_1)
|
||||
end
|
||||
|
||||
def tools_seed_trough_2
|
||||
@tools_seed_trough_2 ||=
|
||||
add_tool(ToolNames::SEED_TROUGH_2)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,53 @@
|
|||
module Devices
|
||||
module Seeders
|
||||
class GenesisXlOneFive < AbstractGenesis
|
||||
def settings_firmware
|
||||
device
|
||||
.fbos_config
|
||||
.update!(firmware_hardware: FbosConfig::FARMDUINO_K15)
|
||||
end
|
||||
|
||||
def settings_device_name
|
||||
device.update!(name: "FarmBot Genesis XL")
|
||||
end
|
||||
|
||||
def settings_default_map_size_x
|
||||
device.web_app_config.update!(map_size_x: 5_900)
|
||||
end
|
||||
|
||||
def settings_default_map_size_y
|
||||
device.web_app_config.update!(map_size_y: 2_900)
|
||||
end
|
||||
|
||||
def tool_slots_slot_7
|
||||
add_tool_slot(name: ToolNames::SEED_TROUGH_1,
|
||||
x: 0,
|
||||
y: 25,
|
||||
z: 0,
|
||||
tool: tools_seed_trough_1,
|
||||
pullout_direction: ToolSlot::NONE,
|
||||
gantry_mounted: true)
|
||||
end
|
||||
|
||||
def tool_slots_slot_8
|
||||
add_tool_slot(name: ToolNames::SEED_TROUGH_2,
|
||||
x: 0,
|
||||
y: 50,
|
||||
z: 0,
|
||||
tool: tools_seed_trough_2,
|
||||
pullout_direction: ToolSlot::NONE,
|
||||
gantry_mounted: true)
|
||||
end
|
||||
|
||||
def tools_seed_trough_1
|
||||
@tools_seed_trough_1 ||=
|
||||
add_tool(ToolNames::SEED_TROUGH_1)
|
||||
end
|
||||
|
||||
def tools_seed_trough_2
|
||||
@tools_seed_trough_2 ||=
|
||||
add_tool(ToolNames::SEED_TROUGH_2)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -28,11 +28,12 @@ module Devices
|
|||
def tool_slots_slot_4; end
|
||||
def tool_slots_slot_5; end
|
||||
def tool_slots_slot_6; end
|
||||
def tool_slots_slot_7; end
|
||||
def tool_slots_slot_8; end
|
||||
def tools_seed_bin; end
|
||||
def tools_seed_tray; end
|
||||
def tools_seed_trough_1; end
|
||||
def tools_seed_trough_2; end
|
||||
def tools_seed_trough_3; end
|
||||
def tools_seeder; end
|
||||
def tools_soil_sensor; end
|
||||
def tools_watering_nozzle; end
|
||||
|
|
|
@ -5,7 +5,7 @@ module PointGroups
|
|||
hash :criteria do
|
||||
hash(:day) do
|
||||
string :op, in: [">", "<"]
|
||||
integer :days
|
||||
integer :days_ago
|
||||
end
|
||||
hash(:string_eq) { array :*, class: String }
|
||||
hash(:number_eq) { array :*, class: Integer }
|
||||
|
|
|
@ -27,11 +27,19 @@ module Points
|
|||
end
|
||||
|
||||
def execute
|
||||
Point.transaction { point.update!(inputs.except(:point)) && point }
|
||||
Point.transaction { point.update!(update_params) && point }
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def merged_meta_fields
|
||||
@merged_meta_fields ||= (point.meta || {}).merge(meta || {})
|
||||
end
|
||||
|
||||
def update_params
|
||||
@update_params ||= inputs.except(:point).merge(meta: merged_meta_fields)
|
||||
end
|
||||
|
||||
def new_tool_id?
|
||||
raw_inputs.key?("tool_id")
|
||||
end
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
module Tools
|
||||
class Destroy < Mutations::Command
|
||||
STILL_IN_USE = "Can't delete tool because the following sequences are "\
|
||||
"still using it: %s"
|
||||
STILL_IN_SLOT = "Can't delete tool because it is still in a tool slot. "\
|
||||
"Please remove it from the tool slot first."
|
||||
STILL_IN_USE = "Can't delete tool or seed container because the " \
|
||||
"following sequences are still using it: %s"
|
||||
STILL_IN_SLOT = "Can't delete tool or seed container because it is " \
|
||||
"still in a slot. Please remove it from the slot first."
|
||||
|
||||
required do
|
||||
model :tool, class: Tool
|
||||
|
@ -15,10 +15,11 @@ module Tools
|
|||
end
|
||||
|
||||
def execute
|
||||
maybe_unmount_tool
|
||||
tool.destroy!
|
||||
end
|
||||
|
||||
private
|
||||
private
|
||||
|
||||
def slot
|
||||
@slot ||= tool.tool_slot
|
||||
|
@ -33,8 +34,14 @@ private
|
|||
end
|
||||
|
||||
def names
|
||||
@names ||= \
|
||||
@names ||=
|
||||
InUseTool.where(tool_id: tool.id).pluck(:sequence_name).join(", ")
|
||||
end
|
||||
|
||||
def maybe_unmount_tool
|
||||
if tool.device.mounted_tool_id == tool.id
|
||||
tool.device.update!(mounted_tool_id: nil)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -1,6 +1,24 @@
|
|||
class BasePointSerializer < ApplicationSerializer
|
||||
attributes :device_id, :name, :pointer_type, :meta, :x, :y, :z
|
||||
|
||||
# PROBLEM:
|
||||
# * Users need a mutable way to mark a plant's creation time => `planted_at`
|
||||
# * DB Admin needs to know the _real_ created_at time.
|
||||
# * We can't change field names (or destroy data) that is in use by legacy devices
|
||||
#
|
||||
# SOLUTION:
|
||||
# * Don't allow users to modify `created_at`
|
||||
# * Provide `planted_at` if possible.
|
||||
# * Always provide `planted_at` if it is available
|
||||
# * Provide a read-only view of `created_at` if `planted_at` is `nil`
|
||||
def planted_at
|
||||
object.planted_at || object.created_at
|
||||
end
|
||||
|
||||
def created_at
|
||||
planted_at
|
||||
end
|
||||
|
||||
def meta
|
||||
object.meta || {}
|
||||
end
|
||||
|
|
|
@ -0,0 +1,3 @@
|
|||
class WeedSerializer < BasePointSerializer
|
||||
attributes :radius, :discarded_at, :plant_stage
|
||||
end
|
|
@ -1,5 +1,4 @@
|
|||
class MakeDefaulDeviceNameFarmbot < ActiveRecord::Migration[5.1]
|
||||
|
||||
def change
|
||||
change_column_default(:devices, :name, "Farmbot")
|
||||
end
|
||||
|
|
|
@ -0,0 +1,8 @@
|
|||
class AddShowWeedsToWebAppConfig < ActiveRecord::Migration[6.0]
|
||||
def change
|
||||
add_column :web_app_configs,
|
||||
:show_weeds,
|
||||
:boolean,
|
||||
default: false
|
||||
end
|
||||
end
|
|
@ -0,0 +1,5 @@
|
|||
class UpdateMaxImageCount < ActiveRecord::Migration[6.0]
|
||||
def change
|
||||
change_column_default(:devices, :max_images_count, 450)
|
||||
end
|
||||
end
|
|
@ -150,8 +150,8 @@ ALTER SEQUENCE public.alerts_id_seq OWNED BY public.alerts.id;
|
|||
CREATE TABLE public.ar_internal_metadata (
|
||||
key character varying NOT NULL,
|
||||
value character varying,
|
||||
created_at timestamp without time zone NOT NULL,
|
||||
updated_at timestamp without time zone NOT NULL
|
||||
created_at timestamp(6) without time zone NOT NULL,
|
||||
updated_at timestamp(6) without time zone NOT NULL
|
||||
);
|
||||
|
||||
|
||||
|
@ -262,7 +262,7 @@ CREATE TABLE public.devices (
|
|||
id integer NOT NULL,
|
||||
name character varying DEFAULT 'FarmBot'::character varying,
|
||||
max_log_count integer DEFAULT 1000,
|
||||
max_images_count integer DEFAULT 100,
|
||||
max_images_count integer DEFAULT 450,
|
||||
timezone character varying(280),
|
||||
last_saw_api timestamp without time zone,
|
||||
last_saw_mq timestamp without time zone,
|
||||
|
@ -1364,7 +1364,7 @@ CREATE VIEW public.resource_update_steps AS
|
|||
edge_nodes.kind,
|
||||
edge_nodes.value
|
||||
FROM public.edge_nodes
|
||||
WHERE (((edge_nodes.kind)::text = 'resource_type'::text) AND ((edge_nodes.value)::text = ANY (ARRAY[('"GenericPointer"'::character varying)::text, ('"ToolSlot"'::character varying)::text, ('"Plant"'::character varying)::text])))
|
||||
WHERE (((edge_nodes.kind)::text = 'resource_type'::text) AND ((edge_nodes.value)::text = ANY ((ARRAY['"GenericPointer"'::character varying, '"ToolSlot"'::character varying, '"Plant"'::character varying])::text[])))
|
||||
), resource_id AS (
|
||||
SELECT edge_nodes.primary_node_id,
|
||||
edge_nodes.kind,
|
||||
|
@ -1644,8 +1644,7 @@ CREATE TABLE public.users (
|
|||
agreed_to_terms_at timestamp without time zone,
|
||||
confirmation_sent_at timestamp without time zone,
|
||||
unconfirmed_email character varying,
|
||||
inactivity_warning_sent_at timestamp without time zone,
|
||||
inactivity_warning_count integer
|
||||
inactivity_warning_sent_at timestamp without time zone
|
||||
);
|
||||
|
||||
|
||||
|
@ -1729,7 +1728,9 @@ CREATE TABLE public.web_app_configs (
|
|||
confirm_sequence_deletion boolean DEFAULT true,
|
||||
discard_unsaved_sequences boolean DEFAULT false,
|
||||
user_interface_read_only_mode boolean DEFAULT false,
|
||||
assertion_log integer DEFAULT 1
|
||||
assertion_log integer DEFAULT 1,
|
||||
show_zones boolean DEFAULT false,
|
||||
show_weeds boolean DEFAULT false
|
||||
);
|
||||
|
||||
|
||||
|
@ -3376,6 +3377,9 @@ INSERT INTO "schema_migrations" (version) VALUES
|
|||
('20191219212755'),
|
||||
('20191220010646'),
|
||||
('20200116140201'),
|
||||
('20200204192005');
|
||||
('20200204192005'),
|
||||
('20200204230135'),
|
||||
('20200323235926'),
|
||||
('20200412152208');
|
||||
|
||||
|
||||
|
|
|
@ -0,0 +1,90 @@
|
|||
# How to install FarmBot Web API on a Debian Buster (10) Machine
|
||||
|
||||
# IMPORTANT NOTE: Resources are limited and Farmbot, inc. cannot provide
|
||||
# longterm support to self-hosted users. If you have never administered a
|
||||
# Ruby on Rails application, we highly advise stopping now. this presents an
|
||||
# extremely high risk of data loss. Free hosting is provided at
|
||||
# https://my.farm.bot and eliminates the risks and troubles of self-hosting.
|
||||
#
|
||||
# You are highly encouraged to use the my.farm.bot servers. Self hosted
|
||||
# documentation is provided with the assumption that you have experience with
|
||||
# Ruby/Javascript development.
|
||||
#
|
||||
# Self-hosting a Farmbot server is not a simple task.
|
||||
|
||||
# Remove old (possibly broke) docker versions
|
||||
sudo apt-get remove docker docker-engine docker.io
|
||||
|
||||
# Install docker
|
||||
sudo apt-get install apt-transport-https ca-certificates curl software-properties-common gnupg2 --yes
|
||||
curl -fsSL https://download.docker.com/linux/debian/gpg | sudo apt-key add -
|
||||
sudo add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/debian buster stable" --yes
|
||||
sudo apt-get update --yes
|
||||
sudo apt-get install docker-ce --yes
|
||||
sudo docker run hello-world # Should run!
|
||||
# Install docker-compose
|
||||
sudo curl -L "https://github.com/docker/compose/releases/download/1.22.0/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
|
||||
sudo chmod +x /usr/local/bin/docker-compose
|
||||
|
||||
# Install FarmBot Web App
|
||||
# âš SKIP THIS STEP IF UPGRADING!
|
||||
git clone https://github.com/FarmBot/Farmbot-Web-App --depth=5 --branch=master
|
||||
|
||||
cd Farmbot-Web-App
|
||||
|
||||
#snap install micro --classic # Don't like `micro`? vim, nano, etc are fine, too.
|
||||
cp example.env .env # âš SKIP THIS STEP IF UPGRADING!
|
||||
|
||||
# == This is a very important step!!! ==
|
||||
#
|
||||
# Open `.env` in a text editor and change all the values.
|
||||
#
|
||||
# == Nothing will work if you skip this step!!! ==
|
||||
|
||||
vim .env # âš SKIP THIS STEP IF UPGRADING!
|
||||
# ^ This is the most important step
|
||||
# READ NOTE ABOVE. Very important!
|
||||
|
||||
# Install the correct version of bundler for the project
|
||||
sudo docker-compose run web gem install bundler:2.1.4
|
||||
# Install application specific Ruby dependencies
|
||||
sudo docker-compose run web bundle install
|
||||
# Install application specific Javascript deps
|
||||
sudo docker-compose run web npm install
|
||||
# Create a database in PostgreSQL
|
||||
sudo docker-compose run web bundle exec rails db:create db:migrate
|
||||
# Generate a set of *.pem files for data encryption
|
||||
sudo docker-compose run web rake keys:generate # âš SKIP THIS STEP IF UPGRADING!
|
||||
# Build the UI assets via ParcelJS
|
||||
sudo docker-compose run web rake assets:precompile
|
||||
# Run the server! ٩(^‿^)۶
|
||||
# NOTE: DONT TRY TO LOGIN until you see a message similar to this:
|
||||
# "✨ Built in 44.92s"
|
||||
# THIS MAY TAKE A VERY LONG TIME ON SLOW MACHINES (~3 minutes on DigitalOcean)
|
||||
# You will just get an empty screen otherwise.
|
||||
# This only happens during initialization
|
||||
sudo docker-compose up
|
||||
|
||||
# At this point, setup is complete. Content should be visible at ===============
|
||||
# http://YOUR_HOST:3000/.
|
||||
|
||||
# You can optionally verify installation by running unit tests.
|
||||
|
||||
# Create the database for the app to use:
|
||||
sudo docker-compose run -e RAILS_ENV=test web bundle exec rails db:setup
|
||||
# Run the tests in the "test" RAILS_ENV:
|
||||
sudo docker-compose run -e RAILS_ENV=test web rspec spec
|
||||
# Run user-interface unit tests REQUIRES AT LEAST 4 GB OF RAM:
|
||||
sudo docker-compose run web npm run test
|
||||
|
||||
# === BEGIN OPTIONAL UPGRADES
|
||||
# To update to later versions of FarmBot,
|
||||
# shut down the server, create a database backup
|
||||
# and run commands below.
|
||||
git pull https://github.com/FarmBot/Farmbot-Web-App.git master
|
||||
sudo docker-compose build
|
||||
sudo docker-compose run web bundle install # <== âš UPGRADE USERS ONLY
|
||||
sudo docker-compose run web npm install # <== âš UPGRADE USERS ONLY
|
||||
sudo docker-compose run web rails db:migrate # <== âš UPGRADE USERS ONLY
|
||||
# === END OPTIONAL UPGRADES ^
|
||||
|
|
@ -4,9 +4,15 @@ export const panelState = (): ControlPanelState => {
|
|||
return {
|
||||
homing_and_calibration: false,
|
||||
motors: false,
|
||||
encoders_and_endstops: false,
|
||||
encoders: false,
|
||||
endstops: false,
|
||||
error_handling: false,
|
||||
pin_bindings: false,
|
||||
danger_zone: false,
|
||||
power_and_reset: false,
|
||||
pin_guard: false
|
||||
pin_guard: false,
|
||||
farm_designer: false,
|
||||
firmware: false,
|
||||
farmbot_os: false,
|
||||
};
|
||||
};
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
import { DesignerState } from "../farm_designer/interfaces";
|
||||
|
||||
export const fakeDesignerState = (): DesignerState => ({
|
||||
selectedPlants: undefined,
|
||||
selectedPoints: undefined,
|
||||
selectionPointType: undefined,
|
||||
hoveredPlant: {
|
||||
plantUUID: undefined,
|
||||
icon: ""
|
||||
|
@ -13,7 +14,10 @@ export const fakeDesignerState = (): DesignerState => ({
|
|||
cropSearchResults: [],
|
||||
cropSearchInProgress: false,
|
||||
chosenLocation: { x: undefined, y: undefined, z: undefined },
|
||||
currentPoint: undefined,
|
||||
drawnPoint: undefined,
|
||||
drawnWeed: undefined,
|
||||
openedSavedGarden: undefined,
|
||||
tryGroupSortType: undefined,
|
||||
editGroupAreaInMap: false,
|
||||
settingsSearchTerm: "",
|
||||
});
|
||||
|
|
|
@ -0,0 +1,2 @@
|
|||
export const mockDispatch = (innerDispatch = jest.fn()) =>
|
||||
jest.fn(x => typeof x === "function" && x(innerDispatch));
|
|
@ -1,16 +1,10 @@
|
|||
import { Everything } from "../../interfaces";
|
||||
import { panelState } from "../control_panel_state";
|
||||
|
||||
export const bot: Everything["bot"] = {
|
||||
"consistent": true,
|
||||
"stepSize": 100,
|
||||
"controlPanelState": {
|
||||
"homing_and_calibration": false,
|
||||
"motors": false,
|
||||
"encoders_and_endstops": false,
|
||||
"danger_zone": false,
|
||||
"power_and_reset": false,
|
||||
"pin_guard": false,
|
||||
},
|
||||
"controlPanelState": panelState(),
|
||||
"hardware": {
|
||||
"gpio_registry": {},
|
||||
"mcu_params": {
|
||||
|
|
|
@ -54,5 +54,5 @@ export const fakeImages: TaggedImage[] = [
|
|||
}
|
||||
},
|
||||
"uuid": "Image.7.5"
|
||||
}
|
||||
},
|
||||
];
|
||||
|
|
|
@ -26,10 +26,11 @@ import {
|
|||
TaggedAlert,
|
||||
TaggedPointGroup,
|
||||
TaggedFolder,
|
||||
TaggedWeedPointer,
|
||||
} from "farmbot";
|
||||
import { fakeResource } from "../fake_resource";
|
||||
import {
|
||||
ExecutableType, PinBindingType, Folder
|
||||
ExecutableType, PinBindingType, Folder,
|
||||
} from "farmbot/dist/resources/api_resources";
|
||||
import { FirmwareConfig } from "farmbot/dist/resources/configs/firmware";
|
||||
import { MessageType } from "../../sequences/interfaces";
|
||||
|
@ -133,7 +134,6 @@ export function fakeToolSlot(): TaggedToolSlotPointer {
|
|||
x: 0,
|
||||
y: 0,
|
||||
z: 0,
|
||||
radius: 25,
|
||||
pointer_type: "ToolSlot",
|
||||
meta: {},
|
||||
tool_id: undefined,
|
||||
|
@ -171,6 +171,20 @@ export function fakePoint(): TaggedGenericPointer {
|
|||
});
|
||||
}
|
||||
|
||||
export function fakeWeed(): TaggedWeedPointer {
|
||||
return fakeResource("Point", {
|
||||
id: idCounter++,
|
||||
name: "Weed 1",
|
||||
pointer_type: "Weed",
|
||||
x: 200,
|
||||
y: 400,
|
||||
z: 0,
|
||||
radius: 100,
|
||||
plant_stage: "planned",
|
||||
meta: { created_by: "plant-detection", color: "red" }
|
||||
});
|
||||
}
|
||||
|
||||
export function fakeSavedGarden(): TaggedSavedGarden {
|
||||
return fakeResource("SavedGarden", {
|
||||
id: idCounter++,
|
||||
|
@ -289,6 +303,7 @@ export function fakeWebAppConfig(): TaggedWebAppConfig {
|
|||
show_sensor_readings: false,
|
||||
show_plants: true,
|
||||
show_points: true,
|
||||
show_weeds: true,
|
||||
x_axis_inverted: false,
|
||||
y_axis_inverted: false,
|
||||
z_axis_inverted: true,
|
||||
|
@ -460,7 +475,7 @@ export function fakePointGroup(): TaggedPointGroup {
|
|||
sort_type: "xy_ascending",
|
||||
point_ids: [],
|
||||
criteria: {
|
||||
day: { op: "<", days: 0 },
|
||||
day: { op: "<", days_ago: 0 },
|
||||
number_eq: {},
|
||||
number_gt: {},
|
||||
number_lt: {},
|
||||
|
|
|
@ -2,7 +2,7 @@ import { Coordinate } from "farmbot";
|
|||
import { VariableNameSet } from "../resources/interfaces";
|
||||
|
||||
export const fakeVariableNameSet = (
|
||||
label = "parent", vector = { x: 0, y: 0, z: 0 }
|
||||
label = "parent", vector = { x: 0, y: 0, z: 0 },
|
||||
): VariableNameSet => {
|
||||
const data_value: Coordinate = {
|
||||
kind: "coordinate", args: vector
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import moment from "moment";
|
||||
import {
|
||||
FarmEventWithExecutable
|
||||
FarmEventWithExecutable,
|
||||
} from "../farm_designer/farm_events/calendar/interfaces";
|
||||
|
||||
export const TIME = {
|
||||
|
@ -24,7 +24,7 @@ export const fakeFarmEventWithExecutable = (): FarmEventWithExecutable => {
|
|||
color: "red",
|
||||
name: "faker",
|
||||
kind: "sequence",
|
||||
args: { version: 0, locals: { kind: "scope_declaration", args: {} }, }
|
||||
args: { version: 0, locals: { kind: "scope_declaration", args: {} } }
|
||||
}
|
||||
};
|
||||
};
|
||||
|
@ -84,7 +84,7 @@ export const calendarRows = [
|
|||
"subheading": "25",
|
||||
"id": 79,
|
||||
"childExecutableName": "Goto 0, 0, 0 123"
|
||||
}
|
||||
},
|
||||
]
|
||||
},
|
||||
{
|
||||
|
@ -171,7 +171,7 @@ export const calendarRows = [
|
|||
"subheading": "25",
|
||||
"id": 79,
|
||||
"childExecutableName": "Goto 0, 0, 0 123"
|
||||
}
|
||||
},
|
||||
]
|
||||
},
|
||||
{
|
||||
|
@ -258,7 +258,7 @@ export const calendarRows = [
|
|||
"subheading": "25",
|
||||
"id": 79,
|
||||
"childExecutableName": "Goto 0, 0, 0 123"
|
||||
}
|
||||
},
|
||||
]
|
||||
}
|
||||
},
|
||||
];
|
||||
|
|
|
@ -7,4 +7,5 @@ jest.mock("../toast/toast", () => ({
|
|||
error: jest.fn(),
|
||||
warning: jest.fn(),
|
||||
busy: jest.fn(),
|
||||
removeToast: jest.fn(),
|
||||
}));
|
||||
|
|
|
@ -62,7 +62,7 @@ const tr0: TaggedResource = {
|
|||
},
|
||||
"speed": 100
|
||||
}
|
||||
}
|
||||
},
|
||||
],
|
||||
"args": {
|
||||
"version": 4,
|
||||
|
@ -265,7 +265,6 @@ const tr11: TaggedPoint = {
|
|||
"pointer_type": "ToolSlot",
|
||||
"pullout_direction": 0,
|
||||
"gantry_mounted": false,
|
||||
"radius": 25,
|
||||
"x": 10,
|
||||
"y": 10,
|
||||
"z": 10,
|
||||
|
@ -287,7 +286,7 @@ const tr12: TaggedResource = {
|
|||
"regimen_id": 11,
|
||||
"sequence_id": 23,
|
||||
"time_offset": 345900000
|
||||
}
|
||||
},
|
||||
],
|
||||
body: [],
|
||||
},
|
||||
|
@ -316,6 +315,28 @@ const tr15: TaggedResource = {
|
|||
"uuid": "Tool.15.50"
|
||||
};
|
||||
|
||||
const tr16: TaggedPoint = {
|
||||
specialStatus: SpecialStatus.SAVED,
|
||||
kind: "Point",
|
||||
body: {
|
||||
id: 1395,
|
||||
created_at: "2017-05-24T20:41:19.889Z",
|
||||
updated_at: "2017-05-24T20:41:19.889Z",
|
||||
meta: {
|
||||
color: "gray",
|
||||
created_by: "plant-detection"
|
||||
},
|
||||
name: "untitled",
|
||||
pointer_type: "Weed",
|
||||
plant_stage: "planned",
|
||||
radius: 10,
|
||||
x: 490,
|
||||
y: 421,
|
||||
z: 5
|
||||
},
|
||||
uuid: "Point.1397.11"
|
||||
};
|
||||
|
||||
const log: TaggedLog = {
|
||||
kind: "Log",
|
||||
specialStatus: SpecialStatus.SAVED,
|
||||
|
@ -345,7 +366,8 @@ export const FAKE_RESOURCES: TaggedResource[] = [
|
|||
tr0,
|
||||
tr14,
|
||||
tr15,
|
||||
log
|
||||
tr16,
|
||||
log,
|
||||
];
|
||||
const KIND: keyof TaggedResource = "kind"; // Safety first, kids.
|
||||
type ResourceGroupNumber = 0 | 1 | 2 | 3 | 4;
|
||||
|
|
|
@ -9,11 +9,11 @@ import { RawApp as App, AppProps, mapStateToProps } from "../app";
|
|||
import { mount } from "enzyme";
|
||||
import { bot } from "../__test_support__/fake_state/bot";
|
||||
import {
|
||||
fakeUser, fakeWebAppConfig, fakeFbosConfig, fakeFarmwareEnv
|
||||
fakeUser, fakeWebAppConfig, fakeFbosConfig, fakeFarmwareEnv,
|
||||
} from "../__test_support__/fake_state/resources";
|
||||
import { fakeState } from "../__test_support__/fake_state";
|
||||
import {
|
||||
buildResourceIndex
|
||||
buildResourceIndex,
|
||||
} from "../__test_support__/resource_index_builder";
|
||||
import { ResourceName } from "farmbot";
|
||||
import { fakeTimeSettings } from "../__test_support__/fake_time_settings";
|
||||
|
@ -125,7 +125,7 @@ describe("<App />: NavBar", () => {
|
|||
"Device",
|
||||
"Sequences",
|
||||
"Regimens",
|
||||
"Farmware"
|
||||
"Farmware",
|
||||
];
|
||||
strings.map(string => expect(t).toContain(string));
|
||||
wrapper.unmount();
|
||||
|
@ -157,7 +157,6 @@ describe("mapStateToProps()", () => {
|
|||
const state = fakeState();
|
||||
const config = fakeFbosConfig();
|
||||
config.body.auto_sync = true;
|
||||
config.body.api_migrated = true;
|
||||
const fakeEnv = fakeFarmwareEnv();
|
||||
state.resources = buildResourceIndex([config, fakeEnv]);
|
||||
state.bot.minOsFeatureData = { api_farmware_env: "8.0.0" };
|
||||
|
|
|
@ -1,17 +1,16 @@
|
|||
jest.mock("../util", () => {
|
||||
return {
|
||||
attachToRoot: jest.fn(),
|
||||
// Incidental mock. Can be removed if errors go away.
|
||||
trim: jest.fn(x => x)
|
||||
};
|
||||
});
|
||||
jest.mock("../util", () => ({
|
||||
attachToRoot: jest.fn(),
|
||||
// Incidental mock. Can be removed if errors go away.
|
||||
trim: jest.fn(x => x),
|
||||
urlFriendly: jest.fn(),
|
||||
}));
|
||||
|
||||
jest.mock("../redux/store", () => {
|
||||
return { store: { dispatch: jest.fn() } };
|
||||
});
|
||||
|
||||
jest.mock("../account/dev/dev_support", () => ({
|
||||
DevSettings: { futureFeaturesEnabled: () => false, }
|
||||
DevSettings: { futureFeaturesEnabled: () => false }
|
||||
}));
|
||||
|
||||
jest.mock("../config/actions", () => {
|
||||
|
|
|
@ -0,0 +1,33 @@
|
|||
jest.unmock("../external_urls");
|
||||
import { ExternalUrl } from "../external_urls";
|
||||
|
||||
/* tslint:disable:max-line-length */
|
||||
|
||||
describe("ExternalUrl", () => {
|
||||
it("returns urls", () => {
|
||||
expect(ExternalUrl.featureMinVersions)
|
||||
.toEqual("https://raw.githubusercontent.com/FarmBot/farmbot_os/staging/FEATURE_MIN_VERSIONS.json");
|
||||
expect(ExternalUrl.osReleaseNotes)
|
||||
.toEqual("https://raw.githubusercontent.com/FarmBot/farmbot_os/staging/RELEASE_NOTES.md");
|
||||
expect(ExternalUrl.latestRelease)
|
||||
.toEqual("https://api.github.com/repos/FarmBot/farmbot_os/releases/latest");
|
||||
expect(ExternalUrl.webAppRepo)
|
||||
.toEqual("https://github.com/FarmBot/Farmbot-Web-App");
|
||||
expect(ExternalUrl.gitHubFarmBot)
|
||||
.toEqual("https://github.com/FarmBot");
|
||||
expect(ExternalUrl.softwareDocs)
|
||||
.toEqual("https://software.farm.bot/docs");
|
||||
expect(ExternalUrl.softwareForum)
|
||||
.toEqual("https://forum.farmbot.org/c/software");
|
||||
expect(ExternalUrl.OpenFarm.cropApi)
|
||||
.toEqual("https://openfarm.cc/api/v1/crops/");
|
||||
expect(ExternalUrl.OpenFarm.cropBrowse)
|
||||
.toEqual("https://openfarm.cc/crops/");
|
||||
expect(ExternalUrl.OpenFarm.newCrop)
|
||||
.toEqual("https://openfarm.cc/en/crops/new");
|
||||
expect(ExternalUrl.Video.desktop)
|
||||
.toEqual("https://cdn.shopify.com/s/files/1/2040/0289/files/Farm_Designer_Loop.mp4?9552037556691879018");
|
||||
expect(ExternalUrl.Video.mobile)
|
||||
.toEqual("https://cdn.shopify.com/s/files/1/2040/0289/files/Controls.png?9668345515035078097");
|
||||
});
|
||||
});
|
|
@ -19,7 +19,7 @@ jest.mock("../session", () => ({
|
|||
}));
|
||||
|
||||
import {
|
||||
responseFulfilled, isLocalRequest, requestFulfilled, responseRejected
|
||||
responseFulfilled, isLocalRequest, requestFulfilled, responseRejected,
|
||||
} from "../interceptors";
|
||||
import { AxiosResponse, Method } from "axios";
|
||||
import { uuid } from "farmbot";
|
||||
|
|
|
@ -30,7 +30,6 @@ import "../regimens/editor/interfaces";
|
|||
import "../regimens/interfaces";
|
||||
import "../resources/interfaces";
|
||||
import "../sequences/interfaces";
|
||||
import "../tools/interfaces";
|
||||
|
||||
describe("interfaces", () => {
|
||||
it("cant explain why coverage is 0 for interface files", () => {
|
||||
|
|
|
@ -9,7 +9,7 @@ jest.mock("axios", () => ({
|
|||
|
||||
}));
|
||||
|
||||
jest.mock("../session", () => ({ Session: { clear: jest.fn(), } }));
|
||||
jest.mock("../session", () => ({ Session: { clear: jest.fn() } }));
|
||||
|
||||
import { maybeRefreshToken } from "../refresh_token";
|
||||
import { API } from "../api/index";
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import {
|
||||
buildResourceIndex,
|
||||
FAKE_RESOURCES
|
||||
FAKE_RESOURCES,
|
||||
} from "../__test_support__/resource_index_builder";
|
||||
import { TaggedFarmEvent, SpecialStatus } from "farmbot";
|
||||
|
||||
|
|
|
@ -12,7 +12,7 @@ type Info = UnboundRouteConfig<{}, {}>;
|
|||
const fakeCallback = (
|
||||
component: ConnectedComponent,
|
||||
child: ConnectedComponent | undefined,
|
||||
info: Info
|
||||
info: Info,
|
||||
) => {
|
||||
if (info.$ == "*") {
|
||||
expect(component.name).toEqual("FourOhFour");
|
||||
|
|
|
@ -11,7 +11,7 @@ jest.mock("axios", () => ({
|
|||
import { API } from "../../api";
|
||||
import { Content } from "../../constants";
|
||||
import {
|
||||
requestAccountExport, generateFilename
|
||||
requestAccountExport, generateFilename,
|
||||
} from "../request_account_export";
|
||||
import { success } from "../../toast/toast";
|
||||
import axios from "axios";
|
||||
|
|
|
@ -3,7 +3,7 @@ import {
|
|||
Widget,
|
||||
WidgetHeader,
|
||||
WidgetBody,
|
||||
SaveBtn
|
||||
SaveBtn,
|
||||
} from "../../ui/index";
|
||||
import { SpecialStatus } from "farmbot";
|
||||
import Axios from "axios";
|
||||
|
|
|
@ -20,7 +20,7 @@ export class DangerousDeleteWidget extends
|
|||
return <Widget>
|
||||
<WidgetHeader title={this.props.title} />
|
||||
<WidgetBody>
|
||||
<div>
|
||||
<div className={"dangerous-delete-warning-messages"}>
|
||||
{t(this.props.warning)}
|
||||
<br /><br />
|
||||
{t(this.props.confirmation)}
|
||||
|
@ -42,6 +42,7 @@ export class DangerousDeleteWidget extends
|
|||
<button
|
||||
onClick={this.onClick}
|
||||
className="red fb-button"
|
||||
title={t(this.props.title)}
|
||||
type="button">
|
||||
{t(this.props.title)}
|
||||
</button>
|
||||
|
|
|
@ -7,7 +7,7 @@ export function ExportAccountPanel(props: { onClick: () => void }) {
|
|||
return <Widget>
|
||||
<WidgetHeader title={t("Export Account Data")} />
|
||||
<WidgetBody>
|
||||
<div>
|
||||
<div className={"export-account-data-description"}>
|
||||
{t(Content.EXPORT_DATA_DESC)}
|
||||
</div>
|
||||
<form>
|
||||
|
@ -19,6 +19,7 @@ export function ExportAccountPanel(props: { onClick: () => void }) {
|
|||
</Col>
|
||||
<Col xs={4}>
|
||||
<button className="green fb-button" type="button"
|
||||
title={t("Export")}
|
||||
onClick={props.onClick}>
|
||||
{t("Export")}
|
||||
</button>
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import * as React from "react";
|
||||
import {
|
||||
BlurableInput, Widget, WidgetHeader, WidgetBody, SaveBtn
|
||||
BlurableInput, Widget, WidgetHeader, WidgetBody, SaveBtn,
|
||||
} from "../../ui/index";
|
||||
import { SettingsPropTypes } from "../interfaces";
|
||||
import { t } from "../../i18next_wrapper";
|
||||
|
|
|
@ -8,7 +8,7 @@ import { DevMode } from "../dev_mode";
|
|||
import * as React from "react";
|
||||
import { range } from "lodash";
|
||||
import {
|
||||
setWebAppConfigValue
|
||||
setWebAppConfigValue,
|
||||
} from "../../../config_storage/actions";
|
||||
import { warning } from "../../../toast/toast";
|
||||
|
||||
|
|
|
@ -7,7 +7,7 @@ jest.mock("../../../config_storage/actions", () => ({
|
|||
import * as React from "react";
|
||||
import { mount, shallow } from "enzyme";
|
||||
import {
|
||||
DevWidget, DevWidgetFERow, DevWidgetFBOSRow, DevWidgetDelModeRow
|
||||
DevWidget, DevWidgetFERow, DevWidgetFBOSRow, DevWidgetDelModeRow,
|
||||
} from "../dev_widget";
|
||||
import { DevSettings } from "../dev_support";
|
||||
import { setWebAppConfigValue } from "../../../config_storage/actions";
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import { store } from "../../redux/store";
|
||||
import {
|
||||
getWebAppConfigValue, setWebAppConfigValue
|
||||
getWebAppConfigValue, setWebAppConfigValue,
|
||||
} from "../../config_storage/actions";
|
||||
import { BooleanConfigKey } from "farmbot/dist/resources/configs/web_app";
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import * as React from "react";
|
||||
import {
|
||||
Widget, WidgetHeader, WidgetBody, Row, Col, BlurableInput
|
||||
Widget, WidgetHeader, WidgetBody, Row, Col, BlurableInput,
|
||||
} from "../../ui";
|
||||
import { ToggleButton } from "../../controls/toggle_button";
|
||||
import { setWebAppConfigValue } from "../../config_storage/actions";
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import * as React from "react";
|
||||
import { connect } from "react-redux";
|
||||
import {
|
||||
Settings, ChangePassword, ExportAccountPanel, DangerousDeleteWidget
|
||||
Settings, ChangePassword, ExportAccountPanel, DangerousDeleteWidget,
|
||||
} from "./components";
|
||||
import { Props } from "./interfaces";
|
||||
import { Page, Row, Col } from "../ui";
|
||||
|
@ -47,12 +47,13 @@ export class RawAccount extends React.Component<Props, State> {
|
|||
(key: keyof User) => (key === "email") && this.setState({ warnThem: true });
|
||||
|
||||
onChange = (e: React.FormEvent<HTMLInputElement>) => {
|
||||
const { name, value } = e.currentTarget;
|
||||
if (isKey(name)) {
|
||||
this.tempHack(name);
|
||||
this.props.dispatch(edit(this.props.user, { [name]: value }));
|
||||
const { value } = e.currentTarget;
|
||||
const field = e.currentTarget.name;
|
||||
if (isKey(field)) {
|
||||
this.tempHack(field);
|
||||
this.props.dispatch(edit(this.props.user, { [field]: value }));
|
||||
} else {
|
||||
throw new Error("Bad key: " + name);
|
||||
throw new Error("Bad key: " + field);
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -5,7 +5,7 @@ const mockFeatures = [
|
|||
storageKey: "weedDetector",
|
||||
callback: jest.fn(),
|
||||
value: false
|
||||
}
|
||||
},
|
||||
];
|
||||
|
||||
const mocks = {
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import { BooleanSetting } from "../../session_keys";
|
||||
import { Content } from "../../constants";
|
||||
import {
|
||||
GetWebAppConfigValue, setWebAppConfigValue
|
||||
GetWebAppConfigValue, setWebAppConfigValue,
|
||||
} from "../../config_storage/actions";
|
||||
import { BooleanConfigKey } from "farmbot/dist/resources/configs/web_app";
|
||||
import { t } from "../../i18next_wrapper";
|
||||
|
@ -78,7 +78,7 @@ export const fetchLabFeatures =
|
|||
storageKey: BooleanSetting.user_interface_read_only_mode,
|
||||
value: false,
|
||||
displayInvert: false,
|
||||
}
|
||||
},
|
||||
].map(fetchSettingValue(getConfigValue)));
|
||||
|
||||
/** Always allow toggling from true => false (deactivate).
|
||||
|
|
|
@ -11,7 +11,7 @@ interface LabsFeaturesListProps {
|
|||
}
|
||||
|
||||
export function LabsFeaturesList(props: LabsFeaturesListProps) {
|
||||
return <div>
|
||||
return <div className="labs-features-list">
|
||||
{fetchLabFeatures(props.getConfigValue).map((feature, i) => {
|
||||
const displayValue = feature.displayInvert ? !feature.value : feature.value;
|
||||
return <Row key={i}>
|
||||
|
@ -23,6 +23,7 @@ export function LabsFeaturesList(props: LabsFeaturesListProps) {
|
|||
</Col>
|
||||
<Col xs={2}>
|
||||
<ToggleButton
|
||||
title={t("toggle feature")}
|
||||
toggleValue={displayValue ? 1 : 0}
|
||||
toggleAction={() => props.onToggle(feature)
|
||||
.then(() => feature.callback && feature.callback())}
|
||||
|
|
|
@ -9,9 +9,8 @@ interface DataDumpExport { device?: DeviceAccountSettings; }
|
|||
type Response = AxiosResponse<DataDumpExport | undefined>;
|
||||
|
||||
export function generateFilename({ device }: DataDumpExport): string {
|
||||
let name: string;
|
||||
name = device ? (device.name + "_" + device.id) : "farmbot";
|
||||
return `export_${name}.json`.toLowerCase();
|
||||
const nameAndId = device ? (device.name + "_" + device.id) : "farmbot";
|
||||
return `export_${nameAndId}.json`.toLowerCase();
|
||||
}
|
||||
|
||||
// Thanks, @KOL - https://stackoverflow.com/a/19328891/1064917
|
||||
|
|
|
@ -158,6 +158,10 @@ export class API {
|
|||
get farmwareInstallationPath() {
|
||||
return `${this.baseUrl}/api/farmware_installations/`;
|
||||
}
|
||||
/** /api/first_party_farmwares */
|
||||
get firstPartyFarmwarePath() {
|
||||
return `${this.baseUrl}/api/first_party_farmwares`;
|
||||
}
|
||||
/** /api/alerts/:id */
|
||||
get alertPath() { return `${this.baseUrl}/api/alerts/`; }
|
||||
/** /api/global_bulletins/:id */
|
||||
|
|
|
@ -334,6 +334,7 @@ const MUST_CONFIRM_LIST: ResourceName[] = [
|
|||
"Regimen",
|
||||
"Image",
|
||||
"SavedGarden",
|
||||
"PointGroup",
|
||||
];
|
||||
|
||||
const confirmationChecker = (resourceName: ResourceName, force = false) =>
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
import * as React from "react";
|
||||
import { Session } from "./session";
|
||||
import { ExternalUrl } from "./external_urls";
|
||||
|
||||
const OUTER_STYLE: React.CSSProperties = {
|
||||
borderRadius: "10px",
|
||||
|
@ -47,7 +48,7 @@ export function Apology(_: {}) {
|
|||
<li>
|
||||
<span>
|
||||
Send a report to our developer team via the
|
||||
<a href="http://forum.farmbot.org/c/software">FarmBot software
|
||||
<a href={ExternalUrl.softwareForum}>FarmBot software
|
||||
forum</a>. Including additional information (such as steps leading up
|
||||
to the error) helps us identify solutions more quickly.
|
||||
</span>
|
||||
|
|
|
@ -18,7 +18,7 @@ import { validBotLocationData, validFwConfig, validFbosConfig } from "./util";
|
|||
import { BooleanSetting } from "./session_keys";
|
||||
import { getPathArray } from "./history";
|
||||
import {
|
||||
getWebAppConfigValue, GetWebAppConfigValue
|
||||
getWebAppConfigValue, GetWebAppConfigValue,
|
||||
} from "./config_storage/actions";
|
||||
import { takeSortedLogs } from "./logs/state_to_props";
|
||||
import { FirmwareConfig } from "farmbot/dist/resources/configs/firmware";
|
||||
|
@ -26,11 +26,11 @@ import { getFirmwareConfig, getFbosConfig } from "./resources/getters";
|
|||
import { intersection } from "lodash";
|
||||
import { t } from "./i18next_wrapper";
|
||||
import { ResourceIndex } from "./resources/interfaces";
|
||||
import { isBotOnline } from "./devices/must_be_online";
|
||||
import { getStatus } from "./connectivity/reducer_support";
|
||||
import { isBotOnlineFromState } from "./devices/must_be_online";
|
||||
import { getAllAlerts } from "./messages/state_to_props";
|
||||
import { PingDictionary } from "./devices/connectivity/qos";
|
||||
import { getEnv, getShouldDisplayFn } from "./farmware/state_to_props";
|
||||
import { filterAlerts } from "./messages/alerts";
|
||||
|
||||
/** For the logger module */
|
||||
init();
|
||||
|
@ -81,7 +81,7 @@ export function mapStateToProps(props: Everything): AppProps {
|
|||
tour: props.resources.consumers.help.currentTour,
|
||||
resources: props.resources.index,
|
||||
autoSync: !!(fbosConfig && fbosConfig.auto_sync),
|
||||
alertCount: getAllAlerts(props.resources).length,
|
||||
alertCount: getAllAlerts(props.resources).filter(filterAlerts).length,
|
||||
pings: props.bot.connectivity.pings,
|
||||
env,
|
||||
};
|
||||
|
@ -99,7 +99,7 @@ const MUST_LOAD: ResourceName[] = [
|
|||
"FarmEvent",
|
||||
"Point",
|
||||
"Device",
|
||||
"Tool" // Sequence editor needs this for rendering.
|
||||
"Tool", // Sequence editor needs this for rendering.
|
||||
];
|
||||
|
||||
export class RawApp extends React.Component<AppProps, {}> {
|
||||
|
@ -124,8 +124,6 @@ export class RawApp extends React.Component<AppProps, {}> {
|
|||
const syncLoaded = this.isLoaded;
|
||||
const currentPage = getPathArray()[2];
|
||||
const { location_data, mcu_params } = this.props.bot.hardware;
|
||||
const { sync_status } = this.props.bot.hardware.informational_settings;
|
||||
const bot2mqtt = this.props.bot.connectivity.uptime["bot.mqtt"];
|
||||
return <div className="app">
|
||||
{!syncLoaded && <LoadingPlant animate={this.props.animate} />}
|
||||
<HotKeys dispatch={this.props.dispatch} />
|
||||
|
@ -151,7 +149,7 @@ export class RawApp extends React.Component<AppProps, {}> {
|
|||
firmwareSettings={this.props.firmwareConfig || mcu_params}
|
||||
xySwap={this.props.xySwap}
|
||||
arduinoBusy={!!this.props.bot.hardware.informational_settings.busy}
|
||||
botOnline={isBotOnline(sync_status, getStatus(bot2mqtt))}
|
||||
botOnline={isBotOnlineFromState(this.props.bot)}
|
||||
env={this.props.env}
|
||||
stepSize={this.props.bot.stepSize} />}
|
||||
</div>;
|
||||
|
|
|
@ -3,8 +3,8 @@ jest.mock("axios", () => ({
|
|||
response: { use: jest.fn() },
|
||||
request: { use: jest.fn() }
|
||||
},
|
||||
post: jest.fn(() => { return Promise.resolve({ data: { foo: "bar" } }); }),
|
||||
get: jest.fn(() => { return Promise.resolve({ data: { foo: "bar" } }); }),
|
||||
post: jest.fn(() => Promise.resolve({ data: { foo: "bar" } })),
|
||||
get: jest.fn(() => Promise.resolve({ data: { foo: "bar" } })),
|
||||
}));
|
||||
|
||||
jest.mock("../../api/api", () => ({
|
||||
|
@ -22,6 +22,7 @@ jest.mock("../../devices/actions", () => ({
|
|||
fetchReleases: jest.fn(),
|
||||
fetchLatestGHBetaRelease: jest.fn(),
|
||||
fetchMinOsFeatureData: jest.fn(),
|
||||
fetchOsReleaseNotes: jest.fn(),
|
||||
}));
|
||||
|
||||
import { didLogin } from "../actions";
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
import axios from "axios";
|
||||
import {
|
||||
fetchReleases, fetchMinOsFeatureData, FEATURE_MIN_VERSIONS_URL,
|
||||
fetchLatestGHBetaRelease
|
||||
fetchReleases, fetchMinOsFeatureData,
|
||||
fetchLatestGHBetaRelease,
|
||||
fetchOsReleaseNotes,
|
||||
} from "../devices/actions";
|
||||
import { AuthState } from "./interfaces";
|
||||
import { ReduxAction } from "../redux/interfaces";
|
||||
|
@ -10,7 +11,7 @@ import { API } from "../api";
|
|||
import {
|
||||
responseFulfilled,
|
||||
responseRejected,
|
||||
requestFulfilled
|
||||
requestFulfilled,
|
||||
} from "../interceptors";
|
||||
import { Actions } from "../constants";
|
||||
import { connectDevice } from "../connectivity/connect_device";
|
||||
|
@ -24,7 +25,8 @@ export function didLogin(authState: AuthState, dispatch: Function) {
|
|||
beta_os_update_server && beta_os_update_server != "NOT_SET" &&
|
||||
dispatch(fetchLatestGHBetaRelease(beta_os_update_server));
|
||||
dispatch(getFirstPartyFarmwareList());
|
||||
dispatch(fetchMinOsFeatureData(FEATURE_MIN_VERSIONS_URL));
|
||||
dispatch(fetchMinOsFeatureData());
|
||||
dispatch(fetchOsReleaseNotes());
|
||||
dispatch(setToken(authState));
|
||||
Sync.fetchSyncData(dispatch);
|
||||
dispatch(connectDevice(authState));
|
||||
|
|
|
@ -1,58 +1,72 @@
|
|||
const mockState = {
|
||||
auth: {
|
||||
token: {
|
||||
unencoded: { iss: "http://geocities.com" }
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
jest.mock("axios", () => ({
|
||||
interceptors: {
|
||||
response: { use: jest.fn() },
|
||||
request: { use: jest.fn() }
|
||||
},
|
||||
get() { return Promise.resolve({ data: mockState }); }
|
||||
}));
|
||||
|
||||
jest.mock("../../session", () => ({
|
||||
Session: {
|
||||
fetchStoredToken: jest.fn(),
|
||||
getAll: () => undefined,
|
||||
clear: jest.fn()
|
||||
clear: jest.fn(),
|
||||
}
|
||||
}));
|
||||
|
||||
jest.mock("../../auth/actions", () => ({
|
||||
didLogin: jest.fn(),
|
||||
setToken: jest.fn()
|
||||
setToken: jest.fn(),
|
||||
}));
|
||||
|
||||
jest.mock("../../refresh_token", () => ({ maybeRefreshToken: jest.fn() }));
|
||||
|
||||
let mockTimeout = Promise.resolve({ token: "fake token data" });
|
||||
jest.mock("promise-timeout", () => ({ timeout: () => mockTimeout }));
|
||||
|
||||
import { ready, storeToken } from "../actions";
|
||||
import { setToken, didLogin } from "../../auth/actions";
|
||||
import { Session } from "../../session";
|
||||
import { auth } from "../../__test_support__/fake_state/token";
|
||||
import { fakeState } from "../../__test_support__/fake_state";
|
||||
|
||||
describe("Actions", () => {
|
||||
it("calls didLogin()", () => {
|
||||
jest.resetAllMocks();
|
||||
describe("ready()", () => {
|
||||
it("uses new token", async () => {
|
||||
const fakeAuth = { token: "fake token data" };
|
||||
mockTimeout = Promise.resolve(fakeAuth);
|
||||
const dispatch = jest.fn();
|
||||
const thunk = ready();
|
||||
thunk(dispatch, fakeState);
|
||||
expect(setToken).toHaveBeenCalled();
|
||||
const state = fakeState();
|
||||
console.warn = jest.fn();
|
||||
await thunk(dispatch, () => state);
|
||||
expect(setToken).toHaveBeenCalledWith(fakeAuth);
|
||||
expect(didLogin).toHaveBeenCalledWith(fakeAuth, dispatch);
|
||||
expect(console.warn).not.toHaveBeenCalled();
|
||||
expect(Session.clear).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("Calls Session.clear() when missing auth", () => {
|
||||
jest.resetAllMocks();
|
||||
it("uses old token", async () => {
|
||||
mockTimeout = Promise.reject({ token: "not used" });
|
||||
const dispatch = jest.fn();
|
||||
const thunk = ready();
|
||||
const state = fakeState();
|
||||
console.warn = jest.fn();
|
||||
await thunk(dispatch, () => state);
|
||||
expect(setToken).toHaveBeenLastCalledWith(state.auth);
|
||||
expect(didLogin).toHaveBeenCalledWith(state.auth, dispatch);
|
||||
expect(console.warn)
|
||||
.toHaveBeenCalledWith(expect.stringContaining("Can't refresh token."));
|
||||
expect(Session.clear).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("calls Session.clear() when missing auth", () => {
|
||||
const dispatch = jest.fn();
|
||||
const state = fakeState();
|
||||
delete state.auth;
|
||||
const getState = () => state;
|
||||
const thunk = ready();
|
||||
console.warn = jest.fn();
|
||||
thunk(dispatch, getState);
|
||||
expect(setToken).not.toHaveBeenCalled();
|
||||
expect(didLogin).not.toHaveBeenCalled();
|
||||
expect(console.warn).not.toHaveBeenCalled();
|
||||
expect(Session.clear).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
describe("storeToken()", () => {
|
||||
it("stores token", () => {
|
||||
const old = auth;
|
||||
old.token.unencoded.jti = "old";
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import {
|
||||
toggleWebAppBool, getWebAppConfigValue, setWebAppConfigValue
|
||||
toggleWebAppBool, getWebAppConfigValue, setWebAppConfigValue,
|
||||
} from "../actions";
|
||||
import { BooleanSetting, NumericSetting } from "../../session_keys";
|
||||
import { edit, save } from "../../api/crud";
|
||||
|
|
|
@ -4,7 +4,7 @@ import {
|
|||
BooleanConfigKey,
|
||||
WebAppConfig,
|
||||
NumberConfigKey,
|
||||
StringConfigKey
|
||||
StringConfigKey,
|
||||
} from "farmbot/dist/resources/configs/web_app";
|
||||
import { getWebAppConfig } from "../resources/getters";
|
||||
|
||||
|
|
|
@ -10,7 +10,7 @@ import { fakeState } from "../../__test_support__/fake_state";
|
|||
import { GetState } from "../../redux/interfaces";
|
||||
import { handleInbound } from "../auto_sync_handle_inbound";
|
||||
import {
|
||||
handleCreateOrUpdate
|
||||
handleCreateOrUpdate,
|
||||
} from "../auto_sync";
|
||||
import { destroyOK } from "../../resources/actions";
|
||||
import { SkipMqttData, BadMqttData, UpdateMqttData, DeleteMqttData } from "../interfaces";
|
||||
|
|
|
@ -4,7 +4,7 @@ import {
|
|||
asTaggedResource,
|
||||
handleCreate,
|
||||
handleUpdate,
|
||||
handleCreateOrUpdate
|
||||
handleCreateOrUpdate,
|
||||
} from "../auto_sync";
|
||||
import { SpecialStatus, TaggedSequence } from "farmbot";
|
||||
import { Actions } from "../../constants";
|
||||
|
|
|
@ -35,7 +35,7 @@ describe("attachEventListeners", () => {
|
|||
].map(e => expect(dev.on).toHaveBeenCalledWith(e, expect.any(Function)));
|
||||
[
|
||||
"message",
|
||||
"reconnect"
|
||||
"reconnect",
|
||||
].map(e => {
|
||||
if (dev.client) {
|
||||
expect(dev.client.on).toHaveBeenCalledWith(e, expect.any(Function));
|
||||
|
|
|
@ -37,7 +37,9 @@ import { getDevice } from "../../../device";
|
|||
import { talk } from "browser-speech";
|
||||
import { MessageType } from "../../../sequences/interfaces";
|
||||
import { FbjsEventName } from "farmbot/dist/constants";
|
||||
import { info, error, success, warning, fun, busy } from "../../../toast/toast";
|
||||
import {
|
||||
info, error, success, warning, fun, busy, removeToast,
|
||||
} from "../../../toast/toast";
|
||||
import { onLogs } from "../../log_handlers";
|
||||
import { fakeState } from "../../../__test_support__/fake_state";
|
||||
import { globalQueue } from "../../batch_queue";
|
||||
|
@ -177,7 +179,8 @@ describe("onOffline", () => {
|
|||
jest.resetAllMocks();
|
||||
onOffline();
|
||||
expect(dispatchNetworkDown).toHaveBeenCalledWith("user.mqtt", ANY_NUMBER);
|
||||
expect(error).toHaveBeenCalledWith(Content.MQTT_DISCONNECTED);
|
||||
expect(error).toHaveBeenCalledWith(
|
||||
Content.MQTT_DISCONNECTED, "Error", "red", "offline");
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -186,13 +189,17 @@ describe("onOnline", () => {
|
|||
jest.resetAllMocks();
|
||||
onOnline();
|
||||
expect(dispatchNetworkUp).toHaveBeenCalledWith("user.mqtt", ANY_NUMBER);
|
||||
expect(removeToast).toHaveBeenCalledWith("offline");
|
||||
});
|
||||
});
|
||||
|
||||
describe("onReconnect", () => {
|
||||
onReconnect();
|
||||
expect(warning).toHaveBeenCalledWith(
|
||||
"Attempting to reconnect to the message broker", "Offline", "yellow");
|
||||
describe("onReconnect()", () => {
|
||||
it("sends reconnect toast", () => {
|
||||
onReconnect();
|
||||
expect(warning).toHaveBeenCalledWith(
|
||||
"Attempting to reconnect to the message broker",
|
||||
"Offline", "yellow", "offline");
|
||||
});
|
||||
});
|
||||
|
||||
describe("changeLastClientConnected", () => {
|
||||
|
@ -268,7 +275,8 @@ describe("onPublicBroadcast", () => {
|
|||
console.log = jest.fn();
|
||||
onPublicBroadcast({});
|
||||
expectBroadcastLog();
|
||||
expect(window.alert).toHaveBeenCalledWith(Content.FORCE_REFRESH_CANCEL_WARNING);
|
||||
expect(window.alert).toHaveBeenCalledWith(
|
||||
Content.FORCE_REFRESH_CANCEL_WARNING);
|
||||
expect(location.assign).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
|
|
@ -1,21 +1,15 @@
|
|||
jest.mock("../../slow_down", () => {
|
||||
return {
|
||||
slowDown: jest.fn((fn: Function) => fn),
|
||||
};
|
||||
});
|
||||
|
||||
jest.mock("../../../devices/actions", () => ({
|
||||
badVersion: jest.fn(),
|
||||
EXPECTED_MAJOR: 1,
|
||||
EXPECTED_MINOR: 0,
|
||||
jest.mock("../../slow_down", () => ({
|
||||
slowDown: jest.fn((fn: Function) => fn)
|
||||
}));
|
||||
|
||||
jest.mock("../../../devices/actions", () => ({ badVersion: jest.fn() }));
|
||||
|
||||
import {
|
||||
onStatus,
|
||||
incomingStatus,
|
||||
incomingLegacyStatus,
|
||||
onLegacyStatus,
|
||||
HACKY_FLAGS
|
||||
HACKY_FLAGS,
|
||||
} from "../../connect_device";
|
||||
import { slowDown } from "../../slow_down";
|
||||
import { fakeState } from "../../../__test_support__/fake_state";
|
||||
|
@ -49,8 +43,10 @@ describe("onStatus()", () => {
|
|||
});
|
||||
|
||||
it("version ok", () => {
|
||||
globalConfig.MINIMUM_FBOS_VERSION = "1.0.0";
|
||||
callOnStatus("1.0.0");
|
||||
expect(badVersion).not.toHaveBeenCalled();
|
||||
delete globalConfig.MINIMUM_FBOS_VERSION;
|
||||
});
|
||||
});
|
||||
|
||||
|
|
|
@ -20,7 +20,7 @@ import { getDevice } from "../../device";
|
|||
import { store } from "../../redux/store";
|
||||
import { Actions } from "../../constants";
|
||||
import {
|
||||
startTracking, outstandingRequests, stopTracking, cleanUUID
|
||||
startTracking, outstandingRequests, stopTracking, cleanUUID,
|
||||
} from "../data_consistency";
|
||||
|
||||
const unprocessedUuid = "~UU.ID~";
|
||||
|
|
|
@ -8,7 +8,7 @@ jest.mock("../index", () => ({
|
|||
import {
|
||||
readPing,
|
||||
startPinging,
|
||||
PING_INTERVAL
|
||||
PING_INTERVAL,
|
||||
} from "../ping_mqtt";
|
||||
import { Farmbot, RpcRequest, RpcRequestBodyItem } from "farmbot";
|
||||
import { FarmBotInternalConfig } from "farmbot/dist/config";
|
||||
|
|
|
@ -41,7 +41,7 @@ describe("connectivity reducer", () => {
|
|||
it("broadcasts PING_OK", () => {
|
||||
pingOK("yep", 123);
|
||||
expect(store.dispatch).toHaveBeenCalledWith({
|
||||
payload: { at: 123, id: "yep", },
|
||||
payload: { at: 123, id: "yep" },
|
||||
type: "PING_OK",
|
||||
});
|
||||
});
|
||||
|
|
|
@ -4,7 +4,7 @@ import { TaggedResource, SpecialStatus } from "farmbot";
|
|||
import { overwrite, init } from "../api/crud";
|
||||
import { handleInbound } from "./auto_sync_handle_inbound";
|
||||
import {
|
||||
SyncPayload, MqttDataResult, Reason, UpdateMqttData
|
||||
SyncPayload, MqttDataResult, Reason, UpdateMqttData,
|
||||
} from "./interfaces";
|
||||
import { outstandingRequests } from "./data_consistency";
|
||||
import { newTaggedResource } from "../sync/actions";
|
||||
|
|
|
@ -4,17 +4,13 @@ import { Log } from "farmbot/dist/resources/api_resources";
|
|||
import { Farmbot, BotStateTree, TaggedResource } from "farmbot";
|
||||
import { FbjsEventName } from "farmbot/dist/constants";
|
||||
import { noop } from "lodash";
|
||||
import { success, error, info, warning, fun, busy } from "../toast/toast";
|
||||
import {
|
||||
success, error, info, warning, fun, busy, removeToast,
|
||||
} from "../toast/toast";
|
||||
import { HardwareState } from "../devices/interfaces";
|
||||
import { GetState, ReduxAction } from "../redux/interfaces";
|
||||
import { Content, Actions } from "../constants";
|
||||
import {
|
||||
EXPECTED_MAJOR,
|
||||
EXPECTED_MINOR,
|
||||
commandOK,
|
||||
badVersion,
|
||||
commandErr
|
||||
} from "../devices/actions";
|
||||
import { commandOK, badVersion, commandErr } from "../devices/actions";
|
||||
import { init } from "../api/crud";
|
||||
import { AuthState } from "../auth/interfaces";
|
||||
import { autoSync } from "./auto_sync";
|
||||
|
@ -108,11 +104,6 @@ export function readStatus() {
|
|||
.then(() => { commandOK(noun); }, commandErr(noun));
|
||||
}
|
||||
|
||||
export const onOffline = () => {
|
||||
dispatchNetworkDown("user.mqtt", now());
|
||||
error(t(Content.MQTT_DISCONNECTED));
|
||||
};
|
||||
|
||||
export const changeLastClientConnected = (bot: Farmbot) => () => {
|
||||
bot.setUserEnv({
|
||||
"LAST_CLIENT_CONNECTED": JSON.stringify(new Date())
|
||||
|
@ -123,7 +114,7 @@ const setBothUp = () => bothUp();
|
|||
const legacyChecks = (getState: GetState) => {
|
||||
const { controller_version } = getState().bot.hardware.informational_settings;
|
||||
if (HACKY_FLAGS.needVersionCheck && controller_version) {
|
||||
const IS_OK = versionOK(controller_version, EXPECTED_MAJOR, EXPECTED_MINOR);
|
||||
const IS_OK = versionOK(controller_version);
|
||||
if (!IS_OK) { badVersion(); }
|
||||
HACKY_FLAGS.needVersionCheck = false;
|
||||
}
|
||||
|
@ -163,14 +154,20 @@ export function onMalformed() {
|
|||
}
|
||||
}
|
||||
|
||||
export const onOnline =
|
||||
() => {
|
||||
success(t("Reconnected to the message broker."), t("Online"));
|
||||
dispatchNetworkUp("user.mqtt", now());
|
||||
};
|
||||
export const onReconnect =
|
||||
() => warning(t("Attempting to reconnect to the message broker"),
|
||||
t("Offline"), "yellow");
|
||||
export const onOnline = () => {
|
||||
removeToast("offline");
|
||||
success(t("Reconnected to the message broker."), t("Online"));
|
||||
dispatchNetworkUp("user.mqtt", now());
|
||||
};
|
||||
|
||||
export const onReconnect = () =>
|
||||
warning(t("Attempting to reconnect to the message broker"),
|
||||
t("Offline"), "yellow", "offline");
|
||||
|
||||
export const onOffline = () => {
|
||||
dispatchNetworkDown("user.mqtt", now());
|
||||
error(t(Content.MQTT_DISCONNECTED), t("Error"), "red", "offline");
|
||||
};
|
||||
|
||||
export function onPublicBroadcast(payl: unknown) {
|
||||
console.log(FbjsEventName.publicBroadcast, payl);
|
||||
|
|
|
@ -3,7 +3,7 @@ import {
|
|||
actOnChannelName,
|
||||
showLogOnScreen,
|
||||
speakLogAloud,
|
||||
initLog
|
||||
initLog,
|
||||
} from "./connect_device";
|
||||
import { GetState } from "../redux/interfaces";
|
||||
import { Log } from "farmbot/dist/resources/api_resources";
|
||||
|
|
|
@ -4,7 +4,7 @@ import {
|
|||
dispatchNetworkUp,
|
||||
dispatchQosStart,
|
||||
pingOK,
|
||||
pingNO
|
||||
pingNO,
|
||||
} from "./index";
|
||||
import { isNumber } from "lodash";
|
||||
import axios from "axios";
|
||||
|
|
|
@ -2,7 +2,7 @@ import { generateReducer } from "../redux/generate_reducer";
|
|||
import { Actions } from "../constants";
|
||||
import {
|
||||
ConnectionState,
|
||||
EdgeStatus
|
||||
EdgeStatus,
|
||||
} from "./interfaces";
|
||||
import { startPing, completePing, failPing } from "../devices/connectivity/qos";
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import { ConnectionStatus } from "./interfaces";
|
||||
|
||||
export function getStatus(cs: ConnectionStatus | undefined): "up" | "down" {
|
||||
return (cs && cs.state) || "down";
|
||||
return cs?.state || "down";
|
||||
}
|
||||
|
|
|
@ -2,6 +2,27 @@ import { trim } from "./util";
|
|||
|
||||
export namespace ToolTips {
|
||||
|
||||
// Farm Designer: Groups
|
||||
export const SORT_DESCRIPTION =
|
||||
trim(`When executing a sequence over a Group of locations, FarmBot will
|
||||
travel to each group member in the order of the chosen sort method.
|
||||
If the random option is chosen, FarmBot will travel in a random order
|
||||
every time, so the ordering shown below will only be representative.`);
|
||||
|
||||
export const CRITERIA_SELECTION_COUNT =
|
||||
trim(`Filter additions can only be removed by changing filters.
|
||||
Click and drag in the map to modify selection filters.
|
||||
Filters will be applied at the time of sequence execution. The final
|
||||
selection at that time may differ from the selection currently
|
||||
displayed.`);
|
||||
|
||||
export const CRITERIA_ALPHA_FEATURE =
|
||||
trim(`Group filters is a new feature under active development.
|
||||
Use with caution.`);
|
||||
|
||||
export const DOT_NOTATION_TIP =
|
||||
trim(`Tip: Use dot notation (i.e., 'meta.color') to access meta fields.`);
|
||||
|
||||
// Controls
|
||||
export const MOVE =
|
||||
trim(`Use these manual control buttons to move FarmBot in realtime.
|
||||
|
@ -12,7 +33,12 @@ export namespace ToolTips {
|
|||
|
||||
export const WEBCAM =
|
||||
trim(`If you have a webcam, you can view the video stream in this widget.
|
||||
Press the edit button to update and save your webcam URL.`);
|
||||
Press the edit button to update and save your webcam URL.
|
||||
Note: Some webcam services do not allow webcam feeds to be embedded in
|
||||
other sites. If you see a web browser error after adding a webcam feed,
|
||||
there is unfortunately nothing FarmBot can do to fix the problem.
|
||||
Please contact your webcam's customer support to see if the security
|
||||
policy for embedding feeds into other sites can be changed.`);
|
||||
|
||||
export const PERIPHERALS =
|
||||
trim(`Use these toggle switches to control FarmBot's peripherals in
|
||||
|
@ -26,10 +52,19 @@ export namespace ToolTips {
|
|||
export const SENSOR_HISTORY =
|
||||
trim(`View and filter historical sensor reading data.`);
|
||||
|
||||
// Device
|
||||
export const OS_SETTINGS =
|
||||
trim(`View and change device settings.`);
|
||||
// FarmBot OS Settings: Firmware
|
||||
export const FIRMWARE_VALUE_API =
|
||||
trim(`Firmware value from your choice in the dropdown to the left, as
|
||||
understood by the Web App.`);
|
||||
|
||||
export const FIRMWARE_VALUE_FBOS =
|
||||
trim(`Firmware value reported from the firmware, as understood by
|
||||
FarmBot OS.`);
|
||||
|
||||
export const FIRMWARE_VALUE_MCU =
|
||||
trim(`Firmware value reported from the firmware.`);
|
||||
|
||||
// Hardware Settings
|
||||
export const HW_SETTINGS =
|
||||
trim(`Change settings of your FarmBot hardware with the fields below.
|
||||
Caution: Changing these settings to extreme values can cause hardware
|
||||
|
@ -38,37 +73,39 @@ export namespace ToolTips {
|
|||
Tip: Recalibrate FarmBot after changing settings and test a
|
||||
few sequences to verify that everything works as expected.`);
|
||||
|
||||
export const PIN_BINDINGS =
|
||||
trim(`Assign a sequence to execute when a Raspberry Pi GPIO pin is
|
||||
activated.`);
|
||||
|
||||
export const PIN_BINDING_WARNING =
|
||||
trim(`Warning: Binding to a pin without a physical button and
|
||||
pull-down resistor connected may put FarmBot into an unstable state.`);
|
||||
|
||||
// Connectivity
|
||||
export const CONNECTIVITY =
|
||||
trim(`Diagnose connectivity issues with FarmBot and the browser.`);
|
||||
|
||||
// Hardware Settings: Homing and Calibration
|
||||
export const HOMING =
|
||||
export const HOMING_ENCODERS =
|
||||
trim(`If encoders or end-stops are enabled, home axis (find zero).`);
|
||||
|
||||
export const CALIBRATION =
|
||||
export const HOMING_STALL_DETECTION =
|
||||
trim(`If stall detection or end-stops are enabled, home axis
|
||||
(find zero).`);
|
||||
|
||||
export const CALIBRATION_ENCODERS =
|
||||
trim(`If encoders or end-stops are enabled, home axis and determine
|
||||
maximum.`);
|
||||
|
||||
export const CALIBRATION_STALL_DETECTION =
|
||||
trim(`If stall detection or end-stops are enabled, home axis and
|
||||
determine maximum.`);
|
||||
|
||||
export const SET_ZERO_POSITION =
|
||||
trim(`Set the current location as zero.`);
|
||||
|
||||
export const FIND_HOME_ON_BOOT =
|
||||
export const FIND_HOME_ON_BOOT_ENCODERS =
|
||||
trim(`If encoders or end-stops are enabled, find the home position
|
||||
when the device powers on.
|
||||
Warning! This will perform homing on all axes when the
|
||||
device powers on. Encoders or endstops must be enabled.
|
||||
when the device powers on. Warning! This will perform homing on all
|
||||
axes when the device powers on. Encoders or endstops must be enabled.
|
||||
It is recommended to make sure homing works properly before enabling
|
||||
this feature. (default: disabled)`);
|
||||
|
||||
export const FIND_HOME_ON_BOOT_STALL_DETECTION =
|
||||
trim(`If stall detection or end-stops are enabled, find the home
|
||||
position when the device powers on. Warning! This will perform homing
|
||||
on all axes when the device powers on. Stall detection or endstops
|
||||
must be enabled. It is recommended to make sure homing works properly
|
||||
before enabling this feature. (default: disabled)`);
|
||||
|
||||
export const STOP_AT_HOME =
|
||||
trim(`Stop at the home location of the axis. (default: disabled)`);
|
||||
|
||||
|
@ -85,18 +122,7 @@ export namespace ToolTips {
|
|||
trim(`Set the length of each axis to provide software limits.
|
||||
Used only if STOP AT MAX is enabled. (default: 0 (disabled))`);
|
||||
|
||||
export const TIMEOUT_AFTER =
|
||||
trim(`Amount of time to wait for a command to execute before stopping.
|
||||
(default: 120s)`);
|
||||
|
||||
// Hardware Settings: Motors
|
||||
export const MAX_MOVEMENT_RETRIES =
|
||||
trim(`Number of times to retry a movement before stopping. (default: 3)`);
|
||||
|
||||
export const E_STOP_ON_MOV_ERR =
|
||||
trim(`Emergency stop if movement is not complete after the maximum
|
||||
number of retries. (default: disabled)`);
|
||||
|
||||
export const MAX_SPEED =
|
||||
trim(`Maximum travel speed after acceleration in millimeters per second.
|
||||
(default: x: 80mm/s, y: 80mm/s, z: 16mm/s)`);
|
||||
|
@ -132,18 +158,22 @@ export namespace ToolTips {
|
|||
export const MOTOR_CURRENT =
|
||||
trim(`Motor current in milliamps. (default: 600)`);
|
||||
|
||||
export const STALL_SENSITIVITY =
|
||||
trim(`Motor stall sensitivity. (default: 30)`);
|
||||
|
||||
export const ENABLE_X2_MOTOR =
|
||||
trim(`Enable use of a second x-axis motor. Connects to E0 on RAMPS.
|
||||
(default: enabled)`);
|
||||
|
||||
// Hardware Settings: Encoders and Endstops
|
||||
// Hardware Settings: Encoders / Stall Detection
|
||||
export const ENABLE_ENCODERS =
|
||||
trim(`Enable use of rotary encoders for stall detection,
|
||||
calibration and homing. (default: enabled)`);
|
||||
|
||||
export const ENABLE_STALL_DETECTION =
|
||||
trim(`Enable use of motor stall detection for detecting missed steps,
|
||||
calibration and homing. (default: enabled)`);
|
||||
|
||||
export const STALL_SENSITIVITY =
|
||||
trim(`Motor stall sensitivity. (default: 30)`);
|
||||
|
||||
export const ENCODER_POSITIONING =
|
||||
trim(`Use encoders for positioning. (default: disabled)`);
|
||||
|
||||
|
@ -151,17 +181,22 @@ export namespace ToolTips {
|
|||
trim(`Reverse the direction of encoder position reading.
|
||||
(default: disabled)`);
|
||||
|
||||
export const MAX_MISSED_STEPS =
|
||||
export const MAX_MISSED_STEPS_ENCODERS =
|
||||
trim(`Number of steps missed (determined by encoder) before motor is
|
||||
considered to have stalled. (default: 5)`);
|
||||
|
||||
export const ENCODER_MISSED_STEP_DECAY =
|
||||
export const MAX_MISSED_STEPS_STALL_DETECTION =
|
||||
trim(`Number of steps missed (determined by motor stall detection) before
|
||||
motor is considered to have stalled. (default: 5)`);
|
||||
|
||||
export const MISSED_STEP_DECAY =
|
||||
trim(`Reduction to missed step total for every good step. (default: 5)`);
|
||||
|
||||
export const ENCODER_SCALING =
|
||||
trim(`encoder scaling factor = 10000 * (motor resolution * microsteps)
|
||||
/ (encoder resolution). (default: 5556 (10000*200/360))`);
|
||||
|
||||
// Hardware Settings: Endstops
|
||||
export const ENABLE_ENDSTOPS =
|
||||
trim(`Enable use of electronic end-stops for end detection,
|
||||
calibration and homing. (default: disabled)`);
|
||||
|
@ -173,18 +208,33 @@ export namespace ToolTips {
|
|||
trim(`Invert axis end-stops. Enable for normally closed (NC),
|
||||
disable for normally open (NO). (default: disabled)`);
|
||||
|
||||
// Hardware Settings: Error Handling
|
||||
export const TIMEOUT_AFTER =
|
||||
trim(`Amount of time to wait for a command to execute before stopping.
|
||||
(default: 120s)`);
|
||||
|
||||
export const MAX_MOVEMENT_RETRIES =
|
||||
trim(`Number of times to retry a movement before stopping. (default: 3)`);
|
||||
|
||||
export const E_STOP_ON_MOV_ERR =
|
||||
trim(`Emergency stop if movement is not complete after the maximum
|
||||
number of retries. (default: disabled)`);
|
||||
|
||||
// Hardware Settings: Pin Guard
|
||||
export const PIN_GUARD_PIN_NUMBER =
|
||||
trim(`The number of the pin to guard. This pin will be set to the specified
|
||||
state after the duration specified by TIMEOUT.`);
|
||||
|
||||
// Hardware Settings: Pin Bindings
|
||||
export const PIN_BINDINGS =
|
||||
trim(`Assign an action or sequence to execute when a Raspberry Pi
|
||||
GPIO pin is activated.`);
|
||||
|
||||
export const PIN_BINDING_WARNING =
|
||||
trim(`Warning: Binding to a pin without a physical button and
|
||||
pull-down resistor connected may put FarmBot into an unstable state.`);
|
||||
|
||||
// Farmware
|
||||
export const FARMWARE =
|
||||
trim(`Manage Farmware (plugins).`);
|
||||
|
||||
export const FARMWARE_LIST =
|
||||
trim(`View, select, and install new Farmware.`);
|
||||
|
||||
export const PHOTOS =
|
||||
trim(`Take and view photos with your FarmBot's camera.`);
|
||||
|
||||
|
@ -208,9 +258,6 @@ export namespace ToolTips {
|
|||
You can also edit, copy, and delete existing sequences;
|
||||
assign a color; and give your commands custom names.`);
|
||||
|
||||
export const SEQUENCE_LIST =
|
||||
trim(`Here is the list of all of your sequences. Click one to edit.`);
|
||||
|
||||
export const DEFAULT_VALUE =
|
||||
trim(`Select a location to be used as the default value for this variable.
|
||||
If the sequence is ever run without the variable explicitly set to
|
||||
|
@ -263,8 +310,12 @@ export namespace ToolTips {
|
|||
|
||||
export const FIND_HOME =
|
||||
trim(`The Find Home step instructs the device to perform a homing
|
||||
command (using encoders or endstops) to find and set zero for
|
||||
the chosen axis or axes.`);
|
||||
command (using encoders, stall detection, or endstops) to find and set
|
||||
zero for the chosen axis or axes.`);
|
||||
|
||||
export const CALIBRATE =
|
||||
trim(`If encoders, stall detection, or end-stops are enabled,
|
||||
home axis and determine maximum.`);
|
||||
|
||||
export const IF =
|
||||
trim(`Execute a sequence if a condition is satisfied. If the condition
|
||||
|
@ -284,6 +335,7 @@ export namespace ToolTips {
|
|||
export const TAKE_PHOTO =
|
||||
trim(`Snaps a photo using the device camera. Select the camera type
|
||||
on the Device page.`);
|
||||
|
||||
export const EMERGENCY_LOCK =
|
||||
trim(`Stops a device from moving until it is unlocked by a user.`);
|
||||
|
||||
|
@ -294,10 +346,7 @@ export namespace ToolTips {
|
|||
trim(`The Mark As step allows FarmBot to programmatically edit the
|
||||
properties of the UTM, plants, and weeds from within a sequence.
|
||||
For example, you can mark a plant as "planted" during a seeding
|
||||
sequence or delete a weed after removing it.`);
|
||||
|
||||
export const REBOOT =
|
||||
trim(`Power cycle FarmBot's onboard computer.`);
|
||||
sequence or mark a weed as "removed" after removing it.`);
|
||||
|
||||
export const SET_SERVO_ANGLE =
|
||||
trim(`Move a servo to the provided angle. An angle of 90 degrees
|
||||
|
@ -310,6 +359,9 @@ export namespace ToolTips {
|
|||
export const MOVE_TO_HOME =
|
||||
trim(`Move FarmBot to home for the provided axis.`);
|
||||
|
||||
export const ASSERTION =
|
||||
trim(`Evaluate Lua commands. For power users and software developers.`);
|
||||
|
||||
export const FIRMWARE_ACTION =
|
||||
trim(`FarmBot OS or micro-controller firmware action.`);
|
||||
|
||||
|
@ -335,20 +387,6 @@ export namespace ToolTips {
|
|||
growing at the same or different times. Multiple regimens can be
|
||||
applied to any one plant.`);
|
||||
|
||||
export const REGIMEN_LIST =
|
||||
trim(`This is a list of all of your regimens. Click one to begin
|
||||
editing it.`);
|
||||
|
||||
// Tools
|
||||
export const TOOL_LIST =
|
||||
trim(`This is a list of all your FarmBot tools and seed containers.
|
||||
Click the Edit button to add, edit, or delete tools or seed containers.`);
|
||||
|
||||
export const TOOLBAY_LIST =
|
||||
trim(`Tool slots are where you store your FarmBot tools and seed
|
||||
containers, which should be reflective of your real FarmBot hardware
|
||||
configuration.`);
|
||||
|
||||
// Logs
|
||||
export const LOGS =
|
||||
trim(`View and filter log messages.`);
|
||||
|
@ -371,16 +409,6 @@ export namespace ToolTips {
|
|||
|
||||
export const FIRMWARE_DEBUG_MESSAGES =
|
||||
trim(`Log all debug received from firmware (clears after refresh).`);
|
||||
|
||||
export const MESSAGES =
|
||||
trim(`View messages.`);
|
||||
|
||||
// App
|
||||
export const LABS =
|
||||
trim(`Customize your web app experience.`);
|
||||
|
||||
export const TOURS =
|
||||
trim(`Take a guided tour of the Web App.`);
|
||||
}
|
||||
|
||||
export namespace Content {
|
||||
|
@ -484,11 +512,9 @@ export namespace Content {
|
|||
real account at`);
|
||||
|
||||
// App Settings
|
||||
export const CONFIRM_STEP_DELETION =
|
||||
trim(`Show a confirmation dialog when deleting a sequence step.`);
|
||||
|
||||
export const CONFIRM_SEQUENCE_DELETION =
|
||||
trim(`Show a confirmation dialog when deleting a sequence.`);
|
||||
export const TIME_FORMAT_24_HOUR =
|
||||
trim(`Display time using the 24-hour notation,
|
||||
i.e., 23:00 instead of 11:00pm`);
|
||||
|
||||
export const HIDE_WEBCAM_WIDGET =
|
||||
trim(`If not using a webcam, use this setting to remove the
|
||||
|
@ -498,14 +524,6 @@ export namespace Content {
|
|||
trim(`If not using sensors, use this setting to remove the
|
||||
widget from the Controls page.`);
|
||||
|
||||
export const DYNAMIC_MAP_SIZE =
|
||||
trim(`Change the garden map size based on axis length.
|
||||
A value must be input in AXIS LENGTH and STOP AT MAX must be enabled in
|
||||
the HARDWARE widget. Overrides MAP SIZE values.`);
|
||||
|
||||
export const PLANT_ANIMATIONS =
|
||||
trim(`Enable plant animations in the garden map.`);
|
||||
|
||||
export const BROWSER_SPEAK_LOGS =
|
||||
trim(`Have the browser also read aloud log messages on the
|
||||
"Speak" channel that are spoken by FarmBot.`);
|
||||
|
@ -518,22 +536,25 @@ export namespace Content {
|
|||
trim(`Warning! When enabled, any unsaved changes
|
||||
will be discarded when refreshing or closing the page. Are you sure?`);
|
||||
|
||||
export const DISCARD_UNSAVED_SEQUENCE_CHANGES =
|
||||
trim(`Don't ask about saving sequence work before
|
||||
closing browser tab. Warning: may cause loss of data.`);
|
||||
export const EMERGENCY_UNLOCK_CONFIRM_CONFIG =
|
||||
trim(`Confirm when unlocking FarmBot after an emergency stop.`);
|
||||
|
||||
export const DISCARD_UNSAVED_SEQUENCE_CHANGES_CONFIRM =
|
||||
trim(`Warning! When enabled, any unsaved changes to sequences
|
||||
will be discarded when refreshing or closing the page. Are you sure?`);
|
||||
export const CONFIRM_EMERGENCY_UNLOCK_CONFIRM_DISABLE =
|
||||
trim(`Warning! When disabled, clicking the UNLOCK button will immediately
|
||||
unlock FarmBot instead of confirming that it is safe to do so.
|
||||
As a result, double-clicking the E-STOP button may not stop FarmBot.
|
||||
Are you sure you want to disable this feature?`);
|
||||
|
||||
export const VIRTUAL_TRAIL =
|
||||
trim(`Display a virtual trail for FarmBot in the garden map to show
|
||||
movement and watering history while the map is open. Toggling this setting
|
||||
will clear data for the current trail.`);
|
||||
export const USER_INTERFACE_READ_ONLY_MODE =
|
||||
trim(`Disallow account data changes. This does
|
||||
not prevent Farmwares or FarmBot OS from changing settings.`);
|
||||
|
||||
export const TIME_FORMAT_24_HOUR =
|
||||
trim(`Display time using the 24-hour notation,
|
||||
i.e., 23:00 instead of 11:00pm`);
|
||||
// Sequence Settings
|
||||
export const CONFIRM_STEP_DELETION =
|
||||
trim(`Show a confirmation dialog when deleting a sequence step.`);
|
||||
|
||||
export const CONFIRM_SEQUENCE_DELETION =
|
||||
trim(`Show a confirmation dialog when deleting a sequence.`);
|
||||
|
||||
export const SHOW_PINS =
|
||||
trim(`Show raw pin lists in Read Sensor, Control Peripheral, and
|
||||
|
@ -542,18 +563,27 @@ export namespace Content {
|
|||
export const EXPAND_STEP_OPTIONS =
|
||||
trim(`Choose whether advanced step options are open or closed by default.`);
|
||||
|
||||
export const EMERGENCY_UNLOCK_CONFIRM_CONFIG =
|
||||
trim(`Confirm when unlocking FarmBot after an emergency stop.`);
|
||||
export const DISCARD_UNSAVED_SEQUENCE_CHANGES =
|
||||
trim(`Don't ask about saving sequence work before
|
||||
closing browser tab. Warning: may cause loss of data.`);
|
||||
|
||||
export const USER_INTERFACE_READ_ONLY_MODE =
|
||||
trim(`Disallow account data changes. This does
|
||||
not prevent Farmwares or FarmBot OS from changing settings.`);
|
||||
export const DISCARD_UNSAVED_SEQUENCE_CHANGES_CONFIRM =
|
||||
trim(`Warning! When enabled, any unsaved changes to sequences
|
||||
will be discarded when refreshing or closing the page. Are you sure?`);
|
||||
|
||||
export const CONFIRM_EMERGENCY_UNLOCK_CONFIRM_DISABLE =
|
||||
trim(`Warning! When disabled, clicking the UNLOCK button will immediately
|
||||
unlock FarmBot instead of confirming that it is safe to do so.
|
||||
As a result, double-clicking the E-STOP button may not stop FarmBot.
|
||||
Are you sure you want to disable this feature?`);
|
||||
// Farm Designer Settings
|
||||
export const PLANT_ANIMATIONS =
|
||||
trim(`Enable plant animations in the garden map.`);
|
||||
|
||||
export const VIRTUAL_TRAIL =
|
||||
trim(`Display a virtual trail for FarmBot in the garden map to show
|
||||
movement and watering history while the map is open. Toggling this setting
|
||||
will clear data for the current trail.`);
|
||||
|
||||
export const DYNAMIC_MAP_SIZE =
|
||||
trim(`Change the garden map size based on axis length.
|
||||
A value must be input in AXIS LENGTH and STOP AT MAX must be enabled in
|
||||
the HARDWARE widget. Overrides MAP SIZE values.`);
|
||||
|
||||
export const MAP_SIZE =
|
||||
trim(`Specify custom map dimensions (in millimeters).
|
||||
|
@ -572,13 +602,41 @@ export namespace Content {
|
|||
export const CONFIRM_PLANT_DELETION =
|
||||
trim(`Show a confirmation dialog when deleting a plant.`);
|
||||
|
||||
// Device
|
||||
export const NOT_HTTPS =
|
||||
trim(`WARNING: Sending passwords via HTTP:// is not secure.`);
|
||||
// FarmBot OS Settings
|
||||
export const DIFFERENT_TZ_WARNING =
|
||||
trim(`Note: The selected timezone for your FarmBot is different than
|
||||
your local browser time.`);
|
||||
|
||||
export const CONTACT_SYSADMIN =
|
||||
trim(`Please contact the system(s) administrator(s) and ask them to enable
|
||||
HTTPS://`);
|
||||
export const OS_BETA_RELEASES =
|
||||
trim(`Warning! Leaving the stable FarmBot OS release channel may reduce
|
||||
FarmBot system stability. Are you sure?`);
|
||||
|
||||
export const DEVICE_NEVER_SEEN =
|
||||
trim(`The device has never been seen. Most likely,
|
||||
there is a network connectivity issue on the device's end.`);
|
||||
|
||||
export const TOO_OLD_TO_UPDATE =
|
||||
trim(`Please re-flash your FarmBot's SD card.`);
|
||||
|
||||
export const OS_AUTO_UPDATE =
|
||||
trim(`When enabled, FarmBot OS will automatically download and install
|
||||
software updates at the chosen time.`);
|
||||
|
||||
export const AUTO_SYNC =
|
||||
trim(`When enabled, device resources such as sequences and regimens
|
||||
will be sent to the device automatically. This removes the need to push
|
||||
"SYNC" after making changes in the web app. Changes to running
|
||||
sequences and regimens while auto sync is enabled will result in
|
||||
instantaneous change.`);
|
||||
|
||||
// FarmBot OS Settings: Power and Reset
|
||||
export const RESTART_FARMBOT =
|
||||
trim(`This will restart FarmBot's Raspberry Pi and controller
|
||||
software.`);
|
||||
|
||||
export const SHUTDOWN_FARMBOT =
|
||||
trim(`This will shutdown FarmBot's Raspberry Pi. To turn it
|
||||
back on, unplug FarmBot and plug it back in.`);
|
||||
|
||||
export const FACTORY_RESET_WARNING =
|
||||
trim(`Factory resetting your FarmBot will destroy all data on the device,
|
||||
|
@ -596,10 +654,6 @@ export namespace Content {
|
|||
not delete data stored in your web app account. Are you sure you wish
|
||||
to continue?`);
|
||||
|
||||
export const MCU_RESET_ALERT =
|
||||
trim(`Warning: This will reset all hardware settings to the default values.
|
||||
Are you sure you wish to continue?`);
|
||||
|
||||
export const AUTO_FACTORY_RESET =
|
||||
trim(`Automatically factory reset when the WiFi network cannot be
|
||||
detected. Useful for network changes.`);
|
||||
|
@ -608,54 +662,26 @@ export namespace Content {
|
|||
trim(`Time in minutes to attempt connecting to WiFi before a factory
|
||||
reset.`);
|
||||
|
||||
export const DIFFERENT_TZ_WARNING =
|
||||
trim(`Note: The selected timezone for your FarmBot is different than
|
||||
your local browser time.`);
|
||||
export const NOT_HTTPS =
|
||||
trim(`WARNING: Sending passwords via HTTP:// is not secure.`);
|
||||
|
||||
export const RESTART_FARMBOT =
|
||||
trim(`This will restart FarmBot's Raspberry Pi and controller
|
||||
software.`);
|
||||
export const CONTACT_SYSADMIN =
|
||||
trim(`Please contact the system(s) administrator(s) and ask them to enable
|
||||
HTTPS://`);
|
||||
|
||||
// FarmBot OS Settings: Firmware
|
||||
export const RESTART_FIRMWARE =
|
||||
trim(`Restart the Farmduino or Arduino firmware.`);
|
||||
|
||||
export const OS_AUTO_UPDATE =
|
||||
trim(`When enabled, FarmBot OS will periodically check for, download,
|
||||
and install updates automatically.`);
|
||||
|
||||
export const AUTO_SYNC =
|
||||
trim(`When enabled, device resources such as sequences and regimens
|
||||
will be sent to the device automatically. This removes the need to push
|
||||
"SYNC" after making changes in the web app. Changes to running
|
||||
sequences and regimens while auto sync is enabled will result in
|
||||
instantaneous change.`);
|
||||
|
||||
export const SHUTDOWN_FARMBOT =
|
||||
trim(`This will shutdown FarmBot's Raspberry Pi. To turn it
|
||||
back on, unplug FarmBot and plug it back in.`);
|
||||
|
||||
export const OS_BETA_RELEASES =
|
||||
trim(`Warning! Opting in to FarmBot OS beta releases may reduce
|
||||
FarmBot system stability. Are you sure?`);
|
||||
|
||||
export const DIAGNOSTIC_CHECK =
|
||||
trim(`Save snapshot of FarmBot OS system information, including
|
||||
user and device identity, to the database. A code will be returned
|
||||
that you can provide in support requests to allow FarmBot to look up
|
||||
data relevant to the issue to help us identify the problem.`);
|
||||
|
||||
export const DEVICE_NEVER_SEEN =
|
||||
trim(`The device has never been seen. Most likely,
|
||||
there is a network connectivity issue on the device's end.`);
|
||||
|
||||
export const TOO_OLD_TO_UPDATE =
|
||||
trim(`Please re-flash your FarmBot's SD card.`);
|
||||
|
||||
// Hardware Settings
|
||||
// Hardware Settings: Danger Zone
|
||||
export const RESTORE_DEFAULT_HARDWARE_SETTINGS =
|
||||
trim(`Restoring hardware parameter defaults will destroy the
|
||||
current settings, resetting them to default values.`);
|
||||
|
||||
export const MCU_RESET_ALERT =
|
||||
trim(`Warning: This will reset all hardware settings to the default values.
|
||||
Are you sure you wish to continue?`);
|
||||
|
||||
// App
|
||||
export const APP_LOAD_TIMEOUT_MESSAGE =
|
||||
trim(`App could not be fully loaded, we recommend you try
|
||||
|
@ -674,19 +700,15 @@ export namespace Content {
|
|||
trim(`FarmBot sent a malformed message. You may need to upgrade
|
||||
FarmBot OS. Please upgrade FarmBot OS and log back in.`);
|
||||
|
||||
export const OLD_FBOS_REC_UPGRADE = trim(`Your version of FarmBot OS is
|
||||
outdated and will soon no longer be supported. Please update your device as
|
||||
soon as possible.`);
|
||||
export const OLD_FBOS_REC_UPGRADE =
|
||||
trim(`Your version of FarmBot OS is outdated and will soon no longer
|
||||
be supported. Please update your device as soon as possible.`);
|
||||
|
||||
export const EXPERIMENTAL_WARNING =
|
||||
trim(`Warning! This is an EXPERIMENTAL feature. This feature may be
|
||||
broken and may break or otherwise hinder your usage of the rest of the
|
||||
app. This feature may disappear or break at any time.`);
|
||||
|
||||
export const NEW_TOS =
|
||||
trim(`Before logging in, you must agree to our latest Terms of Service and
|
||||
Privacy Policy`);
|
||||
|
||||
export const FORCE_REFRESH_CONFIRM =
|
||||
trim(`A new version of the FarmBot web app has been released.
|
||||
Refresh page?`);
|
||||
|
@ -715,8 +737,17 @@ export namespace Content {
|
|||
|
||||
export const END_DETECTION_DISABLED =
|
||||
trim(`This command will not execute correctly because you do not have
|
||||
encoders or endstops enabled for the chosen axis. Enable endstops or
|
||||
encoders from the Device page for: `);
|
||||
encoders, stall detection, or endstops enabled for the chosen axis.
|
||||
Enable endstops, encoders, or stall detection from the Device page for: `);
|
||||
|
||||
export const REBOOT_STEP =
|
||||
trim(`Power cycle FarmBot's onboard computer.`);
|
||||
|
||||
export const SHUTDOWN_STEP =
|
||||
trim(`Power down FarmBot's onboard computer.`);
|
||||
|
||||
export const ESTOP_STEP =
|
||||
trim(`Unlocking a device requires user intervention.`);
|
||||
|
||||
export const IN_USE =
|
||||
trim(`Used in another resource. Protected from deletion.`);
|
||||
|
@ -745,7 +776,7 @@ export namespace Content {
|
|||
trim(`Click and drag or use the inputs to draw a weed.`);
|
||||
|
||||
export const BOX_SELECT_DESCRIPTION =
|
||||
trim(`Drag a box around the plants you would like to select.
|
||||
trim(`Drag a box around the items you would like to select.
|
||||
Press the back arrow to exit.`);
|
||||
|
||||
export const SAVED_GARDENS =
|
||||
|
@ -784,11 +815,15 @@ export namespace Content {
|
|||
trim(`add this crop on OpenFarm?`);
|
||||
|
||||
export const NO_TOOLS =
|
||||
trim(`Press "+" to add a new tool.`);
|
||||
trim(`Press "+" to add a new tool or seed container.`);
|
||||
|
||||
export const NO_SEED_CONTAINERS =
|
||||
trim(`Press "+" to add a seed container.`);
|
||||
|
||||
export const MOUNTED_TOOL =
|
||||
trim(`The tool currently mounted to the UTM can be set here or by using
|
||||
a MARK AS step in a sequence.`);
|
||||
a MARK AS step in a sequence. Use the verify button or read the tool
|
||||
verification pin in a sequence to verify that a tool is attached.`);
|
||||
|
||||
// Farm Events
|
||||
export const NOTHING_SCHEDULED =
|
||||
|
@ -800,10 +835,6 @@ export namespace Content {
|
|||
regimen tasks. Consider rescheduling this event to tomorrow if
|
||||
this is a concern.`);
|
||||
|
||||
export const INVALID_RUN_TIME =
|
||||
trim(`This event does not appear to have a valid run time.
|
||||
Perhaps you entered bad dates?`);
|
||||
|
||||
export const FARM_EVENT_TZ_WARNING =
|
||||
trim(`Note: Times displayed according to FarmBot's local time, which
|
||||
is currently different from your browser's time. Timezone data is
|
||||
|
@ -818,27 +849,14 @@ export namespace Content {
|
|||
trim(`You haven't made any sequences or regimens yet. To add an event,
|
||||
first create a sequence or regimen.`);
|
||||
|
||||
// Groups
|
||||
export const SORT_DESCRIPTION =
|
||||
trim(`When executing a sequence over a Group of locations, FarmBot will
|
||||
travel to each group member in the order of the chosen sort method.
|
||||
If the random option is chosen, FarmBot will travel in a random order
|
||||
every time, so the ordering shown below will only be representative.`);
|
||||
|
||||
export const CRITERIA_SELECTION_COUNT =
|
||||
trim(`Criteria additions can only be removed by changing criteria.
|
||||
Click and drag in the map to modify zone selection criteria.
|
||||
Criteria will be applied at the time of sequence execution. The final
|
||||
selection at that time may differ from the selection currently
|
||||
displayed.`);
|
||||
|
||||
// Farmware
|
||||
export const NO_IMAGES_YET =
|
||||
trim(`You haven't yet taken any photos with your FarmBot.
|
||||
Once you do, they will show up here.`);
|
||||
|
||||
export const PROCESSING_PHOTO =
|
||||
trim(`Processing now. Results usually available in one minute.`);
|
||||
trim(`Processing now. Results usually available in one minute.
|
||||
Check log messages for result status.`);
|
||||
|
||||
export const NOT_AVAILABLE_WHEN_OFFLINE =
|
||||
trim(`Not available when device is offline.`);
|
||||
|
@ -859,12 +877,23 @@ export namespace TourContent {
|
|||
selecting one, and dragging it into the garden.`);
|
||||
|
||||
export const ADD_TOOLS =
|
||||
trim(`Press edit and then the + button to add tools and seed containers.`);
|
||||
trim(`Press the + button to add tools and seed containers.`);
|
||||
|
||||
export const ADD_SEED_CONTAINERS =
|
||||
trim(`Press the + button to add seed containers.`);
|
||||
|
||||
export const ADD_TOOLS_AND_SLOTS =
|
||||
trim(`Press the + button to add tools and seed containers. Then create
|
||||
slots for them to by pressing the slot + button.`);
|
||||
|
||||
export const ADD_SEED_CONTAINERS_AND_SLOTS =
|
||||
trim(`Press the + button to add seed containers. Then create
|
||||
slots for them to by pressing the slot + button.`);
|
||||
|
||||
export const ADD_TOOLS_SLOTS =
|
||||
trim(`Add the newly created tools and seed containers to the
|
||||
corresponding tool slots on FarmBot:
|
||||
press edit and then + to create a tool slot.`);
|
||||
corresponding slots on FarmBot:
|
||||
press the + button to create a slot.`);
|
||||
|
||||
export const ADD_PERIPHERALS =
|
||||
trim(`Press edit and then the + button to add peripherals.`);
|
||||
|
@ -902,6 +931,112 @@ export namespace TourContent {
|
|||
trim(`Toggle various settings to customize your web app experience.`);
|
||||
}
|
||||
|
||||
export enum DeviceSetting {
|
||||
axisHeadingLabels = ``,
|
||||
|
||||
// Homing and calibration
|
||||
homingAndCalibration = `Homing and Calibration`,
|
||||
homing = `Homing`,
|
||||
calibration = `Calibration`,
|
||||
setZeroPosition = `Set Zero Position`,
|
||||
findHomeOnBoot = `Find Home on Boot`,
|
||||
stopAtHome = `Stop at Home`,
|
||||
stopAtMax = `Stop at Max`,
|
||||
negativeCoordinatesOnly = `Negative Coordinates Only`,
|
||||
axisLength = `Axis Length (mm)`,
|
||||
|
||||
// Motors
|
||||
motors = `Motors`,
|
||||
maxSpeed = `Max Speed (mm/s)`,
|
||||
homingSpeed = `Homing Speed (mm/s)`,
|
||||
minimumSpeed = `Minimum Speed (mm/s)`,
|
||||
accelerateFor = `Accelerate for (mm)`,
|
||||
stepsPerMm = `Steps per MM`,
|
||||
microstepsPerStep = `Microsteps per step`,
|
||||
alwaysPowerMotors = `Always Power Motors`,
|
||||
invertMotors = `Invert Motors`,
|
||||
motorCurrent = `Motor Current`,
|
||||
enable2ndXMotor = `Enable 2nd X Motor`,
|
||||
invert2ndXMotor = `Invert 2nd X Motor`,
|
||||
|
||||
// Encoders / Stall Detection
|
||||
encoders = `Encoders`,
|
||||
stallDetection = `Stall Detection`,
|
||||
enableEncoders = `Enable Encoders`,
|
||||
enableStallDetection = `Enable Stall Detection`,
|
||||
stallSensitivity = `Stall Sensitivity`,
|
||||
useEncodersForPositioning = `Use Encoders for Positioning`,
|
||||
invertEncoders = `Invert Encoders`,
|
||||
maxMissedSteps = `Max Missed Steps`,
|
||||
missedStepDecay = `Missed Step Decay`,
|
||||
encoderScaling = `Encoder Scaling`,
|
||||
|
||||
// Endstops
|
||||
endstops = `Endstops`,
|
||||
enableEndstops = `Enable Endstops`,
|
||||
swapEndstops = `Swap Endstops`,
|
||||
invertEndstops = `Invert Endstops`,
|
||||
|
||||
// Error handling
|
||||
errorHandling = `Error Handling`,
|
||||
timeoutAfter = `Timeout after (seconds)`,
|
||||
maxRetries = `Max Retries`,
|
||||
estopOnMovementError = `E-Stop on Movement Error`,
|
||||
|
||||
// Pin Guard
|
||||
pinGuard = `Pin Guard`,
|
||||
pinGuard1 = `Pin Guard 1`,
|
||||
pinGuard2 = `Pin Guard 2`,
|
||||
pinGuard3 = `Pin Guard 3`,
|
||||
pinGuard4 = `Pin Guard 4`,
|
||||
pinGuard5 = `Pin Guard 5`,
|
||||
|
||||
// Danger Zone
|
||||
dangerZone = `Danger Zone`,
|
||||
resetHardwareParams = `Reset hardware parameter defaults`,
|
||||
|
||||
// Pin Bindings
|
||||
pinBindings = `Pin Bindings`,
|
||||
savedPinBindings = `Saved pin bindings`,
|
||||
addNewPinBinding = `Add new pin binding`,
|
||||
|
||||
// FarmBot OS
|
||||
farmbot = `FarmBot`,
|
||||
name = `name`,
|
||||
timezone = `timezone`,
|
||||
camera = `camera`,
|
||||
firmware = `Firmware`,
|
||||
applySoftwareUpdates = `update time`,
|
||||
farmbotOSAutoUpdate = `auto update`,
|
||||
farmbotOS = `Farmbot OS`,
|
||||
autoSync = `Auto Sync`,
|
||||
bootSequence = `Boot Sequence`,
|
||||
|
||||
// Power and Reset
|
||||
powerAndReset = `Power and Reset`,
|
||||
restartFarmbot = `Restart Farmbot`,
|
||||
shutdownFarmbot = `Shutdown Farmbot`,
|
||||
factoryReset = `Factory Reset`,
|
||||
autoFactoryReset = `Automatic Factory Reset`,
|
||||
connectionAttemptPeriod = `Connection Attempt Period`,
|
||||
changeOwnership = `Change Ownership`,
|
||||
|
||||
// Farm Designer
|
||||
farmDesigner = `Farm Designer`,
|
||||
animations = `Plant animations`,
|
||||
trail = `Virtual FarmBot trail`,
|
||||
dynamicMap = `Dynamic map size`,
|
||||
mapSize = `Map size`,
|
||||
rotateMap = `Rotate map`,
|
||||
mapOrigin = `Map origin`,
|
||||
confirmPlantDeletion = `Confirm plant deletion`,
|
||||
|
||||
// Firmware
|
||||
firmwareSection = `Firmware`,
|
||||
restartFirmware = `Restart Firmware`,
|
||||
flashFirmware = `Flash firmware`,
|
||||
}
|
||||
|
||||
export namespace DiagnosticMessages {
|
||||
export const OK = trim(`All systems nominal.`);
|
||||
|
||||
|
@ -924,8 +1059,7 @@ export namespace DiagnosticMessages {
|
|||
but we have no recent record of FarmBot connecting to the internet.
|
||||
This usually happens because of poor WiFi connectivity in the garden,
|
||||
a bad password during configuration, a very long power outage, or
|
||||
blocked ports on FarmBot's local network. Please refer IT staff to
|
||||
https://software.farm.bot/docs/for-it-security-professionals`);
|
||||
blocked ports on FarmBot's local network. Please refer IT staff to:`);
|
||||
|
||||
export const NO_WS_AVAILABLE = trim(`You are either offline, using a web
|
||||
browser that does not support WebSockets, or are behind a firewall that
|
||||
|
@ -989,6 +1123,8 @@ export enum Actions {
|
|||
FETCH_BETA_OS_UPDATE_INFO_ERROR = "FETCH_BETA_OS_UPDATE_INFO_ERROR",
|
||||
FETCH_MIN_OS_FEATURE_INFO_OK = "FETCH_MIN_OS_FEATURE_INFO_OK",
|
||||
FETCH_MIN_OS_FEATURE_INFO_ERROR = "FETCH_MIN_OS_FEATURE_INFO_ERROR",
|
||||
FETCH_OS_RELEASE_NOTES_OK = "FETCH_OS_RELEASE_NOTES_OK",
|
||||
FETCH_OS_RELEASE_NOTES_ERROR = "FETCH_OS_RELEASE_NOTES_ERROR",
|
||||
INVERT_JOG_BUTTON = "INVERT_JOG_BUTTON",
|
||||
DISPLAY_ENCODER_DATA = "DISPLAY_ENCODER_DATA",
|
||||
STASH_STATUS = "STASH_STATUS",
|
||||
|
@ -999,7 +1135,8 @@ export enum Actions {
|
|||
|
||||
// Designer
|
||||
SEARCH_QUERY_CHANGE = "SEARCH_QUERY_CHANGE",
|
||||
SELECT_PLANT = "SELECT_PLANT",
|
||||
SELECT_POINT = "SELECT_POINT",
|
||||
SET_SELECTION_POINT_TYPE = "SET_SELECTION_POINT_TYPE",
|
||||
TOGGLE_HOVERED_PLANT = "TOGGLE_HOVERED_PLANT",
|
||||
TOGGLE_HOVERED_POINT = "TOGGLE_HOVERED_POINT",
|
||||
HOVER_PLANT_LIST_ITEM = "HOVER_PLANT_LIST_ITEM",
|
||||
|
@ -1008,9 +1145,12 @@ export enum Actions {
|
|||
OF_SEARCH_RESULTS_OK = "OF_SEARCH_RESULTS_OK",
|
||||
OF_SEARCH_RESULTS_NO = "OF_SEARCH_RESULTS_NO",
|
||||
CHOOSE_LOCATION = "CHOOSE_LOCATION",
|
||||
SET_CURRENT_POINT_DATA = "SET_CURRENT_POINT_DATA",
|
||||
SET_DRAWN_POINT_DATA = "SET_DRAWN_POINT_DATA",
|
||||
SET_DRAWN_WEED_DATA = "SET_DRAWN_WEED_DATA",
|
||||
CHOOSE_SAVED_GARDEN = "CHOOSE_SAVED_GARDEN",
|
||||
TRY_SORT_TYPE = "TRY_SORT_TYPE",
|
||||
SET_SETTINGS_SEARCH_TERM = "SET_SETTINGS_SEARCH_TERM",
|
||||
EDIT_GROUP_AREA_IN_MAP = "EDIT_GROUP_AREA_IN_MAP",
|
||||
|
||||
// Regimens
|
||||
PUSH_WEEK = "PUSH_WEEK",
|
||||
|
|
|
@ -3,7 +3,7 @@ import { mount } from "enzyme";
|
|||
import { RawControls as Controls } from "../controls";
|
||||
import { bot } from "../../__test_support__/fake_state/bot";
|
||||
import {
|
||||
fakePeripheral, fakeWebcamFeed, fakeSensor
|
||||
fakePeripheral, fakeWebcamFeed, fakeSensor,
|
||||
} from "../../__test_support__/fake_state/resources";
|
||||
import { Dictionary } from "farmbot";
|
||||
import { Props } from "../interfaces";
|
||||
|
@ -18,10 +18,9 @@ describe("<Controls />", () => {
|
|||
feeds: [fakeWebcamFeed()],
|
||||
peripherals: [fakePeripheral()],
|
||||
sensors: [fakeSensor()],
|
||||
botToMqttStatus: "up",
|
||||
firmwareSettings: bot.hardware.mcu_params,
|
||||
shouldDisplay: () => true,
|
||||
getWebAppConfigVal: jest.fn((key) => (mockConfig[key])),
|
||||
getWebAppConfigVal: jest.fn(key => mockConfig[key]),
|
||||
sensorReadings: [],
|
||||
timeSettings: fakeTimeSettings(),
|
||||
env: {},
|
||||
|
@ -65,6 +64,17 @@ describe("<Controls />", () => {
|
|||
.map(string => expect(txt).not.toContain(string));
|
||||
});
|
||||
|
||||
it("hides sensors widget based on model", () => {
|
||||
mockConfig.hide_sensors = false;
|
||||
const p = fakeProps();
|
||||
p.firmwareHardware = "express_k10";
|
||||
const wrapper = mount(<Controls {...p} />);
|
||||
const txt = wrapper.text().toLowerCase();
|
||||
["move", "peripherals"]
|
||||
.map(string => expect(txt).toContain(string));
|
||||
["sensors"].map(string => expect(txt).not.toContain(string));
|
||||
});
|
||||
|
||||
it("doesn't show sensor readings widget", () => {
|
||||
const p = fakeProps();
|
||||
mockConfig.hide_sensors = true;
|
||||
|
|
|
@ -3,17 +3,19 @@ import { Row, Col } from "../ui/index";
|
|||
import { AxisDisplayGroupProps } from "./interfaces";
|
||||
import { isNumber } from "lodash";
|
||||
import { t } from "../i18next_wrapper";
|
||||
import { Xyz } from "farmbot";
|
||||
|
||||
const Axis = ({ val }: { val: number | undefined }) => <Col xs={3}>
|
||||
<input disabled value={isNumber(val) ? val : "---"} />
|
||||
</Col>;
|
||||
const Axis = ({ axis, val }: { val: number | undefined, axis: Xyz }) =>
|
||||
<Col xs={3}>
|
||||
<input disabled name={axis} value={isNumber(val) ? val : "---"} />
|
||||
</Col>;
|
||||
|
||||
export const AxisDisplayGroup = ({ position, label }: AxisDisplayGroupProps) => {
|
||||
const { x, y, z } = position;
|
||||
return <Row>
|
||||
<Axis val={x} />
|
||||
<Axis val={y} />
|
||||
<Axis val={z} />
|
||||
<Axis axis={"x"} val={x} />
|
||||
<Axis axis={"y"} val={y} />
|
||||
<Axis axis={"z"} val={z} />
|
||||
<Col xs={3}>
|
||||
<label>
|
||||
{t(label)}
|
||||
|
|
|
@ -9,7 +9,8 @@ import { Props } from "./interfaces";
|
|||
import { Move } from "./move/move";
|
||||
import { BooleanSetting } from "../session_keys";
|
||||
import { SensorReadings } from "./sensor_readings/sensor_readings";
|
||||
import { isBotOnline } from "../devices/must_be_online";
|
||||
import { isBotOnlineFromState } from "../devices/must_be_online";
|
||||
import { hasSensors } from "../devices/components/firmware_hardware_support";
|
||||
|
||||
/** Controls page. */
|
||||
export class RawControls extends React.Component<Props, {}> {
|
||||
|
@ -18,13 +19,12 @@ export class RawControls extends React.Component<Props, {}> {
|
|||
}
|
||||
|
||||
get botOnline() {
|
||||
return isBotOnline(
|
||||
this.props.bot.hardware.informational_settings.sync_status,
|
||||
this.props.botToMqttStatus);
|
||||
return isBotOnlineFromState(this.props.bot);
|
||||
}
|
||||
|
||||
get hideSensors() {
|
||||
return this.props.getWebAppConfigVal(BooleanSetting.hide_sensors);
|
||||
return this.props.getWebAppConfigVal(BooleanSetting.hide_sensors)
|
||||
|| !hasSensors(this.props.firmwareHardware);
|
||||
}
|
||||
|
||||
move = () => <Move
|
||||
|
@ -32,12 +32,12 @@ export class RawControls extends React.Component<Props, {}> {
|
|||
env={this.props.env}
|
||||
dispatch={this.props.dispatch}
|
||||
arduinoBusy={this.arduinoBusy}
|
||||
botToMqttStatus={this.props.botToMqttStatus}
|
||||
firmwareSettings={this.props.firmwareSettings}
|
||||
firmwareHardware={this.props.firmwareHardware}
|
||||
getWebAppConfigVal={this.props.getWebAppConfigVal} />
|
||||
|
||||
peripherals = () => <Peripherals
|
||||
firmwareHardware={this.props.firmwareHardware}
|
||||
bot={this.props.bot}
|
||||
peripherals={this.props.peripherals}
|
||||
dispatch={this.props.dispatch}
|
||||
|
@ -50,6 +50,7 @@ export class RawControls extends React.Component<Props, {}> {
|
|||
sensors = () => this.hideSensors
|
||||
? <div id="hidden-sensors-widget" />
|
||||
: <Sensors
|
||||
firmwareHardware={this.props.firmwareHardware}
|
||||
bot={this.props.bot}
|
||||
sensors={this.props.sensors}
|
||||
dispatch={this.props.dispatch}
|
||||
|
|
|
@ -1,14 +1,13 @@
|
|||
import {
|
||||
BotState, Xyz, BotPosition, ShouldDisplay, UserEnv
|
||||
BotState, Xyz, BotPosition, ShouldDisplay, UserEnv,
|
||||
} from "../devices/interfaces";
|
||||
import { Vector3, McuParams, FirmwareHardware } from "farmbot/dist";
|
||||
import {
|
||||
TaggedWebcamFeed,
|
||||
TaggedPeripheral,
|
||||
TaggedSensor,
|
||||
TaggedSensorReading
|
||||
TaggedSensorReading,
|
||||
} from "farmbot";
|
||||
import { NetworkState } from "../connectivity/interfaces";
|
||||
import { GetWebAppConfigValue } from "../config_storage/actions";
|
||||
import { TimeSettings } from "../interfaces";
|
||||
|
||||
|
@ -18,7 +17,6 @@ export interface Props {
|
|||
feeds: TaggedWebcamFeed[];
|
||||
peripherals: TaggedPeripheral[];
|
||||
sensors: TaggedSensor[];
|
||||
botToMqttStatus: NetworkState;
|
||||
firmwareSettings: McuParams;
|
||||
shouldDisplay: ShouldDisplay;
|
||||
getWebAppConfigVal: GetWebAppConfigValue;
|
||||
|
@ -60,4 +58,5 @@ export interface ToggleButtonProps {
|
|||
dim?: boolean;
|
||||
grayscale?: boolean;
|
||||
title?: string;
|
||||
className?: string;
|
||||
}
|
||||
|
|
|
@ -15,12 +15,14 @@ export function KeyValEditRow(p: Props) {
|
|||
return <Row>
|
||||
<Col xs={6}>
|
||||
<input type="text"
|
||||
name="label"
|
||||
placeholder={p.labelPlaceholder}
|
||||
value={p.label}
|
||||
onChange={p.onLabelChange} />
|
||||
</Col>
|
||||
<Col xs={4}>
|
||||
<input type={p.valueType}
|
||||
name="value"
|
||||
value={p.value}
|
||||
placeholder={p.valuePlaceholder}
|
||||
onChange={p.onValueChange} />
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import {
|
||||
calcMicrostepsPerMm, calculateAxialLengths
|
||||
calcMicrostepsPerMm, calculateAxialLengths,
|
||||
} from "../direction_axes_props";
|
||||
import { fakeFirmwareConfig } from "../../../__test_support__/fake_state/resources";
|
||||
|
||||
|
|
|
@ -9,7 +9,7 @@ jest.mock("../../../device", () => ({
|
|||
import * as React from "react";
|
||||
import { mount } from "enzyme";
|
||||
import {
|
||||
DirectionButton, directionDisabled, calculateDistance
|
||||
DirectionButton, directionDisabled, calculateDistance,
|
||||
} from "../direction_button";
|
||||
import { DirectionButtonProps } from "../interfaces";
|
||||
|
||||
|
|
|
@ -29,7 +29,6 @@ describe("<Move />", () => {
|
|||
dispatch: jest.fn(),
|
||||
bot: bot,
|
||||
arduinoBusy: false,
|
||||
botToMqttStatus: "up",
|
||||
firmwareSettings: bot.hardware.mcu_params,
|
||||
getWebAppConfigVal: jest.fn((key) => (mockConfig[key])),
|
||||
env: {},
|
||||
|
|
|
@ -9,7 +9,7 @@ import * as React from "react";
|
|||
import { mount } from "enzyme";
|
||||
import { BooleanSetting } from "../../../session_keys";
|
||||
import {
|
||||
moveWidgetSetting, MoveWidgetSettingsMenu, MoveWidgetSettingsMenuProps
|
||||
moveWidgetSetting, MoveWidgetSettingsMenu, MoveWidgetSettingsMenuProps,
|
||||
} from "../settings_menu";
|
||||
|
||||
describe("moveWidgetSetting()", () => {
|
||||
|
|
|
@ -7,7 +7,7 @@ import { AxisInputBoxGroup } from "../axis_input_box_group";
|
|||
import { GetWebAppBool } from "./interfaces";
|
||||
import { BooleanSetting } from "../../session_keys";
|
||||
import { t } from "../../i18next_wrapper";
|
||||
import { isExpressBoard } from "../../devices/components/firmware_hardware_support";
|
||||
import { hasEncoders } from "../../devices/components/firmware_hardware_support";
|
||||
import { FirmwareHardware } from "farmbot";
|
||||
|
||||
export interface BotPositionRowsProps {
|
||||
|
@ -19,7 +19,7 @@ export interface BotPositionRowsProps {
|
|||
|
||||
export const BotPositionRows = (props: BotPositionRowsProps) => {
|
||||
const { locationData, getValue, arduinoBusy } = props;
|
||||
return <div>
|
||||
return <div className={"bot-position-rows"}>
|
||||
<Row>
|
||||
<Col xs={3}>
|
||||
<label>{t("X AXIS")}</label>
|
||||
|
@ -34,12 +34,12 @@ export const BotPositionRows = (props: BotPositionRowsProps) => {
|
|||
<AxisDisplayGroup
|
||||
position={locationData.position}
|
||||
label={t("Motor Coordinates (mm)")} />
|
||||
{!isExpressBoard(props.firmwareHardware) &&
|
||||
{hasEncoders(props.firmwareHardware) &&
|
||||
getValue(BooleanSetting.scaled_encoders) &&
|
||||
<AxisDisplayGroup
|
||||
position={locationData.scaled_encoders}
|
||||
label={t("Scaled Encoder (mm)")} />}
|
||||
{!isExpressBoard(props.firmwareHardware) &&
|
||||
{hasEncoders(props.firmwareHardware) &&
|
||||
getValue(BooleanSetting.raw_encoders) &&
|
||||
<AxisDisplayGroup
|
||||
position={locationData.raw_encoders}
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
import { BotPosition, BotState, UserEnv } from "../../devices/interfaces";
|
||||
import { McuParams, Xyz, FirmwareHardware } from "farmbot";
|
||||
import { NetworkState } from "../../connectivity/interfaces";
|
||||
import { GetWebAppConfigValue } from "../../config_storage/actions";
|
||||
import { BooleanConfigKey } from "farmbot/dist/resources/configs/web_app";
|
||||
|
||||
|
@ -11,7 +10,6 @@ export interface MoveProps {
|
|||
dispatch: Function;
|
||||
bot: BotState;
|
||||
arduinoBusy: boolean;
|
||||
botToMqttStatus: NetworkState;
|
||||
firmwareSettings: McuParams;
|
||||
getWebAppConfigVal: GetWebAppConfigValue;
|
||||
env: UserEnv;
|
||||
|
|
|
@ -6,7 +6,7 @@ import { getDevice } from "../../device";
|
|||
import { buildDirectionProps } from "./direction_axes_props";
|
||||
import { t } from "../../i18next_wrapper";
|
||||
import {
|
||||
cameraBtnProps
|
||||
cameraBtnProps,
|
||||
} from "../../devices/components/fbos_settings/camera_selection";
|
||||
const DEFAULT_STEP_SIZE = 100;
|
||||
|
||||
|
|
|
@ -22,7 +22,7 @@ export const JogControlsGroup = (props: JogControlsGroupProps) => {
|
|||
const {
|
||||
dispatch, stepSize, botPosition, getValue, arduinoBusy, firmwareSettings
|
||||
} = props;
|
||||
return <div>
|
||||
return <div className={"jog-controls-group"}>
|
||||
<label className="text-center">
|
||||
{t("MOVE AMOUNT (mm)")}
|
||||
</label>
|
||||
|
|
|
@ -4,7 +4,7 @@ import moment from "moment";
|
|||
import { BotLocationData, BotPosition } from "../../devices/interfaces";
|
||||
import { trim } from "../../util";
|
||||
import {
|
||||
cloneDeep, max, get, isNumber, isEqual, takeRight, ceil, range
|
||||
cloneDeep, max, get, isNumber, isEqual, takeRight, ceil, range,
|
||||
} from "lodash";
|
||||
import { t } from "../../i18next_wrapper";
|
||||
|
||||
|
@ -46,9 +46,9 @@ const getLastEntry = (): Entry | undefined => {
|
|||
const findYLimit = (): number => {
|
||||
const array = getArray();
|
||||
const arrayAbsMax = max(array.map(entry =>
|
||||
max(["position", "scaled_encoders"].map((name: LocationName) =>
|
||||
max(["position", "scaled_encoders"].map((key: LocationName) =>
|
||||
max(["x", "y", "z"].map((axis: Xyz) =>
|
||||
Math.abs(entry.locationData[name][axis] || 0) + 1))))));
|
||||
Math.abs(entry.locationData[key][axis] || 0) + 1))))));
|
||||
return Math.max(ceil(arrayAbsMax || 0, -2), DEFAULT_Y_MAX);
|
||||
};
|
||||
|
||||
|
@ -80,19 +80,19 @@ const getPaths = (): Paths => {
|
|||
const paths = newPaths();
|
||||
if (last) {
|
||||
getReversedArray().map(entry => {
|
||||
["position", "scaled_encoders"].map((name: LocationName) => {
|
||||
["position", "scaled_encoders"].map((key: LocationName) => {
|
||||
["x", "y", "z"].map((axis: Xyz) => {
|
||||
const lastPos = last.locationData[name][axis];
|
||||
const pos = entry.locationData[name][axis];
|
||||
const lastPos = last.locationData[key][axis];
|
||||
const pos = entry.locationData[key][axis];
|
||||
if (isNumber(lastPos) && isFinite(lastPos)
|
||||
&& isNumber(maxY) && isNumber(pos)) {
|
||||
if (!paths[name][axis].startsWith("M")) {
|
||||
if (!paths[key][axis].startsWith("M")) {
|
||||
const yStart = -lastPos / maxY * HEIGHT / 2;
|
||||
paths[name][axis] = `M ${MAX_X},${yStart} `;
|
||||
paths[key][axis] = `M ${MAX_X},${yStart} `;
|
||||
}
|
||||
const x = MAX_X - (last.timestamp - entry.timestamp);
|
||||
const y = -pos / maxY * HEIGHT / 2;
|
||||
paths[name][axis] += `L ${x},${y} `;
|
||||
paths[key][axis] += `L ${x},${y} `;
|
||||
}
|
||||
});
|
||||
});
|
||||
|
@ -154,12 +154,12 @@ const PlotLines = ({ locationData }: { locationData: BotLocationData }) => {
|
|||
updateArray({ timestamp: moment().unix(), locationData });
|
||||
const paths = getPaths();
|
||||
return <g id="plot_lines">
|
||||
{["position", "scaled_encoders"].map((name: LocationName) =>
|
||||
{["position", "scaled_encoders"].map((key: LocationName) =>
|
||||
["x", "y", "z"].map((axis: Xyz) =>
|
||||
<path key={name + axis} fill={"none"}
|
||||
stroke={COLOR_LOOKUP[axis]} strokeWidth={LINEWIDTH_LOOKUP[name]}
|
||||
<path key={key + axis} fill={"none"}
|
||||
stroke={COLOR_LOOKUP[axis]} strokeWidth={LINEWIDTH_LOOKUP[key]}
|
||||
strokeLinecap={"round"} strokeLinejoin={"round"}
|
||||
d={paths[name][axis]} />))}
|
||||
d={paths[key][axis]} />))}
|
||||
</g>;
|
||||
};
|
||||
|
||||
|
|
|
@ -13,6 +13,7 @@ import { MotorPositionPlot } from "./motor_position_plot";
|
|||
import { Popover, Position } from "@blueprintjs/core";
|
||||
import { BooleanConfigKey } from "farmbot/dist/resources/configs/web_app";
|
||||
import { t } from "../../i18next_wrapper";
|
||||
import { getStatus } from "../../connectivity/reducer_support";
|
||||
|
||||
export class Move extends React.Component<MoveProps, {}> {
|
||||
|
||||
|
@ -23,7 +24,8 @@ export class Move extends React.Component<MoveProps, {}> {
|
|||
!!this.props.getWebAppConfigVal(BooleanSetting[key]);
|
||||
|
||||
render() {
|
||||
const { location_data, informational_settings } = this.props.bot.hardware;
|
||||
const { bot } = this.props;
|
||||
const { location_data, informational_settings } = bot.hardware;
|
||||
const locationData = validBotLocationData(location_data);
|
||||
return <Widget className="move-widget">
|
||||
<WidgetHeader
|
||||
|
@ -40,11 +42,11 @@ export class Move extends React.Component<MoveProps, {}> {
|
|||
<WidgetBody>
|
||||
<MustBeOnline
|
||||
lockOpen={process.env.NODE_ENV !== "production"}
|
||||
networkState={this.props.botToMqttStatus}
|
||||
networkState={getStatus(bot.connectivity.uptime["bot.mqtt"])}
|
||||
syncStatus={informational_settings.sync_status}>
|
||||
<JogControlsGroup
|
||||
dispatch={this.props.dispatch}
|
||||
stepSize={this.props.bot.stepSize}
|
||||
stepSize={bot.stepSize}
|
||||
botPosition={locationData.position}
|
||||
getValue={this.getValue}
|
||||
arduinoBusy={this.props.arduinoBusy}
|
||||
|
|
|
@ -6,7 +6,7 @@ import { BooleanConfigKey } from "farmbot/dist/resources/configs/web_app";
|
|||
import { DevSettings } from "../../account/dev/dev_support";
|
||||
import { t } from "../../i18next_wrapper";
|
||||
import { FirmwareHardware } from "farmbot";
|
||||
import { isExpressBoard } from "../../devices/components/firmware_hardware_support";
|
||||
import { hasEncoders } from "../../devices/components/firmware_hardware_support";
|
||||
|
||||
export const moveWidgetSetting =
|
||||
(toggle: ToggleWebAppBool, getValue: GetWebAppBool) =>
|
||||
|
@ -27,7 +27,7 @@ export interface MoveWidgetSettingsMenuProps {
|
|||
}
|
||||
|
||||
export const MoveWidgetSettingsMenu = (
|
||||
{ toggle, getValue, firmwareHardware }: MoveWidgetSettingsMenuProps
|
||||
{ toggle, getValue, firmwareHardware }: MoveWidgetSettingsMenuProps,
|
||||
) => {
|
||||
const Setting = moveWidgetSetting(toggle, getValue);
|
||||
return <div className="move-settings-menu">
|
||||
|
@ -36,7 +36,7 @@ export const MoveWidgetSettingsMenu = (
|
|||
<Setting label={t("Y Axis")} setting={BooleanSetting.y_axis_inverted} />
|
||||
<Setting label={t("Z Axis")} setting={BooleanSetting.z_axis_inverted} />
|
||||
|
||||
{!isExpressBoard(firmwareHardware) &&
|
||||
{hasEncoders(firmwareHardware) &&
|
||||
<div className="display-encoder-data">
|
||||
<p>{t("Display Encoder Data")}</p>
|
||||
<Setting
|
||||
|
@ -56,7 +56,7 @@ export const MoveWidgetSettingsMenu = (
|
|||
setting={BooleanSetting.home_button_homing} />
|
||||
|
||||
{DevSettings.futureFeaturesEnabled() &&
|
||||
<div>
|
||||
<div className={"motor-position-plot-setting-row"}>
|
||||
<p>{t("Motor position plot")}</p>
|
||||
<Setting
|
||||
label={t("show")}
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue