diff --git a/app/controllers/awon_controller.rb b/.archive/app/controllers/awon_controller.rb similarity index 100% rename from app/controllers/awon_controller.rb rename to .archive/app/controllers/awon_controller.rb diff --git a/.archive/app/controllers_old/heartbeat_controller.rb b/.archive/app/controllers/heartbeat_controller.rb similarity index 100% rename from .archive/app/controllers_old/heartbeat_controller.rb rename to .archive/app/controllers/heartbeat_controller.rb diff --git a/app/helpers/awon_helper.rb b/.archive/app/helpers/awon_helper.rb similarity index 100% rename from app/helpers/awon_helper.rb rename to .archive/app/helpers/awon_helper.rb diff --git a/.archive/app/helpers_old/heartbeat_helper.rb b/.archive/app/helpers/heartbeat_helper.rb similarity index 100% rename from .archive/app/helpers_old/heartbeat_helper.rb rename to .archive/app/helpers/heartbeat_helper.rb diff --git a/.archive/app/models_old/concerns/grid_db.rb b/.archive/app/models/concerns/grid_db.rb similarity index 100% rename from .archive/app/models_old/concerns/grid_db.rb rename to .archive/app/models/concerns/grid_db.rb diff --git a/.archive/app/models_old/cranberry_product.rb b/.archive/app/models/cranberry_product.rb similarity index 100% rename from .archive/app/models_old/cranberry_product.rb rename to .archive/app/models/cranberry_product.rb diff --git a/.archive/app/models_old/grid_product.rb b/.archive/app/models/grid_product.rb similarity index 100% rename from .archive/app/models_old/grid_product.rb rename to .archive/app/models/grid_product.rb diff --git a/.archive/app/models_old/insol.rb b/.archive/app/models/insol.rb similarity index 100% rename from .archive/app/models_old/insol.rb rename to .archive/app/models/insol.rb diff --git a/.archive/app/models_old/product.rb b/.archive/app/models/product.rb similarity index 100% rename from .archive/app/models_old/product.rb rename to .archive/app/models/product.rb diff --git a/.archive/app/models_old/region.rb b/.archive/app/models/region.rb similarity index 100% rename from .archive/app/models_old/region.rb rename to .archive/app/models/region.rb diff --git a/.archive/app/models_old/webcam_image.rb b/.archive/app/models/webcam_image.rb similarity index 100% rename from .archive/app/models_old/webcam_image.rb rename to .archive/app/models/webcam_image.rb diff --git a/.archive/app/models_old/wi_mn_d_ave_t_air.rb b/.archive/app/models/wi_mn_d_ave_t_air.rb similarity index 100% rename from .archive/app/models_old/wi_mn_d_ave_t_air.rb rename to .archive/app/models/wi_mn_d_ave_t_air.rb diff --git a/.archive/app/models_old/wi_mn_d_ave_vapr.rb b/.archive/app/models/wi_mn_d_ave_vapr.rb similarity index 100% rename from .archive/app/models_old/wi_mn_d_ave_vapr.rb rename to .archive/app/models/wi_mn_d_ave_vapr.rb diff --git a/.archive/app/models_old/wi_mn_d_max_t_air.rb b/.archive/app/models/wi_mn_d_max_t_air.rb similarity index 100% rename from .archive/app/models_old/wi_mn_d_max_t_air.rb rename to .archive/app/models/wi_mn_d_max_t_air.rb diff --git a/.archive/app/models_old/wi_mn_d_min_t_air.rb b/.archive/app/models/wi_mn_d_min_t_air.rb similarity index 100% rename from .archive/app/models_old/wi_mn_d_min_t_air.rb rename to .archive/app/models/wi_mn_d_min_t_air.rb diff --git a/.archive/app/models_old/wi_mn_det.rb b/.archive/app/models/wi_mn_det.rb similarity index 100% rename from .archive/app/models_old/wi_mn_det.rb rename to .archive/app/models/wi_mn_det.rb diff --git a/app/views/awon/_awon_check_boxes.html.erb b/.archive/app/views/awon/_awon_check_boxes.html.erb similarity index 100% rename from app/views/awon/_awon_check_boxes.html.erb rename to .archive/app/views/awon/_awon_check_boxes.html.erb diff --git a/.archive/app/views_old/awon/awon_seven_day.html.erb b/.archive/app/views/awon/awon_seven_day.html.erb similarity index 100% rename from .archive/app/views_old/awon/awon_seven_day.html.erb rename to .archive/app/views/awon/awon_seven_day.html.erb diff --git a/app/views/awon/index.html.erb b/.archive/app/views/awon/index.html.erb similarity index 100% rename from app/views/awon/index.html.erb rename to .archive/app/views/awon/index.html.erb diff --git a/app/views/awon/station_info.html.erb b/.archive/app/views/awon/station_info.html.erb similarity index 100% rename from app/views/awon/station_info.html.erb rename to .archive/app/views/awon/station_info.html.erb diff --git a/.archive/app/views_old/degree_day_stations/_form.html.erb b/.archive/app/views/degree_day_stations/_form.html.erb similarity index 100% rename from .archive/app/views_old/degree_day_stations/_form.html.erb rename to .archive/app/views/degree_day_stations/_form.html.erb diff --git a/.archive/app/views_old/degree_day_stations/edit.html.erb b/.archive/app/views/degree_day_stations/edit.html.erb similarity index 100% rename from .archive/app/views_old/degree_day_stations/edit.html.erb rename to .archive/app/views/degree_day_stations/edit.html.erb diff --git a/.archive/app/views_old/degree_day_stations/index.html.erb b/.archive/app/views/degree_day_stations/index.html.erb similarity index 100% rename from .archive/app/views_old/degree_day_stations/index.html.erb rename to .archive/app/views/degree_day_stations/index.html.erb diff --git a/.archive/app/views_old/degree_day_stations/index.json.jbuilder b/.archive/app/views/degree_day_stations/index.json.jbuilder similarity index 100% rename from .archive/app/views_old/degree_day_stations/index.json.jbuilder rename to .archive/app/views/degree_day_stations/index.json.jbuilder diff --git a/.archive/app/views_old/degree_day_stations/new.html.erb b/.archive/app/views/degree_day_stations/new.html.erb similarity index 100% rename from .archive/app/views_old/degree_day_stations/new.html.erb rename to .archive/app/views/degree_day_stations/new.html.erb diff --git a/.archive/app/views_old/degree_day_stations/show.html.erb b/.archive/app/views/degree_day_stations/show.html.erb similarity index 100% rename from .archive/app/views_old/degree_day_stations/show.html.erb rename to .archive/app/views/degree_day_stations/show.html.erb diff --git a/.archive/app/views_old/degree_day_stations/show.json.jbuilder b/.archive/app/views/degree_day_stations/show.json.jbuilder similarity index 100% rename from .archive/app/views_old/degree_day_stations/show.json.jbuilder rename to .archive/app/views/degree_day_stations/show.json.jbuilder diff --git a/.archive/app/views_old/heartbeat/_asos.html.erb b/.archive/app/views/heartbeat/_asos.html.erb similarity index 100% rename from .archive/app/views_old/heartbeat/_asos.html.erb rename to .archive/app/views/heartbeat/_asos.html.erb diff --git a/.archive/app/views_old/heartbeat/_asos_grids.html.erb b/.archive/app/views/heartbeat/_asos_grids.html.erb similarity index 100% rename from .archive/app/views_old/heartbeat/_asos_grids.html.erb rename to .archive/app/views/heartbeat/_asos_grids.html.erb diff --git a/.archive/app/views_old/heartbeat/_awon.html.erb b/.archive/app/views/heartbeat/_awon.html.erb similarity index 100% rename from .archive/app/views_old/heartbeat/_awon.html.erb rename to .archive/app/views/heartbeat/_awon.html.erb diff --git a/.archive/app/views_old/heartbeat/_dd.html.erb b/.archive/app/views/heartbeat/_dd.html.erb similarity index 100% rename from .archive/app/views_old/heartbeat/_dd.html.erb rename to .archive/app/views/heartbeat/_dd.html.erb diff --git a/.archive/app/views_old/heartbeat/_et.html.erb b/.archive/app/views/heartbeat/_et.html.erb similarity index 100% rename from .archive/app/views_old/heartbeat/_et.html.erb rename to .archive/app/views/heartbeat/_et.html.erb diff --git a/.archive/app/views_old/heartbeat/_hyd.html.erb b/.archive/app/views/heartbeat/_hyd.html.erb similarity index 100% rename from .archive/app/views_old/heartbeat/_hyd.html.erb rename to .archive/app/views/heartbeat/_hyd.html.erb diff --git a/.archive/app/views_old/heartbeat/_insol.html.erb b/.archive/app/views/heartbeat/_insol.html.erb similarity index 100% rename from .archive/app/views_old/heartbeat/_insol.html.erb rename to .archive/app/views/heartbeat/_insol.html.erb diff --git a/.archive/app/views_old/heartbeat/_ping.html.erb b/.archive/app/views/heartbeat/_ping.html.erb similarity index 100% rename from .archive/app/views_old/heartbeat/_ping.html.erb rename to .archive/app/views/heartbeat/_ping.html.erb diff --git a/.archive/app/views_old/heartbeat/_webapps.html.erb b/.archive/app/views/heartbeat/_webapps.html.erb similarity index 100% rename from .archive/app/views_old/heartbeat/_webapps.html.erb rename to .archive/app/views/heartbeat/_webapps.html.erb diff --git a/.archive/app/views_old/heartbeat/index.html.erb b/.archive/app/views/heartbeat/index.html.erb similarity index 100% rename from .archive/app/views_old/heartbeat/index.html.erb rename to .archive/app/views/heartbeat/index.html.erb diff --git a/.archive/app/views_old/heartbeat/webapps.html.erb b/.archive/app/views/heartbeat/webapps.html.erb similarity index 100% rename from .archive/app/views_old/heartbeat/webapps.html.erb rename to .archive/app/views/heartbeat/webapps.html.erb diff --git a/app/views/home/king_hall.html.erb b/.archive/app/views/home/king_hall.html.erb similarity index 100% rename from app/views/home/king_hall.html.erb rename to .archive/app/views/home/king_hall.html.erb diff --git a/.archive/app/views_old/layouts/cranberry.html.erb b/.archive/app/views/layouts/cranberry.html.erb similarity index 100% rename from .archive/app/views_old/layouts/cranberry.html.erb rename to .archive/app/views/layouts/cranberry.html.erb diff --git a/.archive/app/views_old/thermal_models/get_dds_many_locations.html.erb b/.archive/app/views/thermal_models/get_dds_many_locations.html.erb similarity index 100% rename from .archive/app/views_old/thermal_models/get_dds_many_locations.html.erb rename to .archive/app/views/thermal_models/get_dds_many_locations.html.erb diff --git a/.archive/app/views_old/thermal_models/gypsy.html.erb b/.archive/app/views/thermal_models/gypsy.html.erb similarity index 100% rename from .archive/app/views_old/thermal_models/gypsy.html.erb rename to .archive/app/views/thermal_models/gypsy.html.erb diff --git a/.archive/app/views_old/thermal_models/many_degree_days_for_date.html.erb b/.archive/app/views/thermal_models/many_degree_days_for_date.html.erb similarity index 100% rename from .archive/app/views_old/thermal_models/many_degree_days_for_date.html.erb rename to .archive/app/views/thermal_models/many_degree_days_for_date.html.erb diff --git a/.archive/app/views_old/weather/webcam.html.erb b/.archive/app/views/weather/webcam.html.erb similarity index 100% rename from .archive/app/views_old/weather/webcam.html.erb rename to .archive/app/views/weather/webcam.html.erb diff --git a/.archive/app/views_old/weather/webcam_archive.html.erb b/.archive/app/views/weather/webcam_archive.html.erb similarity index 100% rename from .archive/app/views_old/weather/webcam_archive.html.erb rename to .archive/app/views/weather/webcam_archive.html.erb diff --git a/spec/requests/awon_spec.rb b/.archive/spec/requests/awon_spec.rb similarity index 100% rename from spec/requests/awon_spec.rb rename to .archive/spec/requests/awon_spec.rb diff --git a/.prettierrc b/.prettierrc new file mode 100644 index 00000000..59821061 --- /dev/null +++ b/.prettierrc @@ -0,0 +1,4 @@ +{ + "singleQuote": false, + "printWidth": 100 +} diff --git a/Gemfile.lock b/Gemfile.lock index 85f16540..e015f87f 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -16,35 +16,35 @@ GIT GEM remote: https://rubygems.org/ specs: - actioncable (7.1.3.2) - actionpack (= 7.1.3.2) - activesupport (= 7.1.3.2) + actioncable (7.1.3.3) + actionpack (= 7.1.3.3) + activesupport (= 7.1.3.3) nio4r (~> 2.0) websocket-driver (>= 0.6.1) zeitwerk (~> 2.6) - actionmailbox (7.1.3.2) - actionpack (= 7.1.3.2) - activejob (= 7.1.3.2) - activerecord (= 7.1.3.2) - activestorage (= 7.1.3.2) - activesupport (= 7.1.3.2) + actionmailbox (7.1.3.3) + actionpack (= 7.1.3.3) + activejob (= 7.1.3.3) + activerecord (= 7.1.3.3) + activestorage (= 7.1.3.3) + activesupport (= 7.1.3.3) mail (>= 2.7.1) net-imap net-pop net-smtp - actionmailer (7.1.3.2) - actionpack (= 7.1.3.2) - actionview (= 7.1.3.2) - activejob (= 7.1.3.2) - activesupport (= 7.1.3.2) + actionmailer (7.1.3.3) + actionpack (= 7.1.3.3) + actionview (= 7.1.3.3) + activejob (= 7.1.3.3) + activesupport (= 7.1.3.3) mail (~> 2.5, >= 2.5.4) net-imap net-pop net-smtp rails-dom-testing (~> 2.2) - actionpack (7.1.3.2) - actionview (= 7.1.3.2) - activesupport (= 7.1.3.2) + actionpack (7.1.3.3) + actionview (= 7.1.3.3) + activesupport (= 7.1.3.3) nokogiri (>= 1.8.5) racc rack (>= 2.2.4) @@ -52,35 +52,35 @@ GEM rack-test (>= 0.6.3) rails-dom-testing (~> 2.2) rails-html-sanitizer (~> 1.6) - actiontext (7.1.3.2) - actionpack (= 7.1.3.2) - activerecord (= 7.1.3.2) - activestorage (= 7.1.3.2) - activesupport (= 7.1.3.2) + actiontext (7.1.3.3) + actionpack (= 7.1.3.3) + activerecord (= 7.1.3.3) + activestorage (= 7.1.3.3) + activesupport (= 7.1.3.3) globalid (>= 0.6.0) nokogiri (>= 1.8.5) - actionview (7.1.3.2) - activesupport (= 7.1.3.2) + actionview (7.1.3.3) + activesupport (= 7.1.3.3) builder (~> 3.1) erubi (~> 1.11) rails-dom-testing (~> 2.2) rails-html-sanitizer (~> 1.6) - activejob (7.1.3.2) - activesupport (= 7.1.3.2) + activejob (7.1.3.3) + activesupport (= 7.1.3.3) globalid (>= 0.3.6) - activemodel (7.1.3.2) - activesupport (= 7.1.3.2) - activerecord (7.1.3.2) - activemodel (= 7.1.3.2) - activesupport (= 7.1.3.2) + activemodel (7.1.3.3) + activesupport (= 7.1.3.3) + activerecord (7.1.3.3) + activemodel (= 7.1.3.3) + activesupport (= 7.1.3.3) timeout (>= 0.4.0) - activestorage (7.1.3.2) - actionpack (= 7.1.3.2) - activejob (= 7.1.3.2) - activerecord (= 7.1.3.2) - activesupport (= 7.1.3.2) + activestorage (7.1.3.3) + actionpack (= 7.1.3.3) + activejob (= 7.1.3.3) + activerecord (= 7.1.3.3) + activesupport (= 7.1.3.3) marcel (~> 1.0) - activesupport (7.1.3.2) + activesupport (7.1.3.3) base64 bigdecimal concurrent-ruby (~> 1.0, >= 1.0.2) @@ -96,7 +96,7 @@ GEM sshkit (>= 1.6.1, != 1.7.0) ast (2.4.2) base64 (0.2.0) - bigdecimal (3.1.7) + bigdecimal (3.1.8) brakeman (6.1.2) racc builder (3.2.4) @@ -138,9 +138,9 @@ GEM date (3.3.4) diff-lcs (1.5.1) docile (1.4.0) - dotenv (3.1.1) - dotenv-rails (3.1.1) - dotenv (= 3.1.1) + dotenv (3.1.2) + dotenv-rails (3.1.2) + dotenv (= 3.1.2) railties (>= 6.1) drb (2.2.1) erubi (1.12.0) @@ -173,10 +173,10 @@ GEM csv mini_mime (>= 1.0.0) multi_xml (>= 0.5.2) - i18n (1.14.4) + i18n (1.14.5) concurrent-ruby (~> 1.0) io-console (0.7.2) - irb (1.13.0) + irb (1.13.1) rdoc (>= 4.0.0) reline (>= 0.4.2) jquery-rails (4.6.0) @@ -185,15 +185,15 @@ GEM thor (>= 0.14, < 2.0) json (2.7.2) language_server-protocol (3.17.0.3) - launchy (3.0.0) + launchy (3.0.1) addressable (~> 2.8) childprocess (~> 5.0) letter_opener (1.10.0) launchy (>= 2.2, < 4) - letter_opener_web (2.0.0) - actionmailer (>= 5.2) - letter_opener (~> 1.7) - railties (>= 5.2) + letter_opener_web (3.0.0) + actionmailer (>= 6.1) + letter_opener (~> 1.9) + railties (>= 6.1) rexml lint_roller (1.1.0) listen (3.9.0) @@ -211,12 +211,12 @@ GEM marcel (1.0.4) method_source (1.1.0) mini_mime (1.1.5) - minitest (5.22.3) + minitest (5.23.1) multi_xml (0.7.1) bigdecimal (~> 3.1) mutex_m (0.2.0) nenv (0.3.0) - net-imap (0.4.10) + net-imap (0.4.11) date net-protocol net-pop (0.1.2) @@ -230,18 +230,18 @@ GEM net-smtp (0.5.0) net-protocol net-ssh (7.2.3) - nio4r (2.7.1) - nokogiri (1.16.4-aarch64-linux) + nio4r (2.7.3) + nokogiri (1.16.5-aarch64-linux) racc (~> 1.4) - nokogiri (1.16.4-arm-linux) + nokogiri (1.16.5-arm-linux) racc (~> 1.4) - nokogiri (1.16.4-arm64-darwin) + nokogiri (1.16.5-arm64-darwin) racc (~> 1.4) - nokogiri (1.16.4-x86-linux) + nokogiri (1.16.5-x86-linux) racc (~> 1.4) - nokogiri (1.16.4-x86_64-darwin) + nokogiri (1.16.5-x86_64-darwin) racc (~> 1.4) - nokogiri (1.16.4-x86_64-linux) + nokogiri (1.16.5-x86_64-linux) racc (~> 1.4) notiffany (0.1.3) nenv (~> 0.1) @@ -261,8 +261,8 @@ GEM public_suffix (5.0.5) puma (6.4.2) nio4r (~> 2.0) - racc (1.7.3) - rack (3.0.10) + racc (1.8.0) + rack (3.0.11) rack-session (2.0.0) rack (>= 3.0.0) rack-test (2.1.0) @@ -270,20 +270,20 @@ GEM rackup (2.1.0) rack (>= 3) webrick (~> 1.8) - rails (7.1.3.2) - actioncable (= 7.1.3.2) - actionmailbox (= 7.1.3.2) - actionmailer (= 7.1.3.2) - actionpack (= 7.1.3.2) - actiontext (= 7.1.3.2) - actionview (= 7.1.3.2) - activejob (= 7.1.3.2) - activemodel (= 7.1.3.2) - activerecord (= 7.1.3.2) - activestorage (= 7.1.3.2) - activesupport (= 7.1.3.2) + rails (7.1.3.3) + actioncable (= 7.1.3.3) + actionmailbox (= 7.1.3.3) + actionmailer (= 7.1.3.3) + actionpack (= 7.1.3.3) + actiontext (= 7.1.3.3) + actionview (= 7.1.3.3) + activejob (= 7.1.3.3) + activemodel (= 7.1.3.3) + activerecord (= 7.1.3.3) + activestorage (= 7.1.3.3) + activesupport (= 7.1.3.3) bundler (>= 1.15.0) - railties (= 7.1.3.2) + railties (= 7.1.3.3) rails-controller-testing (1.0.5) actionpack (>= 5.0.1.rc1) actionview (>= 5.0.1.rc1) @@ -297,9 +297,9 @@ GEM nokogiri (~> 1.14) rails-ujs (0.1.0) railties (>= 3.1) - railties (7.1.3.2) - actionpack (= 7.1.3.2) - activesupport (= 7.1.3.2) + railties (7.1.3.3) + actionpack (= 7.1.3.3) + activesupport (= 7.1.3.3) irb rackup (>= 1.0.0) rake (>= 12.2) @@ -308,15 +308,16 @@ GEM rainbow (3.1.1) rake (13.2.1) rb-fsevent (0.11.2) - rb-inotify (0.10.1) + rb-inotify (0.11.1) ffi (~> 1.0) - rdoc (6.6.3.1) + rdoc (6.7.0) psych (>= 4.0.0) - regexp_parser (2.9.0) - reline (0.5.5) + regexp_parser (2.9.2) + reline (0.5.7) io-console (~> 0.5) render_async (2.1.11) - rexml (3.2.6) + rexml (3.2.8) + strscan (>= 3.0.9) rspec (3.13.0) rspec-core (~> 3.13.0) rspec-expectations (~> 3.13.0) @@ -326,7 +327,7 @@ GEM rspec-expectations (3.13.0) diff-lcs (>= 1.2.0, < 2.0) rspec-support (~> 3.13.0) - rspec-mocks (3.13.0) + rspec-mocks (3.13.1) diff-lcs (>= 1.2.0, < 2.0) rspec-support (~> 3.13.0) rspec-rails (6.1.2) @@ -338,7 +339,7 @@ GEM rspec-mocks (~> 3.13) rspec-support (~> 3.13) rspec-support (3.13.1) - rubocop (1.62.1) + rubocop (1.63.5) json (~> 2.3) language_server-protocol (>= 3.17.0) parallel (~> 1.10) @@ -351,9 +352,9 @@ GEM unicode-display_width (>= 2.4.0, < 3.0) rubocop-ast (1.31.3) parser (>= 3.3.1.0) - rubocop-performance (1.20.2) + rubocop-performance (1.21.0) rubocop (>= 1.48.1, < 2.0) - rubocop-ast (>= 1.30.0, < 2.0) + rubocop-ast (>= 1.31.1, < 2.0) ruby-progressbar (1.13.0) sassc (2.4.0) ffi (~> 1.9) @@ -386,19 +387,20 @@ GEM net-scp (>= 1.1.2) net-sftp (>= 2.1.2) net-ssh (>= 2.8.0) - standard (1.35.1) + standard (1.36.0) language_server-protocol (~> 3.17.0.2) lint_roller (~> 1.0) - rubocop (~> 1.62.0) + rubocop (~> 1.63.0) standard-custom (~> 1.0.0) - standard-performance (~> 1.3) + standard-performance (~> 1.4) standard-custom (1.0.2) lint_roller (~> 1.0) rubocop (~> 1.50) - standard-performance (1.3.1) + standard-performance (1.4.0) lint_roller (~> 1.1) - rubocop-performance (~> 1.20.2) + rubocop-performance (~> 1.21.0) stringio (3.1.0) + strscan (3.1.0) terser (1.2.2) execjs (>= 0.3.0, < 3) thor (1.3.1) @@ -423,7 +425,7 @@ GEM whenever (1.0.0) chronic (>= 0.6.3) will_paginate (4.0.0) - zeitwerk (2.6.13) + zeitwerk (2.6.14) PLATFORMS aarch64-linux diff --git a/app/assets/config/manifest.js b/app/assets/config/manifest.js index 1a0eb1fe..abb4d59d 100644 --- a/app/assets/config/manifest.js +++ b/app/assets/config/manifest.js @@ -2,4 +2,3 @@ //= link_directory ../javascripts .js //= link_directory ../stylesheets //= link application.css -//= link style.css diff --git a/app/assets/stylesheets/application.css.scss b/app/assets/stylesheets/application.css.scss deleted file mode 100644 index f82f2405..00000000 --- a/app/assets/stylesheets/application.css.scss +++ /dev/null @@ -1,19 +0,0 @@ -// *= require_tree . -// *= require_self - - -.calendar-table { - font-size: 11px; -} - -.table-scroll-wrapper { - overflow-x: scroll; - margin: 1rem; -} - -.field_with_errors { - color: red; - display: inline; -} - - diff --git a/app/assets/stylesheets/application.scss b/app/assets/stylesheets/application.scss new file mode 100644 index 00000000..e6bc9740 --- /dev/null +++ b/app/assets/stylesheets/application.scss @@ -0,0 +1,721 @@ +// *= require_tree . +// *= require_self + +@import "./breakpoints.scss"; +@import "./colors.scss"; + +// --- BASIC STYLES --- // + +html, +body, +h1, +h2 { + margin: 0px; + padding: 0px; +} + +body { + background: $page-bg-color; + font-size: 15px; + font-family: "Lato", sans-serif; +} + +a { + font-weight: 600; + color: $content-link-color; +} + +a:hover { + color: $content-link-hover-color; + text-decoration: underline; +} + +h2 { + color: $heading-text-color; +} + +h2 a { + text-decoration: none; +} + +img { + max-width: 100%; + display: block; +} + +ul { + padding-inline-start: 20px; +} + +li { + margin-bottom: 0.25em; +} + +table { + border-collapse: collapse; + max-width: 100%; + overflow: auto; +} + +hr { + margin-top: 0.5em; + margin-bottom: 1.5em; + border: 1px; + border-bottom: 1px solid $hr-color; +} + +label { + white-space: nowrap; + margin-bottom: 2px; +} + +input, +select, +button { + margin-top: 1px; + margin-bottom: 2px; +} + +button { + cursor: pointer; +} + +button:disabled, +button[disabled] { + cursor: default; +} + +input[type="checkbox"] { + transform: scale(1.15); +} + +.flex { + display: flex; + flex-wrap: wrap; +} + +.gap-sm { + row-gap: 5px; + column-gap: 10px; +} + +.flex-col { + display: flex; + flex-direction: row; + row-gap: 5px; + column-gap: 10px; +} + +.flex-row { + display: flex; + flex-direction: column; + gap: 10px; +} + +// --- LAYOUT --- // + +.wrapper { + max-width: 1200px; + min-height: calc(100vh - 20px); + text-align: left; + margin: auto; + margin-top: 20px; +} + +// --- NAV BAR --- // + +.nav-bar { + display: inline-flex; + width: 100%; + + @media #{$medium-down} { + flex-direction: column; + } +} + +.nav-title { + color: $nav-title-color; + font-variant: small-caps; + + a { + text-decoration: none; + color: inherit; + } + + @media #{$medium-down} { + text-align: center; + margin-bottom: 1em; + } +} + +.nav-buttons { + margin-left: auto; + margin-top: auto; + margin-right: 5px; + display: inline-flex; + white-space: nowrap; + justify-content: flex-end; + gap: 1px; + + @media #{$small-only} { + flex-wrap: wrap; + justify-content: space-evenly; + margin-left: inherit; + width: 100%; + } + + a { + flex-grow: 1; + color: inherit; + text-decoration: none; + } +} + +.nav-button { + background-color: $nav-bg-color; + color: $nav-title-color; + border-top-left-radius: 10px; + border-top-right-radius: 10px; + height: 1.5em; + padding: 5px 10px 0 10px; + text-align: center; + font-weight: bold; + font-size: 1.1em; + + @media #{$small-only} { + margin: 5px; + border-radius: 5px; + flex-wrap: wrap; + } +} + +.nav-button:hover, +.nav-button.selected { + background-color: $frame-bg-color; + color: $content-bg-color; +} + +// --- MAIN BOX --- // + +.main-box { + background-color: $frame-bg-color; + border-radius: 5px; + padding: 10px; +} + +.main { + display: flex; + gap: 0 10px; + width: inherit; + min-height: 750px; + // overflow: auto; + // width: 100%; +} + +// --- WELCOME BOX --- // + +.welcome-box { + background-color: $welcome-bg-color; + max-width: 250px; + border-radius: 5px; + color: $welcome-text-color; + + @media #{$small-only} { + display: none; + } + + @media #{$medium-only} { + width: 200px; + } +} + +.welcome-image img { + border-top-left-radius: 5px; + border-top-right-radius: 5px; + width: 100%; +} + +.welcome { + padding: 10px; + + a { + color: $welcome-text-color; + } + + a:hover { + color: $welcome-link-color; + } + + h2, + h2 a { + text-align: center; + color: $welcome-title-color; + } + + ul { + margin: 5px 0; + } + + h4 { + margin-bottom: 5px; + } +} + +// --- CONTENT BOX --- // + +.content-box { + background-color: $content-bg-color; + border-radius: 5px; + width: 100%; + overflow: auto; + padding: 10px; + display: flex; + flex-direction: column; +} + +.main-content { + flex: 1; + + h3 { + margin-top: 2em; + margin-bottom: 1em; + } +} + +.content-row { + display: inline-flex; + min-height: 150px; + + h1, + h2, + h3, + h4 { + margin-top: 0; + } +} + +.content-img { + flex: 0 0 auto; + width: 150px; + margin-right: 20px; + + img { + border-radius: 5px; + width: 100%; + } + + @media #{$medium-down} { + width: 100px; + } + + @media screen and (max-width: 21em) { + display: none; + } +} + +.content-footer { + margin-top: auto; + padding-top: 1em; +} + +// --- STYLES --- // + +.indent { + margin-left: 1em; +} + +.more { + text-align: right; +} + +.clear { + clear: both; +} + +.note { + font-style: italic; + margin-top: 1em; + margin-bottom: 1em; +} + +.error { + font-weight: bold; + color: #c5050c; +} + +div .error { + border: 1px solid #c5050c; + border-radius: 5px; + background-color: rgb(255, 240, 240); + padding: 10px; + margin-bottom: 1em; + width: fit-content; +} + +.success { + font-weight: bold; + color: #008000; +} + +div .success { + border: 1px solid #008000; + border-radius: 5px; + background-color: rgb(240, 255, 240); + padding: 10px; + margin-bottom: 1em; + width: fit-content; +} + +.notice { + font-weight: bold; + color: #008000; +} + +.notice-container { + display: flex; + padding: 1em 0; + min-height: 2em; +} + +.copyright { + font: 13px arial, sans-serif; + color: $copyright-text-color; + text-align: right; + margin-right: 10px; + + p { + margin-top: 10px; + } +} + +.cal-container { + width: inherit; + display: inline-flex; + + .cal-month { + flex: 0 1 auto; + } +} + +.tbl-container { + overflow: auto; +} + +.grid-table { + td, + th { + padding: 2px 1em 2px 1em; + } + + th { + text-align: center; + border-bottom: 1px solid; + } + + td { + color: black; + text-align: right; + } + + tbody tr:nth-child(even) { + background: $table-row-highlight-color; + } + + tbody tr:nth-child(7n) { + border-bottom: 1px solid $table-row-underline-color; + } + + tfoot { + border-top: 1px solid; + border-bottom: 1px solid; + font-weight: bold; + font-style: italic; + } +} + +.normal-table { + thead { + border: 1px solid $nav-bg-color; + background: $table-row-highlight-color; + } + + tbody { + border: 1px solid $nav-bg-color; + } + + td, + th { + padding: 0.25em 1em 0.25em 1em; + } + + th { + border-bottom: 1px solid $nav-bg-color; + } + + tbody tr:nth-child(even) { + background: $table-row-highlight-color; + } +} + +.simple-table { + tbody { + border: 1px solid $nav-bg-color; + } + + td, + th { + padding: 0.25em 1em 0.25em 1em; + } + + th { + border-bottom: 1px solid $nav-bg-color; + } + + tbody tr:nth-child(even) { + background: $table-row-highlight-color; + } +} + +.subscriber-table { + font-size: small; + + tbody { + border: 1px solid $nav-bg-color; + } + + th { + border-bottom: 1px solid $nav-bg-color; + } + + tbody tr:nth-child(even) { + background: $table-row-highlight-color; + } +} + +.plain-table { + td, + th { + text-align: center; + padding: 0 1em 1em 0; + } +} + +.center { + text-align: center; +} + +.center-div { + display: block; + margin-left: auto; + margin-right: auto; + width: fit-content; + max-width: inherit; +} + +.form-box { + border: 1px solid $form-border-color; + background-color: $form-bg-color; + border-radius: 3px; + padding: 1em; + margin-bottom: 1em; + width: fit-content; + + .title { + font-weight: bold; + margin-top: 0; + margin-bottom: 1em; + } + + fieldset { + margin-top: 1em; + margin-bottom: 1em; + border: 2px solid lightgrey; + border-radius: 5px; + } + + button { + margin-top: 0.5em; + } +} + +.submit { + width: 100%; + border: 1px solid grey; + border-radius: 3px; + padding: 0.5em; + cursor: pointer; + font-weight: bold; + + &:hover { + background: lightgrey; + border-color: $welcome-bg-color; + } +} + +.no-top-margin { + margin-top: 0; +} + +.two-box { + display: flex; + flex-direction: row; + margin-bottom: 0.5em; + gap: 0 20px; + + @media #{$small-only} { + flex-direction: column; + } + + .box { + display: flex; + flex-direction: column; + flex: 1 1 auto; + // flex-grow: 1; + // flex-basis: 0; + // min-width: 0; + + @media #{$small-only} { + width: auto; + } + } +} + +.col-container { + display: flex; + flex-direction: row; + gap: 1em; + + @media #{$small-only} { + flex-direction: column; + } +} + +.col-50 { + width: 50%; + @media #{$small-only} { + width: inherit; + } +} + +.map-loading { + padding: 0.5em; + border: 1px solid $form-border-color; + border-radius: 5px; + background: $table-row-highlight-color; + display: flex; + margin-bottom: 1em; + width: inherit; + // aspect-ratio: 1; + flex: 1 1 auto; + + div { + margin-right: 1em; + } +} + +.form-items { + display: flex; + flex-wrap: wrap; + flex-direction: row; + + div { + border: 1px solid grey; + border-radius: 5px; + padding: 5px; + gap: 1em; + } +} + +// --- Map --- // + +.map-container { + margin-bottom: 1em; + // padding: 0 20px; + + @media #{$small-only} { + padding: 0; + } +} + +.map-form { + padding: 10px 10px 5px 10px; + border: 1px solid $form-border-color; + border-radius: 5px; + background: $map-form-bg-color; + margin-bottom: 10px; +} + +.map-form-row { + line-height: 20px; + margin-bottom: 5px; + display: flex; + flex-wrap: wrap; + flex-direction: row; + gap: 5px 15px; +} + +.grey { + background: $form-bg-color; +} + +#map-img { + position: relative; + border: 1px solid $form-border-color; +} + +.map-fail { + padding: 1em; + font-style: italic; + font-weight: bold; + color: #c5050c; +} + +.map-note { + font-style: italic; + text-align: center; + margin: 1em; + font-size: small; +} + +.no-border { + border: none !important; +} + +#dot { + position: absolute; + width: 5px; + height: 5px; + border-radius: 5px; + background: black; + border: 1px solid white; + pointer-events: none; +} + +#data-container { + max-width: 100%; + overflow: auto; + + h4 { + margin-top: 0px; + } +} + +#date-warning { + font-style: italic; + color: red; + margin-top: 0.5em; +} + +.calendar-table { + font-size: 11px; +} + +.table-scroll-wrapper { + overflow-x: scroll; + margin: 1rem; +} + +.field_with_errors { + color: red; + display: inline; +} diff --git a/app/assets/stylesheets/style.css.scss b/app/assets/stylesheets/style.css.scss deleted file mode 100644 index 59579108..00000000 --- a/app/assets/stylesheets/style.css.scss +++ /dev/null @@ -1,683 +0,0 @@ -@import "./breakpoints.scss"; -@import "./colors.scss"; - - -// --- BASIC STYLES --- // - -html, body, h1, h2 { - margin: 0px; - padding: 0px; -} - -body { - background: $page-bg-color; - font-size: 15px; - font-family: 'Lato', sans-serif; -} - -a { - font-weight: 600; - color: $content-link-color; -} - -a:hover { - color: $content-link-hover-color; - text-decoration: underline; -} - -h2 { - color: $heading-text-color; -} - -h2 a { - text-decoration: none; -} - -img { - max-width: 100%; - display: block; -} - -ul { - padding-inline-start: 20px; -} - -li { - margin-bottom: 0.25em; -} - -table { - border-collapse: collapse; - max-width: 100%; - overflow: auto; -} - -hr { - margin-top: 0.5em; - margin-bottom: 1.5em; - border: 1px; - border-bottom: 1px solid $hr-color; -} - -label { - white-space: nowrap; - margin-bottom: 2px; -} - -input, select, button { - margin-top: 1px; - margin-bottom: 2px; -} - -button { - cursor: pointer; -} - -button:disabled, -button[disabled]{ - cursor: default; -} - -input[type=checkbox] { - transform: scale(1.15); -} - -.flex { - display: flex; - flex-wrap: wrap; -} - -.gap-sm { - row-gap: 5px; - column-gap: 10px -} - -.flex-col { - display: flex; - flex-direction: row; - row-gap: 5px; - column-gap: 10px; -} - -.flex-row { - display: flex; - flex-direction: column; - gap: 10px; -} - - -// --- LAYOUT --- // - -.wrapper { - max-width: 1200px; - min-height: calc(100vh - 20px); - text-align: left; - margin: auto; - margin-top: 20px; -} - - -// --- NAV BAR --- // - -.nav-bar { - display: inline-flex; - width: 100%; - - @media #{$medium-down} { - flex-direction: column; - } -} - -.nav-title { - color: $nav-title-color; - font-variant: small-caps; - - a { - text-decoration: none; - color: inherit - } - - @media #{$medium-down} { - text-align: center; - margin-bottom: 1em; - } -} - -.nav-buttons { - margin-left: auto; - margin-top: auto; - margin-right: 5px; - display: inline-flex; - white-space: nowrap; - justify-content: flex-end; - gap: 1px; - - @media #{$small-only} { - flex-wrap: wrap; - justify-content: space-evenly; - margin-left: inherit; - width: 100%; - } - - a { - flex-grow: 1; - color: inherit; - text-decoration: none; - } -} - -.nav-button { - background-color: $nav-bg-color; - color: $nav-title-color; - border-top-left-radius: 10px; - border-top-right-radius: 10px; - height: 1.5em; - padding: 5px 10px 0 10px; - text-align: center; - font-weight: bold; - font-size: 1.1em; - - @media #{$small-only} { - margin: 5px; - border-radius: 5px; - flex-wrap: wrap; - } -} - -.nav-button:hover, .nav-button.selected { - background-color: $frame-bg-color; - color: $content-bg-color; -} - - -// --- MAIN BOX --- // - -.main-box { - background-color: $frame-bg-color; - border-radius: 5px; - padding: 10px; -} - -.main { - display: flex; - gap: 0 10px; - width: inherit; - min-height: 750px; - // overflow: auto; - // width: 100%; -} - - -// --- WELCOME BOX --- // - -.welcome-box { - background-color: $welcome-bg-color; - max-width: 250px; - border-radius: 5px; - color: $welcome-text-color; - - @media #{$small-only} { - display: none; - } - - @media #{$medium-only} { - width: 200px; - } -} - -.welcome-image img { - border-top-left-radius: 5px; - border-top-right-radius: 5px; - width: 100%; -} - -.welcome { - padding: 10px; - - a { - color: $welcome-text-color; - } - - a:hover { - color: $welcome-link-color; - } - - h2, h2 a { - text-align: center; - color: $welcome-title-color; - } - - ul { - margin: 5px 0; - } - - h4 { - margin-bottom: 5px; - } -} - - -// --- CONTENT BOX --- // - -.content-box { - background-color: $content-bg-color; - border-radius: 5px; - width: 100%; - overflow: auto; - padding: 10px; - display: flex; - flex-direction: column; -} - -.main-content { - flex: 1; - - h3 { - margin-top: 2em; - margin-bottom: 1em; - } -} - -.row { - display: inline-flex; - min-height: 150px; - - h1, h2, h3, h4 { - margin-top: 0; - } -} - -.left { - flex: 0 0 auto; - width: 150px; - margin-right: 20px; - - img { - border-radius: 5px; - width: 100%; - } - - @media #{$medium-down} { - width: 100px; - } - - @media screen and (max-width: 21em) { - display: none; - } -} - -.content-footer { - margin-top: auto; - padding-top: 1em; -} - - - -// --- STYLES --- // - -.indent { - margin-left: 1em; -} - -.more { - text-align: right; -} - -.clear { - clear: both; -} - -.note { - font-style: italic; - margin-top: 1em; - margin-bottom: 1em; -} - -.error { - font-weight: bold; - color: #c5050c; -} - -div .error { - border: 1px solid #c5050c; - border-radius: 5px; - background-color: rgb(255, 240, 240); - padding: 10px; - margin-bottom: 1em; - width: fit-content; -} - -.success { - font-weight: bold; - color: #008000; -} - -div .success { - border: 1px solid #008000; - border-radius: 5px; - background-color: rgb(240, 255, 240); - padding: 10px; - margin-bottom: 1em; - width: fit-content; -} - -.notice { - font-weight: bold; - color: #008000; -} - -.notice-container { - display: flex; - padding: 1em 0; - min-height: 2em; -} - -.copyright { - font: 13px arial, sans-serif; - color: $copyright-text-color; - text-align: right; - margin-right: 10px; - - p { - margin-top: 10px; - } -} - -.cal-container { - width: inherit; - display: inline-flex; - - .cal-month { - flex: 0 1 auto; - } -} - -.tbl-container { - overflow: auto; -} - -.grid-table { - td, th { - padding: 2px 1em 2px 1em; - } - - th { - text-align: center; - border-bottom: 1px solid; - } - - td { - color: black; - text-align: right; - } - - tbody tr:nth-child(even) { - background: $table-row-highlight-color; - } - - tbody tr:nth-child(7n) { - border-bottom: 1px solid $table-row-underline-color; - } - - tfoot { - border-top: 1px solid; - border-bottom: 1px solid; - font-weight: bold; - font-style: italic; - } -} - -.normal-table { - thead { - border: 1px solid $nav-bg-color; - background: $table-row-highlight-color; - } - - tbody { - border: 1px solid $nav-bg-color; - } - - td, th { - padding: 0.25em 1em 0.25em 1em; - } - - th { - border-bottom: 1px solid $nav-bg-color; - } - - tbody tr:nth-child(even) { - background: $table-row-highlight-color; - } -} - -.simple-table { - tbody { - border: 1px solid $nav-bg-color; - } - - td, th { - padding: 0.25em 1em 0.25em 1em; - } - - th { - border-bottom: 1px solid $nav-bg-color; - } - - tbody tr:nth-child(even) { - background: $table-row-highlight-color; - } -} - -.plain-table { - td, th { - text-align: center; - padding: 0 1em 1em 0; - } -} - -.center { - text-align: center; -} - -.center-div { - display: block; - margin-left: auto; - margin-right: auto; - width: fit-content; - max-width: inherit; -} - -.form-box { - border: 1px solid $form-border-color; - background-color: $form-bg-color; - border-radius: 3px; - padding: 1em; - margin-bottom: 1em; - width: fit-content; - - .title { - font-weight: bold; - margin-top: 0; - margin-bottom: 1em; - } - - fieldset { - margin-top: 1em; - margin-bottom: 1em; - border: 2px solid lightgrey; - border-radius: 5px; - } - - button { - margin-top: 0.5em; - } -} - -.submit { - width: 100%; - border: 1px solid grey; - border-radius: 3px; - padding: 0.5em; - cursor: pointer; - font-weight: bold; - - &:hover { - background: lightgrey; - border-color: $welcome-bg-color; - } -} - -.no-top-margin { - margin-top: 0; -} - -.two-box { - display: flex; - flex-direction: row; - margin-bottom: 0.5em; - gap: 0 20px; - - @media #{$small-only} { - flex-direction: column; - } - - .box { - display: flex; - flex-direction: column; - flex: 1 1 auto; - // flex-grow: 1; - // flex-basis: 0; - // min-width: 0; - - @media #{$small-only} { - width: auto; - } - } -} - -.col-container { - display: flex; - flex-direction: row; - gap: 1em; - - @media #{$small-only} { - flex-direction: column; - } -} - -.col-50 { - width: 50%; - @media #{$small-only} { - width: inherit; - } -} - -.map-loading { - padding: 0.5em; - border: 1px solid $form-border-color; - border-radius: 5px; - background: $table-row-highlight-color; - display: flex; - margin-bottom: 1em; - width: inherit; - // aspect-ratio: 1; - flex: 1 1 auto; - - div { - margin-right: 1em; - } -} - -.form-items { - display: flex; - flex-wrap: wrap; - flex-direction: row; - - div { - border: 1px solid grey; - border-radius: 5px; - padding: 5px; - gap: 1em; - } -} - - -// --- Map --- // - -.map-container { - margin-bottom: 1em; - // padding: 0 20px; - - @media #{$small-only} { - padding: 0; - } -} - -.map-form { - padding: 10px 10px 5px 10px; - border: 1px solid $form-border-color; - border-radius: 5px; - background: $map-form-bg-color; - margin-bottom: 10px; -} - -.map-form-row { - line-height: 20px; - margin-bottom: 5px; - display: flex; - flex-wrap: wrap; - flex-direction: row; - gap: 5px 15px; -} - -.grey { - background: $form-bg-color; -} - -#map-img { - position: relative; - border: 1px solid $form-border-color; -} - -.map-fail { - padding: 1em; - font-style: italic; - font-weight: bold; - color: #c5050c; -} - -.map-note { - font-style: italic; - text-align: center; - margin: 1em; - font-size: small; -} - -.no-border { - border: none !important; -} - -#dot { - position: absolute; - width: 5px; - height: 5px; - border-radius: 5px; - background: black; - border: 1px solid white; - pointer-events: none; -} - -#data-container { - max-width: 100%; - overflow: auto; - - h4 { - margin-top: 0px; - } -} - -#date-warning { - font-style: italic; - color: red; - margin-top: 0.5em; -} diff --git a/app/assets/stylesheets/subscribers.css.scss b/app/assets/stylesheets/subscribers.scss similarity index 95% rename from app/assets/stylesheets/subscribers.css.scss rename to app/assets/stylesheets/subscribers.scss index 1c0f0659..7cda1c12 100644 --- a/app/assets/stylesheets/subscribers.css.scss +++ b/app/assets/stylesheets/subscribers.scss @@ -42,16 +42,18 @@ h4 { thead tr { padding: 5px x; } - + tbody tr { margin: 0; } - - th, td { + + th, + td { padding: 0 5px; } - th, td:first-child { + th, + td:first-child { padding: 5px 5px; } } @@ -110,14 +112,15 @@ h4 { .apple_pagination { text-align: center; - padding: 1em; + margin: 1em 0; cursor: default; button { padding: 2px 4px; } - a, span { + a, + span { padding: 0.2em 0.3em; } @@ -126,7 +129,8 @@ h4 { color: black; } - a:hover, a:focus { + a:hover, + a:focus { text-decoration: underline; } diff --git a/app/assets/stylesheets/thermal_models.css.scss b/app/assets/stylesheets/thermal_models.scss similarity index 100% rename from app/assets/stylesheets/thermal_models.css.scss rename to app/assets/stylesheets/thermal_models.scss diff --git a/app/controllers/subscribers_controller.rb b/app/controllers/subscribers_controller.rb index 00672cd1..98573faa 100644 --- a/app/controllers/subscribers_controller.rb +++ b/app/controllers/subscribers_controller.rb @@ -120,7 +120,31 @@ def admin return redirect_to manage_subscribers_path, alert: "You must be an admin to view that page." end - @subscribers = Subscriber.order(:id).paginate(page: params[:page], per_page: 20) + @all = Subscriber.all + @active = Subscriber.active + @unconfirmed = Subscriber.unconfirmed + @no_sites = Subscriber.has_no_sites + @stale = Subscriber.stale + @selection_opts = [ + ["All (#{@all.size})", "all"], + ["Active (#{@active.size})", "active"], + ["Unconfirmed (#{@unconfirmed.size})", "unconfirmed"], + ["No sites (#{@no_sites.size})", "no_sites"], + ["Stale (#{@stale.size})", "stale"] + ] + @selection = params[:selection].presence || "all" + @subscribers = case @selection + when "active" + @active + when "unconfirmed" + @unconfirmed + when "no_sites" + @no_sites + when "stale" + @stale + else + @all + end.paginate(page: params[:page], per_page: 500) end def export diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb index 794f10cb..5aaa3e70 100644 --- a/app/helpers/application_helper.rb +++ b/app/helpers/application_helper.rb @@ -49,6 +49,12 @@ def fmt_date(datestring) datestring end + def fmt_x_of_y(x, y) + "#{x} / #{y} (#{sprintf("%.1f", 100 * x / y)}%)" + rescue + "#{x} / #{y}" + end + def freeze_temp (@units == "F") ? 28 : -2.22 end diff --git a/app/mailers/application_mailer.rb b/app/mailers/application_mailer.rb index d5261137..ca0a19c0 100644 --- a/app/mailers/application_mailer.rb +++ b/app/mailers/application_mailer.rb @@ -1,5 +1,6 @@ class ApplicationMailer < ActionMailer::Base default( - from: "AgWeather " + from: "AgWeather ", + reply_to: "No Reply " ) end diff --git a/app/models/subscriber.rb b/app/models/subscriber.rb index 636abc3b..a583b1aa 100644 --- a/app/models/subscriber.rb +++ b/app/models/subscriber.rb @@ -2,6 +2,8 @@ class Subscriber < ApplicationRecord has_many :sites, dependent: :destroy has_many :subscriptions, through: :sites + default_scope { order(:id) } + # per http://stackoverflow.com/questions/201323/using-a-regular-expression-to-validate-an-email-address validates :email, format: {with: /\A([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})\z/i}, presence: true validates_uniqueness_of :email @@ -26,6 +28,22 @@ def is_confirmed? !confirmed_at.nil? end + def self.unconfirmed + where(id: all.collect { |s| (!s.is_confirmed? && (s.updated_at < 1.week.ago)) ? s.id : nil }.compact) + end + + def self.has_no_sites + where(id: all.collect { |s| (s.sites.size == 0) ? s.id : nil }.compact) + end + + def self.active + where(id: all.collect { |s| (s.sites.size > 0 && s.emails_enabled) ? s.id : nil }.compact) + end + + def self.stale + where(id: all.collect { |s| (!s.admin? && s.is_confirmed? && (s.updated_at < 1.month.ago) && (s.sites.size == 0)) ? s.id : nil }.compact) + end + def confirm!(token) if token == auth_token self.confirmed_at = Time.current @@ -104,9 +122,21 @@ def self.send_subscriptions(subscribers) def self.to_csv CSV.generate(headers: true) do |csv| - csv << %w[ID Name Email DateCreated Admin? Sites SitesEnabled Subscriptions] + csv << %w[ID Name Email Created Updated Confirmed Subscribed Sites SitesEnabled Subscriptions Admin] Subscriber.all.order(:id).each do |s| - csv << [s.id, s.name, s.email, s.created_at, s.admin, s.sites.size, s.sites.enabled.size, s.subscriptions.size] + csv << [ + s.id, + s.name, + s.email, + s.created_at, + s.updated_at, + s.confirmed_at.present?, + s.emails_enabled, + s.sites.size, + s.sites.enabled.size, + s.subscriptions.size, + s.admin + ] end end end diff --git a/app/models/tasks.rb b/app/models/tasks.rb index 43e39e33..ab9ebc65 100644 --- a/app/models/tasks.rb +++ b/app/models/tasks.rb @@ -56,12 +56,12 @@ def self.subscribe_all_sites_to_weather end def self.purge_subs(delete: false) - unconfirmed = Subscriber.select { |s| !s.is_confirmed? && (s.updated_at < 1.week.ago) } - stale = Subscriber.select { |s| !s.admin? && s.is_confirmed? && (s.updated_at < 1.month.ago) && (s.sites.size == 0) } + unconfirmed = Subscriber.unconfirmed + stale = Subscriber.stale puts "Total subscribers: #{Subscriber.all.size}. Unconfirmed: #{unconfirmed.size}. Stale: #{stale.size}." if delete - unconfirmed.each(&:destroy) - stale.each(&:destroy) + unconfirmed.destroy_all + stale.destroy_all else puts "Run with delete:true to delete unconfirmed/stale subscriber records." {unconfirmed:, stale:} diff --git a/app/views/home/about.html.erb b/app/views/home/about.html.erb index a8e543a9..56bf6550 100644 --- a/app/views/home/about.html.erb +++ b/app/views/home/about.html.erb @@ -20,15 +20,13 @@

This site, the associated <%= link_to "VDIFN", vdifn_path, target: "_blank" %> and <%= link_to "WISP", wisp_path, target: "_blank" %> sites, and the backend weather data server are currently under the stewardship of the <%= link_to "Entomology Department", @ento_url, target: "_blank" %> at UW-Madison. <%= link_to "Ben Bradford", @ben_url, target: "_blank" %>, researcher, is responsible for ongoing development and expansion of the capabilities of the AgWeather sites. <%= link_to "Russell Groves", @russ_url, target: "_blank" %>, professor of Vegetable Entomology, and <%= link_to "Amanda Gevens", @amanda_url, target: "_blank" %>, professor of Plant Pathology, are consulting members. Thanks also to Jason Pursian at UW CALS who manages the site hosting infrastructure.

-

Learn more about <%= link_to "King Hall", action: :king_hall %>, home of the UW Soil Science Department.

-

Webmaster/developer:

-
-
+
+
<%= image_tag "webmaster.png", title: "hard at work" %>
-
+
Ben Bradford
Department of Entomology
    diff --git a/app/views/home/index.html.erb b/app/views/home/index.html.erb index a323bf9c..decd61b4 100644 --- a/app/views/home/index.html.erb +++ b/app/views/home/index.html.erb @@ -9,13 +9,13 @@

    <%= link_to image_tag("logos/uw-logo-reverse.png", width: "100%"), "https://www.wisc.edu" %>

    <% end %> -
    -
    +
    +
    <%= link_to image_tag("weather-150px.png"), controller: :weather %>
    -
    +

    <%= link_to "Weather Data", controller: :weather %>

    -

    Our weather page offers maps and data for temperature, precipitation, evapotranspiration, and solar insolation, derived from NOAA daily grids and satellite observations. We use Space Science's insolation model to derive estimates of solar radiation from satellite imagery. Combined with atmospheric data from Unidata's Internet Data Distribution project, this allows us to calculate reference evapotranspiration via the Priestley-Taylor equation to derive soil moisture and inform irrigation decisions. In addition, access archived National Weather Service hydrometeorological (HYD) reports, daily weather summaries throughout Wisconsin 1995-present. Our automated weather observation network (AWON) archive offers a record of hourly weather observations at Hancock and Arlington from 1985-2017.

    +

    Our weather page offers maps and data for temperature, precipitation, evapotranspiration, and solar insolation, derived from NOAA daily grids and satellite observations. We use Space Science's insolation model to derive estimates of solar radiation from satellite imagery. Combined with atmospheric data from Unidata's Internet Data Distribution project, this allows us to calculate reference evapotranspiration via the Priestley-Taylor equation to derive soil moisture and inform irrigation decisions.

    Quick links:

    • @@ -26,17 +26,16 @@ <%= link_to "Insolation", controller: :weather, action: :insol %>
    • <%= link_to 'National Weather Service HYD reports', controller: :weather, action: :hyd %>
    • -
    • <%= link_to "Automated Weather Observation Network (AWON) data archive", controller: :awon %> (Note: stations are no longer active)
    • <%= link_to "Day-of-year calendar", controller: :weather, action: :doycal %>
    • -
    • <%= link_to "Wisconsin Environmental Mesonet (WiscoNet)", "https://wisconet.wisc.edu/", target: "_blank" %> - opens in new tab
    • +
    • <%= link_to "Wisconsin's Environmental Mesonet (WiscoNet)", "https://wisconet.wisc.edu/", target: "_blank" %> - opens in new tab

    -
    -
    +
    +
    <%= link_to image_tag("dd-map-250px.png"), controller: :thermal_models %>
    @@ -62,11 +61,11 @@
    -
    -
    +
    +
    <%= link_to image_tag("awon-150px.png"), sites_path %>
    -
    +

    <%= link_to "Site Data", sites_path %> and <%= link_to "Email Subscriptions", subscribers_path %>

    While our weather data can be accessed from the individual weather, precipitation, evapotranspiration, and insolation pages in the <%= link_to "weather tab", weather_path %>, these <%= link_to "site pages", sites_path %> provide a convenient dashboard for accessing the past week's weather data for any single point within our data coverage area. You can bookmark these pages for quick access, or add them to your saved sites in the <%= link_to "subscribers page", sites_path %>. Currently only weather data is presented on the site pages, but we have plans to add degree days and other relevant information in the future.

      @@ -78,8 +77,8 @@
      -
      -
      +
      +
      <%= link_to image_tag("vdifn-250px.png"), vdifn_path, target: "_blank" %>
      @@ -91,8 +90,8 @@
      -
      -
      +
      +
      <%= link_to image_tag("pivot-150px.png"), wisp_url, target: "_blank" %>
      @@ -104,8 +103,8 @@
      -
      -
      +
      +
      <%= link_to image_tag("hal-250px.png"), api_path %>
      @@ -116,8 +115,8 @@
      -
      -
      +
      +
      <%= link_to image_tag("tree-150px.png"), action: :about %>
      diff --git a/app/views/subscribers/admin.html.erb b/app/views/subscribers/admin.html.erb index 95610b9b..cc348212 100644 --- a/app/views/subscribers/admin.html.erb +++ b/app/views/subscribers/admin.html.erb @@ -1,26 +1,6 @@ <% @title = "Subscriber Administration" %> <% @welcome_image = "awon.png" %> -<%= content_for :scripts do %> - -<% end %> - <% content_for :welcome do %>

      <%= @title %>

      Subscriber administration page. Reminder: you cannot change your own email from this page, nor can you set or remove admin status on other users. Use the rails terminal for those tasks.

      @@ -36,54 +16,66 @@ Email: <%= @subscriber.email %>

      -

      Name and email can be changed for subscribers in the list below. You cannot change your own email from this page, nor can you set or remove admin status on other users. Use the rails terminal for those tasks.

      +

      Subscriber list

      +<% n_subs = @all.size %> +
        +
      • Total: <%= @subscribers.size %>
      • +
      • Active: <%= fmt_x_of_y(@active.size, n_subs) %>
      • +
      • Unconfirmed: <%= fmt_x_of_y(@unconfirmed.size, n_subs) %>
      • +
      • No sites: <%= fmt_x_of_y(@no_sites.size, n_subs) %>
      • +
      • Stale: <%= fmt_x_of_y(@stale.size, n_subs) %>
      • +
      - <%= will_paginate @subscribers, class: :apple_pagination %> -
      - - - - - - - - - - - - - <% @subscribers.each do |subscriber| %> - - - - - - - + + <% end %> + +
      IDNameEmailLocationsSubscribed?Actions
      <%= subscriber.id %> - <%= @subscriber.id == subscriber.id ? "[YOU] " : "" %> - <%= subscriber.admin? ? "[ADMIN] " : ""%> - <%= best_in_place subscriber, :name, as: :input %> - <%= best_in_place_if @subscriber.id != subscriber.id, subscriber, :email, as: :input %><%= subscriber.sites.size %><%= subscriber.emails_enabled ? "Yes" : "No" %> - +
      + <%= form_tag do %> + <%= select_tag :selection, options_for_select(@selection_opts, @selection), { onchange: "this.form.submit()" } %> + <% end %> +
      + <%= will_paginate(@subscribers, params: { selection: @selection }) %> +
      + + + + + + + + + + + + + + + + <% @subscribers.each do |subscriber| %> + + + + + + + + + + - - <% end %> - -
      IDNameEmailCreatedConf?Last loginSitesSub?Actions
      <%= subscriber.id %> + <%= subscriber.admin? ? "[ADMIN] " : ""%> + <%= subscriber.name %> + <%= subscriber.email %><%= subscriber.created_at.to_date %><%= subscriber.is_confirmed? %><%= subscriber.validation_created_at ? subscriber.validation_created_at.to_date : (subscriber.confirmed_at ? subscriber.confirmed_at.to_date : "never") %><%= subscriber.sites.size %><%= subscriber.emails_enabled ? "Yes" : "No" %> <%= link_to "".html_safe, url_for(action: :manage, to_edit_id: subscriber.id) %> <% unless @subscriber.id == subscriber.id || subscriber.admin? %> <%= link_to "".html_safe, subscriber_path(subscriber.id), method: :delete, data: {confirm: "Are you sure you want to delete this user?"} %> <% end %> - -
      -
      +
      +
      <%= will_paginate @subscribers, class: :apple_pagination %>
      - - -
      - <%= content_for :footer do %>
      <%= link_to button_tag("Back"), manage_subscribers_path %>
      diff --git a/app/views/thermal_models/_potato_data.html.erb b/app/views/thermal_models/_potato_data.html.erb index f8542761..f0dba443 100644 --- a/app/views/thermal_models/_potato_data.html.erb +++ b/app/views/thermal_models/_potato_data.html.erb @@ -24,7 +24,7 @@ <%= k %> <% v.each do |val| %> - <%= val < 0 ? "-" : val >= model[:threshold] ? "#{val}".html_safe : val %> + <%= val < 0 ? "-" : val >= model[:threshold] ? "#{val}".html_safe : val %> <% end %> diff --git a/app/views/thermal_models/index.html.erb b/app/views/thermal_models/index.html.erb index 419e75f3..6a65b5d0 100644 --- a/app/views/thermal_models/index.html.erb +++ b/app/views/thermal_models/index.html.erb @@ -6,8 +6,8 @@

      Growth and development for many plants and insects is keyed to temperature. By calculating the history of daily temperatures over a season, we can predict pest emergence, crop development, and other events of keen interest in agriculture.

      <% end %> -
      -
      +
      +
      <%= link_to image_tag("vdifn-250px.png"), vdifn_path, target: "_blank" %>
      @@ -18,8 +18,8 @@
      -
      -
      +
      +
      <%= link_to image_tag("dd-map-250px.png"), action: :dd_map %>
      @@ -30,8 +30,8 @@
      -
      -
      +
      +
      <%= link_to image_tag("degree-flower.png"), action: :degree_days %>
      @@ -42,8 +42,8 @@
      -
      -
      +
      +
      <%= link_to image_tag("oak-wilt-250px.png"), action: :oak_wilt %>
      @@ -54,8 +54,8 @@
      -
      -
      +
      +
      <%= link_to image_tag("potato.png"), action: :potato %>
      @@ -66,8 +66,8 @@
      -
      -
      +
      +
      <%= link_to image_tag("alfalfa-weevil.png"), action: :alfalfa_weevil %>
      @@ -78,8 +78,8 @@
      -
      -
      +
      +
      <%= link_to image_tag("stalk-borer.png"), action: :ecb %>
      @@ -90,8 +90,8 @@
      -
      -
      +
      +
      <%= link_to image_tag("ecb.png"), action: :ecb %>
      @@ -102,8 +102,8 @@
      -
      -
      +
      +
      <%= link_to image_tag("spongy.png"), action: :spongy_moth %>
      @@ -114,8 +114,8 @@
      -
      -
      +
      +
      <%= link_to image_tag("seedcorn-maggot.png"), action: :scm %>
      @@ -126,8 +126,8 @@
      -
      -
      +
      +
      <%= link_to image_tag("wbc.png"), action: :western_bean_cutworm %>
      @@ -138,8 +138,8 @@
      -
      -
      +
      +
      <%= link_to image_tag("corn.png"), action: :corn_dev %>
      @@ -150,8 +150,8 @@
      -
      -
      +
      +
      <%= link_to image_tag("frost-map-250px.png"), action: :frost_map %>
      diff --git a/app/views/thermal_models/potato.html.erb b/app/views/thermal_models/potato.html.erb index f4e2df37..24eb42c1 100644 --- a/app/views/thermal_models/potato.html.erb +++ b/app/views/thermal_models/potato.html.erb @@ -16,7 +16,7 @@

      Unlike late blight, early blight spores are assumed to be present in the soil, so once the potato physiological day (p-day) total exceeds 300 since emergence, preventive action for early blight should be considered because disease development risk is elevated.

      -

      Learn more about <%= link_to "late blight", "https://vegpath.plantpath.wisc.edu/resources/potato-late-blight/", target: "_blank" %>, <%= link_to "early blight", "https://vegpath.plantpath.wisc.edu/resources/early-blight/", target: "_blank" %> or visit the UW Vegetable Pathology website <%= link_to "here", "https://vegpath.plantpath.wisc.edu/", target: "_blank" %>. You can also view weather data, disease risk, and insect developmental models for the upper Midwest interactively at our Vetable Disease and Insect Forecast Network (VDIFN) website <%= link_to "here", vdifn_path, target: "_blank" %>. +

      Learn more about <%= link_to "late blight", "https://vegpath.plantpath.wisc.edu/diseases/potato-late-blight/", target: "_blank" %>, <%= link_to "early blight", "https://vegpath.plantpath.wisc.edu/diseases/potato-early-blight/", target: "_blank" %> or visit the UW Vegetable Pathology website <%= link_to "here", "https://vegpath.plantpath.wisc.edu/", target: "_blank" %>. You can also view weather data, disease risk, and insect developmental models for the upper Midwest interactively at our Vetable Disease and Insect Forecast Network (VDIFN) website <%= link_to "here", vdifn_path, target: "_blank" %>.

      Current DSV and P-Day values for select locations:

      diff --git a/app/views/weather/index.html.erb b/app/views/weather/index.html.erb index 14d11586..b7adf15a 100644 --- a/app/views/weather/index.html.erb +++ b/app/views/weather/index.html.erb @@ -7,8 +7,8 @@ <%= render partial: "quick_links" %> <% end %> -
      -
      +
      +
      <%= link_to image_tag("mean-temps-250px.png"), action: :weather %>
      @@ -20,8 +20,8 @@
      -
      -
      +
      +
      <%= link_to image_tag("precip-map-250px.png"), action: :precip %>
      @@ -33,8 +33,8 @@
      -
      -
      +
      +
      <%= link_to image_tag("sunwater-150px.png"), action: :et %>
      @@ -48,8 +48,8 @@
      -
      -
      +
      +
      <%= link_to image_tag("insol-150px.png"), action: :insol %>
      @@ -63,8 +63,8 @@
      -
      -
      +
      +
      <%= link_to image_tag("hyd-150px.png"), action: :hyd %>
      @@ -79,20 +79,8 @@
      -
      -
      - <%= link_to image_tag("awon-150px.png"), controller: :awon %> -
      -
      -

      <%= link_to "Automated Weather Observation Network", controller: :awon %>

      -

      From 1985-2017, we maintained automated weather stations at the Hancock and Arlington Ag Research stations. (Others were also operated in the 1980s-1990s.) They made hourly observations and daily averages for temperature, humidity, wind speed and direction, solar radiation, and soil temperature. Stations were discontinued in 2017. Since then data from Arlington and Hancock can be accessed via the <%= link_to "Michigan State University Enviroweather Service", "https://enviroweather.msu.edu" %>.

      -
      -
      - -
      - -
      -
      +
      +
      <%= link_to image_tag("doy-cal-150px.png"), action: :doycal %>
      diff --git a/config/routes.rb b/config/routes.rb index dbe3b571..de01f5e4 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -1,6 +1,6 @@ # Helper for easy routing and dasherizing. Default verb is :get. def route(action, verb = :get, *other_verbs) - match action.dasherize => "#{@controller}##{action}", via: [verb] + other_verbs + match action.dasherize => "#{@controller}##{action}", :via => [verb] + other_verbs end Rails.application.routes.draw do @@ -16,7 +16,7 @@ def route(action, verb = :get, *other_verbs) resources :weather, only: :index do collection do route "awon" - match "data" => "weather#weather", via: [:get, :post] + match "data" => "weather#weather", :via => [:get, :post] route "precip", :get, :post route "et", :get, :post route "insol", :get, :post @@ -45,7 +45,7 @@ def route(action, verb = :get, *other_verbs) put :update end end - get "sites/:lat,:long" => "sites#show", constraints: { + get "sites/:lat,:long" => "sites#show", :constraints => { lat: /[-+]?\d+\.?\d*/, long: /[-+]?\d+\.?\d*/ } @@ -53,16 +53,16 @@ def route(action, verb = :get, *other_verbs) get "sites/(*path)" => redirect("sites") # AWON controller - @controller = :awon - resources :awon, only: :index do - collection do - route "awon_check_boxes" - route "station_info" - route "download_data", :post - end - end - get "awon", to: "awon#index" - get "awon/(*path)", to: redirect("/awon") if Rails.env.production? + # @controller = :awon + # resources :awon, only: :index do + # collection do + # route "awon_check_boxes" + # route "station_info" + # route "download_data", :post + # end + # end + # get "awon", to: "awon#index" + # get "awon/(*path)", to: redirect("/awon") if Rails.env.production? # Thermal models controller @controller = :thermal_models @@ -94,7 +94,7 @@ def route(action, verb = :get, *other_verbs) @controller = :subscribers resources :subscribers, only: %i[index new create update destroy] do collection do - route "admin" + route "admin", :get, :post route "manage", :get, :post route "account", :get, :post route "logout" diff --git a/config/schedule.rb b/config/schedule.rb index cbb00d83..f0a601c2 100644 --- a/config/schedule.rb +++ b/config/schedule.rb @@ -27,7 +27,7 @@ runner "Subscriber.send_daily_mail" end -every :month do +every :day do runner "Tasks.purge_subs(delete:true)" end diff --git a/spec/helpers/.keep b/spec/helpers/.keep new file mode 100644 index 00000000..e69de29b diff --git a/spec/helpers/application_helper_spec.rb b/spec/helpers/application_helper_spec.rb deleted file mode 100644 index ebdc3863..00000000 --- a/spec/helpers/application_helper_spec.rb +++ /dev/null @@ -1,5 +0,0 @@ -require "rails_helper" - -RSpec.describe ApplicationHelper, type: :helper do - pending "add some examples to (or delete) #{__FILE__}" -end diff --git a/spec/helpers/sites_helper_spec.rb b/spec/helpers/sites_helper_spec.rb deleted file mode 100644 index 11d217b9..00000000 --- a/spec/helpers/sites_helper_spec.rb +++ /dev/null @@ -1,5 +0,0 @@ -require "rails_helper" - -RSpec.describe SitesHelper, type: :helper do - pending "add some examples to (or delete) #{__FILE__}" -end diff --git a/spec/requests/.keep b/spec/requests/.keep new file mode 100644 index 00000000..e69de29b diff --git a/spec/requests/home_spec.rb b/spec/requests/home_spec.rb index 0a8c7236..0f0537fa 100644 --- a/spec/requests/home_spec.rb +++ b/spec/requests/home_spec.rb @@ -12,9 +12,9 @@ expect(response).to have_http_status(:success) end - it "gets king_hall" do - get url_for(controller: :home, action: :king_hall) - expect(response).to have_http_status(:success) - end + # it "gets king_hall" do + # get url_for(controller: :home, action: :king_hall) + # expect(response).to have_http_status(:success) + # end end end diff --git a/spec/views/.keep b/spec/views/.keep new file mode 100644 index 00000000..e69de29b diff --git a/spec/views/sites/index.html.erb_spec.rb b/spec/views/sites/index.html.erb_spec.rb deleted file mode 100644 index 96dbf045..00000000 --- a/spec/views/sites/index.html.erb_spec.rb +++ /dev/null @@ -1,5 +0,0 @@ -require "rails_helper" - -RSpec.describe "sites/index.html.erb", type: :view do - pending "add some examples to (or delete) #{__FILE__}" -end